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