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
11namespace v8 {
12namespace base {
13class AccountingAllocator;
14}
15
16namespace internal {
17namespace wasm {
18
19// forward declarations.
20struct ModuleBytesEnv;
21struct WasmFunction;
22class WasmInterpreterInternals;
23
24typedef size_t pc_t;
25typedef size_t sp_t;
26typedef int32_t pcdiff_t;
27typedef uint32_t spdiff_t;
28
29const pc_t kInvalidPc = 0x80000000;
30
31typedef 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.
43struct 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
51  WasmVal() : type(kWasmStmt) {}
52
53#define DECLARE_CONSTRUCTOR(field, localtype, ctype) \
54  explicit WasmVal(ctype v) : type(localtype) { val.field = v; }
55  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>
64  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  }
79FOREACH_UNION_MEMBER(DECLARE_CAST)
80#undef DECLARE_CAST
81
82// Representation of frames within the interpreter.
83class 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.
110class 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