1 // Copyright 2015 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_INTERPRETER_BYTECODE_PIPELINE_H_ 6 #define V8_INTERPRETER_BYTECODE_PIPELINE_H_ 7 8 #include "src/interpreter/bytecode-register-allocator.h" 9 #include "src/interpreter/bytecodes.h" 10 #include "src/zone-containers.h" 11 12 namespace v8 { 13 namespace internal { 14 namespace interpreter { 15 16 class BytecodeLabel; 17 class BytecodeNode; 18 class BytecodeSourceInfo; 19 20 // Interface for bytecode pipeline stages. 21 class BytecodePipelineStage { 22 public: ~BytecodePipelineStage()23 virtual ~BytecodePipelineStage() {} 24 25 // Write bytecode node |node| into pipeline. The node is only valid 26 // for the duration of the call. Callee's should clone it if 27 // deferring Write() to the next stage. 28 virtual void Write(BytecodeNode* node) = 0; 29 30 // Write jump bytecode node |node| which jumps to |label| into pipeline. 31 // The node and label are only valid for the duration of the call. This call 32 // implicitly ends the current basic block so should always write to the next 33 // stage. 34 virtual void WriteJump(BytecodeNode* node, BytecodeLabel* label) = 0; 35 36 // Binds |label| to the current bytecode location. This call implicitly 37 // ends the current basic block and so any deferred bytecodes should be 38 // written to the next stage. 39 virtual void BindLabel(BytecodeLabel* label) = 0; 40 41 // Binds |label| to the location of |target|. This call implicitly 42 // ends the current basic block and so any deferred bytecodes should be 43 // written to the next stage. 44 virtual void BindLabel(const BytecodeLabel& target, BytecodeLabel* label) = 0; 45 46 // Flush the pipeline and generate a bytecode array. 47 virtual Handle<BytecodeArray> ToBytecodeArray( 48 int fixed_register_count, int parameter_count, 49 Handle<FixedArray> handler_table) = 0; 50 }; 51 52 // Source code position information. 53 class BytecodeSourceInfo final { 54 public: 55 static const int kUninitializedPosition = -1; 56 BytecodeSourceInfo()57 BytecodeSourceInfo() 58 : position_type_(PositionType::kNone), 59 source_position_(kUninitializedPosition) {} 60 BytecodeSourceInfo(int source_position,bool is_statement)61 BytecodeSourceInfo(int source_position, bool is_statement) 62 : position_type_(is_statement ? PositionType::kStatement 63 : PositionType::kExpression), 64 source_position_(source_position) { 65 DCHECK_GE(source_position, 0); 66 } 67 68 // Makes instance into a statement position. MakeStatementPosition(int source_position)69 void MakeStatementPosition(int source_position) { 70 // Statement positions can be replaced by other statement 71 // positions. For example , "for (x = 0; x < 3; ++x) 7;" has a 72 // statement position associated with 7 but no bytecode associated 73 // with it. Then Next is emitted after the body and has 74 // statement position and overrides the existing one. 75 position_type_ = PositionType::kStatement; 76 source_position_ = source_position; 77 } 78 79 // Makes instance into an expression position. Instance should not 80 // be a statement position otherwise it could be lost and impair the 81 // debugging experience. MakeExpressionPosition(int source_position)82 void MakeExpressionPosition(int source_position) { 83 DCHECK(!is_statement()); 84 position_type_ = PositionType::kExpression; 85 source_position_ = source_position; 86 } 87 88 // Forces an instance into an expression position. ForceExpressionPosition(int source_position)89 void ForceExpressionPosition(int source_position) { 90 position_type_ = PositionType::kExpression; 91 source_position_ = source_position; 92 } 93 94 // Clones a source position. The current instance is expected to be 95 // invalid. Clone(const BytecodeSourceInfo & other)96 void Clone(const BytecodeSourceInfo& other) { 97 DCHECK(!is_valid()); 98 position_type_ = other.position_type_; 99 source_position_ = other.source_position_; 100 } 101 source_position()102 int source_position() const { 103 DCHECK(is_valid()); 104 return source_position_; 105 } 106 is_statement()107 bool is_statement() const { 108 return position_type_ == PositionType::kStatement; 109 } is_expression()110 bool is_expression() const { 111 return position_type_ == PositionType::kExpression; 112 } 113 is_valid()114 bool is_valid() const { return position_type_ != PositionType::kNone; } set_invalid()115 void set_invalid() { 116 position_type_ = PositionType::kNone; 117 source_position_ = kUninitializedPosition; 118 } 119 120 bool operator==(const BytecodeSourceInfo& other) const { 121 return position_type_ == other.position_type_ && 122 source_position_ == other.source_position_; 123 } 124 125 bool operator!=(const BytecodeSourceInfo& other) const { 126 return position_type_ != other.position_type_ || 127 source_position_ != other.source_position_; 128 } 129 130 private: 131 enum class PositionType : uint8_t { kNone, kExpression, kStatement }; 132 133 PositionType position_type_; 134 int source_position_; 135 136 DISALLOW_COPY_AND_ASSIGN(BytecodeSourceInfo); 137 }; 138 139 // A container for a generated bytecode, it's operands, and source information. 140 // These must be allocated by a BytecodeNodeAllocator instance. 141 class BytecodeNode final : ZoneObject { 142 public: 143 explicit BytecodeNode(Bytecode bytecode = Bytecode::kIllegal); 144 BytecodeNode(Bytecode bytecode, uint32_t operand0); 145 BytecodeNode(Bytecode bytecode, uint32_t operand0, uint32_t operand1); 146 BytecodeNode(Bytecode bytecode, uint32_t operand0, uint32_t operand1, 147 uint32_t operand2); 148 BytecodeNode(Bytecode bytecode, uint32_t operand0, uint32_t operand1, 149 uint32_t operand2, uint32_t operand3); 150 151 BytecodeNode(const BytecodeNode& other); 152 BytecodeNode& operator=(const BytecodeNode& other); 153 154 void set_bytecode(Bytecode bytecode); 155 void set_bytecode(Bytecode bytecode, uint32_t operand0); 156 157 // Clone |other|. 158 void Clone(const BytecodeNode* const other); 159 160 // Print to stream |os|. 161 void Print(std::ostream& os) const; 162 163 // Transform to a node representing |new_bytecode| which has one 164 // operand more than the current bytecode. 165 void Transform(Bytecode new_bytecode, uint32_t extra_operand); 166 bytecode()167 Bytecode bytecode() const { return bytecode_; } 168 operand(int i)169 uint32_t operand(int i) const { 170 DCHECK_LT(i, operand_count()); 171 return operands_[i]; 172 } operands()173 uint32_t* operands() { return operands_; } operands()174 const uint32_t* operands() const { return operands_; } 175 operand_count()176 int operand_count() const { return Bytecodes::NumberOfOperands(bytecode_); } 177 source_info()178 const BytecodeSourceInfo& source_info() const { return source_info_; } source_info()179 BytecodeSourceInfo& source_info() { return source_info_; } 180 181 bool operator==(const BytecodeNode& other) const; 182 bool operator!=(const BytecodeNode& other) const { return !(*this == other); } 183 184 private: 185 static const int kInvalidPosition = kMinInt; 186 static const size_t kMaxOperands = 4; 187 188 Bytecode bytecode_; 189 uint32_t operands_[kMaxOperands]; 190 BytecodeSourceInfo source_info_; 191 }; 192 193 std::ostream& operator<<(std::ostream& os, const BytecodeSourceInfo& info); 194 std::ostream& operator<<(std::ostream& os, const BytecodeNode& node); 195 196 } // namespace interpreter 197 } // namespace internal 198 } // namespace v8 199 200 #endif // V8_INTERPRETER_BYTECODE_PIPELINE_H_ 201