Home | History | Annotate | Download | only in wasm
      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     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