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