// 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.

#ifndef V8_WASM_WASM_INTERPRETER_H_
#define V8_WASM_WASM_INTERPRETER_H_

#include <memory>

#include "src/wasm/wasm-opcodes.h"
#include "src/wasm/wasm-value.h"
#include "src/zone/zone-containers.h"

namespace v8 {

namespace internal {
class WasmInstanceObject;

namespace wasm {

// Forward declarations.
struct ModuleWireBytes;
struct WasmFunction;
struct WasmModule;
class WasmInterpreterInternals;

using pc_t = size_t;
using sp_t = size_t;
using pcdiff_t = int32_t;
using spdiff_t = uint32_t;

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;
};

using ControlTransferMap = ZoneMap<pc_t, ControlTransferEntry>;

// An interpreter capable of executing WebAssembly.
class V8_EXPORT_PRIVATE WasmInterpreter {
 public:
  // State machine for a Thread:
  //    +----------------------------------------------------------+
  //    |                    +--------Run()/Step()---------+       |
  //    V                    V                             |       |
  // STOPPED ---Run()-->  RUNNING  ------Pause()-----+-> PAUSED <--+
  //    ^                 | | | |                   /              |
  //    +--- Exception ---+ | | +--- Breakpoint ---+       RaiseException() <--+
  //                        | |                                                |
  //                        | +---------- Trap --------------> TRAPPED --------+
  //                        +----------- Finish -------------> FINISHED
  enum State { STOPPED, RUNNING, PAUSED, FINISHED, TRAPPED };

  // Tells a thread to pause after certain instructions.
  enum BreakFlag : uint8_t {
    None = 0,
    AfterReturn = 1 << 0,
    AfterCall = 1 << 1
  };

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

   public:
    enum ExceptionHandlingResult { HANDLED, UNWOUND };

    // Execution control.
    State state();
    void InitFrame(const WasmFunction* function, WasmValue* args);
    // Pass -1 as num_steps to run till completion, pause or breakpoint.
    State Run(int num_steps = -1);
    State Step() { return Run(1); }
    void Pause();
    void Reset();

    // Raise an exception in the current activation and unwind the stack
    // accordingly. Return whether the exception was handled inside wasm:
    //  - HANDLED: Activation at handler position and in {PAUSED} state.
    //  - UNWOUND: Frames unwound, exception pending, and in {STOPPED} state.
    ExceptionHandlingResult RaiseException(Isolate*, Handle<Object> exception);

    // Stack inspection and modification.
    int GetFrameCount();
    WasmValue GetReturnValue(int index = 0);
    TrapReason GetTrapReason();

    // 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.
    bool PossibleNondeterminism();

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

    // 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);
  };

  WasmInterpreter(Isolate* isolate, const WasmModule* module,
                  const ModuleWireBytes& wire_bytes,
                  Handle<WasmInstanceObject> instance);

  ~WasmInterpreter();

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

  //==========================================================================
  // Thread iteration and inspection.
  //==========================================================================
  int GetThreadCount();
  Thread* GetThread(int id);

  //==========================================================================
  // Testing functionality.
  //==========================================================================
  // 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);
  // Manually adds code to the interpreter for the given function.
  void SetFunctionCodeForTesting(const WasmFunction* function,
                                 const byte* start, const byte* end);

  // Computes the control transfers for the given bytecode. Used internally in
  // the interpreter, but exposed for testing.
  static ControlTransferMap ComputeControlTransfersForTesting(
      Zone* zone, const WasmModule* module, const byte* start, const byte* end);

 private:
  Zone zone_;
  std::unique_ptr<WasmInterpreterInternals> internals_;

  DISALLOW_COPY_AND_ASSIGN(WasmInterpreter);
};

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

#endif  // V8_WASM_WASM_INTERPRETER_H_