• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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);
Step()121     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* const internals_;
212 };
213 
214 }  // namespace wasm
215 }  // namespace internal
216 }  // namespace v8
217 
218 #endif  // V8_WASM_WASM_INTERPRETER_H_
219