wasm-interpreter.h 7.57 KB
Newer Older
1 2 3 4
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
#ifndef V8_WASM_WASM_INTERPRETER_H_
#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 13 14

namespace v8 {

namespace internal {
15 16
class WasmInstanceObject;

17 18 19
namespace wasm {

// forward declarations.
20
struct ModuleWireBytes;
21
struct WasmFunction;
22
struct WasmModule;
23 24
class WasmInterpreterInternals;

25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
using pc_t = size_t;
using sp_t = size_t;
using pcdiff_t = int32_t;
using spdiff_t = uint32_t;

constexpr pc_t kInvalidPc = 0x80000000;

struct ControlTransferEntry {
  // Distance from the instruction to the label to jump to (forward, but can be
  // negative).
  pcdiff_t pc_diff;
  // Delta by which to decrease the stack height.
  spdiff_t sp_diff;
  // Arity of the block we jump to.
  uint32_t target_arity;
};
41

42
using ControlTransferMap = ZoneMap<pc_t, ControlTransferEntry>;
43 44

// Representation of frames within the interpreter.
45 46 47 48 49 50 51 52 53 54 55 56 57 58
//
// Layout of a frame:
// -----------------
// stack slot #N  ‾\.
// ...             |  stack entries: GetStackHeight(); GetStackValue()
// stack slot #0  _/·
// local #L       ‾\.
// ...             |  locals: GetLocalCount(); GetLocalValue()
// local #P+1      |
// param #P        |   ‾\.
// ...             |    | parameters: GetParameterCount(); GetLocalValue()
// param #0       _/·  _/·
// -----------------
//
59
class InterpretedFrame {
60
 public:
61 62
  const WasmFunction* function() const;
  int pc() const;
63 64

  int GetParameterCount() const;
65 66
  int GetLocalCount() const;
  int GetStackHeight() const;
67 68
  WasmValue GetLocalValue(int index) const;
  WasmValue GetStackValue(int index) const;
69 70 71

 private:
  friend class WasmInterpreter;
72 73 74 75
  // Don't instante InterpretedFrames; they will be allocated as
  // InterpretedFrameImpl in the interpreter implementation.
  InterpretedFrame() = delete;
  DISALLOW_COPY_AND_ASSIGN(InterpretedFrame);
76 77
};

Marja Hölttä's avatar
Marja Hölttä committed
78 79 80 81 82 83
// Deleter struct to delete the underlying InterpretedFrameImpl without
// violating language specifications.
struct InterpretedFrameDeleter {
  void operator()(InterpretedFrame* ptr);
};

84
// An interpreter capable of executing WebAssembly.
85
class V8_EXPORT_PRIVATE WasmInterpreter {
86 87
 public:
  // State machine for a Thread:
88 89 90 91 92
  //                         +---------Run()/Step()--------+
  //                         V                             |
  // STOPPED ---Run()-->  RUNNING  ------Pause()-----+-> PAUSED
  //  ^                   | | | |                   /
  //  +- HandleException -+ | | +--- Breakpoint ---+
93 94 95
  //                        | |
  //                        | +---------- Trap --------------> TRAPPED
  //                        +----------- Finish -------------> FINISHED
96 97
  enum State { STOPPED, RUNNING, PAUSED, FINISHED, TRAPPED };

98 99 100 101 102 103 104
  // Tells a thread to pause after certain instructions.
  enum BreakFlag : uint8_t {
    None = 0,
    AfterReturn = 1 << 0,
    AfterCall = 1 << 1
  };

Marja Hölttä's avatar
Marja Hölttä committed
105
  using FramePtr = std::unique_ptr<InterpretedFrame, InterpretedFrameDeleter>;
106

107
  // Representation of a thread in the interpreter.
108
  class V8_EXPORT_PRIVATE Thread {
109 110 111
    // Don't instante Threads; they will be allocated as ThreadImpl in the
    // interpreter implementation.
    Thread() = delete;
112

113
   public:
114 115
    enum ExceptionHandlingResult { HANDLED, UNWOUND };

116
    // Execution control.
117
    State state();
118
    void InitFrame(const WasmFunction* function, WasmValue* args);
119 120 121
    // Pass -1 as num_steps to run till completion, pause or breakpoint.
    State Run(int num_steps = -1);
    State Step() { return Run(1); }
122 123
    void Pause();
    void Reset();
124 125 126
    // Handle the pending exception in the passed isolate. Unwind the stack
    // accordingly. Return whether the exception was handled inside wasm.
    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 138 139
    // Returns true if the thread executed an instruction which may produce
    // nondeterministic results, e.g. float div, float sqrt, and float mul,
    // where the sign bit of a NaN is nondeterministic.
140
    bool PossibleNondeterminism();
141

142 143 144
    // Returns the number of calls / function frames executed on this thread.
    uint64_t NumInterpretedCalls();

145
    // Thread-specific breakpoints.
146 147 148
    // TODO(wasm): Implement this once we support multiple threads.
    // bool SetBreakpoint(const WasmFunction* function, int pc, bool enabled);
    // bool GetBreakpoint(const WasmFunction* function, int pc);
149 150 151

    void AddBreakFlags(uint8_t flags);
    void ClearBreakFlags();
152 153 154 155 156 157 158 159 160 161 162 163

    // Each thread can have multiple activations, each represented by a portion
    // of the stack frames of this thread. StartActivation returns the id
    // (counting from 0 up) of the started activation.
    // Activations must be properly stacked, i.e. if FinishActivation is called,
    // the given id must the the latest activation on the stack.
    uint32_t NumActivations();
    uint32_t StartActivation();
    void FinishActivation(uint32_t activation_id);
    // Return the frame base of the given activation, i.e. the number of frames
    // when this activation was started.
    uint32_t ActivationFrameBase(uint32_t activation_id);
164 165
  };

166
  WasmInterpreter(Isolate* isolate, const WasmModule* module,
167 168
                  const ModuleWireBytes& wire_bytes,
                  Handle<WasmInstanceObject> instance);
169 170 171 172 173 174 175 176 177 178
  ~WasmInterpreter();

  //==========================================================================
  // Execution controls.
  //==========================================================================
  void Run();
  void Pause();

  // Set a breakpoint at {pc} in {function} to be {enabled}. Returns the
  // 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 185 186 187 188 189 190

  // Enable or disable tracing for {function}. Return the previous state.
  bool SetTracing(const WasmFunction* function, bool enabled);

  //==========================================================================
  // Thread iteration and inspection.
  //==========================================================================
  int GetThreadCount();
191
  Thread* GetThread(int id);
192 193 194 195

  //==========================================================================
  // Testing functionality.
  //==========================================================================
196 197 198
  // Manually adds a function to this interpreter. The func_index of the
  // function must match the current number of functions.
  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 205
  // Computes the control transfers for the given bytecode. Used internally in
  // the interpreter, but exposed for testing.
206 207
  static ControlTransferMap ComputeControlTransfersForTesting(
      Zone* zone, const WasmModule* module, const byte* start, const byte* end);
208 209 210

 private:
  Zone zone_;
211
  WasmInterpreterInternals* internals_;
212 213 214 215 216 217
};

}  // namespace wasm
}  // namespace internal
}  // namespace v8

218
#endif  // V8_WASM_WASM_INTERPRETER_H_