LCOV - code coverage report
Current view: top level - src/wasm - wasm-interpreter.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 714 780 91.5 %
Date: 2017-10-20 Functions: 90 106 84.9 %

          Line data    Source code
       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/assembler-inl.h"
      10             : #include "src/compiler/wasm-compiler.h"
      11             : #include "src/conversions.h"
      12             : #include "src/identity-map.h"
      13             : #include "src/objects-inl.h"
      14             : #include "src/utils.h"
      15             : #include "src/wasm/decoder.h"
      16             : #include "src/wasm/function-body-decoder-impl.h"
      17             : #include "src/wasm/function-body-decoder.h"
      18             : #include "src/wasm/memory-tracing.h"
      19             : #include "src/wasm/wasm-external-refs.h"
      20             : #include "src/wasm/wasm-limits.h"
      21             : #include "src/wasm/wasm-module.h"
      22             : #include "src/wasm/wasm-objects-inl.h"
      23             : 
      24             : #include "src/zone/accounting-allocator.h"
      25             : #include "src/zone/zone-containers.h"
      26             : 
      27             : namespace v8 {
      28             : namespace internal {
      29             : namespace wasm {
      30             : 
      31             : #if DEBUG
      32             : #define TRACE(...)                                        \
      33             :   do {                                                    \
      34             :     if (FLAG_trace_wasm_interpreter) PrintF(__VA_ARGS__); \
      35             :   } while (false)
      36             : #else
      37             : #define TRACE(...)
      38             : #endif
      39             : 
      40             : #define FOREACH_INTERNAL_OPCODE(V) V(Breakpoint, 0xFF)
      41             : 
      42             : #define WASM_CTYPES(V) \
      43             :   V(I32, int32_t) V(I64, int64_t) V(F32, float) V(F64, double)
      44             : 
      45             : #define FOREACH_SIMPLE_BINOP(V) \
      46             :   V(I32Add, uint32_t, +)        \
      47             :   V(I32Sub, uint32_t, -)        \
      48             :   V(I32Mul, uint32_t, *)        \
      49             :   V(I32And, uint32_t, &)        \
      50             :   V(I32Ior, uint32_t, |)        \
      51             :   V(I32Xor, uint32_t, ^)        \
      52             :   V(I32Eq, uint32_t, ==)        \
      53             :   V(I32Ne, uint32_t, !=)        \
      54             :   V(I32LtU, uint32_t, <)        \
      55             :   V(I32LeU, uint32_t, <=)       \
      56             :   V(I32GtU, uint32_t, >)        \
      57             :   V(I32GeU, uint32_t, >=)       \
      58             :   V(I32LtS, int32_t, <)         \
      59             :   V(I32LeS, int32_t, <=)        \
      60             :   V(I32GtS, int32_t, >)         \
      61             :   V(I32GeS, int32_t, >=)        \
      62             :   V(I64Add, uint64_t, +)        \
      63             :   V(I64Sub, uint64_t, -)        \
      64             :   V(I64Mul, uint64_t, *)        \
      65             :   V(I64And, uint64_t, &)        \
      66             :   V(I64Ior, uint64_t, |)        \
      67             :   V(I64Xor, uint64_t, ^)        \
      68             :   V(I64Eq, uint64_t, ==)        \
      69             :   V(I64Ne, uint64_t, !=)        \
      70             :   V(I64LtU, uint64_t, <)        \
      71             :   V(I64LeU, uint64_t, <=)       \
      72             :   V(I64GtU, uint64_t, >)        \
      73             :   V(I64GeU, uint64_t, >=)       \
      74             :   V(I64LtS, int64_t, <)         \
      75             :   V(I64LeS, int64_t, <=)        \
      76             :   V(I64GtS, int64_t, >)         \
      77             :   V(I64GeS, int64_t, >=)        \
      78             :   V(F32Add, float, +)           \
      79             :   V(F32Sub, float, -)           \
      80             :   V(F32Eq, float, ==)           \
      81             :   V(F32Ne, float, !=)           \
      82             :   V(F32Lt, float, <)            \
      83             :   V(F32Le, float, <=)           \
      84             :   V(F32Gt, float, >)            \
      85             :   V(F32Ge, float, >=)           \
      86             :   V(F64Add, double, +)          \
      87             :   V(F64Sub, double, -)          \
      88             :   V(F64Eq, double, ==)          \
      89             :   V(F64Ne, double, !=)          \
      90             :   V(F64Lt, double, <)           \
      91             :   V(F64Le, double, <=)          \
      92             :   V(F64Gt, double, >)           \
      93             :   V(F64Ge, double, >=)          \
      94             :   V(F32Mul, float, *)           \
      95             :   V(F64Mul, double, *)          \
      96             :   V(F32Div, float, /)           \
      97             :   V(F64Div, double, /)
      98             : 
      99             : #define FOREACH_OTHER_BINOP(V) \
     100             :   V(I32DivS, int32_t)          \
     101             :   V(I32DivU, uint32_t)         \
     102             :   V(I32RemS, int32_t)          \
     103             :   V(I32RemU, uint32_t)         \
     104             :   V(I32Shl, uint32_t)          \
     105             :   V(I32ShrU, uint32_t)         \
     106             :   V(I32ShrS, int32_t)          \
     107             :   V(I64DivS, int64_t)          \
     108             :   V(I64DivU, uint64_t)         \
     109             :   V(I64RemS, int64_t)          \
     110             :   V(I64RemU, uint64_t)         \
     111             :   V(I64Shl, uint64_t)          \
     112             :   V(I64ShrU, uint64_t)         \
     113             :   V(I64ShrS, int64_t)          \
     114             :   V(I32Ror, int32_t)           \
     115             :   V(I32Rol, int32_t)           \
     116             :   V(I64Ror, int64_t)           \
     117             :   V(I64Rol, int64_t)           \
     118             :   V(F32Min, float)             \
     119             :   V(F32Max, float)             \
     120             :   V(F64Min, double)            \
     121             :   V(F64Max, double)            \
     122             :   V(I32AsmjsDivS, int32_t)     \
     123             :   V(I32AsmjsDivU, uint32_t)    \
     124             :   V(I32AsmjsRemS, int32_t)     \
     125             :   V(I32AsmjsRemU, uint32_t)
     126             : 
     127             : #define FOREACH_OTHER_UNOP(V)    \
     128             :   V(I32Clz, uint32_t)            \
     129             :   V(I32Ctz, uint32_t)            \
     130             :   V(I32Popcnt, uint32_t)         \
     131             :   V(I32Eqz, uint32_t)            \
     132             :   V(I64Clz, uint64_t)            \
     133             :   V(I64Ctz, uint64_t)            \
     134             :   V(I64Popcnt, uint64_t)         \
     135             :   V(I64Eqz, uint64_t)            \
     136             :   V(F32Abs, float)               \
     137             :   V(F32Neg, float)               \
     138             :   V(F32Ceil, float)              \
     139             :   V(F32Floor, float)             \
     140             :   V(F32Trunc, float)             \
     141             :   V(F32NearestInt, float)        \
     142             :   V(F64Abs, double)              \
     143             :   V(F64Neg, double)              \
     144             :   V(F64Ceil, double)             \
     145             :   V(F64Floor, double)            \
     146             :   V(F64Trunc, double)            \
     147             :   V(F64NearestInt, double)       \
     148             :   V(I32SConvertF32, float)       \
     149             :   V(I32SConvertF64, double)      \
     150             :   V(I32UConvertF32, float)       \
     151             :   V(I32UConvertF64, double)      \
     152             :   V(I32ConvertI64, int64_t)      \
     153             :   V(I64SConvertF32, float)       \
     154             :   V(I64SConvertF64, double)      \
     155             :   V(I64UConvertF32, float)       \
     156             :   V(I64UConvertF64, double)      \
     157             :   V(I64SConvertI32, int32_t)     \
     158             :   V(I64UConvertI32, uint32_t)    \
     159             :   V(F32SConvertI32, int32_t)     \
     160             :   V(F32UConvertI32, uint32_t)    \
     161             :   V(F32SConvertI64, int64_t)     \
     162             :   V(F32UConvertI64, uint64_t)    \
     163             :   V(F32ConvertF64, double)       \
     164             :   V(F32ReinterpretI32, int32_t)  \
     165             :   V(F64SConvertI32, int32_t)     \
     166             :   V(F64UConvertI32, uint32_t)    \
     167             :   V(F64SConvertI64, int64_t)     \
     168             :   V(F64UConvertI64, uint64_t)    \
     169             :   V(F64ConvertF32, float)        \
     170             :   V(F64ReinterpretI64, int64_t)  \
     171             :   V(I32AsmjsSConvertF32, float)  \
     172             :   V(I32AsmjsUConvertF32, float)  \
     173             :   V(I32AsmjsSConvertF64, double) \
     174             :   V(I32AsmjsUConvertF64, double) \
     175             :   V(F32Sqrt, float)              \
     176             :   V(F64Sqrt, double)
     177             : 
     178             : namespace {
     179             : 
     180             : // CachedInstanceInfo encapsulates globals and memory buffer runtime information
     181             : // for a wasm instance. The interpreter caches that information when
     182             : // constructed, copying it from the {WasmInstanceObject}. It expects it be
     183             : // notified on changes to it, e.g. {GrowMemory}. We cache it because interpreter
     184             : // perf is sensitive to accesses to this information.
     185             : //
     186             : // TODO(wasm): other runtime information, such as indirect function table, or
     187             : // code table (incl. imports) is currently handled separately. Consider
     188             : // unifying, if possible, with {ModuleEnv}.
     189             : 
     190             : struct CachedInstanceInfo {
     191             :   CachedInstanceInfo(byte* globals, byte* mem, uint32_t size)
     192             :       : globals_start(globals), mem_start(mem), mem_size(size) {}
     193             :   // We do not expect the location of the globals buffer to
     194             :   // change for an instance.
     195             :   byte* const globals_start = nullptr;
     196             :   // The memory buffer may change because of GrowMemory
     197             :   byte* mem_start = nullptr;
     198             :   uint32_t mem_size = 0;
     199             : };
     200             : 
     201             : inline int32_t ExecuteI32DivS(int32_t a, int32_t b, TrapReason* trap) {
     202         972 :   if (b == 0) {
     203             :     *trap = kTrapDivByZero;
     204             :     return 0;
     205             :   }
     206         846 :   if (b == -1 && a == std::numeric_limits<int32_t>::min()) {
     207             :     *trap = kTrapDivUnrepresentable;
     208             :     return 0;
     209             :   }
     210         840 :   return a / b;
     211             : }
     212             : 
     213             : inline uint32_t ExecuteI32DivU(uint32_t a, uint32_t b, TrapReason* trap) {
     214          42 :   if (b == 0) {
     215             :     *trap = kTrapDivByZero;
     216             :     return 0;
     217             :   }
     218          24 :   return a / b;
     219             : }
     220             : 
     221             : inline int32_t ExecuteI32RemS(int32_t a, int32_t b, TrapReason* trap) {
     222          84 :   if (b == 0) {
     223             :     *trap = kTrapRemByZero;
     224             :     return 0;
     225             :   }
     226          48 :   if (b == -1) return 0;
     227          36 :   return a % b;
     228             : }
     229             : 
     230             : inline uint32_t ExecuteI32RemU(uint32_t a, uint32_t b, TrapReason* trap) {
     231          42 :   if (b == 0) {
     232             :     *trap = kTrapRemByZero;
     233             :     return 0;
     234             :   }
     235          24 :   return a % b;
     236             : }
     237             : 
     238             : inline uint32_t ExecuteI32Shl(uint32_t a, uint32_t b, TrapReason* trap) {
     239       20196 :   return a << (b & 0x1f);
     240             : }
     241             : 
     242             : inline uint32_t ExecuteI32ShrU(uint32_t a, uint32_t b, TrapReason* trap) {
     243       20196 :   return a >> (b & 0x1f);
     244             : }
     245             : 
     246             : inline int32_t ExecuteI32ShrS(int32_t a, int32_t b, TrapReason* trap) {
     247       20196 :   return a >> (b & 0x1f);
     248             : }
     249             : 
     250             : inline int64_t ExecuteI64DivS(int64_t a, int64_t b, TrapReason* trap) {
     251       40314 :   if (b == 0) {
     252             :     *trap = kTrapDivByZero;
     253             :     return 0;
     254             :   }
     255       39228 :   if (b == -1 && a == std::numeric_limits<int64_t>::min()) {
     256             :     *trap = kTrapDivUnrepresentable;
     257             :     return 0;
     258             :   }
     259       39222 :   return a / b;
     260             : }
     261             : 
     262             : inline uint64_t ExecuteI64DivU(uint64_t a, uint64_t b, TrapReason* trap) {
     263       39402 :   if (b == 0) {
     264             :     *trap = kTrapDivByZero;
     265             :     return 0;
     266             :   }
     267       38412 :   return a / b;
     268             : }
     269             : 
     270             : inline int64_t ExecuteI64RemS(int64_t a, int64_t b, TrapReason* trap) {
     271       39408 :   if (b == 0) {
     272             :     *trap = kTrapRemByZero;
     273             :     return 0;
     274             :   }
     275       38418 :   if (b == -1) return 0;
     276       37926 :   return a % b;
     277             : }
     278             : 
     279             : inline uint64_t ExecuteI64RemU(uint64_t a, uint64_t b, TrapReason* trap) {
     280       39402 :   if (b == 0) {
     281             :     *trap = kTrapRemByZero;
     282             :     return 0;
     283             :   }
     284       38412 :   return a % b;
     285             : }
     286             : 
     287             : inline uint64_t ExecuteI64Shl(uint64_t a, uint64_t b, TrapReason* trap) {
     288       80688 :   return a << (b & 0x3f);
     289             : }
     290             : 
     291             : inline uint64_t ExecuteI64ShrU(uint64_t a, uint64_t b, TrapReason* trap) {
     292       80688 :   return a >> (b & 0x3f);
     293             : }
     294             : 
     295             : inline int64_t ExecuteI64ShrS(int64_t a, int64_t b, TrapReason* trap) {
     296       80688 :   return a >> (b & 0x3f);
     297             : }
     298             : 
     299             : inline uint32_t ExecuteI32Ror(uint32_t a, uint32_t b, TrapReason* trap) {
     300          24 :   uint32_t shift = (b & 0x1f);
     301          24 :   return (a >> shift) | (a << (32 - shift));
     302             : }
     303             : 
     304             : inline uint32_t ExecuteI32Rol(uint32_t a, uint32_t b, TrapReason* trap) {
     305          24 :   uint32_t shift = (b & 0x1f);
     306          24 :   return (a << shift) | (a >> (32 - shift));
     307             : }
     308             : 
     309             : inline uint64_t ExecuteI64Ror(uint64_t a, uint64_t b, TrapReason* trap) {
     310       39390 :   uint32_t shift = (b & 0x3f);
     311       39390 :   return (a >> shift) | (a << (64 - shift));
     312             : }
     313             : 
     314             : inline uint64_t ExecuteI64Rol(uint64_t a, uint64_t b, TrapReason* trap) {
     315       39390 :   uint32_t shift = (b & 0x3f);
     316       39390 :   return (a << shift) | (a >> (64 - shift));
     317             : }
     318             : 
     319             : inline float ExecuteF32Min(float a, float b, TrapReason* trap) {
     320       79350 :   return JSMin(a, b);
     321             : }
     322             : 
     323             : inline float ExecuteF32Max(float a, float b, TrapReason* trap) {
     324       79350 :   return JSMax(a, b);
     325             : }
     326             : 
     327             : inline float ExecuteF32CopySign(float a, float b, TrapReason* trap) {
     328       79362 :   return copysignf(a, b);
     329             : }
     330             : 
     331             : inline double ExecuteF64Min(double a, double b, TrapReason* trap) {
     332       14406 :   return JSMin(a, b);
     333             : }
     334             : 
     335             : inline double ExecuteF64Max(double a, double b, TrapReason* trap) {
     336       14406 :   return JSMax(a, b);
     337             : }
     338             : 
     339             : inline double ExecuteF64CopySign(double a, double b, TrapReason* trap) {
     340       14418 :   return copysign(a, b);
     341             : }
     342             : 
     343             : inline int32_t ExecuteI32AsmjsDivS(int32_t a, int32_t b, TrapReason* trap) {
     344        3510 :   if (b == 0) return 0;
     345        3144 :   if (b == -1 && a == std::numeric_limits<int32_t>::min()) {
     346             :     return std::numeric_limits<int32_t>::min();
     347             :   }
     348        3132 :   return a / b;
     349             : }
     350             : 
     351             : inline uint32_t ExecuteI32AsmjsDivU(uint32_t a, uint32_t b, TrapReason* trap) {
     352          30 :   if (b == 0) return 0;
     353          12 :   return a / b;
     354             : }
     355             : 
     356             : inline int32_t ExecuteI32AsmjsRemS(int32_t a, int32_t b, TrapReason* trap) {
     357        3510 :   if (b == 0) return 0;
     358        3144 :   if (b == -1) return 0;
     359        2790 :   return a % b;
     360             : }
     361             : 
     362             : inline uint32_t ExecuteI32AsmjsRemU(uint32_t a, uint32_t b, TrapReason* trap) {
     363          30 :   if (b == 0) return 0;
     364          12 :   return a % b;
     365             : }
     366             : 
     367             : inline int32_t ExecuteI32AsmjsSConvertF32(float a, TrapReason* trap) {
     368         690 :   return DoubleToInt32(a);
     369             : }
     370             : 
     371             : inline uint32_t ExecuteI32AsmjsUConvertF32(float a, TrapReason* trap) {
     372         690 :   return DoubleToUint32(a);
     373             : }
     374             : 
     375             : inline int32_t ExecuteI32AsmjsSConvertF64(double a, TrapReason* trap) {
     376         294 :   return DoubleToInt32(a);
     377             : }
     378             : 
     379             : inline uint32_t ExecuteI32AsmjsUConvertF64(double a, TrapReason* trap) {
     380             :   return DoubleToUint32(a);
     381             : }
     382             : 
     383             : int32_t ExecuteI32Clz(uint32_t val, TrapReason* trap) {
     384         396 :   return base::bits::CountLeadingZeros32(val);
     385             : }
     386             : 
     387             : uint32_t ExecuteI32Ctz(uint32_t val, TrapReason* trap) {
     388             :   return base::bits::CountTrailingZeros32(val);
     389             : }
     390             : 
     391             : uint32_t ExecuteI32Popcnt(uint32_t val, TrapReason* trap) {
     392          60 :   return word32_popcnt_wrapper(&val);
     393             : }
     394             : 
     395             : inline uint32_t ExecuteI32Eqz(uint32_t val, TrapReason* trap) {
     396         744 :   return val == 0 ? 1 : 0;
     397             : }
     398             : 
     399             : int64_t ExecuteI64Clz(uint64_t val, TrapReason* trap) {
     400         390 :   return base::bits::CountLeadingZeros64(val);
     401             : }
     402             : 
     403             : inline uint64_t ExecuteI64Ctz(uint64_t val, TrapReason* trap) {
     404         390 :   return base::bits::CountTrailingZeros64(val);
     405             : }
     406             : 
     407             : inline int64_t ExecuteI64Popcnt(uint64_t val, TrapReason* trap) {
     408          60 :   return word64_popcnt_wrapper(&val);
     409             : }
     410             : 
     411             : inline int32_t ExecuteI64Eqz(uint64_t val, TrapReason* trap) {
     412         498 :   return val == 0 ? 1 : 0;
     413             : }
     414             : 
     415             : inline float ExecuteF32Abs(float a, TrapReason* trap) {
     416          24 :   return bit_cast<float>(bit_cast<uint32_t>(a) & 0x7fffffff);
     417             : }
     418             : 
     419             : inline float ExecuteF32Neg(float a, TrapReason* trap) {
     420         702 :   return bit_cast<float>(bit_cast<uint32_t>(a) ^ 0x80000000);
     421             : }
     422             : 
     423         690 : inline float ExecuteF32Ceil(float a, TrapReason* trap) { return ceilf(a); }
     424             : 
     425         690 : inline float ExecuteF32Floor(float a, TrapReason* trap) { return floorf(a); }
     426             : 
     427         690 : inline float ExecuteF32Trunc(float a, TrapReason* trap) { return truncf(a); }
     428             : 
     429             : inline float ExecuteF32NearestInt(float a, TrapReason* trap) {
     430         690 :   return nearbyintf(a);
     431             : }
     432             : 
     433             : inline float ExecuteF32Sqrt(float a, TrapReason* trap) {
     434          12 :   float result = sqrtf(a);
     435             :   return result;
     436             : }
     437             : 
     438             : inline double ExecuteF64Abs(double a, TrapReason* trap) {
     439          24 :   return bit_cast<double>(bit_cast<uint64_t>(a) & 0x7fffffffffffffff);
     440             : }
     441             : 
     442             : inline double ExecuteF64Neg(double a, TrapReason* trap) {
     443         306 :   return bit_cast<double>(bit_cast<uint64_t>(a) ^ 0x8000000000000000);
     444             : }
     445             : 
     446         294 : inline double ExecuteF64Ceil(double a, TrapReason* trap) { return ceil(a); }
     447             : 
     448         294 : inline double ExecuteF64Floor(double a, TrapReason* trap) { return floor(a); }
     449             : 
     450         294 : inline double ExecuteF64Trunc(double a, TrapReason* trap) { return trunc(a); }
     451             : 
     452             : inline double ExecuteF64NearestInt(double a, TrapReason* trap) {
     453         294 :   return nearbyint(a);
     454             : }
     455             : 
     456          12 : inline double ExecuteF64Sqrt(double a, TrapReason* trap) { return sqrt(a); }
     457             : 
     458             : int32_t ExecuteI32SConvertF32(float a, TrapReason* trap) {
     459             :   // The upper bound is (INT32_MAX + 1), which is the lowest float-representable
     460             :   // number above INT32_MAX which cannot be represented as int32.
     461             :   float upper_bound = 2147483648.0f;
     462             :   // We use INT32_MIN as a lower bound because (INT32_MIN - 1) is not
     463             :   // representable as float, and no number between (INT32_MIN - 1) and INT32_MIN
     464             :   // is.
     465             :   float lower_bound = static_cast<float>(INT32_MIN);
     466         792 :   if (a < upper_bound && a >= lower_bound) {
     467         528 :     return static_cast<int32_t>(a);
     468             :   }
     469             :   *trap = kTrapFloatUnrepresentable;
     470             :   return 0;
     471             : }
     472             : 
     473             : int32_t ExecuteI32SConvertF64(double a, TrapReason* trap) {
     474             :   // The upper bound is (INT32_MAX + 1), which is the lowest double-
     475             :   // representable number above INT32_MAX which cannot be represented as int32.
     476             :   double upper_bound = 2147483648.0;
     477             :   // The lower bound is (INT32_MIN - 1), which is the greatest double-
     478             :   // representable number below INT32_MIN which cannot be represented as int32.
     479             :   double lower_bound = -2147483649.0;
     480         396 :   if (a < upper_bound && a > lower_bound) {
     481         300 :     return static_cast<int32_t>(a);
     482             :   }
     483             :   *trap = kTrapFloatUnrepresentable;
     484             :   return 0;
     485             : }
     486             : 
     487             : uint32_t ExecuteI32UConvertF32(float a, TrapReason* trap) {
     488             :   // The upper bound is (UINT32_MAX + 1), which is the lowest
     489             :   // float-representable number above UINT32_MAX which cannot be represented as
     490             :   // uint32.
     491             :   double upper_bound = 4294967296.0f;
     492             :   double lower_bound = -1.0f;
     493         690 :   if (a < upper_bound && a > lower_bound) {
     494         276 :     return static_cast<uint32_t>(a);
     495             :   }
     496             :   *trap = kTrapFloatUnrepresentable;
     497             :   return 0;
     498             : }
     499             : 
     500             : uint32_t ExecuteI32UConvertF64(double a, TrapReason* trap) {
     501             :   // The upper bound is (UINT32_MAX + 1), which is the lowest
     502             :   // double-representable number above UINT32_MAX which cannot be represented as
     503             :   // uint32.
     504             :   double upper_bound = 4294967296.0;
     505             :   double lower_bound = -1.0;
     506         294 :   if (a < upper_bound && a > lower_bound) {
     507         162 :     return static_cast<uint32_t>(a);
     508             :   }
     509             :   *trap = kTrapFloatUnrepresentable;
     510             :   return 0;
     511             : }
     512             : 
     513             : inline uint32_t ExecuteI32ConvertI64(int64_t a, TrapReason* trap) {
     514      236892 :   return static_cast<uint32_t>(a & 0xFFFFFFFF);
     515             : }
     516             : 
     517             : int64_t ExecuteI64SConvertF32(float a, TrapReason* trap) {
     518             :   int64_t output;
     519        1380 :   if (!float32_to_int64_wrapper(&a, &output)) {
     520             :     *trap = kTrapFloatUnrepresentable;
     521             :   }
     522        1380 :   return output;
     523             : }
     524             : 
     525             : int64_t ExecuteI64SConvertF64(double a, TrapReason* trap) {
     526             :   int64_t output;
     527        1084 :   if (!float64_to_int64_wrapper(&a, &output)) {
     528             :     *trap = kTrapFloatUnrepresentable;
     529             :   }
     530        1084 :   return output;
     531             : }
     532             : 
     533             : uint64_t ExecuteI64UConvertF32(float a, TrapReason* trap) {
     534             :   uint64_t output;
     535        1380 :   if (!float32_to_uint64_wrapper(&a, &output)) {
     536             :     *trap = kTrapFloatUnrepresentable;
     537             :   }
     538        1380 :   return output;
     539             : }
     540             : 
     541             : uint64_t ExecuteI64UConvertF64(double a, TrapReason* trap) {
     542             :   uint64_t output;
     543         588 :   if (!float64_to_uint64_wrapper(&a, &output)) {
     544             :     *trap = kTrapFloatUnrepresentable;
     545             :   }
     546         588 :   return output;
     547             : }
     548             : 
     549             : inline int64_t ExecuteI64SConvertI32(int32_t a, TrapReason* trap) {
     550         372 :   return static_cast<int64_t>(a);
     551             : }
     552             : 
     553             : inline int64_t ExecuteI64UConvertI32(uint32_t a, TrapReason* trap) {
     554         348 :   return static_cast<uint64_t>(a);
     555             : }
     556             : 
     557             : inline float ExecuteF32SConvertI32(int32_t a, TrapReason* trap) {
     558          30 :   return static_cast<float>(a);
     559             : }
     560             : 
     561             : inline float ExecuteF32UConvertI32(uint32_t a, TrapReason* trap) {
     562          10 :   return static_cast<float>(a);
     563             : }
     564             : 
     565             : inline float ExecuteF32SConvertI64(int64_t a, TrapReason* trap) {
     566             :   float output;
     567         486 :   int64_to_float32_wrapper(&a, &output);
     568         486 :   return output;
     569             : }
     570             : 
     571             : inline float ExecuteF32UConvertI64(uint64_t a, TrapReason* trap) {
     572             :   float output;
     573         456 :   uint64_to_float32_wrapper(&a, &output);
     574         456 :   return output;
     575             : }
     576             : 
     577             : inline float ExecuteF32ConvertF64(double a, TrapReason* trap) {
     578          10 :   return static_cast<float>(a);
     579             : }
     580             : 
     581             : inline float ExecuteF32ReinterpretI32(int32_t a, TrapReason* trap) {
     582             :   return bit_cast<float>(a);
     583             : }
     584             : 
     585             : inline double ExecuteF64SConvertI32(int32_t a, TrapReason* trap) {
     586        1404 :   return static_cast<double>(a);
     587             : }
     588             : 
     589             : inline double ExecuteF64UConvertI32(uint32_t a, TrapReason* trap) {
     590          10 :   return static_cast<double>(a);
     591             : }
     592             : 
     593             : inline double ExecuteF64SConvertI64(int64_t a, TrapReason* trap) {
     594             :   double output;
     595       23048 :   int64_to_float64_wrapper(&a, &output);
     596       23048 :   return output;
     597             : }
     598             : 
     599             : inline double ExecuteF64UConvertI64(uint64_t a, TrapReason* trap) {
     600             :   double output;
     601         450 :   uint64_to_float64_wrapper(&a, &output);
     602         450 :   return output;
     603             : }
     604             : 
     605             : inline double ExecuteF64ConvertF32(float a, TrapReason* trap) {
     606        2090 :   return static_cast<double>(a);
     607             : }
     608             : 
     609             : inline double ExecuteF64ReinterpretI64(int64_t a, TrapReason* trap) {
     610             :   return bit_cast<double>(a);
     611             : }
     612             : 
     613             : inline int32_t ExecuteI32ReinterpretF32(WasmValue a) {
     614             :   return a.to_unchecked<int32_t>();
     615             : }
     616             : 
     617             : inline int64_t ExecuteI64ReinterpretF64(WasmValue a) {
     618             :   return a.to_unchecked<int64_t>();
     619             : }
     620             : 
     621             : enum InternalOpcode {
     622             : #define DECL_INTERNAL_ENUM(name, value) kInternal##name = value,
     623             :   FOREACH_INTERNAL_OPCODE(DECL_INTERNAL_ENUM)
     624             : #undef DECL_INTERNAL_ENUM
     625             : };
     626             : 
     627             : const char* OpcodeName(uint32_t val) {
     628           0 :   switch (val) {
     629             : #define DECL_INTERNAL_CASE(name, value) \
     630             :   case kInternal##name:                 \
     631             :     return "Internal" #name;
     632             :     FOREACH_INTERNAL_OPCODE(DECL_INTERNAL_CASE)
     633             : #undef DECL_INTERNAL_CASE
     634             :   }
     635           0 :   return WasmOpcodes::OpcodeName(static_cast<WasmOpcode>(val));
     636             : }
     637             : 
     638             : // Unwrap a wasm to js wrapper, return the callable heap object.
     639             : // If the wrapper would throw a TypeError, return a null handle.
     640        6220 : Handle<HeapObject> UnwrapWasmToJSWrapper(Isolate* isolate,
     641             :                                          Handle<Code> js_wrapper) {
     642             :   DCHECK_EQ(Code::WASM_TO_JS_FUNCTION, js_wrapper->kind());
     643             :   Handle<FixedArray> deopt_data(js_wrapper->deoptimization_data(), isolate);
     644             :   DCHECK_EQ(2, deopt_data->length());
     645             :   intptr_t js_imports_table_loc = static_cast<intptr_t>(
     646             :       HeapNumber::cast(deopt_data->get(0))->value_as_bits());
     647             :   Handle<FixedArray> js_imports_table(
     648        6220 :       reinterpret_cast<FixedArray**>(js_imports_table_loc));
     649        6220 :   int index = 0;
     650        6220 :   CHECK(deopt_data->get(1)->ToInt32(&index));
     651             :   DCHECK_GT(js_imports_table->length(), index);
     652        6220 :   Handle<Object> obj(js_imports_table->get(index), isolate);
     653        6220 :   if (obj->IsCallable()) {
     654             :     return Handle<HeapObject>::cast(obj);
     655             :   } else {
     656             :     // If we did not find a callable object, this is an illegal JS import and
     657             :     // obj must be undefined.
     658             :     DCHECK(obj->IsUndefined(isolate));
     659             :     return Handle<HeapObject>::null();
     660             :   }
     661             : }
     662             : 
     663             : class SideTable;
     664             : 
     665             : // Code and metadata needed to execute a function.
     666       59186 : struct InterpreterCode {
     667             :   const WasmFunction* function;  // wasm function
     668             :   BodyLocalDecls locals;         // local declarations
     669             :   const byte* orig_start;        // start of original code
     670             :   const byte* orig_end;          // end of original code
     671             :   byte* start;                   // start of (maybe altered) code
     672             :   byte* end;                     // end of (maybe altered) code
     673             :   SideTable* side_table;         // precomputed side table for control flow.
     674             : 
     675     9226304 :   const byte* at(pc_t pc) { return start + pc; }
     676             : };
     677             : 
     678             : // A helper class to compute the control transfers for each bytecode offset.
     679             : // Control transfers allow Br, BrIf, BrTable, If, Else, and End bytecodes to
     680             : // be directly executed without the need to dynamically track blocks.
     681             : class SideTable : public ZoneObject {
     682             :  public:
     683             :   ControlTransferMap map_;
     684             :   uint32_t max_stack_height_;
     685             : 
     686       40546 :   SideTable(Zone* zone, const WasmModule* module, InterpreterCode* code)
     687       20273 :       : map_(zone), max_stack_height_(0) {
     688             :     // Create a zone for all temporary objects.
     689       20273 :     Zone control_transfer_zone(zone->allocator(), ZONE_NAME);
     690             : 
     691             :     // Represents a control flow label.
     692             :     class CLabel : public ZoneObject {
     693             :       explicit CLabel(Zone* zone, uint32_t target_stack_height, uint32_t arity)
     694             :           : target(nullptr),
     695             :             target_stack_height(target_stack_height),
     696             :             arity(arity),
     697       53185 :             refs(zone) {}
     698             : 
     699             :      public:
     700             :       struct Ref {
     701             :         const byte* from_pc;
     702             :         const uint32_t stack_height;
     703             :       };
     704             :       const byte* target;
     705             :       uint32_t target_stack_height;
     706             :       // Arity when branching to this label.
     707             :       const uint32_t arity;
     708             :       ZoneVector<Ref> refs;
     709             : 
     710       53185 :       static CLabel* New(Zone* zone, uint32_t stack_height, uint32_t arity) {
     711       53185 :         return new (zone) CLabel(zone, stack_height, arity);
     712             :       }
     713             : 
     714             :       // Bind this label to the given PC.
     715             :       void Bind(const byte* pc) {
     716             :         DCHECK_NULL(target);
     717       53185 :         target = pc;
     718             :       }
     719             : 
     720             :       // Reference this label from the given location.
     721             :       void Ref(const byte* from_pc, uint32_t stack_height) {
     722             :         // Target being bound before a reference means this is a loop.
     723             :         DCHECK_IMPLIES(target, *target == kExprLoop);
     724       52646 :         refs.push_back({from_pc, stack_height});
     725             :       }
     726             : 
     727       53185 :       void Finish(ControlTransferMap* map, const byte* start) {
     728             :         DCHECK_NOT_NULL(target);
     729      132693 :         for (auto ref : refs) {
     730       26323 :           size_t offset = static_cast<size_t>(ref.from_pc - start);
     731       26323 :           auto pcdiff = static_cast<pcdiff_t>(target - ref.from_pc);
     732             :           DCHECK_GE(ref.stack_height, target_stack_height);
     733             :           spdiff_t spdiff =
     734       26323 :               static_cast<spdiff_t>(ref.stack_height - target_stack_height);
     735             :           TRACE("control transfer @%zu: Δpc %d, stack %u->%u = -%u\n", offset,
     736             :                 pcdiff, ref.stack_height, target_stack_height, spdiff);
     737       26323 :           ControlTransferEntry& entry = (*map)[offset];
     738       26323 :           entry.pc_diff = pcdiff;
     739       26323 :           entry.sp_diff = spdiff;
     740       26323 :           entry.target_arity = arity;
     741             :         }
     742       53185 :       }
     743             :     };
     744             : 
     745             :     // An entry in the control stack.
     746             :     struct Control {
     747             :       const byte* pc;
     748             :       CLabel* end_label;
     749             :       CLabel* else_label;
     750             :       // Arity (number of values on the stack) when exiting this control
     751             :       // structure via |end|.
     752             :       uint32_t exit_arity;
     753             :       // Track whether this block was already left, i.e. all further
     754             :       // instructions are unreachable.
     755             :       bool unreachable = false;
     756             : 
     757             :       Control(const byte* pc, CLabel* end_label, CLabel* else_label,
     758             :               uint32_t exit_arity)
     759             :           : pc(pc),
     760             :             end_label(end_label),
     761             :             else_label(else_label),
     762       52833 :             exit_arity(exit_arity) {}
     763             :       Control(const byte* pc, CLabel* end_label, uint32_t exit_arity)
     764             :           : Control(pc, end_label, nullptr, exit_arity) {}
     765             : 
     766       52833 :       void Finish(ControlTransferMap* map, const byte* start) {
     767       52833 :         end_label->Finish(map, start);
     768       52833 :         if (else_label) else_label->Finish(map, start);
     769       52833 :       }
     770             :     };
     771             : 
     772             :     // Compute the ControlTransfer map.
     773             :     // This algorithm maintains a stack of control constructs similar to the
     774             :     // AST decoder. The {control_stack} allows matching {br,br_if,br_table}
     775             :     // bytecodes with their target, as well as determining whether the current
     776             :     // bytecodes are within the true or false block of an else.
     777             :     ZoneVector<Control> control_stack(&control_transfer_zone);
     778             :     uint32_t stack_height = 0;
     779             :     uint32_t func_arity =
     780       20273 :         static_cast<uint32_t>(code->function->sig->return_count());
     781             :     CLabel* func_label =
     782       20273 :         CLabel::New(&control_transfer_zone, stack_height, func_arity);
     783       20273 :     control_stack.emplace_back(code->orig_start, func_label, func_arity);
     784             :     auto control_parent = [&]() -> Control& {
     785             :       DCHECK_LE(2, control_stack.size());
     786       65724 :       return control_stack[control_stack.size() - 2];
     787       20273 :     };
     788             :     auto copy_unreachable = [&] {
     789       32711 :       control_stack.back().unreachable = control_parent().unreachable;
     790             :     };
     791      253857 :     for (BytecodeIterator i(code->orig_start, code->orig_end, &code->locals);
     792      213311 :          i.has_next(); i.next()) {
     793             :       WasmOpcode opcode = i.current();
     794      213311 :       bool unreachable = control_stack.back().unreachable;
     795      213311 :       if (unreachable) {
     796             :         TRACE("@%u: %s (is unreachable)\n", i.pc_offset(),
     797             :               WasmOpcodes::OpcodeName(opcode));
     798             :       } else {
     799             :         auto stack_effect =
     800      179323 :             StackEffect(module, code->function->sig, i.pc(), i.end());
     801             :         TRACE("@%u: %s (sp %d - %d + %d)\n", i.pc_offset(),
     802             :               WasmOpcodes::OpcodeName(opcode), stack_height, stack_effect.first,
     803             :               stack_effect.second);
     804             :         DCHECK_GE(stack_height, stack_effect.first);
     805             :         DCHECK_GE(kMaxUInt32, static_cast<uint64_t>(stack_height) -
     806             :                                   stack_effect.first + stack_effect.second);
     807      179323 :         stack_height = stack_height - stack_effect.first + stack_effect.second;
     808      179323 :         if (stack_height > max_stack_height_) max_stack_height_ = stack_height;
     809             :       }
     810      213311 :       switch (opcode) {
     811             :         case kExprBlock:
     812             :         case kExprLoop: {
     813       32208 :           bool is_loop = opcode == kExprLoop;
     814       32208 :           BlockTypeOperand<Decoder::kNoValidate> operand(&i, i.pc());
     815       32208 :           if (operand.type == kWasmVar) {
     816          30 :             operand.sig = module->signatures[operand.sig_index];
     817             :           }
     818             :           TRACE("control @%u: %s, arity %d->%d\n", i.pc_offset(),
     819             :                 is_loop ? "Loop" : "Block",
     820             :                 operand.in_arity(), operand.out_arity());
     821             :           CLabel* label = CLabel::New(&control_transfer_zone, stack_height,
     822             :                                       is_loop ? operand.in_arity()
     823       64416 :                                               : operand.out_arity());
     824       64416 :           control_stack.emplace_back(i.pc(), label, operand.out_arity());
     825             :           copy_unreachable();
     826       32208 :           if (is_loop) label->Bind(i.pc());
     827             :           break;
     828             :         }
     829             :         case kExprIf: {
     830         352 :           BlockTypeOperand<Decoder::kNoValidate> operand(&i, i.pc());
     831         352 :           if (operand.type == kWasmVar) {
     832          12 :             operand.sig = module->signatures[operand.sig_index];
     833             :           }
     834             :           TRACE("control @%u: If, arity %d->%d\n", i.pc_offset(),
     835             :                 operand.in_arity(), operand.out_arity());
     836             :           CLabel* end_label =
     837             :               CLabel::New(&control_transfer_zone, stack_height,
     838         352 :                           operand.out_arity());
     839             :           CLabel* else_label =
     840         352 :               CLabel::New(&control_transfer_zone, stack_height, 0);
     841         352 :           control_stack.emplace_back(i.pc(), end_label, else_label,
     842        1056 :                                      operand.out_arity());
     843             :           copy_unreachable();
     844         352 :           if (!unreachable) else_label->Ref(i.pc(), stack_height);
     845             :           break;
     846             :         }
     847             :         case kExprElse: {
     848             :           Control* c = &control_stack.back();
     849             :           copy_unreachable();
     850             :           TRACE("control @%u: Else\n", i.pc_offset());
     851         151 :           if (!control_parent().unreachable) {
     852         144 :             c->end_label->Ref(i.pc(), stack_height);
     853             :           }
     854             :           DCHECK_NOT_NULL(c->else_label);
     855         151 :           c->else_label->Bind(i.pc() + 1);
     856         151 :           c->else_label->Finish(&map_, code->orig_start);
     857         151 :           c->else_label = nullptr;
     858             :           DCHECK_GE(stack_height, c->end_label->target_stack_height);
     859         151 :           stack_height = c->end_label->target_stack_height;
     860         151 :           break;
     861             :         }
     862             :         case kExprEnd: {
     863       52833 :           Control* c = &control_stack.back();
     864             :           TRACE("control @%u: End\n", i.pc_offset());
     865             :           // Only loops have bound labels.
     866             :           DCHECK_IMPLIES(c->end_label->target, *c->pc == kExprLoop);
     867       52833 :           if (!c->end_label->target) {
     868       52613 :             if (c->else_label) c->else_label->Bind(i.pc());
     869       52613 :             c->end_label->Bind(i.pc() + 1);
     870             :           }
     871      105666 :           c->Finish(&map_, code->orig_start);
     872             :           DCHECK_GE(stack_height, c->end_label->target_stack_height);
     873       52833 :           stack_height = c->end_label->target_stack_height + c->exit_arity;
     874             :           control_stack.pop_back();
     875             :           break;
     876             :         }
     877             :         case kExprBr: {
     878         603 :           BreakDepthOperand<Decoder::kNoValidate> operand(&i, i.pc());
     879             :           TRACE("control @%u: Br[depth=%u]\n", i.pc_offset(), operand.depth);
     880        1206 :           Control* c = &control_stack[control_stack.size() - operand.depth - 1];
     881         603 :           if (!unreachable) c->end_label->Ref(i.pc(), stack_height);
     882             :           break;
     883             :         }
     884             :         case kExprBrIf: {
     885         139 :           BreakDepthOperand<Decoder::kNoValidate> operand(&i, i.pc());
     886             :           TRACE("control @%u: BrIf[depth=%u]\n", i.pc_offset(), operand.depth);
     887         278 :           Control* c = &control_stack[control_stack.size() - operand.depth - 1];
     888         139 :           if (!unreachable) c->end_label->Ref(i.pc(), stack_height);
     889             :           break;
     890             :         }
     891             :         case kExprBrTable: {
     892        6305 :           BranchTableOperand<Decoder::kNoValidate> operand(&i, i.pc());
     893             :           BranchTableIterator<Decoder::kNoValidate> iterator(&i, operand);
     894             :           TRACE("control @%u: BrTable[count=%u]\n", i.pc_offset(),
     895             :                 operand.table_count);
     896        6305 :           if (!unreachable) {
     897       31411 :             while (iterator.has_next()) {
     898       25106 :               uint32_t j = iterator.cur_index();
     899       25106 :               uint32_t target = iterator.next();
     900       50212 :               Control* c = &control_stack[control_stack.size() - target - 1];
     901       25106 :               c->end_label->Ref(i.pc() + j, stack_height);
     902             :             }
     903             :           }
     904             :           break;
     905             :         }
     906             :         default:
     907             :           break;
     908             :       }
     909      213311 :       if (WasmOpcodes::IsUnconditionalJump(opcode)) {
     910       32151 :         control_stack.back().unreachable = true;
     911             :       }
     912             :     }
     913             :     DCHECK_EQ(0, control_stack.size());
     914       20273 :     DCHECK_EQ(func_arity, stack_height);
     915       20273 :   }
     916             : 
     917             :   ControlTransferEntry& Lookup(pc_t from) {
     918             :     auto result = map_.find(from);
     919             :     DCHECK(result != map_.end());
     920             :     return result->second;
     921             :   }
     922             : };
     923             : 
     924             : struct ExternalCallResult {
     925             :   enum Type {
     926             :     // The function should be executed inside this interpreter.
     927             :     INTERNAL,
     928             :     // For indirect calls: Table or function does not exist.
     929             :     INVALID_FUNC,
     930             :     // For indirect calls: Signature does not match expected signature.
     931             :     SIGNATURE_MISMATCH,
     932             :     // The function was executed and returned normally.
     933             :     EXTERNAL_RETURNED,
     934             :     // The function was executed, threw an exception, and the stack was unwound.
     935             :     EXTERNAL_UNWOUND
     936             :   };
     937             :   Type type;
     938             :   // If type is INTERNAL, this field holds the function to call internally.
     939             :   InterpreterCode* interpreter_code;
     940             : 
     941             :   ExternalCallResult(Type type) : type(type) {  // NOLINT
     942             :     DCHECK_NE(INTERNAL, type);
     943             :   }
     944             :   ExternalCallResult(Type type, InterpreterCode* code)
     945             :       : type(type), interpreter_code(code) {
     946             :     DCHECK_EQ(INTERNAL, type);
     947             :   }
     948             : };
     949             : 
     950             : // The main storage for interpreter code. It maps {WasmFunction} to the
     951             : // metadata needed to execute each function.
     952             : class CodeMap {
     953             :   Zone* zone_;
     954             :   const WasmModule* module_;
     955             :   ZoneVector<InterpreterCode> interpreter_code_;
     956             :   // This handle is set and reset by the SetInstanceObject() /
     957             :   // ClearInstanceObject() method, which is used by the HeapObjectsScope.
     958             :   Handle<WasmInstanceObject> instance_;
     959             : 
     960             :  public:
     961       18637 :   CodeMap(Isolate* isolate, const WasmModule* module,
     962             :           const uint8_t* module_start, Zone* zone)
     963       18637 :       : zone_(zone), module_(module), interpreter_code_(zone) {
     964       37274 :     if (module == nullptr) return;
     965       37274 :     interpreter_code_.reserve(module->functions.size());
     966       39278 :     for (const WasmFunction& function : module->functions) {
     967        2004 :       if (function.imported) {
     968             :         DCHECK(!function.code.is_set());
     969         800 :         AddFunction(&function, nullptr, nullptr);
     970             :       } else {
     971             :         AddFunction(&function, module_start + function.code.offset(),
     972        1204 :                     module_start + function.code.end_offset());
     973             :       }
     974             :     }
     975             :   }
     976             : 
     977             :   void SetInstanceObject(Handle<WasmInstanceObject> instance) {
     978             :     DCHECK(instance_.is_null());
     979     2558780 :     instance_ = instance;
     980             :   }
     981             : 
     982     2558780 :   void ClearInstanceObject() { instance_ = Handle<WasmInstanceObject>::null(); }
     983             : 
     984             :   const WasmModule* module() const { return module_; }
     985             :   bool has_instance() const { return !instance_.is_null(); }
     986             :   WasmInstanceObject* instance() const {
     987             :     DCHECK(has_instance());
     988             :     return *instance_;
     989             :   }
     990          64 :   MaybeHandle<WasmInstanceObject> maybe_instance() const {
     991             :     return has_instance() ? handle(instance())
     992         128 :                           : MaybeHandle<WasmInstanceObject>();
     993             :   }
     994             : 
     995        6260 :   Code* GetImportedFunction(uint32_t function_index) {
     996             :     DCHECK(has_instance());
     997             :     DCHECK_GT(module_->num_imported_functions, function_index);
     998             :     FixedArray* code_table = instance()->compiled_module()->ptr_to_code_table();
     999       12520 :     return Code::cast(code_table->get(static_cast<int>(function_index)));
    1000             :   }
    1001             : 
    1002             :   InterpreterCode* GetCode(const WasmFunction* function) {
    1003             :     InterpreterCode* code = GetCode(function->func_index);
    1004             :     DCHECK_EQ(function, code->function);
    1005             :     return code;
    1006             :   }
    1007             : 
    1008             :   InterpreterCode* GetCode(uint32_t function_index) {
    1009             :     DCHECK_LT(function_index, interpreter_code_.size());
    1010     6746248 :     return Preprocess(&interpreter_code_[function_index]);
    1011             :   }
    1012             : 
    1013         156 :   InterpreterCode* GetIndirectCode(uint32_t table_index, uint32_t entry_index) {
    1014         312 :     if (table_index >= module_->function_tables.size()) return nullptr;
    1015             :     const WasmIndirectFunctionTable* table =
    1016             :         &module_->function_tables[table_index];
    1017         312 :     if (entry_index >= table->values.size()) return nullptr;
    1018         102 :     uint32_t index = table->values[entry_index];
    1019         204 :     if (index >= interpreter_code_.size()) return nullptr;
    1020         102 :     return GetCode(index);
    1021             :   }
    1022             : 
    1023     3392370 :   InterpreterCode* Preprocess(InterpreterCode* code) {
    1024             :     DCHECK_EQ(code->function->imported, code->start == nullptr);
    1025     3392370 :     if (!code->side_table && code->start) {
    1026             :       // Compute the control targets map and the local declarations.
    1027       40486 :       code->side_table = new (zone_) SideTable(zone_, module_, code);
    1028             :     }
    1029     3392370 :     return code;
    1030             :   }
    1031             : 
    1032       24151 :   void AddFunction(const WasmFunction* function, const byte* code_start,
    1033             :                    const byte* code_end) {
    1034             :     InterpreterCode code = {
    1035             :         function, BodyLocalDecls(zone_),         code_start,
    1036             :         code_end, const_cast<byte*>(code_start), const_cast<byte*>(code_end),
    1037       48302 :         nullptr};
    1038             : 
    1039             :     DCHECK_EQ(interpreter_code_.size(), function->func_index);
    1040       24151 :     interpreter_code_.push_back(code);
    1041       24151 :   }
    1042             : 
    1043       19195 :   void SetFunctionCode(const WasmFunction* function, const byte* start,
    1044             :                        const byte* end) {
    1045             :     DCHECK_LT(function->func_index, interpreter_code_.size());
    1046       19195 :     InterpreterCode* code = &interpreter_code_[function->func_index];
    1047             :     DCHECK_EQ(function, code->function);
    1048       19195 :     code->orig_start = start;
    1049       19195 :     code->orig_end = end;
    1050       19195 :     code->start = const_cast<byte*>(start);
    1051       19195 :     code->end = const_cast<byte*>(end);
    1052       19195 :     code->side_table = nullptr;
    1053       19195 :     Preprocess(code);
    1054       19195 :   }
    1055             : };
    1056             : 
    1057        6140 : Handle<Object> WasmValueToNumber(Factory* factory, WasmValue val,
    1058             :                                  wasm::ValueType type) {
    1059        6140 :   switch (type) {
    1060             :     case kWasmI32:
    1061        6130 :       return factory->NewNumberFromInt(val.to<int32_t>());
    1062             :     case kWasmI64:
    1063             :       // wasm->js and js->wasm is illegal for i64 type.
    1064           0 :       UNREACHABLE();
    1065             :     case kWasmF32:
    1066           0 :       return factory->NewNumber(val.to<float>());
    1067             :     case kWasmF64:
    1068          10 :       return factory->NewNumber(val.to<double>());
    1069             :     default:
    1070             :       // TODO(wasm): Implement simd.
    1071           0 :       UNIMPLEMENTED();
    1072             :       return Handle<Object>::null();
    1073             :   }
    1074             : }
    1075             : 
    1076             : // Convert JS value to WebAssembly, spec here:
    1077             : // https://github.com/WebAssembly/design/blob/master/JS.md#towebassemblyvalue
    1078        6040 : WasmValue ToWebAssemblyValue(Isolate* isolate, Handle<Object> value,
    1079             :                              wasm::ValueType type) {
    1080        6040 :   switch (type) {
    1081             :     case kWasmI32: {
    1082             :       MaybeHandle<Object> maybe_i32 = Object::ToInt32(isolate, value);
    1083             :       // TODO(clemensh): Handle failure here (unwind).
    1084             :       int32_t value;
    1085        6030 :       CHECK(maybe_i32.ToHandleChecked()->ToInt32(&value));
    1086        6030 :       return WasmValue(value);
    1087             :     }
    1088             :     case kWasmI64:
    1089             :       // If the signature contains i64, a type error was thrown before.
    1090           0 :       UNREACHABLE();
    1091             :     case kWasmF32: {
    1092          10 :       MaybeHandle<Object> maybe_number = Object::ToNumber(value);
    1093             :       // TODO(clemensh): Handle failure here (unwind).
    1094             :       return WasmValue(
    1095          10 :           static_cast<float>(maybe_number.ToHandleChecked()->Number()));
    1096             :     }
    1097             :     case kWasmF64: {
    1098           0 :       MaybeHandle<Object> maybe_number = Object::ToNumber(value);
    1099             :       // TODO(clemensh): Handle failure here (unwind).
    1100           0 :       return WasmValue(maybe_number.ToHandleChecked()->Number());
    1101             :     }
    1102             :     default:
    1103             :       // TODO(wasm): Handle simd.
    1104           0 :       UNIMPLEMENTED();
    1105             :       return WasmValue();
    1106             :   }
    1107             : }
    1108             : 
    1109             : // Responsible for executing code directly.
    1110           0 : class ThreadImpl {
    1111             :   struct Activation {
    1112             :     uint32_t fp;
    1113             :     sp_t sp;
    1114       45156 :     Activation(uint32_t fp, sp_t sp) : fp(fp), sp(sp) {}
    1115             :   };
    1116             : 
    1117             :  public:
    1118             :   ThreadImpl(Zone* zone, CodeMap* codemap, WasmContext* wasm_context)
    1119             :       : codemap_(codemap),
    1120             :         wasm_context_(wasm_context),
    1121             :         zone_(zone),
    1122             :         frames_(zone),
    1123       37274 :         activations_(zone) {}
    1124             : 
    1125             :   //==========================================================================
    1126             :   // Implementation of public interface for WasmInterpreter::Thread.
    1127             :   //==========================================================================
    1128             : 
    1129             :   WasmInterpreter::State state() { return state_; }
    1130             : 
    1131     2563038 :   void InitFrame(const WasmFunction* function, WasmValue* args) {
    1132             :     DCHECK_EQ(current_activation().fp, frames_.size());
    1133             :     InterpreterCode* code = codemap()->GetCode(function);
    1134     2563038 :     size_t num_params = function->sig->parameter_count();
    1135     2563038 :     EnsureStackSpace(num_params);
    1136             :     Push(args, num_params);
    1137     2563038 :     PushFrame(code);
    1138     2563038 :   }
    1139             : 
    1140           0 :   WasmInterpreter::State Run(int num_steps = -1) {
    1141             :     DCHECK(state_ == WasmInterpreter::STOPPED ||
    1142             :            state_ == WasmInterpreter::PAUSED);
    1143             :     DCHECK(num_steps == -1 || num_steps > 0);
    1144             :     if (num_steps == -1) {
    1145             :       TRACE("  => Run()\n");
    1146             :     } else if (num_steps == 1) {
    1147             :       TRACE("  => Step()\n");
    1148             :     } else {
    1149             :       TRACE("  => Run(%d)\n", num_steps);
    1150             :     }
    1151     2570688 :     state_ = WasmInterpreter::RUNNING;
    1152     2570688 :     Execute(frames_.back().code, frames_.back().pc, num_steps);
    1153             :     // If state_ is STOPPED, the current activation must be fully unwound.
    1154             :     DCHECK_IMPLIES(state_ == WasmInterpreter::STOPPED,
    1155             :                    current_activation().fp == frames_.size());
    1156     2570688 :     return state_;
    1157             :   }
    1158             : 
    1159           0 :   void Pause() { UNIMPLEMENTED(); }
    1160             : 
    1161             :   void Reset() {
    1162             :     TRACE("----- RESET -----\n");
    1163     2517882 :     sp_ = stack_start_;
    1164             :     frames_.clear();
    1165     2517882 :     state_ = WasmInterpreter::STOPPED;
    1166     2517882 :     trap_reason_ = kTrapCount;
    1167     2517882 :     possible_nondeterminism_ = false;
    1168             :   }
    1169             : 
    1170             :   int GetFrameCount() {
    1171             :     DCHECK_GE(kMaxInt, frames_.size());
    1172        9488 :     return static_cast<int>(frames_.size());
    1173             :   }
    1174             : 
    1175     5103388 :   WasmValue GetReturnValue(uint32_t index) {
    1176     2551694 :     if (state_ == WasmInterpreter::TRAPPED) return WasmValue(0xdeadbeef);
    1177             :     DCHECK_EQ(WasmInterpreter::FINISHED, state_);
    1178             :     Activation act = current_activation();
    1179             :     // Current activation must be finished.
    1180             :     DCHECK_EQ(act.fp, frames_.size());
    1181     2551694 :     return GetStackValue(act.sp + index);
    1182             :   }
    1183             : 
    1184             :   WasmValue GetStackValue(sp_t index) {
    1185             :     DCHECK_GT(StackHeight(), index);
    1186     7998358 :     return stack_start_[index];
    1187             :   }
    1188             : 
    1189             :   void SetStackValue(sp_t index, WasmValue value) {
    1190             :     DCHECK_GT(StackHeight(), index);
    1191       15778 :     stack_start_[index] = value;
    1192             :   }
    1193             : 
    1194             :   TrapReason GetTrapReason() { return trap_reason_; }
    1195             : 
    1196             :   pc_t GetBreakpointPc() { return break_pc_; }
    1197             : 
    1198             :   bool PossibleNondeterminism() { return possible_nondeterminism_; }
    1199             : 
    1200             :   uint64_t NumInterpretedCalls() { return num_interpreted_calls_; }
    1201             : 
    1202          26 :   void AddBreakFlags(uint8_t flags) { break_flags_ |= flags; }
    1203             : 
    1204           0 :   void ClearBreakFlags() { break_flags_ = WasmInterpreter::BreakFlag::None; }
    1205             : 
    1206             :   uint32_t NumActivations() {
    1207          72 :     return static_cast<uint32_t>(activations_.size());
    1208             :   }
    1209             : 
    1210       90312 :   uint32_t StartActivation() {
    1211             :     TRACE("----- START ACTIVATION %zu -----\n", activations_.size());
    1212             :     // If you use activations, use them consistently:
    1213             :     DCHECK_IMPLIES(activations_.empty(), frames_.empty());
    1214             :     DCHECK_IMPLIES(activations_.empty(), StackHeight() == 0);
    1215       90312 :     uint32_t activation_id = static_cast<uint32_t>(activations_.size());
    1216       45156 :     activations_.emplace_back(static_cast<uint32_t>(frames_.size()),
    1217       90312 :                               StackHeight());
    1218       45156 :     state_ = WasmInterpreter::STOPPED;
    1219       45156 :     return activation_id;
    1220             :   }
    1221             : 
    1222             :   void FinishActivation(uint32_t id) {
    1223             :     TRACE("----- FINISH ACTIVATION %zu -----\n", activations_.size() - 1);
    1224             :     DCHECK_LT(0, activations_.size());
    1225             :     DCHECK_EQ(activations_.size() - 1, id);
    1226             :     // Stack height must match the start of this activation (otherwise unwind
    1227             :     // first).
    1228             :     DCHECK_EQ(activations_.back().fp, frames_.size());
    1229             :     DCHECK_LE(activations_.back().sp, StackHeight());
    1230       90312 :     sp_ = stack_start_ + activations_.back().sp;
    1231             :     activations_.pop_back();
    1232             :   }
    1233             : 
    1234             :   uint32_t ActivationFrameBase(uint32_t id) {
    1235             :     DCHECK_GT(activations_.size(), id);
    1236        8200 :     return activations_[id].fp;
    1237             :   }
    1238             : 
    1239             :   // Handle a thrown exception. Returns whether the exception was handled inside
    1240             :   // the current activation. Unwinds the interpreted stack accordingly.
    1241         222 :   WasmInterpreter::Thread::ExceptionHandlingResult HandleException(
    1242             :       Isolate* isolate) {
    1243             :     DCHECK(isolate->has_pending_exception());
    1244             :     // TODO(wasm): Add wasm exception handling (would return true).
    1245             :     USE(isolate->pending_exception());
    1246             :     TRACE("----- UNWIND -----\n");
    1247             :     DCHECK_LT(0, activations_.size());
    1248             :     Activation& act = activations_.back();
    1249             :     DCHECK_LE(act.fp, frames_.size());
    1250         222 :     frames_.resize(act.fp);
    1251             :     DCHECK_LE(act.sp, StackHeight());
    1252         222 :     sp_ = stack_start_ + act.sp;
    1253         222 :     state_ = WasmInterpreter::STOPPED;
    1254         222 :     return WasmInterpreter::Thread::UNWOUND;
    1255             :   }
    1256             : 
    1257             :  private:
    1258             :   // Entries on the stack of functions being evaluated.
    1259             :   struct Frame {
    1260             :     InterpreterCode* code;
    1261             :     pc_t pc;
    1262             :     sp_t sp;
    1263             : 
    1264             :     // Limit of parameters.
    1265             :     sp_t plimit() { return sp + code->function->sig->parameter_count(); }
    1266             :     // Limit of locals.
    1267             :     sp_t llimit() { return plimit() + code->locals.type_list.size(); }
    1268             :   };
    1269             : 
    1270             :   struct Block {
    1271             :     pc_t pc;
    1272             :     sp_t sp;
    1273             :     size_t fp;
    1274             :     unsigned arity;
    1275             :   };
    1276             : 
    1277             :   friend class InterpretedFrameImpl;
    1278             : 
    1279             :   CodeMap* codemap_;
    1280             :   WasmContext* wasm_context_;
    1281             :   Zone* zone_;
    1282             :   WasmValue* stack_start_ = nullptr;  // Start of allocated stack space.
    1283             :   WasmValue* stack_limit_ = nullptr;  // End of allocated stack space.
    1284             :   WasmValue* sp_ = nullptr;           // Current stack pointer.
    1285             :   ZoneVector<Frame> frames_;
    1286             :   WasmInterpreter::State state_ = WasmInterpreter::STOPPED;
    1287             :   pc_t break_pc_ = kInvalidPc;
    1288             :   TrapReason trap_reason_ = kTrapCount;
    1289             :   bool possible_nondeterminism_ = false;
    1290             :   uint8_t break_flags_ = 0;  // a combination of WasmInterpreter::BreakFlag
    1291             :   uint64_t num_interpreted_calls_ = 0;
    1292             :   // Store the stack height of each activation (for unwind and frame
    1293             :   // inspection).
    1294             :   ZoneVector<Activation> activations_;
    1295             : 
    1296             :   CodeMap* codemap() const { return codemap_; }
    1297         650 :   const WasmModule* module() const { return codemap_->module(); }
    1298             : 
    1299             :   void DoTrap(TrapReason trap, pc_t pc) {
    1300       10975 :     state_ = WasmInterpreter::TRAPPED;
    1301       10975 :     trap_reason_ = trap;
    1302             :     CommitPc(pc);
    1303             :   }
    1304             : 
    1305             :   // Push a frame with arguments already on the stack.
    1306     6729418 :   void PushFrame(InterpreterCode* code) {
    1307             :     DCHECK_NOT_NULL(code);
    1308             :     DCHECK_NOT_NULL(code->side_table);
    1309             :     EnsureStackSpace(code->side_table->max_stack_height_ +
    1310     6729418 :                      code->locals.type_list.size());
    1311             : 
    1312     3364709 :     ++num_interpreted_calls_;
    1313     3364709 :     size_t arity = code->function->sig->parameter_count();
    1314             :     // The parameters will overlap the arguments already on the stack.
    1315             :     DCHECK_GE(StackHeight(), arity);
    1316    10094127 :     frames_.push_back({code, 0, StackHeight() - arity});
    1317     3364709 :     frames_.back().pc = InitLocals(code);
    1318             :     TRACE("  => PushFrame #%zu (#%u @%zu)\n", frames_.size() - 1,
    1319             :           code->function->func_index, frames_.back().pc);
    1320     3364709 :   }
    1321             : 
    1322     3364709 :   pc_t InitLocals(InterpreterCode* code) {
    1323     6736196 :     for (auto p : code->locals.type_list) {
    1324             :       WasmValue val;
    1325        6778 :       switch (p) {
    1326             : #define CASE_TYPE(wasm, ctype)              \
    1327             :   case kWasm##wasm:                         \
    1328             :     val = WasmValue(static_cast<ctype>(0)); \
    1329             :     break;
    1330        3485 :         WASM_CTYPES(CASE_TYPE)
    1331             : #undef CASE_TYPE
    1332             :         default:
    1333           0 :           UNREACHABLE();
    1334             :           break;
    1335             :       }
    1336             :       Push(val);
    1337             :     }
    1338     3364709 :     return code->locals.encoded_size;
    1339             :   }
    1340             : 
    1341             :   void CommitPc(pc_t pc) {
    1342             :     DCHECK(!frames_.empty());
    1343       24898 :     frames_.back().pc = pc;
    1344             :   }
    1345             : 
    1346             :   bool SkipBreakpoint(InterpreterCode* code, pc_t pc) {
    1347        8570 :     if (pc == break_pc_) {
    1348             :       // Skip the previously hit breakpoint when resuming.
    1349        4285 :       break_pc_ = kInvalidPc;
    1350             :       return true;
    1351             :     }
    1352             :     return false;
    1353             :   }
    1354             : 
    1355             :   int LookupTargetDelta(InterpreterCode* code, pc_t pc) {
    1356       24593 :     return static_cast<int>(code->side_table->Lookup(pc).pc_diff);
    1357             :   }
    1358             : 
    1359      381308 :   int DoBreak(InterpreterCode* code, pc_t pc, size_t depth) {
    1360      381308 :     ControlTransferEntry& control_transfer_entry = code->side_table->Lookup(pc);
    1361      381308 :     DoStackTransfer(sp_ - control_transfer_entry.sp_diff,
    1362      762616 :                     control_transfer_entry.target_arity);
    1363      381308 :     return control_transfer_entry.pc_diff;
    1364             :   }
    1365             : 
    1366      292522 :   pc_t ReturnPc(Decoder* decoder, InterpreterCode* code, pc_t pc) {
    1367      146261 :     switch (code->orig_start[pc]) {
    1368             :       case kExprCallFunction: {
    1369             :         CallFunctionOperand<Decoder::kNoValidate> operand(decoder,
    1370             :                                                           code->at(pc));
    1371      146155 :         return pc + 1 + operand.length;
    1372             :       }
    1373             :       case kExprCallIndirect: {
    1374             :         CallIndirectOperand<Decoder::kNoValidate> operand(decoder,
    1375         106 :                                                           code->at(pc));
    1376         106 :         return pc + 1 + operand.length;
    1377             :       }
    1378             :       default:
    1379           0 :         UNREACHABLE();
    1380             :     }
    1381             :   }
    1382             : 
    1383     2698201 :   bool DoReturn(Decoder* decoder, InterpreterCode** code, pc_t* pc, pc_t* limit,
    1384             :                 size_t arity) {
    1385             :     DCHECK_GT(frames_.size(), 0);
    1386     8094603 :     WasmValue* sp_dest = stack_start_ + frames_.back().sp;
    1387             :     frames_.pop_back();
    1388     2698201 :     if (frames_.size() == current_activation().fp) {
    1389             :       // A return from the last frame terminates the execution.
    1390     2551940 :       state_ = WasmInterpreter::FINISHED;
    1391     2551940 :       DoStackTransfer(sp_dest, arity);
    1392             :       TRACE("  => finish\n");
    1393     2551940 :       return false;
    1394             :     } else {
    1395             :       // Return to caller frame.
    1396             :       Frame* top = &frames_.back();
    1397      146261 :       *code = top->code;
    1398      146261 :       decoder->Reset((*code)->start, (*code)->end);
    1399      146261 :       *pc = ReturnPc(decoder, *code, top->pc);
    1400      146261 :       *limit = top->code->end - top->code->start;
    1401             :       TRACE("  => Return to #%zu (#%u @%zu)\n", frames_.size() - 1,
    1402             :             (*code)->function->func_index, *pc);
    1403      146261 :       DoStackTransfer(sp_dest, arity);
    1404      146261 :       return true;
    1405             :     }
    1406             :   }
    1407             : 
    1408             :   // Returns true if the call was successful, false if the stack check failed
    1409             :   // and the current activation was fully unwound.
    1410      801671 :   bool DoCall(Decoder* decoder, InterpreterCode* target, pc_t* pc,
    1411             :               pc_t* limit) WARN_UNUSED_RESULT {
    1412      801671 :     frames_.back().pc = *pc;
    1413      801671 :     PushFrame(target);
    1414      801671 :     if (!DoStackCheck()) return false;
    1415      801661 :     *pc = frames_.back().pc;
    1416      801661 :     *limit = target->end - target->start;
    1417      801661 :     decoder->Reset(target->start, target->end);
    1418      801661 :     return true;
    1419             :   }
    1420             : 
    1421             :   // Copies {arity} values on the top of the stack down the stack to {dest},
    1422             :   // dropping the values in-between.
    1423     3079509 :   void DoStackTransfer(WasmValue* dest, size_t arity) {
    1424             :     // before: |---------------| pop_count | arity |
    1425             :     //         ^ 0             ^ dest              ^ sp_
    1426             :     //
    1427             :     // after:  |---------------| arity |
    1428             :     //         ^ 0                     ^ sp_
    1429             :     DCHECK_LE(dest, sp_);
    1430             :     DCHECK_LE(dest + arity, sp_);
    1431     3079509 :     if (arity) memcpy(dest, sp_ - arity, arity * sizeof(*sp_));
    1432     3079509 :     sp_ = dest + arity;
    1433     3079509 :   }
    1434             : 
    1435             :   template <typename mtype>
    1436             :   inline bool BoundsCheck(uint32_t mem_size, uint32_t offset, uint32_t index) {
    1437             :     return sizeof(mtype) <= mem_size && offset <= mem_size - sizeof(mtype) &&
    1438      121830 :            index <= mem_size - sizeof(mtype) - offset;
    1439             :   }
    1440             : 
    1441             :   template <typename ctype, typename mtype>
    1442       97380 :   bool ExecuteLoad(Decoder* decoder, InterpreterCode* code, pc_t pc, int& len,
    1443             :                    MachineRepresentation rep) {
    1444             :     MemoryAccessOperand<Decoder::kNoValidate> operand(decoder, code->at(pc),
    1445       97380 :                                                       sizeof(ctype));
    1446       97380 :     uint32_t index = Pop().to<uint32_t>();
    1447      194760 :     if (!BoundsCheck<mtype>(wasm_context_->mem_size, operand.offset, index)) {
    1448             :       DoTrap(kTrapMemOutOfBounds, pc);
    1449        2501 :       return false;
    1450             :     }
    1451       94879 :     byte* addr = wasm_context_->mem_start + operand.offset + index;
    1452        1512 :     WasmValue result(static_cast<ctype>(ReadLittleEndianValue<mtype>(addr)));
    1453             : 
    1454             :     Push(result);
    1455       94879 :     len = 1 + operand.length;
    1456             : 
    1457       94879 :     if (FLAG_wasm_trace_memory) {
    1458          42 :       tracing::TraceMemoryOperation(
    1459             :           tracing::kWasmInterpreted, false, rep, operand.offset + index,
    1460             :           code->function->func_index, static_cast<int>(pc),
    1461          42 :           wasm_context_->mem_start);
    1462             :     }
    1463             : 
    1464             :     return true;
    1465             :   }
    1466             : 
    1467             :   template <typename ctype, typename mtype>
    1468       22548 :   bool ExecuteStore(Decoder* decoder, InterpreterCode* code, pc_t pc, int& len,
    1469             :                     MachineRepresentation rep) {
    1470             :     MemoryAccessOperand<Decoder::kNoValidate> operand(decoder, code->at(pc),
    1471       22548 :                                                       sizeof(ctype));
    1472       22548 :     WasmValue val = Pop();
    1473             : 
    1474       22548 :     uint32_t index = Pop().to<uint32_t>();
    1475       45096 :     if (!BoundsCheck<mtype>(wasm_context_->mem_size, operand.offset, index)) {
    1476             :       DoTrap(kTrapMemOutOfBounds, pc);
    1477        1620 :       return false;
    1478             :     }
    1479       20928 :     byte* addr = wasm_context_->mem_start + operand.offset + index;
    1480          70 :     WriteLittleEndianValue<mtype>(addr, static_cast<mtype>(val.to<ctype>()));
    1481       20928 :     len = 1 + operand.length;
    1482             : 
    1483             :     if (std::is_same<float, ctype>::value) {
    1484        1234 :       possible_nondeterminism_ |= std::isnan(val.to<float>());
    1485             :     } else if (std::is_same<double, ctype>::value) {
    1486       16168 :       possible_nondeterminism_ |= std::isnan(val.to<double>());
    1487             :     }
    1488             : 
    1489       20928 :     if (FLAG_wasm_trace_memory) {
    1490          12 :       tracing::TraceMemoryOperation(
    1491             :           tracing::kWasmInterpreted, true, rep, operand.offset + index,
    1492             :           code->function->func_index, static_cast<int>(pc),
    1493          12 :           wasm_context_->mem_start);
    1494             :     }
    1495             : 
    1496             :     return true;
    1497             :   }
    1498             : 
    1499             :   // Check if our control stack (frames_) exceeds the limit. Trigger stack
    1500             :   // overflow if it does, and unwinding the current frame.
    1501             :   // Returns true if execution can continue, false if the current activation was
    1502             :   // fully unwound.
    1503             :   // Do call this function immediately *after* pushing a new frame. The pc of
    1504             :   // the top frame will be reset to 0 if the stack check fails.
    1505      801691 :   bool DoStackCheck() WARN_UNUSED_RESULT {
    1506             :     // Sum up the size of all dynamically growing structures.
    1507     1603342 :     if (V8_LIKELY(frames_.size() <= kV8MaxWasmInterpretedStackSize)) {
    1508             :       return true;
    1509             :     }
    1510          10 :     if (!codemap()->has_instance()) {
    1511             :       // In test mode: Just abort.
    1512           0 :       FATAL("wasm interpreter: stack overflow");
    1513             :     }
    1514             :     // The pc of the top frame is initialized to the first instruction. We reset
    1515             :     // it to 0 here such that we report the same position as in compiled code.
    1516          10 :     frames_.back().pc = 0;
    1517             :     Isolate* isolate = codemap()->instance()->GetIsolate();
    1518             :     HandleScope handle_scope(isolate);
    1519          10 :     isolate->StackOverflow();
    1520          10 :     return HandleException(isolate) == WasmInterpreter::Thread::HANDLED;
    1521             :   }
    1522             : 
    1523     8840784 :   void Execute(InterpreterCode* code, pc_t pc, int max) {
    1524             :     DCHECK_NOT_NULL(code->side_table);
    1525             :     DCHECK(!frames_.empty());
    1526             :     // There must be enough space on the stack to hold the arguments, locals,
    1527             :     // and the value stack.
    1528             :     DCHECK_LE(code->function->sig->parameter_count() +
    1529             :                   code->locals.type_list.size() +
    1530             :                   code->side_table->max_stack_height_,
    1531             :               stack_limit_ - stack_start_ - frames_.back().sp);
    1532             : 
    1533    11936704 :     Decoder decoder(code->start, code->end);
    1534     2570688 :     pc_t limit = code->end - code->start;
    1535             :     bool hit_break = false;
    1536             : 
    1537             :     while (true) {
    1538             : #define PAUSE_IF_BREAK_FLAG(flag)                                     \
    1539             :   if (V8_UNLIKELY(break_flags_ & WasmInterpreter::BreakFlag::flag)) { \
    1540             :     hit_break = true;                                                 \
    1541             :     max = 0;                                                          \
    1542             :   }
    1543             : 
    1544             :       DCHECK_GT(limit, pc);
    1545             :       DCHECK_NOT_NULL(code->start);
    1546             : 
    1547             :       // Do first check for a breakpoint, in order to set hit_break correctly.
    1548             :       const char* skip = "        ";
    1549    15358682 :       int len = 1;
    1550    15358682 :       byte opcode = code->start[pc];
    1551             :       byte orig = opcode;
    1552    15358682 :       if (V8_UNLIKELY(opcode == kInternalBreakpoint)) {
    1553        8570 :         orig = code->orig_start[pc];
    1554        8570 :         if (SkipBreakpoint(code, pc)) {
    1555             :           // skip breakpoint by switching on original code.
    1556             :           skip = "[skip]  ";
    1557             :         } else {
    1558             :           TRACE("@%-3zu: [break] %-24s:", pc,
    1559             :                 WasmOpcodes::OpcodeName(static_cast<WasmOpcode>(orig)));
    1560             :           TraceValueStack();
    1561             :           TRACE("\n");
    1562             :           hit_break = true;
    1563        7663 :           break;
    1564             :         }
    1565             :       }
    1566             : 
    1567             :       // If max is 0, break. If max is positive (a limit is set), decrement it.
    1568    15354397 :       if (max == 0) break;
    1569    15351019 :       if (max > 0) --max;
    1570             : 
    1571             :       USE(skip);
    1572             :       TRACE("@%-3zu: %s%-24s:", pc, skip,
    1573             :             WasmOpcodes::OpcodeName(static_cast<WasmOpcode>(orig)));
    1574             :       TraceValueStack();
    1575             :       TRACE("\n");
    1576             : 
    1577             : #ifdef DEBUG
    1578             :       // Compute the stack effect of this opcode, and verify later that the
    1579             :       // stack was modified accordingly.
    1580             :       std::pair<uint32_t, uint32_t> stack_effect = wasm::StackEffect(
    1581             :           codemap_->module(), frames_.back().code->function->sig,
    1582             :           code->orig_start + pc, code->orig_end);
    1583             :       sp_t expected_new_stack_height =
    1584             :           StackHeight() - stack_effect.first + stack_effect.second;
    1585             : #endif
    1586             : 
    1587    15351019 :       switch (orig) {
    1588             :         case kExprNop:
    1589             :           break;
    1590             :         case kExprBlock: {
    1591             :           BlockTypeOperand<Decoder::kNoValidate> operand(&decoder,
    1592     1703628 :                                                          code->at(pc));
    1593     1703628 :           len = 1 + operand.length;
    1594             :           break;
    1595             :         }
    1596             :         case kExprLoop: {
    1597             :           BlockTypeOperand<Decoder::kNoValidate> operand(&decoder,
    1598       47954 :                                                          code->at(pc));
    1599       47954 :           len = 1 + operand.length;
    1600             :           break;
    1601             :         }
    1602             :         case kExprIf: {
    1603             :           BlockTypeOperand<Decoder::kNoValidate> operand(&decoder,
    1604       30786 :                                                          code->at(pc));
    1605       30786 :           WasmValue cond = Pop();
    1606             :           bool is_true = cond.to<uint32_t>() != 0;
    1607       30786 :           if (is_true) {
    1608             :             // fall through to the true block.
    1609       28159 :             len = 1 + operand.length;
    1610             :             TRACE("  true => fallthrough\n");
    1611             :           } else {
    1612        5254 :             len = LookupTargetDelta(code, pc);
    1613             :             TRACE("  false => @%zu\n", pc + len);
    1614             :           }
    1615             :           break;
    1616             :         }
    1617             :         case kExprElse: {
    1618       21966 :           len = LookupTargetDelta(code, pc);
    1619             :           TRACE("  end => @%zu\n", pc + len);
    1620       21966 :           break;
    1621             :         }
    1622             :         case kExprSelect: {
    1623        1398 :           WasmValue cond = Pop();
    1624        1398 :           WasmValue fval = Pop();
    1625        1398 :           WasmValue tval = Pop();
    1626        1398 :           Push(cond.to<int32_t>() != 0 ? tval : fval);
    1627             :           break;
    1628             :         }
    1629             :         case kExprBr: {
    1630             :           BreakDepthOperand<Decoder::kNoValidate> operand(&decoder,
    1631             :                                                           code->at(pc));
    1632       52804 :           len = DoBreak(code, pc, operand.depth);
    1633             :           TRACE("  br => @%zu\n", pc + len);
    1634             :           break;
    1635             :         }
    1636             :         case kExprBrIf: {
    1637             :           BreakDepthOperand<Decoder::kNoValidate> operand(&decoder,
    1638             :                                                           code->at(pc));
    1639       43098 :           WasmValue cond = Pop();
    1640             :           bool is_true = cond.to<uint32_t>() != 0;
    1641       43098 :           if (is_true) {
    1642       44040 :             len = DoBreak(code, pc, operand.depth);
    1643             :             TRACE("  br_if => @%zu\n", pc + len);
    1644             :           } else {
    1645             :             TRACE("  false => fallthrough\n");
    1646       21078 :             len = 1 + operand.length;
    1647             :           }
    1648             :           break;
    1649             :         }
    1650             :         case kExprBrTable: {
    1651             :           BranchTableOperand<Decoder::kNoValidate> operand(&decoder,
    1652      332886 :                                                            code->at(pc));
    1653             :           BranchTableIterator<Decoder::kNoValidate> iterator(&decoder, operand);
    1654      332886 :           uint32_t key = Pop().to<uint32_t>();
    1655             :           uint32_t depth = 0;
    1656      332886 :           if (key >= operand.table_count) key = operand.table_count;
    1657     1622604 :           for (uint32_t i = 0; i <= key; i++) {
    1658             :             DCHECK(iterator.has_next());
    1659     1289718 :             depth = iterator.next();
    1660             :           }
    1661      665772 :           len = key + DoBreak(code, pc + key, static_cast<size_t>(depth));
    1662             :           TRACE("  br[%u] => @%zu\n", key, pc + key + len);
    1663             :           break;
    1664             :         }
    1665             :         case kExprReturn: {
    1666     2698201 :           size_t arity = code->function->sig->return_count();
    1667     2896391 :           if (!DoReturn(&decoder, &code, &pc, &limit, arity)) return;
    1668          12 :           PAUSE_IF_BREAK_FLAG(AfterReturn);
    1669      801673 :           continue;
    1670             :         }
    1671             :         case kExprUnreachable: {
    1672             :           return DoTrap(kTrapUnreachable, pc);
    1673             :         }
    1674             :         case kExprEnd: {
    1675             :           break;
    1676             :         }
    1677             :         case kExprI32Const: {
    1678             :           ImmI32Operand<Decoder::kNoValidate> operand(&decoder, code->at(pc));
    1679             :           Push(WasmValue(operand.value));
    1680      492765 :           len = 1 + operand.length;
    1681             :           break;
    1682             :         }
    1683             :         case kExprI64Const: {
    1684             :           ImmI64Operand<Decoder::kNoValidate> operand(&decoder, code->at(pc));
    1685             :           Push(WasmValue(operand.value));
    1686       10290 :           len = 1 + operand.length;
    1687             :           break;
    1688             :         }
    1689             :         case kExprF32Const: {
    1690             :           ImmF32Operand<Decoder::kNoValidate> operand(&decoder, code->at(pc));
    1691             :           Push(WasmValue(operand.value));
    1692         294 :           len = 1 + operand.length;
    1693             :           break;
    1694             :         }
    1695             :         case kExprF64Const: {
    1696             :           ImmF64Operand<Decoder::kNoValidate> operand(&decoder, code->at(pc));
    1697             :           Push(WasmValue(operand.value));
    1698        1680 :           len = 1 + operand.length;
    1699             :           break;
    1700             :         }
    1701             :         case kExprGetLocal: {
    1702             :           LocalIndexOperand<Decoder::kNoValidate> operand(&decoder,
    1703             :                                                           code->at(pc));
    1704     5445897 :           Push(GetStackValue(frames_.back().sp + operand.index));
    1705     5445897 :           len = 1 + operand.length;
    1706             :           break;
    1707             :         }
    1708             :         case kExprSetLocal: {
    1709             :           LocalIndexOperand<Decoder::kNoValidate> operand(&decoder,
    1710             :                                                           code->at(pc));
    1711       11998 :           WasmValue val = Pop();
    1712       11998 :           SetStackValue(frames_.back().sp + operand.index, val);
    1713       11998 :           len = 1 + operand.length;
    1714             :           break;
    1715             :         }
    1716             :         case kExprTeeLocal: {
    1717             :           LocalIndexOperand<Decoder::kNoValidate> operand(&decoder,
    1718             :                                                           code->at(pc));
    1719        3780 :           WasmValue val = Pop();
    1720        3780 :           SetStackValue(frames_.back().sp + operand.index, val);
    1721             :           Push(val);
    1722        3780 :           len = 1 + operand.length;
    1723             :           break;
    1724             :         }
    1725             :         case kExprDrop: {
    1726             :           Pop();
    1727             :           break;
    1728             :         }
    1729             :         case kExprCallFunction: {
    1730             :           CallFunctionOperand<Decoder::kNoValidate> operand(&decoder,
    1731             :                                                             code->at(pc));
    1732             :           InterpreterCode* target = codemap()->GetCode(operand.index);
    1733      807805 :           if (target->function->imported) {
    1734        6260 :             CommitPc(pc);
    1735             :             ExternalCallResult result =
    1736        6260 :                 CallImportedFunction(target->function->func_index);
    1737        6260 :             switch (result.type) {
    1738             :               case ExternalCallResult::INTERNAL:
    1739             :                 // The import is a function of this instance. Call it directly.
    1740           0 :                 target = result.interpreter_code;
    1741             :                 DCHECK(!target->function->imported);
    1742           0 :                 break;
    1743             :               case ExternalCallResult::INVALID_FUNC:
    1744             :               case ExternalCallResult::SIGNATURE_MISMATCH:
    1745             :                 // Direct calls are checked statically.
    1746           0 :                 UNREACHABLE();
    1747             :               case ExternalCallResult::EXTERNAL_RETURNED:
    1748        6170 :                 PAUSE_IF_BREAK_FLAG(AfterCall);
    1749        6170 :                 len = 1 + operand.length;
    1750        6170 :                 break;
    1751             :               case ExternalCallResult::EXTERNAL_UNWOUND:
    1752          90 :                 return;
    1753             :             }
    1754        6170 :             if (result.type != ExternalCallResult::INTERNAL) break;
    1755             :           }
    1756             :           // Execute an internal call.
    1757      801545 :           if (!DoCall(&decoder, target, &pc, &limit)) return;
    1758      801535 :           code = target;
    1759      801535 :           PAUSE_IF_BREAK_FLAG(AfterCall);
    1760      801535 :           continue;  // don't bump pc
    1761             :         } break;
    1762             :         case kExprCallIndirect: {
    1763             :           CallIndirectOperand<Decoder::kNoValidate> operand(&decoder,
    1764         236 :                                                             code->at(pc));
    1765         236 :           uint32_t entry_index = Pop().to<uint32_t>();
    1766             :           // Assume only one table for now.
    1767             :           DCHECK_LE(module()->function_tables.size(), 1u);
    1768             :           ExternalCallResult result =
    1769         236 :               CallIndirectFunction(0, entry_index, operand.index);
    1770         236 :           switch (result.type) {
    1771             :             case ExternalCallResult::INTERNAL:
    1772             :               // The import is a function of this instance. Call it directly.
    1773         126 :               if (!DoCall(&decoder, result.interpreter_code, &pc, &limit))
    1774         100 :                 return;
    1775         126 :               code = result.interpreter_code;
    1776         126 :               PAUSE_IF_BREAK_FLAG(AfterCall);
    1777         126 :               continue;  // don't bump pc
    1778             :             case ExternalCallResult::INVALID_FUNC:
    1779          64 :               return DoTrap(kTrapFuncInvalid, pc);
    1780             :             case ExternalCallResult::SIGNATURE_MISMATCH:
    1781          26 :               return DoTrap(kTrapFuncSigMismatch, pc);
    1782             :             case ExternalCallResult::EXTERNAL_RETURNED:
    1783          10 :               PAUSE_IF_BREAK_FLAG(AfterCall);
    1784          10 :               len = 1 + operand.length;
    1785          10 :               break;
    1786             :             case ExternalCallResult::EXTERNAL_UNWOUND:
    1787             :               return;
    1788             :           }
    1789          10 :         } break;
    1790             :         case kExprGetGlobal: {
    1791             :           GlobalIndexOperand<Decoder::kNoValidate> operand(&decoder,
    1792             :                                                            code->at(pc));
    1793         640 :           const WasmGlobal* global = &module()->globals[operand.index];
    1794         320 :           byte* ptr = wasm_context_->globals_start + global->offset;
    1795             :           WasmValue val;
    1796         320 :           switch (global->type) {
    1797             : #define CASE_TYPE(wasm, ctype)                       \
    1798             :   case kWasm##wasm:                                  \
    1799             :     val = WasmValue(*reinterpret_cast<ctype*>(ptr)); \
    1800             :     break;
    1801         188 :             WASM_CTYPES(CASE_TYPE)
    1802             : #undef CASE_TYPE
    1803             :             default:
    1804           0 :               UNREACHABLE();
    1805             :           }
    1806             :           Push(val);
    1807         320 :           len = 1 + operand.length;
    1808             :           break;
    1809             :         }
    1810             :         case kExprSetGlobal: {
    1811             :           GlobalIndexOperand<Decoder::kNoValidate> operand(&decoder,
    1812             :                                                            code->at(pc));
    1813         464 :           const WasmGlobal* global = &module()->globals[operand.index];
    1814         232 :           byte* ptr = wasm_context_->globals_start + global->offset;
    1815         232 :           WasmValue val = Pop();
    1816         232 :           switch (global->type) {
    1817             : #define CASE_TYPE(wasm, ctype)                        \
    1818             :   case kWasm##wasm:                                   \
    1819             :     *reinterpret_cast<ctype*>(ptr) = val.to<ctype>(); \
    1820             :     break;
    1821         232 :             WASM_CTYPES(CASE_TYPE)
    1822             : #undef CASE_TYPE
    1823             :             default:
    1824           0 :               UNREACHABLE();
    1825             :           }
    1826         232 :           len = 1 + operand.length;
    1827             :           break;
    1828             :         }
    1829             : 
    1830             : #define LOAD_CASE(name, ctype, mtype, rep)                      \
    1831             :   case kExpr##name: {                                           \
    1832             :     if (!ExecuteLoad<ctype, mtype>(&decoder, code, pc, len,     \
    1833             :                                    MachineRepresentation::rep)) \
    1834             :       return;                                                   \
    1835             :     break;                                                      \
    1836             :   }
    1837             : 
    1838         381 :           LOAD_CASE(I32LoadMem8S, int32_t, int8_t, kWord8);
    1839         393 :           LOAD_CASE(I32LoadMem8U, int32_t, uint8_t, kWord8);
    1840         333 :           LOAD_CASE(I32LoadMem16S, int32_t, int16_t, kWord16);
    1841         333 :           LOAD_CASE(I32LoadMem16U, int32_t, uint16_t, kWord16);
    1842         144 :           LOAD_CASE(I64LoadMem8S, int64_t, int8_t, kWord8);
    1843           0 :           LOAD_CASE(I64LoadMem8U, int64_t, uint8_t, kWord16);
    1844         144 :           LOAD_CASE(I64LoadMem16S, int64_t, int16_t, kWord16);
    1845           0 :           LOAD_CASE(I64LoadMem16U, int64_t, uint16_t, kWord16);
    1846         144 :           LOAD_CASE(I64LoadMem32S, int64_t, int32_t, kWord32);
    1847           0 :           LOAD_CASE(I64LoadMem32U, int64_t, uint32_t, kWord32);
    1848       27580 :           LOAD_CASE(I32LoadMem, int32_t, int32_t, kWord32);
    1849        9302 :           LOAD_CASE(I64LoadMem, int64_t, int64_t, kWord64);
    1850       13773 :           LOAD_CASE(F32LoadMem, float, float, kFloat32);
    1851       44853 :           LOAD_CASE(F64LoadMem, double, double, kFloat64);
    1852             : #undef LOAD_CASE
    1853             : 
    1854             : #define STORE_CASE(name, ctype, mtype, rep)                      \
    1855             :   case kExpr##name: {                                            \
    1856             :     if (!ExecuteStore<ctype, mtype>(&decoder, code, pc, len,     \
    1857             :                                     MachineRepresentation::rep)) \
    1858             :       return;                                                    \
    1859             :     break;                                                       \
    1860             :   }
    1861             : 
    1862         410 :           STORE_CASE(I32StoreMem8, int32_t, int8_t, kWord8);
    1863         380 :           STORE_CASE(I32StoreMem16, int32_t, int16_t, kWord16);
    1864           0 :           STORE_CASE(I64StoreMem8, int64_t, int8_t, kWord8);
    1865           0 :           STORE_CASE(I64StoreMem16, int64_t, int16_t, kWord16);
    1866           0 :           STORE_CASE(I64StoreMem32, int64_t, int32_t, kWord32);
    1867        2822 :           STORE_CASE(I32StoreMem, int32_t, int32_t, kWord32);
    1868        1174 :           STORE_CASE(I64StoreMem, int64_t, int64_t, kWord64);
    1869        1414 :           STORE_CASE(F32StoreMem, float, float, kFloat32);
    1870       16348 :           STORE_CASE(F64StoreMem, double, double, kFloat64);
    1871             : #undef STORE_CASE
    1872             : 
    1873             : #define ASMJS_LOAD_CASE(name, ctype, mtype, defval)                 \
    1874             :   case kExpr##name: {                                               \
    1875             :     uint32_t index = Pop().to<uint32_t>();                          \
    1876             :     ctype result;                                                   \
    1877             :     if (!BoundsCheck<mtype>(wasm_context_->mem_size, 0, index)) {   \
    1878             :       result = defval;                                              \
    1879             :     } else {                                                        \
    1880             :       byte* addr = wasm_context_->mem_start + index;                \
    1881             :       /* TODO(titzer): alignment for asmjs load mem? */             \
    1882             :       result = static_cast<ctype>(*reinterpret_cast<mtype*>(addr)); \
    1883             :     }                                                               \
    1884             :     Push(WasmValue(result));                                        \
    1885             :     break;                                                          \
    1886             :   }
    1887           0 :           ASMJS_LOAD_CASE(I32AsmjsLoadMem8S, int32_t, int8_t, 0);
    1888           0 :           ASMJS_LOAD_CASE(I32AsmjsLoadMem8U, int32_t, uint8_t, 0);
    1889           0 :           ASMJS_LOAD_CASE(I32AsmjsLoadMem16S, int32_t, int16_t, 0);
    1890           0 :           ASMJS_LOAD_CASE(I32AsmjsLoadMem16U, int32_t, uint16_t, 0);
    1891         450 :           ASMJS_LOAD_CASE(I32AsmjsLoadMem, int32_t, int32_t, 0);
    1892         450 :           ASMJS_LOAD_CASE(F32AsmjsLoadMem, float, float,
    1893             :                           std::numeric_limits<float>::quiet_NaN());
    1894         612 :           ASMJS_LOAD_CASE(F64AsmjsLoadMem, double, double,
    1895             :                           std::numeric_limits<double>::quiet_NaN());
    1896             : #undef ASMJS_LOAD_CASE
    1897             : 
    1898             : #define ASMJS_STORE_CASE(name, ctype, mtype)                                   \
    1899             :   case kExpr##name: {                                                          \
    1900             :     WasmValue val = Pop();                                                     \
    1901             :     uint32_t index = Pop().to<uint32_t>();                                     \
    1902             :     if (BoundsCheck<mtype>(wasm_context_->mem_size, 0, index)) {               \
    1903             :       byte* addr = wasm_context_->mem_start + index;                           \
    1904             :       /* TODO(titzer): alignment for asmjs store mem? */                       \
    1905             :       *(reinterpret_cast<mtype*>(addr)) = static_cast<mtype>(val.to<ctype>()); \
    1906             :     }                                                                          \
    1907             :     Push(val);                                                                 \
    1908             :     break;                                                                     \
    1909             :   }
    1910             : 
    1911           0 :           ASMJS_STORE_CASE(I32AsmjsStoreMem8, int32_t, int8_t);
    1912           0 :           ASMJS_STORE_CASE(I32AsmjsStoreMem16, int32_t, int16_t);
    1913        4194 :           ASMJS_STORE_CASE(I32AsmjsStoreMem, int32_t, int32_t);
    1914           0 :           ASMJS_STORE_CASE(F32AsmjsStoreMem, float, float);
    1915           0 :           ASMJS_STORE_CASE(F64AsmjsStoreMem, double, double);
    1916             : #undef ASMJS_STORE_CASE
    1917             :         case kExprGrowMemory: {
    1918             :           MemoryIndexOperand<Decoder::kNoValidate> operand(&decoder,
    1919             :                                                            code->at(pc));
    1920          64 :           uint32_t delta_pages = Pop().to<uint32_t>();
    1921             :           Handle<WasmInstanceObject> instance =
    1922         128 :               codemap()->maybe_instance().ToHandleChecked();
    1923             :           DCHECK_EQ(wasm_context_, instance->wasm_context()->get());
    1924             :           Isolate* isolate = instance->GetIsolate();
    1925             :           int32_t result =
    1926          64 :               WasmInstanceObject::GrowMemory(isolate, instance, delta_pages);
    1927             :           Push(WasmValue(result));
    1928          64 :           len = 1 + operand.length;
    1929             :           break;
    1930             :         }
    1931             :         case kExprMemorySize: {
    1932             :           MemoryIndexOperand<Decoder::kNoValidate> operand(&decoder,
    1933             :                                                            code->at(pc));
    1934             :           Push(WasmValue(static_cast<uint32_t>(wasm_context_->mem_size /
    1935           0 :                                                WasmModule::kPageSize)));
    1936           0 :           len = 1 + operand.length;
    1937             :           break;
    1938             :         }
    1939             :         // We need to treat kExprI32ReinterpretF32 and kExprI64ReinterpretF64
    1940             :         // specially to guarantee that the quiet bit of a NaN is preserved on
    1941             :         // ia32 by the reinterpret casts.
    1942             :         case kExprI32ReinterpretF32: {
    1943          18 :           WasmValue val = Pop();
    1944             :           Push(WasmValue(ExecuteI32ReinterpretF32(val)));
    1945          18 :           possible_nondeterminism_ |= std::isnan(val.to<float>());
    1946             :           break;
    1947             :         }
    1948             :         case kExprI64ReinterpretF64: {
    1949         366 :           WasmValue val = Pop();
    1950             :           Push(WasmValue(ExecuteI64ReinterpretF64(val)));
    1951         366 :           possible_nondeterminism_ |= std::isnan(val.to<double>());
    1952             :           break;
    1953             :         }
    1954             : #define EXECUTE_SIMPLE_BINOP(name, ctype, op)               \
    1955             :   case kExpr##name: {                                       \
    1956             :     WasmValue rval = Pop();                                 \
    1957             :     WasmValue lval = Pop();                                 \
    1958             :     WasmValue result(lval.to<ctype>() op rval.to<ctype>()); \
    1959             :     Push(result);                                           \
    1960             :     break;                                                  \
    1961             :   }
    1962     3450434 :           FOREACH_SIMPLE_BINOP(EXECUTE_SIMPLE_BINOP)
    1963             : #undef EXECUTE_SIMPLE_BINOP
    1964             : 
    1965             : #define EXECUTE_OTHER_BINOP(name, ctype)                \
    1966             :   case kExpr##name: {                                   \
    1967             :     TrapReason trap = kTrapCount;                       \
    1968             :     volatile ctype rval = Pop().to<ctype>();            \
    1969             :     volatile ctype lval = Pop().to<ctype>();            \
    1970             :     WasmValue result(Execute##name(lval, rval, &trap)); \
    1971             :     if (trap != kTrapCount) return DoTrap(trap, pc);    \
    1972             :     Push(result);                                       \
    1973             :     break;                                              \
    1974             :   }
    1975     1631142 :           FOREACH_OTHER_BINOP(EXECUTE_OTHER_BINOP)
    1976             : #undef EXECUTE_OTHER_BINOP
    1977             : 
    1978             :         case kExprF32CopySign: {
    1979             :           // Handle kExprF32CopySign separately because it may introduce
    1980             :           // observable non-determinism.
    1981             :           TrapReason trap = kTrapCount;
    1982       79362 :           volatile float rval = Pop().to<float>();
    1983       79362 :           volatile float lval = Pop().to<float>();
    1984       79362 :           WasmValue result(ExecuteF32CopySign(lval, rval, &trap));
    1985             :           Push(result);
    1986      158724 :           possible_nondeterminism_ |= std::isnan(rval);
    1987             :           break;
    1988             :         }
    1989             :         case kExprF64CopySign: {
    1990             :           // Handle kExprF32CopySign separately because it may introduce
    1991             :           // observable non-determinism.
    1992             :           TrapReason trap = kTrapCount;
    1993       14418 :           volatile double rval = Pop().to<double>();
    1994       14418 :           volatile double lval = Pop().to<double>();
    1995       14418 :           WasmValue result(ExecuteF64CopySign(lval, rval, &trap));
    1996             :           Push(result);
    1997       28836 :           possible_nondeterminism_ |= std::isnan(rval);
    1998             :           break;
    1999             :         }
    2000             : #define EXECUTE_OTHER_UNOP(name, ctype)              \
    2001             :   case kExpr##name: {                                \
    2002             :     TrapReason trap = kTrapCount;                    \
    2003             :     volatile ctype val = Pop().to<ctype>();          \
    2004             :     WasmValue result(Execute##name(val, &trap));     \
    2005             :     if (trap != kTrapCount) return DoTrap(trap, pc); \
    2006             :     Push(result);                                    \
    2007             :     break;                                           \
    2008             :   }
    2009      289080 :           FOREACH_OTHER_UNOP(EXECUTE_OTHER_UNOP)
    2010             : #undef EXECUTE_OTHER_UNOP
    2011             : 
    2012             :         default:
    2013             :           V8_Fatal(__FILE__, __LINE__, "Unknown or unimplemented opcode #%d:%s",
    2014           0 :                    code->start[pc], OpcodeName(code->start[pc]));
    2015             :           UNREACHABLE();
    2016             :       }
    2017             : 
    2018             : #ifdef DEBUG
    2019             :       if (!WasmOpcodes::IsControlOpcode(static_cast<WasmOpcode>(opcode))) {
    2020             :         DCHECK_EQ(expected_new_stack_height, StackHeight());
    2021             :       }
    2022             : #endif
    2023             : 
    2024    14204907 :       pc += len;
    2025    14204907 :       if (pc == limit) {
    2026             :         // Fell off end of code; do an implicit return.
    2027             :         TRACE("@%-3zu: ImplicitReturn\n", pc);
    2028     2364835 :         if (!DoReturn(&decoder, &code, &pc, &limit,
    2029     4729670 :                       code->function->sig->return_count()))
    2030             :           return;
    2031      146249 :         PAUSE_IF_BREAK_FLAG(AfterReturn);
    2032             :       }
    2033             : #undef PAUSE_IF_BREAK_FLAG
    2034             :     }
    2035             : 
    2036        7663 :     state_ = WasmInterpreter::PAUSED;
    2037       11974 :     break_pc_ = hit_break ? pc : kInvalidPc;
    2038        7663 :     CommitPc(pc);
    2039             :   }
    2040             : 
    2041             :   WasmValue Pop() {
    2042             :     DCHECK_GT(frames_.size(), 0);
    2043             :     DCHECK_GT(StackHeight(), frames_.back().llimit());  // can't pop into locals
    2044     5986988 :     return *--sp_;
    2045             :   }
    2046             : 
    2047             :   void PopN(int n) {
    2048             :     DCHECK_GE(StackHeight(), n);
    2049             :     DCHECK_GT(frames_.size(), 0);
    2050             :     // Check that we don't pop into locals.
    2051             :     DCHECK_GE(StackHeight() - n, frames_.back().llimit());
    2052             :     sp_ -= n;
    2053             :   }
    2054             : 
    2055             :   WasmValue PopArity(size_t arity) {
    2056             :     if (arity == 0) return WasmValue();
    2057             :     CHECK_EQ(1, arity);
    2058             :     return Pop();
    2059             :   }
    2060             : 
    2061             :   void Push(WasmValue val) {
    2062             :     DCHECK_NE(kWasmStmt, val.type());
    2063             :     DCHECK_LE(1, stack_limit_ - sp_);
    2064     8897006 :     *sp_++ = val;
    2065             :   }
    2066             : 
    2067             :   void Push(WasmValue* vals, size_t arity) {
    2068             :     DCHECK_LE(arity, stack_limit_ - sp_);
    2069     2563038 :     for (WasmValue *val = vals, *end = vals + arity; val != end; ++val) {
    2070             :       DCHECK_NE(kWasmStmt, val->type());
    2071             :     }
    2072     2563038 :     memcpy(sp_, vals, arity * sizeof(*sp_));
    2073     2563038 :     sp_ += arity;
    2074             :   }
    2075             : 
    2076     5927747 :   void EnsureStackSpace(size_t size) {
    2077    11855494 :     if (V8_LIKELY(static_cast<size_t>(stack_limit_ - sp_) >= size)) return;
    2078       17250 :     size_t old_size = stack_limit_ - stack_start_;
    2079             :     size_t requested_size =
    2080       17250 :         base::bits::RoundUpToPowerOfTwo64((sp_ - stack_start_) + size);
    2081       17250 :     size_t new_size = Max(size_t{8}, Max(2 * old_size, requested_size));
    2082       17250 :     WasmValue* new_stack = zone_->NewArray<WasmValue>(new_size);
    2083       17250 :     memcpy(new_stack, stack_start_, old_size * sizeof(*sp_));
    2084       17250 :     sp_ = new_stack + (sp_ - stack_start_);
    2085       17250 :     stack_start_ = new_stack;
    2086       17250 :     stack_limit_ = new_stack + new_size;
    2087             :   }
    2088             : 
    2089     3410280 :   sp_t StackHeight() { return sp_ - stack_start_; }
    2090             : 
    2091             :   void TraceValueStack() {
    2092             : #ifdef DEBUG
    2093             :     if (!FLAG_trace_wasm_interpreter) return;
    2094             :     Frame* top = frames_.size() > 0 ? &frames_.back() : nullptr;
    2095             :     sp_t sp = top ? top->sp : 0;
    2096             :     sp_t plimit = top ? top->plimit() : 0;
    2097             :     sp_t llimit = top ? top->llimit() : 0;
    2098             :     for (size_t i = sp; i < StackHeight(); ++i) {
    2099             :       if (i < plimit)
    2100             :         PrintF(" p%zu:", i);
    2101             :       else if (i < llimit)
    2102             :         PrintF(" l%zu:", i);
    2103             :       else
    2104             :         PrintF(" s%zu:", i);
    2105             :       WasmValue val = GetStackValue(i);
    2106             :       switch (val.type()) {
    2107             :         case kWasmI32:
    2108             :           PrintF("i32:%d", val.to<int32_t>());
    2109             :           break;
    2110             :         case kWasmI64:
    2111             :           PrintF("i64:%" PRId64 "", val.to<int64_t>());
    2112             :           break;
    2113             :         case kWasmF32:
    2114             :           PrintF("f32:%f", val.to<float>());
    2115             :           break;
    2116             :         case kWasmF64:
    2117             :           PrintF("f64:%lf", val.to<double>());
    2118             :           break;
    2119             :         case kWasmStmt:
    2120             :           PrintF("void");
    2121             :           break;
    2122             :         default:
    2123             :           UNREACHABLE();
    2124             :           break;
    2125             :       }
    2126             :     }
    2127             : #endif  // DEBUG
    2128             :   }
    2129             : 
    2130             :   ExternalCallResult TryHandleException(Isolate* isolate) {
    2131         100 :     if (HandleException(isolate) == WasmInterpreter::Thread::UNWOUND) {
    2132             :       return {ExternalCallResult::EXTERNAL_UNWOUND};
    2133             :     }
    2134             :     return {ExternalCallResult::EXTERNAL_RETURNED};
    2135             :   }
    2136             : 
    2137             :   // TODO(clemensh): Remove this, call JS via existing wasm-to-js wrapper, using
    2138             :   //                 CallExternalWasmFunction.
    2139        6220 :   ExternalCallResult CallExternalJSFunction(Isolate* isolate, Handle<Code> code,
    2140       24540 :                                             FunctionSig* signature) {
    2141        6220 :     Handle<HeapObject> target = UnwrapWasmToJSWrapper(isolate, code);
    2142             : 
    2143        6220 :     if (target.is_null()) {
    2144             :       isolate->Throw(*isolate->factory()->NewTypeError(
    2145          40 :           MessageTemplate::kWasmTrapTypeError));
    2146             :       return TryHandleException(isolate);
    2147             :     }
    2148             : 
    2149             : #if DEBUG
    2150             :     std::ostringstream oss;
    2151             :     target->HeapObjectShortPrint(oss);
    2152             :     TRACE("  => Calling imported function %s\n", oss.str().c_str());
    2153             : #endif
    2154             : 
    2155        6200 :     int num_args = static_cast<int>(signature->parameter_count());
    2156             : 
    2157             :     // Get all arguments as JS values.
    2158             :     std::vector<Handle<Object>> args;
    2159        6200 :     args.reserve(num_args);
    2160        6200 :     WasmValue* wasm_args = sp_ - num_args;
    2161       12340 :     for (int i = 0; i < num_args; ++i) {
    2162             :       args.push_back(WasmValueToNumber(isolate->factory(), wasm_args[i],
    2163       18420 :                                        signature->GetParam(i)));
    2164             :     }
    2165             : 
    2166             :     // The receiver is the global proxy if in sloppy mode (default), undefined
    2167             :     // if in strict mode.
    2168        6200 :     Handle<Object> receiver = isolate->global_proxy();
    2169       12400 :     if (target->IsJSFunction() &&
    2170             :         is_strict(JSFunction::cast(*target)->shared()->language_mode())) {
    2171           0 :       receiver = isolate->factory()->undefined_value();
    2172             :     }
    2173             : 
    2174             :     MaybeHandle<Object> maybe_retval =
    2175        6200 :         Execution::Call(isolate, target, receiver, num_args, args.data());
    2176        6200 :     if (maybe_retval.is_null()) return TryHandleException(isolate);
    2177             : 
    2178        6160 :     Handle<Object> retval = maybe_retval.ToHandleChecked();
    2179             :     // Pop arguments off the stack.
    2180        6160 :     sp_ -= num_args;
    2181             :     // Push return values.
    2182        6160 :     if (signature->return_count() > 0) {
    2183             :       // TODO(wasm): Handle multiple returns.
    2184             :       DCHECK_EQ(1, signature->return_count());
    2185        6040 :       Push(ToWebAssemblyValue(isolate, retval, signature->GetReturn()));
    2186             :     }
    2187        6160 :     return {ExternalCallResult::EXTERNAL_RETURNED};
    2188             :   }
    2189             : 
    2190          60 :   ExternalCallResult CallExternalWasmFunction(Isolate* isolate,
    2191             :                                               Handle<Code> code,
    2192         280 :                                               FunctionSig* sig) {
    2193             :     Handle<WasmDebugInfo> debug_info(codemap()->instance()->debug_info(),
    2194             :                                      isolate);
    2195             :     Handle<JSFunction> wasm_entry =
    2196          60 :         WasmDebugInfo::GetCWasmEntry(debug_info, sig);
    2197             : 
    2198             :     TRACE("  => Calling external wasm function\n");
    2199             : 
    2200             :     // Copy the arguments to one buffer.
    2201             :     // TODO(clemensh): Introduce a helper for all argument buffer
    2202             :     // con-/destruction.
    2203          60 :     int num_args = static_cast<int>(sig->parameter_count());
    2204          60 :     std::vector<uint8_t> arg_buffer(num_args * 8);
    2205             :     size_t offset = 0;
    2206          60 :     WasmValue* wasm_args = sp_ - num_args;
    2207         120 :     for (int i = 0; i < num_args; ++i) {
    2208         120 :       uint32_t param_size = 1 << ElementSizeLog2Of(sig->GetParam(i));
    2209         120 :       if (arg_buffer.size() < offset + param_size) {
    2210           0 :         arg_buffer.resize(std::max(2 * arg_buffer.size(), offset + param_size));
    2211             :       }
    2212          60 :       switch (sig->GetParam(i)) {
    2213             :         case kWasmI32:
    2214          60 :           WriteUnalignedValue(arg_buffer.data() + offset,
    2215          60 :                               wasm_args[i].to<uint32_t>());
    2216             :           break;
    2217             :         case kWasmI64:
    2218           0 :           WriteUnalignedValue(arg_buffer.data() + offset,
    2219           0 :                               wasm_args[i].to<uint64_t>());
    2220             :           break;
    2221             :         case kWasmF32:
    2222           0 :           WriteUnalignedValue(arg_buffer.data() + offset,
    2223           0 :                               wasm_args[i].to<float>());
    2224             :           break;
    2225             :         case kWasmF64:
    2226           0 :           WriteUnalignedValue(arg_buffer.data() + offset,
    2227           0 :                               wasm_args[i].to<double>());
    2228             :           break;
    2229             :         default:
    2230           0 :           UNIMPLEMENTED();
    2231             :       }
    2232             :       offset += param_size;
    2233             :     }
    2234             : 
    2235             :     // Wrap the arg_buffer data pointer in a handle. As this is an aligned
    2236             :     // pointer, to the GC it will look like a Smi.
    2237             :     Handle<Object> arg_buffer_obj(reinterpret_cast<Object*>(arg_buffer.data()),
    2238             :                                   isolate);
    2239             :     DCHECK(!arg_buffer_obj->IsHeapObject());
    2240             : 
    2241         180 :     Handle<Object> args[compiler::CWasmEntryParameters::kNumParameters];
    2242          60 :     args[compiler::CWasmEntryParameters::kCodeObject] = code;
    2243          60 :     args[compiler::CWasmEntryParameters::kArgumentsBuffer] = arg_buffer_obj;
    2244             : 
    2245             :     Handle<Object> receiver = isolate->factory()->undefined_value();
    2246             :     trap_handler::SetThreadInWasm();
    2247             :     MaybeHandle<Object> maybe_retval =
    2248          60 :         Execution::Call(isolate, wasm_entry, receiver, arraysize(args), args);
    2249             :     TRACE("  => External wasm function returned%s\n",
    2250             :           maybe_retval.is_null() ? " with exception" : "");
    2251             : 
    2252          60 :     if (maybe_retval.is_null()) {
    2253             :       DCHECK(!trap_handler::IsThreadInWasm());
    2254             :       return TryHandleException(isolate);
    2255             :     }
    2256             : 
    2257             :     trap_handler::ClearThreadInWasm();
    2258             : 
    2259             :     // Pop arguments off the stack.
    2260          20 :     sp_ -= num_args;
    2261             :     // Push return values.
    2262          20 :     if (sig->return_count() > 0) {
    2263             :       // TODO(wasm): Handle multiple returns.
    2264             :       DCHECK_EQ(1, sig->return_count());
    2265          20 :       switch (sig->GetReturn()) {
    2266             :         case kWasmI32:
    2267             :           Push(WasmValue(ReadUnalignedValue<uint32_t>(arg_buffer.data())));
    2268          20 :           break;
    2269             :         case kWasmI64:
    2270             :           Push(WasmValue(ReadUnalignedValue<uint64_t>(arg_buffer.data())));
    2271           0 :           break;
    2272             :         case kWasmF32:
    2273             :           Push(WasmValue(ReadUnalignedValue<float>(arg_buffer.data())));
    2274           0 :           break;
    2275             :         case kWasmF64:
    2276             :           Push(WasmValue(ReadUnalignedValue<double>(arg_buffer.data())));
    2277           0 :           break;
    2278             :         default:
    2279           0 :           UNIMPLEMENTED();
    2280             :       }
    2281             :     }
    2282          20 :     return {ExternalCallResult::EXTERNAL_RETURNED};
    2283             :   }
    2284             : 
    2285        6310 :   ExternalCallResult CallCodeObject(Isolate* isolate, Handle<Code> code,
    2286         120 :                                     FunctionSig* signature) {
    2287             :     DCHECK(AllowHandleAllocation::IsAllowed());
    2288             :     DCHECK(AllowHeapAllocation::IsAllowed());
    2289             : 
    2290        6310 :     if (code->kind() == Code::WASM_FUNCTION) {
    2291             :       FixedArray* deopt_data = code->deoptimization_data();
    2292             :       DCHECK_EQ(2, deopt_data->length());
    2293             :       WasmInstanceObject* target_instance =
    2294             :           WasmInstanceObject::cast(WeakCell::cast(deopt_data->get(0))->value());
    2295          90 :       if (target_instance != codemap()->instance()) {
    2296          60 :         return CallExternalWasmFunction(isolate, code, signature);
    2297             :       }
    2298             :       int target_func_idx = Smi::ToInt(deopt_data->get(1));
    2299             :       DCHECK_LE(0, target_func_idx);
    2300             :       return {ExternalCallResult::INTERNAL,
    2301          60 :               codemap()->GetCode(target_func_idx)};
    2302             :     }
    2303             : 
    2304        6220 :     return CallExternalJSFunction(isolate, code, signature);
    2305             :   }
    2306             : 
    2307       18780 :   ExternalCallResult CallImportedFunction(uint32_t function_index) {
    2308             :     // Use a new HandleScope to avoid leaking / accumulating handles in the
    2309             :     // outer scope.
    2310             :     Isolate* isolate = codemap()->instance()->GetIsolate();
    2311             :     HandleScope handle_scope(isolate);
    2312             : 
    2313             :     Handle<Code> target(codemap()->GetImportedFunction(function_index),
    2314        6260 :                         isolate);
    2315             :     return CallCodeObject(isolate, target,
    2316       25040 :                           codemap()->module()->functions[function_index].sig);
    2317             :   }
    2318             : 
    2319         236 :   ExternalCallResult CallIndirectFunction(uint32_t table_index,
    2320             :                                           uint32_t entry_index,
    2321         540 :                                           uint32_t sig_index) {
    2322         472 :     if (!codemap()->has_instance() ||
    2323         236 :         !codemap()->instance()->compiled_module()->has_function_tables()) {
    2324             :       // No instance. Rely on the information stored in the WasmModule.
    2325             :       // TODO(wasm): This is only needed for testing. Refactor testing to use
    2326             :       // the same paths as production.
    2327             :       InterpreterCode* code =
    2328         156 :           codemap()->GetIndirectCode(table_index, entry_index);
    2329         156 :       if (!code) return {ExternalCallResult::INVALID_FUNC};
    2330         102 :       if (code->function->sig_index != sig_index) {
    2331             :         // If not an exact match, we have to do a canonical check.
    2332             :         int function_canonical_id =
    2333          54 :             module()->signature_ids[code->function->sig_index];
    2334          36 :         int expected_canonical_id = module()->signature_ids[sig_index];
    2335             :         DCHECK_EQ(function_canonical_id,
    2336             :                   module()->signature_map.Find(code->function->sig));
    2337          18 :         if (function_canonical_id != expected_canonical_id) {
    2338           6 :           return {ExternalCallResult::SIGNATURE_MISMATCH};
    2339             :         }
    2340             :       }
    2341          96 :       return {ExternalCallResult::INTERNAL, code};
    2342             :     }
    2343             : 
    2344             :     WasmCompiledModule* compiled_module =
    2345             :         codemap()->instance()->compiled_module();
    2346             :     Isolate* isolate = compiled_module->GetIsolate();
    2347             : 
    2348             :     Code* target;
    2349             :     {
    2350             :       DisallowHeapAllocation no_gc;
    2351             :       // Get function to be called directly from the live instance to see latest
    2352             :       // changes to the tables.
    2353             : 
    2354             :       // Canonicalize signature index.
    2355         240 :       uint32_t canonical_sig_index = module()->signature_ids[sig_index];
    2356             :       DCHECK_EQ(canonical_sig_index,
    2357             :                 module()->signature_map.Find(module()->signatures[sig_index]));
    2358             : 
    2359             :       // Check signature.
    2360             :       FixedArray* sig_tables = compiled_module->ptr_to_signature_tables();
    2361          80 :       if (table_index >= static_cast<uint32_t>(sig_tables->length())) {
    2362           0 :         return {ExternalCallResult::INVALID_FUNC};
    2363             :       }
    2364             :       // Reconstitute the global handle to sig_table, and, further below,
    2365             :       // to the function table, from the address stored in the
    2366             :       // respective table of tables.
    2367          80 :       int table_index_as_int = static_cast<int>(table_index);
    2368             :       Handle<FixedArray> sig_table(reinterpret_cast<FixedArray**>(
    2369          80 :           WasmCompiledModule::GetTableValue(sig_tables, table_index_as_int)));
    2370          80 :       if (entry_index >= static_cast<uint32_t>(sig_table->length())) {
    2371          10 :         return {ExternalCallResult::INVALID_FUNC};
    2372             :       }
    2373          70 :       int found_sig = Smi::ToInt(sig_table->get(static_cast<int>(entry_index)));
    2374          70 :       if (static_cast<uint32_t>(found_sig) != canonical_sig_index) {
    2375          20 :         return {ExternalCallResult::SIGNATURE_MISMATCH};
    2376             :       }
    2377             : 
    2378             :       // Get code object.
    2379             :       FixedArray* fun_tables = compiled_module->ptr_to_function_tables();
    2380             :       DCHECK_EQ(sig_tables->length(), fun_tables->length());
    2381             :       Handle<FixedArray> fun_table(reinterpret_cast<FixedArray**>(
    2382          50 :           WasmCompiledModule::GetTableValue(fun_tables, table_index_as_int)));
    2383             :       DCHECK_EQ(sig_table->length(), fun_table->length());
    2384             :       target = Code::cast(fun_table->get(static_cast<int>(entry_index)));
    2385             :     }
    2386             : 
    2387             :     // Call the code object. Use a new HandleScope to avoid leaking /
    2388             :     // accumulating handles in the outer scope.
    2389             :     HandleScope handle_scope(isolate);
    2390             :     FunctionSig* signature =
    2391         150 :         &codemap()->module()->signatures[table_index][sig_index];
    2392          50 :     return CallCodeObject(isolate, handle(target, isolate), signature);
    2393             :   }
    2394             : 
    2395             :   inline Activation current_activation() {
    2396     5249895 :     return activations_.empty() ? Activation(0, 0) : activations_.back();
    2397             :   }
    2398             : };
    2399             : 
    2400             : class InterpretedFrameImpl {
    2401             :  public:
    2402             :   InterpretedFrameImpl(ThreadImpl* thread, int index)
    2403     1315720 :       : thread_(thread), index_(index) {
    2404             :     DCHECK_LE(0, index);
    2405             :   }
    2406             : 
    2407     2632858 :   const WasmFunction* function() const { return frame()->code->function; }
    2408             : 
    2409     1314799 :   int pc() const {
    2410             :     DCHECK_LE(0, frame()->pc);
    2411             :     DCHECK_GE(kMaxInt, frame()->pc);
    2412     1314799 :     return static_cast<int>(frame()->pc);
    2413             :   }
    2414             : 
    2415             :   int GetParameterCount() const {
    2416             :     DCHECK_GE(kMaxInt, function()->sig->parameter_count());
    2417         285 :     return static_cast<int>(function()->sig->parameter_count());
    2418             :   }
    2419             : 
    2420             :   int GetLocalCount() const {
    2421        1289 :     size_t num_locals = function()->sig->parameter_count() +
    2422        2578 :                         frame()->code->locals.type_list.size();
    2423             :     DCHECK_GE(kMaxInt, num_locals);
    2424        1289 :     return static_cast<int>(num_locals);
    2425             :   }
    2426             : 
    2427         465 :   int GetStackHeight() const {
    2428             :     bool is_top_frame =
    2429         880 :         static_cast<size_t>(index_) + 1 == thread_->frames_.size();
    2430             :     size_t stack_limit =
    2431         565 :         is_top_frame ? thread_->StackHeight() : thread_->frames_[index_ + 1].sp;
    2432             :     DCHECK_LE(frame()->sp, stack_limit);
    2433         465 :     size_t frame_size = stack_limit - frame()->sp;
    2434             :     DCHECK_LE(GetLocalCount(), frame_size);
    2435         930 :     return static_cast<int>(frame_size) - GetLocalCount();
    2436             :   }
    2437             : 
    2438         624 :   WasmValue GetLocalValue(int index) const {
    2439             :     DCHECK_LE(0, index);
    2440             :     DCHECK_GT(GetLocalCount(), index);
    2441        1248 :     return thread_->GetStackValue(static_cast<int>(frame()->sp) + index);
    2442             :   }
    2443             : 
    2444         143 :   WasmValue GetStackValue(int index) const {
    2445             :     DCHECK_LE(0, index);
    2446             :     // Index must be within the number of stack values of this frame.
    2447             :     DCHECK_GT(GetStackHeight(), index);
    2448         286 :     return thread_->GetStackValue(static_cast<int>(frame()->sp) +
    2449         286 :                                   GetLocalCount() + index);
    2450             :   }
    2451             : 
    2452             :  private:
    2453             :   ThreadImpl* thread_;
    2454             :   int index_;
    2455             : 
    2456             :   ThreadImpl::Frame* frame() const {
    2457             :     DCHECK_GT(thread_->frames_.size(), index_);
    2458     2631691 :     return &thread_->frames_[index_];
    2459             :   }
    2460             : };
    2461             : 
    2462             : // Converters between WasmInterpreter::Thread and WasmInterpreter::ThreadImpl.
    2463             : // Thread* is the public interface, without knowledge of the object layout.
    2464             : // This cast is potentially risky, but as long as we always cast it back before
    2465             : // accessing any data, it should be fine. UBSan is not complaining.
    2466             : WasmInterpreter::Thread* ToThread(ThreadImpl* impl) {
    2467             :   return reinterpret_cast<WasmInterpreter::Thread*>(impl);
    2468             : }
    2469             : ThreadImpl* ToImpl(WasmInterpreter::Thread* thread) {
    2470             :   return reinterpret_cast<ThreadImpl*>(thread);
    2471             : }
    2472             : 
    2473             : // Same conversion for InterpretedFrame and InterpretedFrameImpl.
    2474             : InterpretedFrame* ToFrame(InterpretedFrameImpl* impl) {
    2475             :   return reinterpret_cast<InterpretedFrame*>(impl);
    2476             : }
    2477             : const InterpretedFrameImpl* ToImpl(const InterpretedFrame* frame) {
    2478             :   return reinterpret_cast<const InterpretedFrameImpl*>(frame);
    2479             : }
    2480             : 
    2481             : //============================================================================
    2482             : // Implementation details of the heap objects scope.
    2483             : //============================================================================
    2484             : class HeapObjectsScopeImpl {
    2485             :  public:
    2486     2558850 :   HeapObjectsScopeImpl(CodeMap* codemap, Handle<WasmInstanceObject> instance)
    2487     5117700 :       : codemap_(codemap), needs_reset(!codemap_->has_instance()) {
    2488     2558850 :     if (needs_reset) {
    2489     2558780 :       instance_ = handle(*instance);
    2490     2558780 :       codemap_->SetInstanceObject(instance_);
    2491             :     } else {
    2492             :       DCHECK_EQ(*instance, codemap_->instance());
    2493     2558850 :       return;
    2494             :     }
    2495             :   }
    2496             : 
    2497             :   ~HeapObjectsScopeImpl() {
    2498     2558850 :     if (!needs_reset) return;
    2499             :     DCHECK_EQ(*instance_, codemap_->instance());
    2500     2558780 :     codemap_->ClearInstanceObject();
    2501             :     // Clear the handle, such that anyone who accidentally copied them will
    2502             :     // notice.
    2503     2558780 :     *instance_.location() = nullptr;
    2504             :   }
    2505             : 
    2506             :  private:
    2507             :   CodeMap* codemap_;
    2508             :   Handle<WasmInstanceObject> instance_;
    2509             :   bool needs_reset;
    2510             : };
    2511             : 
    2512             : }  // namespace
    2513             : 
    2514             : //============================================================================
    2515             : // Implementation of the pimpl idiom for WasmInterpreter::Thread.
    2516             : // Instead of placing a pointer to the ThreadImpl inside of the Thread object,
    2517             : // we just reinterpret_cast them. ThreadImpls are only allocated inside this
    2518             : // translation unit anyway.
    2519             : //============================================================================
    2520       22359 : WasmInterpreter::State WasmInterpreter::Thread::state() {
    2521       22359 :   return ToImpl(this)->state();
    2522             : }
    2523     2563038 : void WasmInterpreter::Thread::InitFrame(const WasmFunction* function,
    2524             :                                         WasmValue* args) {
    2525     2563038 :   ToImpl(this)->InitFrame(function, args);
    2526     2563038 : }
    2527     2570688 : WasmInterpreter::State WasmInterpreter::Thread::Run(int num_steps) {
    2528     2570688 :   return ToImpl(this)->Run(num_steps);
    2529             : }
    2530           0 : void WasmInterpreter::Thread::Pause() { return ToImpl(this)->Pause(); }
    2531     5035764 : void WasmInterpreter::Thread::Reset() { return ToImpl(this)->Reset(); }
    2532             : WasmInterpreter::Thread::ExceptionHandlingResult
    2533         112 : WasmInterpreter::Thread::HandleException(Isolate* isolate) {
    2534         112 :   return ToImpl(this)->HandleException(isolate);
    2535             : }
    2536        4176 : pc_t WasmInterpreter::Thread::GetBreakpointPc() {
    2537        4176 :   return ToImpl(this)->GetBreakpointPc();
    2538             : }
    2539        4744 : int WasmInterpreter::Thread::GetFrameCount() {
    2540        4744 :   return ToImpl(this)->GetFrameCount();
    2541             : }
    2542     1315720 : std::unique_ptr<InterpretedFrame> WasmInterpreter::Thread::GetFrame(int index) {
    2543             :   DCHECK_LE(0, index);
    2544             :   DCHECK_GT(GetFrameCount(), index);
    2545             :   return std::unique_ptr<InterpretedFrame>(
    2546     2631440 :       ToFrame(new InterpretedFrameImpl(ToImpl(this), index)));
    2547             : }
    2548     2551694 : WasmValue WasmInterpreter::Thread::GetReturnValue(int index) {
    2549     2551694 :   return ToImpl(this)->GetReturnValue(index);
    2550             : }
    2551         100 : TrapReason WasmInterpreter::Thread::GetTrapReason() {
    2552         100 :   return ToImpl(this)->GetTrapReason();
    2553             : }
    2554     2502830 : bool WasmInterpreter::Thread::PossibleNondeterminism() {
    2555     2502830 :   return ToImpl(this)->PossibleNondeterminism();
    2556             : }
    2557       77252 : uint64_t WasmInterpreter::Thread::NumInterpretedCalls() {
    2558       77252 :   return ToImpl(this)->NumInterpretedCalls();
    2559             : }
    2560          26 : void WasmInterpreter::Thread::AddBreakFlags(uint8_t flags) {
    2561             :   ToImpl(this)->AddBreakFlags(flags);
    2562          26 : }
    2563           0 : void WasmInterpreter::Thread::ClearBreakFlags() {
    2564             :   ToImpl(this)->ClearBreakFlags();
    2565           0 : }
    2566          36 : uint32_t WasmInterpreter::Thread::NumActivations() {
    2567          36 :   return ToImpl(this)->NumActivations();
    2568             : }
    2569       45156 : uint32_t WasmInterpreter::Thread::StartActivation() {
    2570       45156 :   return ToImpl(this)->StartActivation();
    2571             : }
    2572       45156 : void WasmInterpreter::Thread::FinishActivation(uint32_t id) {
    2573             :   ToImpl(this)->FinishActivation(id);
    2574       45156 : }
    2575        4100 : uint32_t WasmInterpreter::Thread::ActivationFrameBase(uint32_t id) {
    2576        4100 :   return ToImpl(this)->ActivationFrameBase(id);
    2577             : }
    2578             : 
    2579             : //============================================================================
    2580             : // The implementation details of the interpreter.
    2581             : //============================================================================
    2582             : class WasmInterpreterInternals : public ZoneObject {
    2583             :  public:
    2584             :   // Create a copy of the module bytes for the interpreter, since the passed
    2585             :   // pointer might be invalidated after constructing the interpreter.
    2586             :   const ZoneVector<uint8_t> module_bytes_;
    2587             :   CodeMap codemap_;
    2588             :   ZoneVector<ThreadImpl> threads_;
    2589             : 
    2590       18637 :   WasmInterpreterInternals(Isolate* isolate, Zone* zone,
    2591             :                            const WasmModule* module,
    2592             :                            const ModuleWireBytes& wire_bytes,
    2593             :                            WasmContext* wasm_context)
    2594             :       : module_bytes_(wire_bytes.start(), wire_bytes.end(), zone),
    2595             :         codemap_(isolate, module, module_bytes_.data(), zone),
    2596       55911 :         threads_(zone) {
    2597       18637 :     threads_.emplace_back(zone, &codemap_, wasm_context);
    2598       18637 :   }
    2599             : };
    2600             : 
    2601             : //============================================================================
    2602             : // Implementation of the public interface of the interpreter.
    2603             : //============================================================================
    2604       18637 : WasmInterpreter::WasmInterpreter(Isolate* isolate, const WasmModule* module,
    2605             :                                  const ModuleWireBytes& wire_bytes,
    2606             :                                  WasmContext* wasm_context)
    2607             :     : zone_(isolate->allocator(), ZONE_NAME),
    2608             :       internals_(new (&zone_) WasmInterpreterInternals(
    2609       37274 :           isolate, &zone_, module, wire_bytes, wasm_context)) {}
    2610             : 
    2611       18617 : WasmInterpreter::~WasmInterpreter() { internals_->~WasmInterpreterInternals(); }
    2612             : 
    2613           0 : void WasmInterpreter::Run() { internals_->threads_[0].Run(); }
    2614             : 
    2615           0 : void WasmInterpreter::Pause() { internals_->threads_[0].Pause(); }
    2616             : 
    2617        4400 : bool WasmInterpreter::SetBreakpoint(const WasmFunction* function, pc_t pc,
    2618             :                                     bool enabled) {
    2619        2200 :   InterpreterCode* code = internals_->codemap_.GetCode(function);
    2620        2200 :   size_t size = static_cast<size_t>(code->end - code->start);
    2621             :   // Check bounds for {pc}.
    2622        2200 :   if (pc < code->locals.encoded_size || pc >= size) return false;
    2623             :   // Make a copy of the code before enabling a breakpoint.
    2624        2200 :   if (enabled && code->orig_start == code->start) {
    2625          61 :     code->start = reinterpret_cast<byte*>(zone_.New(size));
    2626          61 :     memcpy(code->start, code->orig_start, size);
    2627          61 :     code->end = code->start + size;
    2628             :   }
    2629        2200 :   bool prev = code->start[pc] == kInternalBreakpoint;
    2630        2200 :   if (enabled) {
    2631        1156 :     code->start[pc] = kInternalBreakpoint;
    2632             :   } else {
    2633        1044 :     code->start[pc] = code->orig_start[pc];
    2634             :   }
    2635        2200 :   return prev;
    2636             : }
    2637             : 
    2638           0 : bool WasmInterpreter::GetBreakpoint(const WasmFunction* function, pc_t pc) {
    2639           0 :   InterpreterCode* code = internals_->codemap_.GetCode(function);
    2640           0 :   size_t size = static_cast<size_t>(code->end - code->start);
    2641             :   // Check bounds for {pc}.
    2642           0 :   if (pc < code->locals.encoded_size || pc >= size) return false;
    2643             :   // Check if a breakpoint is present at that place in the code.
    2644           0 :   return code->start[pc] == kInternalBreakpoint;
    2645             : }
    2646             : 
    2647           0 : bool WasmInterpreter::SetTracing(const WasmFunction* function, bool enabled) {
    2648           0 :   UNIMPLEMENTED();
    2649             :   return false;
    2650             : }
    2651             : 
    2652           0 : int WasmInterpreter::GetThreadCount() {
    2653           0 :   return 1;  // only one thread for now.
    2654             : }
    2655             : 
    2656     2731039 : WasmInterpreter::Thread* WasmInterpreter::GetThread(int id) {
    2657     2731039 :   CHECK_EQ(0, id);  // only one thread for now.
    2658     5462078 :   return ToThread(&internals_->threads_[id]);
    2659             : }
    2660             : 
    2661       22147 : void WasmInterpreter::AddFunctionForTesting(const WasmFunction* function) {
    2662       22147 :   internals_->codemap_.AddFunction(function, nullptr, nullptr);
    2663       22147 : }
    2664             : 
    2665       38390 : void WasmInterpreter::SetFunctionCodeForTesting(const WasmFunction* function,
    2666             :                                                 const byte* start,
    2667             :                                                 const byte* end) {
    2668       38390 :   internals_->codemap_.SetFunctionCode(function, start, end);
    2669       19195 : }
    2670             : 
    2671          30 : ControlTransferMap WasmInterpreter::ComputeControlTransfersForTesting(
    2672             :     Zone* zone, const WasmModule* module, const byte* start, const byte* end) {
    2673             :   // Create some dummy structures, to avoid special-casing the implementation
    2674             :   // just for testing.
    2675          30 :   FunctionSig sig(0, 0, nullptr);
    2676          30 :   WasmFunction function{&sig, 0, 0, {0, 0}, {0, 0}, false, false};
    2677             :   InterpreterCode code{
    2678          60 :       &function, BodyLocalDecls(zone), start, end, nullptr, nullptr, nullptr};
    2679             : 
    2680             :   // Now compute and return the control transfers.
    2681          30 :   SideTable side_table(zone, module, &code);
    2682          30 :   return side_table.map_;
    2683             : }
    2684             : 
    2685             : //============================================================================
    2686             : // Implementation of the frame inspection interface.
    2687             : //============================================================================
    2688     1315159 : const WasmFunction* InterpretedFrame::function() const {
    2689     1315159 :   return ToImpl(this)->function();
    2690             : }
    2691     2629598 : int InterpretedFrame::pc() const { return ToImpl(this)->pc(); }
    2692         285 : int InterpretedFrame::GetParameterCount() const {
    2693         285 :   return ToImpl(this)->GetParameterCount();
    2694             : }
    2695         681 : int InterpretedFrame::GetLocalCount() const {
    2696         681 :   return ToImpl(this)->GetLocalCount();
    2697             : }
    2698         465 : int InterpretedFrame::GetStackHeight() const {
    2699         465 :   return ToImpl(this)->GetStackHeight();
    2700             : }
    2701         624 : WasmValue InterpretedFrame::GetLocalValue(int index) const {
    2702         624 :   return ToImpl(this)->GetLocalValue(index);
    2703             : }
    2704         143 : WasmValue InterpretedFrame::GetStackValue(int index) const {
    2705         143 :   return ToImpl(this)->GetStackValue(index);
    2706             : }
    2707             : 
    2708             : //============================================================================
    2709             : // Public API of the heap objects scope.
    2710             : //============================================================================
    2711     2558850 : WasmInterpreter::HeapObjectsScope::HeapObjectsScope(
    2712             :     WasmInterpreter* interpreter, Handle<WasmInstanceObject> instance) {
    2713             :   static_assert(sizeof(data) == sizeof(HeapObjectsScopeImpl), "Size mismatch");
    2714     2558850 :   new (data) HeapObjectsScopeImpl(&interpreter->internals_->codemap_, instance);
    2715     2558850 : }
    2716             : 
    2717     2558850 : WasmInterpreter::HeapObjectsScope::~HeapObjectsScope() {
    2718             :   reinterpret_cast<HeapObjectsScopeImpl*>(data)->~HeapObjectsScopeImpl();
    2719     2558850 : }
    2720             : 
    2721             : #undef TRACE
    2722             : #undef FOREACH_INTERNAL_OPCODE
    2723             : #undef WASM_CTYPES
    2724             : #undef FOREACH_SIMPLE_BINOP
    2725             : #undef FOREACH_OTHER_BINOP
    2726             : #undef FOREACH_OTHER_UNOP
    2727             : 
    2728             : }  // namespace wasm
    2729             : }  // namespace internal
    2730             : }  // namespace v8

Generated by: LCOV version 1.10