// 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/frames.h"
#include "src/utils.h"

namespace v8 {
namespace internal {
namespace interpreter {

#define INVALID_OPERAND_TYPE_LIST(V) V(None, OperandTypeInfo::kNone)

#define REGISTER_INPUT_OPERAND_TYPE_LIST(V)         \
  V(MaybeReg, OperandTypeInfo::kScalableSignedByte) \
  V(Reg, OperandTypeInfo::kScalableSignedByte)      \
  V(RegPair, OperandTypeInfo::kScalableSignedByte)

#define REGISTER_OUTPUT_OPERAND_TYPE_LIST(V)          \
  V(RegOut, OperandTypeInfo::kScalableSignedByte)     \
  V(RegOutPair, OperandTypeInfo::kScalableSignedByte) \
  V(RegOutTriple, OperandTypeInfo::kScalableSignedByte)

#define SCALAR_OPERAND_TYPE_LIST(V)                   \
  V(Flag8, OperandTypeInfo::kFixedUnsignedByte)       \
  V(IntrinsicId, OperandTypeInfo::kFixedUnsignedByte) \
  V(Idx, OperandTypeInfo::kScalableUnsignedByte)      \
  V(Imm, OperandTypeInfo::kScalableSignedByte)        \
  V(RegCount, OperandTypeInfo::kScalableUnsignedByte) \
  V(RuntimeId, OperandTypeInfo::kFixedUnsignedShort)

#define REGISTER_OPERAND_TYPE_LIST(V) \
  REGISTER_INPUT_OPERAND_TYPE_LIST(V) \
  REGISTER_OUTPUT_OPERAND_TYPE_LIST(V)

#define NON_REGISTER_OPERAND_TYPE_LIST(V) \
  INVALID_OPERAND_TYPE_LIST(V)            \
  SCALAR_OPERAND_TYPE_LIST(V)

// The list of operand types used by bytecodes.
#define OPERAND_TYPE_LIST(V)        \
  NON_REGISTER_OPERAND_TYPE_LIST(V) \
  REGISTER_OPERAND_TYPE_LIST(V)

// Define one debug break bytecode for each possible size of unscaled
// bytecodes. Format is V(<bytecode>, <accumulator_use>, <operands>).
#define DEBUG_BREAK_PLAIN_BYTECODE_LIST(V)                                    \
  V(DebugBreak0, AccumulatorUse::kRead)                                       \
  V(DebugBreak1, AccumulatorUse::kRead, OperandType::kReg)                    \
  V(DebugBreak2, AccumulatorUse::kRead, OperandType::kReg, OperandType::kReg) \
  V(DebugBreak3, AccumulatorUse::kRead, OperandType::kReg, OperandType::kReg, \
    OperandType::kReg)                                                        \
  V(DebugBreak4, AccumulatorUse::kRead, OperandType::kReg, OperandType::kReg, \
    OperandType::kReg, OperandType::kReg)                                     \
  V(DebugBreak5, AccumulatorUse::kRead, OperandType::kRuntimeId,              \
    OperandType::kReg, OperandType::kReg)                                     \
  V(DebugBreak6, AccumulatorUse::kRead, OperandType::kRuntimeId,              \
    OperandType::kReg, OperandType::kReg, OperandType::kReg)

// Define one debug break for each widening prefix.
#define DEBUG_BREAK_PREFIX_BYTECODE_LIST(V) \
  V(DebugBreakWide, AccumulatorUse::kRead)  \
  V(DebugBreakExtraWide, AccumulatorUse::kRead)

#define DEBUG_BREAK_BYTECODE_LIST(V) \
  DEBUG_BREAK_PLAIN_BYTECODE_LIST(V) \
  DEBUG_BREAK_PREFIX_BYTECODE_LIST(V)

// The list of bytecodes which are interpreted by the interpreter.
#define BYTECODE_LIST(V)                                                       \
  /* Extended width operands */                                                \
  V(Wide, AccumulatorUse::kNone)                                               \
  V(ExtraWide, AccumulatorUse::kNone)                                          \
                                                                               \
  /* Loading the accumulator */                                                \
  V(LdaZero, AccumulatorUse::kWrite)                                           \
  V(LdaSmi, AccumulatorUse::kWrite, OperandType::kImm)                         \
  V(LdaUndefined, AccumulatorUse::kWrite)                                      \
  V(LdaNull, AccumulatorUse::kWrite)                                           \
  V(LdaTheHole, AccumulatorUse::kWrite)                                        \
  V(LdaTrue, AccumulatorUse::kWrite)                                           \
  V(LdaFalse, AccumulatorUse::kWrite)                                          \
  V(LdaConstant, AccumulatorUse::kWrite, OperandType::kIdx)                    \
                                                                               \
  /* Loading registers */                                                      \
  V(LdrUndefined, AccumulatorUse::kNone, OperandType::kRegOut)                 \
                                                                               \
  /* Globals */                                                                \
  V(LdaGlobal, AccumulatorUse::kWrite, OperandType::kIdx)                      \
  V(LdrGlobal, AccumulatorUse::kNone, OperandType::kIdx, OperandType::kRegOut) \
  V(LdaGlobalInsideTypeof, AccumulatorUse::kWrite, OperandType::kIdx)          \
  V(StaGlobalSloppy, AccumulatorUse::kRead, OperandType::kIdx,                 \
    OperandType::kIdx)                                                         \
  V(StaGlobalStrict, AccumulatorUse::kRead, OperandType::kIdx,                 \
    OperandType::kIdx)                                                         \
                                                                               \
  /* Context operations */                                                     \
  V(PushContext, AccumulatorUse::kRead, OperandType::kRegOut)                  \
  V(PopContext, AccumulatorUse::kNone, OperandType::kReg)                      \
  V(LdaContextSlot, AccumulatorUse::kWrite, OperandType::kReg,                 \
    OperandType::kIdx)                                                         \
  V(LdrContextSlot, AccumulatorUse::kNone, OperandType::kReg,                  \
    OperandType::kIdx, OperandType::kRegOut)                                   \
  V(StaContextSlot, AccumulatorUse::kRead, OperandType::kReg,                  \
    OperandType::kIdx)                                                         \
                                                                               \
  /* Load-Store lookup slots */                                                \
  V(LdaLookupSlot, AccumulatorUse::kWrite, OperandType::kIdx)                  \
  V(LdaLookupSlotInsideTypeof, AccumulatorUse::kWrite, OperandType::kIdx)      \
  V(StaLookupSlotSloppy, AccumulatorUse::kReadWrite, OperandType::kIdx)        \
  V(StaLookupSlotStrict, AccumulatorUse::kReadWrite, OperandType::kIdx)        \
                                                                               \
  /* Register-accumulator transfers */                                         \
  V(Ldar, AccumulatorUse::kWrite, OperandType::kReg)                           \
  V(Star, AccumulatorUse::kRead, OperandType::kRegOut)                         \
                                                                               \
  /* Register-register transfers */                                            \
  V(Mov, AccumulatorUse::kNone, OperandType::kReg, OperandType::kRegOut)       \
                                                                               \
  /* Property loads (LoadIC) operations */                                     \
  V(LdaNamedProperty, AccumulatorUse::kWrite, OperandType::kReg,               \
    OperandType::kIdx, OperandType::kIdx)                                      \
  V(LdrNamedProperty, AccumulatorUse::kNone, OperandType::kReg,                \
    OperandType::kIdx, OperandType::kIdx, OperandType::kRegOut)                \
  V(LdaKeyedProperty, AccumulatorUse::kReadWrite, OperandType::kReg,           \
    OperandType::kIdx)                                                         \
  V(LdrKeyedProperty, AccumulatorUse::kRead, OperandType::kReg,                \
    OperandType::kIdx, OperandType::kRegOut)                                   \
                                                                               \
  /* Propery stores (StoreIC) operations */                                    \
  V(StaNamedPropertySloppy, AccumulatorUse::kRead, OperandType::kReg,          \
    OperandType::kIdx, OperandType::kIdx)                                      \
  V(StaNamedPropertyStrict, AccumulatorUse::kRead, OperandType::kReg,          \
    OperandType::kIdx, OperandType::kIdx)                                      \
  V(StaKeyedPropertySloppy, AccumulatorUse::kRead, OperandType::kReg,          \
    OperandType::kReg, OperandType::kIdx)                                      \
  V(StaKeyedPropertyStrict, AccumulatorUse::kRead, OperandType::kReg,          \
    OperandType::kReg, OperandType::kIdx)                                      \
                                                                               \
  /* Binary Operators */                                                       \
  V(Add, AccumulatorUse::kReadWrite, OperandType::kReg)                        \
  V(Sub, AccumulatorUse::kReadWrite, OperandType::kReg)                        \
  V(Mul, AccumulatorUse::kReadWrite, OperandType::kReg)                        \
  V(Div, AccumulatorUse::kReadWrite, OperandType::kReg)                        \
  V(Mod, AccumulatorUse::kReadWrite, OperandType::kReg)                        \
  V(BitwiseOr, AccumulatorUse::kReadWrite, OperandType::kReg)                  \
  V(BitwiseXor, AccumulatorUse::kReadWrite, OperandType::kReg)                 \
  V(BitwiseAnd, AccumulatorUse::kReadWrite, OperandType::kReg)                 \
  V(ShiftLeft, AccumulatorUse::kReadWrite, OperandType::kReg)                  \
  V(ShiftRight, AccumulatorUse::kReadWrite, OperandType::kReg)                 \
  V(ShiftRightLogical, AccumulatorUse::kReadWrite, OperandType::kReg)          \
                                                                               \
  /* Unary Operators */                                                        \
  V(Inc, AccumulatorUse::kReadWrite)                                           \
  V(Dec, AccumulatorUse::kReadWrite)                                           \
  V(ToBooleanLogicalNot, AccumulatorUse::kReadWrite)                           \
  V(LogicalNot, AccumulatorUse::kReadWrite)                                    \
  V(TypeOf, AccumulatorUse::kReadWrite)                                        \
  V(DeletePropertyStrict, AccumulatorUse::kReadWrite, OperandType::kReg)       \
  V(DeletePropertySloppy, AccumulatorUse::kReadWrite, OperandType::kReg)       \
                                                                               \
  /* Call operations */                                                        \
  V(Call, AccumulatorUse::kWrite, OperandType::kReg, OperandType::kReg,        \
    OperandType::kRegCount, OperandType::kIdx)                                 \
  V(TailCall, AccumulatorUse::kWrite, OperandType::kReg, OperandType::kReg,    \
    OperandType::kRegCount, OperandType::kIdx)                                 \
  V(CallRuntime, AccumulatorUse::kWrite, OperandType::kRuntimeId,              \
    OperandType::kMaybeReg, OperandType::kRegCount)                            \
  V(CallRuntimeForPair, AccumulatorUse::kNone, OperandType::kRuntimeId,        \
    OperandType::kMaybeReg, OperandType::kRegCount, OperandType::kRegOutPair)  \
  V(CallJSRuntime, AccumulatorUse::kWrite, OperandType::kIdx,                  \
    OperandType::kReg, OperandType::kRegCount)                                 \
                                                                               \
  /* Intrinsics */                                                             \
  V(InvokeIntrinsic, AccumulatorUse::kWrite, OperandType::kIntrinsicId,        \
    OperandType::kMaybeReg, OperandType::kRegCount)                            \
                                                                               \
  /* New operator */                                                           \
  V(New, AccumulatorUse::kReadWrite, OperandType::kReg,                        \
    OperandType::kMaybeReg, OperandType::kRegCount)                            \
                                                                               \
  /* Test Operators */                                                         \
  V(TestEqual, AccumulatorUse::kReadWrite, OperandType::kReg)                  \
  V(TestNotEqual, AccumulatorUse::kReadWrite, OperandType::kReg)               \
  V(TestEqualStrict, AccumulatorUse::kReadWrite, OperandType::kReg)            \
  V(TestLessThan, AccumulatorUse::kReadWrite, OperandType::kReg)               \
  V(TestGreaterThan, AccumulatorUse::kReadWrite, OperandType::kReg)            \
  V(TestLessThanOrEqual, AccumulatorUse::kReadWrite, OperandType::kReg)        \
  V(TestGreaterThanOrEqual, AccumulatorUse::kReadWrite, OperandType::kReg)     \
  V(TestInstanceOf, AccumulatorUse::kReadWrite, OperandType::kReg)             \
  V(TestIn, AccumulatorUse::kReadWrite, OperandType::kReg)                     \
                                                                               \
  /* Cast operators */                                                         \
  V(ToName, AccumulatorUse::kReadWrite)                                        \
  V(ToNumber, AccumulatorUse::kReadWrite)                                      \
  V(ToObject, AccumulatorUse::kReadWrite)                                      \
                                                                               \
  /* Literals */                                                               \
  V(CreateRegExpLiteral, AccumulatorUse::kWrite, OperandType::kIdx,            \
    OperandType::kIdx, OperandType::kFlag8)                                    \
  V(CreateArrayLiteral, AccumulatorUse::kWrite, OperandType::kIdx,             \
    OperandType::kIdx, OperandType::kFlag8)                                    \
  V(CreateObjectLiteral, AccumulatorUse::kWrite, OperandType::kIdx,            \
    OperandType::kIdx, OperandType::kFlag8)                                    \
                                                                               \
  /* Closure allocation */                                                     \
  V(CreateClosure, AccumulatorUse::kWrite, OperandType::kIdx,                  \
    OperandType::kFlag8)                                                       \
                                                                               \
  /* Arguments allocation */                                                   \
  V(CreateMappedArguments, AccumulatorUse::kWrite)                             \
  V(CreateUnmappedArguments, AccumulatorUse::kWrite)                           \
  V(CreateRestParameter, AccumulatorUse::kWrite)                               \
                                                                               \
  /* Control Flow */                                                           \
  V(Jump, AccumulatorUse::kNone, OperandType::kImm)                            \
  V(JumpConstant, AccumulatorUse::kNone, OperandType::kIdx)                    \
  V(JumpIfTrue, AccumulatorUse::kRead, OperandType::kImm)                      \
  V(JumpIfTrueConstant, AccumulatorUse::kRead, OperandType::kIdx)              \
  V(JumpIfFalse, AccumulatorUse::kRead, OperandType::kImm)                     \
  V(JumpIfFalseConstant, AccumulatorUse::kRead, OperandType::kIdx)             \
  V(JumpIfToBooleanTrue, AccumulatorUse::kRead, OperandType::kImm)             \
  V(JumpIfToBooleanTrueConstant, AccumulatorUse::kRead, OperandType::kIdx)     \
  V(JumpIfToBooleanFalse, AccumulatorUse::kRead, OperandType::kImm)            \
  V(JumpIfToBooleanFalseConstant, AccumulatorUse::kRead, OperandType::kIdx)    \
  V(JumpIfNull, AccumulatorUse::kRead, OperandType::kImm)                      \
  V(JumpIfNullConstant, AccumulatorUse::kRead, OperandType::kIdx)              \
  V(JumpIfUndefined, AccumulatorUse::kRead, OperandType::kImm)                 \
  V(JumpIfUndefinedConstant, AccumulatorUse::kRead, OperandType::kIdx)         \
  V(JumpIfNotHole, AccumulatorUse::kRead, OperandType::kImm)                   \
  V(JumpIfNotHoleConstant, AccumulatorUse::kRead, OperandType::kIdx)           \
                                                                               \
  /* Complex flow control For..in */                                           \
  V(ForInPrepare, AccumulatorUse::kRead, OperandType::kRegOutTriple)           \
  V(ForInDone, AccumulatorUse::kWrite, OperandType::kReg, OperandType::kReg)   \
  V(ForInNext, AccumulatorUse::kWrite, OperandType::kReg, OperandType::kReg,   \
    OperandType::kRegPair, OperandType::kIdx)                                  \
  V(ForInStep, AccumulatorUse::kWrite, OperandType::kReg)                      \
                                                                               \
  /* Perform a stack guard check */                                            \
  V(StackCheck, AccumulatorUse::kNone)                                         \
                                                                               \
  /* Non-local flow control */                                                 \
  V(Throw, AccumulatorUse::kRead)                                              \
  V(ReThrow, AccumulatorUse::kRead)                                            \
  V(Return, AccumulatorUse::kRead)                                             \
                                                                               \
  /* Generators */                                                             \
  V(SuspendGenerator, AccumulatorUse::kRead, OperandType::kReg)                \
  V(ResumeGenerator, AccumulatorUse::kWrite, OperandType::kReg)                \
                                                                               \
  /* Debugger */                                                               \
  V(Debugger, AccumulatorUse::kNone)                                           \
  DEBUG_BREAK_BYTECODE_LIST(V)                                                 \
                                                                               \
  /* Illegal bytecode (terminates execution) */                                \
  V(Illegal, AccumulatorUse::kNone)                                            \
                                                                               \
  /* No operation (used to maintain source positions for peephole */           \
  /* eliminated bytecodes). */                                                 \
  V(Nop, AccumulatorUse::kNone)

enum class AccumulatorUse : uint8_t {
  kNone = 0,
  kRead = 1 << 0,
  kWrite = 1 << 1,
  kReadWrite = kRead | kWrite
};

V8_INLINE AccumulatorUse operator&(AccumulatorUse lhs, AccumulatorUse rhs) {
  int result = static_cast<int>(lhs) & static_cast<int>(rhs);
  return static_cast<AccumulatorUse>(result);
}

V8_INLINE AccumulatorUse operator|(AccumulatorUse lhs, AccumulatorUse rhs) {
  int result = static_cast<int>(lhs) | static_cast<int>(rhs);
  return static_cast<AccumulatorUse>(result);
}

// Enumeration of scaling factors applicable to scalable operands. Code
// relies on being able to cast values to integer scaling values.
#define OPERAND_SCALE_LIST(V) \
  V(Single, 1)                \
  V(Double, 2)                \
  V(Quadruple, 4)

enum class OperandScale : uint8_t {
#define DECLARE_OPERAND_SCALE(Name, Scale) k##Name = Scale,
  OPERAND_SCALE_LIST(DECLARE_OPERAND_SCALE)
#undef DECLARE_OPERAND_SCALE
      kLast = kQuadruple
};

// Enumeration of the size classes of operand types used by
// bytecodes. Code relies on being able to cast values to integer
// types to get the size in bytes.
enum class OperandSize : uint8_t {
  kNone = 0,
  kByte = 1,
  kShort = 2,
  kQuad = 4,
  kLast = kQuad
};

// Primitive operand info used that summarize properties of operands.
// Columns are Name, IsScalable, IsUnsigned, UnscaledSize.
#define OPERAND_TYPE_INFO_LIST(V)                         \
  V(None, false, false, OperandSize::kNone)               \
  V(ScalableSignedByte, true, false, OperandSize::kByte)  \
  V(ScalableUnsignedByte, true, true, OperandSize::kByte) \
  V(FixedUnsignedByte, false, true, OperandSize::kByte)   \
  V(FixedUnsignedShort, false, true, OperandSize::kShort)

enum class OperandTypeInfo : uint8_t {
#define DECLARE_OPERAND_TYPE_INFO(Name, ...) k##Name,
  OPERAND_TYPE_INFO_LIST(DECLARE_OPERAND_TYPE_INFO)
#undef DECLARE_OPERAND_TYPE_INFO
};

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


// An interpreter Register which is located in the function's Register file
// in its stack-frame. Register hold parameters, this, and expression values.
class Register final {
 public:
  explicit Register(int index = kInvalidIndex) : index_(index) {}

