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 #ifndef V8_WASM_INTERPRETER_H_ 6 #define V8_WASM_INTERPRETER_H_ 7 8 #include "src/wasm/wasm-opcodes.h" 9 #include "src/zone/zone-containers.h" 10 11 namespace v8 { 12 namespace base { 13 class AccountingAllocator; 14 } 15 16 namespace internal { 17 namespace wasm { 18 19 // forward declarations. 20 struct ModuleBytesEnv; 21 struct WasmFunction; 22 class WasmInterpreterInternals; 23 24 typedef size_t pc_t; 25 typedef size_t sp_t; 26 typedef int32_t pcdiff_t; 27 typedef uint32_t spdiff_t; 28 29 const pc_t kInvalidPc = 0x80000000; 30 31 typedef ZoneMap<pc_t, pcdiff_t> ControlTransferMap; 32 33 // Macro for defining union members. 34 #define FOREACH_UNION_MEMBER(V) \ 35 V(i32, kWasmI32, int32_t) \ 36 V(u32, kWasmI32, uint32_t) \ 37 V(i64, kWasmI64, int64_t) \ 38 V(u64, kWasmI64, uint64_t) \ 39 V(f32, kWasmF32, float) \ 40 V(f64, kWasmF64, double) 41 42 // Representation of values within the interpreter. 43 struct WasmVal { 44 ValueType type; 45 union { 46 #define DECLARE_FIELD(field, localtype, ctype) ctype field; 47 FOREACH_UNION_MEMBER(DECLARE_FIELD) 48 #undef DECLARE_FIELD 49 } val; 50 51 WasmVal() : type(kWasmStmt) {} 52 53 #define DECLARE_CONSTRUCTOR(field, localtype, ctype) \ 54 explicit WasmVal(ctype v) : type(localtype) { val.field = v; } 55 FOREACH_UNION_MEMBER(DECLARE_CONSTRUCTOR) 56 #undef DECLARE_CONSTRUCTOR 57 58 template <typename T> 59 inline T to() { 60 UNREACHABLE(); 61 } 62 63 template <typename T> 64 inline T to_unchecked() { 65 UNREACHABLE(); 66 } 67 }; 68 69 #define DECLARE_CAST(field, localtype, ctype) \ 70 template <> \ 71 inline ctype WasmVal::to_unchecked() { \ 72 return val.field; \ 73 } \ 74 template <> \ 75 inline ctype WasmVal::to() { \ 76 CHECK_EQ(localtype, type); \ 77 return val.field; \ 78 } 79 FOREACH_UNION_MEMBER(DECLARE_CAST) 80 #undef DECLARE_CAST 81 82 // Representation of frames within the interpreter. 83 class InterpretedFrame { 84 public: 85 const WasmFunction* function() const { return function_; } 86 int pc() const { return pc_; } 87 88 //========================================================================== 89 // Stack frame inspection. 90 //========================================================================== 91 int GetParameterCount() const; 92 WasmVal GetLocalVal(int index) const; 93 WasmVal GetExprVal(int pc) const; 94 void SetLocalVal(int index, WasmVal val); 95 void SetExprVal(int pc, WasmVal val); 96 97 private: 98 friend class WasmInterpreter; 99 100 InterpretedFrame(const WasmFunction* function, int pc, int fp, int sp) 101 : function_(function), pc_(pc), fp_(fp), sp_(sp) {} 102 103 const WasmFunction* function_; 104 int pc_; 105 int fp_; 106 int sp_; 107 }; 108 109 // An interpreter capable of executing WASM. 110 class V8_EXPORT_PRIVATE WasmInterpreter { 111 public: 112 // State machine for a Thread: 113 // +---------------Run()-----------+ 114 // V | 115 // STOPPED ---Run()--> RUNNING ------Pause()-----+-> PAUSED <------+ 116 // | | | / | | 117 // | | +---- Breakpoint ---+ +-- Step() --+ 118 // | | 119 // | +------------ Trap --------------> TRAPPED 120 // +------------- Finish -------------> FINISHED 121 enum State { STOPPED, RUNNING, PAUSED, FINISHED, TRAPPED }; 122 123 // Tells a thread to pause after certain instructions. 124 enum BreakFlag : uint8_t { 125 None = 0, 126 AfterReturn = 1 << 0, 127 AfterCall = 1 << 1 128 }; 129 130 // Representation of a thread in the interpreter. 131 class V8_EXPORT_PRIVATE Thread { 132 // Don't instante Threads; they will be allocated as ThreadImpl in the 133 // interpreter implementation. 134 Thread() = delete; 135 136 public: 137 // Execution control. 138 State state(); 139 void PushFrame(const WasmFunction* function, WasmVal* args); 140 State Run(); 141 State Step(); 142 void Pause(); 143 void Reset(); 144 145 // Stack inspection and modification. 146 pc_t GetBreakpointPc(); 147 int GetFrameCount(); 148 const InterpretedFrame GetFrame(int index); 149 InterpretedFrame GetMutableFrame(int index); 150 WasmVal GetReturnValue(int index = 0); 151 152 // Returns true if the thread executed an instruction which may produce 153 // nondeterministic results, e.g. float div, float sqrt, and float mul, 154 // where the sign bit of a NaN is nondeterministic. 155 bool PossibleNondeterminism(); 156 157 // Returns the number of calls / function frames executed on this thread. 158 uint64_t NumInterpretedCalls(); 159 160 // Thread-specific breakpoints. 161 // TODO(wasm): Implement this once we support multiple threads. 162 // bool SetBreakpoint(const WasmFunction* function, int pc, bool enabled); 163 // bool GetBreakpoint(const WasmFunction* function, int pc); 164 165 void AddBreakFlags(uint8_t flags); 166 void ClearBreakFlags(); 167 }; 168 169 WasmInterpreter(const ModuleBytesEnv& env, AccountingAllocator* allocator); 170 ~WasmInterpreter(); 171 172 //========================================================================== 173 // Execution controls. 174 //========================================================================== 175 void Run(); 176 void Pause(); 177 178 // Set a breakpoint at {pc} in {function} to be {enabled}. Returns the 179 // previous state of the breakpoint at {pc}. 180 bool SetBreakpoint(const WasmFunction* function, pc_t pc, bool enabled); 181 182 // Gets the current state of the breakpoint at {function}. 183 bool GetBreakpoint(const WasmFunction* function, pc_t pc); 184 185 // Enable or disable tracing for {function}. Return the previous state. 186 bool SetTracing(const WasmFunction* function, bool enabled); 187 188 //========================================================================== 189 // Thread iteration and inspection. 190 //========================================================================== 191 int GetThreadCount(); 192 Thread* GetThread(int id); 193 194 //========================================================================== 195 // Memory access. 196 //========================================================================== 197 size_t GetMemorySize(); 198 WasmVal ReadMemory(size_t offset); 199 void WriteMemory(size_t offset, WasmVal val); 200 201 //========================================================================== 202 // Testing functionality. 203 //========================================================================== 204 // Manually adds a function to this interpreter, returning the index of the 205 // function. 206 int AddFunctionForTesting(const WasmFunction* function); 207 // Manually adds code to the interpreter for the given function. 208 bool SetFunctionCodeForTesting(const WasmFunction* function, 209 const byte* start, const byte* end); 210 211 // Computes the control transfers for the given bytecode. Used internally in 212 // the interpreter, but exposed for testing. 213 static ControlTransferMap ComputeControlTransfersForTesting(Zone* zone, 214 const byte* start, 215 const byte* end); 216 217 private: 218 Zone zone_; 219 WasmInterpreterInternals* internals_; 220 }; 221 222 } // namespace wasm 223 } // namespace internal 224 } // namespace v8 225 226 #endif // V8_WASM_INTERPRETER_H_ 227