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