  int index() const { return index_; }
  bool is_parameter() const { return index() < 0; }
  bool is_valid() const { return index_ != kInvalidIndex; }

  static Register FromParameterIndex(int index, int parameter_count);
  int ToParameterIndex(int parameter_count) const;

  // Returns an invalid register.
  static Register invalid_value() { return Register(); }

  // Returns the register for the function's closure object.
  static Register function_closure();
  bool is_function_closure() const;

  // Returns the register which holds the current context object.
  static Register current_context();
  bool is_current_context() const;

  // Returns the register for the incoming new target value.
  static Register new_target();
  bool is_new_target() const;

  // Returns the register for the bytecode array.
  static Register bytecode_array();
  bool is_bytecode_array() const;

  // Returns the register for the saved bytecode offset.
  static Register bytecode_offset();
  bool is_bytecode_offset() const;

  // Returns a register that can be used to represent the accumulator
  // within code in the interpreter, but should never be emitted in
  // bytecode.
  static Register virtual_accumulator();

  OperandSize SizeOfOperand() const;

  int32_t ToOperand() const { return kRegisterFileStartOffset - index_; }
  static Register FromOperand(int32_t operand) {
    return Register(kRegisterFileStartOffset - operand);
  }

  static bool AreContiguous(Register reg1, Register reg2,
                            Register reg3 = Register(),
                            Register reg4 = Register(),
                            Register reg5 = Register());

