// Copyright 2015 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_INTERPRETER_BYTECODES_H_
#define V8_INTERPRETER_BYTECODES_H_

#include <iosfwd>

// Clients of this interface shouldn't depend on lots of interpreter internals.
// Do not include anything from src/interpreter here!
#include "src/utils.h"

namespace v8 {
namespace internal {
namespace interpreter {

// The list of operand types used by bytecodes.
#define OPERAND_TYPE_LIST(V) \
  V(None)                    \
  V(Imm8)                    \
  V(Idx)                     \
  V(Reg)

// The list of bytecodes which are interpreted by the interpreter.
#define BYTECODE_LIST(V)               \
                                       \
  /* Loading the accumulator */        \
  V(LdaZero, OperandType::kNone)       \
  V(LdaSmi8, OperandType::kImm8)       \
  V(LdaConstant, OperandType::kIdx)    \
  V(LdaUndefined, OperandType::kNone)  \
  V(LdaNull, OperandType::kNone)       \
  V(LdaTheHole, OperandType::kNone)    \
  V(LdaTrue, OperandType::kNone)       \
  V(LdaFalse, OperandType::kNone)      \
                                       \
  /* Register-accumulator transfers */ \
  V(Ldar, OperandType::kReg)           \
  V(Star, OperandType::kReg)           \
                                       \
  /* Binary Operators */               \
  V(Add, OperandType::kReg)            \
  V(Sub, OperandType::kReg)            \
  V(Mul, OperandType::kReg)            \
  V(Div, OperandType::kReg)            \
  V(Mod, OperandType::kReg)            \
                                       \
  /* Control Flow */                   \
  V(Return, OperandType::kNone)


// Enumeration of operand types used by bytecodes.
enum class OperandType : uint8_t {
#define DECLARE_OPERAND_TYPE(Name) k##Name,
  OPERAND_TYPE_LIST(DECLARE_OPERAND_TYPE)
#undef DECLARE_OPERAND_TYPE
#define COUNT_OPERAND_TYPES(x) +1
  // The COUNT_OPERAND macro will turn this into kLast = -1 +1 +1... which will
  // evaluate to the same value as the last operand.
  kLast = -1 OPERAND_TYPE_LIST(COUNT_OPERAND_TYPES)
#undef COUNT_OPERAND_TYPES
};


// Enumeration of interpreter bytecodes.
enum class Bytecode : uint8_t {
#define DECLARE_BYTECODE(Name, ...) k##Name,
  BYTECODE_LIST(DECLARE_BYTECODE)
#undef DECLARE_BYTECODE
#define COUNT_BYTECODE(x, ...) +1
  // The COUNT_BYTECODE macro will turn this into kLast = -1 +1 +1... which will
  // evaluate to the same value as the last real bytecode.
  kLast = -1 BYTECODE_LIST(COUNT_BYTECODE)
#undef COUNT_BYTECODE
};


class Bytecodes {
 public:
  // Returns string representation of |bytecode|.
  static const char* ToString(Bytecode bytecode);

  // Returns string representation of |operand_type|.
  static const char* OperandTypeToString(OperandType operand_type);

  // Returns byte value of bytecode.
  static uint8_t ToByte(Bytecode bytecode);

  // Returns bytecode for |value|.
  static Bytecode FromByte(uint8_t value);

  // Returns the number of operands expected by |bytecode|.
  static int NumberOfOperands(Bytecode bytecode);

  // Return the i-th operand of |bytecode|.
  static OperandType GetOperandType(Bytecode bytecode, int i);

  // Returns the size of the bytecode including its operands.
  static int Size(Bytecode bytecode);

  // The maximum number of operands across all bytecodes.
  static int MaximumNumberOfOperands();

  // Maximum size of a bytecode and its operands.
  static int MaximumSize();

  // Decode a single bytecode and operands to |os|.
  static std::ostream& Decode(std::ostream& os, const uint8_t* bytecode_start);

 private:
  DISALLOW_IMPLICIT_CONSTRUCTORS(Bytecodes);
};

std::ostream& operator<<(std::ostream& os, const Bytecode& bytecode);
std::ostream& operator<<(std::ostream& os, const OperandType& operand_type);

}  // namespace interpreter
}  // namespace internal
}  // namespace v8

#endif  // V8_INTERPRETER_BYTECODES_H_