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 #include "src/interpreter/bytecode-array-builder.h" 6 7 #include "src/globals.h" 8 #include "src/interpreter/bytecode-array-writer.h" 9 #include "src/interpreter/bytecode-dead-code-optimizer.h" 10 #include "src/interpreter/bytecode-label.h" 11 #include "src/interpreter/bytecode-peephole-optimizer.h" 12 #include "src/interpreter/bytecode-register-optimizer.h" 13 #include "src/interpreter/interpreter-intrinsics.h" 14 15 namespace v8 { 16 namespace internal { 17 namespace interpreter { 18 19 BytecodeArrayBuilder::BytecodeArrayBuilder( 20 Isolate* isolate, Zone* zone, int parameter_count, int context_count, 21 int locals_count, FunctionLiteral* literal, 22 SourcePositionTableBuilder::RecordingMode source_position_mode) 23 : zone_(zone), 24 bytecode_generated_(false), 25 constant_array_builder_(zone, isolate->factory()->the_hole_value()), 26 handler_table_builder_(zone), 27 return_seen_in_block_(false), 28 parameter_count_(parameter_count), 29 local_register_count_(locals_count), 30 context_register_count_(context_count), 31 register_allocator_(fixed_register_count()), 32 bytecode_array_writer_(zone, &constant_array_builder_, 33 source_position_mode), 34 pipeline_(&bytecode_array_writer_), 35 register_optimizer_(nullptr) { 36 DCHECK_GE(parameter_count_, 0); 37 DCHECK_GE(context_register_count_, 0); 38 DCHECK_GE(local_register_count_, 0); 39 40 if (FLAG_ignition_deadcode) { 41 pipeline_ = new (zone) BytecodeDeadCodeOptimizer(pipeline_); 42 } 43 44 if (FLAG_ignition_peephole) { 45 pipeline_ = new (zone) BytecodePeepholeOptimizer(pipeline_); 46 } 47 48 if (FLAG_ignition_reo) { 49 register_optimizer_ = new (zone) BytecodeRegisterOptimizer( 50 zone, ®ister_allocator_, fixed_register_count(), parameter_count, 51 pipeline_); 52 } 53 54 return_position_ = literal ? literal->return_position() : kNoSourcePosition; 55 } 56 57 Register BytecodeArrayBuilder::first_context_register() const { 58 DCHECK_GT(context_register_count_, 0); 59 return Register(local_register_count_); 60 } 61 62 Register BytecodeArrayBuilder::last_context_register() const { 63 DCHECK_GT(context_register_count_, 0); 64 return Register(local_register_count_ + context_register_count_ - 1); 65 } 66 67 Register BytecodeArrayBuilder::Parameter(int parameter_index) const { 68 DCHECK_GE(parameter_index, 0); 69 return Register::FromParameterIndex(parameter_index, parameter_count()); 70 } 71 72 Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray(Isolate* isolate) { 73 DCHECK(return_seen_in_block_); 74 DCHECK(!bytecode_generated_); 75 bytecode_generated_ = true; 76 77 int register_count = total_register_count(); 78 79 if (register_optimizer_) { 80 register_optimizer_->Flush(); 81 register_count = register_optimizer_->maxiumum_register_index() + 1; 82 } 83 84 Handle<FixedArray> handler_table = 85 handler_table_builder()->ToHandlerTable(isolate); 86 return pipeline_->ToBytecodeArray(isolate, register_count, parameter_count(), 87 handler_table); 88 } 89 90 BytecodeSourceInfo BytecodeArrayBuilder::CurrentSourcePosition( 91 Bytecode bytecode) { 92 BytecodeSourceInfo source_position; 93 if (latest_source_info_.is_valid()) { 94 // Statement positions need to be emitted immediately. Expression 95 // positions can be pushed back until a bytecode is found that can 96 // throw (if expression position filtering is turned on). We only 97 // invalidate the existing source position information if it is used. 98 if (latest_source_info_.is_statement() || 99 !FLAG_ignition_filter_expression_positions || 100 !Bytecodes::IsWithoutExternalSideEffects(bytecode)) { 101 source_position = latest_source_info_; 102 latest_source_info_.set_invalid(); 103 } 104 } 105 return source_position; 106 } 107 108 namespace { 109 110 template <OperandTypeInfo type_info> 111 class UnsignedOperandHelper { 112 public: 113 INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, size_t value)) { 114 DCHECK(IsValid(value)); 115 return static_cast<uint32_t>(value); 116 } 117 118 INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, int value)) { 119 DCHECK_GE(value, 0); 120 return Convert(builder, static_cast<size_t>(value)); 121 } 122 123 private: 124 static bool IsValid(size_t value) { 125 switch (type_info) { 126 case OperandTypeInfo::kFixedUnsignedByte: 127 return value <= kMaxUInt8; 128 case OperandTypeInfo::kFixedUnsignedShort: 129 return value <= kMaxUInt16; 130 case OperandTypeInfo::kScalableUnsignedByte: 131 return value <= kMaxUInt32; 132 default: 133 UNREACHABLE(); 134 return false; 135 } 136 } 137 }; 138 139 template <OperandType> 140 class OperandHelper {}; 141 142 #define DEFINE_UNSIGNED_OPERAND_HELPER(Name, Type) \ 143 template <> \ 144 class OperandHelper<OperandType::k##Name> \ 145 : public UnsignedOperandHelper<Type> {}; 146 UNSIGNED_SCALAR_OPERAND_TYPE_LIST(DEFINE_UNSIGNED_OPERAND_HELPER) 147 #undef DEFINE_UNSIGNED_OPERAND_HELPER 148 149 template <> 150 class OperandHelper<OperandType::kImm> { 151 public: 152 INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, int value)) { 153 return static_cast<uint32_t>(value); 154 } 155 }; 156 157 template <> 158 class OperandHelper<OperandType::kReg> { 159 public: 160 INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, Register reg)) { 161 return builder->GetInputRegisterOperand(reg); 162 } 163 }; 164 165 template <> 166 class OperandHelper<OperandType::kRegList> { 167 public: 168 INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, 169 RegisterList reg_list)) { 170 return builder->GetInputRegisterListOperand(reg_list); 171 } 172 }; 173 174 template <> 175 class OperandHelper<OperandType::kRegPair> { 176 public: 177 INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, 178 RegisterList reg_list)) { 179 DCHECK_EQ(reg_list.register_count(), 2); 180 return builder->GetInputRegisterListOperand(reg_list); 181 } 182 }; 183 184 template <> 185 class OperandHelper<OperandType::kRegOut> { 186 public: 187 INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, Register reg)) { 188 return builder->GetOutputRegisterOperand(reg); 189 } 190 }; 191 192 template <> 193 class OperandHelper<OperandType::kRegOutPair> { 194 public: 195 INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, 196 RegisterList reg_list)) { 197 DCHECK_EQ(2, reg_list.register_count()); 198 return builder->GetOutputRegisterListOperand(reg_list); 199 } 200 }; 201 202 template <> 203 class OperandHelper<OperandType::kRegOutTriple> { 204 public: 205 INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, 206 RegisterList reg_list)) { 207 DCHECK_EQ(3, reg_list.register_count()); 208 return builder->GetOutputRegisterListOperand(reg_list); 209 } 210 }; 211 212 } // namespace 213 214 template <OperandType... operand_types> 215 class BytecodeNodeBuilder { 216 public: 217 template <typename... Operands> 218 INLINE(static BytecodeNode Make(BytecodeArrayBuilder* builder, 219 BytecodeSourceInfo source_info, 220 Bytecode bytecode, Operands... operands)) { 221 builder->PrepareToOutputBytecode(bytecode); 222 // The "OperandHelper<operand_types>::Convert(builder, operands)..." will 223 // expand both the OperandType... and Operands... parameter packs e.g. for: 224 // BytecodeNodeBuilder<OperandType::kReg, OperandType::kImm>::Make< 225 // Register, int>(..., Register reg, int immediate) 226 // the code will expand into: 227 // OperandHelper<OperandType::kReg>::Convert(builder, reg), 228 // OperandHelper<OperandType::kImm>::Convert(builder, immediate), 229 return BytecodeNode( 230 bytecode, OperandHelper<operand_types>::Convert(builder, operands)..., 231 source_info); 232 } 233 }; 234 235 #define DEFINE_BYTECODE_OUTPUT(name, accumulator_use, ...) \ 236 template <typename... Operands> \ 237 void BytecodeArrayBuilder::Output##name(Operands... operands) { \ 238 BytecodeNode node(BytecodeNodeBuilder<__VA_ARGS__>::Make<Operands...>( \ 239 this, CurrentSourcePosition(Bytecode::k##name), Bytecode::k##name, \ 240 operands...)); \ 241 pipeline()->Write(&node); \ 242 } \ 243 \ 244 template <typename... Operands> \ 245 void BytecodeArrayBuilder::Output##name(BytecodeLabel* label, \ 246 Operands... operands) { \ 247 DCHECK(Bytecodes::IsJump(Bytecode::k##name)); \ 248 BytecodeNode node(BytecodeNodeBuilder<__VA_ARGS__>::Make<Operands...>( \ 249 this, CurrentSourcePosition(Bytecode::k##name), Bytecode::k##name, \ 250 operands...)); \ 251 pipeline()->WriteJump(&node, label); \ 252 LeaveBasicBlock(); \ 253 } 254 BYTECODE_LIST(DEFINE_BYTECODE_OUTPUT) 255 #undef DEFINE_BYTECODE_OUTPUT 256 257 BytecodeArrayBuilder& BytecodeArrayBuilder::BinaryOperation(Token::Value op, 258 Register reg, 259 int feedback_slot) { 260 switch (op) { 261 case Token::Value::ADD: 262 OutputAdd(reg, feedback_slot); 263 break; 264 case Token::Value::SUB: 265 OutputSub(reg, feedback_slot); 266 break; 267 case Token::Value::MUL: 268 OutputMul(reg, feedback_slot); 269 break; 270 case Token::Value::DIV: 271 OutputDiv(reg, feedback_slot); 272 break; 273 case Token::Value::MOD: 274 OutputMod(reg, feedback_slot); 275 break; 276 case Token::Value::BIT_OR: 277 OutputBitwiseOr(reg, feedback_slot); 278 break; 279 case Token::Value::BIT_XOR: 280 OutputBitwiseXor(reg, feedback_slot); 281 break; 282 case Token::Value::BIT_AND: 283 OutputBitwiseAnd(reg, feedback_slot); 284 break; 285 case Token::Value::SHL: 286 OutputShiftLeft(reg, feedback_slot); 287 break; 288 case Token::Value::SAR: 289 OutputShiftRight(reg, feedback_slot); 290 break; 291 case Token::Value::SHR: 292 OutputShiftRightLogical(reg, feedback_slot); 293 break; 294 default: 295 UNREACHABLE(); 296 } 297 return *this; 298 } 299 300 BytecodeArrayBuilder& BytecodeArrayBuilder::CountOperation(Token::Value op, 301 int feedback_slot) { 302 if (op == Token::Value::ADD) { 303 OutputInc(feedback_slot); 304 } else { 305 DCHECK_EQ(op, Token::Value::SUB); 306 OutputDec(feedback_slot); 307 } 308 return *this; 309 } 310 311 BytecodeArrayBuilder& BytecodeArrayBuilder::LogicalNot() { 312 OutputToBooleanLogicalNot(); 313 return *this; 314 } 315 316 BytecodeArrayBuilder& BytecodeArrayBuilder::TypeOf() { 317 OutputTypeOf(); 318 return *this; 319 } 320 321 BytecodeArrayBuilder& BytecodeArrayBuilder::CompareOperation( 322 Token::Value op, Register reg, int feedback_slot) { 323 switch (op) { 324 case Token::Value::EQ: 325 OutputTestEqual(reg, feedback_slot); 326 break; 327 case Token::Value::NE: 328 OutputTestNotEqual(reg, feedback_slot); 329 break; 330 case Token::Value::EQ_STRICT: 331 OutputTestEqualStrict(reg, feedback_slot); 332 break; 333 case Token::Value::LT: 334 OutputTestLessThan(reg, feedback_slot); 335 break; 336 case Token::Value::GT: 337 OutputTestGreaterThan(reg, feedback_slot); 338 break; 339 case Token::Value::LTE: 340 OutputTestLessThanOrEqual(reg, feedback_slot); 341 break; 342 case Token::Value::GTE: 343 OutputTestGreaterThanOrEqual(reg, feedback_slot); 344 break; 345 case Token::Value::INSTANCEOF: 346 OutputTestInstanceOf(reg); 347 break; 348 case Token::Value::IN: 349 OutputTestIn(reg); 350 break; 351 default: 352 UNREACHABLE(); 353 } 354 return *this; 355 } 356 357 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadConstantPoolEntry( 358 size_t entry) { 359 OutputLdaConstant(entry); 360 return *this; 361 } 362 363 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral( 364 v8::internal::Smi* smi) { 365 int32_t raw_smi = smi->value(); 366 if (raw_smi == 0) { 367 OutputLdaZero(); 368 } else { 369 OutputLdaSmi(raw_smi); 370 } 371 return *this; 372 } 373 374 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(Handle<Object> object) { 375 size_t entry = GetConstantPoolEntry(object); 376 OutputLdaConstant(entry); 377 return *this; 378 } 379 380 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadUndefined() { 381 OutputLdaUndefined(); 382 return *this; 383 } 384 385 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNull() { 386 OutputLdaNull(); 387 return *this; 388 } 389 390 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadTheHole() { 391 OutputLdaTheHole(); 392 return *this; 393 } 394 395 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadTrue() { 396 OutputLdaTrue(); 397 return *this; 398 } 399 400 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadFalse() { 401 OutputLdaFalse(); 402 return *this; 403 } 404 405 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadAccumulatorWithRegister( 406 Register reg) { 407 if (register_optimizer_) { 408 register_optimizer_->DoLdar(reg, CurrentSourcePosition(Bytecode::kLdar)); 409 } else { 410 OutputLdar(reg); 411 } 412 return *this; 413 } 414 415 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreAccumulatorInRegister( 416 Register reg) { 417 if (register_optimizer_) { 418 register_optimizer_->DoStar(reg, CurrentSourcePosition(Bytecode::kStar)); 419 } else { 420 OutputStar(reg); 421 } 422 return *this; 423 } 424 425 BytecodeArrayBuilder& BytecodeArrayBuilder::MoveRegister(Register from, 426 Register to) { 427 DCHECK(from != to); 428 if (register_optimizer_) { 429 register_optimizer_->DoMov(from, to, CurrentSourcePosition(Bytecode::kMov)); 430 } else { 431 OutputMov(from, to); 432 } 433 return *this; 434 } 435 436 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadGlobal(int feedback_slot, 437 TypeofMode typeof_mode) { 438 if (typeof_mode == INSIDE_TYPEOF) { 439 OutputLdaGlobalInsideTypeof(feedback_slot); 440 } else { 441 DCHECK_EQ(typeof_mode, NOT_INSIDE_TYPEOF); 442 OutputLdaGlobal(feedback_slot); 443 } 444 return *this; 445 } 446 447 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreGlobal( 448 const Handle<String> name, int feedback_slot, LanguageMode language_mode) { 449 size_t name_index = GetConstantPoolEntry(name); 450 if (language_mode == SLOPPY) { 451 OutputStaGlobalSloppy(name_index, feedback_slot); 452 } else { 453 DCHECK_EQ(language_mode, STRICT); 454 OutputStaGlobalStrict(name_index, feedback_slot); 455 } 456 return *this; 457 } 458 459 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadContextSlot(Register context, 460 int slot_index, 461 int depth) { 462 if (context.is_current_context() && depth == 0) { 463 OutputLdaCurrentContextSlot(slot_index); 464 } else { 465 OutputLdaContextSlot(context, slot_index, depth); 466 } 467 return *this; 468 } 469 470 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreContextSlot(Register context, 471 int slot_index, 472 int depth) { 473 if (context.is_current_context() && depth == 0) { 474 OutputStaCurrentContextSlot(slot_index); 475 } else { 476 OutputStaContextSlot(context, slot_index, depth); 477 } 478 return *this; 479 } 480 481 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupSlot( 482 const Handle<String> name, TypeofMode typeof_mode) { 483 size_t name_index = GetConstantPoolEntry(name); 484 if (typeof_mode == INSIDE_TYPEOF) { 485 OutputLdaLookupSlotInsideTypeof(name_index); 486 } else { 487 DCHECK_EQ(typeof_mode, NOT_INSIDE_TYPEOF); 488 OutputLdaLookupSlot(name_index); 489 } 490 return *this; 491 } 492 493 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupContextSlot( 494 const Handle<String> name, TypeofMode typeof_mode, int slot_index, 495 int depth) { 496 size_t name_index = GetConstantPoolEntry(name); 497 if (typeof_mode == INSIDE_TYPEOF) { 498 OutputLdaLookupContextSlotInsideTypeof(name_index, slot_index, depth); 499 } else { 500 DCHECK(typeof_mode == NOT_INSIDE_TYPEOF); 501 OutputLdaLookupContextSlot(name_index, slot_index, depth); 502 } 503 return *this; 504 } 505 506 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupGlobalSlot( 507 const Handle<String> name, TypeofMode typeof_mode, int feedback_slot, 508 int depth) { 509 size_t name_index = GetConstantPoolEntry(name); 510 if (typeof_mode == INSIDE_TYPEOF) { 511 OutputLdaLookupGlobalSlotInsideTypeof(name_index, feedback_slot, depth); 512 } else { 513 DCHECK(typeof_mode == NOT_INSIDE_TYPEOF); 514 OutputLdaLookupGlobalSlot(name_index, feedback_slot, depth); 515 } 516 return *this; 517 } 518 519 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreLookupSlot( 520 const Handle<String> name, LanguageMode language_mode) { 521 size_t name_index = GetConstantPoolEntry(name); 522 if (language_mode == SLOPPY) { 523 OutputStaLookupSlotSloppy(name_index); 524 } else { 525 DCHECK_EQ(language_mode, STRICT); 526 OutputStaLookupSlotStrict(name_index); 527 } 528 return *this; 529 } 530 531 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNamedProperty( 532 Register object, const Handle<Name> name, int feedback_slot) { 533 size_t name_index = GetConstantPoolEntry(name); 534 OutputLdaNamedProperty(object, name_index, feedback_slot); 535 return *this; 536 } 537 538 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadKeyedProperty( 539 Register object, int feedback_slot) { 540 OutputLdaKeyedProperty(object, feedback_slot); 541 return *this; 542 } 543 544 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreNamedProperty( 545 Register object, const Handle<Name> name, int feedback_slot, 546 LanguageMode language_mode) { 547 size_t name_index = GetConstantPoolEntry(name); 548 if (language_mode == SLOPPY) { 549 OutputStaNamedPropertySloppy(object, name_index, feedback_slot); 550 } else { 551 DCHECK_EQ(language_mode, STRICT); 552 OutputStaNamedPropertyStrict(object, name_index, feedback_slot); 553 } 554 return *this; 555 } 556 557 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreKeyedProperty( 558 Register object, Register key, int feedback_slot, 559 LanguageMode language_mode) { 560 if (language_mode == SLOPPY) { 561 OutputStaKeyedPropertySloppy(object, key, feedback_slot); 562 } else { 563 DCHECK_EQ(language_mode, STRICT); 564 OutputStaKeyedPropertyStrict(object, key, feedback_slot); 565 } 566 return *this; 567 } 568 569 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateClosure(size_t entry, 570 int flags) { 571 OutputCreateClosure(entry, flags); 572 return *this; 573 } 574 575 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateBlockContext( 576 Handle<ScopeInfo> scope_info) { 577 size_t entry = GetConstantPoolEntry(scope_info); 578 OutputCreateBlockContext(entry); 579 return *this; 580 } 581 582 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateCatchContext( 583 Register exception, Handle<String> name, Handle<ScopeInfo> scope_info) { 584 size_t name_index = GetConstantPoolEntry(name); 585 size_t scope_info_index = GetConstantPoolEntry(scope_info); 586 OutputCreateCatchContext(exception, name_index, scope_info_index); 587 return *this; 588 } 589 590 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateFunctionContext(int slots) { 591 OutputCreateFunctionContext(slots); 592 return *this; 593 } 594 595 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateWithContext( 596 Register object, Handle<ScopeInfo> scope_info) { 597 size_t scope_info_index = GetConstantPoolEntry(scope_info); 598 OutputCreateWithContext(object, scope_info_index); 599 return *this; 600 } 601 602 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArguments( 603 CreateArgumentsType type) { 604 switch (type) { 605 case CreateArgumentsType::kMappedArguments: 606 OutputCreateMappedArguments(); 607 break; 608 case CreateArgumentsType::kUnmappedArguments: 609 OutputCreateUnmappedArguments(); 610 break; 611 case CreateArgumentsType::kRestParameter: 612 OutputCreateRestParameter(); 613 break; 614 default: 615 UNREACHABLE(); 616 } 617 return *this; 618 } 619 620 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateRegExpLiteral( 621 Handle<String> pattern, int literal_index, int flags) { 622 size_t pattern_entry = GetConstantPoolEntry(pattern); 623 OutputCreateRegExpLiteral(pattern_entry, literal_index, flags); 624 return *this; 625 } 626 627 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArrayLiteral( 628 Handle<FixedArray> constant_elements, int literal_index, int flags) { 629 size_t constant_elements_entry = GetConstantPoolEntry(constant_elements); 630 OutputCreateArrayLiteral(constant_elements_entry, literal_index, flags); 631 return *this; 632 } 633 634 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateObjectLiteral( 635 Handle<FixedArray> constant_properties, int literal_index, int flags, 636 Register output) { 637 size_t constant_properties_entry = GetConstantPoolEntry(constant_properties); 638 OutputCreateObjectLiteral(constant_properties_entry, literal_index, flags, 639 output); 640 return *this; 641 } 642 643 BytecodeArrayBuilder& BytecodeArrayBuilder::PushContext(Register context) { 644 OutputPushContext(context); 645 return *this; 646 } 647 648 BytecodeArrayBuilder& BytecodeArrayBuilder::PopContext(Register context) { 649 OutputPopContext(context); 650 return *this; 651 } 652 653 BytecodeArrayBuilder& BytecodeArrayBuilder::ConvertAccumulatorToObject( 654 Register out) { 655 OutputToObject(out); 656 return *this; 657 } 658 659 BytecodeArrayBuilder& BytecodeArrayBuilder::ConvertAccumulatorToName( 660 Register out) { 661 OutputToName(out); 662 return *this; 663 } 664 665 BytecodeArrayBuilder& BytecodeArrayBuilder::ConvertAccumulatorToNumber( 666 Register out) { 667 OutputToNumber(out); 668 return *this; 669 } 670 671 BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(BytecodeLabel* label) { 672 // Flush the register optimizer when binding a label to ensure all 673 // expected registers are valid when jumping to this label. 674 if (register_optimizer_) register_optimizer_->Flush(); 675 pipeline_->BindLabel(label); 676 LeaveBasicBlock(); 677 return *this; 678 } 679 680 BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(const BytecodeLabel& target, 681 BytecodeLabel* label) { 682 pipeline_->BindLabel(target, label); 683 LeaveBasicBlock(); 684 return *this; 685 } 686 687 BytecodeArrayBuilder& BytecodeArrayBuilder::Jump(BytecodeLabel* label) { 688 OutputJump(label, 0); 689 return *this; 690 } 691 692 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfTrue(BytecodeLabel* label) { 693 // The peephole optimizer attempts to simplify JumpIfToBooleanTrue 694 // to JumpIfTrue. 695 OutputJumpIfToBooleanTrue(label, 0); 696 return *this; 697 } 698 699 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfFalse(BytecodeLabel* label) { 700 OutputJumpIfToBooleanFalse(label, 0); 701 return *this; 702 } 703 704 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNull(BytecodeLabel* label) { 705 OutputJumpIfNull(label, 0); 706 return *this; 707 } 708 709 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfUndefined( 710 BytecodeLabel* label) { 711 OutputJumpIfUndefined(label, 0); 712 return *this; 713 } 714 715 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNotHole( 716 BytecodeLabel* label) { 717 OutputJumpIfNotHole(label, 0); 718 return *this; 719 } 720 721 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpLoop(BytecodeLabel* label, 722 int loop_depth) { 723 OutputJumpLoop(label, 0, loop_depth); 724 return *this; 725 } 726 727 BytecodeArrayBuilder& BytecodeArrayBuilder::StackCheck(int position) { 728 if (position != kNoSourcePosition) { 729 // We need to attach a non-breakable source position to a stack 730 // check, so we simply add it as expression position. There can be 731 // a prior statement position from constructs like: 732 // 733 // do var x; while (false); 734 // 735 // A Nop could be inserted for empty statements, but since no code 736 // is associated with these positions, instead we force the stack 737 // check's expression position which eliminates the empty 738 // statement's position. 739 latest_source_info_.ForceExpressionPosition(position); 740 } 741 OutputStackCheck(); 742 return *this; 743 } 744 745 BytecodeArrayBuilder& BytecodeArrayBuilder::Throw() { 746 OutputThrow(); 747 return *this; 748 } 749 750 BytecodeArrayBuilder& BytecodeArrayBuilder::ReThrow() { 751 OutputReThrow(); 752 return *this; 753 } 754 755 BytecodeArrayBuilder& BytecodeArrayBuilder::Return() { 756 SetReturnPosition(); 757 OutputReturn(); 758 return_seen_in_block_ = true; 759 return *this; 760 } 761 762 BytecodeArrayBuilder& BytecodeArrayBuilder::Debugger() { 763 OutputDebugger(); 764 return *this; 765 } 766 767 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInPrepare( 768 Register receiver, RegisterList cache_info_triple) { 769 DCHECK_EQ(3, cache_info_triple.register_count()); 770 OutputForInPrepare(receiver, cache_info_triple); 771 return *this; 772 } 773 774 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInContinue( 775 Register index, Register cache_length) { 776 OutputForInContinue(index, cache_length); 777 return *this; 778 } 779 780 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInNext( 781 Register receiver, Register index, RegisterList cache_type_array_pair, 782 int feedback_slot) { 783 DCHECK_EQ(2, cache_type_array_pair.register_count()); 784 OutputForInNext(receiver, index, cache_type_array_pair, feedback_slot); 785 return *this; 786 } 787 788 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInStep(Register index) { 789 OutputForInStep(index); 790 return *this; 791 } 792 793 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreModuleVariable(int cell_index, 794 int depth) { 795 OutputStaModuleVariable(cell_index, depth); 796 return *this; 797 } 798 799 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadModuleVariable(int cell_index, 800 int depth) { 801 OutputLdaModuleVariable(cell_index, depth); 802 return *this; 803 } 804 805 BytecodeArrayBuilder& BytecodeArrayBuilder::SuspendGenerator( 806 Register generator) { 807 OutputSuspendGenerator(generator); 808 return *this; 809 } 810 811 BytecodeArrayBuilder& BytecodeArrayBuilder::ResumeGenerator( 812 Register generator) { 813 OutputResumeGenerator(generator); 814 return *this; 815 } 816 817 BytecodeArrayBuilder& BytecodeArrayBuilder::MarkHandler( 818 int handler_id, HandlerTable::CatchPrediction catch_prediction) { 819 BytecodeLabel handler; 820 Bind(&handler); 821 handler_table_builder()->SetHandlerTarget(handler_id, handler.offset()); 822 handler_table_builder()->SetPrediction(handler_id, catch_prediction); 823 return *this; 824 } 825 826 BytecodeArrayBuilder& BytecodeArrayBuilder::MarkTryBegin(int handler_id, 827 Register context) { 828 BytecodeLabel try_begin; 829 Bind(&try_begin); 830 handler_table_builder()->SetTryRegionStart(handler_id, try_begin.offset()); 831 handler_table_builder()->SetContextRegister(handler_id, context); 832 return *this; 833 } 834 835 BytecodeArrayBuilder& BytecodeArrayBuilder::MarkTryEnd(int handler_id) { 836 BytecodeLabel try_end; 837 Bind(&try_end); 838 handler_table_builder()->SetTryRegionEnd(handler_id, try_end.offset()); 839 return *this; 840 } 841 842 BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable, 843 RegisterList args, 844 int feedback_slot, 845 Call::CallType call_type, 846 TailCallMode tail_call_mode) { 847 if (tail_call_mode == TailCallMode::kDisallow) { 848 if (call_type == Call::NAMED_PROPERTY_CALL || 849 call_type == Call::KEYED_PROPERTY_CALL) { 850 OutputCallProperty(callable, args, args.register_count(), feedback_slot); 851 } else { 852 OutputCall(callable, args, args.register_count(), feedback_slot); 853 } 854 } else { 855 DCHECK(tail_call_mode == TailCallMode::kAllow); 856 OutputTailCall(callable, args, args.register_count(), feedback_slot); 857 } 858 return *this; 859 } 860 861 BytecodeArrayBuilder& BytecodeArrayBuilder::New(Register constructor, 862 RegisterList args, 863 int feedback_slot_id) { 864 OutputNew(constructor, args, args.register_count(), feedback_slot_id); 865 return *this; 866 } 867 868 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime( 869 Runtime::FunctionId function_id, RegisterList args) { 870 DCHECK_EQ(1, Runtime::FunctionForId(function_id)->result_size); 871 DCHECK(Bytecodes::SizeForUnsignedOperand(function_id) <= OperandSize::kShort); 872 if (IntrinsicsHelper::IsSupported(function_id)) { 873 IntrinsicsHelper::IntrinsicId intrinsic_id = 874 IntrinsicsHelper::FromRuntimeId(function_id); 875 OutputInvokeIntrinsic(static_cast<int>(intrinsic_id), args, 876 args.register_count()); 877 } else { 878 OutputCallRuntime(static_cast<int>(function_id), args, 879 args.register_count()); 880 } 881 return *this; 882 } 883 884 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime( 885 Runtime::FunctionId function_id, Register arg) { 886 return CallRuntime(function_id, RegisterList(arg.index(), 1)); 887 } 888 889 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime( 890 Runtime::FunctionId function_id) { 891 return CallRuntime(function_id, RegisterList()); 892 } 893 894 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntimeForPair( 895 Runtime::FunctionId function_id, RegisterList args, 896 RegisterList return_pair) { 897 DCHECK_EQ(2, Runtime::FunctionForId(function_id)->result_size); 898 DCHECK(Bytecodes::SizeForUnsignedOperand(function_id) <= OperandSize::kShort); 899 DCHECK_EQ(2, return_pair.register_count()); 900 OutputCallRuntimeForPair(static_cast<uint16_t>(function_id), args, 901 args.register_count(), return_pair); 902 return *this; 903 } 904 905 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntimeForPair( 906 Runtime::FunctionId function_id, Register arg, RegisterList return_pair) { 907 return CallRuntimeForPair(function_id, RegisterList(arg.index(), 1), 908 return_pair); 909 } 910 911 BytecodeArrayBuilder& BytecodeArrayBuilder::CallJSRuntime(int context_index, 912 RegisterList args) { 913 OutputCallJSRuntime(context_index, args, args.register_count()); 914 return *this; 915 } 916 917 BytecodeArrayBuilder& BytecodeArrayBuilder::Delete(Register object, 918 LanguageMode language_mode) { 919 if (language_mode == SLOPPY) { 920 OutputDeletePropertySloppy(object); 921 } else { 922 DCHECK_EQ(language_mode, STRICT); 923 OutputDeletePropertyStrict(object); 924 } 925 return *this; 926 } 927 928 size_t BytecodeArrayBuilder::GetConstantPoolEntry(Handle<Object> object) { 929 return constant_array_builder()->Insert(object); 930 } 931 932 size_t BytecodeArrayBuilder::AllocateConstantPoolEntry() { 933 return constant_array_builder()->AllocateEntry(); 934 } 935 936 void BytecodeArrayBuilder::InsertConstantPoolEntryAt(size_t entry, 937 Handle<Object> object) { 938 constant_array_builder()->InsertAllocatedEntry(entry, object); 939 } 940 941 void BytecodeArrayBuilder::SetReturnPosition() { 942 if (return_position_ == kNoSourcePosition) return; 943 latest_source_info_.MakeStatementPosition(return_position_); 944 } 945 946 bool BytecodeArrayBuilder::RegisterIsValid(Register reg) const { 947 if (!reg.is_valid()) { 948 return false; 949 } 950 951 if (reg.is_current_context() || reg.is_function_closure() || 952 reg.is_new_target()) { 953 return true; 954 } else if (reg.is_parameter()) { 955 int parameter_index = reg.ToParameterIndex(parameter_count()); 956 return parameter_index >= 0 && parameter_index < parameter_count(); 957 } else if (reg.index() < fixed_register_count()) { 958 return true; 959 } else { 960 return register_allocator()->RegisterIsLive(reg); 961 } 962 } 963 964 bool BytecodeArrayBuilder::RegisterListIsValid(RegisterList reg_list) const { 965 if (reg_list.register_count() == 0) { 966 return reg_list.first_register() == Register(0); 967 } else { 968 int first_reg_index = reg_list.first_register().index(); 969 for (int i = 0; i < reg_list.register_count(); i++) { 970 if (!RegisterIsValid(Register(first_reg_index + i))) { 971 return false; 972 } 973 } 974 return true; 975 } 976 } 977 978 void BytecodeArrayBuilder::PrepareToOutputBytecode(Bytecode bytecode) { 979 if (register_optimizer_) register_optimizer_->PrepareForBytecode(bytecode); 980 } 981 982 uint32_t BytecodeArrayBuilder::GetInputRegisterOperand(Register reg) { 983 DCHECK(RegisterIsValid(reg)); 984 if (register_optimizer_) reg = register_optimizer_->GetInputRegister(reg); 985 return static_cast<uint32_t>(reg.ToOperand()); 986 } 987 988 uint32_t BytecodeArrayBuilder::GetOutputRegisterOperand(Register reg) { 989 DCHECK(RegisterIsValid(reg)); 990 if (register_optimizer_) register_optimizer_->PrepareOutputRegister(reg); 991 return static_cast<uint32_t>(reg.ToOperand()); 992 } 993 994 uint32_t BytecodeArrayBuilder::GetInputRegisterListOperand( 995 RegisterList reg_list) { 996 DCHECK(RegisterListIsValid(reg_list)); 997 if (register_optimizer_) 998 reg_list = register_optimizer_->GetInputRegisterList(reg_list); 999 return static_cast<uint32_t>(reg_list.first_register().ToOperand()); 1000 } 1001 1002 uint32_t BytecodeArrayBuilder::GetOutputRegisterListOperand( 1003 RegisterList reg_list) { 1004 DCHECK(RegisterListIsValid(reg_list)); 1005 if (register_optimizer_) 1006 register_optimizer_->PrepareOutputRegisterList(reg_list); 1007 return static_cast<uint32_t>(reg_list.first_register().ToOperand()); 1008 } 1009 1010 } // namespace interpreter 1011 } // namespace internal 1012 } // namespace v8 1013