  std::string ToString(int parameter_count);

  bool operator==(const Register& other) const {
    return index() == other.index();
  }
  bool operator!=(const Register& other) const {
    return index() != other.index();
  }
  bool operator<(const Register& other) const {
    return index() < other.index();
  }
  bool operator<=(const Register& other) const {
    return index() <= other.index();
  }
  bool operator>(const Register& other) const {
    return index() > other.index();
  }
  bool operator>=(const Register& other) const {
    return index() >= other.index();
  }

 private:
  static const int kInvalidIndex = kMaxInt;
  static const int kRegisterFileStartOffset =
      InterpreterFrameConstants::kRegisterFileFromFp / kPointerSize;

  void* operator new(size_t size);
  void operator delete(void* p);

  int index_;
};


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

  // Returns string representation of |bytecode|.
  static std::string ToString(Bytecode bytecode, OperandScale operand_scale);

  // Returns string representation of |accumulator_use|.
  static const char* AccumulatorUseToString(AccumulatorUse accumulator_use);

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

  // Returns string representation of |operand_scale|.
  static const char* OperandScaleToString(OperandScale operand_scale);

  // Returns string representation of |operand_size|.
  static const char* OperandSizeToString(OperandSize operand_size);

  // Returns byte value of bytecode.
  static uint8_t ToByte(Bytecode bytecode) {
    DCHECK_LE(bytecode, Bytecode::kLast);
    return static_cast<uint8_t>(bytecode);
  }

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

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

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

