| // 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 <algorithm> | 
 |  | 
 | #include "src/common/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 <typename... Operands>                                            \ | 
 |   V8_INLINE static BytecodeNode Name(BytecodeSourceInfo source_info,         \ | 
 |                                      Operands... operands) {                 \ | 
 |     return Create<Bytecode::k##Name, __VA_ARGS__>(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 <Bytecode bytecode, AccumulatorUse accumulator_use, | 
 |             OperandType... operand_types> | 
 |   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 <Bytecode bytecode, AccumulatorUse accum_use> | 
 |   V8_INLINE static BytecodeNode Create(BytecodeSourceInfo source_info) { | 
 |     return BytecodeNode(bytecode, 0, OperandScale::kSingle, source_info); | 
 |   } | 
 |  | 
 |   template <Bytecode bytecode, AccumulatorUse accum_use, | 
 |             OperandType operand0_type> | 
 |   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_type>(operand0)); | 
 |     return BytecodeNode(bytecode, 1, scale, source_info, operand0); | 
 |   } | 
 |  | 
 |   template <Bytecode bytecode, AccumulatorUse accum_use, | 
 |             OperandType operand0_type, OperandType operand1_type> | 
 |   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_type>(operand0)); | 
 |     scale = std::max(scale, ScaleForOperand<operand1_type>(operand1)); | 
 |     return BytecodeNode(bytecode, 2, scale, source_info, operand0, operand1); | 
 |   } | 
 |  | 
 |   template <Bytecode bytecode, AccumulatorUse accum_use, | 
 |             OperandType operand0_type, OperandType operand1_type, | 
 |             OperandType operand2_type> | 
 |   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_type>(operand0)); | 
 |     scale = std::max(scale, ScaleForOperand<operand1_type>(operand1)); | 
 |     scale = std::max(scale, ScaleForOperand<operand2_type>(operand2)); | 
 |     return BytecodeNode(bytecode, 3, scale, source_info, operand0, operand1, | 
 |                         operand2); | 
 |   } | 
 |  | 
 |   template <Bytecode bytecode, AccumulatorUse accum_use, | 
 |             OperandType operand0_type, OperandType operand1_type, | 
 |             OperandType operand2_type, OperandType operand3_type> | 
 |   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_type>(operand0)); | 
 |     scale = std::max(scale, ScaleForOperand<operand1_type>(operand1)); | 
 |     scale = std::max(scale, ScaleForOperand<operand2_type>(operand2)); | 
 |     scale = std::max(scale, ScaleForOperand<operand3_type>(operand3)); | 
 |     return BytecodeNode(bytecode, 4, scale, source_info, operand0, operand1, | 
 |                         operand2, operand3); | 
 |   } | 
 |  | 
 |   template <Bytecode bytecode, AccumulatorUse accum_use, | 
 |             OperandType operand0_type, OperandType operand1_type, | 
 |             OperandType operand2_type, OperandType operand3_type, | 
 |             OperandType operand4_type> | 
 |   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_type>(operand0)); | 
 |     scale = std::max(scale, ScaleForOperand<operand1_type>(operand1)); | 
 |     scale = std::max(scale, ScaleForOperand<operand2_type>(operand2)); | 
 |     scale = std::max(scale, ScaleForOperand<operand3_type>(operand3)); | 
 |     scale = std::max(scale, ScaleForOperand<operand4_type>(operand4)); | 
 |     return BytecodeNode(bytecode, 5, scale, source_info, operand0, operand1, | 
 |                         operand2, operand3, operand4); | 
 |   } | 
 |  | 
 |   template <OperandType operand_type> | 
 |   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_ |