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_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 V8_EXPORT_PRIVATE 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 V8_EXPORT_PRIVATE 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 : // +----------------------------------------------------------+
89 : // | +--------Run()/Step()---------+ |
90 : // V V | |
91 : // STOPPED ---Run()--> RUNNING ------Pause()-----+-> PAUSED <--+
92 : // ^ | | | | / |
93 : // +--- Exception ---+ | | +--- Breakpoint ---+ RaiseException() <--+
94 : // | | |
95 : // | +---------- Trap --------------> TRAPPED --------+
96 : // +----------- Finish -------------> FINISHED
97 : enum State { STOPPED, RUNNING, PAUSED, FINISHED, TRAPPED };
98 :
99 : // Tells a thread to pause after certain instructions.
100 : enum BreakFlag : uint8_t {
101 : None = 0,
102 : AfterReturn = 1 << 0,
103 : AfterCall = 1 << 1
104 : };
105 :
106 : using FramePtr = std::unique_ptr<InterpretedFrame, InterpretedFrameDeleter>;
107 :
108 : // Representation of a thread in the interpreter.
109 : class V8_EXPORT_PRIVATE Thread {
110 : // Don't instante Threads; they will be allocated as ThreadImpl in the
111 : // interpreter implementation.
112 : Thread() = delete;
113 :
114 : public:
115 : enum ExceptionHandlingResult { HANDLED, UNWOUND };
116 :
117 : // Execution control.
118 : State state();
119 : void InitFrame(const WasmFunction* function, WasmValue* args);
120 : // Pass -1 as num_steps to run till completion, pause or breakpoint.
121 : State Run(int num_steps = -1);
122 3116 : State Step() { return Run(1); }
123 : void Pause();
124 : void Reset();
125 :
126 : // Raise an exception in the current activation and unwind the stack
127 : // accordingly. Return whether the exception was handled inside wasm:
128 : // - HANDLED: Activation at handler position and in {PAUSED} state.
129 : // - UNWOUND: Frames unwound, exception pending, and in {STOPPED} state.
130 : ExceptionHandlingResult RaiseException(Isolate*, Handle<Object> exception);
131 :
132 : // Stack inspection and modification.
133 : pc_t GetBreakpointPc();
134 : // TODO(clemensh): Make this uint32_t.
135 : int GetFrameCount();
136 : // The InterpretedFrame is only valid as long as the Thread is paused.
137 : FramePtr GetFrame(int index);
138 : WasmValue GetReturnValue(int index = 0);
139 : TrapReason GetTrapReason();
140 :
141 : // Returns true if the thread executed an instruction which may produce
142 : // nondeterministic results, e.g. float div, float sqrt, and float mul,
143 : // where the sign bit of a NaN is nondeterministic.
144 : bool PossibleNondeterminism();
145 :
146 : // Returns the number of calls / function frames executed on this thread.
147 : uint64_t NumInterpretedCalls();
148 :
149 : // Thread-specific breakpoints.
150 : // TODO(wasm): Implement this once we support multiple threads.
151 : // bool SetBreakpoint(const WasmFunction* function, int pc, bool enabled);
152 : // bool GetBreakpoint(const WasmFunction* function, int pc);
153 :
154 : void AddBreakFlags(uint8_t flags);
155 : void ClearBreakFlags();
156 :
157 : // Each thread can have multiple activations, each represented by a portion
158 : // of the stack frames of this thread. StartActivation returns the id
159 : // (counting from 0 up) of the started activation.
160 : // Activations must be properly stacked, i.e. if FinishActivation is called,
161 : // the given id must the the latest activation on the stack.
162 : uint32_t NumActivations();
163 : uint32_t StartActivation();
164 : void FinishActivation(uint32_t activation_id);
165 : // Return the frame base of the given activation, i.e. the number of frames
166 : // when this activation was started.
167 : uint32_t ActivationFrameBase(uint32_t activation_id);
168 : };
169 :
170 : WasmInterpreter(Isolate* isolate, const WasmModule* module,
171 : const ModuleWireBytes& wire_bytes,
172 : Handle<WasmInstanceObject> instance);
173 : ~WasmInterpreter();
174 :
175 : //==========================================================================
176 : // Execution controls.
177 : //==========================================================================
178 : void Run();
179 : void Pause();
180 :
181 : // Set a breakpoint at {pc} in {function} to be {enabled}. Returns the
182 : // previous state of the breakpoint at {pc}.
183 : bool SetBreakpoint(const WasmFunction* function, pc_t pc, bool enabled);
184 :
185 : // Gets the current state of the breakpoint at {function}.
186 : bool GetBreakpoint(const WasmFunction* function, pc_t pc);
187 :
188 : // Enable or disable tracing for {function}. Return the previous state.
189 : bool SetTracing(const WasmFunction* function, bool enabled);
190 :
191 : //==========================================================================
192 : // Thread iteration and inspection.
193 : //==========================================================================
194 : int GetThreadCount();
195 : Thread* GetThread(int id);
196 :
197 : //==========================================================================
198 : // Testing functionality.
199 : //==========================================================================
200 : // Manually adds a function to this interpreter. The func_index of the
201 : // function must match the current number of functions.
202 : void AddFunctionForTesting(const WasmFunction* function);
203 : // Manually adds code to the interpreter for the given function.
204 : void SetFunctionCodeForTesting(const WasmFunction* function,
205 : const byte* start, const byte* end);
206 :
207 : // Computes the control transfers for the given bytecode. Used internally in
208 : // the interpreter, but exposed for testing.
209 : static ControlTransferMap ComputeControlTransfersForTesting(
210 : Zone* zone, const WasmModule* module, const byte* start, const byte* end);
211 :
212 : private:
213 : Zone zone_;
214 : WasmInterpreterInternals* internals_;
215 : };
216 :
217 : } // namespace wasm
218 : } // namespace internal
219 : } // namespace v8
220 :
221 : #endif // V8_WASM_WASM_INTERPRETER_H_
|