  // Returns the prefix bytecode representing an operand scale to be
  // applied to a a bytecode.
  static Bytecode OperandScaleToPrefixBytecode(OperandScale operand_scale);

  // Returns true if the operand scale requires a prefix bytecode.
  static bool OperandScaleRequiresPrefixBytecode(OperandScale operand_scale);

  // Returns the scaling applied to scalable operands if bytecode is
  // is a scaling prefix.
  static OperandScale PrefixBytecodeToOperandScale(Bytecode bytecode);

  // Returns how accumulator is used by |bytecode|.
  static AccumulatorUse GetAccumulatorUse(Bytecode bytecode);

  // Returns true if |bytecode| reads the accumulator.
  static bool ReadsAccumulator(Bytecode bytecode);

  // Returns true if |bytecode| writes the accumulator.
  static bool WritesAccumulator(Bytecode bytecode);

  // Return true if |bytecode| writes the accumulator with a boolean value.
  static bool WritesBooleanToAccumulator(Bytecode bytecode);

  // Return true if |bytecode| is an accumulator load without effects,
  // e.g. LdaConstant, LdaTrue, Ldar.
  static bool IsAccumulatorLoadWithoutEffects(Bytecode bytecode);

  // Return true if |bytecode| is a jump without effects,
  // e.g.  any jump excluding those that include type coercion like
  // JumpIfTrueToBoolean.
  static bool IsJumpWithoutEffects(Bytecode bytecode);

