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