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 WasmFunction;
21 struct WasmInstance;
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, kAstI32, int32_t) \
36 V(u32, kAstI32, uint32_t) \
37 V(i64, kAstI64, int64_t) \
38 V(u64, kAstI64, uint64_t) \
39 V(f32, kAstF32, float) \
40 V(f64, kAstF64, double)
41
42 // Representation of values within the interpreter.
43 struct WasmVal {
44 LocalType 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(kAstStmt) {}
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 T to() {
60 UNREACHABLE();
61 }
62 };
63
64 #define DECLARE_CAST(field, localtype, ctype) \
65 template <> \
66 inline ctype WasmVal::to() { \
67 CHECK_EQ(localtype, type); \
68 return val.field; \
69 }
FOREACH_UNION_MEMBER(DECLARE_CAST)70 FOREACH_UNION_MEMBER(DECLARE_CAST)
71 #undef DECLARE_CAST
72
73 template <>
74 inline void WasmVal::to() {
75 CHECK_EQ(kAstStmt, type);
76 }
77
78 // Representation of frames within the interpreter.
79 class WasmFrame {
80 public:
function()81 const WasmFunction* function() const { return function_; }
pc()82 int pc() const { return pc_; }
83
84 private:
85 friend class WasmInterpreter;
86
WasmFrame(const WasmFunction * function,int pc,int fp,int sp)87 WasmFrame(const WasmFunction* function, int pc, int fp, int sp)
88 : function_(function), pc_(pc), fp_(fp), sp_(sp) {}
89
90 const WasmFunction* function_;
91 int pc_;
92 int fp_;
93 int sp_;
94 };
95
96 // An interpreter capable of executing WASM.
97 class V8_EXPORT_PRIVATE WasmInterpreter {
98 public:
99 // State machine for a Thread:
100 // +---------------Run()-----------+
101 // V |
102 // STOPPED ---Run()--> RUNNING ------Pause()-----+-> PAUSED <------+
103 // | | | / | |
104 // | | +---- Breakpoint ---+ +-- Step() --+
105 // | |
106 // | +------------ Trap --------------> TRAPPED
107 // +------------- Finish -------------> FINISHED
108 enum State { STOPPED, RUNNING, PAUSED, FINISHED, TRAPPED };
109
110 // Representation of a thread in the interpreter.
111 class Thread {
112 public:
113 // Execution control.
114 virtual State state() = 0;
115 virtual void PushFrame(const WasmFunction* function, WasmVal* args) = 0;
116 virtual State Run() = 0;
117 virtual State Step() = 0;
118 virtual void Pause() = 0;
119 virtual void Reset() = 0;
~Thread()120 virtual ~Thread() {}
121
122 // Stack inspection and modification.
123 virtual pc_t GetBreakpointPc() = 0;
124 virtual int GetFrameCount() = 0;
125 virtual const WasmFrame* GetFrame(int index) = 0;
126 virtual WasmFrame* GetMutableFrame(int index) = 0;
127 virtual WasmVal GetReturnValue(int index = 0) = 0;
128 // Returns true if the thread executed an instruction which may produce
129 // nondeterministic results, e.g. float div, float sqrt, and float mul,
130 // where the sign bit of a NaN is nondeterministic.
131 virtual bool PossibleNondeterminism() = 0;
132
133 // Thread-specific breakpoints.
134 bool SetBreakpoint(const WasmFunction* function, int pc, bool enabled);
135 bool GetBreakpoint(const WasmFunction* function, int pc);
136 };
137
138 WasmInterpreter(WasmInstance* instance, AccountingAllocator* allocator);
139 ~WasmInterpreter();
140
141 //==========================================================================
142 // Execution controls.
143 //==========================================================================
144 void Run();
145 void Pause();
146
147 // Set a breakpoint at {pc} in {function} to be {enabled}. Returns the
148 // previous state of the breakpoint at {pc}.
149 bool SetBreakpoint(const WasmFunction* function, pc_t pc, bool enabled);
150
151 // Gets the current state of the breakpoint at {function}.
152 bool GetBreakpoint(const WasmFunction* function, pc_t pc);
153
154 // Enable or disable tracing for {function}. Return the previous state.
155 bool SetTracing(const WasmFunction* function, bool enabled);
156
157 //==========================================================================
158 // Thread iteration and inspection.
159 //==========================================================================
160 int GetThreadCount();
161 Thread* GetThread(int id);
162
163 //==========================================================================
164 // Stack frame inspection.
165 //==========================================================================
166 WasmVal GetLocalVal(const WasmFrame* frame, int index);
167 WasmVal GetExprVal(const WasmFrame* frame, int pc);
168 void SetLocalVal(WasmFrame* frame, int index, WasmVal val);
169 void SetExprVal(WasmFrame* frame, int pc, WasmVal val);
170
171 //==========================================================================
172 // Memory access.
173 //==========================================================================
174 size_t GetMemorySize();
175 WasmVal ReadMemory(size_t offset);
176 void WriteMemory(size_t offset, WasmVal val);
177
178 //==========================================================================
179 // Testing functionality.
180 //==========================================================================
181 // Manually adds a function to this interpreter, returning the index of the
182 // function.
183 int AddFunctionForTesting(const WasmFunction* function);
184 // Manually adds code to the interpreter for the given function.
185 bool SetFunctionCodeForTesting(const WasmFunction* function,
186 const byte* start, const byte* end);
187
188 // Computes the control transfers for the given bytecode. Used internally in
189 // the interpreter, but exposed for testing.
190 static ControlTransferMap ComputeControlTransfersForTesting(Zone* zone,
191 const byte* start,
192 const byte* end);
193
194 private:
195 Zone zone_;
196 WasmInterpreterInternals* internals_;
197 };
198
199 } // namespace wasm
200 } // namespace internal
201 } // namespace v8
202
203 #endif // V8_WASM_INTERPRETER_H_
204