// Copyright 2017 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_BYTECODE_NODE_H_ #define V8_INTERPRETER_BYTECODE_NODE_H_ #include #include "src/globals.h" #include "src/interpreter/bytecode-source-info.h" #include "src/interpreter/bytecodes.h" namespace v8 { namespace internal { namespace interpreter { // A container for a generated bytecode, it's operands, and source information. class V8_EXPORT_PRIVATE BytecodeNode final { public: V8_INLINE BytecodeNode(Bytecode bytecode, BytecodeSourceInfo source_info = BytecodeSourceInfo()) : bytecode_(bytecode), operand_count_(0), operand_scale_(OperandScale::kSingle), source_info_(source_info) { DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), operand_count()); } V8_INLINE BytecodeNode(Bytecode bytecode, uint32_t operand0, BytecodeSourceInfo source_info = BytecodeSourceInfo()) : bytecode_(bytecode), operand_count_(1), operand_scale_(OperandScale::kSingle), source_info_(source_info) { DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), operand_count()); SetOperand(0, operand0); } V8_INLINE BytecodeNode(Bytecode bytecode, uint32_t operand0, uint32_t operand1, BytecodeSourceInfo source_info = BytecodeSourceInfo()) : bytecode_(bytecode), operand_count_(2), operand_scale_(OperandScale::kSingle), source_info_(source_info) { DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), operand_count()); SetOperand(0, operand0); SetOperand(1, operand1); } V8_INLINE BytecodeNode(Bytecode bytecode, uint32_t operand0, uint32_t operand1, uint32_t operand2, BytecodeSourceInfo source_info = BytecodeSourceInfo()) : bytecode_(bytecode), operand_count_(3), operand_scale_(OperandScale::kSingle), source_info_(source_info) { DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), operand_count()); SetOperand(0, operand0); SetOperand(1, operand1); SetOperand(2, operand2); } V8_INLINE BytecodeNode(Bytecode bytecode, uint32_t operand0, uint32_t operand1, uint32_t operand2, uint32_t operand3, BytecodeSourceInfo source_info = BytecodeSourceInfo()) : bytecode_(bytecode), operand_count_(4), operand_scale_(OperandScale::kSingle), source_info_(source_info) { DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), operand_count()); SetOperand(0, operand0); SetOperand(1, operand1); SetOperand(2, operand2); SetOperand(3, operand3); } V8_INLINE BytecodeNode(Bytecode bytecode, uint32_t operand0, uint32_t operand1, uint32_t operand2, uint32_t operand3, uint32_t operand4, BytecodeSourceInfo source_info = BytecodeSourceInfo()) : bytecode_(bytecode), operand_count_(5), operand_scale_(OperandScale::kSingle), source_info_(source_info) { DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), operand_count()); SetOperand(0, operand0); SetOperand(1, operand1); SetOperand(2, operand2); SetOperand(3, operand3); SetOperand(4, operand4); } #define DEFINE_BYTECODE_NODE_CREATOR(Name, ...) \ template \ V8_INLINE static BytecodeNode Name(BytecodeSourceInfo source_info, \ Operands... operands) { \ return Create(source_info, operands...); \ } BYTECODE_LIST(DEFINE_BYTECODE_NODE_CREATOR) #undef DEFINE_BYTECODE_NODE_CREATOR // Print to stream |os|. void Print(std::ostream& os) const; Bytecode bytecode() const { return bytecode_; } uint32_t operand(int i) const { DCHECK_LT(i, operand_count()); return operands_[i]; } const uint32_t* operands() const { return operands_; } void update_operand0(uint32_t operand0) { SetOperand(0, operand0); } int operand_count() const { return operand_count_; } OperandScale operand_scale() const { return operand_scale_; } const BytecodeSourceInfo& source_info() const { return source_info_; } void set_source_info(BytecodeSourceInfo source_info) { source_info_ = source_info; } bool operator==(const BytecodeNode& other) const; bool operator!=(const BytecodeNode& other) const { return !(*this == other); } private: template friend class BytecodeNodeBuilder; V8_INLINE BytecodeNode(Bytecode bytecode, int operand_count, OperandScale operand_scale, BytecodeSourceInfo source_info, uint32_t operand0 = 0, uint32_t operand1 = 0, uint32_t operand2 = 0, uint32_t operand3 = 0, uint32_t operand4 = 0) : bytecode_(bytecode), operand_count_(operand_count), operand_scale_(operand_scale), source_info_(source_info) { DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), operand_count); operands_[0] = operand0; operands_[1] = operand1; operands_[2] = operand2; operands_[3] = operand3; operands_[4] = operand4; } template V8_INLINE static BytecodeNode Create(BytecodeSourceInfo source_info) { return BytecodeNode(bytecode, 0, OperandScale::kSingle, source_info); } template V8_INLINE static BytecodeNode Create(BytecodeSourceInfo source_info, uint32_t operand0) { DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 0), operand0_type); OperandScale scale = OperandScale::kSingle; scale = std::max(scale, ScaleForOperand(operand0)); return BytecodeNode(bytecode, 1, scale, source_info, operand0); } template V8_INLINE static BytecodeNode Create(BytecodeSourceInfo source_info, uint32_t operand0, uint32_t operand1) { DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 0), operand0_type); DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 1), operand1_type); OperandScale scale = OperandScale::kSingle; scale = std::max(scale, ScaleForOperand(operand0)); scale = std::max(scale, ScaleForOperand(operand1)); return BytecodeNode(bytecode, 2, scale, source_info, operand0, operand1); } template V8_INLINE static BytecodeNode Create(BytecodeSourceInfo source_info, uint32_t operand0, uint32_t operand1, uint32_t operand2) { DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 0), operand0_type); DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 1), operand1_type); DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 2), operand2_type); OperandScale scale = OperandScale::kSingle; scale = std::max(scale, ScaleForOperand(operand0)); scale = std::max(scale, ScaleForOperand(operand1)); scale = std::max(scale, ScaleForOperand(operand2)); return BytecodeNode(bytecode, 3, scale, source_info, operand0, operand1, operand2); } template V8_INLINE static BytecodeNode Create(BytecodeSourceInfo source_info, uint32_t operand0, uint32_t operand1, uint32_t operand2, uint32_t operand3) { DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 0), operand0_type); DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 1), operand1_type); DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 2), operand2_type); DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 3), operand3_type); OperandScale scale = OperandScale::kSingle; scale = std::max(scale, ScaleForOperand(operand0)); scale = std::max(scale, ScaleForOperand(operand1)); scale = std::max(scale, ScaleForOperand(operand2)); scale = std::max(scale, ScaleForOperand(operand3)); return BytecodeNode(bytecode, 4, scale, source_info, operand0, operand1, operand2, operand3); } template V8_INLINE static BytecodeNode Create(BytecodeSourceInfo source_info, uint32_t operand0, uint32_t operand1, uint32_t operand2, uint32_t operand3, uint32_t operand4) { DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 0), operand0_type); DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 1), operand1_type); DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 2), operand2_type); DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 3), operand3_type); DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 4), operand4_type); OperandScale scale = OperandScale::kSingle; scale = std::max(scale, ScaleForOperand(operand0)); scale = std::max(scale, ScaleForOperand(operand1)); scale = std::max(scale, ScaleForOperand(operand2)); scale = std::max(scale, ScaleForOperand(operand3)); scale = std::max(scale, ScaleForOperand(operand4)); return BytecodeNode(bytecode, 5, scale, source_info, operand0, operand1, operand2, operand3, operand4); } template V8_INLINE static OperandScale ScaleForOperand(uint32_t operand) { if (BytecodeOperands::IsScalableUnsignedByte(operand_type)) { return Bytecodes::ScaleForUnsignedOperand(operand); } else if (BytecodeOperands::IsScalableSignedByte(operand_type)) { return Bytecodes::ScaleForSignedOperand(operand); } else { return OperandScale::kSingle; } } V8_INLINE void UpdateScaleForOperand(int operand_index, uint32_t operand) { if (Bytecodes::OperandIsScalableSignedByte(bytecode(), operand_index)) { operand_scale_ = std::max(operand_scale_, Bytecodes::ScaleForSignedOperand(operand)); } else if (Bytecodes::OperandIsScalableUnsignedByte(bytecode(), operand_index)) { operand_scale_ = std::max(operand_scale_, Bytecodes::ScaleForUnsignedOperand(operand)); } } V8_INLINE void SetOperand(int operand_index, uint32_t operand) { operands_[operand_index] = operand; UpdateScaleForOperand(operand_index, operand); } Bytecode bytecode_; uint32_t operands_[Bytecodes::kMaxOperands]; int operand_count_; OperandScale operand_scale_; BytecodeSourceInfo source_info_; }; V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, const BytecodeNode& node); } // namespace interpreter } // namespace internal } // namespace v8 #endif // V8_INTERPRETER_BYTECODE_NODE_H_