  // Return true if |bytecode| is a register load without effects,
  // e.g. Mov, Star, LdrUndefined.
  static bool IsRegisterLoadWithoutEffects(Bytecode bytecode);

  // Returns true if |bytecode| has no effects.
  static bool IsWithoutExternalSideEffects(Bytecode bytecode);

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

  // Returns a pointer to an array of operand types terminated in
  // OperandType::kNone.
  static const OperandType* GetOperandTypes(Bytecode bytecode);

  // Returns a pointer to an array of operand type info terminated in
  // OperandTypeInfo::kNone.
  static const OperandTypeInfo* GetOperandTypeInfos(Bytecode bytecode);

  // Returns the size of the i-th operand of |bytecode|.
  static OperandSize GetOperandSize(Bytecode bytecode, int i,
                                    OperandScale operand_scale);

  // Returns a pointer to an array of the operand sizes for |bytecode|.
  static const OperandSize* GetOperandSizes(Bytecode bytecode,
                                            OperandScale operand_scale);

  // Returns the offset of the i-th operand of |bytecode| relative to the start
  // of the bytecode.
  static int GetOperandOffset(Bytecode bytecode, int i,
                              OperandScale operand_scale);

  // Returns a zero-based bitmap of the register operand positions of
  // |bytecode|.
  static int GetRegisterOperandBitmap(Bytecode bytecode);

