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/zone/zone-containers.h"
10 :
11 : namespace v8 {
12 : namespace base {
13 : class AccountingAllocator;
14 : }
15 :
16 : namespace internal {
17 : class WasmInstanceObject;
18 :
19 : namespace wasm {
20 :
21 : // forward declarations.
22 : struct ModuleBytesEnv;
23 : struct WasmFunction;
24 : struct WasmModule;
25 : class WasmInterpreterInternals;
26 :
27 : using pc_t = size_t;
28 : using sp_t = size_t;
29 : using pcdiff_t = int32_t;
30 : using spdiff_t = uint32_t;
31 :
32 : constexpr pc_t kInvalidPc = 0x80000000;
33 :
34 : struct ControlTransferEntry {
35 : // Distance from the instruction to the label to jump to (forward, but can be
36 : // negative).
37 : pcdiff_t pc_diff;
38 : // Delta by which to decrease the stack height.
39 : spdiff_t sp_diff;
40 : // Arity of the block we jump to.
41 : uint32_t target_arity;
42 : };
43 :
44 : using ControlTransferMap = ZoneMap<pc_t, ControlTransferEntry>;
45 :
46 : // Macro for defining union members.
47 : #define FOREACH_UNION_MEMBER(V) \
48 : V(i32, kWasmI32, int32_t) \
49 : V(u32, kWasmI32, uint32_t) \
50 : V(i64, kWasmI64, int64_t) \
51 : V(u64, kWasmI64, uint64_t) \
52 : V(f32, kWasmF32, float) \
53 : V(f64, kWasmF64, double)
54 :
55 : // Representation of values within the interpreter.
56 : struct WasmVal {
57 : ValueType type;
58 : union {
59 : #define DECLARE_FIELD(field, localtype, ctype) ctype field;
60 : FOREACH_UNION_MEMBER(DECLARE_FIELD)
61 : #undef DECLARE_FIELD
62 : } val;
63 :
64 72900 : WasmVal() : type(kWasmStmt) {}
65 :
66 : #define DECLARE_CONSTRUCTOR(field, localtype, ctype) \
67 : explicit WasmVal(ctype v) : type(localtype) { val.field = v; }
68 : FOREACH_UNION_MEMBER(DECLARE_CONSTRUCTOR)
69 : #undef DECLARE_CONSTRUCTOR
70 :
71 : bool operator==(const WasmVal& other) const {
72 : if (type != other.type) return false;
73 : #define CHECK_VAL_EQ(field, localtype, ctype) \
74 : if (type == localtype) { \
75 : return val.field == other.val.field; \
76 : }
77 : FOREACH_UNION_MEMBER(CHECK_VAL_EQ)
78 : #undef CHECK_VAL_EQ
79 : UNREACHABLE();
80 : return false;
81 : }
82 :
83 : template <typename T>
84 : inline T to() const {
85 : UNREACHABLE();
86 : }
87 :
88 : template <typename T>
89 : inline T to_unchecked() const {
90 : UNREACHABLE();
91 : }
92 : };
93 :
94 : #define DECLARE_CAST(field, localtype, ctype) \
95 : template <> \
96 : inline ctype WasmVal::to_unchecked() const { \
97 : return val.field; \
98 : } \
99 : template <> \
100 : inline ctype WasmVal::to() const { \
101 : CHECK_EQ(localtype, type); \
102 : return val.field; \
103 : }
104 4644512 : FOREACH_UNION_MEMBER(DECLARE_CAST)
105 : #undef DECLARE_CAST
106 :
107 : // Representation of frames within the interpreter.
108 : //
109 : // Layout of a frame:
110 : // -----------------
111 : // stack slot #N ‾\.
112 : // ... | stack entries: GetStackHeight(); GetStackValue()
113 : // stack slot #0 _/·
114 : // local #L ‾\.
115 : // ... | locals: GetLocalCount(); GetLocalValue()
116 : // local #P+1 |
117 : // param #P | ‾\.
118 : // ... | | parameters: GetParameterCount(); GetLocalValue()
119 : // param #0 _/· _/·
120 : // -----------------
121 : //
122 : class InterpretedFrame {
123 : public:
124 : const WasmFunction* function() const;
125 : int pc() const;
126 :
127 : int GetParameterCount() const;
128 : int GetLocalCount() const;
129 : int GetStackHeight() const;
130 : WasmVal GetLocalValue(int index) const;
131 : WasmVal GetStackValue(int index) const;
132 :
133 : private:
134 : friend class WasmInterpreter;
135 : // Don't instante InterpretedFrames; they will be allocated as
136 : // InterpretedFrameImpl in the interpreter implementation.
137 : InterpretedFrame() = delete;
138 : DISALLOW_COPY_AND_ASSIGN(InterpretedFrame);
139 : };
140 :
141 : // An interpreter capable of executing WASM.
142 : class V8_EXPORT_PRIVATE WasmInterpreter {
143 : public:
144 : // State machine for a Thread:
145 : // +---------Run()/Step()--------+
146 : // V |
147 : // STOPPED ---Run()--> RUNNING ------Pause()-----+-> PAUSED
148 : // ^ | | | | /
149 : // +- HandleException -+ | | +--- Breakpoint ---+
150 : // | |
151 : // | +---------- Trap --------------> TRAPPED
152 : // +----------- Finish -------------> FINISHED
153 : enum State { STOPPED, RUNNING, PAUSED, FINISHED, TRAPPED };
154 :
155 : // Tells a thread to pause after certain instructions.
156 : enum BreakFlag : uint8_t {
157 : None = 0,
158 : AfterReturn = 1 << 0,
159 : AfterCall = 1 << 1
160 : };
161 :
162 : // Representation of a thread in the interpreter.
163 : class V8_EXPORT_PRIVATE Thread {
164 : // Don't instante Threads; they will be allocated as ThreadImpl in the
165 : // interpreter implementation.
166 : Thread() = delete;
167 :
168 : public:
169 : enum ExceptionHandlingResult { HANDLED, UNWOUND };
170 :
171 : // Execution control.
172 : State state();
173 : void InitFrame(const WasmFunction* function, WasmVal* args);
174 : // Pass -1 as num_steps to run till completion, pause or breakpoint.
175 : State Run(int num_steps = -1);
176 219 : State Step() { return Run(1); }
177 : void Pause();
178 : void Reset();
179 : // Handle the pending exception in the passed isolate. Unwind the stack
180 : // accordingly. Return whether the exception was handled inside wasm.
181 : ExceptionHandlingResult HandleException(Isolate* isolate);
182 :
183 : // Stack inspection and modification.
184 : pc_t GetBreakpointPc();
185 : // TODO(clemensh): Make this uint32_t.
186 : int GetFrameCount();
187 : // The InterpretedFrame is only valid as long as the Thread is paused.
188 : std::unique_ptr<InterpretedFrame> GetFrame(int index);
189 : WasmVal GetReturnValue(int index = 0);
190 : TrapReason GetTrapReason();
191 :
192 : // Returns true if the thread executed an instruction which may produce
193 : // nondeterministic results, e.g. float div, float sqrt, and float mul,
194 : // where the sign bit of a NaN is nondeterministic.
195 : bool PossibleNondeterminism();
196 :
197 : // Returns the number of calls / function frames executed on this thread.
198 : uint64_t NumInterpretedCalls();
199 :
200 : // Thread-specific breakpoints.
201 : // TODO(wasm): Implement this once we support multiple threads.
202 : // bool SetBreakpoint(const WasmFunction* function, int pc, bool enabled);
203 : // bool GetBreakpoint(const WasmFunction* function, int pc);
204 :
205 : void AddBreakFlags(uint8_t flags);
206 : void ClearBreakFlags();
207 :
208 : // Each thread can have multiple activations, each represented by a portion
209 : // of the stack frames of this thread. StartActivation returns the id
210 : // (counting from 0 up) of the started activation.
211 : // Activations must be properly stacked, i.e. if FinishActivation is called,
212 : // the given id must the the latest activation on the stack.
213 : uint32_t NumActivations();
214 : uint32_t StartActivation();
215 : void FinishActivation(uint32_t activation_id);
216 : // Return the frame base of the given activation, i.e. the number of frames
217 : // when this activation was started.
218 : uint32_t ActivationFrameBase(uint32_t activation_id);
219 : };
220 :
221 : WasmInterpreter(Isolate* isolate, const ModuleBytesEnv& env);
222 : ~WasmInterpreter();
223 :
224 : //==========================================================================
225 : // Execution controls.
226 : //==========================================================================
227 : void Run();
228 : void Pause();
229 :
230 : // Set a breakpoint at {pc} in {function} to be {enabled}. Returns the
231 : // previous state of the breakpoint at {pc}.
232 : bool SetBreakpoint(const WasmFunction* function, pc_t pc, bool enabled);
233 :
234 : // Gets the current state of the breakpoint at {function}.
235 : bool GetBreakpoint(const WasmFunction* function, pc_t pc);
236 :
237 : // Enable or disable tracing for {function}. Return the previous state.
238 : bool SetTracing(const WasmFunction* function, bool enabled);
239 :
240 : // Set the associated wasm instance object.
241 : // If the instance object has been set, some tables stored inside it are used
242 : // instead of the tables stored in the WasmModule struct. This allows to call
243 : // back and forth between the interpreter and outside code (JS or wasm
244 : // compiled) without repeatedly copying information.
245 : void SetInstanceObject(WasmInstanceObject*);
246 :
247 : //==========================================================================
248 : // Thread iteration and inspection.
249 : //==========================================================================
250 : int GetThreadCount();
251 : Thread* GetThread(int id);
252 :
253 : //==========================================================================
254 : // Memory access.
255 : //==========================================================================
256 : size_t GetMemorySize();
257 : WasmVal ReadMemory(size_t offset);
258 : void WriteMemory(size_t offset, WasmVal val);
259 :
260 : //==========================================================================
261 : // Testing functionality.
262 : //==========================================================================
263 : // Manually adds a function to this interpreter. The func_index of the
264 : // function must match the current number of functions.
265 : void AddFunctionForTesting(const WasmFunction* function);
266 : // Manually adds code to the interpreter for the given function.
267 : void SetFunctionCodeForTesting(const WasmFunction* function,
268 : const byte* start, const byte* end);
269 :
270 : // Computes the control transfers for the given bytecode. Used internally in
271 : // the interpreter, but exposed for testing.
272 : static ControlTransferMap ComputeControlTransfersForTesting(
273 : Zone* zone, const WasmModule* module, const byte* start, const byte* end);
274 :
275 : private:
276 : Zone zone_;
277 : WasmInterpreterInternals* internals_;
278 : };
279 :
280 : } // namespace wasm
281 : } // namespace internal
282 : } // namespace v8
283 :
284 : #endif // V8_WASM_INTERPRETER_H_
|