Home | History | Annotate | Download | only in wasm
      1 // Copyright 2016 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <type_traits>
      6 
      7 #include "src/wasm/wasm-interpreter.h"
      8 
      9 #include "src/conversions.h"
     10 #include "src/objects-inl.h"
     11 #include "src/utils.h"
     12 #include "src/wasm/decoder.h"
     13 #include "src/wasm/function-body-decoder-impl.h"
     14 #include "src/wasm/function-body-decoder.h"
     15 #include "src/wasm/wasm-external-refs.h"
     16 #include "src/wasm/wasm-limits.h"
     17 #include "src/wasm/wasm-module.h"
     18 
     19 #include "src/zone/accounting-allocator.h"
     20 #include "src/zone/zone-containers.h"
     21 
     22 namespace v8 {
     23 namespace internal {
     24 namespace wasm {
     25 
     26 #if DEBUG
     27 #define TRACE(...)                                        \
     28   do {                                                    \
     29     if (FLAG_trace_wasm_interpreter) PrintF(__VA_ARGS__); \
     30   } while (false)
     31 #else
     32 #define TRACE(...)
     33 #endif
     34 
     35 #define FOREACH_INTERNAL_OPCODE(V) V(Breakpoint, 0xFF)
     36 
     37 #define FOREACH_SIMPLE_BINOP(V) \
     38   V(I32Add, uint32_t, +)        \
     39   V(I32Sub, uint32_t, -)        \
     40   V(I32Mul, uint32_t, *)        \
     41   V(I32And, uint32_t, &)        \
     42   V(I32Ior, uint32_t, |)        \
     43   V(I32Xor, uint32_t, ^)        \
     44   V(I32Eq, uint32_t, ==)        \
     45   V(I32Ne, uint32_t, !=)        \
     46   V(I32LtU, uint32_t, <)        \
     47   V(I32LeU, uint32_t, <=)       \
     48   V(I32GtU, uint32_t, >)        \
     49   V(I32GeU, uint32_t, >=)       \
     50   V(I32LtS, int32_t, <)         \
     51   V(I32LeS, int32_t, <=)        \
     52   V(I32GtS, int32_t, >)         \
     53   V(I32GeS, int32_t, >=)        \
     54   V(I64Add, uint64_t, +)        \
     55   V(I64Sub, uint64_t, -)        \
     56   V(I64Mul, uint64_t, *)        \
     57   V(I64And, uint64_t, &)        \
     58   V(I64Ior, uint64_t, |)        \
     59   V(I64Xor, uint64_t, ^)        \
     60   V(I64Eq, uint64_t, ==)        \
     61   V(I64Ne, uint64_t, !=)        \
     62   V(I64LtU, uint64_t, <)        \
     63   V(I64LeU, uint64_t, <=)       \
     64   V(I64GtU, uint64_t, >)        \
     65   V(I64GeU, uint64_t, >=)       \
     66   V(I64LtS, int64_t, <)         \
     67   V(I64LeS, int64_t, <=)        \
     68   V(I64GtS, int64_t, >)         \
     69   V(I64GeS, int64_t, >=)        \
     70   V(F32Add, float, +)           \
     71   V(F32Sub, float, -)           \
     72   V(F32Eq, float, ==)           \
     73   V(F32Ne, float, !=)           \
     74   V(F32Lt, float, <)            \
     75   V(F32Le, float, <=)           \
     76   V(F32Gt, float, >)            \
     77   V(F32Ge, float, >=)           \
     78   V(F64Add, double, +)          \
     79   V(F64Sub, double, -)          \
     80   V(F64Eq, double, ==)          \
     81   V(F64Ne, double, !=)          \
     82   V(F64Lt, double, <)           \
     83   V(F64Le, double, <=)          \
     84   V(F64Gt, double, >)           \
     85   V(F64Ge, double, >=)          \
     86   V(F32Mul, float, *)           \
     87   V(F64Mul, double, *)          \
     88   V(F32Div, float, /)           \
     89   V(F64Div, double, /)
     90 
     91 #define FOREACH_OTHER_BINOP(V) \
     92   V(I32DivS, int32_t)          \
     93   V(I32DivU, uint32_t)         \
     94   V(I32RemS, int32_t)          \
     95   V(I32RemU, uint32_t)         \
     96   V(I32Shl, uint32_t)          \
     97   V(I32ShrU, uint32_t)         \
     98   V(I32ShrS, int32_t)          \
     99   V(I64DivS, int64_t)          \
    100   V(I64DivU, uint64_t)         \
    101   V(I64RemS, int64_t)          \
    102   V(I64RemU, uint64_t)         \
    103   V(I64Shl, uint64_t)          \
    104   V(I64ShrU, uint64_t)         \
    105   V(I64ShrS, int64_t)          \
    106   V(I32Ror, int32_t)           \
    107   V(I32Rol, int32_t)           \
    108   V(I64Ror, int64_t)           \
    109   V(I64Rol, int64_t)           \
    110   V(F32Min, float)             \
    111   V(F32Max, float)             \
    112   V(F64Min, double)            \
    113   V(F64Max, double)            \
    114   V(I32AsmjsDivS, int32_t)     \
    115   V(I32AsmjsDivU, uint32_t)    \
    116   V(I32AsmjsRemS, int32_t)     \
    117   V(I32AsmjsRemU, uint32_t)
    118 
    119 #define FOREACH_OTHER_UNOP(V)    \
    120   V(I32Clz, uint32_t)            \
    121   V(I32Ctz, uint32_t)            \
    122   V(I32Popcnt, uint32_t)         \
    123   V(I32Eqz, uint32_t)            \
    124   V(I64Clz, uint64_t)            \
    125   V(I64Ctz, uint64_t)            \
    126   V(I64Popcnt, uint64_t)         \
    127   V(I64Eqz, uint64_t)            \
    128   V(F32Abs, float)               \
    129   V(F32Neg, float)               \
    130   V(F32Ceil, float)              \
    131   V(F32Floor, float)             \
    132   V(F32Trunc, float)             \
    133   V(F32NearestInt, float)        \
    134   V(F64Abs, double)              \
    135   V(F64Neg, double)              \
    136   V(F64Ceil, double)             \
    137   V(F64Floor, double)            \
    138   V(F64Trunc, double)            \
    139   V(F64NearestInt, double)       \
    140   V(I32SConvertF32, float)       \
    141   V(I32SConvertF64, double)      \
    142   V(I32UConvertF32, float)       \
    143   V(I32UConvertF64, double)      \
    144   V(I32ConvertI64, int64_t)      \
    145   V(I64SConvertF32, float)       \
    146   V(I64SConvertF64, double)      \
    147   V(I64UConvertF32, float)       \
    148   V(I64UConvertF64, double)      \
    149   V(I64SConvertI32, int32_t)     \
    150   V(I64UConvertI32, uint32_t)    \
    151   V(F32SConvertI32, int32_t)     \
    152   V(F32UConvertI32, uint32_t)    \
    153   V(F32SConvertI64, int64_t)     \
    154   V(F32UConvertI64, uint64_t)    \
    155   V(F32ConvertF64, double)       \
    156   V(F32ReinterpretI32, int32_t)  \
    157   V(F64SConvertI32, int32_t)     \
    158   V(F64UConvertI32, uint32_t)    \
    159   V(F64SConvertI64, int64_t)     \
    160   V(F64UConvertI64, uint64_t)    \
    161   V(F64ConvertF32, float)        \
    162   V(F64ReinterpretI64, int64_t)  \
    163   V(I32AsmjsSConvertF32, float)  \
    164   V(I32AsmjsUConvertF32, float)  \
    165   V(I32AsmjsSConvertF64, double) \
    166   V(I32AsmjsUConvertF64, double) \
    167   V(F32Sqrt, float)              \
    168   V(F64Sqrt, double)
    169 
    170 static inline int32_t ExecuteI32DivS(int32_t a, int32_t b, TrapReason* trap) {
    171   if (b == 0) {
    172     *trap = kTrapDivByZero;
    173     return 0;
    174   }
    175   if (b == -1 && a == std::numeric_limits<int32_t>::min()) {
    176     *trap = kTrapDivUnrepresentable;
    177     return 0;
    178   }
    179   return a / b;
    180 }
    181 
    182 static inline uint32_t ExecuteI32DivU(uint32_t a, uint32_t b,
    183                                       TrapReason* trap) {
    184   if (b == 0) {
    185     *trap = kTrapDivByZero;
    186     return 0;
    187   }
    188   return a / b;
    189 }
    190 
    191 static inline int32_t ExecuteI32RemS(int32_t a, int32_t b, TrapReason* trap) {
    192   if (b == 0) {
    193     *trap = kTrapRemByZero;
    194     return 0;
    195   }
    196   if (b == -1) return 0;
    197   return a % b;
    198 }
    199 
    200 static inline uint32_t ExecuteI32RemU(uint32_t a, uint32_t b,
    201                                       TrapReason* trap) {
    202   if (b == 0) {
    203     *trap = kTrapRemByZero;
    204     return 0;
    205   }
    206   return a % b;
    207 }
    208 
    209 static inline uint32_t ExecuteI32Shl(uint32_t a, uint32_t b, TrapReason* trap) {
    210   return a << (b & 0x1f);
    211 }
    212 
    213 static inline uint32_t ExecuteI32ShrU(uint32_t a, uint32_t b,
    214                                       TrapReason* trap) {
    215   return a >> (b & 0x1f);
    216 }
    217 
    218 static inline int32_t ExecuteI32ShrS(int32_t a, int32_t b, TrapReason* trap) {
    219   return a >> (b & 0x1f);
    220 }
    221 
    222 static inline int64_t ExecuteI64DivS(int64_t a, int64_t b, TrapReason* trap) {
    223   if (b == 0) {
    224     *trap = kTrapDivByZero;
    225     return 0;
    226   }
    227   if (b == -1 && a == std::numeric_limits<int64_t>::min()) {
    228     *trap = kTrapDivUnrepresentable;
    229     return 0;
    230   }
    231   return a / b;
    232 }
    233 
    234 static inline uint64_t ExecuteI64DivU(uint64_t a, uint64_t b,
    235                                       TrapReason* trap) {
    236   if (b == 0) {
    237     *trap = kTrapDivByZero;
    238     return 0;
    239   }
    240   return a / b;
    241 }
    242 
    243 static inline int64_t ExecuteI64RemS(int64_t a, int64_t b, TrapReason* trap) {
    244   if (b == 0) {
    245     *trap = kTrapRemByZero;
    246     return 0;
    247   }
    248   if (b == -1) return 0;
    249   return a % b;
    250 }
    251 
    252 static inline uint64_t ExecuteI64RemU(uint64_t a, uint64_t b,
    253                                       TrapReason* trap) {
    254   if (b == 0) {
    255     *trap = kTrapRemByZero;
    256     return 0;
    257   }
    258   return a % b;
    259 }
    260 
    261 static inline uint64_t ExecuteI64Shl(uint64_t a, uint64_t b, TrapReason* trap) {
    262   return a << (b & 0x3f);
    263 }
    264 
    265 static inline uint64_t ExecuteI64ShrU(uint64_t a, uint64_t b,
    266                                       TrapReason* trap) {
    267   return a >> (b & 0x3f);
    268 }
    269 
    270 static inline int64_t ExecuteI64ShrS(int64_t a, int64_t b, TrapReason* trap) {
    271   return a >> (b & 0x3f);
    272 }
    273 
    274 static inline uint32_t ExecuteI32Ror(uint32_t a, uint32_t b, TrapReason* trap) {
    275   uint32_t shift = (b & 0x1f);
    276   return (a >> shift) | (a << (32 - shift));
    277 }
    278 
    279 static inline uint32_t ExecuteI32Rol(uint32_t a, uint32_t b, TrapReason* trap) {
    280   uint32_t shift = (b & 0x1f);
    281   return (a << shift) | (a >> (32 - shift));
    282 }
    283 
    284 static inline uint64_t ExecuteI64Ror(uint64_t a, uint64_t b, TrapReason* trap) {
    285   uint32_t shift = (b & 0x3f);
    286   return (a >> shift) | (a << (64 - shift));
    287 }
    288 
    289 static inline uint64_t ExecuteI64Rol(uint64_t a, uint64_t b, TrapReason* trap) {
    290   uint32_t shift = (b & 0x3f);
    291   return (a << shift) | (a >> (64 - shift));
    292 }
    293 
    294 static inline float ExecuteF32Min(float a, float b, TrapReason* trap) {
    295   return JSMin(a, b);
    296 }
    297 
    298 static inline float ExecuteF32Max(float a, float b, TrapReason* trap) {
    299   return JSMax(a, b);
    300 }
    301 
    302 static inline float ExecuteF32CopySign(float a, float b, TrapReason* trap) {
    303   return copysignf(a, b);
    304 }
    305 
    306 static inline double ExecuteF64Min(double a, double b, TrapReason* trap) {
    307   return JSMin(a, b);
    308 }
    309 
    310 static inline double ExecuteF64Max(double a, double b, TrapReason* trap) {
    311   return JSMax(a, b);
    312 }
    313 
    314 static inline double ExecuteF64CopySign(double a, double b, TrapReason* trap) {
    315   return copysign(a, b);
    316 }
    317 
    318 static inline int32_t ExecuteI32AsmjsDivS(int32_t a, int32_t b,
    319                                           TrapReason* trap) {
    320   if (b == 0) return 0;
    321   if (b == -1 && a == std::numeric_limits<int32_t>::min()) {
    322     return std::numeric_limits<int32_t>::min();
    323   }
    324   return a / b;
    325 }
    326 
    327 static inline uint32_t ExecuteI32AsmjsDivU(uint32_t a, uint32_t b,
    328                                            TrapReason* trap) {
    329   if (b == 0) return 0;
    330   return a / b;
    331 }
    332 
    333 static inline int32_t ExecuteI32AsmjsRemS(int32_t a, int32_t b,
    334                                           TrapReason* trap) {
    335   if (b == 0) return 0;
    336   if (b == -1) return 0;
    337   return a % b;
    338 }
    339 
    340 static inline uint32_t ExecuteI32AsmjsRemU(uint32_t a, uint32_t b,
    341                                            TrapReason* trap) {
    342   if (b == 0) return 0;
    343   return a % b;
    344 }
    345 
    346 static inline int32_t ExecuteI32AsmjsSConvertF32(float a, TrapReason* trap) {
    347   return DoubleToInt32(a);
    348 }
    349 
    350 static inline uint32_t ExecuteI32AsmjsUConvertF32(float a, TrapReason* trap) {
    351   return DoubleToUint32(a);
    352 }
    353 
    354 static inline int32_t ExecuteI32AsmjsSConvertF64(double a, TrapReason* trap) {
    355   return DoubleToInt32(a);
    356 }
    357 
    358 static inline uint32_t ExecuteI32AsmjsUConvertF64(double a, TrapReason* trap) {
    359   return DoubleToUint32(a);
    360 }
    361 
    362 static int32_t ExecuteI32Clz(uint32_t val, TrapReason* trap) {
    363   return base::bits::CountLeadingZeros32(val);
    364 }
    365 
    366 static uint32_t ExecuteI32Ctz(uint32_t val, TrapReason* trap) {
    367   return base::bits::CountTrailingZeros32(val);
    368 }
    369 
    370 static uint32_t ExecuteI32Popcnt(uint32_t val, TrapReason* trap) {
    371   return word32_popcnt_wrapper(&val);
    372 }
    373 
    374 static inline uint32_t ExecuteI32Eqz(uint32_t val, TrapReason* trap) {
    375   return val == 0 ? 1 : 0;
    376 }
    377 
    378 static int64_t ExecuteI64Clz(uint64_t val, TrapReason* trap) {
    379   return base::bits::CountLeadingZeros64(val);
    380 }
    381 
    382 static inline uint64_t ExecuteI64Ctz(uint64_t val, TrapReason* trap) {
    383   return base::bits::CountTrailingZeros64(val);
    384 }
    385 
    386 static inline int64_t ExecuteI64Popcnt(uint64_t val, TrapReason* trap) {
    387   return word64_popcnt_wrapper(&val);
    388 }
    389 
    390 static inline int32_t ExecuteI64Eqz(uint64_t val, TrapReason* trap) {
    391   return val == 0 ? 1 : 0;
    392 }
    393 
    394 static inline float ExecuteF32Abs(float a, TrapReason* trap) {
    395   return bit_cast<float>(bit_cast<uint32_t>(a) & 0x7fffffff);
    396 }
    397 
    398 static inline float ExecuteF32Neg(float a, TrapReason* trap) {
    399   return bit_cast<float>(bit_cast<uint32_t>(a) ^ 0x80000000);
    400 }
    401 
    402 static inline float ExecuteF32Ceil(float a, TrapReason* trap) {
    403   return ceilf(a);
    404 }
    405 
    406 static inline float ExecuteF32Floor(float a, TrapReason* trap) {
    407   return floorf(a);
    408 }
    409 
    410 static inline float ExecuteF32Trunc(float a, TrapReason* trap) {
    411   return truncf(a);
    412 }
    413 
    414 static inline float ExecuteF32NearestInt(float a, TrapReason* trap) {
    415   return nearbyintf(a);
    416 }
    417 
    418 static inline float ExecuteF32Sqrt(float a, TrapReason* trap) {
    419   float result = sqrtf(a);
    420   return result;
    421 }
    422 
    423 static inline double ExecuteF64Abs(double a, TrapReason* trap) {
    424   return bit_cast<double>(bit_cast<uint64_t>(a) & 0x7fffffffffffffff);
    425 }
    426 
    427 static inline double ExecuteF64Neg(double a, TrapReason* trap) {
    428   return bit_cast<double>(bit_cast<uint64_t>(a) ^ 0x8000000000000000);
    429 }
    430 
    431 static inline double ExecuteF64Ceil(double a, TrapReason* trap) {
    432   return ceil(a);
    433 }
    434 
    435 static inline double ExecuteF64Floor(double a, TrapReason* trap) {
    436   return floor(a);
    437 }
    438 
    439 static inline double ExecuteF64Trunc(double a, TrapReason* trap) {
    440   return trunc(a);
    441 }
    442 
    443 static inline double ExecuteF64NearestInt(double a, TrapReason* trap) {
    444   return nearbyint(a);
    445 }
    446 
    447 static inline double ExecuteF64Sqrt(double a, TrapReason* trap) {
    448   return sqrt(a);
    449 }
    450 
    451 static int32_t ExecuteI32SConvertF32(float a, TrapReason* trap) {
    452   // The upper bound is (INT32_MAX + 1), which is the lowest float-representable
    453   // number above INT32_MAX which cannot be represented as int32.
    454   float upper_bound = 2147483648.0f;
    455   // We use INT32_MIN as a lower bound because (INT32_MIN - 1) is not
    456   // representable as float, and no number between (INT32_MIN - 1) and INT32_MIN
    457   // is.
    458   float lower_bound = static_cast<float>(INT32_MIN);
    459   if (a < upper_bound && a >= lower_bound) {
    460     return static_cast<int32_t>(a);
    461   }
    462   *trap = kTrapFloatUnrepresentable;
    463   return 0;
    464 }
    465 
    466 static int32_t ExecuteI32SConvertF64(double a, TrapReason* trap) {
    467   // The upper bound is (INT32_MAX + 1), which is the lowest double-
    468   // representable number above INT32_MAX which cannot be represented as int32.
    469   double upper_bound = 2147483648.0;
    470   // The lower bound is (INT32_MIN - 1), which is the greatest double-
    471   // representable number below INT32_MIN which cannot be represented as int32.
    472   double lower_bound = -2147483649.0;
    473   if (a < upper_bound && a > lower_bound) {
    474     return static_cast<int32_t>(a);
    475   }
    476   *trap = kTrapFloatUnrepresentable;
    477   return 0;
    478 }
    479 
    480 static uint32_t ExecuteI32UConvertF32(float a, TrapReason* trap) {
    481   // The upper bound is (UINT32_MAX + 1), which is the lowest
    482   // float-representable number above UINT32_MAX which cannot be represented as
    483   // uint32.
    484   double upper_bound = 4294967296.0f;
    485   double lower_bound = -1.0f;
    486   if (a < upper_bound && a > lower_bound) {
    487     return static_cast<uint32_t>(a);
    488   }
    489   *trap = kTrapFloatUnrepresentable;
    490   return 0;
    491 }
    492 
    493 static uint32_t ExecuteI32UConvertF64(double a, TrapReason* trap) {
    494   // The upper bound is (UINT32_MAX + 1), which is the lowest
    495   // double-representable number above UINT32_MAX which cannot be represented as
    496   // uint32.
    497   double upper_bound = 4294967296.0;
    498   double lower_bound = -1.0;
    499   if (a < upper_bound && a > lower_bound) {
    500     return static_cast<uint32_t>(a);
    501   }
    502   *trap = kTrapFloatUnrepresentable;
    503   return 0;
    504 }
    505 
    506 static inline uint32_t ExecuteI32ConvertI64(int64_t a, TrapReason* trap) {
    507   return static_cast<uint32_t>(a & 0xFFFFFFFF);
    508 }
    509 
    510 static int64_t ExecuteI64SConvertF32(float a, TrapReason* trap) {
    511   int64_t output;
    512   if (!float32_to_int64_wrapper(&a, &output)) {
    513     *trap = kTrapFloatUnrepresentable;
    514   }
    515   return output;
    516 }
    517 
    518 static int64_t ExecuteI64SConvertF64(double a, TrapReason* trap) {
    519   int64_t output;
    520   if (!float64_to_int64_wrapper(&a, &output)) {
    521     *trap = kTrapFloatUnrepresentable;
    522   }
    523   return output;
    524 }
    525 
    526 static uint64_t ExecuteI64UConvertF32(float a, TrapReason* trap) {
    527   uint64_t output;
    528   if (!float32_to_uint64_wrapper(&a, &output)) {
    529     *trap = kTrapFloatUnrepresentable;
    530   }
    531   return output;
    532 }
    533 
    534 static uint64_t ExecuteI64UConvertF64(double a, TrapReason* trap) {
    535   uint64_t output;
    536   if (!float64_to_uint64_wrapper(&a, &output)) {
    537     *trap = kTrapFloatUnrepresentable;
    538   }
    539   return output;
    540 }
    541 
    542 static inline int64_t ExecuteI64SConvertI32(int32_t a, TrapReason* trap) {
    543   return static_cast<int64_t>(a);
    544 }
    545 
    546 static inline int64_t ExecuteI64UConvertI32(uint32_t a, TrapReason* trap) {
    547   return static_cast<uint64_t>(a);
    548 }
    549 
    550 static inline float ExecuteF32SConvertI32(int32_t a, TrapReason* trap) {
    551   return static_cast<float>(a);
    552 }
    553 
    554 static inline float ExecuteF32UConvertI32(uint32_t a, TrapReason* trap) {
    555   return static_cast<float>(a);
    556 }
    557 
    558 static inline float ExecuteF32SConvertI64(int64_t a, TrapReason* trap) {
    559   float output;
    560   int64_to_float32_wrapper(&a, &output);
    561   return output;
    562 }
    563 
    564 static inline float ExecuteF32UConvertI64(uint64_t a, TrapReason* trap) {
    565   float output;
    566   uint64_to_float32_wrapper(&a, &output);
    567   return output;
    568 }
    569 
    570 static inline float ExecuteF32ConvertF64(double a, TrapReason* trap) {
    571   return static_cast<float>(a);
    572 }
    573 
    574 static inline float ExecuteF32ReinterpretI32(int32_t a, TrapReason* trap) {
    575   return bit_cast<float>(a);
    576 }
    577 
    578 static inline double ExecuteF64SConvertI32(int32_t a, TrapReason* trap) {
    579   return static_cast<double>(a);
    580 }
    581 
    582 static inline double ExecuteF64UConvertI32(uint32_t a, TrapReason* trap) {
    583   return static_cast<double>(a);
    584 }
    585 
    586 static inline double ExecuteF64SConvertI64(int64_t a, TrapReason* trap) {
    587   double output;
    588   int64_to_float64_wrapper(&a, &output);
    589   return output;
    590 }
    591 
    592 static inline double ExecuteF64UConvertI64(uint64_t a, TrapReason* trap) {
    593   double output;
    594   uint64_to_float64_wrapper(&a, &output);
    595   return output;
    596 }
    597 
    598 static inline double ExecuteF64ConvertF32(float a, TrapReason* trap) {
    599   return static_cast<double>(a);
    600 }
    601 
    602 static inline double ExecuteF64ReinterpretI64(int64_t a, TrapReason* trap) {
    603   return bit_cast<double>(a);
    604 }
    605 
    606 static inline int32_t ExecuteI32ReinterpretF32(WasmVal a) {
    607   return a.to_unchecked<int32_t>();
    608 }
    609 
    610 static inline int64_t ExecuteI64ReinterpretF64(WasmVal a) {
    611   return a.to_unchecked<int64_t>();
    612 }
    613 
    614 static inline int32_t ExecuteGrowMemory(uint32_t delta_pages,
    615                                         WasmInstance* instance) {
    616   // TODO(ahaas): Move memory allocation to wasm-module.cc for better
    617   // encapsulation.
    618   if (delta_pages > FLAG_wasm_max_mem_pages ||
    619       delta_pages > instance->module->max_mem_pages) {
    620     return -1;
    621   }
    622   uint32_t old_size = instance->mem_size;
    623   uint32_t new_size;
    624   byte* new_mem_start;
    625   if (instance->mem_size == 0) {
    626     // TODO(gdeepti): Fix bounds check to take into account size of memtype.
    627     new_size = delta_pages * wasm::WasmModule::kPageSize;
    628     new_mem_start = static_cast<byte*>(calloc(new_size, sizeof(byte)));
    629     if (!new_mem_start) {
    630       return -1;
    631     }
    632   } else {
    633     DCHECK_NOT_NULL(instance->mem_start);
    634     new_size = old_size + delta_pages * wasm::WasmModule::kPageSize;
    635     if (new_size / wasm::WasmModule::kPageSize > FLAG_wasm_max_mem_pages ||
    636         new_size / wasm::WasmModule::kPageSize >
    637             instance->module->max_mem_pages) {
    638       return -1;
    639     }
    640     new_mem_start = static_cast<byte*>(realloc(instance->mem_start, new_size));
    641     if (!new_mem_start) {
    642       return -1;
    643     }
    644     // Zero initializing uninitialized memory from realloc
    645     memset(new_mem_start + old_size, 0, new_size - old_size);
    646   }
    647   instance->mem_start = new_mem_start;
    648   instance->mem_size = new_size;
    649   return static_cast<int32_t>(old_size / WasmModule::kPageSize);
    650 }
    651 
    652 enum InternalOpcode {
    653 #define DECL_INTERNAL_ENUM(name, value) kInternal##name = value,
    654   FOREACH_INTERNAL_OPCODE(DECL_INTERNAL_ENUM)
    655 #undef DECL_INTERNAL_ENUM
    656 };
    657 
    658 static const char* OpcodeName(uint32_t val) {
    659   switch (val) {
    660 #define DECL_INTERNAL_CASE(name, value) \
    661   case kInternal##name:                 \
    662     return "Internal" #name;
    663     FOREACH_INTERNAL_OPCODE(DECL_INTERNAL_CASE)
    664 #undef DECL_INTERNAL_CASE
    665   }
    666   return WasmOpcodes::OpcodeName(static_cast<WasmOpcode>(val));
    667 }
    668 
    669 static const int kRunSteps = 1000;
    670 
    671 // A helper class to compute the control transfers for each bytecode offset.
    672 // Control transfers allow Br, BrIf, BrTable, If, Else, and End bytecodes to
    673 // be directly executed without the need to dynamically track blocks.
    674 class ControlTransfers : public ZoneObject {
    675  public:
    676   ControlTransferMap map_;
    677 
    678   ControlTransfers(Zone* zone, BodyLocalDecls* locals, const byte* start,
    679                    const byte* end)
    680       : map_(zone) {
    681     // Represents a control flow label.
    682     struct CLabel : public ZoneObject {
    683       const byte* target;
    684       ZoneVector<const byte*> refs;
    685 
    686       explicit CLabel(Zone* zone) : target(nullptr), refs(zone) {}
    687 
    688       // Bind this label to the given PC.
    689       void Bind(ControlTransferMap* map, const byte* start, const byte* pc) {
    690         DCHECK_NULL(target);
    691         target = pc;
    692         for (auto from_pc : refs) {
    693           auto pcdiff = static_cast<pcdiff_t>(target - from_pc);
    694           size_t offset = static_cast<size_t>(from_pc - start);
    695           (*map)[offset] = pcdiff;
    696         }
    697       }
    698 
    699       // Reference this label from the given location.
    700       void Ref(ControlTransferMap* map, const byte* start,
    701                const byte* from_pc) {
    702         if (target) {
    703           // Target being bound before a reference means this is a loop.
    704           DCHECK_EQ(kExprLoop, *target);
    705           auto pcdiff = static_cast<pcdiff_t>(target - from_pc);
    706           size_t offset = static_cast<size_t>(from_pc - start);
    707           (*map)[offset] = pcdiff;
    708         } else {
    709           refs.push_back(from_pc);
    710         }
    711       }
    712     };
    713 
    714     // An entry in the control stack.
    715     struct Control {
    716       const byte* pc;
    717       CLabel* end_label;
    718       CLabel* else_label;
    719 
    720       void Ref(ControlTransferMap* map, const byte* start,
    721                const byte* from_pc) {
    722         end_label->Ref(map, start, from_pc);
    723       }
    724     };
    725 
    726     // Compute the ControlTransfer map.
    727     // This algorithm maintains a stack of control constructs similar to the
    728     // AST decoder. The {control_stack} allows matching {br,br_if,br_table}
    729     // bytecodes with their target, as well as determining whether the current
    730     // bytecodes are within the true or false block of an else.
    731     std::vector<Control> control_stack;
    732     CLabel* func_label = new (zone) CLabel(zone);
    733     control_stack.push_back({start, func_label, nullptr});
    734     for (BytecodeIterator i(start, end, locals); i.has_next(); i.next()) {
    735       WasmOpcode opcode = i.current();
    736       TRACE("@%u: control %s\n", i.pc_offset(),
    737             WasmOpcodes::OpcodeName(opcode));
    738       switch (opcode) {
    739         case kExprBlock: {
    740           TRACE("control @%u: Block\n", i.pc_offset());
    741           CLabel* label = new (zone) CLabel(zone);
    742           control_stack.push_back({i.pc(), label, nullptr});
    743           break;
    744         }
    745         case kExprLoop: {
    746           TRACE("control @%u: Loop\n", i.pc_offset());
    747           CLabel* label = new (zone) CLabel(zone);
    748           control_stack.push_back({i.pc(), label, nullptr});
    749           label->Bind(&map_, start, i.pc());
    750           break;
    751         }
    752         case kExprIf: {
    753           TRACE("control @%u: If\n", i.pc_offset());
    754           CLabel* end_label = new (zone) CLabel(zone);
    755           CLabel* else_label = new (zone) CLabel(zone);
    756           control_stack.push_back({i.pc(), end_label, else_label});
    757           else_label->Ref(&map_, start, i.pc());
    758           break;
    759         }
    760         case kExprElse: {
    761           Control* c = &control_stack.back();
    762           TRACE("control @%u: Else\n", i.pc_offset());
    763           c->end_label->Ref(&map_, start, i.pc());
    764           DCHECK_NOT_NULL(c->else_label);
    765           c->else_label->Bind(&map_, start, i.pc() + 1);
    766           c->else_label = nullptr;
    767           break;
    768         }
    769         case kExprEnd: {
    770           Control* c = &control_stack.back();
    771           TRACE("control @%u: End\n", i.pc_offset());
    772           if (c->end_label->target) {
    773             // only loops have bound labels.
    774             DCHECK_EQ(kExprLoop, *c->pc);
    775           } else {
    776             if (c->else_label) c->else_label->Bind(&map_, start, i.pc());
    777             c->end_label->Bind(&map_, start, i.pc() + 1);
    778           }
    779           control_stack.pop_back();
    780           break;
    781         }
    782         case kExprBr: {
    783           BreakDepthOperand operand(&i, i.pc());
    784           TRACE("control @%u: Br[depth=%u]\n", i.pc_offset(), operand.depth);
    785           Control* c = &control_stack[control_stack.size() - operand.depth - 1];
    786           c->Ref(&map_, start, i.pc());
    787           break;
    788         }
    789         case kExprBrIf: {
    790           BreakDepthOperand operand(&i, i.pc());
    791           TRACE("control @%u: BrIf[depth=%u]\n", i.pc_offset(), operand.depth);
    792           Control* c = &control_stack[control_stack.size() - operand.depth - 1];
    793           c->Ref(&map_, start, i.pc());
    794           break;
    795         }
    796         case kExprBrTable: {
    797           BranchTableOperand operand(&i, i.pc());
    798           BranchTableIterator iterator(&i, operand);
    799           TRACE("control @%u: BrTable[count=%u]\n", i.pc_offset(),
    800                 operand.table_count);
    801           while (iterator.has_next()) {
    802             uint32_t j = iterator.cur_index();
    803             uint32_t target = iterator.next();
    804             Control* c = &control_stack[control_stack.size() - target - 1];
    805             c->Ref(&map_, start, i.pc() + j);
    806           }
    807           break;
    808         }
    809         default: {
    810           break;
    811         }
    812       }
    813     }
    814     if (!func_label->target) func_label->Bind(&map_, start, end);
    815   }
    816 
    817   pcdiff_t Lookup(pc_t from) {
    818     auto result = map_.find(from);
    819     if (result == map_.end()) {
    820       V8_Fatal(__FILE__, __LINE__, "no control target for pc %zu", from);
    821     }
    822     return result->second;
    823   }
    824 };
    825 
    826 // Code and metadata needed to execute a function.
    827 struct InterpreterCode {
    828   const WasmFunction* function;  // wasm function
    829   BodyLocalDecls locals;         // local declarations
    830   const byte* orig_start;        // start of original code
    831   const byte* orig_end;          // end of original code
    832   byte* start;                   // start of (maybe altered) code
    833   byte* end;                     // end of (maybe altered) code
    834   ControlTransfers* targets;     // helper for control flow.
    835 
    836   const byte* at(pc_t pc) { return start + pc; }
    837 };
    838 
    839 // The main storage for interpreter code. It maps {WasmFunction} to the
    840 // metadata needed to execute each function.
    841 class CodeMap {
    842  public:
    843   Zone* zone_;
    844   const WasmModule* module_;
    845   ZoneVector<InterpreterCode> interpreter_code_;
    846 
    847   CodeMap(const WasmModule* module, const uint8_t* module_start, Zone* zone)
    848       : zone_(zone), module_(module), interpreter_code_(zone) {
    849     if (module == nullptr) return;
    850     for (size_t i = 0; i < module->functions.size(); ++i) {
    851       const WasmFunction* function = &module->functions[i];
    852       const byte* code_start = module_start + function->code_start_offset;
    853       const byte* code_end = module_start + function->code_end_offset;
    854       AddFunction(function, code_start, code_end);
    855     }
    856   }
    857 
    858   InterpreterCode* FindCode(const WasmFunction* function) {
    859     if (function->func_index < interpreter_code_.size()) {
    860       InterpreterCode* code = &interpreter_code_[function->func_index];
    861       DCHECK_EQ(function, code->function);
    862       return Preprocess(code);
    863     }
    864     return nullptr;
    865   }
    866 
    867   InterpreterCode* GetCode(uint32_t function_index) {
    868     CHECK_LT(function_index, interpreter_code_.size());
    869     return Preprocess(&interpreter_code_[function_index]);
    870   }
    871 
    872   InterpreterCode* GetIndirectCode(uint32_t table_index, uint32_t entry_index) {
    873     if (table_index >= module_->function_tables.size()) return nullptr;
    874     const WasmIndirectFunctionTable* table =
    875         &module_->function_tables[table_index];
    876     if (entry_index >= table->values.size()) return nullptr;
    877     uint32_t index = table->values[entry_index];
    878     if (index >= interpreter_code_.size()) return nullptr;
    879     return GetCode(index);
    880   }
    881 
    882   InterpreterCode* Preprocess(InterpreterCode* code) {
    883     if (code->targets == nullptr && code->start) {
    884       // Compute the control targets map and the local declarations.
    885       CHECK(DecodeLocalDecls(&code->locals, code->start, code->end));
    886       code->targets = new (zone_) ControlTransfers(
    887           zone_, &code->locals, code->orig_start, code->orig_end);
    888     }
    889     return code;
    890   }
    891 
    892   int AddFunction(const WasmFunction* function, const byte* code_start,
    893                   const byte* code_end) {
    894     InterpreterCode code = {
    895         function, BodyLocalDecls(zone_),         code_start,
    896         code_end, const_cast<byte*>(code_start), const_cast<byte*>(code_end),
    897         nullptr};
    898 
    899     DCHECK_EQ(interpreter_code_.size(), function->func_index);
    900     interpreter_code_.push_back(code);
    901     return static_cast<int>(interpreter_code_.size()) - 1;
    902   }
    903 
    904   bool SetFunctionCode(const WasmFunction* function, const byte* start,
    905                        const byte* end) {
    906     InterpreterCode* code = FindCode(function);
    907     if (code == nullptr) return false;
    908     code->targets = nullptr;
    909     code->orig_start = start;
    910     code->orig_end = end;
    911     code->start = const_cast<byte*>(start);
    912     code->end = const_cast<byte*>(end);
    913     Preprocess(code);
    914     return true;
    915   }
    916 };
    917 
    918 namespace {
    919 // Responsible for executing code directly.
    920 class ThreadImpl {
    921  public:
    922   ThreadImpl(Zone* zone, CodeMap* codemap, WasmInstance* instance)
    923       : codemap_(codemap),
    924         instance_(instance),
    925         stack_(zone),
    926         frames_(zone),
    927         blocks_(zone) {}
    928 
    929   //==========================================================================
    930   // Implementation of public interface for WasmInterpreter::Thread.
    931   //==========================================================================
    932 
    933   WasmInterpreter::State state() { return state_; }
    934 
    935   void PushFrame(const WasmFunction* function, WasmVal* args) {
    936     InterpreterCode* code = codemap()->FindCode(function);
    937     CHECK_NOT_NULL(code);
    938     ++num_interpreted_calls_;
    939     frames_.push_back({code, 0, 0, stack_.size()});
    940     for (size_t i = 0; i < function->sig->parameter_count(); ++i) {
    941       stack_.push_back(args[i]);
    942     }
    943     frames_.back().ret_pc = InitLocals(code);
    944     blocks_.push_back(
    945         {0, stack_.size(), frames_.size(),
    946          static_cast<uint32_t>(code->function->sig->return_count())});
    947     TRACE("  => PushFrame(#%u @%zu)\n", code->function->func_index,
    948           frames_.back().ret_pc);
    949   }
    950 
    951   WasmInterpreter::State Run() {
    952     do {
    953       TRACE("  => Run()\n");
    954       if (state_ == WasmInterpreter::STOPPED ||
    955           state_ == WasmInterpreter::PAUSED) {
    956         state_ = WasmInterpreter::RUNNING;
    957         Execute(frames_.back().code, frames_.back().ret_pc, kRunSteps);
    958       }
    959     } while (state_ == WasmInterpreter::STOPPED);
    960     return state_;
    961   }
    962 
    963   WasmInterpreter::State Step() {
    964     TRACE("  => Step()\n");
    965     if (state_ == WasmInterpreter::STOPPED ||
    966         state_ == WasmInterpreter::PAUSED) {
    967       state_ = WasmInterpreter::RUNNING;
    968       Execute(frames_.back().code, frames_.back().ret_pc, 1);
    969     }
    970     return state_;
    971   }
    972 
    973   void Pause() { UNIMPLEMENTED(); }
    974 
    975   void Reset() {
    976     TRACE("----- RESET -----\n");
    977     stack_.clear();
    978     frames_.clear();
    979     state_ = WasmInterpreter::STOPPED;
    980     trap_reason_ = kTrapCount;
    981     possible_nondeterminism_ = false;
    982   }
    983 
    984   int GetFrameCount() {
    985     DCHECK_GE(kMaxInt, frames_.size());
    986     return static_cast<int>(frames_.size());
    987   }
    988 
    989   template <typename FrameCons>
    990   InterpretedFrame GetMutableFrame(int index, FrameCons frame_cons) {
    991     DCHECK_LE(0, index);
    992     DCHECK_GT(frames_.size(), index);
    993     Frame* frame = &frames_[index];
    994     DCHECK_GE(kMaxInt, frame->ret_pc);
    995     DCHECK_GE(kMaxInt, frame->sp);
    996     DCHECK_GE(kMaxInt, frame->llimit());
    997     return frame_cons(frame->code->function, static_cast<int>(frame->ret_pc),
    998                       static_cast<int>(frame->sp),
    999                       static_cast<int>(frame->llimit()));
   1000   }
   1001 
   1002   WasmVal GetReturnValue(int index) {
   1003     if (state_ == WasmInterpreter::TRAPPED) return WasmVal(0xdeadbeef);
   1004     CHECK_EQ(WasmInterpreter::FINISHED, state_);
   1005     CHECK_LT(static_cast<size_t>(index), stack_.size());
   1006     return stack_[index];
   1007   }
   1008 
   1009   pc_t GetBreakpointPc() { return break_pc_; }
   1010 
   1011   bool PossibleNondeterminism() { return possible_nondeterminism_; }
   1012 
   1013   uint64_t NumInterpretedCalls() { return num_interpreted_calls_; }
   1014 
   1015   void AddBreakFlags(uint8_t flags) { break_flags_ |= flags; }
   1016 
   1017   void ClearBreakFlags() { break_flags_ = WasmInterpreter::BreakFlag::None; }
   1018 
   1019  private:
   1020   // Entries on the stack of functions being evaluated.
   1021   struct Frame {
   1022     InterpreterCode* code;
   1023     pc_t call_pc;
   1024     pc_t ret_pc;
   1025     sp_t sp;
   1026 
   1027     // Limit of parameters.
   1028     sp_t plimit() { return sp + code->function->sig->parameter_count(); }
   1029     // Limit of locals.
   1030     sp_t llimit() { return plimit() + code->locals.type_list.size(); }
   1031   };
   1032 
   1033   struct Block {
   1034     pc_t pc;
   1035     sp_t sp;
   1036     size_t fp;
   1037     unsigned arity;
   1038   };
   1039 
   1040   CodeMap* codemap_;
   1041   WasmInstance* instance_;
   1042   ZoneVector<WasmVal> stack_;
   1043   ZoneVector<Frame> frames_;
   1044   ZoneVector<Block> blocks_;
   1045   WasmInterpreter::State state_ = WasmInterpreter::STOPPED;
   1046   pc_t break_pc_ = kInvalidPc;
   1047   TrapReason trap_reason_ = kTrapCount;
   1048   bool possible_nondeterminism_ = false;
   1049   uint8_t break_flags_ = 0;  // a combination of WasmInterpreter::BreakFlag
   1050   uint64_t num_interpreted_calls_ = 0;
   1051 
   1052   CodeMap* codemap() { return codemap_; }
   1053   WasmInstance* instance() { return instance_; }
   1054   const WasmModule* module() { return instance_->module; }
   1055 
   1056   void DoTrap(TrapReason trap, pc_t pc) {
   1057     state_ = WasmInterpreter::TRAPPED;
   1058     trap_reason_ = trap;
   1059     CommitPc(pc);
   1060   }
   1061 
   1062   // Push a frame with arguments already on the stack.
   1063   void PushFrame(InterpreterCode* code, pc_t call_pc, pc_t ret_pc) {
   1064     CHECK_NOT_NULL(code);
   1065     DCHECK(!frames_.empty());
   1066     ++num_interpreted_calls_;
   1067     frames_.back().call_pc = call_pc;
   1068     frames_.back().ret_pc = ret_pc;
   1069     size_t arity = code->function->sig->parameter_count();
   1070     DCHECK_GE(stack_.size(), arity);
   1071     // The parameters will overlap the arguments already on the stack.
   1072     frames_.push_back({code, 0, 0, stack_.size() - arity});
   1073     blocks_.push_back(
   1074         {0, stack_.size(), frames_.size(),
   1075          static_cast<uint32_t>(code->function->sig->return_count())});
   1076     frames_.back().ret_pc = InitLocals(code);
   1077     TRACE("  => push func#%u @%zu\n", code->function->func_index,
   1078           frames_.back().ret_pc);
   1079   }
   1080 
   1081   pc_t InitLocals(InterpreterCode* code) {
   1082     for (auto p : code->locals.type_list) {
   1083       WasmVal val;
   1084       switch (p) {
   1085         case kWasmI32:
   1086           val = WasmVal(static_cast<int32_t>(0));
   1087           break;
   1088         case kWasmI64:
   1089           val = WasmVal(static_cast<int64_t>(0));
   1090           break;
   1091         case kWasmF32:
   1092           val = WasmVal(static_cast<float>(0));
   1093           break;
   1094         case kWasmF64:
   1095           val = WasmVal(static_cast<double>(0));
   1096           break;
   1097         default:
   1098           UNREACHABLE();
   1099           break;
   1100       }
   1101       stack_.push_back(val);
   1102     }
   1103     return code->locals.encoded_size;
   1104   }
   1105 
   1106   void CommitPc(pc_t pc) {
   1107     if (!frames_.empty()) {
   1108       frames_.back().ret_pc = pc;
   1109     }
   1110   }
   1111 
   1112   bool SkipBreakpoint(InterpreterCode* code, pc_t pc) {
   1113     if (pc == break_pc_) {
   1114       // Skip the previously hit breakpoint when resuming.
   1115       break_pc_ = kInvalidPc;
   1116       return true;
   1117     }
   1118     return false;
   1119   }
   1120 
   1121   int LookupTarget(InterpreterCode* code, pc_t pc) {
   1122     return static_cast<int>(code->targets->Lookup(pc));
   1123   }
   1124 
   1125   int DoBreak(InterpreterCode* code, pc_t pc, size_t depth) {
   1126     size_t bp = blocks_.size() - depth - 1;
   1127     Block* target = &blocks_[bp];
   1128     DoStackTransfer(target->sp, target->arity);
   1129     blocks_.resize(bp);
   1130     return LookupTarget(code, pc);
   1131   }
   1132 
   1133   bool DoReturn(InterpreterCode** code, pc_t* pc, pc_t* limit, size_t arity) {
   1134     DCHECK_GT(frames_.size(), 0);
   1135     // Pop all blocks for this frame.
   1136     while (!blocks_.empty() && blocks_.back().fp == frames_.size()) {
   1137       blocks_.pop_back();
   1138     }
   1139 
   1140     sp_t dest = frames_.back().sp;
   1141     frames_.pop_back();
   1142     if (frames_.size() == 0) {
   1143       // A return from the last frame terminates the execution.
   1144       state_ = WasmInterpreter::FINISHED;
   1145       DoStackTransfer(0, arity);
   1146       TRACE("  => finish\n");
   1147       return false;
   1148     } else {
   1149       // Return to caller frame.
   1150       Frame* top = &frames_.back();
   1151       *code = top->code;
   1152       *pc = top->ret_pc;
   1153       *limit = top->code->end - top->code->start;
   1154       TRACE("  => pop func#%u @%zu\n", (*code)->function->func_index, *pc);
   1155       DoStackTransfer(dest, arity);
   1156       return true;
   1157     }
   1158   }
   1159 
   1160   void DoCall(InterpreterCode* target, pc_t* pc, pc_t ret_pc, pc_t* limit) {
   1161     PushFrame(target, *pc, ret_pc);
   1162     *pc = frames_.back().ret_pc;
   1163     *limit = target->end - target->start;
   1164   }
   1165 
   1166   // Copies {arity} values on the top of the stack down the stack to {dest},
   1167   // dropping the values in-between.
   1168   void DoStackTransfer(sp_t dest, size_t arity) {
   1169     // before: |---------------| pop_count | arity |
   1170     //         ^ 0             ^ dest              ^ stack_.size()
   1171     //
   1172     // after:  |---------------| arity |
   1173     //         ^ 0                     ^ stack_.size()
   1174     DCHECK_LE(dest, stack_.size());
   1175     DCHECK_LE(dest + arity, stack_.size());
   1176     size_t pop_count = stack_.size() - dest - arity;
   1177     for (size_t i = 0; i < arity; i++) {
   1178       stack_[dest + i] = stack_[dest + pop_count + i];
   1179     }
   1180     stack_.resize(stack_.size() - pop_count);
   1181   }
   1182 
   1183   template <typename ctype, typename mtype>
   1184   bool ExecuteLoad(Decoder* decoder, InterpreterCode* code, pc_t pc, int& len) {
   1185     MemoryAccessOperand operand(decoder, code->at(pc), sizeof(ctype));
   1186     uint32_t index = Pop().to<uint32_t>();
   1187     size_t effective_mem_size = instance()->mem_size - sizeof(mtype);
   1188     if (operand.offset > effective_mem_size ||
   1189         index > (effective_mem_size - operand.offset)) {
   1190       DoTrap(kTrapMemOutOfBounds, pc);
   1191       return false;
   1192     }
   1193     byte* addr = instance()->mem_start + operand.offset + index;
   1194     WasmVal result(static_cast<ctype>(ReadLittleEndianValue<mtype>(addr)));
   1195 
   1196     Push(pc, result);
   1197     len = 1 + operand.length;
   1198     return true;
   1199   }
   1200 
   1201   template <typename ctype, typename mtype>
   1202   bool ExecuteStore(Decoder* decoder, InterpreterCode* code, pc_t pc,
   1203                     int& len) {
   1204     MemoryAccessOperand operand(decoder, code->at(pc), sizeof(ctype));
   1205     WasmVal val = Pop();
   1206 
   1207     uint32_t index = Pop().to<uint32_t>();
   1208     size_t effective_mem_size = instance()->mem_size - sizeof(mtype);
   1209     if (operand.offset > effective_mem_size ||
   1210         index > (effective_mem_size - operand.offset)) {
   1211       DoTrap(kTrapMemOutOfBounds, pc);
   1212       return false;
   1213     }
   1214     byte* addr = instance()->mem_start + operand.offset + index;
   1215     WriteLittleEndianValue<mtype>(addr, static_cast<mtype>(val.to<ctype>()));
   1216     len = 1 + operand.length;
   1217 
   1218     if (std::is_same<float, ctype>::value) {
   1219       possible_nondeterminism_ |= std::isnan(val.to<float>());
   1220     } else if (std::is_same<double, ctype>::value) {
   1221       possible_nondeterminism_ |= std::isnan(val.to<double>());
   1222     }
   1223     return true;
   1224   }
   1225 
   1226   void Execute(InterpreterCode* code, pc_t pc, int max) {
   1227     Decoder decoder(code->start, code->end);
   1228     pc_t limit = code->end - code->start;
   1229     while (--max >= 0) {
   1230 #define PAUSE_IF_BREAK_FLAG(flag) \
   1231   if (V8_UNLIKELY(break_flags_ & WasmInterpreter::BreakFlag::flag)) max = 0;
   1232 
   1233       DCHECK_GT(limit, pc);
   1234 
   1235       const char* skip = "        ";
   1236       int len = 1;
   1237       byte opcode = code->start[pc];
   1238       byte orig = opcode;
   1239       if (V8_UNLIKELY(opcode == kInternalBreakpoint)) {
   1240         orig = code->orig_start[pc];
   1241         if (SkipBreakpoint(code, pc)) {
   1242           // skip breakpoint by switching on original code.
   1243           skip = "[skip]  ";
   1244         } else {
   1245           TRACE("@%-3zu: [break] %-24s:", pc,
   1246                 WasmOpcodes::OpcodeName(static_cast<WasmOpcode>(orig)));
   1247           TraceValueStack();
   1248           TRACE("\n");
   1249           break;
   1250         }
   1251       }
   1252 
   1253       USE(skip);
   1254       TRACE("@%-3zu: %s%-24s:", pc, skip,
   1255             WasmOpcodes::OpcodeName(static_cast<WasmOpcode>(orig)));
   1256       TraceValueStack();
   1257       TRACE("\n");
   1258 
   1259       switch (orig) {
   1260         case kExprNop:
   1261           break;
   1262         case kExprBlock: {
   1263           BlockTypeOperand operand(&decoder, code->at(pc));
   1264           blocks_.push_back({pc, stack_.size(), frames_.size(), operand.arity});
   1265           len = 1 + operand.length;
   1266           break;
   1267         }
   1268         case kExprLoop: {
   1269           BlockTypeOperand operand(&decoder, code->at(pc));
   1270           blocks_.push_back({pc, stack_.size(), frames_.size(), 0});
   1271           len = 1 + operand.length;
   1272           break;
   1273         }
   1274         case kExprIf: {
   1275           BlockTypeOperand operand(&decoder, code->at(pc));
   1276           WasmVal cond = Pop();
   1277           bool is_true = cond.to<uint32_t>() != 0;
   1278           blocks_.push_back({pc, stack_.size(), frames_.size(), operand.arity});
   1279           if (is_true) {
   1280             // fall through to the true block.
   1281             len = 1 + operand.length;
   1282             TRACE("  true => fallthrough\n");
   1283           } else {
   1284             len = LookupTarget(code, pc);
   1285             TRACE("  false => @%zu\n", pc + len);
   1286           }
   1287           break;
   1288         }
   1289         case kExprElse: {
   1290           blocks_.pop_back();
   1291           len = LookupTarget(code, pc);
   1292           TRACE("  end => @%zu\n", pc + len);
   1293           break;
   1294         }
   1295         case kExprSelect: {
   1296           WasmVal cond = Pop();
   1297           WasmVal fval = Pop();
   1298           WasmVal tval = Pop();
   1299           Push(pc, cond.to<int32_t>() != 0 ? tval : fval);
   1300           break;
   1301         }
   1302         case kExprBr: {
   1303           BreakDepthOperand operand(&decoder, code->at(pc));
   1304           len = DoBreak(code, pc, operand.depth);
   1305           TRACE("  br => @%zu\n", pc + len);
   1306           break;
   1307         }
   1308         case kExprBrIf: {
   1309           BreakDepthOperand operand(&decoder, code->at(pc));
   1310           WasmVal cond = Pop();
   1311           bool is_true = cond.to<uint32_t>() != 0;
   1312           if (is_true) {
   1313             len = DoBreak(code, pc, operand.depth);
   1314             TRACE("  br_if => @%zu\n", pc + len);
   1315           } else {
   1316             TRACE("  false => fallthrough\n");
   1317             len = 1 + operand.length;
   1318           }
   1319           break;
   1320         }
   1321         case kExprBrTable: {
   1322           BranchTableOperand operand(&decoder, code->at(pc));
   1323           BranchTableIterator iterator(&decoder, operand);
   1324           uint32_t key = Pop().to<uint32_t>();
   1325           uint32_t depth = 0;
   1326           if (key >= operand.table_count) key = operand.table_count;
   1327           for (uint32_t i = 0; i <= key; i++) {
   1328             DCHECK(iterator.has_next());
   1329             depth = iterator.next();
   1330           }
   1331           len = key + DoBreak(code, pc + key, static_cast<size_t>(depth));
   1332           TRACE("  br[%u] => @%zu\n", key, pc + key + len);
   1333           break;
   1334         }
   1335         case kExprReturn: {
   1336           size_t arity = code->function->sig->return_count();
   1337           if (!DoReturn(&code, &pc, &limit, arity)) return;
   1338           decoder.Reset(code->start, code->end);
   1339           PAUSE_IF_BREAK_FLAG(AfterReturn);
   1340           continue;
   1341         }
   1342         case kExprUnreachable: {
   1343           DoTrap(kTrapUnreachable, pc);
   1344           return CommitPc(pc);
   1345         }
   1346         case kExprEnd: {
   1347           blocks_.pop_back();
   1348           break;
   1349         }
   1350         case kExprI32Const: {
   1351           ImmI32Operand operand(&decoder, code->at(pc));
   1352           Push(pc, WasmVal(operand.value));
   1353           len = 1 + operand.length;
   1354           break;
   1355         }
   1356         case kExprI64Const: {
   1357           ImmI64Operand operand(&decoder, code->at(pc));
   1358           Push(pc, WasmVal(operand.value));
   1359           len = 1 + operand.length;
   1360           break;
   1361         }
   1362         case kExprF32Const: {
   1363           ImmF32Operand operand(&decoder, code->at(pc));
   1364           Push(pc, WasmVal(operand.value));
   1365           len = 1 + operand.length;
   1366           break;
   1367         }
   1368         case kExprF64Const: {
   1369           ImmF64Operand operand(&decoder, code->at(pc));
   1370           Push(pc, WasmVal(operand.value));
   1371           len = 1 + operand.length;
   1372           break;
   1373         }
   1374         case kExprGetLocal: {
   1375           LocalIndexOperand operand(&decoder, code->at(pc));
   1376           Push(pc, stack_[frames_.back().sp + operand.index]);
   1377           len = 1 + operand.length;
   1378           break;
   1379         }
   1380         case kExprSetLocal: {
   1381           LocalIndexOperand operand(&decoder, code->at(pc));
   1382           WasmVal val = Pop();
   1383           stack_[frames_.back().sp + operand.index] = val;
   1384           len = 1 + operand.length;
   1385           break;
   1386         }
   1387         case kExprTeeLocal: {
   1388           LocalIndexOperand operand(&decoder, code->at(pc));
   1389           WasmVal val = Pop();
   1390           stack_[frames_.back().sp + operand.index] = val;
   1391           Push(pc, val);
   1392           len = 1 + operand.length;
   1393           break;
   1394         }
   1395         case kExprDrop: {
   1396           Pop();
   1397           break;
   1398         }
   1399         case kExprCallFunction: {
   1400           CallFunctionOperand operand(&decoder, code->at(pc));
   1401           InterpreterCode* target = codemap()->GetCode(operand.index);
   1402           DoCall(target, &pc, pc + 1 + operand.length, &limit);
   1403           code = target;
   1404           decoder.Reset(code->start, code->end);
   1405           PAUSE_IF_BREAK_FLAG(AfterCall);
   1406           continue;
   1407         }
   1408         case kExprCallIndirect: {
   1409           CallIndirectOperand operand(&decoder, code->at(pc));
   1410           uint32_t entry_index = Pop().to<uint32_t>();
   1411           // Assume only one table for now.
   1412           DCHECK_LE(module()->function_tables.size(), 1u);
   1413           InterpreterCode* target = codemap()->GetIndirectCode(0, entry_index);
   1414           if (target == nullptr) {
   1415             return DoTrap(kTrapFuncInvalid, pc);
   1416           } else if (target->function->sig_index != operand.index) {
   1417             // If not an exact match, we have to do a canonical check.
   1418             // TODO(titzer): make this faster with some kind of caching?
   1419             const WasmIndirectFunctionTable* table =
   1420                 &module()->function_tables[0];
   1421             int function_key = table->map.Find(target->function->sig);
   1422             if (function_key < 0 ||
   1423                 (function_key !=
   1424                  table->map.Find(module()->signatures[operand.index]))) {
   1425               return DoTrap(kTrapFuncSigMismatch, pc);
   1426             }
   1427           }
   1428 
   1429           DoCall(target, &pc, pc + 1 + operand.length, &limit);
   1430           code = target;
   1431           decoder.Reset(code->start, code->end);
   1432           PAUSE_IF_BREAK_FLAG(AfterCall);
   1433           continue;
   1434         }
   1435         case kExprGetGlobal: {
   1436           GlobalIndexOperand operand(&decoder, code->at(pc));
   1437           const WasmGlobal* global = &module()->globals[operand.index];
   1438           byte* ptr = instance()->globals_start + global->offset;
   1439           ValueType type = global->type;
   1440           WasmVal val;
   1441           if (type == kWasmI32) {
   1442             val = WasmVal(*reinterpret_cast<int32_t*>(ptr));
   1443           } else if (type == kWasmI64) {
   1444             val = WasmVal(*reinterpret_cast<int64_t*>(ptr));
   1445           } else if (type == kWasmF32) {
   1446             val = WasmVal(*reinterpret_cast<float*>(ptr));
   1447           } else if (type == kWasmF64) {
   1448             val = WasmVal(*reinterpret_cast<double*>(ptr));
   1449           } else {
   1450             UNREACHABLE();
   1451           }
   1452           Push(pc, val);
   1453           len = 1 + operand.length;
   1454           break;
   1455         }
   1456         case kExprSetGlobal: {
   1457           GlobalIndexOperand operand(&decoder, code->at(pc));
   1458           const WasmGlobal* global = &module()->globals[operand.index];
   1459           byte* ptr = instance()->globals_start + global->offset;
   1460           ValueType type = global->type;
   1461           WasmVal val = Pop();
   1462           if (type == kWasmI32) {
   1463             *reinterpret_cast<int32_t*>(ptr) = val.to<int32_t>();
   1464           } else if (type == kWasmI64) {
   1465             *reinterpret_cast<int64_t*>(ptr) = val.to<int64_t>();
   1466           } else if (type == kWasmF32) {
   1467             *reinterpret_cast<float*>(ptr) = val.to<float>();
   1468           } else if (type == kWasmF64) {
   1469             *reinterpret_cast<double*>(ptr) = val.to<double>();
   1470           } else {
   1471             UNREACHABLE();
   1472           }
   1473           len = 1 + operand.length;
   1474           break;
   1475         }
   1476 
   1477 #define LOAD_CASE(name, ctype, mtype)                                \
   1478   case kExpr##name: {                                                \
   1479     if (!ExecuteLoad<ctype, mtype>(&decoder, code, pc, len)) return; \
   1480     break;                                                           \
   1481   }
   1482 
   1483           LOAD_CASE(I32LoadMem8S, int32_t, int8_t);
   1484           LOAD_CASE(I32LoadMem8U, int32_t, uint8_t);
   1485           LOAD_CASE(I32LoadMem16S, int32_t, int16_t);
   1486           LOAD_CASE(I32LoadMem16U, int32_t, uint16_t);
   1487           LOAD_CASE(I64LoadMem8S, int64_t, int8_t);
   1488           LOAD_CASE(I64LoadMem8U, int64_t, uint8_t);
   1489           LOAD_CASE(I64LoadMem16S, int64_t, int16_t);
   1490           LOAD_CASE(I64LoadMem16U, int64_t, uint16_t);
   1491           LOAD_CASE(I64LoadMem32S, int64_t, int32_t);
   1492           LOAD_CASE(I64LoadMem32U, int64_t, uint32_t);
   1493           LOAD_CASE(I32LoadMem, int32_t, int32_t);
   1494           LOAD_CASE(I64LoadMem, int64_t, int64_t);
   1495           LOAD_CASE(F32LoadMem, float, float);
   1496           LOAD_CASE(F64LoadMem, double, double);
   1497 #undef LOAD_CASE
   1498 
   1499 #define STORE_CASE(name, ctype, mtype)                                \
   1500   case kExpr##name: {                                                 \
   1501     if (!ExecuteStore<ctype, mtype>(&decoder, code, pc, len)) return; \
   1502     break;                                                            \
   1503   }
   1504 
   1505           STORE_CASE(I32StoreMem8, int32_t, int8_t);
   1506           STORE_CASE(I32StoreMem16, int32_t, int16_t);
   1507           STORE_CASE(I64StoreMem8, int64_t, int8_t);
   1508           STORE_CASE(I64StoreMem16, int64_t, int16_t);
   1509           STORE_CASE(I64StoreMem32, int64_t, int32_t);
   1510           STORE_CASE(I32StoreMem, int32_t, int32_t);
   1511           STORE_CASE(I64StoreMem, int64_t, int64_t);
   1512           STORE_CASE(F32StoreMem, float, float);
   1513           STORE_CASE(F64StoreMem, double, double);
   1514 #undef STORE_CASE
   1515 
   1516 #define ASMJS_LOAD_CASE(name, ctype, mtype, defval)                 \
   1517   case kExpr##name: {                                               \
   1518     uint32_t index = Pop().to<uint32_t>();                          \
   1519     ctype result;                                                   \
   1520     if (index >= (instance()->mem_size - sizeof(mtype))) {          \
   1521       result = defval;                                              \
   1522     } else {                                                        \
   1523       byte* addr = instance()->mem_start + index;                   \
   1524       /* TODO(titzer): alignment for asmjs load mem? */             \
   1525       result = static_cast<ctype>(*reinterpret_cast<mtype*>(addr)); \
   1526     }                                                               \
   1527     Push(pc, WasmVal(result));                                      \
   1528     break;                                                          \
   1529   }
   1530           ASMJS_LOAD_CASE(I32AsmjsLoadMem8S, int32_t, int8_t, 0);
   1531           ASMJS_LOAD_CASE(I32AsmjsLoadMem8U, int32_t, uint8_t, 0);
   1532           ASMJS_LOAD_CASE(I32AsmjsLoadMem16S, int32_t, int16_t, 0);
   1533           ASMJS_LOAD_CASE(I32AsmjsLoadMem16U, int32_t, uint16_t, 0);
   1534           ASMJS_LOAD_CASE(I32AsmjsLoadMem, int32_t, int32_t, 0);
   1535           ASMJS_LOAD_CASE(F32AsmjsLoadMem, float, float,
   1536                           std::numeric_limits<float>::quiet_NaN());
   1537           ASMJS_LOAD_CASE(F64AsmjsLoadMem, double, double,
   1538                           std::numeric_limits<double>::quiet_NaN());
   1539 #undef ASMJS_LOAD_CASE
   1540 
   1541 #define ASMJS_STORE_CASE(name, ctype, mtype)                                   \
   1542   case kExpr##name: {                                                          \
   1543     WasmVal val = Pop();                                                       \
   1544     uint32_t index = Pop().to<uint32_t>();                                     \
   1545     if (index < (instance()->mem_size - sizeof(mtype))) {                      \
   1546       byte* addr = instance()->mem_start + index;                              \
   1547       /* TODO(titzer): alignment for asmjs store mem? */                       \
   1548       *(reinterpret_cast<mtype*>(addr)) = static_cast<mtype>(val.to<ctype>()); \
   1549     }                                                                          \
   1550     Push(pc, val);                                                             \
   1551     break;                                                                     \
   1552   }
   1553 
   1554           ASMJS_STORE_CASE(I32AsmjsStoreMem8, int32_t, int8_t);
   1555           ASMJS_STORE_CASE(I32AsmjsStoreMem16, int32_t, int16_t);
   1556           ASMJS_STORE_CASE(I32AsmjsStoreMem, int32_t, int32_t);
   1557           ASMJS_STORE_CASE(F32AsmjsStoreMem, float, float);
   1558           ASMJS_STORE_CASE(F64AsmjsStoreMem, double, double);
   1559 #undef ASMJS_STORE_CASE
   1560         case kExprGrowMemory: {
   1561           MemoryIndexOperand operand(&decoder, code->at(pc));
   1562           uint32_t delta_pages = Pop().to<uint32_t>();
   1563           Push(pc, WasmVal(ExecuteGrowMemory(delta_pages, instance())));
   1564           len = 1 + operand.length;
   1565           break;
   1566         }
   1567         case kExprMemorySize: {
   1568           MemoryIndexOperand operand(&decoder, code->at(pc));
   1569           Push(pc, WasmVal(static_cast<uint32_t>(instance()->mem_size /
   1570                                                  WasmModule::kPageSize)));
   1571           len = 1 + operand.length;
   1572           break;
   1573         }
   1574         // We need to treat kExprI32ReinterpretF32 and kExprI64ReinterpretF64
   1575         // specially to guarantee that the quiet bit of a NaN is preserved on
   1576         // ia32 by the reinterpret casts.
   1577         case kExprI32ReinterpretF32: {
   1578           WasmVal val = Pop();
   1579           WasmVal result(ExecuteI32ReinterpretF32(val));
   1580           Push(pc, result);
   1581           possible_nondeterminism_ |= std::isnan(val.to<float>());
   1582           break;
   1583         }
   1584         case kExprI64ReinterpretF64: {
   1585           WasmVal val = Pop();
   1586           WasmVal result(ExecuteI64ReinterpretF64(val));
   1587           Push(pc, result);
   1588           possible_nondeterminism_ |= std::isnan(val.to<double>());
   1589           break;
   1590         }
   1591 #define EXECUTE_SIMPLE_BINOP(name, ctype, op)             \
   1592   case kExpr##name: {                                     \
   1593     WasmVal rval = Pop();                                 \
   1594     WasmVal lval = Pop();                                 \
   1595     WasmVal result(lval.to<ctype>() op rval.to<ctype>()); \
   1596     Push(pc, result);                                     \
   1597     break;                                                \
   1598   }
   1599           FOREACH_SIMPLE_BINOP(EXECUTE_SIMPLE_BINOP)
   1600 #undef EXECUTE_SIMPLE_BINOP
   1601 
   1602 #define EXECUTE_OTHER_BINOP(name, ctype)              \
   1603   case kExpr##name: {                                 \
   1604     TrapReason trap = kTrapCount;                     \
   1605     volatile ctype rval = Pop().to<ctype>();          \
   1606     volatile ctype lval = Pop().to<ctype>();          \
   1607     WasmVal result(Execute##name(lval, rval, &trap)); \
   1608     if (trap != kTrapCount) return DoTrap(trap, pc);  \
   1609     Push(pc, result);                                 \
   1610     break;                                            \
   1611   }
   1612           FOREACH_OTHER_BINOP(EXECUTE_OTHER_BINOP)
   1613 #undef EXECUTE_OTHER_BINOP
   1614 
   1615         case kExprF32CopySign: {
   1616           // Handle kExprF32CopySign separately because it may introduce
   1617           // observable non-determinism.
   1618           TrapReason trap = kTrapCount;
   1619           volatile float rval = Pop().to<float>();
   1620           volatile float lval = Pop().to<float>();
   1621           WasmVal result(ExecuteF32CopySign(lval, rval, &trap));
   1622           Push(pc, result);
   1623           possible_nondeterminism_ |= std::isnan(rval);
   1624           break;
   1625         }
   1626         case kExprF64CopySign: {
   1627           // Handle kExprF32CopySign separately because it may introduce
   1628           // observable non-determinism.
   1629           TrapReason trap = kTrapCount;
   1630           volatile double rval = Pop().to<double>();
   1631           volatile double lval = Pop().to<double>();
   1632           WasmVal result(ExecuteF64CopySign(lval, rval, &trap));
   1633           Push(pc, result);
   1634           possible_nondeterminism_ |= std::isnan(rval);
   1635           break;
   1636         }
   1637 #define EXECUTE_OTHER_UNOP(name, ctype)              \
   1638   case kExpr##name: {                                \
   1639     TrapReason trap = kTrapCount;                    \
   1640     volatile ctype val = Pop().to<ctype>();          \
   1641     WasmVal result(Execute##name(val, &trap));       \
   1642     if (trap != kTrapCount) return DoTrap(trap, pc); \
   1643     Push(pc, result);                                \
   1644     break;                                           \
   1645   }
   1646           FOREACH_OTHER_UNOP(EXECUTE_OTHER_UNOP)
   1647 #undef EXECUTE_OTHER_UNOP
   1648 
   1649         default:
   1650           V8_Fatal(__FILE__, __LINE__, "Unknown or unimplemented opcode #%d:%s",
   1651                    code->start[pc], OpcodeName(code->start[pc]));
   1652           UNREACHABLE();
   1653       }
   1654 
   1655       pc += len;
   1656       if (pc == limit) {
   1657         // Fell off end of code; do an implicit return.
   1658         TRACE("@%-3zu: ImplicitReturn\n", pc);
   1659         if (!DoReturn(&code, &pc, &limit, code->function->sig->return_count()))
   1660           return;
   1661         decoder.Reset(code->start, code->end);
   1662         PAUSE_IF_BREAK_FLAG(AfterReturn);
   1663       }
   1664     }
   1665     // Set break_pc_, even though we might have stopped because max was reached.
   1666     // We don't want to stop after executing zero instructions next time.
   1667     break_pc_ = pc;
   1668     state_ = WasmInterpreter::PAUSED;
   1669     CommitPc(pc);
   1670   }
   1671 
   1672   WasmVal Pop() {
   1673     DCHECK_GT(stack_.size(), 0);
   1674     DCHECK_GT(frames_.size(), 0);
   1675     DCHECK_GT(stack_.size(), frames_.back().llimit());  // can't pop into locals
   1676     WasmVal val = stack_.back();
   1677     stack_.pop_back();
   1678     return val;
   1679   }
   1680 
   1681   void PopN(int n) {
   1682     DCHECK_GE(stack_.size(), n);
   1683     DCHECK_GT(frames_.size(), 0);
   1684     size_t nsize = stack_.size() - n;
   1685     DCHECK_GE(nsize, frames_.back().llimit());  // can't pop into locals
   1686     stack_.resize(nsize);
   1687   }
   1688 
   1689   WasmVal PopArity(size_t arity) {
   1690     if (arity == 0) return WasmVal();
   1691     CHECK_EQ(1, arity);
   1692     return Pop();
   1693   }
   1694 
   1695   void Push(pc_t pc, WasmVal val) {
   1696     // TODO(titzer): store PC as well?
   1697     if (val.type != kWasmStmt) stack_.push_back(val);
   1698   }
   1699 
   1700   void TraceStack(const char* phase, pc_t pc) {
   1701     if (FLAG_trace_wasm_interpreter) {
   1702       PrintF("%s @%zu", phase, pc);
   1703       UNIMPLEMENTED();
   1704       PrintF("\n");
   1705     }
   1706   }
   1707 
   1708   void TraceValueStack() {
   1709 #ifdef DEBUG
   1710     Frame* top = frames_.size() > 0 ? &frames_.back() : nullptr;
   1711     sp_t sp = top ? top->sp : 0;
   1712     sp_t plimit = top ? top->plimit() : 0;
   1713     sp_t llimit = top ? top->llimit() : 0;
   1714     if (FLAG_trace_wasm_interpreter) {
   1715       for (size_t i = sp; i < stack_.size(); ++i) {
   1716         if (i < plimit)
   1717           PrintF(" p%zu:", i);
   1718         else if (i < llimit)
   1719           PrintF(" l%zu:", i);
   1720         else
   1721           PrintF(" s%zu:", i);
   1722         WasmVal val = stack_[i];
   1723         switch (val.type) {
   1724           case kWasmI32:
   1725             PrintF("i32:%d", val.to<int32_t>());
   1726             break;
   1727           case kWasmI64:
   1728             PrintF("i64:%" PRId64 "", val.to<int64_t>());
   1729             break;
   1730           case kWasmF32:
   1731             PrintF("f32:%f", val.to<float>());
   1732             break;
   1733           case kWasmF64:
   1734             PrintF("f64:%lf", val.to<double>());
   1735             break;
   1736           case kWasmStmt:
   1737             PrintF("void");
   1738             break;
   1739           default:
   1740             UNREACHABLE();
   1741             break;
   1742         }
   1743       }
   1744     }
   1745 #endif  // DEBUG
   1746   }
   1747 };
   1748 
   1749 // Converters between WasmInterpreter::Thread and WasmInterpreter::ThreadImpl.
   1750 // Thread* is the public interface, without knowledge of the object layout.
   1751 // This cast is potentially risky, but as long as we always cast it back before
   1752 // accessing any data, it should be fine. UBSan is not complaining.
   1753 WasmInterpreter::Thread* ToThread(ThreadImpl* impl) {
   1754   return reinterpret_cast<WasmInterpreter::Thread*>(impl);
   1755 }
   1756 static ThreadImpl* ToImpl(WasmInterpreter::Thread* thread) {
   1757   return reinterpret_cast<ThreadImpl*>(thread);
   1758 }
   1759 }  // namespace
   1760 
   1761 //============================================================================
   1762 // Implementation of the pimpl idiom for WasmInterpreter::Thread.
   1763 // Instead of placing a pointer to the ThreadImpl inside of the Thread object,
   1764 // we just reinterpret_cast them. ThreadImpls are only allocated inside this
   1765 // translation unit anyway.
   1766 //============================================================================
   1767 WasmInterpreter::State WasmInterpreter::Thread::state() {
   1768   return ToImpl(this)->state();
   1769 }
   1770 void WasmInterpreter::Thread::PushFrame(const WasmFunction* function,
   1771                                         WasmVal* args) {
   1772   return ToImpl(this)->PushFrame(function, args);
   1773 }
   1774 WasmInterpreter::State WasmInterpreter::Thread::Run() {
   1775   return ToImpl(this)->Run();
   1776 }
   1777 WasmInterpreter::State WasmInterpreter::Thread::Step() {
   1778   return ToImpl(this)->Step();
   1779 }
   1780 void WasmInterpreter::Thread::Pause() { return ToImpl(this)->Pause(); }
   1781 void WasmInterpreter::Thread::Reset() { return ToImpl(this)->Reset(); }
   1782 pc_t WasmInterpreter::Thread::GetBreakpointPc() {
   1783   return ToImpl(this)->GetBreakpointPc();
   1784 }
   1785 int WasmInterpreter::Thread::GetFrameCount() {
   1786   return ToImpl(this)->GetFrameCount();
   1787 }
   1788 const InterpretedFrame WasmInterpreter::Thread::GetFrame(int index) {
   1789   return GetMutableFrame(index);
   1790 }
   1791 InterpretedFrame WasmInterpreter::Thread::GetMutableFrame(int index) {
   1792   // We have access to the constructor of InterpretedFrame, but ThreadImpl has
   1793   // not. So pass it as a lambda (should all get inlined).
   1794   auto frame_cons = [](const WasmFunction* function, int pc, int fp, int sp) {
   1795     return InterpretedFrame(function, pc, fp, sp);
   1796   };
   1797   return ToImpl(this)->GetMutableFrame(index, frame_cons);
   1798 }
   1799 WasmVal WasmInterpreter::Thread::GetReturnValue(int index) {
   1800   return ToImpl(this)->GetReturnValue(index);
   1801 }
   1802 bool WasmInterpreter::Thread::PossibleNondeterminism() {
   1803   return ToImpl(this)->PossibleNondeterminism();
   1804 }
   1805 uint64_t WasmInterpreter::Thread::NumInterpretedCalls() {
   1806   return ToImpl(this)->NumInterpretedCalls();
   1807 }
   1808 void WasmInterpreter::Thread::AddBreakFlags(uint8_t flags) {
   1809   ToImpl(this)->AddBreakFlags(flags);
   1810 }
   1811 void WasmInterpreter::Thread::ClearBreakFlags() {
   1812   ToImpl(this)->ClearBreakFlags();
   1813 }
   1814 
   1815 //============================================================================
   1816 // The implementation details of the interpreter.
   1817 //============================================================================
   1818 class WasmInterpreterInternals : public ZoneObject {
   1819  public:
   1820   WasmInstance* instance_;
   1821   // Create a copy of the module bytes for the interpreter, since the passed
   1822   // pointer might be invalidated after constructing the interpreter.
   1823   const ZoneVector<uint8_t> module_bytes_;
   1824   CodeMap codemap_;
   1825   ZoneVector<ThreadImpl> threads_;
   1826 
   1827   WasmInterpreterInternals(Zone* zone, const ModuleBytesEnv& env)
   1828       : instance_(env.module_env.instance),
   1829         module_bytes_(env.wire_bytes.start(), env.wire_bytes.end(), zone),
   1830         codemap_(
   1831             env.module_env.instance ? env.module_env.instance->module : nullptr,
   1832             module_bytes_.data(), zone),
   1833         threads_(zone) {
   1834     threads_.emplace_back(zone, &codemap_, env.module_env.instance);
   1835   }
   1836 
   1837   void Delete() { threads_.clear(); }
   1838 };
   1839 
   1840 //============================================================================
   1841 // Implementation of the public interface of the interpreter.
   1842 //============================================================================
   1843 WasmInterpreter::WasmInterpreter(const ModuleBytesEnv& env,
   1844                                  AccountingAllocator* allocator)
   1845     : zone_(allocator, ZONE_NAME),
   1846       internals_(new (&zone_) WasmInterpreterInternals(&zone_, env)) {}
   1847 
   1848 WasmInterpreter::~WasmInterpreter() { internals_->Delete(); }
   1849 
   1850 void WasmInterpreter::Run() { internals_->threads_[0].Run(); }
   1851 
   1852 void WasmInterpreter::Pause() { internals_->threads_[0].Pause(); }
   1853 
   1854 bool WasmInterpreter::SetBreakpoint(const WasmFunction* function, pc_t pc,
   1855                                     bool enabled) {
   1856   InterpreterCode* code = internals_->codemap_.FindCode(function);
   1857   if (!code) return false;
   1858   size_t size = static_cast<size_t>(code->end - code->start);
   1859   // Check bounds for {pc}.
   1860   if (pc < code->locals.encoded_size || pc >= size) return false;
   1861   // Make a copy of the code before enabling a breakpoint.
   1862   if (enabled && code->orig_start == code->start) {
   1863     code->start = reinterpret_cast<byte*>(zone_.New(size));
   1864     memcpy(code->start, code->orig_start, size);
   1865     code->end = code->start + size;
   1866   }
   1867   bool prev = code->start[pc] == kInternalBreakpoint;
   1868   if (enabled) {
   1869     code->start[pc] = kInternalBreakpoint;
   1870   } else {
   1871     code->start[pc] = code->orig_start[pc];
   1872   }
   1873   return prev;
   1874 }
   1875 
   1876 bool WasmInterpreter::GetBreakpoint(const WasmFunction* function, pc_t pc) {
   1877   InterpreterCode* code = internals_->codemap_.FindCode(function);
   1878   if (!code) return false;
   1879   size_t size = static_cast<size_t>(code->end - code->start);
   1880   // Check bounds for {pc}.
   1881   if (pc < code->locals.encoded_size || pc >= size) return false;
   1882   // Check if a breakpoint is present at that place in the code.
   1883   return code->start[pc] == kInternalBreakpoint;
   1884 }
   1885 
   1886 bool WasmInterpreter::SetTracing(const WasmFunction* function, bool enabled) {
   1887   UNIMPLEMENTED();
   1888   return false;
   1889 }
   1890 
   1891 int WasmInterpreter::GetThreadCount() {
   1892   return 1;  // only one thread for now.
   1893 }
   1894 
   1895 WasmInterpreter::Thread* WasmInterpreter::GetThread(int id) {
   1896   CHECK_EQ(0, id);  // only one thread for now.
   1897   return ToThread(&internals_->threads_[id]);
   1898 }
   1899 
   1900 size_t WasmInterpreter::GetMemorySize() {
   1901   return internals_->instance_->mem_size;
   1902 }
   1903 
   1904 WasmVal WasmInterpreter::ReadMemory(size_t offset) {
   1905   UNIMPLEMENTED();
   1906   return WasmVal();
   1907 }
   1908 
   1909 void WasmInterpreter::WriteMemory(size_t offset, WasmVal val) {
   1910   UNIMPLEMENTED();
   1911 }
   1912 
   1913 int WasmInterpreter::AddFunctionForTesting(const WasmFunction* function) {
   1914   return internals_->codemap_.AddFunction(function, nullptr, nullptr);
   1915 }
   1916 
   1917 bool WasmInterpreter::SetFunctionCodeForTesting(const WasmFunction* function,
   1918                                                 const byte* start,
   1919                                                 const byte* end) {
   1920   return internals_->codemap_.SetFunctionCode(function, start, end);
   1921 }
   1922 
   1923 ControlTransferMap WasmInterpreter::ComputeControlTransfersForTesting(
   1924     Zone* zone, const byte* start, const byte* end) {
   1925   ControlTransfers targets(zone, nullptr, start, end);
   1926   return targets.map_;
   1927 }
   1928 
   1929 //============================================================================
   1930 // Implementation of the frame inspection interface.
   1931 //============================================================================
   1932 int InterpretedFrame::GetParameterCount() const {
   1933   USE(fp_);
   1934   USE(sp_);
   1935   // TODO(clemensh): Return the correct number of parameters.
   1936   return 0;
   1937 }
   1938 
   1939 WasmVal InterpretedFrame::GetLocalVal(int index) const {
   1940   CHECK_GE(index, 0);
   1941   UNIMPLEMENTED();
   1942   WasmVal none;
   1943   none.type = kWasmStmt;
   1944   return none;
   1945 }
   1946 
   1947 WasmVal InterpretedFrame::GetExprVal(int pc) const {
   1948   UNIMPLEMENTED();
   1949   WasmVal none;
   1950   none.type = kWasmStmt;
   1951   return none;
   1952 }
   1953 
   1954 void InterpretedFrame::SetLocalVal(int index, WasmVal val) { UNIMPLEMENTED(); }
   1955 
   1956 void InterpretedFrame::SetExprVal(int pc, WasmVal val) { UNIMPLEMENTED(); }
   1957 
   1958 }  // namespace wasm
   1959 }  // namespace internal
   1960 }  // namespace v8
   1961