  // Returns a debug break bytecode to replace |bytecode|.
  static Bytecode GetDebugBreak(Bytecode bytecode);

  // Returns the size of the bytecode including its operands for the
  // given |operand_scale|.
  static int Size(Bytecode bytecode, OperandScale operand_scale);

  // Returns the size of |operand|.
  static OperandSize SizeOfOperand(OperandType operand, OperandScale scale);

  // Returns the number of values which |bytecode| returns.
  static size_t ReturnCount(Bytecode bytecode);

  // Returns true if the bytecode is a conditional jump taking
  // an immediate byte operand (OperandType::kImm).
  static bool IsConditionalJumpImmediate(Bytecode bytecode);

  // Returns true if the bytecode is a conditional jump taking
  // a constant pool entry (OperandType::kIdx).
  static bool IsConditionalJumpConstant(Bytecode bytecode);

  // Returns true if the bytecode is a conditional jump taking
  // any kind of operand.
  static bool IsConditionalJump(Bytecode bytecode);

  // Returns true if the bytecode is a jump or a conditional jump taking
  // an immediate byte operand (OperandType::kImm).
  static bool IsJumpImmediate(Bytecode bytecode);

  // Returns true if the bytecode is a jump or conditional jump taking a
  // constant pool entry (OperandType::kIdx).
  static bool IsJumpConstant(Bytecode bytecode);

