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
WasmValWasmVal51 WasmVal() : type(kWasmStmt) {}
52
53 #define DECLARE_CONSTRUCTOR(field, localtype, ctype) \
54 explicit WasmVal(ctype v) : type(localtype) { val.field = v; }
FOREACH_UNION_MEMBERWasmVal55 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>
to_uncheckedWasmVal64 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 }
FOREACH_UNION_MEMBER(DECLARE_CAST)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