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-jump-table.h" 10 #include "src/interpreter/bytecode-label.h" 11 #include "src/interpreter/bytecode-node.h" 12 #include "src/interpreter/bytecode-register-optimizer.h" 13 #include "src/interpreter/bytecode-source-info.h" 14 #include "src/interpreter/interpreter-intrinsics.h" 15 #include "src/objects-inl.h" 16 17 namespace v8 { 18 namespace internal { 19 namespace interpreter { 20 21 class RegisterTransferWriter final 22 : public NON_EXPORTED_BASE(BytecodeRegisterOptimizer::BytecodeWriter), 23 public NON_EXPORTED_BASE(ZoneObject) { 24 public: 25 RegisterTransferWriter(BytecodeArrayBuilder* builder) : builder_(builder) {} 26 ~RegisterTransferWriter() override {} 27 28 void EmitLdar(Register input) override { builder_->OutputLdarRaw(input); } 29 30 void EmitStar(Register output) override { builder_->OutputStarRaw(output); } 31 32 void EmitMov(Register input, Register output) override { 33 builder_->OutputMovRaw(input, output); 34 } 35 36 private: 37 BytecodeArrayBuilder* builder_; 38 }; 39 40 BytecodeArrayBuilder::BytecodeArrayBuilder( 41 Zone* zone, int parameter_count, int locals_count, 42 FeedbackVectorSpec* feedback_vector_spec, 43 SourcePositionTableBuilder::RecordingMode source_position_mode) 44 : zone_(zone), 45 feedback_vector_spec_(feedback_vector_spec), 46 bytecode_generated_(false), 47 constant_array_builder_(zone), 48 handler_table_builder_(zone), 49 return_seen_in_block_(false), 50 parameter_count_(parameter_count), 51 local_register_count_(locals_count), 52 register_allocator_(fixed_register_count()), 53 bytecode_array_writer_(zone, &constant_array_builder_, 54 source_position_mode), 55 register_optimizer_(nullptr) { 56 DCHECK_GE(parameter_count_, 0); 57 DCHECK_GE(local_register_count_, 0); 58 59 if (FLAG_ignition_reo) { 60 register_optimizer_ = new (zone) BytecodeRegisterOptimizer( 61 zone, ®ister_allocator_, fixed_register_count(), parameter_count, 62 new (zone) RegisterTransferWriter(this)); 63 } 64 } 65 66 Register BytecodeArrayBuilder::Parameter(int parameter_index) const { 67 DCHECK_GE(parameter_index, 0); 68 // The parameter indices are shifted by 1 (receiver is the 69 // first entry). 70 return Register::FromParameterIndex(parameter_index + 1, parameter_count()); 71 } 72 73 Register BytecodeArrayBuilder::Receiver() const { 74 return Register::FromParameterIndex(0, parameter_count()); 75 } 76 77 Register BytecodeArrayBuilder::Local(int index) const { 78 // TODO(marja): Make a DCHECK once crbug.com/706234 is fixed. 79 CHECK_LT(index, locals_count()); 80 return Register(index); 81 } 82 83 Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray(Isolate* isolate) { 84 DCHECK(return_seen_in_block_); 85 DCHECK(!bytecode_generated_); 86 bytecode_generated_ = true; 87 88 int register_count = total_register_count(); 89 90 if (register_optimizer_) { 91 register_optimizer_->Flush(); 92 register_count = register_optimizer_->maxiumum_register_index() + 1; 93 } 94 95 Handle<ByteArray> handler_table = 96 handler_table_builder()->ToHandlerTable(isolate); 97 return bytecode_array_writer_.ToBytecodeArray( 98 isolate, register_count, parameter_count(), handler_table); 99 } 100 101 BytecodeSourceInfo BytecodeArrayBuilder::CurrentSourcePosition( 102 Bytecode bytecode) { 103 BytecodeSourceInfo source_position; 104 if (latest_source_info_.is_valid()) { 105 // Statement positions need to be emitted immediately. Expression 106 // positions can be pushed back until a bytecode is found that can 107 // throw (if expression position filtering is turned on). We only 108 // invalidate the existing source position information if it is used. 109 if (latest_source_info_.is_statement() || 110 !FLAG_ignition_filter_expression_positions || 111 !Bytecodes::IsWithoutExternalSideEffects(bytecode)) { 112 source_position = latest_source_info_; 113 latest_source_info_.set_invalid(); 114 } 115 } 116 return source_position; 117 } 118 119 void BytecodeArrayBuilder::SetDeferredSourceInfo( 120 BytecodeSourceInfo source_info) { 121 if (!source_info.is_valid()) return; 122 deferred_source_info_ = source_info; 123 } 124 125 void BytecodeArrayBuilder::AttachOrEmitDeferredSourceInfo(BytecodeNode* node) { 126 if (!deferred_source_info_.is_valid()) return; 127 if (!node->source_info().is_valid()) { 128 node->set_source_info(deferred_source_info_); 129 } else if (deferred_source_info_.is_statement() && 130 node->source_info().is_expression()) { 131 BytecodeSourceInfo source_position = node->source_info(); 132 source_position.MakeStatementPosition(source_position.source_position()); 133 node->set_source_info(source_position); 134 } 135 deferred_source_info_.set_invalid(); 136 } 137 138 void BytecodeArrayBuilder::Write(BytecodeNode* node) { 139 AttachOrEmitDeferredSourceInfo(node); 140 bytecode_array_writer_.Write(node); 141 } 142 143 void BytecodeArrayBuilder::WriteJump(BytecodeNode* node, BytecodeLabel* label) { 144 AttachOrEmitDeferredSourceInfo(node); 145 bytecode_array_writer_.WriteJump(node, label); 146 } 147 148 void BytecodeArrayBuilder::WriteSwitch(BytecodeNode* node, 149 BytecodeJumpTable* jump_table) { 150 AttachOrEmitDeferredSourceInfo(node); 151 bytecode_array_writer_.WriteSwitch(node, jump_table); 152 } 153 154 void BytecodeArrayBuilder::OutputLdarRaw(Register reg) { 155 uint32_t operand = static_cast<uint32_t>(reg.ToOperand()); 156 BytecodeNode node(BytecodeNode::Ldar(BytecodeSourceInfo(), operand)); 157 Write(&node); 158 } 159 160 void BytecodeArrayBuilder::OutputStarRaw(Register reg) { 161 uint32_t operand = static_cast<uint32_t>(reg.ToOperand()); 162 BytecodeNode node(BytecodeNode::Star(BytecodeSourceInfo(), operand)); 163 Write(&node); 164 } 165 166 void BytecodeArrayBuilder::OutputMovRaw(Register src, Register dest) { 167 uint32_t operand0 = static_cast<uint32_t>(src.ToOperand()); 168 uint32_t operand1 = static_cast<uint32_t>(dest.ToOperand()); 169 BytecodeNode node( 170 BytecodeNode::Mov(BytecodeSourceInfo(), operand0, operand1)); 171 Write(&node); 172 } 173 174 namespace { 175 176 template <OperandTypeInfo type_info> 177 class UnsignedOperandHelper { 178 public: 179 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder, 180 size_t value) { 181 DCHECK(IsValid(value)); 182 return static_cast<uint32_t>(value); 183 } 184 185 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder, int value) { 186 DCHECK_GE(value, 0); 187 return Convert(builder, static_cast<size_t>(value)); 188 } 189 190 private: 191 static bool IsValid(size_t value) { 192 switch (type_info) { 193 case OperandTypeInfo::kFixedUnsignedByte: 194 return value <= kMaxUInt8; 195 case OperandTypeInfo::kFixedUnsignedShort: 196 return value <= kMaxUInt16; 197 case OperandTypeInfo::kScalableUnsignedByte: 198 return value <= kMaxUInt32; 199 default: 200 UNREACHABLE(); 201 } 202 } 203 }; 204 205 template <OperandType> 206 class OperandHelper {}; 207 208 #define DEFINE_UNSIGNED_OPERAND_HELPER(Name, Type) \ 209 template <> \ 210 class OperandHelper<OperandType::k##Name> \ 211 : public UnsignedOperandHelper<Type> {}; 212 UNSIGNED_FIXED_SCALAR_OPERAND_TYPE_LIST(DEFINE_UNSIGNED_OPERAND_HELPER) 213 UNSIGNED_SCALABLE_SCALAR_OPERAND_TYPE_LIST(DEFINE_UNSIGNED_OPERAND_HELPER) 214 #undef DEFINE_UNSIGNED_OPERAND_HELPER 215 216 template <> 217 class OperandHelper<OperandType::kImm> { 218 public: 219 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder, int value) { 220 return static_cast<uint32_t>(value); 221 } 222 }; 223 224 template <> 225 class OperandHelper<OperandType::kReg> { 226 public: 227 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder, 228 Register reg) { 229 return builder->GetInputRegisterOperand(reg); 230 } 231 }; 232 233 template <> 234 class OperandHelper<OperandType::kRegList> { 235 public: 236 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder, 237 RegisterList reg_list) { 238 return builder->GetInputRegisterListOperand(reg_list); 239 } 240 }; 241 242 template <> 243 class OperandHelper<OperandType::kRegPair> { 244 public: 245 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder, 246 RegisterList reg_list) { 247 DCHECK_EQ(reg_list.register_count(), 2); 248 return builder->GetInputRegisterListOperand(reg_list); 249 } 250 }; 251 252 template <> 253 class OperandHelper<OperandType::kRegOut> { 254 public: 255 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder, 256 Register reg) { 257 return builder->GetOutputRegisterOperand(reg); 258 } 259 }; 260 261 template <> 262 class OperandHelper<OperandType::kRegOutList> { 263 public: 264 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder, 265 RegisterList reg_list) { 266 return builder->GetOutputRegisterListOperand(reg_list); 267 } 268 }; 269 270 template <> 271 class OperandHelper<OperandType::kRegOutPair> { 272 public: 273 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder, 274 RegisterList reg_list) { 275 DCHECK_EQ(2, reg_list.register_count()); 276 return builder->GetOutputRegisterListOperand(reg_list); 277 } 278 }; 279 280 template <> 281 class OperandHelper<OperandType::kRegOutTriple> { 282 public: 283 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder, 284 RegisterList reg_list) { 285 DCHECK_EQ(3, reg_list.register_count()); 286 return builder->GetOutputRegisterListOperand(reg_list); 287 } 288 }; 289 290 } // namespace 291 292 template <Bytecode bytecode, AccumulatorUse accumulator_use, 293 OperandType... operand_types> 294 class BytecodeNodeBuilder { 295 public: 296 template <typename... Operands> 297 V8_INLINE static BytecodeNode Make(BytecodeArrayBuilder* builder, 298 Operands... operands) { 299 static_assert(sizeof...(Operands) <= Bytecodes::kMaxOperands, 300 "too many operands for bytecode"); 301 builder->PrepareToOutputBytecode<bytecode, accumulator_use>(); 302 // The "OperandHelper<operand_types>::Convert(builder, operands)..." will 303 // expand both the OperandType... and Operands... parameter packs e.g. for: 304 // BytecodeNodeBuilder<OperandType::kReg, OperandType::kImm>::Make< 305 // Register, int>(..., Register reg, int immediate) 306 // the code will expand into: 307 // OperandHelper<OperandType::kReg>::Convert(builder, reg), 308 // OperandHelper<OperandType::kImm>::Convert(builder, immediate), 309 return BytecodeNode::Create<bytecode, accumulator_use, operand_types...>( 310 builder->CurrentSourcePosition(bytecode), 311 OperandHelper<operand_types>::Convert(builder, operands)...); 312 } 313 }; 314 315 #define DEFINE_BYTECODE_OUTPUT(name, ...) \ 316 template <typename... Operands> \ 317 BytecodeNode BytecodeArrayBuilder::Create##name##Node( \ 318 Operands... operands) { \ 319 return BytecodeNodeBuilder<Bytecode::k##name, __VA_ARGS__>::Make( \ 320 this, operands...); \ 321 } \ 322 \ 323 template <typename... Operands> \ 324 void BytecodeArrayBuilder::Output##name(Operands... operands) { \ 325 BytecodeNode node(Create##name##Node(operands...)); \ 326 Write(&node); \ 327 } \ 328 \ 329 template <typename... Operands> \ 330 void BytecodeArrayBuilder::Output##name(BytecodeLabel* label, \ 331 Operands... operands) { \ 332 DCHECK(Bytecodes::IsJump(Bytecode::k##name)); \ 333 BytecodeNode node(Create##name##Node(operands...)); \ 334 WriteJump(&node, label); \ 335 LeaveBasicBlock(); \ 336 } 337 BYTECODE_LIST(DEFINE_BYTECODE_OUTPUT) 338 #undef DEFINE_BYTECODE_OUTPUT 339 340 void BytecodeArrayBuilder::OutputSwitchOnSmiNoFeedback( 341 BytecodeJumpTable* jump_table) { 342 BytecodeNode node(CreateSwitchOnSmiNoFeedbackNode( 343 jump_table->constant_pool_index(), jump_table->size(), 344 jump_table->case_value_base())); 345 WriteSwitch(&node, jump_table); 346 LeaveBasicBlock(); 347 } 348 349 BytecodeArrayBuilder& BytecodeArrayBuilder::BinaryOperation(Token::Value op, 350 Register reg, 351 int feedback_slot) { 352 switch (op) { 353 case Token::Value::ADD: 354 OutputAdd(reg, feedback_slot); 355 break; 356 case Token::Value::SUB: 357 OutputSub(reg, feedback_slot); 358 break; 359 case Token::Value::MUL: 360 OutputMul(reg, feedback_slot); 361 break; 362 case Token::Value::DIV: 363 OutputDiv(reg, feedback_slot); 364 break; 365 case Token::Value::MOD: 366 OutputMod(reg, feedback_slot); 367 break; 368 case Token::Value::EXP: 369 OutputExp(reg, feedback_slot); 370 break; 371 case Token::Value::BIT_OR: 372 OutputBitwiseOr(reg, feedback_slot); 373 break; 374 case Token::Value::BIT_XOR: 375 OutputBitwiseXor(reg, feedback_slot); 376 break; 377 case Token::Value::BIT_AND: 378 OutputBitwiseAnd(reg, feedback_slot); 379 break; 380 case Token::Value::SHL: 381 OutputShiftLeft(reg, feedback_slot); 382 break; 383 case Token::Value::SAR: 384 OutputShiftRight(reg, feedback_slot); 385 break; 386 case Token::Value::SHR: 387 OutputShiftRightLogical(reg, feedback_slot); 388 break; 389 default: 390 UNREACHABLE(); 391 } 392 return *this; 393 } 394 395 BytecodeArrayBuilder& BytecodeArrayBuilder::BinaryOperationSmiLiteral( 396 Token::Value op, Smi* literal, int feedback_slot) { 397 switch (op) { 398 case Token::Value::ADD: 399 OutputAddSmi(literal->value(), feedback_slot); 400 break; 401 case Token::Value::SUB: 402 OutputSubSmi(literal->value(), feedback_slot); 403 break; 404 case Token::Value::MUL: 405 OutputMulSmi(literal->value(), feedback_slot); 406 break; 407 case Token::Value::DIV: 408 OutputDivSmi(literal->value(), feedback_slot); 409 break; 410 case Token::Value::MOD: 411 OutputModSmi(literal->value(), feedback_slot); 412 break; 413 case Token::Value::EXP: 414 OutputExpSmi(literal->value(), feedback_slot); 415 break; 416 case Token::Value::BIT_OR: 417 OutputBitwiseOrSmi(literal->value(), feedback_slot); 418 break; 419 case Token::Value::BIT_XOR: 420 OutputBitwiseXorSmi(literal->value(), feedback_slot); 421 break; 422 case Token::Value::BIT_AND: 423 OutputBitwiseAndSmi(literal->value(), feedback_slot); 424 break; 425 case Token::Value::SHL: 426 OutputShiftLeftSmi(literal->value(), feedback_slot); 427 break; 428 case Token::Value::SAR: 429 OutputShiftRightSmi(literal->value(), feedback_slot); 430 break; 431 case Token::Value::SHR: 432 OutputShiftRightLogicalSmi(literal->value(), feedback_slot); 433 break; 434 default: 435 UNREACHABLE(); 436 } 437 return *this; 438 } 439 440 BytecodeArrayBuilder& BytecodeArrayBuilder::UnaryOperation(Token::Value op, 441 int feedback_slot) { 442 switch (op) { 443 case Token::Value::INC: 444 OutputInc(feedback_slot); 445 break; 446 case Token::Value::DEC: 447 OutputDec(feedback_slot); 448 break; 449 case Token::Value::ADD: 450 OutputToNumber(feedback_slot); 451 break; 452 case Token::Value::SUB: 453 OutputNegate(feedback_slot); 454 break; 455 case Token::Value::BIT_NOT: 456 OutputBitwiseNot(feedback_slot); 457 break; 458 default: 459 UNREACHABLE(); 460 } 461 return *this; 462 } 463 464 BytecodeArrayBuilder& BytecodeArrayBuilder::LogicalNot(ToBooleanMode mode) { 465 if (mode == ToBooleanMode::kAlreadyBoolean) { 466 OutputLogicalNot(); 467 } else { 468 DCHECK_EQ(mode, ToBooleanMode::kConvertToBoolean); 469 OutputToBooleanLogicalNot(); 470 } 471 return *this; 472 } 473 474 BytecodeArrayBuilder& BytecodeArrayBuilder::TypeOf() { 475 OutputTypeOf(); 476 return *this; 477 } 478 479 BytecodeArrayBuilder& BytecodeArrayBuilder::GetSuperConstructor(Register out) { 480 OutputGetSuperConstructor(out); 481 return *this; 482 } 483 484 BytecodeArrayBuilder& BytecodeArrayBuilder::CompareOperation( 485 Token::Value op, Register reg, int feedback_slot) { 486 switch (op) { 487 case Token::Value::EQ: 488 OutputTestEqual(reg, feedback_slot); 489 break; 490 case Token::Value::EQ_STRICT: 491 OutputTestEqualStrict(reg, feedback_slot); 492 break; 493 case Token::Value::LT: 494 OutputTestLessThan(reg, feedback_slot); 495 break; 496 case Token::Value::GT: 497 OutputTestGreaterThan(reg, feedback_slot); 498 break; 499 case Token::Value::LTE: 500 OutputTestLessThanOrEqual(reg, feedback_slot); 501 break; 502 case Token::Value::GTE: 503 OutputTestGreaterThanOrEqual(reg, feedback_slot); 504 break; 505 case Token::Value::INSTANCEOF: 506 OutputTestInstanceOf(reg, feedback_slot); 507 break; 508 default: 509 UNREACHABLE(); 510 } 511 return *this; 512 } 513 514 BytecodeArrayBuilder& BytecodeArrayBuilder::CompareOperation(Token::Value op, 515 Register reg) { 516 switch (op) { 517 case Token::Value::IN: 518 OutputTestIn(reg); 519 break; 520 default: 521 UNREACHABLE(); 522 } 523 return *this; 524 } 525 526 BytecodeArrayBuilder& BytecodeArrayBuilder::CompareReference(Register reg) { 527 OutputTestReferenceEqual(reg); 528 return *this; 529 } 530 531 BytecodeArrayBuilder& BytecodeArrayBuilder::CompareUndetectable() { 532 OutputTestUndetectable(); 533 return *this; 534 } 535 536 BytecodeArrayBuilder& BytecodeArrayBuilder::CompareUndefined() { 537 OutputTestUndefined(); 538 return *this; 539 } 540 541 BytecodeArrayBuilder& BytecodeArrayBuilder::CompareNull() { 542 OutputTestNull(); 543 return *this; 544 } 545 546 BytecodeArrayBuilder& BytecodeArrayBuilder::CompareNil(Token::Value op, 547 NilValue nil) { 548 if (op == Token::EQ) { 549 return CompareUndetectable(); 550 } else { 551 DCHECK_EQ(Token::EQ_STRICT, op); 552 if (nil == kUndefinedValue) { 553 return CompareUndefined(); 554 } else { 555 DCHECK_EQ(kNullValue, nil); 556 return CompareNull(); 557 } 558 } 559 } 560 561 BytecodeArrayBuilder& BytecodeArrayBuilder::CompareTypeOf( 562 TestTypeOfFlags::LiteralFlag literal_flag) { 563 DCHECK_NE(literal_flag, TestTypeOfFlags::LiteralFlag::kOther); 564 OutputTestTypeOf(TestTypeOfFlags::Encode(literal_flag)); 565 return *this; 566 } 567 568 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadConstantPoolEntry( 569 size_t entry) { 570 OutputLdaConstant(entry); 571 return *this; 572 } 573 574 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral( 575 v8::internal::Smi* smi) { 576 int32_t raw_smi = smi->value(); 577 if (raw_smi == 0) { 578 OutputLdaZero(); 579 } else { 580 OutputLdaSmi(raw_smi); 581 } 582 return *this; 583 } 584 585 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(double value) { 586 size_t entry = GetConstantPoolEntry(value); 587 OutputLdaConstant(entry); 588 return *this; 589 } 590 591 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral( 592 const AstRawString* raw_string) { 593 size_t entry = GetConstantPoolEntry(raw_string); 594 OutputLdaConstant(entry); 595 return *this; 596 } 597 598 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(const Scope* scope) { 599 size_t entry = GetConstantPoolEntry(scope); 600 OutputLdaConstant(entry); 601 return *this; 602 } 603 604 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(AstBigInt bigint) { 605 size_t entry = GetConstantPoolEntry(bigint); 606 OutputLdaConstant(entry); 607 return *this; 608 } 609 610 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(AstSymbol symbol) { 611 size_t entry; 612 switch (symbol) { 613 case AstSymbol::kHomeObjectSymbol: 614 entry = HomeObjectSymbolConstantPoolEntry(); 615 break; 616 // No default case so that we get a warning if AstSymbol changes 617 } 618 OutputLdaConstant(entry); 619 return *this; 620 } 621 622 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadUndefined() { 623 OutputLdaUndefined(); 624 return *this; 625 } 626 627 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNull() { 628 OutputLdaNull(); 629 return *this; 630 } 631 632 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadTheHole() { 633 OutputLdaTheHole(); 634 return *this; 635 } 636 637 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadTrue() { 638 OutputLdaTrue(); 639 return *this; 640 } 641 642 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadFalse() { 643 OutputLdaFalse(); 644 return *this; 645 } 646 647 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadBoolean(bool value) { 648 return value ? LoadTrue() : LoadFalse(); 649 } 650 651 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadAccumulatorWithRegister( 652 Register reg) { 653 if (register_optimizer_) { 654 // Defer source info so that if we elide the bytecode transfer, we attach 655 // the source info to a subsequent bytecode if it exists. 656 SetDeferredSourceInfo(CurrentSourcePosition(Bytecode::kLdar)); 657 register_optimizer_->DoLdar(reg); 658 } else { 659 OutputLdar(reg); 660 } 661 return *this; 662 } 663 664 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreAccumulatorInRegister( 665 Register reg) { 666 if (register_optimizer_) { 667 // Defer source info so that if we elide the bytecode transfer, we attach 668 // the source info to a subsequent bytecode if it exists. 669 SetDeferredSourceInfo(CurrentSourcePosition(Bytecode::kStar)); 670 register_optimizer_->DoStar(reg); 671 } else { 672 OutputStar(reg); 673 } 674 return *this; 675 } 676 677 BytecodeArrayBuilder& BytecodeArrayBuilder::MoveRegister(Register from, 678 Register to) { 679 DCHECK(from != to); 680 if (register_optimizer_) { 681 // Defer source info so that if we elide the bytecode transfer, we attach 682 // the source info to a subsequent bytecode if it exists. 683 SetDeferredSourceInfo(CurrentSourcePosition(Bytecode::kMov)); 684 register_optimizer_->DoMov(from, to); 685 } else { 686 OutputMov(from, to); 687 } 688 return *this; 689 } 690 691 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadGlobal(const AstRawString* name, 692 int feedback_slot, 693 TypeofMode typeof_mode) { 694 size_t name_index = GetConstantPoolEntry(name); 695 // Ensure that typeof mode is in sync with the IC slot kind. 696 DCHECK_EQ(GetTypeofModeFromSlotKind(feedback_vector_spec()->GetKind( 697 FeedbackVector::ToSlot(feedback_slot))), 698 typeof_mode); 699 if (typeof_mode == INSIDE_TYPEOF) { 700 OutputLdaGlobalInsideTypeof(name_index, feedback_slot); 701 } else { 702 DCHECK_EQ(typeof_mode, NOT_INSIDE_TYPEOF); 703 OutputLdaGlobal(name_index, feedback_slot); 704 } 705 return *this; 706 } 707 708 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreGlobal( 709 const AstRawString* name, int feedback_slot) { 710 size_t name_index = GetConstantPoolEntry(name); 711 OutputStaGlobal(name_index, feedback_slot); 712 return *this; 713 } 714 715 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadContextSlot( 716 Register context, int slot_index, int depth, 717 ContextSlotMutability mutability) { 718 if (context.is_current_context() && depth == 0) { 719 if (mutability == kImmutableSlot) { 720 OutputLdaImmutableCurrentContextSlot(slot_index); 721 } else { 722 DCHECK_EQ(kMutableSlot, mutability); 723 OutputLdaCurrentContextSlot(slot_index); 724 } 725 } else if (mutability == kImmutableSlot) { 726 OutputLdaImmutableContextSlot(context, slot_index, depth); 727 } else { 728 DCHECK_EQ(mutability, kMutableSlot); 729 OutputLdaContextSlot(context, slot_index, depth); 730 } 731 return *this; 732 } 733 734 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreContextSlot(Register context, 735 int slot_index, 736 int depth) { 737 if (context.is_current_context() && depth == 0) { 738 OutputStaCurrentContextSlot(slot_index); 739 } else { 740 OutputStaContextSlot(context, slot_index, depth); 741 } 742 return *this; 743 } 744 745 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupSlot( 746 const AstRawString* name, TypeofMode typeof_mode) { 747 size_t name_index = GetConstantPoolEntry(name); 748 if (typeof_mode == INSIDE_TYPEOF) { 749 OutputLdaLookupSlotInsideTypeof(name_index); 750 } else { 751 DCHECK_EQ(typeof_mode, NOT_INSIDE_TYPEOF); 752 OutputLdaLookupSlot(name_index); 753 } 754 return *this; 755 } 756 757 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupContextSlot( 758 const AstRawString* name, TypeofMode typeof_mode, int slot_index, 759 int depth) { 760 size_t name_index = GetConstantPoolEntry(name); 761 if (typeof_mode == INSIDE_TYPEOF) { 762 OutputLdaLookupContextSlotInsideTypeof(name_index, slot_index, depth); 763 } else { 764 DCHECK(typeof_mode == NOT_INSIDE_TYPEOF); 765 OutputLdaLookupContextSlot(name_index, slot_index, depth); 766 } 767 return *this; 768 } 769 770 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupGlobalSlot( 771 const AstRawString* name, TypeofMode typeof_mode, int feedback_slot, 772 int depth) { 773 size_t name_index = GetConstantPoolEntry(name); 774 if (typeof_mode == INSIDE_TYPEOF) { 775 OutputLdaLookupGlobalSlotInsideTypeof(name_index, feedback_slot, depth); 776 } else { 777 DCHECK(typeof_mode == NOT_INSIDE_TYPEOF); 778 OutputLdaLookupGlobalSlot(name_index, feedback_slot, depth); 779 } 780 return *this; 781 } 782 783 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreLookupSlot( 784 const AstRawString* name, LanguageMode language_mode, 785 LookupHoistingMode lookup_hoisting_mode) { 786 size_t name_index = GetConstantPoolEntry(name); 787 uint8_t flags = 788 StoreLookupSlotFlags::Encode(language_mode, lookup_hoisting_mode); 789 OutputStaLookupSlot(name_index, flags); 790 return *this; 791 } 792 793 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNamedProperty( 794 Register object, const AstRawString* name, int feedback_slot) { 795 size_t name_index = GetConstantPoolEntry(name); 796 OutputLdaNamedProperty(object, name_index, feedback_slot); 797 return *this; 798 } 799 800 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadKeyedProperty( 801 Register object, int feedback_slot) { 802 OutputLdaKeyedProperty(object, feedback_slot); 803 return *this; 804 } 805 806 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadIteratorProperty( 807 Register object, int feedback_slot) { 808 size_t name_index = IteratorSymbolConstantPoolEntry(); 809 OutputLdaNamedProperty(object, name_index, feedback_slot); 810 return *this; 811 } 812 813 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadAsyncIteratorProperty( 814 Register object, int feedback_slot) { 815 size_t name_index = AsyncIteratorSymbolConstantPoolEntry(); 816 OutputLdaNamedProperty(object, name_index, feedback_slot); 817 return *this; 818 } 819 820 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreDataPropertyInLiteral( 821 Register object, Register name, DataPropertyInLiteralFlags flags, 822 int feedback_slot) { 823 OutputStaDataPropertyInLiteral(object, name, flags, feedback_slot); 824 return *this; 825 } 826 827 BytecodeArrayBuilder& BytecodeArrayBuilder::CollectTypeProfile(int position) { 828 OutputCollectTypeProfile(position); 829 return *this; 830 } 831 832 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreNamedProperty( 833 Register object, size_t name_index, int feedback_slot, 834 LanguageMode language_mode) { 835 // Ensure that language mode is in sync with the IC slot kind. 836 DCHECK_EQ(GetLanguageModeFromSlotKind(feedback_vector_spec()->GetKind( 837 FeedbackVector::ToSlot(feedback_slot))), 838 language_mode); 839 OutputStaNamedProperty(object, name_index, feedback_slot); 840 return *this; 841 } 842 843 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreNamedProperty( 844 Register object, const AstRawString* name, int feedback_slot, 845 LanguageMode language_mode) { 846 size_t name_index = GetConstantPoolEntry(name); 847 return StoreNamedProperty(object, name_index, feedback_slot, language_mode); 848 } 849 850 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreNamedOwnProperty( 851 Register object, const AstRawString* name, int feedback_slot) { 852 size_t name_index = GetConstantPoolEntry(name); 853 // Ensure that the store operation is in sync with the IC slot kind. 854 DCHECK_EQ( 855 FeedbackSlotKind::kStoreOwnNamed, 856 feedback_vector_spec()->GetKind(FeedbackVector::ToSlot(feedback_slot))); 857 OutputStaNamedOwnProperty(object, name_index, feedback_slot); 858 return *this; 859 } 860 861 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreKeyedProperty( 862 Register object, Register key, int feedback_slot, 863 LanguageMode language_mode) { 864 // Ensure that language mode is in sync with the IC slot kind. 865 DCHECK_EQ(GetLanguageModeFromSlotKind(feedback_vector_spec()->GetKind( 866 FeedbackVector::ToSlot(feedback_slot))), 867 language_mode); 868 OutputStaKeyedProperty(object, key, feedback_slot); 869 return *this; 870 } 871 872 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreInArrayLiteral( 873 Register array, Register index, int feedback_slot) { 874 OutputStaInArrayLiteral(array, index, feedback_slot); 875 return *this; 876 } 877 878 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreHomeObjectProperty( 879 Register object, int feedback_slot, LanguageMode language_mode) { 880 size_t name_index = HomeObjectSymbolConstantPoolEntry(); 881 return StoreNamedProperty(object, name_index, feedback_slot, language_mode); 882 } 883 884 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreClassFieldsInitializer( 885 Register constructor, int feedback_slot) { 886 size_t name_index = ClassFieldsSymbolConstantPoolEntry(); 887 return StoreNamedProperty(constructor, name_index, feedback_slot, 888 LanguageMode::kStrict); 889 } 890 891 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadClassFieldsInitializer( 892 Register constructor, int feedback_slot) { 893 size_t name_index = ClassFieldsSymbolConstantPoolEntry(); 894 OutputLdaNamedProperty(constructor, name_index, feedback_slot); 895 return *this; 896 } 897 898 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateClosure( 899 size_t shared_function_info_entry, int slot, int flags) { 900 OutputCreateClosure(shared_function_info_entry, slot, flags); 901 return *this; 902 } 903 904 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateBlockContext( 905 const Scope* scope) { 906 size_t entry = GetConstantPoolEntry(scope); 907 OutputCreateBlockContext(entry); 908 return *this; 909 } 910 911 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateCatchContext( 912 Register exception, const Scope* scope) { 913 size_t scope_index = GetConstantPoolEntry(scope); 914 OutputCreateCatchContext(exception, scope_index); 915 return *this; 916 } 917 918 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateFunctionContext( 919 const Scope* scope, int slots) { 920 size_t scope_index = GetConstantPoolEntry(scope); 921 OutputCreateFunctionContext(scope_index, slots); 922 return *this; 923 } 924 925 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateEvalContext( 926 const Scope* scope, int slots) { 927 size_t scope_index = GetConstantPoolEntry(scope); 928 OutputCreateEvalContext(scope_index, slots); 929 return *this; 930 } 931 932 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateWithContext( 933 Register object, const Scope* scope) { 934 size_t scope_index = GetConstantPoolEntry(scope); 935 OutputCreateWithContext(object, scope_index); 936 return *this; 937 } 938 939 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArguments( 940 CreateArgumentsType type) { 941 switch (type) { 942 case CreateArgumentsType::kMappedArguments: 943 OutputCreateMappedArguments(); 944 break; 945 case CreateArgumentsType::kUnmappedArguments: 946 OutputCreateUnmappedArguments(); 947 break; 948 case CreateArgumentsType::kRestParameter: 949 OutputCreateRestParameter(); 950 break; 951 default: 952 UNREACHABLE(); 953 } 954 return *this; 955 } 956 957 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateRegExpLiteral( 958 const AstRawString* pattern, int literal_index, int flags) { 959 size_t pattern_entry = GetConstantPoolEntry(pattern); 960 OutputCreateRegExpLiteral(pattern_entry, literal_index, flags); 961 return *this; 962 } 963 964 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateEmptyArrayLiteral( 965 int literal_index) { 966 OutputCreateEmptyArrayLiteral(literal_index); 967 return *this; 968 } 969 970 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArrayLiteral( 971 size_t constant_elements_entry, int literal_index, int flags) { 972 OutputCreateArrayLiteral(constant_elements_entry, literal_index, flags); 973 return *this; 974 } 975 976 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateObjectLiteral( 977 size_t constant_properties_entry, int literal_index, int flags, 978 Register output) { 979 OutputCreateObjectLiteral(constant_properties_entry, literal_index, flags, 980 output); 981 return *this; 982 } 983 984 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateEmptyObjectLiteral() { 985 OutputCreateEmptyObjectLiteral(); 986 return *this; 987 } 988 989 BytecodeArrayBuilder& BytecodeArrayBuilder::CloneObject(Register source, 990 int flags, 991 int feedback_slot) { 992 OutputCloneObject(source, flags, feedback_slot); 993 return *this; 994 } 995 996 BytecodeArrayBuilder& BytecodeArrayBuilder::GetTemplateObject( 997 size_t template_object_description_entry, int feedback_slot) { 998 OutputGetTemplateObject(template_object_description_entry, feedback_slot); 999 return *this; 1000 } 1001 1002 BytecodeArrayBuilder& BytecodeArrayBuilder::PushContext(Register context) { 1003 OutputPushContext(context); 1004 return *this; 1005 } 1006 1007 BytecodeArrayBuilder& BytecodeArrayBuilder::PopContext(Register context) { 1008 OutputPopContext(context); 1009 return *this; 1010 } 1011 1012 BytecodeArrayBuilder& BytecodeArrayBuilder::ToObject(Register out) { 1013 OutputToObject(out); 1014 return *this; 1015 } 1016 1017 BytecodeArrayBuilder& BytecodeArrayBuilder::ToName(Register out) { 1018 OutputToName(out); 1019 return *this; 1020 } 1021 1022 BytecodeArrayBuilder& BytecodeArrayBuilder::ToString() { 1023 OutputToString(); 1024 return *this; 1025 } 1026 1027 BytecodeArrayBuilder& BytecodeArrayBuilder::ToNumber(int feedback_slot) { 1028 OutputToNumber(feedback_slot); 1029 return *this; 1030 } 1031 1032 BytecodeArrayBuilder& BytecodeArrayBuilder::ToNumeric(int feedback_slot) { 1033 OutputToNumeric(feedback_slot); 1034 return *this; 1035 } 1036 1037 BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(BytecodeLabel* label) { 1038 // Flush the register optimizer when binding a label to ensure all 1039 // expected registers are valid when jumping to this label. 1040 if (register_optimizer_) register_optimizer_->Flush(); 1041 bytecode_array_writer_.BindLabel(label); 1042 LeaveBasicBlock(); 1043 return *this; 1044 } 1045 1046 BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(const BytecodeLabel& target, 1047 BytecodeLabel* label) { 1048 bytecode_array_writer_.BindLabel(target, label); 1049 LeaveBasicBlock(); 1050 return *this; 1051 } 1052 1053 BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(BytecodeJumpTable* jump_table, 1054 int case_value) { 1055 // Flush the register optimizer when binding a jump table entry to ensure 1056 // all expected registers are valid when jumping to this location. 1057 if (register_optimizer_) register_optimizer_->Flush(); 1058 bytecode_array_writer_.BindJumpTableEntry(jump_table, case_value); 1059 LeaveBasicBlock(); 1060 return *this; 1061 } 1062 1063 BytecodeArrayBuilder& BytecodeArrayBuilder::Jump(BytecodeLabel* label) { 1064 DCHECK(!label->is_bound()); 1065 OutputJump(label, 0); 1066 return *this; 1067 } 1068 1069 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfTrue(ToBooleanMode mode, 1070 BytecodeLabel* label) { 1071 DCHECK(!label->is_bound()); 1072 if (mode == ToBooleanMode::kAlreadyBoolean) { 1073 OutputJumpIfTrue(label, 0); 1074 } else { 1075 DCHECK_EQ(mode, ToBooleanMode::kConvertToBoolean); 1076 OutputJumpIfToBooleanTrue(label, 0); 1077 } 1078 return *this; 1079 } 1080 1081 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfFalse(ToBooleanMode mode, 1082 BytecodeLabel* label) { 1083 DCHECK(!label->is_bound()); 1084 if (mode == ToBooleanMode::kAlreadyBoolean) { 1085 OutputJumpIfFalse(label, 0); 1086 } else { 1087 DCHECK_EQ(mode, ToBooleanMode::kConvertToBoolean); 1088 OutputJumpIfToBooleanFalse(label, 0); 1089 } 1090 return *this; 1091 } 1092 1093 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNull(BytecodeLabel* label) { 1094 DCHECK(!label->is_bound()); 1095 OutputJumpIfNull(label, 0); 1096 return *this; 1097 } 1098 1099 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNotNull( 1100 BytecodeLabel* label) { 1101 DCHECK(!label->is_bound()); 1102 OutputJumpIfNotNull(label, 0); 1103 return *this; 1104 } 1105 1106 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfUndefined( 1107 BytecodeLabel* label) { 1108 DCHECK(!label->is_bound()); 1109 OutputJumpIfUndefined(label, 0); 1110 return *this; 1111 } 1112 1113 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNotUndefined( 1114 BytecodeLabel* label) { 1115 DCHECK(!label->is_bound()); 1116 OutputJumpIfNotUndefined(label, 0); 1117 return *this; 1118 } 1119 1120 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNil(BytecodeLabel* label, 1121 Token::Value op, 1122 NilValue nil) { 1123 if (op == Token::EQ) { 1124 // TODO(rmcilroy): Implement JumpIfUndetectable. 1125 return CompareUndetectable().JumpIfTrue(ToBooleanMode::kAlreadyBoolean, 1126 label); 1127 } else { 1128 DCHECK_EQ(Token::EQ_STRICT, op); 1129 if (nil == kUndefinedValue) { 1130 return JumpIfUndefined(label); 1131 } else { 1132 DCHECK_EQ(kNullValue, nil); 1133 return JumpIfNull(label); 1134 } 1135 } 1136 } 1137 1138 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNotNil(BytecodeLabel* label, 1139 Token::Value op, 1140 NilValue nil) { 1141 if (op == Token::EQ) { 1142 // TODO(rmcilroy): Implement JumpIfUndetectable. 1143 return CompareUndetectable().JumpIfFalse(ToBooleanMode::kAlreadyBoolean, 1144 label); 1145 } else { 1146 DCHECK_EQ(Token::EQ_STRICT, op); 1147 if (nil == kUndefinedValue) { 1148 return JumpIfNotUndefined(label); 1149 } else { 1150 DCHECK_EQ(kNullValue, nil); 1151 return JumpIfNotNull(label); 1152 } 1153 } 1154 } 1155 1156 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfJSReceiver( 1157 BytecodeLabel* label) { 1158 DCHECK(!label->is_bound()); 1159 OutputJumpIfJSReceiver(label, 0); 1160 return *this; 1161 } 1162 1163 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpLoop(BytecodeLabel* label, 1164 int loop_depth) { 1165 DCHECK(label->is_bound()); 1166 OutputJumpLoop(label, 0, loop_depth); 1167 return *this; 1168 } 1169 1170 BytecodeArrayBuilder& BytecodeArrayBuilder::SwitchOnSmiNoFeedback( 1171 BytecodeJumpTable* jump_table) { 1172 OutputSwitchOnSmiNoFeedback(jump_table); 1173 return *this; 1174 } 1175 1176 BytecodeArrayBuilder& BytecodeArrayBuilder::StackCheck(int position) { 1177 if (position != kNoSourcePosition) { 1178 // We need to attach a non-breakable source position to a stack 1179 // check, so we simply add it as expression position. There can be 1180 // a prior statement position from constructs like: 1181 // 1182 // do var x; while (false); 1183 // 1184 // A Nop could be inserted for empty statements, but since no code 1185 // is associated with these positions, instead we force the stack 1186 // check's expression position which eliminates the empty 1187 // statement's position. 1188 latest_source_info_.ForceExpressionPosition(position); 1189 } 1190 OutputStackCheck(); 1191 return *this; 1192 } 1193 1194 BytecodeArrayBuilder& BytecodeArrayBuilder::SetPendingMessage() { 1195 OutputSetPendingMessage(); 1196 return *this; 1197 } 1198 1199 BytecodeArrayBuilder& BytecodeArrayBuilder::Throw() { 1200 OutputThrow(); 1201 return *this; 1202 } 1203 1204 BytecodeArrayBuilder& BytecodeArrayBuilder::ReThrow() { 1205 OutputReThrow(); 1206 return *this; 1207 } 1208 1209 BytecodeArrayBuilder& BytecodeArrayBuilder::Abort(AbortReason reason) { 1210 DCHECK_LT(reason, AbortReason::kLastErrorMessage); 1211 DCHECK_GE(reason, AbortReason::kNoReason); 1212 OutputAbort(static_cast<int>(reason)); 1213 return *this; 1214 } 1215 1216 BytecodeArrayBuilder& BytecodeArrayBuilder::Return() { 1217 OutputReturn(); 1218 return_seen_in_block_ = true; 1219 return *this; 1220 } 1221 1222 BytecodeArrayBuilder& BytecodeArrayBuilder::ThrowReferenceErrorIfHole( 1223 const AstRawString* name) { 1224 size_t entry = GetConstantPoolEntry(name); 1225 OutputThrowReferenceErrorIfHole(entry); 1226 return *this; 1227 } 1228 1229 BytecodeArrayBuilder& BytecodeArrayBuilder::ThrowSuperNotCalledIfHole() { 1230 OutputThrowSuperNotCalledIfHole(); 1231 return *this; 1232 } 1233 1234 BytecodeArrayBuilder& BytecodeArrayBuilder::ThrowSuperAlreadyCalledIfNotHole() { 1235 OutputThrowSuperAlreadyCalledIfNotHole(); 1236 return *this; 1237 } 1238 1239 BytecodeArrayBuilder& BytecodeArrayBuilder::Debugger() { 1240 OutputDebugger(); 1241 return *this; 1242 } 1243 1244 BytecodeArrayBuilder& BytecodeArrayBuilder::IncBlockCounter( 1245 int coverage_array_slot) { 1246 OutputIncBlockCounter(coverage_array_slot); 1247 return *this; 1248 } 1249 1250 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInEnumerate(Register receiver) { 1251 OutputForInEnumerate(receiver); 1252 return *this; 1253 } 1254 1255 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInPrepare( 1256 RegisterList cache_info_triple, int feedback_slot) { 1257 DCHECK_EQ(3, cache_info_triple.register_count()); 1258 OutputForInPrepare(cache_info_triple, feedback_slot); 1259 return *this; 1260 } 1261 1262 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInContinue( 1263 Register index, Register cache_length) { 1264 OutputForInContinue(index, cache_length); 1265 return *this; 1266 } 1267 1268 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInNext( 1269 Register receiver, Register index, RegisterList cache_type_array_pair, 1270 int feedback_slot) { 1271 DCHECK_EQ(2, cache_type_array_pair.register_count()); 1272 OutputForInNext(receiver, index, cache_type_array_pair, feedback_slot); 1273 return *this; 1274 } 1275 1276 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInStep(Register index) { 1277 OutputForInStep(index); 1278 return *this; 1279 } 1280 1281 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreModuleVariable(int cell_index, 1282 int depth) { 1283 OutputStaModuleVariable(cell_index, depth); 1284 return *this; 1285 } 1286 1287 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadModuleVariable(int cell_index, 1288 int depth) { 1289 OutputLdaModuleVariable(cell_index, depth); 1290 return *this; 1291 } 1292 1293 BytecodeArrayBuilder& BytecodeArrayBuilder::SuspendGenerator( 1294 Register generator, RegisterList registers, int suspend_id) { 1295 OutputSuspendGenerator(generator, registers, registers.register_count(), 1296 suspend_id); 1297 return *this; 1298 } 1299 1300 BytecodeArrayBuilder& BytecodeArrayBuilder::SwitchOnGeneratorState( 1301 Register generator, BytecodeJumpTable* jump_table) { 1302 DCHECK_EQ(jump_table->case_value_base(), 0); 1303 BytecodeNode node(CreateSwitchOnGeneratorStateNode( 1304 generator, jump_table->constant_pool_index(), jump_table->size())); 1305 WriteSwitch(&node, jump_table); 1306 LeaveBasicBlock(); 1307 return *this; 1308 } 1309 1310 BytecodeArrayBuilder& BytecodeArrayBuilder::ResumeGenerator( 1311 Register generator, RegisterList registers) { 1312 OutputResumeGenerator(generator, registers, registers.register_count()); 1313 return *this; 1314 } 1315 1316 BytecodeArrayBuilder& BytecodeArrayBuilder::MarkHandler( 1317 int handler_id, HandlerTable::CatchPrediction catch_prediction) { 1318 BytecodeLabel handler; 1319 Bind(&handler); 1320 handler_table_builder()->SetHandlerTarget(handler_id, handler.offset()); 1321 handler_table_builder()->SetPrediction(handler_id, catch_prediction); 1322 return *this; 1323 } 1324 1325 BytecodeArrayBuilder& BytecodeArrayBuilder::MarkTryBegin(int handler_id, 1326 Register context) { 1327 BytecodeLabel try_begin; 1328 Bind(&try_begin); 1329 handler_table_builder()->SetTryRegionStart(handler_id, try_begin.offset()); 1330 handler_table_builder()->SetContextRegister(handler_id, context); 1331 return *this; 1332 } 1333 1334 BytecodeArrayBuilder& BytecodeArrayBuilder::MarkTryEnd(int handler_id) { 1335 BytecodeLabel try_end; 1336 Bind(&try_end); 1337 handler_table_builder()->SetTryRegionEnd(handler_id, try_end.offset()); 1338 return *this; 1339 } 1340 1341 BytecodeArrayBuilder& BytecodeArrayBuilder::CallProperty(Register callable, 1342 RegisterList args, 1343 int feedback_slot) { 1344 if (args.register_count() == 1) { 1345 OutputCallProperty0(callable, args[0], feedback_slot); 1346 } else if (args.register_count() == 2) { 1347 OutputCallProperty1(callable, args[0], args[1], feedback_slot); 1348 } else if (args.register_count() == 3) { 1349 OutputCallProperty2(callable, args[0], args[1], args[2], feedback_slot); 1350 } else { 1351 OutputCallProperty(callable, args, args.register_count(), feedback_slot); 1352 } 1353 return *this; 1354 } 1355 1356 BytecodeArrayBuilder& BytecodeArrayBuilder::CallUndefinedReceiver( 1357 Register callable, RegisterList args, int feedback_slot) { 1358 if (args.register_count() == 0) { 1359 OutputCallUndefinedReceiver0(callable, feedback_slot); 1360 } else if (args.register_count() == 1) { 1361 OutputCallUndefinedReceiver1(callable, args[0], feedback_slot); 1362 } else if (args.register_count() == 2) { 1363 OutputCallUndefinedReceiver2(callable, args[0], args[1], feedback_slot); 1364 } else { 1365 OutputCallUndefinedReceiver(callable, args, args.register_count(), 1366 feedback_slot); 1367 } 1368 return *this; 1369 } 1370 1371 BytecodeArrayBuilder& BytecodeArrayBuilder::CallAnyReceiver(Register callable, 1372 RegisterList args, 1373 int feedback_slot) { 1374 OutputCallAnyReceiver(callable, args, args.register_count(), feedback_slot); 1375 return *this; 1376 } 1377 1378 BytecodeArrayBuilder& BytecodeArrayBuilder::CallWithSpread(Register callable, 1379 RegisterList args, 1380 int feedback_slot) { 1381 OutputCallWithSpread(callable, args, args.register_count(), feedback_slot); 1382 return *this; 1383 } 1384 1385 BytecodeArrayBuilder& BytecodeArrayBuilder::Construct(Register constructor, 1386 RegisterList args, 1387 int feedback_slot_id) { 1388 OutputConstruct(constructor, args, args.register_count(), feedback_slot_id); 1389 return *this; 1390 } 1391 1392 BytecodeArrayBuilder& BytecodeArrayBuilder::ConstructWithSpread( 1393 Register constructor, RegisterList args, int feedback_slot_id) { 1394 OutputConstructWithSpread(constructor, args, args.register_count(), 1395 feedback_slot_id); 1396 return *this; 1397 } 1398 1399 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime( 1400 Runtime::FunctionId function_id, RegisterList args) { 1401 DCHECK_EQ(1, Runtime::FunctionForId(function_id)->result_size); 1402 DCHECK_LE(Bytecodes::SizeForUnsignedOperand(function_id), 1403 OperandSize::kShort); 1404 if (IntrinsicsHelper::IsSupported(function_id)) { 1405 IntrinsicsHelper::IntrinsicId intrinsic_id = 1406 IntrinsicsHelper::FromRuntimeId(function_id); 1407 OutputInvokeIntrinsic(static_cast<int>(intrinsic_id), args, 1408 args.register_count()); 1409 } else { 1410 OutputCallRuntime(static_cast<int>(function_id), args, 1411 args.register_count()); 1412 } 1413 return *this; 1414 } 1415 1416 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime( 1417 Runtime::FunctionId function_id, Register arg) { 1418 return CallRuntime(function_id, RegisterList(arg)); 1419 } 1420 1421 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime( 1422 Runtime::FunctionId function_id) { 1423 return CallRuntime(function_id, RegisterList()); 1424 } 1425 1426 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntimeForPair( 1427 Runtime::FunctionId function_id, RegisterList args, 1428 RegisterList return_pair) { 1429 DCHECK_EQ(2, Runtime::FunctionForId(function_id)->result_size); 1430 DCHECK_LE(Bytecodes::SizeForUnsignedOperand(function_id), 1431 OperandSize::kShort); 1432 DCHECK_EQ(2, return_pair.register_count()); 1433 OutputCallRuntimeForPair(static_cast<uint16_t>(function_id), args, 1434 args.register_count(), return_pair); 1435 return *this; 1436 } 1437 1438 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntimeForPair( 1439 Runtime::FunctionId function_id, Register arg, RegisterList return_pair) { 1440 return CallRuntimeForPair(function_id, RegisterList(arg), return_pair); 1441 } 1442 1443 BytecodeArrayBuilder& BytecodeArrayBuilder::CallJSRuntime(int context_index, 1444 RegisterList args) { 1445 OutputCallJSRuntime(context_index, args, args.register_count()); 1446 return *this; 1447 } 1448 1449 BytecodeArrayBuilder& BytecodeArrayBuilder::Delete(Register object, 1450 LanguageMode language_mode) { 1451 if (language_mode == LanguageMode::kSloppy) { 1452 OutputDeletePropertySloppy(object); 1453 } else { 1454 DCHECK_EQ(language_mode, LanguageMode::kStrict); 1455 OutputDeletePropertyStrict(object); 1456 } 1457 return *this; 1458 } 1459 1460 size_t BytecodeArrayBuilder::GetConstantPoolEntry( 1461 const AstRawString* raw_string) { 1462 return constant_array_builder()->Insert(raw_string); 1463 } 1464 1465 size_t BytecodeArrayBuilder::GetConstantPoolEntry(AstBigInt bigint) { 1466 return constant_array_builder()->Insert(bigint); 1467 } 1468 1469 size_t BytecodeArrayBuilder::GetConstantPoolEntry(const Scope* scope) { 1470 return constant_array_builder()->Insert(scope); 1471 } 1472 1473 size_t BytecodeArrayBuilder::GetConstantPoolEntry(double number) { 1474 return constant_array_builder()->Insert(number); 1475 } 1476 1477 #define ENTRY_GETTER(NAME, ...) \ 1478 size_t BytecodeArrayBuilder::NAME##ConstantPoolEntry() { \ 1479 return constant_array_builder()->Insert##NAME(); \ 1480 } 1481 SINGLETON_CONSTANT_ENTRY_TYPES(ENTRY_GETTER) 1482 #undef ENTRY_GETTER 1483 1484 BytecodeJumpTable* BytecodeArrayBuilder::AllocateJumpTable( 1485 int size, int case_value_base) { 1486 DCHECK_GT(size, 0); 1487 1488 size_t constant_pool_index = constant_array_builder()->InsertJumpTable(size); 1489 1490 return new (zone()) 1491 BytecodeJumpTable(constant_pool_index, size, case_value_base, zone()); 1492 } 1493 1494 size_t BytecodeArrayBuilder::AllocateDeferredConstantPoolEntry() { 1495 return constant_array_builder()->InsertDeferred(); 1496 } 1497 1498 void BytecodeArrayBuilder::SetDeferredConstantPoolEntry(size_t entry, 1499 Handle<Object> object) { 1500 constant_array_builder()->SetDeferredAt(entry, object); 1501 } 1502 1503 bool BytecodeArrayBuilder::RegisterIsValid(Register reg) const { 1504 if (!reg.is_valid()) { 1505 return false; 1506 } 1507 1508 if (reg.is_current_context() || reg.is_function_closure()) { 1509 return true; 1510 } else if (reg.is_parameter()) { 1511 int parameter_index = reg.ToParameterIndex(parameter_count()); 1512 return parameter_index >= 0 && parameter_index < parameter_count(); 1513 } else if (reg.index() < fixed_register_count()) { 1514 return true; 1515 } else { 1516 return register_allocator()->RegisterIsLive(reg); 1517 } 1518 } 1519 1520 bool BytecodeArrayBuilder::RegisterListIsValid(RegisterList reg_list) const { 1521 if (reg_list.register_count() == 0) { 1522 return reg_list.first_register() == Register(0); 1523 } else { 1524 int first_reg_index = reg_list.first_register().index(); 1525 for (int i = 0; i < reg_list.register_count(); i++) { 1526 if (!RegisterIsValid(Register(first_reg_index + i))) { 1527 return false; 1528 } 1529 } 1530 return true; 1531 } 1532 } 1533 1534 template <Bytecode bytecode, AccumulatorUse accumulator_use> 1535 void BytecodeArrayBuilder::PrepareToOutputBytecode() { 1536 if (register_optimizer_) 1537 register_optimizer_->PrepareForBytecode<bytecode, accumulator_use>(); 1538 } 1539 1540 uint32_t BytecodeArrayBuilder::GetInputRegisterOperand(Register reg) { 1541 DCHECK(RegisterIsValid(reg)); 1542 if (register_optimizer_) reg = register_optimizer_->GetInputRegister(reg); 1543 return static_cast<uint32_t>(reg.ToOperand()); 1544 } 1545 1546 uint32_t BytecodeArrayBuilder::GetOutputRegisterOperand(Register reg) { 1547 DCHECK(RegisterIsValid(reg)); 1548 if (register_optimizer_) register_optimizer_->PrepareOutputRegister(reg); 1549 return static_cast<uint32_t>(reg.ToOperand()); 1550 } 1551 1552 uint32_t BytecodeArrayBuilder::GetInputRegisterListOperand( 1553 RegisterList reg_list) { 1554 DCHECK(RegisterListIsValid(reg_list)); 1555 if (register_optimizer_) 1556 reg_list = register_optimizer_->GetInputRegisterList(reg_list); 1557 return static_cast<uint32_t>(reg_list.first_register().ToOperand()); 1558 } 1559 1560 uint32_t BytecodeArrayBuilder::GetOutputRegisterListOperand( 1561 RegisterList reg_list) { 1562 DCHECK(RegisterListIsValid(reg_list)); 1563 if (register_optimizer_) 1564 register_optimizer_->PrepareOutputRegisterList(reg_list); 1565 return static_cast<uint32_t>(reg_list.first_register().ToOperand()); 1566 } 1567 1568 std::ostream& operator<<(std::ostream& os, 1569 const BytecodeArrayBuilder::ToBooleanMode& mode) { 1570 switch (mode) { 1571 case BytecodeArrayBuilder::ToBooleanMode::kAlreadyBoolean: 1572 return os << "AlreadyBoolean"; 1573 case BytecodeArrayBuilder::ToBooleanMode::kConvertToBoolean: 1574 return os << "ConvertToBoolean"; 1575 } 1576 UNREACHABLE(); 1577 } 1578 1579 } // namespace interpreter 1580 } // namespace internal 1581 } // namespace v8 1582