  // Returns true if the bytecode is a jump or conditional jump taking
  // any kind of operand.
  static bool IsJump(Bytecode bytecode);

  // Returns true if the bytecode is a jump that internally coerces the
  // accumulator to a boolean.
  static bool IsJumpIfToBoolean(Bytecode bytecode);

  // Returns the equivalent jump bytecode without the accumulator coercion.
  static Bytecode GetJumpWithoutToBoolean(Bytecode bytecode);

  // Returns true if the bytecode is a conditional jump, a jump, or a return.
  static bool IsJumpOrReturn(Bytecode bytecode);

  // Returns true if the bytecode is a call or a constructor call.
  static bool IsCallOrNew(Bytecode bytecode);

  // Returns true if the bytecode is a call to the runtime.
  static bool IsCallRuntime(Bytecode bytecode);

  // Returns true if the bytecode is a debug break.
  static bool IsDebugBreak(Bytecode bytecode);

  // Returns true if the bytecode is Ldar or Star.
  static bool IsLdarOrStar(Bytecode bytecode);

  // Returns true if the bytecode has wider operand forms.
  static bool IsBytecodeWithScalableOperands(Bytecode bytecode);

  // Returns true if the bytecode is a scaling prefix bytecode.
  static bool IsPrefixScalingBytecode(Bytecode bytecode);

