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_WASM_INTERPRETER_H_ 6 #define V8_WASM_WASM_INTERPRETER_H_ 7 8 #include "src/wasm/wasm-opcodes.h" 9 #include "src/wasm/wasm-value.h" 10 #include "src/zone/zone-containers.h" 11 12 namespace v8 { 13 14 namespace internal { 15 class WasmInstanceObject; 16 17 namespace wasm { 18 19 // forward declarations. 20 struct ModuleWireBytes; 21 struct WasmFunction; 22 struct WasmModule; 23 class WasmInterpreterInternals; 24 25 using pc_t = size_t; 26 using sp_t = size_t; 27 using pcdiff_t = int32_t; 28 using spdiff_t = uint32_t; 29 30 constexpr pc_t kInvalidPc = 0x80000000; 31 32 struct ControlTransferEntry { 33 // Distance from the instruction to the label to jump to (forward, but can be 34 // negative). 35 pcdiff_t pc_diff; 36 // Delta by which to decrease the stack height. 37 spdiff_t sp_diff; 38 // Arity of the block we jump to. 39 uint32_t target_arity; 40 }; 41 42 using ControlTransferMap = ZoneMap<pc_t, ControlTransferEntry>; 43 44 // Representation of frames within the interpreter. 45 // 46 // Layout of a frame: 47 // ----------------- 48 // stack slot #N \. 49 // ... | stack entries: GetStackHeight(); GetStackValue() 50 // stack slot #0 _/ 51 // local #L \. 52 // ... | locals: GetLocalCount(); GetLocalValue() 53 // local #P+1 | 54 // param #P | \. 55 // ... | | parameters: GetParameterCount(); GetLocalValue() 56 // param #0 _/ _/ 57 // ----------------- 58 // 59 class InterpretedFrame { 60 public: 61 const WasmFunction* function() const; 62 int pc() const; 63 64 int GetParameterCount() const; 65 int GetLocalCount() const; 66 int GetStackHeight() const; 67 WasmValue GetLocalValue(int index) const; 68 WasmValue GetStackValue(int index) const; 69 70 private: 71 friend class WasmInterpreter; 72 // Don't instante InterpretedFrames; they will be allocated as 73 // InterpretedFrameImpl in the interpreter implementation. 74 InterpretedFrame() = delete; 75 DISALLOW_COPY_AND_ASSIGN(InterpretedFrame); 76 }; 77 78 // Deleter struct to delete the underlying InterpretedFrameImpl without 79 // violating language specifications. 80 struct InterpretedFrameDeleter { 81 void operator()(InterpretedFrame* ptr); 82 }; 83 84 // An interpreter capable of executing WebAssembly. 85 class V8_EXPORT_PRIVATE WasmInterpreter { 86 public: 87 // State machine for a Thread: 88 // +---------Run()/Step()--------+ 89 // V | 90 // STOPPED ---Run()--> RUNNING ------Pause()-----+-> PAUSED 91 // ^ | | | | / 92 // +- HandleException -+ | | +--- Breakpoint ---+ 93 // | | 94 // | +---------- Trap --------------> TRAPPED 95 // +----------- Finish -------------> FINISHED 96 enum State { STOPPED, RUNNING, PAUSED, FINISHED, TRAPPED }; 97 98 // Tells a thread to pause after certain instructions. 99 enum BreakFlag : uint8_t { 100 None = 0, 101 AfterReturn = 1 << 0, 102 AfterCall = 1 << 1 103 }; 104 105 using FramePtr = std::unique_ptr<InterpretedFrame, InterpretedFrameDeleter>; 106 107 // Representation of a thread in the interpreter. 108 class V8_EXPORT_PRIVATE Thread { 109 // Don't instante Threads; they will be allocated as ThreadImpl in the 110 // interpreter implementation. 111 Thread() = delete; 112 113 public: 114 enum ExceptionHandlingResult { HANDLED, UNWOUND }; 115 116 // Execution control. 117 State state(); 118 void InitFrame(const WasmFunction* function, WasmValue* args); 119 // Pass -1 as num_steps to run till completion, pause or breakpoint. 120 State Run(int num_steps = -1); 121 State Step() { return Run(1); } 122 void Pause(); 123 void Reset(); 124 // Handle the pending exception in the passed isolate. Unwind the stack 125 // accordingly. Return whether the exception was handled inside wasm. 126 ExceptionHandlingResult HandleException(Isolate* isolate); 127 128 // Stack inspection and modification. 129 pc_t GetBreakpointPc(); 130 // TODO(clemensh): Make this uint32_t. 131 int GetFrameCount(); 132 // The InterpretedFrame is only valid as long as the Thread is paused. 133 FramePtr GetFrame(int index); 134 WasmValue GetReturnValue(int index = 0); 135 TrapReason GetTrapReason(); 136 137 // Returns true if the thread executed an instruction which may produce 138 // nondeterministic results, e.g. float div, float sqrt, and float mul, 139 // where the sign bit of a NaN is nondeterministic. 140 bool PossibleNondeterminism(); 141 142 // Returns the number of calls / function frames executed on this thread. 143 uint64_t NumInterpretedCalls(); 144 145 // Thread-specific breakpoints. 146 // TODO(wasm): Implement this once we support multiple threads. 147 // bool SetBreakpoint(const WasmFunction* function, int pc, bool enabled); 148 // bool GetBreakpoint(const WasmFunction* function, int pc); 149 150 void AddBreakFlags(uint8_t flags); 151 void ClearBreakFlags(); 152 153 // Each thread can have multiple activations, each represented by a portion 154 // of the stack frames of this thread. StartActivation returns the id 155 // (counting from 0 up) of the started activation. 156 // Activations must be properly stacked, i.e. if FinishActivation is called, 157 // the given id must the the latest activation on the stack. 158 uint32_t NumActivations(); 159 uint32_t StartActivation(); 160 void FinishActivation(uint32_t activation_id); 161 // Return the frame base of the given activation, i.e. the number of frames 162 // when this activation was started. 163 uint32_t ActivationFrameBase(uint32_t activation_id); 164 }; 165 166 WasmInterpreter(Isolate* isolate, const WasmModule* module, 167 const ModuleWireBytes& wire_bytes, 168 Handle<WasmInstanceObject> instance); 169 ~WasmInterpreter(); 170 171 //========================================================================== 172 // Execution controls. 173 //========================================================================== 174 void Run(); 175 void Pause(); 176 177 // Set a breakpoint at {pc} in {function} to be {enabled}. Returns the 178 // previous state of the breakpoint at {pc}. 179 bool SetBreakpoint(const WasmFunction* function, pc_t pc, bool enabled); 180 181 // Gets the current state of the breakpoint at {function}. 182 bool GetBreakpoint(const WasmFunction* function, pc_t pc); 183 184 // Enable or disable tracing for {function}. Return the previous state. 185 bool SetTracing(const WasmFunction* function, bool enabled); 186 187 //========================================================================== 188 // Thread iteration and inspection. 189 //========================================================================== 190 int GetThreadCount(); 191 Thread* GetThread(int id); 192 193 //========================================================================== 194 // Testing functionality. 195 //========================================================================== 196 // Manually adds a function to this interpreter. The func_index of the 197 // function must match the current number of functions. 198 void AddFunctionForTesting(const WasmFunction* function); 199 // Manually adds code to the interpreter for the given function. 200 void SetFunctionCodeForTesting(const WasmFunction* function, 201 const byte* start, const byte* end); 202 void SetCallIndirectTestMode(); 203 204 // Computes the control transfers for the given bytecode. Used internally in 205 // the interpreter, but exposed for testing. 206 static ControlTransferMap ComputeControlTransfersForTesting( 207 Zone* zone, const WasmModule* module, const byte* start, const byte* end); 208 209 private: 210 Zone zone_; 211 WasmInterpreterInternals* const internals_; 212 }; 213 214 } // namespace wasm 215 } // namespace internal 216 } // namespace v8 217 218 #endif // V8_WASM_WASM_INTERPRETER_H_ 219