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/base/compiler-specific.h" 9 #include "src/globals.h" 10 #include "src/interpreter/bytecode-register-allocator.h" 11 #include "src/interpreter/bytecode-register.h" 12 #include "src/interpreter/bytecodes.h" 13 #include "src/objects.h" 14 #include "src/zone/zone-containers.h" 15 16 namespace v8 { 17 namespace internal { 18 namespace interpreter { 19 20 class BytecodeLabel; 21 class BytecodeNode; 22 class BytecodeSourceInfo; 23 24 // Interface for bytecode pipeline stages. 25 class BytecodePipelineStage { 26 public: 27 virtual ~BytecodePipelineStage() {} 28 29 // Write bytecode node |node| into pipeline. The node is only valid 30 // for the duration of the call. Callee's should clone it if 31 // deferring Write() to the next stage. 32 virtual void Write(BytecodeNode* node) = 0; 33 34 // Write jump bytecode node |node| which jumps to |label| into pipeline. 35 // The node and label are only valid for the duration of the call. This call 36 // implicitly ends the current basic block so should always write to the next 37 // stage. 38 virtual void WriteJump(BytecodeNode* node, BytecodeLabel* label) = 0; 39 40 // Binds |label| to the current bytecode location. This call implicitly 41 // ends the current basic block and so any deferred bytecodes should be 42 // written to the next stage. 43 virtual void BindLabel(BytecodeLabel* label) = 0; 44 45 // Binds |label| to the location of |target|. This call implicitly 46 // ends the current basic block and so any deferred bytecodes should be 47 // written to the next stage. 48 virtual void BindLabel(const BytecodeLabel& target, BytecodeLabel* label) = 0; 49 50 // Flush the pipeline and generate a bytecode array. 51 virtual Handle<BytecodeArray> ToBytecodeArray( 52 Isolate* isolate, int register_count, int parameter_count, 53 Handle<FixedArray> handler_table) = 0; 54 }; 55 56 // Source code position information. 57 class BytecodeSourceInfo final { 58 public: 59 static const int kUninitializedPosition = -1; 60 61 BytecodeSourceInfo() 62 : position_type_(PositionType::kNone), 63 source_position_(kUninitializedPosition) {} 64 65 BytecodeSourceInfo(int source_position, bool is_statement) 66 : position_type_(is_statement ? PositionType::kStatement 67 : PositionType::kExpression), 68 source_position_(source_position) { 69 DCHECK_GE(source_position, 0); 70 } 71 72 // Makes instance into a statement position. 73 void MakeStatementPosition(int source_position) { 74 // Statement positions can be replaced by other statement 75 // positions. For example , "for (x = 0; x < 3; ++x) 7;" has a 76 // statement position associated with 7 but no bytecode associated 77 // with it. Then Next is emitted after the body and has 78 // statement position and overrides the existing one. 79 position_type_ = PositionType::kStatement; 80 source_position_ = source_position; 81 } 82 83 // Makes instance into an expression position. Instance should not 84 // be a statement position otherwise it could be lost and impair the 85 // debugging experience. 86 void MakeExpressionPosition(int source_position) { 87 DCHECK(!is_statement()); 88 position_type_ = PositionType::kExpression; 89 source_position_ = source_position; 90 } 91 92 // Forces an instance into an expression position. 93 void ForceExpressionPosition(int source_position) { 94 position_type_ = PositionType::kExpression; 95 source_position_ = source_position; 96 } 97 98 int source_position() const { 99 DCHECK(is_valid()); 100 return source_position_; 101 } 102 103 bool is_statement() const { 104 return position_type_ == PositionType::kStatement; 105 } 106 bool is_expression() const { 107 return position_type_ == PositionType::kExpression; 108 } 109 110 bool is_valid() const { return position_type_ != PositionType::kNone; } 111 void set_invalid() { 112 position_type_ = PositionType::kNone; 113 source_position_ = kUninitializedPosition; 114 } 115 116 bool operator==(const BytecodeSourceInfo& other) const { 117 return position_type_ == other.position_type_ && 118 source_position_ == other.source_position_; 119 } 120 121 bool operator!=(const BytecodeSourceInfo& other) const { 122 return position_type_ != other.position_type_ || 123 source_position_ != other.source_position_; 124 } 125 126 private: 127 enum class PositionType : uint8_t { kNone, kExpression, kStatement }; 128 129 PositionType position_type_; 130 int source_position_; 131 }; 132 133 // A container for a generated bytecode, it's operands, and source information. 134 // These must be allocated by a BytecodeNodeAllocator instance. 135 class V8_EXPORT_PRIVATE BytecodeNode final : NON_EXPORTED_BASE(ZoneObject) { 136 public: 137 INLINE(BytecodeNode(Bytecode bytecode, 138 BytecodeSourceInfo source_info = BytecodeSourceInfo())) 139 : bytecode_(bytecode), 140 operand_count_(0), 141 operand_scale_(OperandScale::kSingle), 142 source_info_(source_info) { 143 DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), operand_count()); 144 } 145 146 INLINE(BytecodeNode(Bytecode bytecode, uint32_t operand0, 147 BytecodeSourceInfo source_info = BytecodeSourceInfo())) 148 : bytecode_(bytecode), 149 operand_count_(1), 150 operand_scale_(OperandScale::kSingle), 151 source_info_(source_info) { 152 DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), operand_count()); 153 SetOperand(0, operand0); 154 } 155 156 INLINE(BytecodeNode(Bytecode bytecode, uint32_t operand0, uint32_t operand1, 157 BytecodeSourceInfo source_info = BytecodeSourceInfo())) 158 : bytecode_(bytecode), 159 operand_count_(2), 160 operand_scale_(OperandScale::kSingle), 161 source_info_(source_info) { 162 DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), operand_count()); 163 SetOperand(0, operand0); 164 SetOperand(1, operand1); 165 } 166 167 INLINE(BytecodeNode(Bytecode bytecode, uint32_t operand0, uint32_t operand1, 168 uint32_t operand2, 169 BytecodeSourceInfo source_info = BytecodeSourceInfo())) 170 : bytecode_(bytecode), 171 operand_count_(3), 172 operand_scale_(OperandScale::kSingle), 173 source_info_(source_info) { 174 DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), operand_count()); 175 SetOperand(0, operand0); 176 SetOperand(1, operand1); 177 SetOperand(2, operand2); 178 } 179 180 INLINE(BytecodeNode(Bytecode bytecode, uint32_t operand0, uint32_t operand1, 181 uint32_t operand2, uint32_t operand3, 182 BytecodeSourceInfo source_info = BytecodeSourceInfo())) 183 : bytecode_(bytecode), 184 operand_count_(4), 185 operand_scale_(OperandScale::kSingle), 186 source_info_(source_info) { 187 DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), operand_count()); 188 SetOperand(0, operand0); 189 SetOperand(1, operand1); 190 SetOperand(2, operand2); 191 SetOperand(3, operand3); 192 } 193 194 #define DEFINE_BYTECODE_NODE_CREATOR(Name, ...) \ 195 template <typename... Operands> \ 196 INLINE(static BytecodeNode Name(BytecodeSourceInfo source_info, \ 197 Operands... operands)) { \ 198 return Create<Bytecode::k##Name, __VA_ARGS__>(source_info, operands...); \ 199 } 200 BYTECODE_LIST(DEFINE_BYTECODE_NODE_CREATOR) 201 #undef DEFINE_BYTECODE_NODE_CREATOR 202 203 // Replace the bytecode of this node with |bytecode| and keep the operands. 204 void replace_bytecode(Bytecode bytecode) { 205 DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode_), 206 Bytecodes::NumberOfOperands(bytecode)); 207 bytecode_ = bytecode; 208 } 209 210 void update_operand0(uint32_t operand0) { SetOperand(0, operand0); } 211 212 // Print to stream |os|. 213 void Print(std::ostream& os) const; 214 215 // Transform to a node representing |new_bytecode| which has one 216 // operand more than the current bytecode. 217 void Transform(Bytecode new_bytecode, uint32_t extra_operand) { 218 DCHECK_EQ(Bytecodes::NumberOfOperands(new_bytecode), 219 Bytecodes::NumberOfOperands(bytecode()) + 1); 220 DCHECK(Bytecodes::NumberOfOperands(bytecode()) < 1 || 221 Bytecodes::GetOperandType(new_bytecode, 0) == 222 Bytecodes::GetOperandType(bytecode(), 0)); 223 DCHECK(Bytecodes::NumberOfOperands(bytecode()) < 2 || 224 Bytecodes::GetOperandType(new_bytecode, 1) == 225 Bytecodes::GetOperandType(bytecode(), 1)); 226 DCHECK(Bytecodes::NumberOfOperands(bytecode()) < 3 || 227 Bytecodes::GetOperandType(new_bytecode, 2) == 228 Bytecodes::GetOperandType(bytecode(), 2)); 229 DCHECK(Bytecodes::NumberOfOperands(bytecode()) < 4); 230 231 bytecode_ = new_bytecode; 232 operand_count_++; 233 SetOperand(operand_count() - 1, extra_operand); 234 } 235 236 Bytecode bytecode() const { return bytecode_; } 237 238 uint32_t operand(int i) const { 239 DCHECK_LT(i, operand_count()); 240 return operands_[i]; 241 } 242 const uint32_t* operands() const { return operands_; } 243 244 int operand_count() const { return operand_count_; } 245 OperandScale operand_scale() const { return operand_scale_; } 246 247 const BytecodeSourceInfo& source_info() const { return source_info_; } 248 void set_source_info(BytecodeSourceInfo source_info) { 249 source_info_ = source_info; 250 } 251 252 bool operator==(const BytecodeNode& other) const; 253 bool operator!=(const BytecodeNode& other) const { return !(*this == other); } 254 255 private: 256 template <Bytecode bytecode, AccumulatorUse accumulator_use, 257 OperandType... operand_types> 258 friend class BytecodeNodeBuilder; 259 260 INLINE(BytecodeNode(Bytecode bytecode, int operand_count, 261 OperandScale operand_scale, 262 BytecodeSourceInfo source_info, uint32_t operand0 = 0, 263 uint32_t operand1 = 0, uint32_t operand2 = 0, 264 uint32_t operand3 = 0)) 265 : bytecode_(bytecode), 266 operand_count_(operand_count), 267 operand_scale_(operand_scale), 268 source_info_(source_info) { 269 DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), operand_count); 270 operands_[0] = operand0; 271 operands_[1] = operand1; 272 operands_[2] = operand2; 273 operands_[3] = operand3; 274 } 275 276 template <Bytecode bytecode, AccumulatorUse accum_use> 277 INLINE(static BytecodeNode Create(BytecodeSourceInfo source_info)) { 278 return BytecodeNode(bytecode, 0, OperandScale::kSingle, source_info); 279 } 280 281 template <Bytecode bytecode, AccumulatorUse accum_use, 282 OperandType operand0_type> 283 INLINE(static BytecodeNode Create(BytecodeSourceInfo source_info, 284 uint32_t operand0)) { 285 DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 0), operand0_type); 286 OperandScale scale = OperandScale::kSingle; 287 scale = std::max(scale, ScaleForOperand<operand0_type>(operand0)); 288 return BytecodeNode(bytecode, 1, scale, source_info, operand0); 289 } 290 291 template <Bytecode bytecode, AccumulatorUse accum_use, 292 OperandType operand0_type, OperandType operand1_type> 293 INLINE(static BytecodeNode Create(BytecodeSourceInfo source_info, 294 uint32_t operand0, uint32_t operand1)) { 295 DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 0), operand0_type); 296 DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 1), operand1_type); 297 OperandScale scale = OperandScale::kSingle; 298 scale = std::max(scale, ScaleForOperand<operand0_type>(operand0)); 299 scale = std::max(scale, ScaleForOperand<operand1_type>(operand1)); 300 return BytecodeNode(bytecode, 2, scale, source_info, operand0, operand1); 301 } 302 303 template <Bytecode bytecode, AccumulatorUse accum_use, 304 OperandType operand0_type, OperandType operand1_type, 305 OperandType operand2_type> 306 INLINE(static BytecodeNode Create(BytecodeSourceInfo source_info, 307 uint32_t operand0, uint32_t operand1, 308 uint32_t operand2)) { 309 DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 0), operand0_type); 310 DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 1), operand1_type); 311 DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 2), operand2_type); 312 OperandScale scale = OperandScale::kSingle; 313 scale = std::max(scale, ScaleForOperand<operand0_type>(operand0)); 314 scale = std::max(scale, ScaleForOperand<operand1_type>(operand1)); 315 scale = std::max(scale, ScaleForOperand<operand2_type>(operand2)); 316 return BytecodeNode(bytecode, 3, scale, source_info, operand0, operand1, 317 operand2); 318 } 319 320 template <Bytecode bytecode, AccumulatorUse accum_use, 321 OperandType operand0_type, OperandType operand1_type, 322 OperandType operand2_type, OperandType operand3_type> 323 INLINE(static BytecodeNode Create(BytecodeSourceInfo source_info, 324 uint32_t operand0, uint32_t operand1, 325 uint32_t operand2, uint32_t operand3)) { 326 DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 0), operand0_type); 327 DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 1), operand1_type); 328 DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 2), operand2_type); 329 DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 3), operand3_type); 330 OperandScale scale = OperandScale::kSingle; 331 scale = std::max(scale, ScaleForOperand<operand0_type>(operand0)); 332 scale = std::max(scale, ScaleForOperand<operand1_type>(operand1)); 333 scale = std::max(scale, ScaleForOperand<operand2_type>(operand2)); 334 scale = std::max(scale, ScaleForOperand<operand3_type>(operand3)); 335 return BytecodeNode(bytecode, 4, scale, source_info, operand0, operand1, 336 operand2, operand3); 337 } 338 339 template <OperandType operand_type> 340 INLINE(static OperandScale ScaleForOperand(uint32_t operand)) { 341 if (BytecodeOperands::IsScalableUnsignedByte(operand_type)) { 342 return Bytecodes::ScaleForUnsignedOperand(operand); 343 } else if (BytecodeOperands::IsScalableSignedByte(operand_type)) { 344 return Bytecodes::ScaleForSignedOperand(operand); 345 } else { 346 return OperandScale::kSingle; 347 } 348 } 349 350 INLINE(void UpdateScaleForOperand(int operand_index, uint32_t operand)) { 351 if (Bytecodes::OperandIsScalableSignedByte(bytecode(), operand_index)) { 352 operand_scale_ = 353 std::max(operand_scale_, Bytecodes::ScaleForSignedOperand(operand)); 354 } else if (Bytecodes::OperandIsScalableUnsignedByte(bytecode(), 355 operand_index)) { 356 operand_scale_ = 357 std::max(operand_scale_, Bytecodes::ScaleForUnsignedOperand(operand)); 358 } 359 } 360 361 INLINE(void SetOperand(int operand_index, uint32_t operand)) { 362 operands_[operand_index] = operand; 363 UpdateScaleForOperand(operand_index, operand); 364 } 365 366 Bytecode bytecode_; 367 uint32_t operands_[Bytecodes::kMaxOperands]; 368 int operand_count_; 369 OperandScale operand_scale_; 370 BytecodeSourceInfo source_info_; 371 }; 372 373 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, 374 const BytecodeSourceInfo& info); 375 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, 376 const BytecodeNode& node); 377 378 } // namespace interpreter 379 } // namespace internal 380 } // namespace v8 381 382 #endif // V8_INTERPRETER_BYTECODE_PIPELINE_H_ 383