  // Returns true if |operand_type| is any type of register operand.
  static bool IsRegisterOperandType(OperandType operand_type);

  // Returns true if |operand_type| represents a register used as an input.
  static bool IsRegisterInputOperandType(OperandType operand_type);

  // Returns true if |operand_type| represents a register used as an output.
  static bool IsRegisterOutputOperandType(OperandType operand_type);

  // Returns the number of registers represented by a register operand. For
  // instance, a RegPair represents two registers.
  static int GetNumberOfRegistersRepresentedBy(OperandType operand_type);

  // Returns true if |operand_type| is a maybe register operand
  // (kMaybeReg).
  static bool IsMaybeRegisterOperandType(OperandType operand_type);

  // Returns true if |operand_type| is a runtime-id operand (kRuntimeId).
  static bool IsRuntimeIdOperandType(OperandType operand_type);

  // Returns true if |operand_type| is unsigned, false if signed.
  static bool IsUnsignedOperandType(OperandType operand_type);

  // Decodes a register operand in a byte array.
  static Register DecodeRegisterOperand(const uint8_t* operand_start,
                                        OperandType operand_type,
                                        OperandScale operand_scale);

  // Decodes a signed operand in a byte array.
  static int32_t DecodeSignedOperand(const uint8_t* operand_start,
                                     OperandType operand_type,
                                     OperandScale operand_scale);

  // Decodes an unsigned operand in a byte array.
  static uint32_t DecodeUnsignedOperand(const uint8_t* operand_start,
                                        OperandType operand_type,
                                        OperandScale operand_scale);

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

  // Returns true if a handler is generated for a bytecode at a given
  // operand scale. All bytecodes have handlers at OperandScale::kSingle,
  // but only bytecodes with scalable operands have handlers with larger
  // OperandScale values.
  static bool BytecodeHasHandler(Bytecode bytecode, OperandScale operand_scale);

  // Return the operand size required to hold a signed operand.
  static OperandSize SizeForSignedOperand(int value);

  // Return the operand size required to hold an unsigned operand.
  static OperandSize SizeForUnsignedOperand(uint32_t value);

 private:
  DISALLOW_IMPLICIT_CONSTRUCTORS(Bytecodes);
};

class CreateObjectLiteralFlags {
 public:
  class FlagsBits : public BitField8<int, 0, 3> {};
  class FastClonePropertiesCountBits
      : public BitField8<int, FlagsBits::kNext, 3> {};
  STATIC_ASSERT((FlagsBits::kMask & FastClonePropertiesCountBits::kMask) == 0);
};

std::ostream& operator<<(std::ostream& os, const Bytecode& bytecode);
std::ostream& operator<<(std::ostream& os, const AccumulatorUse& use);
std::ostream& operator<<(std::ostream& os, const OperandScale& operand_scale);
std::ostream& operator<<(std::ostream& os, const OperandSize& operand_size);
std::ostream& operator<<(std::ostream& os, const OperandType& operand_type);

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

#endif  // V8_INTERPRETER_BYTECODES_H_