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-generator.h" 6 7 #include "src/api-inl.h" 8 #include "src/ast/ast-source-ranges.h" 9 #include "src/ast/scopes.h" 10 #include "src/builtins/builtins-constructor.h" 11 #include "src/code-stubs.h" 12 #include "src/compiler.h" 13 #include "src/interpreter/bytecode-flags.h" 14 #include "src/interpreter/bytecode-jump-table.h" 15 #include "src/interpreter/bytecode-label.h" 16 #include "src/interpreter/bytecode-register-allocator.h" 17 #include "src/interpreter/control-flow-builders.h" 18 #include "src/objects-inl.h" 19 #include "src/objects/debug-objects.h" 20 #include "src/objects/literal-objects-inl.h" 21 #include "src/parsing/parse-info.h" 22 #include "src/parsing/token.h" 23 #include "src/unoptimized-compilation-info.h" 24 25 namespace v8 { 26 namespace internal { 27 namespace interpreter { 28 29 // Scoped class tracking context objects created by the visitor. Represents 30 // mutations of the context chain within the function body, allowing pushing and 31 // popping of the current {context_register} during visitation. 32 class BytecodeGenerator::ContextScope BASE_EMBEDDED { 33 public: 34 ContextScope(BytecodeGenerator* generator, Scope* scope) 35 : generator_(generator), 36 scope_(scope), 37 outer_(generator_->execution_context()), 38 register_(Register::current_context()), 39 depth_(0) { 40 DCHECK(scope->NeedsContext() || outer_ == nullptr); 41 if (outer_) { 42 depth_ = outer_->depth_ + 1; 43 44 // Push the outer context into a new context register. 45 Register outer_context_reg = 46 generator_->register_allocator()->NewRegister(); 47 outer_->set_register(outer_context_reg); 48 generator_->builder()->PushContext(outer_context_reg); 49 } 50 generator_->set_execution_context(this); 51 } 52 53 ~ContextScope() { 54 if (outer_) { 55 DCHECK_EQ(register_.index(), Register::current_context().index()); 56 generator_->builder()->PopContext(outer_->reg()); 57 outer_->set_register(register_); 58 } 59 generator_->set_execution_context(outer_); 60 } 61 62 // Returns the depth of the given |scope| for the current execution context. 63 int ContextChainDepth(Scope* scope) { 64 return scope_->ContextChainLength(scope); 65 } 66 67 // Returns the execution context at |depth| in the current context chain if it 68 // is a function local execution context, otherwise returns nullptr. 69 ContextScope* Previous(int depth) { 70 if (depth > depth_) { 71 return nullptr; 72 } 73 74 ContextScope* previous = this; 75 for (int i = depth; i > 0; --i) { 76 previous = previous->outer_; 77 } 78 return previous; 79 } 80 81 Register reg() const { return register_; } 82 83 private: 84 const BytecodeArrayBuilder* builder() const { return generator_->builder(); } 85 86 void set_register(Register reg) { register_ = reg; } 87 88 BytecodeGenerator* generator_; 89 Scope* scope_; 90 ContextScope* outer_; 91 Register register_; 92 int depth_; 93 }; 94 95 // Scoped class for tracking control statements entered by the 96 // visitor. The pattern derives AstGraphBuilder::ControlScope. 97 class BytecodeGenerator::ControlScope BASE_EMBEDDED { 98 public: 99 explicit ControlScope(BytecodeGenerator* generator) 100 : generator_(generator), outer_(generator->execution_control()), 101 context_(generator->execution_context()) { 102 generator_->set_execution_control(this); 103 } 104 virtual ~ControlScope() { generator_->set_execution_control(outer()); } 105 106 void Break(Statement* stmt) { 107 PerformCommand(CMD_BREAK, stmt, kNoSourcePosition); 108 } 109 void Continue(Statement* stmt) { 110 PerformCommand(CMD_CONTINUE, stmt, kNoSourcePosition); 111 } 112 void ReturnAccumulator(int source_position = kNoSourcePosition) { 113 PerformCommand(CMD_RETURN, nullptr, source_position); 114 } 115 void AsyncReturnAccumulator(int source_position = kNoSourcePosition) { 116 PerformCommand(CMD_ASYNC_RETURN, nullptr, source_position); 117 } 118 119 class DeferredCommands; 120 121 protected: 122 enum Command { 123 CMD_BREAK, 124 CMD_CONTINUE, 125 CMD_RETURN, 126 CMD_ASYNC_RETURN, 127 CMD_RETHROW 128 }; 129 static constexpr bool CommandUsesAccumulator(Command command) { 130 return command != CMD_BREAK && command != CMD_CONTINUE; 131 } 132 133 void PerformCommand(Command command, Statement* statement, 134 int source_position); 135 virtual bool Execute(Command command, Statement* statement, 136 int source_position) = 0; 137 138 // Helper to pop the context chain to a depth expected by this control scope. 139 // Note that it is the responsibility of each individual {Execute} method to 140 // trigger this when commands are handled and control-flow continues locally. 141 void PopContextToExpectedDepth(); 142 143 BytecodeGenerator* generator() const { return generator_; } 144 ControlScope* outer() const { return outer_; } 145 ContextScope* context() const { return context_; } 146 147 private: 148 BytecodeGenerator* generator_; 149 ControlScope* outer_; 150 ContextScope* context_; 151 152 DISALLOW_COPY_AND_ASSIGN(ControlScope); 153 }; 154 155 // Helper class for a try-finally control scope. It can record intercepted 156 // control-flow commands that cause entry into a finally-block, and re-apply 157 // them after again leaving that block. Special tokens are used to identify 158 // paths going through the finally-block to dispatch after leaving the block. 159 class BytecodeGenerator::ControlScope::DeferredCommands final { 160 public: 161 DeferredCommands(BytecodeGenerator* generator, Register token_register, 162 Register result_register) 163 : generator_(generator), 164 deferred_(generator->zone()), 165 token_register_(token_register), 166 result_register_(result_register), 167 return_token_(-1), 168 async_return_token_(-1), 169 rethrow_token_(-1) {} 170 171 // One recorded control-flow command. 172 struct Entry { 173 Command command; // The command type being applied on this path. 174 Statement* statement; // The target statement for the command or {nullptr}. 175 int token; // A token identifying this particular path. 176 }; 177 178 // Records a control-flow command while entering the finally-block. This also 179 // generates a new dispatch token that identifies one particular path. This 180 // expects the result to be in the accumulator. 181 void RecordCommand(Command command, Statement* statement) { 182 int token = GetTokenForCommand(command, statement); 183 184 DCHECK_LT(token, deferred_.size()); 185 DCHECK_EQ(deferred_[token].command, command); 186 DCHECK_EQ(deferred_[token].statement, statement); 187 DCHECK_EQ(deferred_[token].token, token); 188 189 if (CommandUsesAccumulator(command)) { 190 builder()->StoreAccumulatorInRegister(result_register_); 191 } 192 builder()->LoadLiteral(Smi::FromInt(token)); 193 builder()->StoreAccumulatorInRegister(token_register_); 194 if (!CommandUsesAccumulator(command)) { 195 // If we're not saving the accumulator in the result register, shove a 196 // harmless value there instead so that it is still considered "killed" in 197 // the liveness analysis. Normally we would LdaUndefined first, but the 198 // Smi token value is just as good, and by reusing it we save a bytecode. 199 builder()->StoreAccumulatorInRegister(result_register_); 200 } 201 } 202 203 // Records the dispatch token to be used to identify the re-throw path when 204 // the finally-block has been entered through the exception handler. This 205 // expects the exception to be in the accumulator. 206 void RecordHandlerReThrowPath() { 207 // The accumulator contains the exception object. 208 RecordCommand(CMD_RETHROW, nullptr); 209 } 210 211 // Records the dispatch token to be used to identify the implicit fall-through 212 // path at the end of a try-block into the corresponding finally-block. 213 void RecordFallThroughPath() { 214 builder()->LoadLiteral(Smi::FromInt(-1)); 215 builder()->StoreAccumulatorInRegister(token_register_); 216 // Since we're not saving the accumulator in the result register, shove a 217 // harmless value there instead so that it is still considered "killed" in 218 // the liveness analysis. Normally we would LdaUndefined first, but the Smi 219 // token value is just as good, and by reusing it we save a bytecode. 220 builder()->StoreAccumulatorInRegister(result_register_); 221 } 222 223 // Applies all recorded control-flow commands after the finally-block again. 224 // This generates a dynamic dispatch on the token from the entry point. 225 void ApplyDeferredCommands() { 226 if (deferred_.size() == 0) return; 227 228 BytecodeLabel fall_through; 229 230 if (deferred_.size() == 1) { 231 // For a single entry, just jump to the fallthrough if we don't match the 232 // entry token. 233 const Entry& entry = deferred_[0]; 234 235 builder() 236 ->LoadLiteral(Smi::FromInt(entry.token)) 237 .CompareReference(token_register_) 238 .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &fall_through); 239 240 if (CommandUsesAccumulator(entry.command)) { 241 builder()->LoadAccumulatorWithRegister(result_register_); 242 } 243 execution_control()->PerformCommand(entry.command, entry.statement, 244 kNoSourcePosition); 245 } else { 246 // For multiple entries, build a jump table and switch on the token, 247 // jumping to the fallthrough if none of them match. 248 249 BytecodeJumpTable* jump_table = 250 builder()->AllocateJumpTable(static_cast<int>(deferred_.size()), 0); 251 builder() 252 ->LoadAccumulatorWithRegister(token_register_) 253 .SwitchOnSmiNoFeedback(jump_table) 254 .Jump(&fall_through); 255 for (const Entry& entry : deferred_) { 256 builder()->Bind(jump_table, entry.token); 257 258 if (CommandUsesAccumulator(entry.command)) { 259 builder()->LoadAccumulatorWithRegister(result_register_); 260 } 261 execution_control()->PerformCommand(entry.command, entry.statement, 262 kNoSourcePosition); 263 } 264 } 265 266 builder()->Bind(&fall_through); 267 } 268 269 BytecodeArrayBuilder* builder() { return generator_->builder(); } 270 ControlScope* execution_control() { return generator_->execution_control(); } 271 272 private: 273 int GetTokenForCommand(Command command, Statement* statement) { 274 switch (command) { 275 case CMD_RETURN: 276 return GetReturnToken(); 277 case CMD_ASYNC_RETURN: 278 return GetAsyncReturnToken(); 279 case CMD_RETHROW: 280 return GetRethrowToken(); 281 default: 282 // TODO(leszeks): We could also search for entries with the same 283 // command and statement. 284 return GetNewTokenForCommand(command, statement); 285 } 286 } 287 288 int GetReturnToken() { 289 if (return_token_ == -1) { 290 return_token_ = GetNewTokenForCommand(CMD_RETURN, nullptr); 291 } 292 return return_token_; 293 } 294 295 int GetAsyncReturnToken() { 296 if (async_return_token_ == -1) { 297 async_return_token_ = GetNewTokenForCommand(CMD_ASYNC_RETURN, nullptr); 298 } 299 return async_return_token_; 300 } 301 302 int GetRethrowToken() { 303 if (rethrow_token_ == -1) { 304 rethrow_token_ = GetNewTokenForCommand(CMD_RETHROW, nullptr); 305 } 306 return rethrow_token_; 307 } 308 309 int GetNewTokenForCommand(Command command, Statement* statement) { 310 int token = static_cast<int>(deferred_.size()); 311 deferred_.push_back({command, statement, token}); 312 return token; 313 } 314 315 BytecodeGenerator* generator_; 316 ZoneVector<Entry> deferred_; 317 Register token_register_; 318 Register result_register_; 319 320 // Tokens for commands that don't need a statement. 321 int return_token_; 322 int async_return_token_; 323 int rethrow_token_; 324 }; 325 326 // Scoped class for dealing with control flow reaching the function level. 327 class BytecodeGenerator::ControlScopeForTopLevel final 328 : public BytecodeGenerator::ControlScope { 329 public: 330 explicit ControlScopeForTopLevel(BytecodeGenerator* generator) 331 : ControlScope(generator) {} 332 333 protected: 334 bool Execute(Command command, Statement* statement, 335 int source_position) override { 336 switch (command) { 337 case CMD_BREAK: // We should never see break/continue in top-level. 338 case CMD_CONTINUE: 339 UNREACHABLE(); 340 case CMD_RETURN: 341 // No need to pop contexts, execution leaves the method body. 342 generator()->BuildReturn(source_position); 343 return true; 344 case CMD_ASYNC_RETURN: 345 // No need to pop contexts, execution leaves the method body. 346 generator()->BuildAsyncReturn(source_position); 347 return true; 348 case CMD_RETHROW: 349 // No need to pop contexts, execution leaves the method body. 350 generator()->BuildReThrow(); 351 return true; 352 } 353 return false; 354 } 355 }; 356 357 // Scoped class for enabling break inside blocks and switch blocks. 358 class BytecodeGenerator::ControlScopeForBreakable final 359 : public BytecodeGenerator::ControlScope { 360 public: 361 ControlScopeForBreakable(BytecodeGenerator* generator, 362 BreakableStatement* statement, 363 BreakableControlFlowBuilder* control_builder) 364 : ControlScope(generator), 365 statement_(statement), 366 control_builder_(control_builder) {} 367 368 protected: 369 bool Execute(Command command, Statement* statement, 370 int source_position) override { 371 control_builder_->set_needs_continuation_counter(); 372 if (statement != statement_) return false; 373 switch (command) { 374 case CMD_BREAK: 375 PopContextToExpectedDepth(); 376 control_builder_->Break(); 377 return true; 378 case CMD_CONTINUE: 379 case CMD_RETURN: 380 case CMD_ASYNC_RETURN: 381 case CMD_RETHROW: 382 break; 383 } 384 return false; 385 } 386 387 private: 388 Statement* statement_; 389 BreakableControlFlowBuilder* control_builder_; 390 }; 391 392 // Scoped class for enabling 'break' and 'continue' in iteration 393 // constructs, e.g. do...while, while..., for... 394 class BytecodeGenerator::ControlScopeForIteration final 395 : public BytecodeGenerator::ControlScope { 396 public: 397 ControlScopeForIteration(BytecodeGenerator* generator, 398 IterationStatement* statement, 399 LoopBuilder* loop_builder) 400 : ControlScope(generator), 401 statement_(statement), 402 loop_builder_(loop_builder) { 403 generator->loop_depth_++; 404 } 405 ~ControlScopeForIteration() { generator()->loop_depth_--; } 406 407 protected: 408 bool Execute(Command command, Statement* statement, 409 int source_position) override { 410 if (statement != statement_) return false; 411 switch (command) { 412 case CMD_BREAK: 413 PopContextToExpectedDepth(); 414 loop_builder_->Break(); 415 return true; 416 case CMD_CONTINUE: 417 PopContextToExpectedDepth(); 418 loop_builder_->Continue(); 419 return true; 420 case CMD_RETURN: 421 case CMD_ASYNC_RETURN: 422 case CMD_RETHROW: 423 break; 424 } 425 return false; 426 } 427 428 private: 429 Statement* statement_; 430 LoopBuilder* loop_builder_; 431 }; 432 433 // Scoped class for enabling 'throw' in try-catch constructs. 434 class BytecodeGenerator::ControlScopeForTryCatch final 435 : public BytecodeGenerator::ControlScope { 436 public: 437 ControlScopeForTryCatch(BytecodeGenerator* generator, 438 TryCatchBuilder* try_catch_builder) 439 : ControlScope(generator) {} 440 441 protected: 442 bool Execute(Command command, Statement* statement, 443 int source_position) override { 444 switch (command) { 445 case CMD_BREAK: 446 case CMD_CONTINUE: 447 case CMD_RETURN: 448 case CMD_ASYNC_RETURN: 449 break; 450 case CMD_RETHROW: 451 // No need to pop contexts, execution re-enters the method body via the 452 // stack unwinding mechanism which itself restores contexts correctly. 453 generator()->BuildReThrow(); 454 return true; 455 } 456 return false; 457 } 458 }; 459 460 // Scoped class for enabling control flow through try-finally constructs. 461 class BytecodeGenerator::ControlScopeForTryFinally final 462 : public BytecodeGenerator::ControlScope { 463 public: 464 ControlScopeForTryFinally(BytecodeGenerator* generator, 465 TryFinallyBuilder* try_finally_builder, 466 DeferredCommands* commands) 467 : ControlScope(generator), 468 try_finally_builder_(try_finally_builder), 469 commands_(commands) {} 470 471 protected: 472 bool Execute(Command command, Statement* statement, 473 int source_position) override { 474 switch (command) { 475 case CMD_BREAK: 476 case CMD_CONTINUE: 477 case CMD_RETURN: 478 case CMD_ASYNC_RETURN: 479 case CMD_RETHROW: 480 PopContextToExpectedDepth(); 481 // We don't record source_position here since we don't generate return 482 // bytecode right here and will generate it later as part of finally 483 // block. Each return bytecode generated in finally block will get own 484 // return source position from corresponded return statement or we'll 485 // use end of function if no return statement is presented. 486 commands_->RecordCommand(command, statement); 487 try_finally_builder_->LeaveTry(); 488 return true; 489 } 490 return false; 491 } 492 493 private: 494 TryFinallyBuilder* try_finally_builder_; 495 DeferredCommands* commands_; 496 }; 497 498 // Allocate and fetch the coverage indices tracking NaryLogical Expressions. 499 class BytecodeGenerator::NaryCodeCoverageSlots { 500 public: 501 NaryCodeCoverageSlots(BytecodeGenerator* generator, NaryOperation* expr) 502 : generator_(generator) { 503 if (generator_->block_coverage_builder_ == nullptr) return; 504 for (size_t i = 0; i < expr->subsequent_length(); i++) { 505 coverage_slots_.push_back( 506 generator_->AllocateNaryBlockCoverageSlotIfEnabled(expr, i)); 507 } 508 } 509 510 int GetSlotFor(size_t subsequent_expr_index) const { 511 if (generator_->block_coverage_builder_ == nullptr) { 512 return BlockCoverageBuilder::kNoCoverageArraySlot; 513 } 514 DCHECK(coverage_slots_.size() > subsequent_expr_index); 515 return coverage_slots_[subsequent_expr_index]; 516 } 517 518 private: 519 BytecodeGenerator* generator_; 520 std::vector<int> coverage_slots_; 521 }; 522 523 void BytecodeGenerator::ControlScope::PerformCommand(Command command, 524 Statement* statement, 525 int source_position) { 526 ControlScope* current = this; 527 do { 528 if (current->Execute(command, statement, source_position)) { 529 return; 530 } 531 current = current->outer(); 532 } while (current != nullptr); 533 UNREACHABLE(); 534 } 535 536 void BytecodeGenerator::ControlScope::PopContextToExpectedDepth() { 537 // Pop context to the expected depth. Note that this can in fact pop multiple 538 // contexts at once because the {PopContext} bytecode takes a saved register. 539 if (generator()->execution_context() != context()) { 540 generator()->builder()->PopContext(context()->reg()); 541 } 542 } 543 544 class BytecodeGenerator::RegisterAllocationScope final { 545 public: 546 explicit RegisterAllocationScope(BytecodeGenerator* generator) 547 : generator_(generator), 548 outer_next_register_index_( 549 generator->register_allocator()->next_register_index()) {} 550 551 ~RegisterAllocationScope() { 552 generator_->register_allocator()->ReleaseRegisters( 553 outer_next_register_index_); 554 } 555 556 private: 557 BytecodeGenerator* generator_; 558 int outer_next_register_index_; 559 560 DISALLOW_COPY_AND_ASSIGN(RegisterAllocationScope); 561 }; 562 563 // Scoped base class for determining how the result of an expression will be 564 // used. 565 class BytecodeGenerator::ExpressionResultScope { 566 public: 567 ExpressionResultScope(BytecodeGenerator* generator, Expression::Context kind) 568 : generator_(generator), 569 outer_(generator->execution_result()), 570 allocator_(generator), 571 kind_(kind), 572 type_hint_(TypeHint::kAny) { 573 generator_->set_execution_result(this); 574 } 575 576 virtual ~ExpressionResultScope() { 577 generator_->set_execution_result(outer_); 578 } 579 580 bool IsEffect() const { return kind_ == Expression::kEffect; } 581 bool IsValue() const { return kind_ == Expression::kValue; } 582 bool IsTest() const { return kind_ == Expression::kTest; } 583 584 TestResultScope* AsTest() { 585 DCHECK(IsTest()); 586 return reinterpret_cast<TestResultScope*>(this); 587 } 588 589 // Specify expression always returns a Boolean result value. 590 void SetResultIsBoolean() { 591 DCHECK_EQ(type_hint_, TypeHint::kAny); 592 type_hint_ = TypeHint::kBoolean; 593 } 594 595 void SetResultIsString() { 596 DCHECK_EQ(type_hint_, TypeHint::kAny); 597 type_hint_ = TypeHint::kString; 598 } 599 600 TypeHint type_hint() const { return type_hint_; } 601 602 private: 603 BytecodeGenerator* generator_; 604 ExpressionResultScope* outer_; 605 RegisterAllocationScope allocator_; 606 Expression::Context kind_; 607 TypeHint type_hint_; 608 609 DISALLOW_COPY_AND_ASSIGN(ExpressionResultScope); 610 }; 611 612 // Scoped class used when the result of the current expression is not 613 // expected to produce a result. 614 class BytecodeGenerator::EffectResultScope final 615 : public ExpressionResultScope { 616 public: 617 explicit EffectResultScope(BytecodeGenerator* generator) 618 : ExpressionResultScope(generator, Expression::kEffect) {} 619 }; 620 621 // Scoped class used when the result of the current expression to be 622 // evaluated should go into the interpreter's accumulator. 623 class BytecodeGenerator::ValueResultScope final : public ExpressionResultScope { 624 public: 625 explicit ValueResultScope(BytecodeGenerator* generator) 626 : ExpressionResultScope(generator, Expression::kValue) {} 627 }; 628 629 // Scoped class used when the result of the current expression to be 630 // evaluated is only tested with jumps to two branches. 631 class BytecodeGenerator::TestResultScope final : public ExpressionResultScope { 632 public: 633 TestResultScope(BytecodeGenerator* generator, BytecodeLabels* then_labels, 634 BytecodeLabels* else_labels, TestFallthrough fallthrough) 635 : ExpressionResultScope(generator, Expression::kTest), 636 result_consumed_by_test_(false), 637 fallthrough_(fallthrough), 638 then_labels_(then_labels), 639 else_labels_(else_labels) {} 640 641 // Used when code special cases for TestResultScope and consumes any 642 // possible value by testing and jumping to a then/else label. 643 void SetResultConsumedByTest() { 644 result_consumed_by_test_ = true; 645 } 646 bool result_consumed_by_test() { return result_consumed_by_test_; } 647 648 // Inverts the control flow of the operation, swapping the then and else 649 // labels and the fallthrough. 650 void InvertControlFlow() { 651 std::swap(then_labels_, else_labels_); 652 fallthrough_ = inverted_fallthrough(); 653 } 654 655 BytecodeLabel* NewThenLabel() { return then_labels_->New(); } 656 BytecodeLabel* NewElseLabel() { return else_labels_->New(); } 657 658 BytecodeLabels* then_labels() const { return then_labels_; } 659 BytecodeLabels* else_labels() const { return else_labels_; } 660 661 void set_then_labels(BytecodeLabels* then_labels) { 662 then_labels_ = then_labels; 663 } 664 void set_else_labels(BytecodeLabels* else_labels) { 665 else_labels_ = else_labels; 666 } 667 668 TestFallthrough fallthrough() const { return fallthrough_; } 669 TestFallthrough inverted_fallthrough() const { 670 switch (fallthrough_) { 671 case TestFallthrough::kThen: 672 return TestFallthrough::kElse; 673 case TestFallthrough::kElse: 674 return TestFallthrough::kThen; 675 default: 676 return TestFallthrough::kNone; 677 } 678 } 679 void set_fallthrough(TestFallthrough fallthrough) { 680 fallthrough_ = fallthrough; 681 } 682 683 private: 684 bool result_consumed_by_test_; 685 TestFallthrough fallthrough_; 686 BytecodeLabels* then_labels_; 687 BytecodeLabels* else_labels_; 688 689 DISALLOW_COPY_AND_ASSIGN(TestResultScope); 690 }; 691 692 // Used to build a list of global declaration initial value pairs. 693 class BytecodeGenerator::GlobalDeclarationsBuilder final : public ZoneObject { 694 public: 695 explicit GlobalDeclarationsBuilder(Zone* zone) 696 : declarations_(0, zone), 697 constant_pool_entry_(0), 698 has_constant_pool_entry_(false) {} 699 700 void AddFunctionDeclaration(const AstRawString* name, FeedbackSlot slot, 701 FeedbackSlot literal_slot, 702 FunctionLiteral* func) { 703 DCHECK(!slot.IsInvalid()); 704 declarations_.push_back(Declaration(name, slot, literal_slot, func)); 705 } 706 707 void AddUndefinedDeclaration(const AstRawString* name, FeedbackSlot slot) { 708 DCHECK(!slot.IsInvalid()); 709 declarations_.push_back(Declaration(name, slot, nullptr)); 710 } 711 712 Handle<FixedArray> AllocateDeclarations(UnoptimizedCompilationInfo* info, 713 Handle<Script> script, 714 Isolate* isolate) { 715 DCHECK(has_constant_pool_entry_); 716 int array_index = 0; 717 Handle<FixedArray> data = isolate->factory()->NewFixedArray( 718 static_cast<int>(declarations_.size() * 4), TENURED); 719 for (const Declaration& declaration : declarations_) { 720 FunctionLiteral* func = declaration.func; 721 Handle<Object> initial_value; 722 if (func == nullptr) { 723 initial_value = isolate->factory()->undefined_value(); 724 } else { 725 initial_value = Compiler::GetSharedFunctionInfo(func, script, isolate); 726 } 727 728 // Return a null handle if any initial values can't be created. Caller 729 // will set stack overflow. 730 if (initial_value.is_null()) return Handle<FixedArray>(); 731 732 data->set(array_index++, *declaration.name->string()); 733 data->set(array_index++, Smi::FromInt(declaration.slot.ToInt())); 734 Object* undefined_or_literal_slot; 735 if (declaration.literal_slot.IsInvalid()) { 736 undefined_or_literal_slot = ReadOnlyRoots(isolate).undefined_value(); 737 } else { 738 undefined_or_literal_slot = 739 Smi::FromInt(declaration.literal_slot.ToInt()); 740 } 741 data->set(array_index++, undefined_or_literal_slot); 742 data->set(array_index++, *initial_value); 743 } 744 return data; 745 } 746 747 size_t constant_pool_entry() { 748 DCHECK(has_constant_pool_entry_); 749 return constant_pool_entry_; 750 } 751 752 void set_constant_pool_entry(size_t constant_pool_entry) { 753 DCHECK(!empty()); 754 DCHECK(!has_constant_pool_entry_); 755 constant_pool_entry_ = constant_pool_entry; 756 has_constant_pool_entry_ = true; 757 } 758 759 bool empty() { return declarations_.empty(); } 760 761 private: 762 struct Declaration { 763 Declaration() : slot(FeedbackSlot::Invalid()), func(nullptr) {} 764 Declaration(const AstRawString* name, FeedbackSlot slot, 765 FeedbackSlot literal_slot, FunctionLiteral* func) 766 : name(name), slot(slot), literal_slot(literal_slot), func(func) {} 767 Declaration(const AstRawString* name, FeedbackSlot slot, 768 FunctionLiteral* func) 769 : name(name), 770 slot(slot), 771 literal_slot(FeedbackSlot::Invalid()), 772 func(func) {} 773 774 const AstRawString* name; 775 FeedbackSlot slot; 776 FeedbackSlot literal_slot; 777 FunctionLiteral* func; 778 }; 779 ZoneVector<Declaration> declarations_; 780 size_t constant_pool_entry_; 781 bool has_constant_pool_entry_; 782 }; 783 784 class BytecodeGenerator::CurrentScope final { 785 public: 786 CurrentScope(BytecodeGenerator* generator, Scope* scope) 787 : generator_(generator), outer_scope_(generator->current_scope()) { 788 if (scope != nullptr) { 789 DCHECK_EQ(outer_scope_, scope->outer_scope()); 790 generator_->set_current_scope(scope); 791 } 792 } 793 ~CurrentScope() { 794 if (outer_scope_ != generator_->current_scope()) { 795 generator_->set_current_scope(outer_scope_); 796 } 797 } 798 799 private: 800 BytecodeGenerator* generator_; 801 Scope* outer_scope_; 802 }; 803 804 class BytecodeGenerator::FeedbackSlotCache : public ZoneObject { 805 public: 806 explicit FeedbackSlotCache(Zone* zone) : map_(zone) {} 807 808 void Put(FeedbackSlotKind slot_kind, Variable* variable, FeedbackSlot slot) { 809 PutImpl(slot_kind, 0, variable, slot); 810 } 811 void Put(FeedbackSlotKind slot_kind, AstNode* node, FeedbackSlot slot) { 812 PutImpl(slot_kind, 0, node, slot); 813 } 814 void Put(FeedbackSlotKind slot_kind, int variable_index, 815 const AstRawString* name, FeedbackSlot slot) { 816 PutImpl(slot_kind, variable_index, name, slot); 817 } 818 819 FeedbackSlot Get(FeedbackSlotKind slot_kind, Variable* variable) const { 820 return GetImpl(slot_kind, 0, variable); 821 } 822 FeedbackSlot Get(FeedbackSlotKind slot_kind, AstNode* node) const { 823 return GetImpl(slot_kind, 0, node); 824 } 825 FeedbackSlot Get(FeedbackSlotKind slot_kind, int variable_index, 826 const AstRawString* name) const { 827 return GetImpl(slot_kind, variable_index, name); 828 } 829 830 private: 831 typedef std::tuple<FeedbackSlotKind, int, const void*> Key; 832 833 void PutImpl(FeedbackSlotKind slot_kind, int index, const void* node, 834 FeedbackSlot slot) { 835 Key key = std::make_tuple(slot_kind, index, node); 836 auto entry = std::make_pair(key, slot); 837 map_.insert(entry); 838 } 839 840 FeedbackSlot GetImpl(FeedbackSlotKind slot_kind, int index, 841 const void* node) const { 842 Key key = std::make_tuple(slot_kind, index, node); 843 auto iter = map_.find(key); 844 if (iter != map_.end()) { 845 return iter->second; 846 } 847 return FeedbackSlot(); 848 } 849 850 ZoneMap<Key, FeedbackSlot> map_; 851 }; 852 853 class BytecodeGenerator::IteratorRecord final { 854 public: 855 IteratorRecord(Register object_register, Register next_register, 856 IteratorType type = IteratorType::kNormal) 857 : type_(type), object_(object_register), next_(next_register) { 858 DCHECK(object_.is_valid() && next_.is_valid()); 859 } 860 861 inline IteratorType type() const { return type_; } 862 inline Register object() const { return object_; } 863 inline Register next() const { return next_; } 864 865 private: 866 IteratorType type_; 867 Register object_; 868 Register next_; 869 }; 870 871 #ifdef DEBUG 872 873 static bool IsInEagerLiterals( 874 FunctionLiteral* literal, 875 const ZoneVector<FunctionLiteral*>& eager_literals) { 876 for (FunctionLiteral* eager_literal : eager_literals) { 877 if (literal == eager_literal) return true; 878 } 879 return false; 880 } 881 882 #endif // DEBUG 883 884 BytecodeGenerator::BytecodeGenerator( 885 UnoptimizedCompilationInfo* info, 886 const AstStringConstants* ast_string_constants, 887 ZoneVector<FunctionLiteral*>* eager_inner_literals) 888 : zone_(info->zone()), 889 builder_(zone(), info->num_parameters_including_this(), 890 info->scope()->num_stack_slots(), info->feedback_vector_spec(), 891 info->SourcePositionRecordingMode()), 892 info_(info), 893 ast_string_constants_(ast_string_constants), 894 closure_scope_(info->scope()), 895 current_scope_(info->scope()), 896 eager_inner_literals_(eager_inner_literals), 897 feedback_slot_cache_(new (zone()) FeedbackSlotCache(zone())), 898 globals_builder_(new (zone()) GlobalDeclarationsBuilder(zone())), 899 block_coverage_builder_(nullptr), 900 global_declarations_(0, zone()), 901 function_literals_(0, zone()), 902 native_function_literals_(0, zone()), 903 object_literals_(0, zone()), 904 array_literals_(0, zone()), 905 class_literals_(0, zone()), 906 template_objects_(0, zone()), 907 execution_control_(nullptr), 908 execution_context_(nullptr), 909 execution_result_(nullptr), 910 incoming_new_target_or_generator_(), 911 dummy_feedback_slot_(), 912 generator_jump_table_(nullptr), 913 suspend_count_(0), 914 loop_depth_(0), 915 catch_prediction_(HandlerTable::UNCAUGHT) { 916 DCHECK_EQ(closure_scope(), closure_scope()->GetClosureScope()); 917 if (info->has_source_range_map()) { 918 block_coverage_builder_ = new (zone()) 919 BlockCoverageBuilder(zone(), builder(), info->source_range_map()); 920 } 921 } 922 923 Handle<BytecodeArray> BytecodeGenerator::FinalizeBytecode( 924 Isolate* isolate, Handle<Script> script) { 925 DCHECK(ThreadId::Current().Equals(isolate->thread_id())); 926 927 AllocateDeferredConstants(isolate, script); 928 929 if (block_coverage_builder_) { 930 info()->set_coverage_info( 931 isolate->factory()->NewCoverageInfo(block_coverage_builder_->slots())); 932 if (FLAG_trace_block_coverage) { 933 info()->coverage_info()->Print(info()->literal()->GetDebugName()); 934 } 935 } 936 937 if (HasStackOverflow()) return Handle<BytecodeArray>(); 938 Handle<BytecodeArray> bytecode_array = builder()->ToBytecodeArray(isolate); 939 940 if (incoming_new_target_or_generator_.is_valid()) { 941 bytecode_array->set_incoming_new_target_or_generator_register( 942 incoming_new_target_or_generator_); 943 } 944 945 return bytecode_array; 946 } 947 948 void BytecodeGenerator::AllocateDeferredConstants(Isolate* isolate, 949 Handle<Script> script) { 950 // Build global declaration pair arrays. 951 for (GlobalDeclarationsBuilder* globals_builder : global_declarations_) { 952 Handle<FixedArray> declarations = 953 globals_builder->AllocateDeclarations(info(), script, isolate); 954 if (declarations.is_null()) return SetStackOverflow(); 955 builder()->SetDeferredConstantPoolEntry( 956 globals_builder->constant_pool_entry(), declarations); 957 } 958 959 // Find or build shared function infos. 960 for (std::pair<FunctionLiteral*, size_t> literal : function_literals_) { 961 FunctionLiteral* expr = literal.first; 962 Handle<SharedFunctionInfo> shared_info = 963 Compiler::GetSharedFunctionInfo(expr, script, isolate); 964 if (shared_info.is_null()) return SetStackOverflow(); 965 builder()->SetDeferredConstantPoolEntry(literal.second, shared_info); 966 } 967 968 // Find or build shared function infos for the native function templates. 969 for (std::pair<NativeFunctionLiteral*, size_t> literal : 970 native_function_literals_) { 971 NativeFunctionLiteral* expr = literal.first; 972 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); 973 974 // Compute the function template for the native function. 975 v8::Local<v8::FunctionTemplate> info = 976 expr->extension()->GetNativeFunctionTemplate( 977 v8_isolate, Utils::ToLocal(expr->name())); 978 DCHECK(!info.IsEmpty()); 979 980 Handle<SharedFunctionInfo> shared_info = 981 FunctionTemplateInfo::GetOrCreateSharedFunctionInfo( 982 isolate, Utils::OpenHandle(*info), expr->name()); 983 DCHECK(!shared_info.is_null()); 984 builder()->SetDeferredConstantPoolEntry(literal.second, shared_info); 985 } 986 987 // Build object literal constant properties 988 for (std::pair<ObjectLiteral*, size_t> literal : object_literals_) { 989 ObjectLiteral* object_literal = literal.first; 990 if (object_literal->properties_count() > 0) { 991 // If constant properties is an empty fixed array, we've already added it 992 // to the constant pool when visiting the object literal. 993 Handle<ObjectBoilerplateDescription> constant_properties = 994 object_literal->GetOrBuildBoilerplateDescription(isolate); 995 996 builder()->SetDeferredConstantPoolEntry(literal.second, 997 constant_properties); 998 } 999 } 1000 1001 // Build array literal constant elements 1002 for (std::pair<ArrayLiteral*, size_t> literal : array_literals_) { 1003 ArrayLiteral* array_literal = literal.first; 1004 Handle<ArrayBoilerplateDescription> constant_elements = 1005 array_literal->GetOrBuildBoilerplateDescription(isolate); 1006 builder()->SetDeferredConstantPoolEntry(literal.second, constant_elements); 1007 } 1008 1009 // Build class literal boilerplates. 1010 for (std::pair<ClassLiteral*, size_t> literal : class_literals_) { 1011 ClassLiteral* class_literal = literal.first; 1012 Handle<ClassBoilerplate> class_boilerplate = 1013 ClassBoilerplate::BuildClassBoilerplate(isolate, class_literal); 1014 builder()->SetDeferredConstantPoolEntry(literal.second, class_boilerplate); 1015 } 1016 1017 // Build template literals. 1018 for (std::pair<GetTemplateObject*, size_t> literal : template_objects_) { 1019 GetTemplateObject* get_template_object = literal.first; 1020 Handle<TemplateObjectDescription> description = 1021 get_template_object->GetOrBuildDescription(isolate); 1022 builder()->SetDeferredConstantPoolEntry(literal.second, description); 1023 } 1024 } 1025 1026 void BytecodeGenerator::GenerateBytecode(uintptr_t stack_limit) { 1027 DisallowHeapAllocation no_allocation; 1028 DisallowHandleAllocation no_handles; 1029 DisallowHandleDereference no_deref; 1030 1031 InitializeAstVisitor(stack_limit); 1032 1033 // Initialize the incoming context. 1034 ContextScope incoming_context(this, closure_scope()); 1035 1036 // Initialize control scope. 1037 ControlScopeForTopLevel control(this); 1038 1039 RegisterAllocationScope register_scope(this); 1040 1041 AllocateTopLevelRegisters(); 1042 1043 if (info()->literal()->CanSuspend()) { 1044 BuildGeneratorPrologue(); 1045 } 1046 1047 if (closure_scope()->NeedsContext()) { 1048 // Push a new inner context scope for the function. 1049 BuildNewLocalActivationContext(); 1050 ContextScope local_function_context(this, closure_scope()); 1051 BuildLocalActivationContextInitialization(); 1052 GenerateBytecodeBody(); 1053 } else { 1054 GenerateBytecodeBody(); 1055 } 1056 1057 // Check that we are not falling off the end. 1058 DCHECK(!builder()->RequiresImplicitReturn()); 1059 } 1060 1061 void BytecodeGenerator::GenerateBytecodeBody() { 1062 // Build the arguments object if it is used. 1063 VisitArgumentsObject(closure_scope()->arguments()); 1064 1065 // Build rest arguments array if it is used. 1066 Variable* rest_parameter = closure_scope()->rest_parameter(); 1067 VisitRestArgumentsArray(rest_parameter); 1068 1069 // Build assignment to the function name or {.this_function} 1070 // variables if used. 1071 VisitThisFunctionVariable(closure_scope()->function_var()); 1072 VisitThisFunctionVariable(closure_scope()->this_function_var()); 1073 1074 // Build assignment to {new.target} variable if it is used. 1075 VisitNewTargetVariable(closure_scope()->new_target_var()); 1076 1077 // Create a generator object if necessary and initialize the 1078 // {.generator_object} variable. 1079 if (info()->literal()->CanSuspend()) { 1080 BuildGeneratorObjectVariableInitialization(); 1081 } 1082 1083 // Emit tracing call if requested to do so. 1084 if (FLAG_trace) builder()->CallRuntime(Runtime::kTraceEnter); 1085 1086 // Emit type profile call. 1087 if (info()->collect_type_profile()) { 1088 feedback_spec()->AddTypeProfileSlot(); 1089 int num_parameters = closure_scope()->num_parameters(); 1090 for (int i = 0; i < num_parameters; i++) { 1091 Register parameter(builder()->Parameter(i)); 1092 builder()->LoadAccumulatorWithRegister(parameter).CollectTypeProfile( 1093 closure_scope()->parameter(i)->initializer_position()); 1094 } 1095 } 1096 1097 // Visit declarations within the function scope. 1098 VisitDeclarations(closure_scope()->declarations()); 1099 1100 // Emit initializing assignments for module namespace imports (if any). 1101 VisitModuleNamespaceImports(); 1102 1103 // Perform a stack-check before the body. 1104 builder()->StackCheck(info()->literal()->start_position()); 1105 1106 // The derived constructor case is handled in VisitCallSuper. 1107 if (IsBaseConstructor(function_kind()) && 1108 info()->literal()->requires_instance_fields_initializer()) { 1109 BuildInstanceFieldInitialization(Register::function_closure(), 1110 builder()->Receiver()); 1111 } 1112 1113 // Visit statements in the function body. 1114 VisitStatements(info()->literal()->body()); 1115 1116 // Emit an implicit return instruction in case control flow can fall off the 1117 // end of the function without an explicit return being present on all paths. 1118 if (builder()->RequiresImplicitReturn()) { 1119 builder()->LoadUndefined(); 1120 BuildReturn(); 1121 } 1122 } 1123 1124 void BytecodeGenerator::AllocateTopLevelRegisters() { 1125 if (info()->literal()->CanSuspend()) { 1126 // Either directly use generator_object_var or allocate a new register for 1127 // the incoming generator object. 1128 Variable* generator_object_var = closure_scope()->generator_object_var(); 1129 if (generator_object_var->location() == VariableLocation::LOCAL) { 1130 incoming_new_target_or_generator_ = 1131 GetRegisterForLocalVariable(generator_object_var); 1132 } else { 1133 incoming_new_target_or_generator_ = register_allocator()->NewRegister(); 1134 } 1135 } else if (closure_scope()->new_target_var()) { 1136 // Either directly use new_target_var or allocate a new register for 1137 // the incoming new target object. 1138 Variable* new_target_var = closure_scope()->new_target_var(); 1139 if (new_target_var->location() == VariableLocation::LOCAL) { 1140 incoming_new_target_or_generator_ = 1141 GetRegisterForLocalVariable(new_target_var); 1142 } else { 1143 incoming_new_target_or_generator_ = register_allocator()->NewRegister(); 1144 } 1145 } 1146 } 1147 1148 void BytecodeGenerator::BuildGeneratorPrologue() { 1149 DCHECK_GT(info()->literal()->suspend_count(), 0); 1150 DCHECK(generator_object().is_valid()); 1151 generator_jump_table_ = 1152 builder()->AllocateJumpTable(info()->literal()->suspend_count(), 0); 1153 1154 // If the generator is not undefined, this is a resume, so perform state 1155 // dispatch. 1156 builder()->SwitchOnGeneratorState(generator_object(), generator_jump_table_); 1157 1158 // Otherwise, fall-through to the ordinary function prologue, after which we 1159 // will run into the generator object creation and other extra code inserted 1160 // by the parser. 1161 } 1162 1163 void BytecodeGenerator::VisitBlock(Block* stmt) { 1164 // Visit declarations and statements. 1165 CurrentScope current_scope(this, stmt->scope()); 1166 if (stmt->scope() != nullptr && stmt->scope()->NeedsContext()) { 1167 BuildNewLocalBlockContext(stmt->scope()); 1168 ContextScope scope(this, stmt->scope()); 1169 VisitBlockDeclarationsAndStatements(stmt); 1170 } else { 1171 VisitBlockDeclarationsAndStatements(stmt); 1172 } 1173 } 1174 1175 void BytecodeGenerator::VisitBlockDeclarationsAndStatements(Block* stmt) { 1176 BlockBuilder block_builder(builder(), block_coverage_builder_, stmt); 1177 ControlScopeForBreakable execution_control(this, stmt, &block_builder); 1178 if (stmt->scope() != nullptr) { 1179 VisitDeclarations(stmt->scope()->declarations()); 1180 } 1181 VisitStatements(stmt->statements()); 1182 } 1183 1184 void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) { 1185 Variable* variable = decl->proxy()->var(); 1186 switch (variable->location()) { 1187 case VariableLocation::UNALLOCATED: { 1188 DCHECK(!variable->binding_needs_init()); 1189 FeedbackSlot slot = 1190 GetCachedLoadGlobalICSlot(NOT_INSIDE_TYPEOF, variable); 1191 globals_builder()->AddUndefinedDeclaration(variable->raw_name(), slot); 1192 break; 1193 } 1194 case VariableLocation::LOCAL: 1195 if (variable->binding_needs_init()) { 1196 Register destination(builder()->Local(variable->index())); 1197 builder()->LoadTheHole().StoreAccumulatorInRegister(destination); 1198 } 1199 break; 1200 case VariableLocation::PARAMETER: 1201 if (variable->binding_needs_init()) { 1202 Register destination(builder()->Parameter(variable->index())); 1203 builder()->LoadTheHole().StoreAccumulatorInRegister(destination); 1204 } 1205 break; 1206 case VariableLocation::CONTEXT: 1207 if (variable->binding_needs_init()) { 1208 DCHECK_EQ(0, execution_context()->ContextChainDepth(variable->scope())); 1209 builder()->LoadTheHole().StoreContextSlot(execution_context()->reg(), 1210 variable->index(), 0); 1211 } 1212 break; 1213 case VariableLocation::LOOKUP: { 1214 DCHECK_EQ(VariableMode::kVar, variable->mode()); 1215 DCHECK(!variable->binding_needs_init()); 1216 1217 Register name = register_allocator()->NewRegister(); 1218 1219 builder() 1220 ->LoadLiteral(variable->raw_name()) 1221 .StoreAccumulatorInRegister(name) 1222 .CallRuntime(Runtime::kDeclareEvalVar, name); 1223 break; 1224 } 1225 case VariableLocation::MODULE: 1226 if (variable->IsExport() && variable->binding_needs_init()) { 1227 builder()->LoadTheHole(); 1228 BuildVariableAssignment(variable, Token::INIT, HoleCheckMode::kElided); 1229 } 1230 // Nothing to do for imports. 1231 break; 1232 } 1233 } 1234 1235 void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) { 1236 Variable* variable = decl->proxy()->var(); 1237 DCHECK(variable->mode() == VariableMode::kLet || 1238 variable->mode() == VariableMode::kVar); 1239 switch (variable->location()) { 1240 case VariableLocation::UNALLOCATED: { 1241 FeedbackSlot slot = 1242 GetCachedLoadGlobalICSlot(NOT_INSIDE_TYPEOF, variable); 1243 FeedbackSlot literal_slot = GetCachedCreateClosureSlot(decl->fun()); 1244 globals_builder()->AddFunctionDeclaration(variable->raw_name(), slot, 1245 literal_slot, decl->fun()); 1246 AddToEagerLiteralsIfEager(decl->fun()); 1247 break; 1248 } 1249 case VariableLocation::PARAMETER: 1250 case VariableLocation::LOCAL: { 1251 VisitForAccumulatorValue(decl->fun()); 1252 BuildVariableAssignment(variable, Token::INIT, HoleCheckMode::kElided); 1253 break; 1254 } 1255 case VariableLocation::CONTEXT: { 1256 DCHECK_EQ(0, execution_context()->ContextChainDepth(variable->scope())); 1257 VisitForAccumulatorValue(decl->fun()); 1258 builder()->StoreContextSlot(execution_context()->reg(), variable->index(), 1259 0); 1260 break; 1261 } 1262 case VariableLocation::LOOKUP: { 1263 RegisterList args = register_allocator()->NewRegisterList(2); 1264 builder() 1265 ->LoadLiteral(variable->raw_name()) 1266 .StoreAccumulatorInRegister(args[0]); 1267 VisitForAccumulatorValue(decl->fun()); 1268 builder()->StoreAccumulatorInRegister(args[1]).CallRuntime( 1269 Runtime::kDeclareEvalFunction, args); 1270 break; 1271 } 1272 case VariableLocation::MODULE: 1273 DCHECK_EQ(variable->mode(), VariableMode::kLet); 1274 DCHECK(variable->IsExport()); 1275 VisitForAccumulatorValue(decl->fun()); 1276 BuildVariableAssignment(variable, Token::INIT, HoleCheckMode::kElided); 1277 break; 1278 } 1279 DCHECK_IMPLIES(decl->fun()->ShouldEagerCompile(), 1280 IsInEagerLiterals(decl->fun(), *eager_inner_literals_)); 1281 } 1282 1283 void BytecodeGenerator::VisitModuleNamespaceImports() { 1284 if (!closure_scope()->is_module_scope()) return; 1285 1286 RegisterAllocationScope register_scope(this); 1287 Register module_request = register_allocator()->NewRegister(); 1288 1289 ModuleDescriptor* descriptor = closure_scope()->AsModuleScope()->module(); 1290 for (auto entry : descriptor->namespace_imports()) { 1291 builder() 1292 ->LoadLiteral(Smi::FromInt(entry->module_request)) 1293 .StoreAccumulatorInRegister(module_request) 1294 .CallRuntime(Runtime::kGetModuleNamespace, module_request); 1295 Variable* var = closure_scope()->LookupLocal(entry->local_name); 1296 DCHECK_NOT_NULL(var); 1297 BuildVariableAssignment(var, Token::INIT, HoleCheckMode::kElided); 1298 } 1299 } 1300 1301 void BytecodeGenerator::VisitDeclarations(Declaration::List* declarations) { 1302 RegisterAllocationScope register_scope(this); 1303 DCHECK(globals_builder()->empty()); 1304 for (Declaration* decl : *declarations) { 1305 RegisterAllocationScope register_scope(this); 1306 Visit(decl); 1307 } 1308 if (globals_builder()->empty()) return; 1309 1310 globals_builder()->set_constant_pool_entry( 1311 builder()->AllocateDeferredConstantPoolEntry()); 1312 int encoded_flags = DeclareGlobalsEvalFlag::encode(info()->is_eval()) | 1313 DeclareGlobalsNativeFlag::encode(info()->is_native()); 1314 1315 // Emit code to declare globals. 1316 RegisterList args = register_allocator()->NewRegisterList(3); 1317 builder() 1318 ->LoadConstantPoolEntry(globals_builder()->constant_pool_entry()) 1319 .StoreAccumulatorInRegister(args[0]) 1320 .LoadLiteral(Smi::FromInt(encoded_flags)) 1321 .StoreAccumulatorInRegister(args[1]) 1322 .MoveRegister(Register::function_closure(), args[2]) 1323 .CallRuntime(Runtime::kDeclareGlobals, args); 1324 1325 // Push and reset globals builder. 1326 global_declarations_.push_back(globals_builder()); 1327 globals_builder_ = new (zone()) GlobalDeclarationsBuilder(zone()); 1328 } 1329 1330 void BytecodeGenerator::VisitStatements(ZonePtrList<Statement>* statements) { 1331 for (int i = 0; i < statements->length(); i++) { 1332 // Allocate an outer register allocations scope for the statement. 1333 RegisterAllocationScope allocation_scope(this); 1334 Statement* stmt = statements->at(i); 1335 Visit(stmt); 1336 if (stmt->IsJump()) break; 1337 } 1338 } 1339 1340 void BytecodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { 1341 builder()->SetStatementPosition(stmt); 1342 VisitForEffect(stmt->expression()); 1343 } 1344 1345 void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) { 1346 } 1347 1348 void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) { 1349 ConditionalControlFlowBuilder conditional_builder( 1350 builder(), block_coverage_builder_, stmt); 1351 builder()->SetStatementPosition(stmt); 1352 1353 if (stmt->condition()->ToBooleanIsTrue()) { 1354 // Generate then block unconditionally as always true. 1355 conditional_builder.Then(); 1356 Visit(stmt->then_statement()); 1357 } else if (stmt->condition()->ToBooleanIsFalse()) { 1358 // Generate else block unconditionally if it exists. 1359 if (stmt->HasElseStatement()) { 1360 conditional_builder.Else(); 1361 Visit(stmt->else_statement()); 1362 } 1363 } else { 1364 // TODO(oth): If then statement is BreakStatement or 1365 // ContinueStatement we can reduce number of generated 1366 // jump/jump_ifs here. See BasicLoops test. 1367 VisitForTest(stmt->condition(), conditional_builder.then_labels(), 1368 conditional_builder.else_labels(), TestFallthrough::kThen); 1369 1370 conditional_builder.Then(); 1371 Visit(stmt->then_statement()); 1372 1373 if (stmt->HasElseStatement()) { 1374 conditional_builder.JumpToEnd(); 1375 conditional_builder.Else(); 1376 Visit(stmt->else_statement()); 1377 } 1378 } 1379 } 1380 1381 void BytecodeGenerator::VisitSloppyBlockFunctionStatement( 1382 SloppyBlockFunctionStatement* stmt) { 1383 Visit(stmt->statement()); 1384 } 1385 1386 void BytecodeGenerator::VisitContinueStatement(ContinueStatement* stmt) { 1387 AllocateBlockCoverageSlotIfEnabled(stmt, SourceRangeKind::kContinuation); 1388 builder()->SetStatementPosition(stmt); 1389 execution_control()->Continue(stmt->target()); 1390 } 1391 1392 void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) { 1393 AllocateBlockCoverageSlotIfEnabled(stmt, SourceRangeKind::kContinuation); 1394 builder()->SetStatementPosition(stmt); 1395 execution_control()->Break(stmt->target()); 1396 } 1397 1398 void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { 1399 AllocateBlockCoverageSlotIfEnabled(stmt, SourceRangeKind::kContinuation); 1400 builder()->SetStatementPosition(stmt); 1401 VisitForAccumulatorValue(stmt->expression()); 1402 if (stmt->is_async_return()) { 1403 execution_control()->AsyncReturnAccumulator(stmt->end_position()); 1404 } else { 1405 execution_control()->ReturnAccumulator(stmt->end_position()); 1406 } 1407 } 1408 1409 void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) { 1410 builder()->SetStatementPosition(stmt); 1411 VisitForAccumulatorValue(stmt->expression()); 1412 BuildNewLocalWithContext(stmt->scope()); 1413 VisitInScope(stmt->statement(), stmt->scope()); 1414 } 1415 1416 void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { 1417 // We need this scope because we visit for register values. We have to 1418 // maintain a execution result scope where registers can be allocated. 1419 ZonePtrList<CaseClause>* clauses = stmt->cases(); 1420 SwitchBuilder switch_builder(builder(), block_coverage_builder_, stmt, 1421 clauses->length()); 1422 ControlScopeForBreakable scope(this, stmt, &switch_builder); 1423 int default_index = -1; 1424 1425 builder()->SetStatementPosition(stmt); 1426 1427 // Keep the switch value in a register until a case matches. 1428 Register tag = VisitForRegisterValue(stmt->tag()); 1429 FeedbackSlot slot = clauses->length() > 0 1430 ? feedback_spec()->AddCompareICSlot() 1431 : FeedbackSlot::Invalid(); 1432 1433 // Iterate over all cases and create nodes for label comparison. 1434 for (int i = 0; i < clauses->length(); i++) { 1435 CaseClause* clause = clauses->at(i); 1436 1437 // The default is not a test, remember index. 1438 if (clause->is_default()) { 1439 default_index = i; 1440 continue; 1441 } 1442 1443 // Perform label comparison as if via '===' with tag. 1444 VisitForAccumulatorValue(clause->label()); 1445 builder()->CompareOperation(Token::Value::EQ_STRICT, tag, 1446 feedback_index(slot)); 1447 switch_builder.Case(ToBooleanMode::kAlreadyBoolean, i); 1448 } 1449 1450 if (default_index >= 0) { 1451 // Emit default jump if there is a default case. 1452 switch_builder.DefaultAt(default_index); 1453 } else { 1454 // Otherwise if we have reached here none of the cases matched, so jump to 1455 // the end. 1456 switch_builder.Break(); 1457 } 1458 1459 // Iterate over all cases and create the case bodies. 1460 for (int i = 0; i < clauses->length(); i++) { 1461 CaseClause* clause = clauses->at(i); 1462 switch_builder.SetCaseTarget(i, clause); 1463 VisitStatements(clause->statements()); 1464 } 1465 } 1466 1467 void BytecodeGenerator::VisitIterationBody(IterationStatement* stmt, 1468 LoopBuilder* loop_builder) { 1469 loop_builder->LoopBody(); 1470 ControlScopeForIteration execution_control(this, stmt, loop_builder); 1471 builder()->StackCheck(stmt->position()); 1472 Visit(stmt->body()); 1473 loop_builder->BindContinueTarget(); 1474 } 1475 1476 void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { 1477 LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt); 1478 if (stmt->cond()->ToBooleanIsFalse()) { 1479 VisitIterationBody(stmt, &loop_builder); 1480 } else if (stmt->cond()->ToBooleanIsTrue()) { 1481 loop_builder.LoopHeader(); 1482 VisitIterationBody(stmt, &loop_builder); 1483 loop_builder.JumpToHeader(loop_depth_); 1484 } else { 1485 loop_builder.LoopHeader(); 1486 VisitIterationBody(stmt, &loop_builder); 1487 builder()->SetExpressionAsStatementPosition(stmt->cond()); 1488 BytecodeLabels loop_backbranch(zone()); 1489 VisitForTest(stmt->cond(), &loop_backbranch, loop_builder.break_labels(), 1490 TestFallthrough::kThen); 1491 loop_backbranch.Bind(builder()); 1492 loop_builder.JumpToHeader(loop_depth_); 1493 } 1494 } 1495 1496 void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) { 1497 LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt); 1498 1499 if (stmt->cond()->ToBooleanIsFalse()) { 1500 // If the condition is false there is no need to generate the loop. 1501 return; 1502 } 1503 1504 loop_builder.LoopHeader(); 1505 if (!stmt->cond()->ToBooleanIsTrue()) { 1506 builder()->SetExpressionAsStatementPosition(stmt->cond()); 1507 BytecodeLabels loop_body(zone()); 1508 VisitForTest(stmt->cond(), &loop_body, loop_builder.break_labels(), 1509 TestFallthrough::kThen); 1510 loop_body.Bind(builder()); 1511 } 1512 VisitIterationBody(stmt, &loop_builder); 1513 loop_builder.JumpToHeader(loop_depth_); 1514 } 1515 1516 void BytecodeGenerator::VisitForStatement(ForStatement* stmt) { 1517 LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt); 1518 1519 if (stmt->init() != nullptr) { 1520 Visit(stmt->init()); 1521 } 1522 if (stmt->cond() && stmt->cond()->ToBooleanIsFalse()) { 1523 // If the condition is known to be false there is no need to generate 1524 // body, next or condition blocks. Init block should be generated. 1525 return; 1526 } 1527 1528 loop_builder.LoopHeader(); 1529 if (stmt->cond() && !stmt->cond()->ToBooleanIsTrue()) { 1530 builder()->SetExpressionAsStatementPosition(stmt->cond()); 1531 BytecodeLabels loop_body(zone()); 1532 VisitForTest(stmt->cond(), &loop_body, loop_builder.break_labels(), 1533 TestFallthrough::kThen); 1534 loop_body.Bind(builder()); 1535 } 1536 VisitIterationBody(stmt, &loop_builder); 1537 if (stmt->next() != nullptr) { 1538 builder()->SetStatementPosition(stmt->next()); 1539 Visit(stmt->next()); 1540 } 1541 loop_builder.JumpToHeader(loop_depth_); 1542 } 1543 1544 void BytecodeGenerator::VisitForInAssignment(Expression* expr) { 1545 DCHECK(expr->IsValidReferenceExpression()); 1546 1547 // Evaluate assignment starting with the value to be stored in the 1548 // accumulator. 1549 Property* property = expr->AsProperty(); 1550 LhsKind assign_type = Property::GetAssignType(property); 1551 switch (assign_type) { 1552 case VARIABLE: { 1553 VariableProxy* proxy = expr->AsVariableProxy(); 1554 BuildVariableAssignment(proxy->var(), Token::ASSIGN, 1555 proxy->hole_check_mode()); 1556 break; 1557 } 1558 case NAMED_PROPERTY: { 1559 RegisterAllocationScope register_scope(this); 1560 Register value = register_allocator()->NewRegister(); 1561 builder()->StoreAccumulatorInRegister(value); 1562 Register object = VisitForRegisterValue(property->obj()); 1563 const AstRawString* name = 1564 property->key()->AsLiteral()->AsRawPropertyName(); 1565 builder()->LoadAccumulatorWithRegister(value); 1566 FeedbackSlot slot = GetCachedStoreICSlot(property->obj(), name); 1567 builder()->StoreNamedProperty(object, name, feedback_index(slot), 1568 language_mode()); 1569 builder()->LoadAccumulatorWithRegister(value); 1570 break; 1571 } 1572 case KEYED_PROPERTY: { 1573 RegisterAllocationScope register_scope(this); 1574 Register value = register_allocator()->NewRegister(); 1575 builder()->StoreAccumulatorInRegister(value); 1576 Register object = VisitForRegisterValue(property->obj()); 1577 Register key = VisitForRegisterValue(property->key()); 1578 builder()->LoadAccumulatorWithRegister(value); 1579 FeedbackSlot slot = feedback_spec()->AddKeyedStoreICSlot(language_mode()); 1580 builder()->StoreKeyedProperty(object, key, feedback_index(slot), 1581 language_mode()); 1582 builder()->LoadAccumulatorWithRegister(value); 1583 break; 1584 } 1585 case NAMED_SUPER_PROPERTY: { 1586 RegisterAllocationScope register_scope(this); 1587 RegisterList args = register_allocator()->NewRegisterList(4); 1588 builder()->StoreAccumulatorInRegister(args[3]); 1589 SuperPropertyReference* super_property = 1590 property->obj()->AsSuperPropertyReference(); 1591 VisitForRegisterValue(super_property->this_var(), args[0]); 1592 VisitForRegisterValue(super_property->home_object(), args[1]); 1593 builder() 1594 ->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName()) 1595 .StoreAccumulatorInRegister(args[2]) 1596 .CallRuntime(StoreToSuperRuntimeId(), args); 1597 break; 1598 } 1599 case KEYED_SUPER_PROPERTY: { 1600 RegisterAllocationScope register_scope(this); 1601 RegisterList args = register_allocator()->NewRegisterList(4); 1602 builder()->StoreAccumulatorInRegister(args[3]); 1603 SuperPropertyReference* super_property = 1604 property->obj()->AsSuperPropertyReference(); 1605 VisitForRegisterValue(super_property->this_var(), args[0]); 1606 VisitForRegisterValue(super_property->home_object(), args[1]); 1607 VisitForRegisterValue(property->key(), args[2]); 1608 builder()->CallRuntime(StoreKeyedToSuperRuntimeId(), args); 1609 break; 1610 } 1611 } 1612 } 1613 1614 void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) { 1615 if (stmt->subject()->IsNullLiteral() || 1616 stmt->subject()->IsUndefinedLiteral()) { 1617 // ForIn generates lots of code, skip if it wouldn't produce any effects. 1618 return; 1619 } 1620 1621 BytecodeLabel subject_null_label, subject_undefined_label; 1622 FeedbackSlot slot = feedback_spec()->AddForInSlot(); 1623 1624 // Prepare the state for executing ForIn. 1625 builder()->SetExpressionAsStatementPosition(stmt->subject()); 1626 VisitForAccumulatorValue(stmt->subject()); 1627 builder()->JumpIfUndefined(&subject_undefined_label); 1628 builder()->JumpIfNull(&subject_null_label); 1629 Register receiver = register_allocator()->NewRegister(); 1630 builder()->ToObject(receiver); 1631 1632 // Used as kRegTriple and kRegPair in ForInPrepare and ForInNext. 1633 RegisterList triple = register_allocator()->NewRegisterList(3); 1634 Register cache_length = triple[2]; 1635 builder()->ForInEnumerate(receiver); 1636 builder()->ForInPrepare(triple, feedback_index(slot)); 1637 1638 // Set up loop counter 1639 Register index = register_allocator()->NewRegister(); 1640 builder()->LoadLiteral(Smi::kZero); 1641 builder()->StoreAccumulatorInRegister(index); 1642 1643 // The loop 1644 { 1645 LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt); 1646 loop_builder.LoopHeader(); 1647 builder()->SetExpressionAsStatementPosition(stmt->each()); 1648 builder()->ForInContinue(index, cache_length); 1649 loop_builder.BreakIfFalse(ToBooleanMode::kAlreadyBoolean); 1650 builder()->ForInNext(receiver, index, triple.Truncate(2), 1651 feedback_index(slot)); 1652 loop_builder.ContinueIfUndefined(); 1653 VisitForInAssignment(stmt->each()); 1654 VisitIterationBody(stmt, &loop_builder); 1655 builder()->ForInStep(index); 1656 builder()->StoreAccumulatorInRegister(index); 1657 loop_builder.JumpToHeader(loop_depth_); 1658 } 1659 builder()->Bind(&subject_null_label); 1660 builder()->Bind(&subject_undefined_label); 1661 } 1662 1663 void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { 1664 LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt); 1665 1666 builder()->SetExpressionAsStatementPosition(stmt->assign_iterator()); 1667 VisitForEffect(stmt->assign_iterator()); 1668 VisitForEffect(stmt->assign_next()); 1669 1670 loop_builder.LoopHeader(); 1671 builder()->SetExpressionAsStatementPosition(stmt->next_result()); 1672 VisitForEffect(stmt->next_result()); 1673 TypeHint type_hint = VisitForAccumulatorValue(stmt->result_done()); 1674 loop_builder.BreakIfTrue(ToBooleanModeFromTypeHint(type_hint)); 1675 1676 VisitForEffect(stmt->assign_each()); 1677 VisitIterationBody(stmt, &loop_builder); 1678 loop_builder.JumpToHeader(loop_depth_); 1679 } 1680 1681 void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { 1682 // Update catch prediction tracking. The updated catch_prediction value lasts 1683 // until the end of the try_block in the AST node, and does not apply to the 1684 // catch_block. 1685 HandlerTable::CatchPrediction outer_catch_prediction = catch_prediction(); 1686 set_catch_prediction(stmt->GetCatchPrediction(outer_catch_prediction)); 1687 1688 TryCatchBuilder try_control_builder(builder(), block_coverage_builder_, stmt, 1689 catch_prediction()); 1690 1691 // Preserve the context in a dedicated register, so that it can be restored 1692 // when the handler is entered by the stack-unwinding machinery. 1693 // TODO(mstarzinger): Be smarter about register allocation. 1694 Register context = register_allocator()->NewRegister(); 1695 builder()->MoveRegister(Register::current_context(), context); 1696 1697 // Evaluate the try-block inside a control scope. This simulates a handler 1698 // that is intercepting 'throw' control commands. 1699 try_control_builder.BeginTry(context); 1700 { 1701 ControlScopeForTryCatch scope(this, &try_control_builder); 1702 Visit(stmt->try_block()); 1703 set_catch_prediction(outer_catch_prediction); 1704 } 1705 try_control_builder.EndTry(); 1706 1707 if (stmt->scope()) { 1708 // Create a catch scope that binds the exception. 1709 BuildNewLocalCatchContext(stmt->scope()); 1710 builder()->StoreAccumulatorInRegister(context); 1711 } 1712 1713 // If requested, clear message object as we enter the catch block. 1714 if (stmt->ShouldClearPendingException(outer_catch_prediction)) { 1715 builder()->LoadTheHole().SetPendingMessage(); 1716 } 1717 1718 // Load the catch context into the accumulator. 1719 builder()->LoadAccumulatorWithRegister(context); 1720 1721 // Evaluate the catch-block. 1722 if (stmt->scope()) { 1723 VisitInScope(stmt->catch_block(), stmt->scope()); 1724 } else { 1725 VisitBlock(stmt->catch_block()); 1726 } 1727 try_control_builder.EndCatch(); 1728 } 1729 1730 void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { 1731 // We can't know whether the finally block will override ("catch") an 1732 // exception thrown in the try block, so we just adopt the outer prediction. 1733 TryFinallyBuilder try_control_builder(builder(), block_coverage_builder_, 1734 stmt, catch_prediction()); 1735 1736 // We keep a record of all paths that enter the finally-block to be able to 1737 // dispatch to the correct continuation point after the statements in the 1738 // finally-block have been evaluated. 1739 // 1740 // The try-finally construct can enter the finally-block in three ways: 1741 // 1. By exiting the try-block normally, falling through at the end. 1742 // 2. By exiting the try-block with a function-local control flow transfer 1743 // (i.e. through break/continue/return statements). 1744 // 3. By exiting the try-block with a thrown exception. 1745 // 1746 // The result register semantics depend on how the block was entered: 1747 // - ReturnStatement: It represents the return value being returned. 1748 // - ThrowStatement: It represents the exception being thrown. 1749 // - BreakStatement/ContinueStatement: Undefined and not used. 1750 // - Falling through into finally-block: Undefined and not used. 1751 Register token = register_allocator()->NewRegister(); 1752 Register result = register_allocator()->NewRegister(); 1753 ControlScope::DeferredCommands commands(this, token, result); 1754 1755 // Preserve the context in a dedicated register, so that it can be restored 1756 // when the handler is entered by the stack-unwinding machinery. 1757 // TODO(mstarzinger): Be smarter about register allocation. 1758 Register context = register_allocator()->NewRegister(); 1759 builder()->MoveRegister(Register::current_context(), context); 1760 1761 // Evaluate the try-block inside a control scope. This simulates a handler 1762 // that is intercepting all control commands. 1763 try_control_builder.BeginTry(context); 1764 { 1765 ControlScopeForTryFinally scope(this, &try_control_builder, &commands); 1766 Visit(stmt->try_block()); 1767 } 1768 try_control_builder.EndTry(); 1769 1770 // Record fall-through and exception cases. 1771 commands.RecordFallThroughPath(); 1772 try_control_builder.LeaveTry(); 1773 try_control_builder.BeginHandler(); 1774 commands.RecordHandlerReThrowPath(); 1775 1776 // Pending message object is saved on entry. 1777 try_control_builder.BeginFinally(); 1778 Register message = context; // Reuse register. 1779 1780 // Clear message object as we enter the finally block. 1781 builder()->LoadTheHole().SetPendingMessage().StoreAccumulatorInRegister( 1782 message); 1783 1784 // Evaluate the finally-block. 1785 Visit(stmt->finally_block()); 1786 try_control_builder.EndFinally(); 1787 1788 // Pending message object is restored on exit. 1789 builder()->LoadAccumulatorWithRegister(message).SetPendingMessage(); 1790 1791 // Dynamic dispatch after the finally-block. 1792 commands.ApplyDeferredCommands(); 1793 } 1794 1795 void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) { 1796 builder()->SetStatementPosition(stmt); 1797 builder()->Debugger(); 1798 } 1799 1800 void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { 1801 DCHECK(expr->scope()->outer_scope() == current_scope()); 1802 uint8_t flags = CreateClosureFlags::Encode( 1803 expr->pretenure(), closure_scope()->is_function_scope()); 1804 size_t entry = builder()->AllocateDeferredConstantPoolEntry(); 1805 FeedbackSlot slot = GetCachedCreateClosureSlot(expr); 1806 builder()->CreateClosure(entry, feedback_index(slot), flags); 1807 function_literals_.push_back(std::make_pair(expr, entry)); 1808 AddToEagerLiteralsIfEager(expr); 1809 } 1810 1811 void BytecodeGenerator::AddToEagerLiteralsIfEager(FunctionLiteral* literal) { 1812 if (eager_inner_literals_ && literal->ShouldEagerCompile()) { 1813 DCHECK(!IsInEagerLiterals(literal, *eager_inner_literals_)); 1814 eager_inner_literals_->push_back(literal); 1815 } 1816 } 1817 1818 bool BytecodeGenerator::ShouldOptimizeAsOneShot() const { 1819 if (!FLAG_enable_one_shot_optimization) return false; 1820 1821 if (loop_depth_ > 0) return false; 1822 1823 return info()->literal()->is_top_level() || info()->literal()->is_iife(); 1824 } 1825 1826 void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr) { 1827 size_t class_boilerplate_entry = 1828 builder()->AllocateDeferredConstantPoolEntry(); 1829 class_literals_.push_back(std::make_pair(expr, class_boilerplate_entry)); 1830 1831 VisitDeclarations(expr->scope()->declarations()); 1832 Register class_constructor = register_allocator()->NewRegister(); 1833 1834 { 1835 RegisterAllocationScope register_scope(this); 1836 RegisterList args = register_allocator()->NewGrowableRegisterList(); 1837 1838 Register class_boilerplate = register_allocator()->GrowRegisterList(&args); 1839 Register class_constructor_in_args = 1840 register_allocator()->GrowRegisterList(&args); 1841 Register super_class = register_allocator()->GrowRegisterList(&args); 1842 DCHECK_EQ(ClassBoilerplate::kFirstDynamicArgumentIndex, 1843 args.register_count()); 1844 1845 VisitForAccumulatorValueOrTheHole(expr->extends()); 1846 builder()->StoreAccumulatorInRegister(super_class); 1847 1848 VisitFunctionLiteral(expr->constructor()); 1849 builder() 1850 ->StoreAccumulatorInRegister(class_constructor) 1851 .MoveRegister(class_constructor, class_constructor_in_args) 1852 .LoadConstantPoolEntry(class_boilerplate_entry) 1853 .StoreAccumulatorInRegister(class_boilerplate); 1854 1855 // Create computed names and method values nodes to store into the literal. 1856 for (int i = 0; i < expr->properties()->length(); i++) { 1857 ClassLiteral::Property* property = expr->properties()->at(i); 1858 if (property->is_computed_name()) { 1859 DCHECK_NE(property->kind(), ClassLiteral::Property::PRIVATE_FIELD); 1860 Register key = register_allocator()->GrowRegisterList(&args); 1861 1862 BuildLoadPropertyKey(property, key); 1863 if (property->is_static()) { 1864 // The static prototype property is read only. We handle the non 1865 // computed property name case in the parser. Since this is the only 1866 // case where we need to check for an own read only property we 1867 // special case this so we do not need to do this for every property. 1868 1869 FeedbackSlot slot = GetDummyCompareICSlot(); 1870 BytecodeLabel done; 1871 builder() 1872 ->LoadLiteral(ast_string_constants()->prototype_string()) 1873 .CompareOperation(Token::Value::EQ_STRICT, key, 1874 feedback_index(slot)) 1875 .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &done) 1876 .CallRuntime(Runtime::kThrowStaticPrototypeError) 1877 .Bind(&done); 1878 } 1879 1880 if (property->kind() == ClassLiteral::Property::PUBLIC_FIELD) { 1881 // Initialize field's name variable with the computed name. 1882 DCHECK_NOT_NULL(property->computed_name_var()); 1883 builder()->LoadAccumulatorWithRegister(key); 1884 BuildVariableAssignment(property->computed_name_var(), Token::INIT, 1885 HoleCheckMode::kElided); 1886 } 1887 } 1888 1889 if (property->kind() == ClassLiteral::Property::PUBLIC_FIELD) { 1890 // We don't compute field's value here, but instead do it in the 1891 // initializer function. 1892 continue; 1893 } else if (property->kind() == ClassLiteral::Property::PRIVATE_FIELD) { 1894 builder()->CallRuntime(Runtime::kCreatePrivateFieldSymbol); 1895 DCHECK_NOT_NULL(property->private_field_name_var()); 1896 BuildVariableAssignment(property->private_field_name_var(), Token::INIT, 1897 HoleCheckMode::kElided); 1898 continue; 1899 } 1900 1901 Register value = register_allocator()->GrowRegisterList(&args); 1902 VisitForRegisterValue(property->value(), value); 1903 } 1904 1905 builder()->CallRuntime(Runtime::kDefineClass, args); 1906 } 1907 Register prototype = register_allocator()->NewRegister(); 1908 builder()->StoreAccumulatorInRegister(prototype); 1909 1910 // Assign to class variable. 1911 if (expr->class_variable() != nullptr) { 1912 DCHECK(expr->class_variable()->IsStackLocal() || 1913 expr->class_variable()->IsContextSlot()); 1914 builder()->LoadAccumulatorWithRegister(class_constructor); 1915 BuildVariableAssignment(expr->class_variable(), Token::INIT, 1916 HoleCheckMode::kElided); 1917 } 1918 1919 if (expr->instance_fields_initializer_function() != nullptr) { 1920 Register initializer = 1921 VisitForRegisterValue(expr->instance_fields_initializer_function()); 1922 1923 if (FunctionLiteral::NeedsHomeObject( 1924 expr->instance_fields_initializer_function())) { 1925 FeedbackSlot slot = feedback_spec()->AddStoreICSlot(language_mode()); 1926 builder()->LoadAccumulatorWithRegister(prototype).StoreHomeObjectProperty( 1927 initializer, feedback_index(slot), language_mode()); 1928 } 1929 1930 FeedbackSlot slot = feedback_spec()->AddStoreICSlot(language_mode()); 1931 builder() 1932 ->LoadAccumulatorWithRegister(initializer) 1933 .StoreClassFieldsInitializer(class_constructor, feedback_index(slot)) 1934 .LoadAccumulatorWithRegister(class_constructor); 1935 } 1936 1937 if (expr->static_fields_initializer() != nullptr) { 1938 RegisterList args = register_allocator()->NewRegisterList(1); 1939 Register initializer = 1940 VisitForRegisterValue(expr->static_fields_initializer()); 1941 1942 if (FunctionLiteral::NeedsHomeObject(expr->static_fields_initializer())) { 1943 FeedbackSlot slot = feedback_spec()->AddStoreICSlot(language_mode()); 1944 builder() 1945 ->LoadAccumulatorWithRegister(class_constructor) 1946 .StoreHomeObjectProperty(initializer, feedback_index(slot), 1947 language_mode()); 1948 } 1949 1950 builder() 1951 ->MoveRegister(class_constructor, args[0]) 1952 .CallProperty(initializer, args, 1953 feedback_index(feedback_spec()->AddCallICSlot())); 1954 } 1955 builder()->LoadAccumulatorWithRegister(class_constructor); 1956 } 1957 1958 void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr) { 1959 CurrentScope current_scope(this, expr->scope()); 1960 DCHECK_NOT_NULL(expr->scope()); 1961 if (expr->scope()->NeedsContext()) { 1962 BuildNewLocalBlockContext(expr->scope()); 1963 ContextScope scope(this, expr->scope()); 1964 BuildClassLiteral(expr); 1965 } else { 1966 BuildClassLiteral(expr); 1967 } 1968 } 1969 1970 void BytecodeGenerator::VisitInitializeClassFieldsStatement( 1971 InitializeClassFieldsStatement* expr) { 1972 RegisterList args = register_allocator()->NewRegisterList(3); 1973 Register constructor = args[0], key = args[1], value = args[2]; 1974 builder()->MoveRegister(builder()->Receiver(), constructor); 1975 1976 for (int i = 0; i < expr->fields()->length(); i++) { 1977 ClassLiteral::Property* property = expr->fields()->at(i); 1978 1979 if (property->is_computed_name()) { 1980 DCHECK_EQ(property->kind(), ClassLiteral::Property::PUBLIC_FIELD); 1981 Variable* var = property->computed_name_var(); 1982 DCHECK_NOT_NULL(var); 1983 // The computed name is already evaluated and stored in a 1984 // variable at class definition time. 1985 BuildVariableLoad(var, HoleCheckMode::kElided); 1986 builder()->StoreAccumulatorInRegister(key); 1987 } else if (property->kind() == ClassLiteral::Property::PRIVATE_FIELD) { 1988 Variable* private_field_name_var = property->private_field_name_var(); 1989 DCHECK_NOT_NULL(private_field_name_var); 1990 BuildVariableLoad(private_field_name_var, HoleCheckMode::kElided); 1991 builder()->StoreAccumulatorInRegister(key); 1992 } else { 1993 BuildLoadPropertyKey(property, key); 1994 } 1995 1996 VisitForRegisterValue(property->value(), value); 1997 VisitSetHomeObject(value, constructor, property); 1998 1999 Runtime::FunctionId function_id = 2000 property->kind() == ClassLiteral::Property::PUBLIC_FIELD 2001 ? Runtime::kCreateDataProperty 2002 : Runtime::kAddPrivateField; 2003 builder()->CallRuntime(function_id, args); 2004 } 2005 } 2006 2007 void BytecodeGenerator::BuildInstanceFieldInitialization(Register constructor, 2008 Register instance) { 2009 RegisterList args = register_allocator()->NewRegisterList(1); 2010 Register initializer = register_allocator()->NewRegister(); 2011 2012 FeedbackSlot slot = feedback_spec()->AddLoadICSlot(); 2013 BytecodeLabel done; 2014 2015 builder() 2016 ->LoadClassFieldsInitializer(constructor, feedback_index(slot)) 2017 // TODO(gsathya): This jump can be elided for the base 2018 // constructor and derived constructor. This is only required 2019 // when called from an arrow function. 2020 .JumpIfUndefined(&done) 2021 .StoreAccumulatorInRegister(initializer) 2022 .MoveRegister(instance, args[0]) 2023 .CallProperty(initializer, args, 2024 feedback_index(feedback_spec()->AddCallICSlot())) 2025 .Bind(&done); 2026 } 2027 2028 void BytecodeGenerator::VisitNativeFunctionLiteral( 2029 NativeFunctionLiteral* expr) { 2030 size_t entry = builder()->AllocateDeferredConstantPoolEntry(); 2031 FeedbackSlot slot = feedback_spec()->AddCreateClosureSlot(); 2032 builder()->CreateClosure(entry, feedback_index(slot), NOT_TENURED); 2033 native_function_literals_.push_back(std::make_pair(expr, entry)); 2034 } 2035 2036 void BytecodeGenerator::VisitDoExpression(DoExpression* expr) { 2037 VisitBlock(expr->block()); 2038 VisitVariableProxy(expr->result()); 2039 } 2040 2041 void BytecodeGenerator::VisitConditional(Conditional* expr) { 2042 ConditionalControlFlowBuilder conditional_builder( 2043 builder(), block_coverage_builder_, expr); 2044 2045 if (expr->condition()->ToBooleanIsTrue()) { 2046 // Generate then block unconditionally as always true. 2047 conditional_builder.Then(); 2048 VisitForAccumulatorValue(expr->then_expression()); 2049 } else if (expr->condition()->ToBooleanIsFalse()) { 2050 // Generate else block unconditionally if it exists. 2051 conditional_builder.Else(); 2052 VisitForAccumulatorValue(expr->else_expression()); 2053 } else { 2054 VisitForTest(expr->condition(), conditional_builder.then_labels(), 2055 conditional_builder.else_labels(), TestFallthrough::kThen); 2056 2057 conditional_builder.Then(); 2058 VisitForAccumulatorValue(expr->then_expression()); 2059 conditional_builder.JumpToEnd(); 2060 2061 conditional_builder.Else(); 2062 VisitForAccumulatorValue(expr->else_expression()); 2063 } 2064 } 2065 2066 void BytecodeGenerator::VisitLiteral(Literal* expr) { 2067 if (execution_result()->IsEffect()) return; 2068 switch (expr->type()) { 2069 case Literal::kSmi: 2070 builder()->LoadLiteral(expr->AsSmiLiteral()); 2071 break; 2072 case Literal::kHeapNumber: 2073 builder()->LoadLiteral(expr->AsNumber()); 2074 break; 2075 case Literal::kUndefined: 2076 builder()->LoadUndefined(); 2077 break; 2078 case Literal::kBoolean: 2079 builder()->LoadBoolean(expr->ToBooleanIsTrue()); 2080 execution_result()->SetResultIsBoolean(); 2081 break; 2082 case Literal::kNull: 2083 builder()->LoadNull(); 2084 break; 2085 case Literal::kTheHole: 2086 builder()->LoadTheHole(); 2087 break; 2088 case Literal::kString: 2089 builder()->LoadLiteral(expr->AsRawString()); 2090 execution_result()->SetResultIsString(); 2091 break; 2092 case Literal::kSymbol: 2093 builder()->LoadLiteral(expr->AsSymbol()); 2094 break; 2095 case Literal::kBigInt: 2096 builder()->LoadLiteral(expr->AsBigInt()); 2097 break; 2098 } 2099 } 2100 2101 void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { 2102 // Materialize a regular expression literal. 2103 builder()->CreateRegExpLiteral( 2104 expr->raw_pattern(), feedback_index(feedback_spec()->AddLiteralSlot()), 2105 expr->flags()); 2106 } 2107 2108 void BytecodeGenerator::BuildCreateObjectLiteral(Register literal, 2109 uint8_t flags, size_t entry) { 2110 if (ShouldOptimizeAsOneShot()) { 2111 RegisterList args = register_allocator()->NewRegisterList(2); 2112 builder() 2113 ->LoadConstantPoolEntry(entry) 2114 .StoreAccumulatorInRegister(args[0]) 2115 .LoadLiteral(Smi::FromInt(flags)) 2116 .StoreAccumulatorInRegister(args[1]) 2117 .CallRuntime(Runtime::kCreateObjectLiteralWithoutAllocationSite, args) 2118 .StoreAccumulatorInRegister(literal); 2119 2120 } else { 2121 // TODO(cbruni): Directly generate runtime call for literals we cannot 2122 // optimize once the CreateShallowObjectLiteral stub is in sync with the TF 2123 // optimizations. 2124 int literal_index = feedback_index(feedback_spec()->AddLiteralSlot()); 2125 builder()->CreateObjectLiteral(entry, literal_index, flags, literal); 2126 } 2127 } 2128 2129 void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { 2130 expr->InitDepthAndFlags(); 2131 2132 // Fast path for the empty object literal which doesn't need an 2133 // AllocationSite. 2134 if (expr->IsEmptyObjectLiteral()) { 2135 DCHECK(expr->IsFastCloningSupported()); 2136 builder()->CreateEmptyObjectLiteral(); 2137 return; 2138 } 2139 2140 // Deep-copy the literal boilerplate. 2141 uint8_t flags = CreateObjectLiteralFlags::Encode( 2142 expr->ComputeFlags(), expr->IsFastCloningSupported()); 2143 2144 Register literal = register_allocator()->NewRegister(); 2145 2146 // Create literal object. 2147 int property_index = 0; 2148 bool clone_object_spread = 2149 expr->properties()->first()->kind() == ObjectLiteral::Property::SPREAD; 2150 if (clone_object_spread) { 2151 // Avoid the slow path for spreads in the following common cases: 2152 // 1) `let obj = { ...source }` 2153 // 2) `let obj = { ...source, override: 1 }` 2154 // 3) `let obj = { ...source, ...overrides }` 2155 RegisterAllocationScope register_scope(this); 2156 Expression* property = expr->properties()->first()->value(); 2157 Register from_value = VisitForRegisterValue(property); 2158 2159 BytecodeLabels clone_object(zone()); 2160 builder()->JumpIfUndefined(clone_object.New()); 2161 builder()->JumpIfNull(clone_object.New()); 2162 builder()->ToObject(from_value); 2163 2164 clone_object.Bind(builder()); 2165 int clone_index = feedback_index(feedback_spec()->AddCloneObjectSlot()); 2166 builder()->CloneObject(from_value, flags, clone_index); 2167 builder()->StoreAccumulatorInRegister(literal); 2168 property_index++; 2169 } else { 2170 size_t entry; 2171 // If constant properties is an empty fixed array, use a cached empty fixed 2172 // array to ensure it's only added to the constant pool once. 2173 if (expr->properties_count() == 0) { 2174 entry = builder()->EmptyObjectBoilerplateDescriptionConstantPoolEntry(); 2175 } else { 2176 entry = builder()->AllocateDeferredConstantPoolEntry(); 2177 object_literals_.push_back(std::make_pair(expr, entry)); 2178 } 2179 BuildCreateObjectLiteral(literal, flags, entry); 2180 } 2181 2182 // Store computed values into the literal. 2183 AccessorTable accessor_table(zone()); 2184 for (; property_index < expr->properties()->length(); property_index++) { 2185 ObjectLiteral::Property* property = expr->properties()->at(property_index); 2186 if (property->is_computed_name()) break; 2187 if (!clone_object_spread && property->IsCompileTimeValue()) continue; 2188 2189 RegisterAllocationScope inner_register_scope(this); 2190 Literal* key = property->key()->AsLiteral(); 2191 switch (property->kind()) { 2192 case ObjectLiteral::Property::SPREAD: 2193 UNREACHABLE(); 2194 case ObjectLiteral::Property::CONSTANT: 2195 case ObjectLiteral::Property::MATERIALIZED_LITERAL: 2196 DCHECK(clone_object_spread || !property->value()->IsCompileTimeValue()); 2197 V8_FALLTHROUGH; 2198 case ObjectLiteral::Property::COMPUTED: { 2199 // It is safe to use [[Put]] here because the boilerplate already 2200 // contains computed properties with an uninitialized value. 2201 if (key->IsStringLiteral()) { 2202 DCHECK(key->IsPropertyName()); 2203 if (property->emit_store()) { 2204 builder()->SetExpressionPosition(property->value()); 2205 VisitForAccumulatorValue(property->value()); 2206 FeedbackSlot slot = feedback_spec()->AddStoreOwnICSlot(); 2207 if (FunctionLiteral::NeedsHomeObject(property->value())) { 2208 RegisterAllocationScope register_scope(this); 2209 Register value = register_allocator()->NewRegister(); 2210 builder()->StoreAccumulatorInRegister(value); 2211 builder()->StoreNamedOwnProperty( 2212 literal, key->AsRawPropertyName(), feedback_index(slot)); 2213 VisitSetHomeObject(value, literal, property); 2214 } else { 2215 builder()->StoreNamedOwnProperty( 2216 literal, key->AsRawPropertyName(), feedback_index(slot)); 2217 } 2218 } else { 2219 builder()->SetExpressionPosition(property->value()); 2220 VisitForEffect(property->value()); 2221 } 2222 } else { 2223 RegisterList args = register_allocator()->NewRegisterList(4); 2224 2225 builder()->MoveRegister(literal, args[0]); 2226 builder()->SetExpressionPosition(property->key()); 2227 VisitForRegisterValue(property->key(), args[1]); 2228 builder()->SetExpressionPosition(property->value()); 2229 VisitForRegisterValue(property->value(), args[2]); 2230 if (property->emit_store()) { 2231 builder() 2232 ->LoadLiteral(Smi::FromEnum(LanguageMode::kSloppy)) 2233 .StoreAccumulatorInRegister(args[3]) 2234 .CallRuntime(Runtime::kSetProperty, args); 2235 Register value = args[2]; 2236 VisitSetHomeObject(value, literal, property); 2237 } 2238 } 2239 break; 2240 } 2241 case ObjectLiteral::Property::PROTOTYPE: { 2242 // __proto__:null is handled by CreateObjectLiteral. 2243 if (property->IsNullPrototype()) break; 2244 DCHECK(property->emit_store()); 2245 DCHECK(!property->NeedsSetFunctionName()); 2246 RegisterList args = register_allocator()->NewRegisterList(2); 2247 builder()->MoveRegister(literal, args[0]); 2248 builder()->SetExpressionPosition(property->value()); 2249 VisitForRegisterValue(property->value(), args[1]); 2250 builder()->CallRuntime(Runtime::kInternalSetPrototype, args); 2251 break; 2252 } 2253 case ObjectLiteral::Property::GETTER: 2254 if (property->emit_store()) { 2255 accessor_table.lookup(key)->second->getter = property; 2256 } 2257 break; 2258 case ObjectLiteral::Property::SETTER: 2259 if (property->emit_store()) { 2260 accessor_table.lookup(key)->second->setter = property; 2261 } 2262 break; 2263 } 2264 } 2265 2266 // Define accessors, using only a single call to the runtime for each pair of 2267 // corresponding getters and setters. 2268 for (AccessorTable::Iterator it = accessor_table.begin(); 2269 it != accessor_table.end(); ++it) { 2270 RegisterAllocationScope inner_register_scope(this); 2271 RegisterList args = register_allocator()->NewRegisterList(5); 2272 builder()->MoveRegister(literal, args[0]); 2273 VisitForRegisterValue(it->first, args[1]); 2274 VisitObjectLiteralAccessor(literal, it->second->getter, args[2]); 2275 VisitObjectLiteralAccessor(literal, it->second->setter, args[3]); 2276 builder() 2277 ->LoadLiteral(Smi::FromInt(NONE)) 2278 .StoreAccumulatorInRegister(args[4]) 2279 .CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, args); 2280 } 2281 2282 // Object literals have two parts. The "static" part on the left contains no 2283 // computed property names, and so we can compute its map ahead of time; see 2284 // Runtime_CreateObjectLiteralBoilerplate. The second "dynamic" part starts 2285 // with the first computed property name and continues with all properties to 2286 // its right. All the code from above initializes the static component of the 2287 // object literal, and arranges for the map of the result to reflect the 2288 // static order in which the keys appear. For the dynamic properties, we 2289 // compile them into a series of "SetOwnProperty" runtime calls. This will 2290 // preserve insertion order. 2291 for (; property_index < expr->properties()->length(); property_index++) { 2292 ObjectLiteral::Property* property = expr->properties()->at(property_index); 2293 RegisterAllocationScope inner_register_scope(this); 2294 2295 if (property->IsPrototype()) { 2296 // __proto__:null is handled by CreateObjectLiteral. 2297 if (property->IsNullPrototype()) continue; 2298 DCHECK(property->emit_store()); 2299 DCHECK(!property->NeedsSetFunctionName()); 2300 RegisterList args = register_allocator()->NewRegisterList(2); 2301 builder()->MoveRegister(literal, args[0]); 2302 builder()->SetExpressionPosition(property->value()); 2303 VisitForRegisterValue(property->value(), args[1]); 2304 builder()->CallRuntime(Runtime::kInternalSetPrototype, args); 2305 continue; 2306 } 2307 2308 switch (property->kind()) { 2309 case ObjectLiteral::Property::CONSTANT: 2310 case ObjectLiteral::Property::COMPUTED: 2311 case ObjectLiteral::Property::MATERIALIZED_LITERAL: { 2312 Register key = register_allocator()->NewRegister(); 2313 BuildLoadPropertyKey(property, key); 2314 builder()->SetExpressionPosition(property->value()); 2315 Register value = VisitForRegisterValue(property->value()); 2316 VisitSetHomeObject(value, literal, property); 2317 2318 DataPropertyInLiteralFlags data_property_flags = 2319 DataPropertyInLiteralFlag::kNoFlags; 2320 if (property->NeedsSetFunctionName()) { 2321 data_property_flags |= DataPropertyInLiteralFlag::kSetFunctionName; 2322 } 2323 2324 FeedbackSlot slot = 2325 feedback_spec()->AddStoreDataPropertyInLiteralICSlot(); 2326 builder() 2327 ->LoadAccumulatorWithRegister(value) 2328 .StoreDataPropertyInLiteral(literal, key, data_property_flags, 2329 feedback_index(slot)); 2330 break; 2331 } 2332 case ObjectLiteral::Property::GETTER: 2333 case ObjectLiteral::Property::SETTER: { 2334 RegisterList args = register_allocator()->NewRegisterList(4); 2335 builder()->MoveRegister(literal, args[0]); 2336 BuildLoadPropertyKey(property, args[1]); 2337 builder()->SetExpressionPosition(property->value()); 2338 VisitForRegisterValue(property->value(), args[2]); 2339 VisitSetHomeObject(args[2], literal, property); 2340 builder() 2341 ->LoadLiteral(Smi::FromInt(NONE)) 2342 .StoreAccumulatorInRegister(args[3]); 2343 Runtime::FunctionId function_id = 2344 property->kind() == ObjectLiteral::Property::GETTER 2345 ? Runtime::kDefineGetterPropertyUnchecked 2346 : Runtime::kDefineSetterPropertyUnchecked; 2347 builder()->CallRuntime(function_id, args); 2348 break; 2349 } 2350 case ObjectLiteral::Property::SPREAD: { 2351 RegisterList args = register_allocator()->NewRegisterList(2); 2352 builder()->MoveRegister(literal, args[0]); 2353 builder()->SetExpressionPosition(property->value()); 2354 VisitForRegisterValue(property->value(), args[1]); 2355 builder()->CallRuntime(Runtime::kCopyDataProperties, args); 2356 break; 2357 } 2358 case ObjectLiteral::Property::PROTOTYPE: 2359 UNREACHABLE(); // Handled specially above. 2360 break; 2361 } 2362 } 2363 2364 builder()->LoadAccumulatorWithRegister(literal); 2365 } 2366 2367 void BytecodeGenerator::BuildArrayLiteralElementsInsertion( 2368 Register array, int first_spread_index, ZonePtrList<Expression>* elements, 2369 bool skip_constants) { 2370 DCHECK_LT(first_spread_index, elements->length()); 2371 2372 Register index = register_allocator()->NewRegister(); 2373 int array_index = 0; 2374 2375 ZonePtrList<Expression>::iterator iter = elements->begin(); 2376 ZonePtrList<Expression>::iterator first_spread_or_end = 2377 first_spread_index >= 0 ? elements->begin() + first_spread_index 2378 : elements->end(); 2379 2380 // Evaluate subexpressions and store them into the array. 2381 FeedbackSlot keyed_store_slot; 2382 for (; iter != first_spread_or_end; ++iter, array_index++) { 2383 Expression* subexpr = *iter; 2384 DCHECK(!subexpr->IsSpread()); 2385 if (skip_constants && subexpr->IsCompileTimeValue()) continue; 2386 if (keyed_store_slot.IsInvalid()) { 2387 keyed_store_slot = feedback_spec()->AddKeyedStoreICSlot(language_mode()); 2388 } 2389 builder() 2390 ->LoadLiteral(Smi::FromInt(array_index)) 2391 .StoreAccumulatorInRegister(index); 2392 VisitForAccumulatorValue(subexpr); 2393 builder()->StoreKeyedProperty( 2394 array, index, feedback_index(keyed_store_slot), language_mode()); 2395 } 2396 if (iter != elements->end()) { 2397 builder()->LoadLiteral(array_index).StoreAccumulatorInRegister(index); 2398 2399 // Handle the first spread element and everything that follows. 2400 FeedbackSlot element_slot = feedback_spec()->AddStoreInArrayLiteralICSlot(); 2401 FeedbackSlot index_slot = feedback_spec()->AddBinaryOpICSlot(); 2402 // TODO(neis): Only create length_slot when there are holes. 2403 FeedbackSlot length_slot = 2404 feedback_spec()->AddStoreICSlot(LanguageMode::kStrict); 2405 for (; iter != elements->end(); ++iter) { 2406 Expression* subexpr = *iter; 2407 if (subexpr->IsSpread()) { 2408 BuildArrayLiteralSpread(subexpr->AsSpread(), array, index, index_slot, 2409 element_slot); 2410 } else if (!subexpr->IsTheHoleLiteral()) { 2411 // literal[index++] = subexpr 2412 VisitForAccumulatorValue(subexpr); 2413 builder() 2414 ->StoreInArrayLiteral(array, index, feedback_index(element_slot)) 2415 .LoadAccumulatorWithRegister(index) 2416 .UnaryOperation(Token::INC, feedback_index(index_slot)) 2417 .StoreAccumulatorInRegister(index); 2418 } else { 2419 // literal.length = ++index 2420 auto length = ast_string_constants()->length_string(); 2421 builder() 2422 ->LoadAccumulatorWithRegister(index) 2423 .UnaryOperation(Token::INC, feedback_index(index_slot)) 2424 .StoreAccumulatorInRegister(index) 2425 .StoreNamedProperty(array, length, feedback_index(length_slot), 2426 LanguageMode::kStrict); 2427 } 2428 } 2429 } 2430 builder()->LoadAccumulatorWithRegister(array); 2431 } 2432 2433 void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { 2434 expr->InitDepthAndFlags(); 2435 uint8_t flags = CreateArrayLiteralFlags::Encode( 2436 expr->IsFastCloningSupported(), expr->ComputeFlags()); 2437 2438 bool is_empty = expr->is_empty(); 2439 bool optimize_as_one_shot = ShouldOptimizeAsOneShot(); 2440 size_t entry; 2441 if (is_empty && optimize_as_one_shot) { 2442 entry = builder()->EmptyArrayBoilerplateDescriptionConstantPoolEntry(); 2443 } else if (!is_empty) { 2444 entry = builder()->AllocateDeferredConstantPoolEntry(); 2445 array_literals_.push_back(std::make_pair(expr, entry)); 2446 } 2447 2448 if (optimize_as_one_shot) { 2449 // Create array literal without any allocation sites 2450 RegisterAllocationScope register_scope(this); 2451 RegisterList args = register_allocator()->NewRegisterList(2); 2452 builder() 2453 ->LoadConstantPoolEntry(entry) 2454 .StoreAccumulatorInRegister(args[0]) 2455 .LoadLiteral(Smi::FromInt(flags)) 2456 .StoreAccumulatorInRegister(args[1]) 2457 .CallRuntime(Runtime::kCreateArrayLiteralWithoutAllocationSite, args); 2458 } else if (is_empty) { 2459 // Empty array literal fast-path. 2460 int literal_index = feedback_index(feedback_spec()->AddLiteralSlot()); 2461 DCHECK(expr->IsFastCloningSupported()); 2462 builder()->CreateEmptyArrayLiteral(literal_index); 2463 return; 2464 } else { 2465 // Deep-copy the literal boilerplate 2466 int literal_index = feedback_index(feedback_spec()->AddLiteralSlot()); 2467 builder()->CreateArrayLiteral(entry, literal_index, flags); 2468 } 2469 2470 Register literal = register_allocator()->NewRegister(); 2471 builder()->StoreAccumulatorInRegister(literal); 2472 // Insert all elements except the constant ones, since they are already there. 2473 BuildArrayLiteralElementsInsertion(literal, expr->first_spread_index(), 2474 expr->values(), true); 2475 } 2476 2477 void BytecodeGenerator::BuildArrayLiteralSpread(Spread* spread, Register array, 2478 Register index, 2479 FeedbackSlot index_slot, 2480 FeedbackSlot element_slot) { 2481 RegisterAllocationScope register_scope(this); 2482 Register value = register_allocator()->NewRegister(); 2483 2484 builder()->SetExpressionAsStatementPosition(spread->expression()); 2485 IteratorRecord iterator = 2486 BuildGetIteratorRecord(spread->expression(), IteratorType::kNormal); 2487 2488 LoopBuilder loop_builder(builder(), nullptr, nullptr); 2489 loop_builder.LoopHeader(); 2490 2491 // Call the iterator's .next() method. Break from the loop if the `done` 2492 // property is truthy, otherwise load the value from the iterator result and 2493 // append the argument. 2494 BuildIteratorNext(iterator, value); 2495 builder()->LoadNamedProperty( 2496 value, ast_string_constants()->done_string(), 2497 feedback_index(feedback_spec()->AddLoadICSlot())); 2498 loop_builder.BreakIfTrue(ToBooleanMode::kConvertToBoolean); 2499 2500 loop_builder.LoopBody(); 2501 builder() 2502 // value = value.value 2503 ->LoadNamedProperty(value, ast_string_constants()->value_string(), 2504 feedback_index(feedback_spec()->AddLoadICSlot())) 2505 .StoreAccumulatorInRegister(value) 2506 // array[index] = value 2507 .StoreInArrayLiteral(array, index, feedback_index(element_slot)) 2508 // index++ 2509 .LoadAccumulatorWithRegister(index) 2510 .UnaryOperation(Token::INC, feedback_index(index_slot)) 2511 .StoreAccumulatorInRegister(index); 2512 loop_builder.BindContinueTarget(); 2513 loop_builder.JumpToHeader(loop_depth_); 2514 } 2515 2516 void BytecodeGenerator::VisitStoreInArrayLiteral(StoreInArrayLiteral* expr) { 2517 builder()->SetExpressionAsStatementPosition(expr); 2518 RegisterAllocationScope register_scope(this); 2519 Register array = register_allocator()->NewRegister(); 2520 Register index = register_allocator()->NewRegister(); 2521 VisitForRegisterValue(expr->array(), array); 2522 VisitForRegisterValue(expr->index(), index); 2523 VisitForAccumulatorValue(expr->value()); 2524 builder()->StoreInArrayLiteral( 2525 array, index, 2526 feedback_index(feedback_spec()->AddStoreInArrayLiteralICSlot())); 2527 } 2528 2529 void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) { 2530 builder()->SetExpressionPosition(proxy); 2531 BuildVariableLoad(proxy->var(), proxy->hole_check_mode()); 2532 } 2533 2534 void BytecodeGenerator::BuildVariableLoad(Variable* variable, 2535 HoleCheckMode hole_check_mode, 2536 TypeofMode typeof_mode) { 2537 switch (variable->location()) { 2538 case VariableLocation::LOCAL: { 2539 Register source(builder()->Local(variable->index())); 2540 // We need to load the variable into the accumulator, even when in a 2541 // VisitForRegisterScope, in order to avoid register aliasing if 2542 // subsequent expressions assign to the same variable. 2543 builder()->LoadAccumulatorWithRegister(source); 2544 if (hole_check_mode == HoleCheckMode::kRequired) { 2545 BuildThrowIfHole(variable); 2546 } 2547 break; 2548 } 2549 case VariableLocation::PARAMETER: { 2550 Register source; 2551 if (variable->IsReceiver()) { 2552 source = builder()->Receiver(); 2553 } else { 2554 source = builder()->Parameter(variable->index()); 2555 } 2556 // We need to load the variable into the accumulator, even when in a 2557 // VisitForRegisterScope, in order to avoid register aliasing if 2558 // subsequent expressions assign to the same variable. 2559 builder()->LoadAccumulatorWithRegister(source); 2560 if (hole_check_mode == HoleCheckMode::kRequired) { 2561 BuildThrowIfHole(variable); 2562 } 2563 break; 2564 } 2565 case VariableLocation::UNALLOCATED: { 2566 // The global identifier "undefined" is immutable. Everything 2567 // else could be reassigned. For performance, we do a pointer comparison 2568 // rather than checking if the raw_name is really "undefined". 2569 if (variable->raw_name() == ast_string_constants()->undefined_string()) { 2570 builder()->LoadUndefined(); 2571 } else { 2572 FeedbackSlot slot = GetCachedLoadGlobalICSlot(typeof_mode, variable); 2573 builder()->LoadGlobal(variable->raw_name(), feedback_index(slot), 2574 typeof_mode); 2575 } 2576 break; 2577 } 2578 case VariableLocation::CONTEXT: { 2579 int depth = execution_context()->ContextChainDepth(variable->scope()); 2580 ContextScope* context = execution_context()->Previous(depth); 2581 Register context_reg; 2582 if (context) { 2583 context_reg = context->reg(); 2584 depth = 0; 2585 } else { 2586 context_reg = execution_context()->reg(); 2587 } 2588 2589 BytecodeArrayBuilder::ContextSlotMutability immutable = 2590 (variable->maybe_assigned() == kNotAssigned) 2591 ? BytecodeArrayBuilder::kImmutableSlot 2592 : BytecodeArrayBuilder::kMutableSlot; 2593 2594 builder()->LoadContextSlot(context_reg, variable->index(), depth, 2595 immutable); 2596 if (hole_check_mode == HoleCheckMode::kRequired) { 2597 BuildThrowIfHole(variable); 2598 } 2599 break; 2600 } 2601 case VariableLocation::LOOKUP: { 2602 switch (variable->mode()) { 2603 case VariableMode::kDynamicLocal: { 2604 Variable* local_variable = variable->local_if_not_shadowed(); 2605 int depth = 2606 execution_context()->ContextChainDepth(local_variable->scope()); 2607 builder()->LoadLookupContextSlot(variable->raw_name(), typeof_mode, 2608 local_variable->index(), depth); 2609 if (hole_check_mode == HoleCheckMode::kRequired) { 2610 BuildThrowIfHole(variable); 2611 } 2612 break; 2613 } 2614 case VariableMode::kDynamicGlobal: { 2615 int depth = 2616 current_scope()->ContextChainLengthUntilOutermostSloppyEval(); 2617 FeedbackSlot slot = GetCachedLoadGlobalICSlot(typeof_mode, variable); 2618 builder()->LoadLookupGlobalSlot(variable->raw_name(), typeof_mode, 2619 feedback_index(slot), depth); 2620 break; 2621 } 2622 default: 2623 builder()->LoadLookupSlot(variable->raw_name(), typeof_mode); 2624 } 2625 break; 2626 } 2627 case VariableLocation::MODULE: { 2628 int depth = execution_context()->ContextChainDepth(variable->scope()); 2629 builder()->LoadModuleVariable(variable->index(), depth); 2630 if (hole_check_mode == HoleCheckMode::kRequired) { 2631 BuildThrowIfHole(variable); 2632 } 2633 break; 2634 } 2635 } 2636 } 2637 2638 void BytecodeGenerator::BuildVariableLoadForAccumulatorValue( 2639 Variable* variable, HoleCheckMode hole_check_mode, TypeofMode typeof_mode) { 2640 ValueResultScope accumulator_result(this); 2641 BuildVariableLoad(variable, hole_check_mode, typeof_mode); 2642 } 2643 2644 void BytecodeGenerator::BuildReturn(int source_position) { 2645 if (FLAG_trace) { 2646 RegisterAllocationScope register_scope(this); 2647 Register result = register_allocator()->NewRegister(); 2648 // Runtime returns {result} value, preserving accumulator. 2649 builder()->StoreAccumulatorInRegister(result).CallRuntime( 2650 Runtime::kTraceExit, result); 2651 } 2652 if (info()->collect_type_profile()) { 2653 builder()->CollectTypeProfile(info()->literal()->return_position()); 2654 } 2655 builder()->SetReturnPosition(source_position, info()->literal()); 2656 builder()->Return(); 2657 } 2658 2659 void BytecodeGenerator::BuildAsyncReturn(int source_position) { 2660 RegisterAllocationScope register_scope(this); 2661 2662 if (IsAsyncGeneratorFunction(info()->literal()->kind())) { 2663 RegisterList args = register_allocator()->NewRegisterList(3); 2664 builder() 2665 ->MoveRegister(generator_object(), args[0]) // generator 2666 .StoreAccumulatorInRegister(args[1]) // value 2667 .LoadTrue() 2668 .StoreAccumulatorInRegister(args[2]) // done 2669 .CallRuntime(Runtime::kInlineAsyncGeneratorResolve, args); 2670 } else { 2671 DCHECK(IsAsyncFunction(info()->literal()->kind())); 2672 RegisterList args = register_allocator()->NewRegisterList(2); 2673 Register promise = args[0]; 2674 Register return_value = args[1]; 2675 builder()->StoreAccumulatorInRegister(return_value); 2676 2677 Variable* var_promise = closure_scope()->promise_var(); 2678 DCHECK_NOT_NULL(var_promise); 2679 BuildVariableLoad(var_promise, HoleCheckMode::kElided); 2680 builder() 2681 ->StoreAccumulatorInRegister(promise) 2682 .CallRuntime(Runtime::kInlineResolvePromise, args) 2683 .LoadAccumulatorWithRegister(promise); 2684 } 2685 2686 BuildReturn(source_position); 2687 } 2688 2689 void BytecodeGenerator::BuildReThrow() { builder()->ReThrow(); } 2690 2691 void BytecodeGenerator::BuildThrowIfHole(Variable* variable) { 2692 if (variable->is_this()) { 2693 DCHECK(variable->mode() == VariableMode::kConst); 2694 builder()->ThrowSuperNotCalledIfHole(); 2695 } else { 2696 builder()->ThrowReferenceErrorIfHole(variable->raw_name()); 2697 } 2698 } 2699 2700 void BytecodeGenerator::BuildHoleCheckForVariableAssignment(Variable* variable, 2701 Token::Value op) { 2702 if (variable->is_this() && variable->mode() == VariableMode::kConst && 2703 op == Token::INIT) { 2704 // Perform an initialization check for 'this'. 'this' variable is the 2705 // only variable able to trigger bind operations outside the TDZ 2706 // via 'super' calls. 2707 builder()->ThrowSuperAlreadyCalledIfNotHole(); 2708 } else { 2709 // Perform an initialization check for let/const declared variables. 2710 // E.g. let x = (x = 20); is not allowed. 2711 DCHECK(IsLexicalVariableMode(variable->mode())); 2712 BuildThrowIfHole(variable); 2713 } 2714 } 2715 2716 void BytecodeGenerator::BuildVariableAssignment( 2717 Variable* variable, Token::Value op, HoleCheckMode hole_check_mode, 2718 LookupHoistingMode lookup_hoisting_mode) { 2719 VariableMode mode = variable->mode(); 2720 RegisterAllocationScope assignment_register_scope(this); 2721 BytecodeLabel end_label; 2722 switch (variable->location()) { 2723 case VariableLocation::PARAMETER: 2724 case VariableLocation::LOCAL: { 2725 Register destination; 2726 if (VariableLocation::PARAMETER == variable->location()) { 2727 if (variable->IsReceiver()) { 2728 destination = builder()->Receiver(); 2729 } else { 2730 destination = builder()->Parameter(variable->index()); 2731 } 2732 } else { 2733 destination = builder()->Local(variable->index()); 2734 } 2735 2736 if (hole_check_mode == HoleCheckMode::kRequired) { 2737 // Load destination to check for hole. 2738 Register value_temp = register_allocator()->NewRegister(); 2739 builder() 2740 ->StoreAccumulatorInRegister(value_temp) 2741 .LoadAccumulatorWithRegister(destination); 2742 2743 BuildHoleCheckForVariableAssignment(variable, op); 2744 builder()->LoadAccumulatorWithRegister(value_temp); 2745 } 2746 2747 if (mode != VariableMode::kConst || op == Token::INIT) { 2748 builder()->StoreAccumulatorInRegister(destination); 2749 } else if (variable->throw_on_const_assignment(language_mode())) { 2750 builder()->CallRuntime(Runtime::kThrowConstAssignError); 2751 } 2752 break; 2753 } 2754 case VariableLocation::UNALLOCATED: { 2755 FeedbackSlot slot = GetCachedStoreGlobalICSlot(language_mode(), variable); 2756 builder()->StoreGlobal(variable->raw_name(), feedback_index(slot)); 2757 break; 2758 } 2759 case VariableLocation::CONTEXT: { 2760 int depth = execution_context()->ContextChainDepth(variable->scope()); 2761 ContextScope* context = execution_context()->Previous(depth); 2762 Register context_reg; 2763 2764 if (context) { 2765 context_reg = context->reg(); 2766 depth = 0; 2767 } else { 2768 context_reg = execution_context()->reg(); 2769 } 2770 2771 if (hole_check_mode == HoleCheckMode::kRequired) { 2772 // Load destination to check for hole. 2773 Register value_temp = register_allocator()->NewRegister(); 2774 builder() 2775 ->StoreAccumulatorInRegister(value_temp) 2776 .LoadContextSlot(context_reg, variable->index(), depth, 2777 BytecodeArrayBuilder::kMutableSlot); 2778 2779 BuildHoleCheckForVariableAssignment(variable, op); 2780 builder()->LoadAccumulatorWithRegister(value_temp); 2781 } 2782 2783 if (mode != VariableMode::kConst || op == Token::INIT) { 2784 builder()->StoreContextSlot(context_reg, variable->index(), depth); 2785 } else if (variable->throw_on_const_assignment(language_mode())) { 2786 builder()->CallRuntime(Runtime::kThrowConstAssignError); 2787 } 2788 break; 2789 } 2790 case VariableLocation::LOOKUP: { 2791 builder()->StoreLookupSlot(variable->raw_name(), language_mode(), 2792 lookup_hoisting_mode); 2793 break; 2794 } 2795 case VariableLocation::MODULE: { 2796 DCHECK(IsDeclaredVariableMode(mode)); 2797 2798 if (mode == VariableMode::kConst && op != Token::INIT) { 2799 builder()->CallRuntime(Runtime::kThrowConstAssignError); 2800 break; 2801 } 2802 2803 // If we don't throw above, we know that we're dealing with an 2804 // export because imports are const and we do not generate initializing 2805 // assignments for them. 2806 DCHECK(variable->IsExport()); 2807 2808 int depth = execution_context()->ContextChainDepth(variable->scope()); 2809 if (hole_check_mode == HoleCheckMode::kRequired) { 2810 Register value_temp = register_allocator()->NewRegister(); 2811 builder() 2812 ->StoreAccumulatorInRegister(value_temp) 2813 .LoadModuleVariable(variable->index(), depth); 2814 BuildHoleCheckForVariableAssignment(variable, op); 2815 builder()->LoadAccumulatorWithRegister(value_temp); 2816 } 2817 builder()->StoreModuleVariable(variable->index(), depth); 2818 break; 2819 } 2820 } 2821 } 2822 2823 void BytecodeGenerator::BuildLoadNamedProperty(Property* property, 2824 Register object, 2825 const AstRawString* name) { 2826 if (ShouldOptimizeAsOneShot()) { 2827 RegisterList args = register_allocator()->NewRegisterList(2); 2828 size_t name_index = builder()->GetConstantPoolEntry(name); 2829 builder() 2830 ->MoveRegister(object, args[0]) 2831 .LoadConstantPoolEntry(name_index) 2832 .StoreAccumulatorInRegister(args[1]) 2833 .CallRuntime(Runtime::kInlineGetProperty, args); 2834 } else { 2835 FeedbackSlot slot = GetCachedLoadICSlot(property->obj(), name); 2836 builder()->LoadNamedProperty(object, name, feedback_index(slot)); 2837 } 2838 } 2839 2840 void BytecodeGenerator::BuildStoreNamedProperty(Property* property, 2841 Register object, 2842 const AstRawString* name) { 2843 Register value; 2844 if (!execution_result()->IsEffect()) { 2845 value = register_allocator()->NewRegister(); 2846 builder()->StoreAccumulatorInRegister(value); 2847 } 2848 2849 if (ShouldOptimizeAsOneShot()) { 2850 RegisterList args = register_allocator()->NewRegisterList(4); 2851 size_t name_index = builder()->GetConstantPoolEntry(name); 2852 builder() 2853 ->MoveRegister(object, args[0]) 2854 .StoreAccumulatorInRegister(args[2]) 2855 .LoadConstantPoolEntry(name_index) 2856 .StoreAccumulatorInRegister(args[1]) 2857 .LoadLiteral(Smi::FromEnum(language_mode())) 2858 .StoreAccumulatorInRegister(args[3]) 2859 .CallRuntime(Runtime::kSetProperty, args); 2860 } else { 2861 FeedbackSlot slot = GetCachedStoreICSlot(property->obj(), name); 2862 builder()->StoreNamedProperty(object, name, feedback_index(slot), 2863 language_mode()); 2864 } 2865 2866 if (!execution_result()->IsEffect()) { 2867 builder()->LoadAccumulatorWithRegister(value); 2868 } 2869 } 2870 2871 void BytecodeGenerator::VisitAssignment(Assignment* expr) { 2872 DCHECK(expr->target()->IsValidReferenceExpression() || 2873 (expr->op() == Token::INIT && expr->target()->IsVariableProxy() && 2874 expr->target()->AsVariableProxy()->is_this())); 2875 Register object, key; 2876 RegisterList super_property_args; 2877 const AstRawString* name; 2878 2879 // Left-hand side can only be a property, a global or a variable slot. 2880 Property* property = expr->target()->AsProperty(); 2881 LhsKind assign_type = Property::GetAssignType(property); 2882 2883 // Evaluate LHS expression. 2884 switch (assign_type) { 2885 case VARIABLE: 2886 // Nothing to do to evaluate variable assignment LHS. 2887 break; 2888 case NAMED_PROPERTY: { 2889 object = VisitForRegisterValue(property->obj()); 2890 name = property->key()->AsLiteral()->AsRawPropertyName(); 2891 break; 2892 } 2893 case KEYED_PROPERTY: { 2894 object = VisitForRegisterValue(property->obj()); 2895 key = VisitForRegisterValue(property->key()); 2896 break; 2897 } 2898 case NAMED_SUPER_PROPERTY: { 2899 super_property_args = register_allocator()->NewRegisterList(4); 2900 SuperPropertyReference* super_property = 2901 property->obj()->AsSuperPropertyReference(); 2902 VisitForRegisterValue(super_property->this_var(), super_property_args[0]); 2903 VisitForRegisterValue(super_property->home_object(), 2904 super_property_args[1]); 2905 builder() 2906 ->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName()) 2907 .StoreAccumulatorInRegister(super_property_args[2]); 2908 break; 2909 } 2910 case KEYED_SUPER_PROPERTY: { 2911 super_property_args = register_allocator()->NewRegisterList(4); 2912 SuperPropertyReference* super_property = 2913 property->obj()->AsSuperPropertyReference(); 2914 VisitForRegisterValue(super_property->this_var(), super_property_args[0]); 2915 VisitForRegisterValue(super_property->home_object(), 2916 super_property_args[1]); 2917 VisitForRegisterValue(property->key(), super_property_args[2]); 2918 break; 2919 } 2920 } 2921 2922 // Evaluate the value and potentially handle compound assignments by loading 2923 // the left-hand side value and performing a binary operation. 2924 if (expr->IsCompoundAssignment()) { 2925 switch (assign_type) { 2926 case VARIABLE: { 2927 VariableProxy* proxy = expr->target()->AsVariableProxy(); 2928 BuildVariableLoad(proxy->var(), proxy->hole_check_mode()); 2929 break; 2930 } 2931 case NAMED_PROPERTY: { 2932 BuildLoadNamedProperty(property, object, name); 2933 break; 2934 } 2935 case KEYED_PROPERTY: { 2936 // Key is already in accumulator at this point due to evaluating the 2937 // LHS above. 2938 FeedbackSlot slot = feedback_spec()->AddKeyedLoadICSlot(); 2939 builder()->LoadKeyedProperty(object, feedback_index(slot)); 2940 break; 2941 } 2942 case NAMED_SUPER_PROPERTY: { 2943 builder()->CallRuntime(Runtime::kLoadFromSuper, 2944 super_property_args.Truncate(3)); 2945 break; 2946 } 2947 case KEYED_SUPER_PROPERTY: { 2948 builder()->CallRuntime(Runtime::kLoadKeyedFromSuper, 2949 super_property_args.Truncate(3)); 2950 break; 2951 } 2952 } 2953 BinaryOperation* binop = expr->AsCompoundAssignment()->binary_operation(); 2954 FeedbackSlot slot = feedback_spec()->AddBinaryOpICSlot(); 2955 if (expr->value()->IsSmiLiteral()) { 2956 builder()->BinaryOperationSmiLiteral( 2957 binop->op(), expr->value()->AsLiteral()->AsSmiLiteral(), 2958 feedback_index(slot)); 2959 } else { 2960 Register old_value = register_allocator()->NewRegister(); 2961 builder()->StoreAccumulatorInRegister(old_value); 2962 VisitForAccumulatorValue(expr->value()); 2963 builder()->BinaryOperation(binop->op(), old_value, feedback_index(slot)); 2964 } 2965 } else { 2966 VisitForAccumulatorValue(expr->value()); 2967 } 2968 2969 // Store the value. 2970 builder()->SetExpressionPosition(expr); 2971 switch (assign_type) { 2972 case VARIABLE: { 2973 // TODO(oth): The BuildVariableAssignment() call is hard to reason about. 2974 // Is the value in the accumulator safe? Yes, but scary. 2975 VariableProxy* proxy = expr->target()->AsVariableProxy(); 2976 BuildVariableAssignment(proxy->var(), expr->op(), 2977 proxy->hole_check_mode(), 2978 expr->lookup_hoisting_mode()); 2979 break; 2980 } 2981 case NAMED_PROPERTY: { 2982 BuildStoreNamedProperty(property, object, name); 2983 break; 2984 } 2985 case KEYED_PROPERTY: { 2986 FeedbackSlot slot = feedback_spec()->AddKeyedStoreICSlot(language_mode()); 2987 Register value; 2988 if (!execution_result()->IsEffect()) { 2989 value = register_allocator()->NewRegister(); 2990 builder()->StoreAccumulatorInRegister(value); 2991 } 2992 builder()->StoreKeyedProperty(object, key, feedback_index(slot), 2993 language_mode()); 2994 if (!execution_result()->IsEffect()) { 2995 builder()->LoadAccumulatorWithRegister(value); 2996 } 2997 break; 2998 } 2999 case NAMED_SUPER_PROPERTY: { 3000 builder() 3001 ->StoreAccumulatorInRegister(super_property_args[3]) 3002 .CallRuntime(StoreToSuperRuntimeId(), super_property_args); 3003 break; 3004 } 3005 case KEYED_SUPER_PROPERTY: { 3006 builder() 3007 ->StoreAccumulatorInRegister(super_property_args[3]) 3008 .CallRuntime(StoreKeyedToSuperRuntimeId(), super_property_args); 3009 break; 3010 } 3011 } 3012 } 3013 3014 void BytecodeGenerator::VisitCompoundAssignment(CompoundAssignment* expr) { 3015 VisitAssignment(expr); 3016 } 3017 3018 // Suspends the generator to resume at the next suspend_id, with output stored 3019 // in the accumulator. When the generator is resumed, the sent value is loaded 3020 // in the accumulator. 3021 void BytecodeGenerator::BuildSuspendPoint(Expression* suspend_expr) { 3022 const int suspend_id = suspend_count_++; 3023 3024 RegisterList registers = register_allocator()->AllLiveRegisters(); 3025 3026 // Save context, registers, and state. This bytecode then returns the value 3027 // in the accumulator. 3028 builder()->SetExpressionPosition(suspend_expr); 3029 builder()->SuspendGenerator(generator_object(), registers, suspend_id); 3030 3031 // Upon resume, we continue here. 3032 builder()->Bind(generator_jump_table_, suspend_id); 3033 3034 // Clobbers all registers and sets the accumulator to the 3035 // [[input_or_debug_pos]] slot of the generator object. 3036 builder()->ResumeGenerator(generator_object(), registers); 3037 } 3038 3039 void BytecodeGenerator::VisitYield(Yield* expr) { 3040 builder()->SetExpressionPosition(expr); 3041 VisitForAccumulatorValue(expr->expression()); 3042 3043 // If this is not the first yield 3044 if (suspend_count_ > 0) { 3045 if (IsAsyncGeneratorFunction(function_kind())) { 3046 // AsyncGenerator yields (with the exception of the initial yield) 3047 // delegate work to the AsyncGeneratorYield stub, which Awaits the operand 3048 // and on success, wraps the value in an IteratorResult. 3049 RegisterAllocationScope register_scope(this); 3050 RegisterList args = register_allocator()->NewRegisterList(3); 3051 builder() 3052 ->MoveRegister(generator_object(), args[0]) // generator 3053 .StoreAccumulatorInRegister(args[1]) // value 3054 .LoadBoolean(catch_prediction() != HandlerTable::ASYNC_AWAIT) 3055 .StoreAccumulatorInRegister(args[2]) // is_caught 3056 .CallRuntime(Runtime::kInlineAsyncGeneratorYield, args); 3057 } else { 3058 // Generator yields (with the exception of the initial yield) wrap the 3059 // value into IteratorResult. 3060 RegisterAllocationScope register_scope(this); 3061 RegisterList args = register_allocator()->NewRegisterList(2); 3062 builder() 3063 ->StoreAccumulatorInRegister(args[0]) // value 3064 .LoadFalse() 3065 .StoreAccumulatorInRegister(args[1]) // done 3066 .CallRuntime(Runtime::kInlineCreateIterResultObject, args); 3067 } 3068 } 3069 3070 BuildSuspendPoint(expr); 3071 // At this point, the generator has been resumed, with the received value in 3072 // the accumulator. 3073 3074 // TODO(caitp): remove once yield* desugaring for async generators is handled 3075 // in BytecodeGenerator. 3076 if (expr->on_abrupt_resume() == Yield::kNoControl) { 3077 DCHECK(IsAsyncGeneratorFunction(function_kind())); 3078 return; 3079 } 3080 3081 Register input = register_allocator()->NewRegister(); 3082 builder()->StoreAccumulatorInRegister(input).CallRuntime( 3083 Runtime::kInlineGeneratorGetResumeMode, generator_object()); 3084 3085 // Now dispatch on resume mode. 3086 STATIC_ASSERT(JSGeneratorObject::kNext + 1 == JSGeneratorObject::kReturn); 3087 BytecodeJumpTable* jump_table = 3088 builder()->AllocateJumpTable(2, JSGeneratorObject::kNext); 3089 3090 builder()->SwitchOnSmiNoFeedback(jump_table); 3091 3092 { 3093 // Resume with throw (switch fallthrough). 3094 // TODO(leszeks): Add a debug-only check that the accumulator is 3095 // JSGeneratorObject::kThrow. 3096 builder()->SetExpressionPosition(expr); 3097 builder()->LoadAccumulatorWithRegister(input); 3098 builder()->Throw(); 3099 } 3100 3101 { 3102 // Resume with return. 3103 builder()->Bind(jump_table, JSGeneratorObject::kReturn); 3104 builder()->LoadAccumulatorWithRegister(input); 3105 if (IsAsyncGeneratorFunction(function_kind())) { 3106 execution_control()->AsyncReturnAccumulator(); 3107 } else { 3108 execution_control()->ReturnAccumulator(); 3109 } 3110 } 3111 3112 { 3113 // Resume with next. 3114 builder()->Bind(jump_table, JSGeneratorObject::kNext); 3115 BuildIncrementBlockCoverageCounterIfEnabled(expr, 3116 SourceRangeKind::kContinuation); 3117 builder()->LoadAccumulatorWithRegister(input); 3118 } 3119 } 3120 3121 // Desugaring of (yield* iterable) 3122 // 3123 // do { 3124 // const kNext = 0; 3125 // const kReturn = 1; 3126 // const kThrow = 2; 3127 // 3128 // let output; // uninitialized 3129 // 3130 // let iteratorRecord = GetIterator(iterable); 3131 // let iterator = iteratorRecord.[[Iterator]]; 3132 // let next = iteratorRecord.[[NextMethod]]; 3133 // let input = undefined; 3134 // let resumeMode = kNext; 3135 // 3136 // while (true) { 3137 // // From the generator to the iterator: 3138 // // Forward input according to resumeMode and obtain output. 3139 // switch (resumeMode) { 3140 // case kNext: 3141 // output = next.[[Call]](iterator, );; 3142 // break; 3143 // case kReturn: 3144 // let iteratorReturn = iterator.return; 3145 // if (IS_NULL_OR_UNDEFINED(iteratorReturn)) return input; 3146 // output = iteratorReturn.[[Call]](iterator, input); 3147 // break; 3148 // case kThrow: 3149 // let iteratorThrow = iterator.throw; 3150 // if (IS_NULL_OR_UNDEFINED(iteratorThrow)) { 3151 // let iteratorReturn = iterator.return; 3152 // if (!IS_NULL_OR_UNDEFINED(iteratorReturn)) { 3153 // output = iteratorReturn.[[Call]](iterator, ); 3154 // if (IS_ASYNC_GENERATOR) output = await output; 3155 // if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output); 3156 // } 3157 // throw MakeTypeError(kThrowMethodMissing); 3158 // } 3159 // output = iteratorThrow.[[Call]](iterator, input); 3160 // break; 3161 // } 3162 // 3163 // if (IS_ASYNC_GENERATOR) output = await output; 3164 // if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output); 3165 // if (output.done) break; 3166 // 3167 // // From the generator to its user: 3168 // // Forward output, receive new input, and determine resume mode. 3169 // if (IS_ASYNC_GENERATOR) { 3170 // // AsyncGeneratorYield abstract operation awaits the operand before 3171 // // resolving the promise for the current AsyncGeneratorRequest. 3172 // %_AsyncGeneratorYield(output.value) 3173 // } 3174 // input = Suspend(output); 3175 // resumeMode = %GeneratorGetResumeMode(); 3176 // } 3177 // 3178 // if (resumeMode === kReturn) { 3179 // return output.value; 3180 // } 3181 // output.value 3182 // } 3183 void BytecodeGenerator::VisitYieldStar(YieldStar* expr) { 3184 Register output = register_allocator()->NewRegister(); 3185 Register resume_mode = register_allocator()->NewRegister(); 3186 IteratorType iterator_type = IsAsyncGeneratorFunction(function_kind()) 3187 ? IteratorType::kAsync 3188 : IteratorType::kNormal; 3189 3190 { 3191 RegisterAllocationScope register_scope(this); 3192 RegisterList iterator_and_input = register_allocator()->NewRegisterList(2); 3193 IteratorRecord iterator = BuildGetIteratorRecord( 3194 expr->expression(), 3195 register_allocator()->NewRegister() /* next method */, 3196 iterator_and_input[0], iterator_type); 3197 3198 Register input = iterator_and_input[1]; 3199 builder()->LoadUndefined().StoreAccumulatorInRegister(input); 3200 builder() 3201 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kNext)) 3202 .StoreAccumulatorInRegister(resume_mode); 3203 3204 { 3205 // This loop builder does not construct counters as the loop is not 3206 // visible to the user, and we therefore neither pass the block coverage 3207 // builder nor the expression. 3208 // 3209 // In addition to the normal suspend for yield*, a yield* in an async 3210 // generator has 2 additional suspends: 3211 // - One for awaiting the iterator result of closing the generator when 3212 // resumed with a "throw" completion, and a throw method is not 3213 // present on the delegated iterator 3214 // - One for awaiting the iterator result yielded by the delegated 3215 // iterator 3216 3217 LoopBuilder loop(builder(), nullptr, nullptr); 3218 loop.LoopHeader(); 3219 3220 { 3221 BytecodeLabels after_switch(zone()); 3222 BytecodeJumpTable* switch_jump_table = 3223 builder()->AllocateJumpTable(2, 1); 3224 3225 builder() 3226 ->LoadAccumulatorWithRegister(resume_mode) 3227 .SwitchOnSmiNoFeedback(switch_jump_table); 3228 3229 // Fallthrough to default case. 3230 // TODO(tebbi): Add debug code to check that {resume_mode} really is 3231 // {JSGeneratorObject::kNext} in this case. 3232 STATIC_ASSERT(JSGeneratorObject::kNext == 0); 3233 { 3234 FeedbackSlot slot = feedback_spec()->AddCallICSlot(); 3235 builder()->CallProperty(iterator.next(), iterator_and_input, 3236 feedback_index(slot)); 3237 builder()->Jump(after_switch.New()); 3238 } 3239 3240 STATIC_ASSERT(JSGeneratorObject::kReturn == 1); 3241 builder()->Bind(switch_jump_table, JSGeneratorObject::kReturn); 3242 { 3243 const AstRawString* return_string = 3244 ast_string_constants()->return_string(); 3245 BytecodeLabels no_return_method(zone()); 3246 3247 BuildCallIteratorMethod(iterator.object(), return_string, 3248 iterator_and_input, after_switch.New(), 3249 &no_return_method); 3250 no_return_method.Bind(builder()); 3251 builder()->LoadAccumulatorWithRegister(input); 3252 if (iterator_type == IteratorType::kAsync) { 3253 execution_control()->AsyncReturnAccumulator(); 3254 } else { 3255 execution_control()->ReturnAccumulator(); 3256 } 3257 } 3258 3259 STATIC_ASSERT(JSGeneratorObject::kThrow == 2); 3260 builder()->Bind(switch_jump_table, JSGeneratorObject::kThrow); 3261 { 3262 const AstRawString* throw_string = 3263 ast_string_constants()->throw_string(); 3264 BytecodeLabels no_throw_method(zone()); 3265 BuildCallIteratorMethod(iterator.object(), throw_string, 3266 iterator_and_input, after_switch.New(), 3267 &no_throw_method); 3268 3269 // If there is no "throw" method, perform IteratorClose, and finally 3270 // throw a TypeError. 3271 no_throw_method.Bind(builder()); 3272 BuildIteratorClose(iterator, expr); 3273 builder()->CallRuntime(Runtime::kThrowThrowMethodMissing); 3274 } 3275 3276 after_switch.Bind(builder()); 3277 } 3278 3279 if (iterator_type == IteratorType::kAsync) { 3280 // Await the result of the method invocation. 3281 BuildAwait(expr); 3282 } 3283 3284 // Check that output is an object. 3285 BytecodeLabel check_if_done; 3286 builder() 3287 ->StoreAccumulatorInRegister(output) 3288 .JumpIfJSReceiver(&check_if_done) 3289 .CallRuntime(Runtime::kThrowIteratorResultNotAnObject, output); 3290 3291 builder()->Bind(&check_if_done); 3292 // Break once output.done is true. 3293 builder()->LoadNamedProperty( 3294 output, ast_string_constants()->done_string(), 3295 feedback_index(feedback_spec()->AddLoadICSlot())); 3296 3297 loop.BreakIfTrue(ToBooleanMode::kConvertToBoolean); 3298 3299 // Suspend the current generator. 3300 if (iterator_type == IteratorType::kNormal) { 3301 builder()->LoadAccumulatorWithRegister(output); 3302 } else { 3303 RegisterAllocationScope register_scope(this); 3304 DCHECK_EQ(iterator_type, IteratorType::kAsync); 3305 // If generatorKind is async, perform AsyncGeneratorYield(output.value), 3306 // which will await `output.value` before resolving the current 3307 // AsyncGeneratorRequest's promise. 3308 builder()->LoadNamedProperty( 3309 output, ast_string_constants()->value_string(), 3310 feedback_index(feedback_spec()->AddLoadICSlot())); 3311 3312 RegisterList args = register_allocator()->NewRegisterList(3); 3313 builder() 3314 ->MoveRegister(generator_object(), args[0]) // generator 3315 .StoreAccumulatorInRegister(args[1]) // value 3316 .LoadBoolean(catch_prediction() != HandlerTable::ASYNC_AWAIT) 3317 .StoreAccumulatorInRegister(args[2]) // is_caught 3318 .CallRuntime(Runtime::kInlineAsyncGeneratorYield, args); 3319 } 3320 3321 BuildSuspendPoint(expr); 3322 builder()->StoreAccumulatorInRegister(input); 3323 builder() 3324 ->CallRuntime(Runtime::kInlineGeneratorGetResumeMode, 3325 generator_object()) 3326 .StoreAccumulatorInRegister(resume_mode); 3327 3328 loop.BindContinueTarget(); 3329 loop.JumpToHeader(loop_depth_); 3330 } 3331 } 3332 3333 // Decide if we trigger a return or if the yield* expression should just 3334 // produce a value. 3335 BytecodeLabel completion_is_output_value; 3336 Register output_value = register_allocator()->NewRegister(); 3337 builder() 3338 ->LoadNamedProperty(output, ast_string_constants()->value_string(), 3339 feedback_index(feedback_spec()->AddLoadICSlot())) 3340 .StoreAccumulatorInRegister(output_value) 3341 .LoadLiteral(Smi::FromInt(JSGeneratorObject::kReturn)) 3342 .CompareReference(resume_mode) 3343 .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &completion_is_output_value) 3344 .LoadAccumulatorWithRegister(output_value); 3345 if (iterator_type == IteratorType::kAsync) { 3346 execution_control()->AsyncReturnAccumulator(); 3347 } else { 3348 execution_control()->ReturnAccumulator(); 3349 } 3350 3351 builder()->Bind(&completion_is_output_value); 3352 BuildIncrementBlockCoverageCounterIfEnabled(expr, 3353 SourceRangeKind::kContinuation); 3354 builder()->LoadAccumulatorWithRegister(output_value); 3355 } 3356 3357 void BytecodeGenerator::BuildAwait(Expression* await_expr) { 3358 // Rather than HandlerTable::UNCAUGHT, async functions use 3359 // HandlerTable::ASYNC_AWAIT to communicate that top-level exceptions are 3360 // transformed into promise rejections. This is necessary to prevent emitting 3361 // multiple debug events for the same uncaught exception. There is no point 3362 // in the body of an async function where catch prediction is 3363 // HandlerTable::UNCAUGHT. 3364 DCHECK(catch_prediction() != HandlerTable::UNCAUGHT); 3365 3366 { 3367 // Await(operand) and suspend. 3368 RegisterAllocationScope register_scope(this); 3369 3370 int await_builtin_context_index; 3371 RegisterList args; 3372 if (IsAsyncGeneratorFunction(function_kind())) { 3373 await_builtin_context_index = 3374 catch_prediction() == HandlerTable::ASYNC_AWAIT 3375 ? Context::ASYNC_GENERATOR_AWAIT_UNCAUGHT 3376 : Context::ASYNC_GENERATOR_AWAIT_CAUGHT; 3377 args = register_allocator()->NewRegisterList(2); 3378 builder() 3379 ->MoveRegister(generator_object(), args[0]) 3380 .StoreAccumulatorInRegister(args[1]); 3381 } else { 3382 await_builtin_context_index = 3383 catch_prediction() == HandlerTable::ASYNC_AWAIT 3384 ? Context::ASYNC_FUNCTION_AWAIT_UNCAUGHT_INDEX 3385 : Context::ASYNC_FUNCTION_AWAIT_CAUGHT_INDEX; 3386 args = register_allocator()->NewRegisterList(3); 3387 builder() 3388 ->MoveRegister(generator_object(), args[0]) 3389 .StoreAccumulatorInRegister(args[1]); 3390 3391 // AsyncFunction Await builtins require a 3rd parameter to hold the outer 3392 // promise. 3393 Variable* var_promise = closure_scope()->promise_var(); 3394 BuildVariableLoadForAccumulatorValue(var_promise, HoleCheckMode::kElided); 3395 builder()->StoreAccumulatorInRegister(args[2]); 3396 } 3397 3398 builder()->CallJSRuntime(await_builtin_context_index, args); 3399 } 3400 3401 BuildSuspendPoint(await_expr); 3402 3403 Register input = register_allocator()->NewRegister(); 3404 Register resume_mode = register_allocator()->NewRegister(); 3405 3406 // Now dispatch on resume mode. 3407 BytecodeLabel resume_next; 3408 builder() 3409 ->StoreAccumulatorInRegister(input) 3410 .CallRuntime(Runtime::kInlineGeneratorGetResumeMode, generator_object()) 3411 .StoreAccumulatorInRegister(resume_mode) 3412 .LoadLiteral(Smi::FromInt(JSGeneratorObject::kNext)) 3413 .CompareReference(resume_mode) 3414 .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &resume_next); 3415 3416 // Resume with "throw" completion (rethrow the received value). 3417 // TODO(leszeks): Add a debug-only check that the accumulator is 3418 // JSGeneratorObject::kThrow. 3419 builder()->LoadAccumulatorWithRegister(input).ReThrow(); 3420 3421 // Resume with next. 3422 builder()->Bind(&resume_next); 3423 builder()->LoadAccumulatorWithRegister(input); 3424 } 3425 3426 void BytecodeGenerator::VisitAwait(Await* expr) { 3427 builder()->SetExpressionPosition(expr); 3428 VisitForAccumulatorValue(expr->expression()); 3429 BuildAwait(expr); 3430 BuildIncrementBlockCoverageCounterIfEnabled(expr, 3431 SourceRangeKind::kContinuation); 3432 } 3433 3434 void BytecodeGenerator::VisitThrow(Throw* expr) { 3435 AllocateBlockCoverageSlotIfEnabled(expr, SourceRangeKind::kContinuation); 3436 VisitForAccumulatorValue(expr->exception()); 3437 builder()->SetExpressionPosition(expr); 3438 builder()->Throw(); 3439 } 3440 3441 void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* property) { 3442 LhsKind property_kind = Property::GetAssignType(property); 3443 switch (property_kind) { 3444 case VARIABLE: 3445 UNREACHABLE(); 3446 case NAMED_PROPERTY: { 3447 builder()->SetExpressionPosition(property); 3448 const AstRawString* name = 3449 property->key()->AsLiteral()->AsRawPropertyName(); 3450 BuildLoadNamedProperty(property, obj, name); 3451 break; 3452 } 3453 case KEYED_PROPERTY: { 3454 VisitForAccumulatorValue(property->key()); 3455 builder()->SetExpressionPosition(property); 3456 builder()->LoadKeyedProperty( 3457 obj, feedback_index(feedback_spec()->AddKeyedLoadICSlot())); 3458 break; 3459 } 3460 case NAMED_SUPER_PROPERTY: 3461 VisitNamedSuperPropertyLoad(property, Register::invalid_value()); 3462 break; 3463 case KEYED_SUPER_PROPERTY: 3464 VisitKeyedSuperPropertyLoad(property, Register::invalid_value()); 3465 break; 3466 } 3467 } 3468 3469 void BytecodeGenerator::VisitPropertyLoadForRegister(Register obj, 3470 Property* expr, 3471 Register destination) { 3472 ValueResultScope result_scope(this); 3473 VisitPropertyLoad(obj, expr); 3474 builder()->StoreAccumulatorInRegister(destination); 3475 } 3476 3477 void BytecodeGenerator::VisitNamedSuperPropertyLoad(Property* property, 3478 Register opt_receiver_out) { 3479 RegisterAllocationScope register_scope(this); 3480 SuperPropertyReference* super_property = 3481 property->obj()->AsSuperPropertyReference(); 3482 RegisterList args = register_allocator()->NewRegisterList(3); 3483 VisitForRegisterValue(super_property->this_var(), args[0]); 3484 VisitForRegisterValue(super_property->home_object(), args[1]); 3485 3486 builder()->SetExpressionPosition(property); 3487 builder() 3488 ->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName()) 3489 .StoreAccumulatorInRegister(args[2]) 3490 .CallRuntime(Runtime::kLoadFromSuper, args); 3491 3492 if (opt_receiver_out.is_valid()) { 3493 builder()->MoveRegister(args[0], opt_receiver_out); 3494 } 3495 } 3496 3497 void BytecodeGenerator::VisitKeyedSuperPropertyLoad(Property* property, 3498 Register opt_receiver_out) { 3499 RegisterAllocationScope register_scope(this); 3500 SuperPropertyReference* super_property = 3501 property->obj()->AsSuperPropertyReference(); 3502 RegisterList args = register_allocator()->NewRegisterList(3); 3503 VisitForRegisterValue(super_property->this_var(), args[0]); 3504 VisitForRegisterValue(super_property->home_object(), args[1]); 3505 VisitForRegisterValue(property->key(), args[2]); 3506 3507 builder()->SetExpressionPosition(property); 3508 builder()->CallRuntime(Runtime::kLoadKeyedFromSuper, args); 3509 3510 if (opt_receiver_out.is_valid()) { 3511 builder()->MoveRegister(args[0], opt_receiver_out); 3512 } 3513 } 3514 3515 void BytecodeGenerator::VisitProperty(Property* expr) { 3516 LhsKind property_kind = Property::GetAssignType(expr); 3517 if (property_kind != NAMED_SUPER_PROPERTY && 3518 property_kind != KEYED_SUPER_PROPERTY) { 3519 Register obj = VisitForRegisterValue(expr->obj()); 3520 VisitPropertyLoad(obj, expr); 3521 } else { 3522 VisitPropertyLoad(Register::invalid_value(), expr); 3523 } 3524 } 3525 3526 void BytecodeGenerator::VisitResolvedProperty(ResolvedProperty* expr) { 3527 // Handled by VisitCall(). 3528 UNREACHABLE(); 3529 } 3530 3531 void BytecodeGenerator::VisitArguments(ZonePtrList<Expression>* args, 3532 RegisterList* arg_regs) { 3533 // Visit arguments. 3534 for (int i = 0; i < static_cast<int>(args->length()); i++) { 3535 VisitAndPushIntoRegisterList(args->at(i), arg_regs); 3536 } 3537 } 3538 3539 void BytecodeGenerator::VisitCall(Call* expr) { 3540 Expression* callee_expr = expr->expression(); 3541 Call::CallType call_type = expr->GetCallType(); 3542 3543 if (call_type == Call::SUPER_CALL) { 3544 return VisitCallSuper(expr); 3545 } 3546 3547 // Grow the args list as we visit receiver / arguments to avoid allocating all 3548 // the registers up-front. Otherwise these registers are unavailable during 3549 // receiver / argument visiting and we can end up with memory leaks due to 3550 // registers keeping objects alive. 3551 Register callee = register_allocator()->NewRegister(); 3552 RegisterList args = register_allocator()->NewGrowableRegisterList(); 3553 3554 bool implicit_undefined_receiver = false; 3555 // When a call contains a spread, a Call AST node is only created if there is 3556 // exactly one spread, and it is the last argument. 3557 bool is_spread_call = expr->only_last_arg_is_spread(); 3558 3559 // TODO(petermarshall): We have a lot of call bytecodes that are very similar, 3560 // see if we can reduce the number by adding a separate argument which 3561 // specifies the call type (e.g., property, spread, tailcall, etc.). 3562 3563 // Prepare the callee and the receiver to the function call. This depends on 3564 // the semantics of the underlying call type. 3565 switch (call_type) { 3566 case Call::NAMED_PROPERTY_CALL: 3567 case Call::KEYED_PROPERTY_CALL: { 3568 Property* property = callee_expr->AsProperty(); 3569 VisitAndPushIntoRegisterList(property->obj(), &args); 3570 VisitPropertyLoadForRegister(args.last_register(), property, callee); 3571 break; 3572 } 3573 case Call::RESOLVED_PROPERTY_CALL: { 3574 ResolvedProperty* resolved = callee_expr->AsResolvedProperty(); 3575 VisitAndPushIntoRegisterList(resolved->object(), &args); 3576 VisitForAccumulatorValue(resolved->property()); 3577 builder()->StoreAccumulatorInRegister(callee); 3578 break; 3579 } 3580 case Call::GLOBAL_CALL: { 3581 // Receiver is undefined for global calls. 3582 if (!is_spread_call) { 3583 implicit_undefined_receiver = true; 3584 } else { 3585 // TODO(leszeks): There's no special bytecode for tail calls or spread 3586 // calls with an undefined receiver, so just push undefined ourselves. 3587 BuildPushUndefinedIntoRegisterList(&args); 3588 } 3589 // Load callee as a global variable. 3590 VariableProxy* proxy = callee_expr->AsVariableProxy(); 3591 BuildVariableLoadForAccumulatorValue(proxy->var(), 3592 proxy->hole_check_mode()); 3593 builder()->StoreAccumulatorInRegister(callee); 3594 break; 3595 } 3596 case Call::WITH_CALL: { 3597 Register receiver = register_allocator()->GrowRegisterList(&args); 3598 DCHECK(callee_expr->AsVariableProxy()->var()->IsLookupSlot()); 3599 { 3600 RegisterAllocationScope inner_register_scope(this); 3601 Register name = register_allocator()->NewRegister(); 3602 3603 // Call %LoadLookupSlotForCall to get the callee and receiver. 3604 RegisterList result_pair = register_allocator()->NewRegisterList(2); 3605 Variable* variable = callee_expr->AsVariableProxy()->var(); 3606 builder() 3607 ->LoadLiteral(variable->raw_name()) 3608 .StoreAccumulatorInRegister(name) 3609 .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, name, 3610 result_pair) 3611 .MoveRegister(result_pair[0], callee) 3612 .MoveRegister(result_pair[1], receiver); 3613 } 3614 break; 3615 } 3616 case Call::OTHER_CALL: { 3617 // Receiver is undefined for other calls. 3618 if (!is_spread_call) { 3619 implicit_undefined_receiver = true; 3620 } else { 3621 // TODO(leszeks): There's no special bytecode for tail calls or spread 3622 // calls with an undefined receiver, so just push undefined ourselves. 3623 BuildPushUndefinedIntoRegisterList(&args); 3624 } 3625 VisitForRegisterValue(callee_expr, callee); 3626 break; 3627 } 3628 case Call::NAMED_SUPER_PROPERTY_CALL: { 3629 Register receiver = register_allocator()->GrowRegisterList(&args); 3630 Property* property = callee_expr->AsProperty(); 3631 VisitNamedSuperPropertyLoad(property, receiver); 3632 builder()->StoreAccumulatorInRegister(callee); 3633 break; 3634 } 3635 case Call::KEYED_SUPER_PROPERTY_CALL: { 3636 Register receiver = register_allocator()->GrowRegisterList(&args); 3637 Property* property = callee_expr->AsProperty(); 3638 VisitKeyedSuperPropertyLoad(property, receiver); 3639 builder()->StoreAccumulatorInRegister(callee); 3640 break; 3641 } 3642 case Call::SUPER_CALL: 3643 UNREACHABLE(); 3644 break; 3645 } 3646 3647 // Evaluate all arguments to the function call and store in sequential args 3648 // registers. 3649 VisitArguments(expr->arguments(), &args); 3650 int reciever_arg_count = implicit_undefined_receiver ? 0 : 1; 3651 CHECK_EQ(reciever_arg_count + expr->arguments()->length(), 3652 args.register_count()); 3653 3654 // Resolve callee for a potential direct eval call. This block will mutate the 3655 // callee value. 3656 if (expr->is_possibly_eval() && expr->arguments()->length() > 0) { 3657 RegisterAllocationScope inner_register_scope(this); 3658 // Set up arguments for ResolvePossiblyDirectEval by copying callee, source 3659 // strings and function closure, and loading language and 3660 // position. 3661 Register first_arg = args[reciever_arg_count]; 3662 RegisterList runtime_call_args = register_allocator()->NewRegisterList(6); 3663 builder() 3664 ->MoveRegister(callee, runtime_call_args[0]) 3665 .MoveRegister(first_arg, runtime_call_args[1]) 3666 .MoveRegister(Register::function_closure(), runtime_call_args[2]) 3667 .LoadLiteral(Smi::FromEnum(language_mode())) 3668 .StoreAccumulatorInRegister(runtime_call_args[3]) 3669 .LoadLiteral(Smi::FromInt(current_scope()->start_position())) 3670 .StoreAccumulatorInRegister(runtime_call_args[4]) 3671 .LoadLiteral(Smi::FromInt(expr->position())) 3672 .StoreAccumulatorInRegister(runtime_call_args[5]); 3673 3674 // Call ResolvePossiblyDirectEval and modify the callee. 3675 builder() 3676 ->CallRuntime(Runtime::kResolvePossiblyDirectEval, runtime_call_args) 3677 .StoreAccumulatorInRegister(callee); 3678 } 3679 3680 builder()->SetExpressionPosition(expr); 3681 3682 int feedback_slot_index = feedback_index(feedback_spec()->AddCallICSlot()); 3683 3684 if (is_spread_call) { 3685 DCHECK(!implicit_undefined_receiver); 3686 builder()->CallWithSpread(callee, args, feedback_slot_index); 3687 } else if (call_type == Call::NAMED_PROPERTY_CALL || 3688 call_type == Call::KEYED_PROPERTY_CALL || 3689 call_type == Call::RESOLVED_PROPERTY_CALL) { 3690 DCHECK(!implicit_undefined_receiver); 3691 builder()->CallProperty(callee, args, feedback_slot_index); 3692 } else if (implicit_undefined_receiver) { 3693 builder()->CallUndefinedReceiver(callee, args, feedback_slot_index); 3694 } else { 3695 builder()->CallAnyReceiver(callee, args, feedback_slot_index); 3696 } 3697 } 3698 3699 void BytecodeGenerator::VisitCallSuper(Call* expr) { 3700 RegisterAllocationScope register_scope(this); 3701 SuperCallReference* super = expr->expression()->AsSuperCallReference(); 3702 ZonePtrList<Expression>* args = expr->arguments(); 3703 3704 int first_spread_index = 0; 3705 for (; first_spread_index < args->length(); first_spread_index++) { 3706 if (args->at(first_spread_index)->IsSpread()) break; 3707 } 3708 3709 // Prepare the constructor to the super call. 3710 Register this_function = VisitForRegisterValue(super->this_function_var()); 3711 Register constructor = register_allocator()->NewRegister(); 3712 builder() 3713 ->LoadAccumulatorWithRegister(this_function) 3714 .GetSuperConstructor(constructor); 3715 3716 if (first_spread_index < expr->arguments()->length() - 1) { 3717 // We rewrite something like 3718 // super(1, ...x, 2) 3719 // to 3720 // %reflect_construct(constructor, [1, ...x, 2], new_target) 3721 // That is, we implement (non-last-arg) spreads in super calls via our 3722 // mechanism for spreads in array literals. 3723 3724 // First generate the array containing all arguments. 3725 Register array = register_allocator()->NewRegister(); 3726 int literal_index = feedback_index(feedback_spec()->AddLiteralSlot()); 3727 builder() 3728 ->CreateEmptyArrayLiteral(literal_index) 3729 .StoreAccumulatorInRegister(array); 3730 BuildArrayLiteralElementsInsertion(array, first_spread_index, args, false); 3731 3732 // Now pass that array to %reflect_construct. 3733 RegisterList construct_args = register_allocator()->NewRegisterList(3); 3734 builder()->MoveRegister(constructor, construct_args[0]); 3735 builder()->MoveRegister(array, construct_args[1]); 3736 VisitForRegisterValue(super->new_target_var(), construct_args[2]); 3737 builder()->CallJSRuntime(Context::REFLECT_CONSTRUCT_INDEX, construct_args); 3738 } else { 3739 RegisterList args_regs = register_allocator()->NewGrowableRegisterList(); 3740 VisitArguments(args, &args_regs); 3741 // The new target is loaded into the accumulator from the 3742 // {new.target} variable. 3743 VisitForAccumulatorValue(super->new_target_var()); 3744 builder()->SetExpressionPosition(expr); 3745 3746 int feedback_slot_index = feedback_index(feedback_spec()->AddCallICSlot()); 3747 3748 if (first_spread_index == expr->arguments()->length() - 1) { 3749 builder()->ConstructWithSpread(constructor, args_regs, 3750 feedback_slot_index); 3751 } else { 3752 DCHECK_EQ(first_spread_index, expr->arguments()->length()); 3753 // Call construct. 3754 // TODO(turbofan): For now we do gather feedback on super constructor 3755 // calls, utilizing the existing machinery to inline the actual call 3756 // target and the JSCreate for the implicit receiver allocation. This 3757 // is not an ideal solution for super constructor calls, but it gets 3758 // the job done for now. In the long run we might want to revisit this 3759 // and come up with a better way. 3760 builder()->Construct(constructor, args_regs, feedback_slot_index); 3761 } 3762 } 3763 3764 // Explicit calls to the super constructor using super() perform an 3765 // implicit binding assignment to the 'this' variable. 3766 // 3767 // Default constructors don't need have to do the assignment because 3768 // 'this' isn't accessed in default constructors. 3769 if (!IsDefaultConstructor(info()->literal()->kind())) { 3770 BuildVariableAssignment(super->this_var()->var(), Token::INIT, 3771 HoleCheckMode::kRequired); 3772 } 3773 3774 // The derived constructor has the correct bit set always, so we 3775 // don't emit code to load and call the initializer if not 3776 // required. 3777 // 3778 // For the arrow function or eval case, we always emit code to load 3779 // and call the initializer. 3780 // 3781 // TODO(gsathya): In the future, we could tag nested arrow functions 3782 // or eval with the correct bit so that we do the load conditionally 3783 // if required. 3784 if (info()->literal()->requires_instance_fields_initializer() || 3785 !IsDerivedConstructor(info()->literal()->kind())) { 3786 Register instance = register_allocator()->NewRegister(); 3787 builder()->StoreAccumulatorInRegister(instance); 3788 BuildInstanceFieldInitialization(this_function, instance); 3789 builder()->LoadAccumulatorWithRegister(instance); 3790 } 3791 } 3792 3793 void BytecodeGenerator::VisitCallNew(CallNew* expr) { 3794 Register constructor = VisitForRegisterValue(expr->expression()); 3795 RegisterList args = register_allocator()->NewGrowableRegisterList(); 3796 VisitArguments(expr->arguments(), &args); 3797 3798 // The accumulator holds new target which is the same as the 3799 // constructor for CallNew. 3800 builder()->SetExpressionPosition(expr); 3801 builder()->LoadAccumulatorWithRegister(constructor); 3802 3803 int feedback_slot_index = feedback_index(feedback_spec()->AddCallICSlot()); 3804 if (expr->only_last_arg_is_spread()) { 3805 builder()->ConstructWithSpread(constructor, args, feedback_slot_index); 3806 } else { 3807 builder()->Construct(constructor, args, feedback_slot_index); 3808 } 3809 } 3810 3811 void BytecodeGenerator::VisitCallRuntime(CallRuntime* expr) { 3812 if (expr->is_jsruntime()) { 3813 RegisterList args = register_allocator()->NewGrowableRegisterList(); 3814 VisitArguments(expr->arguments(), &args); 3815 builder()->CallJSRuntime(expr->context_index(), args); 3816 } else { 3817 // Evaluate all arguments to the runtime call. 3818 RegisterList args = register_allocator()->NewGrowableRegisterList(); 3819 VisitArguments(expr->arguments(), &args); 3820 Runtime::FunctionId function_id = expr->function()->function_id; 3821 builder()->CallRuntime(function_id, args); 3822 } 3823 } 3824 3825 void BytecodeGenerator::VisitVoid(UnaryOperation* expr) { 3826 VisitForEffect(expr->expression()); 3827 builder()->LoadUndefined(); 3828 } 3829 3830 void BytecodeGenerator::VisitForTypeOfValue(Expression* expr) { 3831 if (expr->IsVariableProxy()) { 3832 // Typeof does not throw a reference error on global variables, hence we 3833 // perform a non-contextual load in case the operand is a variable proxy. 3834 VariableProxy* proxy = expr->AsVariableProxy(); 3835 BuildVariableLoadForAccumulatorValue(proxy->var(), proxy->hole_check_mode(), 3836 INSIDE_TYPEOF); 3837 } else { 3838 VisitForAccumulatorValue(expr); 3839 } 3840 } 3841 3842 void BytecodeGenerator::VisitTypeOf(UnaryOperation* expr) { 3843 VisitForTypeOfValue(expr->expression()); 3844 builder()->TypeOf(); 3845 } 3846 3847 void BytecodeGenerator::VisitNot(UnaryOperation* expr) { 3848 if (execution_result()->IsEffect()) { 3849 VisitForEffect(expr->expression()); 3850 } else if (execution_result()->IsTest()) { 3851 // No actual logical negation happening, we just swap the control flow, by 3852 // swapping the target labels and the fallthrough branch, and visit in the 3853 // same test result context. 3854 TestResultScope* test_result = execution_result()->AsTest(); 3855 test_result->InvertControlFlow(); 3856 VisitInSameTestExecutionScope(expr->expression()); 3857 } else { 3858 TypeHint type_hint = VisitForAccumulatorValue(expr->expression()); 3859 builder()->LogicalNot(ToBooleanModeFromTypeHint(type_hint)); 3860 // Always returns a boolean value. 3861 execution_result()->SetResultIsBoolean(); 3862 } 3863 } 3864 3865 void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { 3866 switch (expr->op()) { 3867 case Token::Value::NOT: 3868 VisitNot(expr); 3869 break; 3870 case Token::Value::TYPEOF: 3871 VisitTypeOf(expr); 3872 break; 3873 case Token::Value::VOID: 3874 VisitVoid(expr); 3875 break; 3876 case Token::Value::DELETE: 3877 VisitDelete(expr); 3878 break; 3879 case Token::Value::ADD: 3880 case Token::Value::SUB: 3881 case Token::Value::BIT_NOT: 3882 VisitForAccumulatorValue(expr->expression()); 3883 builder()->SetExpressionPosition(expr); 3884 builder()->UnaryOperation( 3885 expr->op(), feedback_index(feedback_spec()->AddBinaryOpICSlot())); 3886 break; 3887 default: 3888 UNREACHABLE(); 3889 } 3890 } 3891 3892 void BytecodeGenerator::VisitDelete(UnaryOperation* expr) { 3893 if (expr->expression()->IsProperty()) { 3894 // Delete of an object property is allowed both in sloppy 3895 // and strict modes. 3896 Property* property = expr->expression()->AsProperty(); 3897 Register object = VisitForRegisterValue(property->obj()); 3898 VisitForAccumulatorValue(property->key()); 3899 builder()->Delete(object, language_mode()); 3900 } else if (expr->expression()->IsVariableProxy()) { 3901 // Delete of an unqualified identifier is allowed in sloppy mode but is 3902 // not allowed in strict mode. Deleting 'this' and 'new.target' is allowed 3903 // in both modes. 3904 VariableProxy* proxy = expr->expression()->AsVariableProxy(); 3905 DCHECK(is_sloppy(language_mode()) || proxy->is_this() || 3906 proxy->is_new_target()); 3907 if (proxy->is_this() || proxy->is_new_target()) { 3908 builder()->LoadTrue(); 3909 } else { 3910 Variable* variable = proxy->var(); 3911 switch (variable->location()) { 3912 case VariableLocation::PARAMETER: 3913 case VariableLocation::LOCAL: 3914 case VariableLocation::CONTEXT: { 3915 // Deleting local var/let/const, context variables, and arguments 3916 // does not have any effect. 3917 builder()->LoadFalse(); 3918 break; 3919 } 3920 case VariableLocation::UNALLOCATED: 3921 // TODO(adamk): Falling through to the runtime results in correct 3922 // behavior, but does unnecessary context-walking (since scope 3923 // analysis has already proven that the variable doesn't exist in 3924 // any non-global scope). Consider adding a DeleteGlobal bytecode 3925 // that knows how to deal with ScriptContexts as well as global 3926 // object properties. 3927 case VariableLocation::LOOKUP: { 3928 Register name_reg = register_allocator()->NewRegister(); 3929 builder() 3930 ->LoadLiteral(variable->raw_name()) 3931 .StoreAccumulatorInRegister(name_reg) 3932 .CallRuntime(Runtime::kDeleteLookupSlot, name_reg); 3933 break; 3934 } 3935 default: 3936 UNREACHABLE(); 3937 } 3938 } 3939 } else { 3940 // Delete of an unresolvable reference returns true. 3941 VisitForEffect(expr->expression()); 3942 builder()->LoadTrue(); 3943 } 3944 } 3945 3946 void BytecodeGenerator::VisitCountOperation(CountOperation* expr) { 3947 DCHECK(expr->expression()->IsValidReferenceExpression()); 3948 3949 // Left-hand side can only be a property, a global or a variable slot. 3950 Property* property = expr->expression()->AsProperty(); 3951 LhsKind assign_type = Property::GetAssignType(property); 3952 3953 bool is_postfix = expr->is_postfix() && !execution_result()->IsEffect(); 3954 3955 // Evaluate LHS expression and get old value. 3956 Register object, key, old_value; 3957 RegisterList super_property_args; 3958 const AstRawString* name; 3959 switch (assign_type) { 3960 case VARIABLE: { 3961 VariableProxy* proxy = expr->expression()->AsVariableProxy(); 3962 BuildVariableLoadForAccumulatorValue(proxy->var(), 3963 proxy->hole_check_mode()); 3964 break; 3965 } 3966 case NAMED_PROPERTY: { 3967 object = VisitForRegisterValue(property->obj()); 3968 name = property->key()->AsLiteral()->AsRawPropertyName(); 3969 builder()->LoadNamedProperty( 3970 object, name, 3971 feedback_index(GetCachedLoadICSlot(property->obj(), name))); 3972 break; 3973 } 3974 case KEYED_PROPERTY: { 3975 object = VisitForRegisterValue(property->obj()); 3976 // Use visit for accumulator here since we need the key in the accumulator 3977 // for the LoadKeyedProperty. 3978 key = register_allocator()->NewRegister(); 3979 VisitForAccumulatorValue(property->key()); 3980 builder()->StoreAccumulatorInRegister(key).LoadKeyedProperty( 3981 object, feedback_index(feedback_spec()->AddKeyedLoadICSlot())); 3982 break; 3983 } 3984 case NAMED_SUPER_PROPERTY: { 3985 super_property_args = register_allocator()->NewRegisterList(4); 3986 RegisterList load_super_args = super_property_args.Truncate(3); 3987 SuperPropertyReference* super_property = 3988 property->obj()->AsSuperPropertyReference(); 3989 VisitForRegisterValue(super_property->this_var(), load_super_args[0]); 3990 VisitForRegisterValue(super_property->home_object(), load_super_args[1]); 3991 builder() 3992 ->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName()) 3993 .StoreAccumulatorInRegister(load_super_args[2]) 3994 .CallRuntime(Runtime::kLoadFromSuper, load_super_args); 3995 break; 3996 } 3997 case KEYED_SUPER_PROPERTY: { 3998 super_property_args = register_allocator()->NewRegisterList(4); 3999 RegisterList load_super_args = super_property_args.Truncate(3); 4000 SuperPropertyReference* super_property = 4001 property->obj()->AsSuperPropertyReference(); 4002 VisitForRegisterValue(super_property->this_var(), load_super_args[0]); 4003 VisitForRegisterValue(super_property->home_object(), load_super_args[1]); 4004 VisitForRegisterValue(property->key(), load_super_args[2]); 4005 builder()->CallRuntime(Runtime::kLoadKeyedFromSuper, load_super_args); 4006 break; 4007 } 4008 } 4009 4010 // Save result for postfix expressions. 4011 FeedbackSlot count_slot = feedback_spec()->AddBinaryOpICSlot(); 4012 if (is_postfix) { 4013 old_value = register_allocator()->NewRegister(); 4014 // Convert old value into a number before saving it. 4015 // TODO(ignition): Think about adding proper PostInc/PostDec bytecodes 4016 // instead of this ToNumeric + Inc/Dec dance. 4017 builder() 4018 ->ToNumeric(feedback_index(count_slot)) 4019 .StoreAccumulatorInRegister(old_value); 4020 } 4021 4022 // Perform +1/-1 operation. 4023 builder()->UnaryOperation(expr->op(), feedback_index(count_slot)); 4024 4025 // Store the value. 4026 builder()->SetExpressionPosition(expr); 4027 switch (assign_type) { 4028 case VARIABLE: { 4029 VariableProxy* proxy = expr->expression()->AsVariableProxy(); 4030 BuildVariableAssignment(proxy->var(), expr->op(), 4031 proxy->hole_check_mode()); 4032 break; 4033 } 4034 case NAMED_PROPERTY: { 4035 FeedbackSlot slot = GetCachedStoreICSlot(property->obj(), name); 4036 Register value; 4037 if (!execution_result()->IsEffect()) { 4038 value = register_allocator()->NewRegister(); 4039 builder()->StoreAccumulatorInRegister(value); 4040 } 4041 builder()->StoreNamedProperty(object, name, feedback_index(slot), 4042 language_mode()); 4043 if (!execution_result()->IsEffect()) { 4044 builder()->LoadAccumulatorWithRegister(value); 4045 } 4046 break; 4047 } 4048 case KEYED_PROPERTY: { 4049 FeedbackSlot slot = feedback_spec()->AddKeyedStoreICSlot(language_mode()); 4050 Register value; 4051 if (!execution_result()->IsEffect()) { 4052 value = register_allocator()->NewRegister(); 4053 builder()->StoreAccumulatorInRegister(value); 4054 } 4055 builder()->StoreKeyedProperty(object, key, feedback_index(slot), 4056 language_mode()); 4057 if (!execution_result()->IsEffect()) { 4058 builder()->LoadAccumulatorWithRegister(value); 4059 } 4060 break; 4061 } 4062 case NAMED_SUPER_PROPERTY: { 4063 builder() 4064 ->StoreAccumulatorInRegister(super_property_args[3]) 4065 .CallRuntime(StoreToSuperRuntimeId(), super_property_args); 4066 break; 4067 } 4068 case KEYED_SUPER_PROPERTY: { 4069 builder() 4070 ->StoreAccumulatorInRegister(super_property_args[3]) 4071 .CallRuntime(StoreKeyedToSuperRuntimeId(), super_property_args); 4072 break; 4073 } 4074 } 4075 4076 // Restore old value for postfix expressions. 4077 if (is_postfix) { 4078 builder()->LoadAccumulatorWithRegister(old_value); 4079 } 4080 } 4081 4082 void BytecodeGenerator::VisitBinaryOperation(BinaryOperation* binop) { 4083 switch (binop->op()) { 4084 case Token::COMMA: 4085 VisitCommaExpression(binop); 4086 break; 4087 case Token::OR: 4088 VisitLogicalOrExpression(binop); 4089 break; 4090 case Token::AND: 4091 VisitLogicalAndExpression(binop); 4092 break; 4093 default: 4094 VisitArithmeticExpression(binop); 4095 break; 4096 } 4097 } 4098 4099 void BytecodeGenerator::VisitNaryOperation(NaryOperation* expr) { 4100 switch (expr->op()) { 4101 case Token::COMMA: 4102 VisitNaryCommaExpression(expr); 4103 break; 4104 case Token::OR: 4105 VisitNaryLogicalOrExpression(expr); 4106 break; 4107 case Token::AND: 4108 VisitNaryLogicalAndExpression(expr); 4109 break; 4110 default: 4111 VisitNaryArithmeticExpression(expr); 4112 break; 4113 } 4114 } 4115 4116 void BytecodeGenerator::BuildLiteralCompareNil( 4117 Token::Value op, BytecodeArrayBuilder::NilValue nil) { 4118 if (execution_result()->IsTest()) { 4119 TestResultScope* test_result = execution_result()->AsTest(); 4120 switch (test_result->fallthrough()) { 4121 case TestFallthrough::kThen: 4122 builder()->JumpIfNotNil(test_result->NewElseLabel(), op, nil); 4123 break; 4124 case TestFallthrough::kElse: 4125 builder()->JumpIfNil(test_result->NewThenLabel(), op, nil); 4126 break; 4127 case TestFallthrough::kNone: 4128 builder() 4129 ->JumpIfNil(test_result->NewThenLabel(), op, nil) 4130 .Jump(test_result->NewElseLabel()); 4131 } 4132 test_result->SetResultConsumedByTest(); 4133 } else { 4134 builder()->CompareNil(op, nil); 4135 } 4136 } 4137 4138 void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) { 4139 Expression* sub_expr; 4140 Literal* literal; 4141 if (expr->IsLiteralCompareTypeof(&sub_expr, &literal)) { 4142 // Emit a fast literal comparion for expressions of the form: 4143 // typeof(x) === 'string'. 4144 VisitForTypeOfValue(sub_expr); 4145 builder()->SetExpressionPosition(expr); 4146 TestTypeOfFlags::LiteralFlag literal_flag = 4147 TestTypeOfFlags::GetFlagForLiteral(ast_string_constants(), literal); 4148 if (literal_flag == TestTypeOfFlags::LiteralFlag::kOther) { 4149 builder()->LoadFalse(); 4150 } else { 4151 builder()->CompareTypeOf(literal_flag); 4152 } 4153 } else if (expr->IsLiteralCompareUndefined(&sub_expr)) { 4154 VisitForAccumulatorValue(sub_expr); 4155 builder()->SetExpressionPosition(expr); 4156 BuildLiteralCompareNil(expr->op(), BytecodeArrayBuilder::kUndefinedValue); 4157 } else if (expr->IsLiteralCompareNull(&sub_expr)) { 4158 VisitForAccumulatorValue(sub_expr); 4159 builder()->SetExpressionPosition(expr); 4160 BuildLiteralCompareNil(expr->op(), BytecodeArrayBuilder::kNullValue); 4161 } else { 4162 Register lhs = VisitForRegisterValue(expr->left()); 4163 VisitForAccumulatorValue(expr->right()); 4164 builder()->SetExpressionPosition(expr); 4165 if (expr->op() == Token::IN) { 4166 builder()->CompareOperation(expr->op(), lhs); 4167 } else if (expr->op() == Token::INSTANCEOF) { 4168 FeedbackSlot slot = feedback_spec()->AddInstanceOfSlot(); 4169 builder()->CompareOperation(expr->op(), lhs, feedback_index(slot)); 4170 } else { 4171 FeedbackSlot slot = feedback_spec()->AddCompareICSlot(); 4172 builder()->CompareOperation(expr->op(), lhs, feedback_index(slot)); 4173 } 4174 } 4175 // Always returns a boolean value. 4176 execution_result()->SetResultIsBoolean(); 4177 } 4178 4179 void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) { 4180 FeedbackSlot slot = feedback_spec()->AddBinaryOpICSlot(); 4181 Expression* subexpr; 4182 Smi* literal; 4183 if (expr->IsSmiLiteralOperation(&subexpr, &literal)) { 4184 TypeHint type_hint = VisitForAccumulatorValue(subexpr); 4185 builder()->SetExpressionPosition(expr); 4186 builder()->BinaryOperationSmiLiteral(expr->op(), literal, 4187 feedback_index(slot)); 4188 if (expr->op() == Token::ADD && type_hint == TypeHint::kString) { 4189 execution_result()->SetResultIsString(); 4190 } 4191 } else { 4192 TypeHint lhs_type = VisitForAccumulatorValue(expr->left()); 4193 Register lhs = register_allocator()->NewRegister(); 4194 builder()->StoreAccumulatorInRegister(lhs); 4195 TypeHint rhs_type = VisitForAccumulatorValue(expr->right()); 4196 if (expr->op() == Token::ADD && 4197 (lhs_type == TypeHint::kString || rhs_type == TypeHint::kString)) { 4198 execution_result()->SetResultIsString(); 4199 } 4200 4201 builder()->SetExpressionPosition(expr); 4202 builder()->BinaryOperation(expr->op(), lhs, feedback_index(slot)); 4203 } 4204 } 4205 4206 void BytecodeGenerator::VisitNaryArithmeticExpression(NaryOperation* expr) { 4207 // TODO(leszeks): Add support for lhs smi in commutative ops. 4208 TypeHint type_hint = VisitForAccumulatorValue(expr->first()); 4209 4210 for (size_t i = 0; i < expr->subsequent_length(); ++i) { 4211 RegisterAllocationScope register_scope(this); 4212 if (expr->subsequent(i)->IsSmiLiteral()) { 4213 builder()->SetExpressionPosition(expr->subsequent_op_position(i)); 4214 builder()->BinaryOperationSmiLiteral( 4215 expr->op(), expr->subsequent(i)->AsLiteral()->AsSmiLiteral(), 4216 feedback_index(feedback_spec()->AddBinaryOpICSlot())); 4217 } else { 4218 Register lhs = register_allocator()->NewRegister(); 4219 builder()->StoreAccumulatorInRegister(lhs); 4220 TypeHint rhs_hint = VisitForAccumulatorValue(expr->subsequent(i)); 4221 if (rhs_hint == TypeHint::kString) type_hint = TypeHint::kString; 4222 builder()->SetExpressionPosition(expr->subsequent_op_position(i)); 4223 builder()->BinaryOperation( 4224 expr->op(), lhs, 4225 feedback_index(feedback_spec()->AddBinaryOpICSlot())); 4226 } 4227 } 4228 4229 if (type_hint == TypeHint::kString && expr->op() == Token::ADD) { 4230 // If any operand of an ADD is a String, a String is produced. 4231 execution_result()->SetResultIsString(); 4232 } 4233 } 4234 4235 // Note: the actual spreading is performed by the surrounding expression's 4236 // visitor. 4237 void BytecodeGenerator::VisitSpread(Spread* expr) { Visit(expr->expression()); } 4238 4239 void BytecodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) { 4240 UNREACHABLE(); 4241 } 4242 4243 void BytecodeGenerator::VisitImportCallExpression(ImportCallExpression* expr) { 4244 RegisterList args = register_allocator()->NewRegisterList(2); 4245 VisitForRegisterValue(expr->argument(), args[1]); 4246 builder() 4247 ->MoveRegister(Register::function_closure(), args[0]) 4248 .CallRuntime(Runtime::kDynamicImportCall, args); 4249 } 4250 4251 void BytecodeGenerator::BuildGetIterator(Expression* iterable, 4252 IteratorType hint) { 4253 RegisterList args = register_allocator()->NewRegisterList(1); 4254 Register method = register_allocator()->NewRegister(); 4255 Register obj = args[0]; 4256 4257 VisitForAccumulatorValue(iterable); 4258 4259 if (hint == IteratorType::kAsync) { 4260 // Set method to GetMethod(obj, @@asyncIterator) 4261 builder()->StoreAccumulatorInRegister(obj).LoadAsyncIteratorProperty( 4262 obj, feedback_index(feedback_spec()->AddLoadICSlot())); 4263 4264 BytecodeLabel async_iterator_undefined, async_iterator_null, done; 4265 // TODO(ignition): Add a single opcode for JumpIfNullOrUndefined 4266 builder()->JumpIfUndefined(&async_iterator_undefined); 4267 builder()->JumpIfNull(&async_iterator_null); 4268 4269 // Let iterator be Call(method, obj) 4270 builder()->StoreAccumulatorInRegister(method).CallProperty( 4271 method, args, feedback_index(feedback_spec()->AddCallICSlot())); 4272 4273 // If Type(iterator) is not Object, throw a TypeError exception. 4274 builder()->JumpIfJSReceiver(&done); 4275 builder()->CallRuntime(Runtime::kThrowSymbolAsyncIteratorInvalid); 4276 4277 builder()->Bind(&async_iterator_undefined); 4278 builder()->Bind(&async_iterator_null); 4279 // If method is undefined, 4280 // Let syncMethod be GetMethod(obj, @@iterator) 4281 builder() 4282 ->LoadIteratorProperty(obj, 4283 feedback_index(feedback_spec()->AddLoadICSlot())) 4284 .StoreAccumulatorInRegister(method); 4285 4286 // Let syncIterator be Call(syncMethod, obj) 4287 builder()->CallProperty(method, args, 4288 feedback_index(feedback_spec()->AddCallICSlot())); 4289 4290 // Return CreateAsyncFromSyncIterator(syncIterator) 4291 // alias `method` register as it's no longer used 4292 Register sync_iter = method; 4293 builder()->StoreAccumulatorInRegister(sync_iter).CallRuntime( 4294 Runtime::kInlineCreateAsyncFromSyncIterator, sync_iter); 4295 4296 builder()->Bind(&done); 4297 } else { 4298 // Let method be GetMethod(obj, @@iterator). 4299 builder() 4300 ->StoreAccumulatorInRegister(obj) 4301 .LoadIteratorProperty(obj, 4302 feedback_index(feedback_spec()->AddLoadICSlot())) 4303 .StoreAccumulatorInRegister(method); 4304 4305 // Let iterator be Call(method, obj). 4306 builder()->CallProperty(method, args, 4307 feedback_index(feedback_spec()->AddCallICSlot())); 4308 4309 // If Type(iterator) is not Object, throw a TypeError exception. 4310 BytecodeLabel no_type_error; 4311 builder()->JumpIfJSReceiver(&no_type_error); 4312 builder()->CallRuntime(Runtime::kThrowSymbolIteratorInvalid); 4313 builder()->Bind(&no_type_error); 4314 } 4315 } 4316 4317 // Returns an IteratorRecord which is valid for the lifetime of the current 4318 // register_allocation_scope. 4319 BytecodeGenerator::IteratorRecord BytecodeGenerator::BuildGetIteratorRecord( 4320 Expression* iterable, Register next, Register object, IteratorType hint) { 4321 DCHECK(next.is_valid() && object.is_valid()); 4322 BuildGetIterator(iterable, hint); 4323 4324 builder() 4325 ->StoreAccumulatorInRegister(object) 4326 .LoadNamedProperty(object, ast_string_constants()->next_string(), 4327 feedback_index(feedback_spec()->AddLoadICSlot())) 4328 .StoreAccumulatorInRegister(next); 4329 return IteratorRecord(object, next, hint); 4330 } 4331 4332 BytecodeGenerator::IteratorRecord BytecodeGenerator::BuildGetIteratorRecord( 4333 Expression* iterable, IteratorType hint) { 4334 Register next = register_allocator()->NewRegister(); 4335 Register object = register_allocator()->NewRegister(); 4336 return BuildGetIteratorRecord(iterable, next, object, hint); 4337 } 4338 4339 void BytecodeGenerator::BuildIteratorNext(const IteratorRecord& iterator, 4340 Register next_result) { 4341 DCHECK(next_result.is_valid()); 4342 builder()->CallProperty(iterator.next(), RegisterList(iterator.object()), 4343 feedback_index(feedback_spec()->AddCallICSlot())); 4344 4345 // TODO(caitp): support async IteratorNext here. 4346 4347 BytecodeLabel is_object; 4348 builder() 4349 ->StoreAccumulatorInRegister(next_result) 4350 .JumpIfJSReceiver(&is_object) 4351 .CallRuntime(Runtime::kThrowIteratorResultNotAnObject, next_result) 4352 .Bind(&is_object); 4353 } 4354 4355 void BytecodeGenerator::BuildCallIteratorMethod(Register iterator, 4356 const AstRawString* method_name, 4357 RegisterList receiver_and_args, 4358 BytecodeLabel* if_called, 4359 BytecodeLabels* if_notcalled) { 4360 RegisterAllocationScope register_scope(this); 4361 4362 Register method = register_allocator()->NewRegister(); 4363 FeedbackSlot slot = feedback_spec()->AddLoadICSlot(); 4364 builder() 4365 ->LoadNamedProperty(iterator, method_name, feedback_index(slot)) 4366 .JumpIfUndefined(if_notcalled->New()) 4367 .JumpIfNull(if_notcalled->New()) 4368 .StoreAccumulatorInRegister(method) 4369 .CallProperty(method, receiver_and_args, 4370 feedback_index(feedback_spec()->AddCallICSlot())) 4371 .Jump(if_called); 4372 } 4373 4374 void BytecodeGenerator::BuildIteratorClose(const IteratorRecord& iterator, 4375 Expression* expr) { 4376 RegisterAllocationScope register_scope(this); 4377 BytecodeLabels done(zone()); 4378 BytecodeLabel if_called; 4379 RegisterList args = RegisterList(iterator.object()); 4380 BuildCallIteratorMethod(iterator.object(), 4381 ast_string_constants()->return_string(), args, 4382 &if_called, &done); 4383 builder()->Bind(&if_called); 4384 4385 if (iterator.type() == IteratorType::kAsync) { 4386 DCHECK_NOT_NULL(expr); 4387 BuildAwait(expr); 4388 } 4389 4390 builder()->JumpIfJSReceiver(done.New()); 4391 { 4392 RegisterAllocationScope register_scope(this); 4393 Register return_result = register_allocator()->NewRegister(); 4394 builder() 4395 ->StoreAccumulatorInRegister(return_result) 4396 .CallRuntime(Runtime::kThrowIteratorResultNotAnObject, return_result); 4397 } 4398 4399 done.Bind(builder()); 4400 } 4401 4402 void BytecodeGenerator::VisitGetIterator(GetIterator* expr) { 4403 builder()->SetExpressionPosition(expr); 4404 BuildGetIterator(expr->iterable(), expr->hint()); 4405 } 4406 4407 void BytecodeGenerator::VisitGetTemplateObject(GetTemplateObject* expr) { 4408 builder()->SetExpressionPosition(expr); 4409 size_t entry = builder()->AllocateDeferredConstantPoolEntry(); 4410 template_objects_.push_back(std::make_pair(expr, entry)); 4411 FeedbackSlot literal_slot = feedback_spec()->AddLiteralSlot(); 4412 builder()->GetTemplateObject(entry, feedback_index(literal_slot)); 4413 } 4414 4415 void BytecodeGenerator::VisitTemplateLiteral(TemplateLiteral* expr) { 4416 const ZonePtrList<const AstRawString>& parts = *expr->string_parts(); 4417 const ZonePtrList<Expression>& substitutions = *expr->substitutions(); 4418 // Template strings with no substitutions are turned into StringLiterals. 4419 DCHECK_GT(substitutions.length(), 0); 4420 DCHECK_EQ(parts.length(), substitutions.length() + 1); 4421 4422 // Generate string concatenation 4423 // TODO(caitp): Don't generate feedback slot if it's not used --- introduce 4424 // a simple, concise, reusable mechanism to lazily create reusable slots. 4425 FeedbackSlot slot = feedback_spec()->AddBinaryOpICSlot(); 4426 Register last_part = register_allocator()->NewRegister(); 4427 bool last_part_valid = false; 4428 4429 builder()->SetExpressionPosition(expr); 4430 for (int i = 0; i < substitutions.length(); ++i) { 4431 if (i != 0) { 4432 builder()->StoreAccumulatorInRegister(last_part); 4433 last_part_valid = true; 4434 } 4435 4436 if (!parts[i]->IsEmpty()) { 4437 builder()->LoadLiteral(parts[i]); 4438 if (last_part_valid) { 4439 builder()->BinaryOperation(Token::ADD, last_part, feedback_index(slot)); 4440 } 4441 builder()->StoreAccumulatorInRegister(last_part); 4442 last_part_valid = true; 4443 } 4444 4445 TypeHint type_hint = VisitForAccumulatorValue(substitutions[i]); 4446 if (type_hint != TypeHint::kString) { 4447 builder()->ToString(); 4448 } 4449 if (last_part_valid) { 4450 builder()->BinaryOperation(Token::ADD, last_part, feedback_index(slot)); 4451 } 4452 last_part_valid = false; 4453 } 4454 4455 if (!parts.last()->IsEmpty()) { 4456 builder()->StoreAccumulatorInRegister(last_part); 4457 builder()->LoadLiteral(parts.last()); 4458 builder()->BinaryOperation(Token::ADD, last_part, feedback_index(slot)); 4459 } 4460 } 4461 4462 void BytecodeGenerator::VisitThisFunction(ThisFunction* expr) { 4463 builder()->LoadAccumulatorWithRegister(Register::function_closure()); 4464 } 4465 4466 void BytecodeGenerator::VisitSuperCallReference(SuperCallReference* expr) { 4467 // Handled by VisitCall(). 4468 UNREACHABLE(); 4469 } 4470 4471 void BytecodeGenerator::VisitSuperPropertyReference( 4472 SuperPropertyReference* expr) { 4473 builder()->CallRuntime(Runtime::kThrowUnsupportedSuperError); 4474 } 4475 4476 void BytecodeGenerator::VisitCommaExpression(BinaryOperation* binop) { 4477 VisitForEffect(binop->left()); 4478 Visit(binop->right()); 4479 } 4480 4481 void BytecodeGenerator::VisitNaryCommaExpression(NaryOperation* expr) { 4482 DCHECK_GT(expr->subsequent_length(), 0); 4483 4484 VisitForEffect(expr->first()); 4485 for (size_t i = 0; i < expr->subsequent_length() - 1; ++i) { 4486 VisitForEffect(expr->subsequent(i)); 4487 } 4488 Visit(expr->subsequent(expr->subsequent_length() - 1)); 4489 } 4490 4491 void BytecodeGenerator::VisitLogicalTestSubExpression( 4492 Token::Value token, Expression* expr, BytecodeLabels* then_labels, 4493 BytecodeLabels* else_labels, int coverage_slot) { 4494 DCHECK(token == Token::OR || token == Token::AND); 4495 4496 BytecodeLabels test_next(zone()); 4497 if (token == Token::OR) { 4498 VisitForTest(expr, then_labels, &test_next, TestFallthrough::kElse); 4499 } else { 4500 DCHECK_EQ(Token::AND, token); 4501 VisitForTest(expr, &test_next, else_labels, TestFallthrough::kThen); 4502 } 4503 test_next.Bind(builder()); 4504 4505 BuildIncrementBlockCoverageCounterIfEnabled(coverage_slot); 4506 } 4507 4508 void BytecodeGenerator::VisitLogicalTest(Token::Value token, Expression* left, 4509 Expression* right, 4510 int right_coverage_slot) { 4511 DCHECK(token == Token::OR || token == Token::AND); 4512 TestResultScope* test_result = execution_result()->AsTest(); 4513 BytecodeLabels* then_labels = test_result->then_labels(); 4514 BytecodeLabels* else_labels = test_result->else_labels(); 4515 TestFallthrough fallthrough = test_result->fallthrough(); 4516 4517 VisitLogicalTestSubExpression(token, left, then_labels, else_labels, 4518 right_coverage_slot); 4519 // The last test has the same then, else and fallthrough as the parent test. 4520 VisitForTest(right, then_labels, else_labels, fallthrough); 4521 } 4522 4523 void BytecodeGenerator::VisitNaryLogicalTest( 4524 Token::Value token, NaryOperation* expr, 4525 const NaryCodeCoverageSlots* coverage_slots) { 4526 DCHECK(token == Token::OR || token == Token::AND); 4527 DCHECK_GT(expr->subsequent_length(), 0); 4528 4529 TestResultScope* test_result = execution_result()->AsTest(); 4530 BytecodeLabels* then_labels = test_result->then_labels(); 4531 BytecodeLabels* else_labels = test_result->else_labels(); 4532 TestFallthrough fallthrough = test_result->fallthrough(); 4533 4534 VisitLogicalTestSubExpression(token, expr->first(), then_labels, else_labels, 4535 coverage_slots->GetSlotFor(0)); 4536 for (size_t i = 0; i < expr->subsequent_length() - 1; ++i) { 4537 VisitLogicalTestSubExpression(token, expr->subsequent(i), then_labels, 4538 else_labels, 4539 coverage_slots->GetSlotFor(i + 1)); 4540 } 4541 // The last test has the same then, else and fallthrough as the parent test. 4542 VisitForTest(expr->subsequent(expr->subsequent_length() - 1), then_labels, 4543 else_labels, fallthrough); 4544 } 4545 4546 bool BytecodeGenerator::VisitLogicalOrSubExpression(Expression* expr, 4547 BytecodeLabels* end_labels, 4548 int coverage_slot) { 4549 if (expr->ToBooleanIsTrue()) { 4550 VisitForAccumulatorValue(expr); 4551 end_labels->Bind(builder()); 4552 return true; 4553 } else if (!expr->ToBooleanIsFalse()) { 4554 TypeHint type_hint = VisitForAccumulatorValue(expr); 4555 builder()->JumpIfTrue(ToBooleanModeFromTypeHint(type_hint), 4556 end_labels->New()); 4557 } 4558 4559 BuildIncrementBlockCoverageCounterIfEnabled(coverage_slot); 4560 4561 return false; 4562 } 4563 4564 bool BytecodeGenerator::VisitLogicalAndSubExpression(Expression* expr, 4565 BytecodeLabels* end_labels, 4566 int coverage_slot) { 4567 if (expr->ToBooleanIsFalse()) { 4568 VisitForAccumulatorValue(expr); 4569 end_labels->Bind(builder()); 4570 return true; 4571 } else if (!expr->ToBooleanIsTrue()) { 4572 TypeHint type_hint = VisitForAccumulatorValue(expr); 4573 builder()->JumpIfFalse(ToBooleanModeFromTypeHint(type_hint), 4574 end_labels->New()); 4575 } 4576 4577 BuildIncrementBlockCoverageCounterIfEnabled(coverage_slot); 4578 4579 return false; 4580 } 4581 4582 void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) { 4583 Expression* left = binop->left(); 4584 Expression* right = binop->right(); 4585 4586 int right_coverage_slot = 4587 AllocateBlockCoverageSlotIfEnabled(binop, SourceRangeKind::kRight); 4588 4589 if (execution_result()->IsTest()) { 4590 TestResultScope* test_result = execution_result()->AsTest(); 4591 if (left->ToBooleanIsTrue()) { 4592 builder()->Jump(test_result->NewThenLabel()); 4593 } else if (left->ToBooleanIsFalse() && right->ToBooleanIsFalse()) { 4594 BuildIncrementBlockCoverageCounterIfEnabled(right_coverage_slot); 4595 builder()->Jump(test_result->NewElseLabel()); 4596 } else { 4597 VisitLogicalTest(Token::OR, left, right, right_coverage_slot); 4598 } 4599 test_result->SetResultConsumedByTest(); 4600 } else { 4601 BytecodeLabels end_labels(zone()); 4602 if (VisitLogicalOrSubExpression(left, &end_labels, right_coverage_slot)) { 4603 return; 4604 } 4605 VisitForAccumulatorValue(right); 4606 end_labels.Bind(builder()); 4607 } 4608 } 4609 4610 void BytecodeGenerator::VisitNaryLogicalOrExpression(NaryOperation* expr) { 4611 Expression* first = expr->first(); 4612 DCHECK_GT(expr->subsequent_length(), 0); 4613 4614 NaryCodeCoverageSlots coverage_slots(this, expr); 4615 4616 if (execution_result()->IsTest()) { 4617 TestResultScope* test_result = execution_result()->AsTest(); 4618 if (first->ToBooleanIsTrue()) { 4619 builder()->Jump(test_result->NewThenLabel()); 4620 } else { 4621 VisitNaryLogicalTest(Token::OR, expr, &coverage_slots); 4622 } 4623 test_result->SetResultConsumedByTest(); 4624 } else { 4625 BytecodeLabels end_labels(zone()); 4626 if (VisitLogicalOrSubExpression(first, &end_labels, 4627 coverage_slots.GetSlotFor(0))) { 4628 return; 4629 } 4630 for (size_t i = 0; i < expr->subsequent_length() - 1; ++i) { 4631 if (VisitLogicalOrSubExpression(expr->subsequent(i), &end_labels, 4632 coverage_slots.GetSlotFor(i + 1))) { 4633 return; 4634 } 4635 } 4636 // We have to visit the last value even if it's true, because we need its 4637 // actual value. 4638 VisitForAccumulatorValue(expr->subsequent(expr->subsequent_length() - 1)); 4639 end_labels.Bind(builder()); 4640 } 4641 } 4642 4643 void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) { 4644 Expression* left = binop->left(); 4645 Expression* right = binop->right(); 4646 4647 int right_coverage_slot = 4648 AllocateBlockCoverageSlotIfEnabled(binop, SourceRangeKind::kRight); 4649 4650 if (execution_result()->IsTest()) { 4651 TestResultScope* test_result = execution_result()->AsTest(); 4652 if (left->ToBooleanIsFalse()) { 4653 builder()->Jump(test_result->NewElseLabel()); 4654 } else if (left->ToBooleanIsTrue() && right->ToBooleanIsTrue()) { 4655 BuildIncrementBlockCoverageCounterIfEnabled(right_coverage_slot); 4656 builder()->Jump(test_result->NewThenLabel()); 4657 } else { 4658 VisitLogicalTest(Token::AND, left, right, right_coverage_slot); 4659 } 4660 test_result->SetResultConsumedByTest(); 4661 } else { 4662 BytecodeLabels end_labels(zone()); 4663 if (VisitLogicalAndSubExpression(left, &end_labels, right_coverage_slot)) { 4664 return; 4665 } 4666 VisitForAccumulatorValue(right); 4667 end_labels.Bind(builder()); 4668 } 4669 } 4670 4671 void BytecodeGenerator::VisitNaryLogicalAndExpression(NaryOperation* expr) { 4672 Expression* first = expr->first(); 4673 DCHECK_GT(expr->subsequent_length(), 0); 4674 4675 NaryCodeCoverageSlots coverage_slots(this, expr); 4676 4677 if (execution_result()->IsTest()) { 4678 TestResultScope* test_result = execution_result()->AsTest(); 4679 if (first->ToBooleanIsFalse()) { 4680 builder()->Jump(test_result->NewElseLabel()); 4681 } else { 4682 VisitNaryLogicalTest(Token::AND, expr, &coverage_slots); 4683 } 4684 test_result->SetResultConsumedByTest(); 4685 } else { 4686 BytecodeLabels end_labels(zone()); 4687 if (VisitLogicalAndSubExpression(first, &end_labels, 4688 coverage_slots.GetSlotFor(0))) { 4689 return; 4690 } 4691 for (size_t i = 0; i < expr->subsequent_length() - 1; ++i) { 4692 if (VisitLogicalAndSubExpression(expr->subsequent(i), &end_labels, 4693 coverage_slots.GetSlotFor(i + 1))) { 4694 return; 4695 } 4696 } 4697 // We have to visit the last value even if it's false, because we need its 4698 // actual value. 4699 VisitForAccumulatorValue(expr->subsequent(expr->subsequent_length() - 1)); 4700 end_labels.Bind(builder()); 4701 } 4702 } 4703 4704 void BytecodeGenerator::VisitRewritableExpression(RewritableExpression* expr) { 4705 Visit(expr->expression()); 4706 } 4707 4708 void BytecodeGenerator::BuildNewLocalActivationContext() { 4709 ValueResultScope value_execution_result(this); 4710 Scope* scope = closure_scope(); 4711 DCHECK_EQ(current_scope(), closure_scope()); 4712 4713 // Create the appropriate context. 4714 if (scope->is_script_scope()) { 4715 Register scope_reg = register_allocator()->NewRegister(); 4716 builder() 4717 ->LoadLiteral(scope) 4718 .StoreAccumulatorInRegister(scope_reg) 4719 .CallRuntime(Runtime::kNewScriptContext, scope_reg); 4720 } else if (scope->is_module_scope()) { 4721 // We don't need to do anything for the outer script scope. 4722 DCHECK(scope->outer_scope()->is_script_scope()); 4723 4724 // A JSFunction representing a module is called with the module object as 4725 // its sole argument. 4726 RegisterList args = register_allocator()->NewRegisterList(2); 4727 builder() 4728 ->MoveRegister(builder()->Parameter(0), args[0]) 4729 .LoadLiteral(scope) 4730 .StoreAccumulatorInRegister(args[1]) 4731 .CallRuntime(Runtime::kPushModuleContext, args); 4732 } else { 4733 DCHECK(scope->is_function_scope() || scope->is_eval_scope()); 4734 int slot_count = scope->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; 4735 if (slot_count <= ConstructorBuiltins::MaximumFunctionContextSlots()) { 4736 switch (scope->scope_type()) { 4737 case EVAL_SCOPE: 4738 builder()->CreateEvalContext(scope, slot_count); 4739 break; 4740 case FUNCTION_SCOPE: 4741 builder()->CreateFunctionContext(scope, slot_count); 4742 break; 4743 default: 4744 UNREACHABLE(); 4745 } 4746 } else { 4747 Register arg = register_allocator()->NewRegister(); 4748 builder()->LoadLiteral(scope).StoreAccumulatorInRegister(arg).CallRuntime( 4749 Runtime::kNewFunctionContext, arg); 4750 } 4751 } 4752 } 4753 4754 void BytecodeGenerator::BuildLocalActivationContextInitialization() { 4755 DeclarationScope* scope = closure_scope(); 4756 4757 if (scope->has_this_declaration() && scope->receiver()->IsContextSlot()) { 4758 Variable* variable = scope->receiver(); 4759 Register receiver(builder()->Receiver()); 4760 // Context variable (at bottom of the context chain). 4761 DCHECK_EQ(0, scope->ContextChainLength(variable->scope())); 4762 builder()->LoadAccumulatorWithRegister(receiver).StoreContextSlot( 4763 execution_context()->reg(), variable->index(), 0); 4764 } 4765 4766 // Copy parameters into context if necessary. 4767 int num_parameters = scope->num_parameters(); 4768 for (int i = 0; i < num_parameters; i++) { 4769 Variable* variable = scope->parameter(i); 4770 if (!variable->IsContextSlot()) continue; 4771 4772 Register parameter(builder()->Parameter(i)); 4773 // Context variable (at bottom of the context chain). 4774 DCHECK_EQ(0, scope->ContextChainLength(variable->scope())); 4775 builder()->LoadAccumulatorWithRegister(parameter).StoreContextSlot( 4776 execution_context()->reg(), variable->index(), 0); 4777 } 4778 } 4779 4780 void BytecodeGenerator::BuildNewLocalBlockContext(Scope* scope) { 4781 ValueResultScope value_execution_result(this); 4782 DCHECK(scope->is_block_scope()); 4783 4784 builder()->CreateBlockContext(scope); 4785 } 4786 4787 void BytecodeGenerator::BuildNewLocalWithContext(Scope* scope) { 4788 ValueResultScope value_execution_result(this); 4789 4790 Register extension_object = register_allocator()->NewRegister(); 4791 4792 builder()->ToObject(extension_object); 4793 builder()->CreateWithContext(extension_object, scope); 4794 } 4795 4796 void BytecodeGenerator::BuildNewLocalCatchContext(Scope* scope) { 4797 ValueResultScope value_execution_result(this); 4798 DCHECK(scope->catch_variable()->IsContextSlot()); 4799 4800 Register exception = register_allocator()->NewRegister(); 4801 builder()->StoreAccumulatorInRegister(exception); 4802 builder()->CreateCatchContext(exception, scope); 4803 } 4804 4805 void BytecodeGenerator::VisitObjectLiteralAccessor( 4806 Register home_object, ObjectLiteralProperty* property, Register value_out) { 4807 if (property == nullptr) { 4808 builder()->LoadNull().StoreAccumulatorInRegister(value_out); 4809 } else { 4810 VisitForRegisterValue(property->value(), value_out); 4811 VisitSetHomeObject(value_out, home_object, property); 4812 } 4813 } 4814 4815 void BytecodeGenerator::VisitSetHomeObject(Register value, Register home_object, 4816 LiteralProperty* property) { 4817 Expression* expr = property->value(); 4818 if (FunctionLiteral::NeedsHomeObject(expr)) { 4819 FeedbackSlot slot = feedback_spec()->AddStoreICSlot(language_mode()); 4820 builder() 4821 ->LoadAccumulatorWithRegister(home_object) 4822 .StoreHomeObjectProperty(value, feedback_index(slot), language_mode()); 4823 } 4824 } 4825 4826 void BytecodeGenerator::VisitArgumentsObject(Variable* variable) { 4827 if (variable == nullptr) return; 4828 4829 DCHECK(variable->IsContextSlot() || variable->IsStackAllocated()); 4830 4831 // Allocate and initialize a new arguments object and assign to the 4832 // {arguments} variable. 4833 builder()->CreateArguments(closure_scope()->GetArgumentsType()); 4834 BuildVariableAssignment(variable, Token::ASSIGN, HoleCheckMode::kElided); 4835 } 4836 4837 void BytecodeGenerator::VisitRestArgumentsArray(Variable* rest) { 4838 if (rest == nullptr) return; 4839 4840 // Allocate and initialize a new rest parameter and assign to the {rest} 4841 // variable. 4842 builder()->CreateArguments(CreateArgumentsType::kRestParameter); 4843 DCHECK(rest->IsContextSlot() || rest->IsStackAllocated()); 4844 BuildVariableAssignment(rest, Token::ASSIGN, HoleCheckMode::kElided); 4845 } 4846 4847 void BytecodeGenerator::VisitThisFunctionVariable(Variable* variable) { 4848 if (variable == nullptr) return; 4849 4850 // Store the closure we were called with in the given variable. 4851 builder()->LoadAccumulatorWithRegister(Register::function_closure()); 4852 BuildVariableAssignment(variable, Token::INIT, HoleCheckMode::kElided); 4853 } 4854 4855 void BytecodeGenerator::VisitNewTargetVariable(Variable* variable) { 4856 if (variable == nullptr) return; 4857 4858 // The generator resume trampoline abuses the new.target register 4859 // to pass in the generator object. In ordinary calls, new.target is always 4860 // undefined because generator functions are non-constructible, so don't 4861 // assign anything to the new.target variable. 4862 if (info()->literal()->CanSuspend()) return; 4863 4864 if (variable->location() == VariableLocation::LOCAL) { 4865 // The new.target register was already assigned by entry trampoline. 4866 DCHECK_EQ(incoming_new_target_or_generator_.index(), 4867 GetRegisterForLocalVariable(variable).index()); 4868 return; 4869 } 4870 4871 // Store the new target we were called with in the given variable. 4872 builder()->LoadAccumulatorWithRegister(incoming_new_target_or_generator_); 4873 BuildVariableAssignment(variable, Token::INIT, HoleCheckMode::kElided); 4874 } 4875 4876 void BytecodeGenerator::BuildGeneratorObjectVariableInitialization() { 4877 DCHECK(IsResumableFunction(info()->literal()->kind())); 4878 4879 Variable* generator_object_var = closure_scope()->generator_object_var(); 4880 RegisterAllocationScope register_scope(this); 4881 RegisterList args = register_allocator()->NewRegisterList(2); 4882 builder() 4883 ->MoveRegister(Register::function_closure(), args[0]) 4884 .MoveRegister(builder()->Receiver(), args[1]) 4885 .CallRuntime(Runtime::kInlineCreateJSGeneratorObject, args) 4886 .StoreAccumulatorInRegister(generator_object()); 4887 4888 if (generator_object_var->location() == VariableLocation::LOCAL) { 4889 // The generator object register is already set to the variable's local 4890 // register. 4891 DCHECK_EQ(generator_object().index(), 4892 GetRegisterForLocalVariable(generator_object_var).index()); 4893 } else { 4894 BuildVariableAssignment(generator_object_var, Token::INIT, 4895 HoleCheckMode::kElided); 4896 } 4897 } 4898 4899 void BytecodeGenerator::BuildPushUndefinedIntoRegisterList( 4900 RegisterList* reg_list) { 4901 Register reg = register_allocator()->GrowRegisterList(reg_list); 4902 builder()->LoadUndefined().StoreAccumulatorInRegister(reg); 4903 } 4904 4905 void BytecodeGenerator::BuildLoadPropertyKey(LiteralProperty* property, 4906 Register out_reg) { 4907 if (property->key()->IsStringLiteral()) { 4908 VisitForRegisterValue(property->key(), out_reg); 4909 } else { 4910 VisitForAccumulatorValue(property->key()); 4911 builder()->ToName(out_reg); 4912 } 4913 } 4914 4915 int BytecodeGenerator::AllocateBlockCoverageSlotIfEnabled( 4916 AstNode* node, SourceRangeKind kind) { 4917 return (block_coverage_builder_ == nullptr) 4918 ? BlockCoverageBuilder::kNoCoverageArraySlot 4919 : block_coverage_builder_->AllocateBlockCoverageSlot(node, kind); 4920 } 4921 4922 int BytecodeGenerator::AllocateNaryBlockCoverageSlotIfEnabled( 4923 NaryOperation* node, size_t index) { 4924 return (block_coverage_builder_ == nullptr) 4925 ? BlockCoverageBuilder::kNoCoverageArraySlot 4926 : block_coverage_builder_->AllocateNaryBlockCoverageSlot(node, 4927 index); 4928 } 4929 4930 void BytecodeGenerator::BuildIncrementBlockCoverageCounterIfEnabled( 4931 AstNode* node, SourceRangeKind kind) { 4932 if (block_coverage_builder_ == nullptr) return; 4933 block_coverage_builder_->IncrementBlockCounter(node, kind); 4934 } 4935 4936 void BytecodeGenerator::BuildIncrementBlockCoverageCounterIfEnabled( 4937 int coverage_array_slot) { 4938 if (block_coverage_builder_ != nullptr) { 4939 block_coverage_builder_->IncrementBlockCounter(coverage_array_slot); 4940 } 4941 } 4942 4943 // Visits the expression |expr| and places the result in the accumulator. 4944 BytecodeGenerator::TypeHint BytecodeGenerator::VisitForAccumulatorValue( 4945 Expression* expr) { 4946 ValueResultScope accumulator_scope(this); 4947 Visit(expr); 4948 return accumulator_scope.type_hint(); 4949 } 4950 4951 void BytecodeGenerator::VisitForAccumulatorValueOrTheHole(Expression* expr) { 4952 if (expr == nullptr) { 4953 builder()->LoadTheHole(); 4954 } else { 4955 VisitForAccumulatorValue(expr); 4956 } 4957 } 4958 4959 // Visits the expression |expr| and discards the result. 4960 void BytecodeGenerator::VisitForEffect(Expression* expr) { 4961 EffectResultScope effect_scope(this); 4962 Visit(expr); 4963 } 4964 4965 // Visits the expression |expr| and returns the register containing 4966 // the expression result. 4967 Register BytecodeGenerator::VisitForRegisterValue(Expression* expr) { 4968 VisitForAccumulatorValue(expr); 4969 Register result = register_allocator()->NewRegister(); 4970 builder()->StoreAccumulatorInRegister(result); 4971 return result; 4972 } 4973 4974 // Visits the expression |expr| and stores the expression result in 4975 // |destination|. 4976 void BytecodeGenerator::VisitForRegisterValue(Expression* expr, 4977 Register destination) { 4978 ValueResultScope register_scope(this); 4979 Visit(expr); 4980 builder()->StoreAccumulatorInRegister(destination); 4981 } 4982 4983 // Visits the expression |expr| and pushes the result into a new register 4984 // added to the end of |reg_list|. 4985 void BytecodeGenerator::VisitAndPushIntoRegisterList(Expression* expr, 4986 RegisterList* reg_list) { 4987 { 4988 ValueResultScope register_scope(this); 4989 Visit(expr); 4990 } 4991 // Grow the register list after visiting the expression to avoid reserving 4992 // the register across the expression evaluation, which could cause memory 4993 // leaks for deep expressions due to dead objects being kept alive by pointers 4994 // in registers. 4995 Register destination = register_allocator()->GrowRegisterList(reg_list); 4996 builder()->StoreAccumulatorInRegister(destination); 4997 } 4998 4999 void BytecodeGenerator::BuildTest(ToBooleanMode mode, 5000 BytecodeLabels* then_labels, 5001 BytecodeLabels* else_labels, 5002 TestFallthrough fallthrough) { 5003 switch (fallthrough) { 5004 case TestFallthrough::kThen: 5005 builder()->JumpIfFalse(mode, else_labels->New()); 5006 break; 5007 case TestFallthrough::kElse: 5008 builder()->JumpIfTrue(mode, then_labels->New()); 5009 break; 5010 case TestFallthrough::kNone: 5011 builder()->JumpIfTrue(mode, then_labels->New()); 5012 builder()->Jump(else_labels->New()); 5013 break; 5014 } 5015 } 5016 5017 // Visits the expression |expr| for testing its boolean value and jumping to the 5018 // |then| or |other| label depending on value and short-circuit semantics 5019 void BytecodeGenerator::VisitForTest(Expression* expr, 5020 BytecodeLabels* then_labels, 5021 BytecodeLabels* else_labels, 5022 TestFallthrough fallthrough) { 5023 bool result_consumed; 5024 TypeHint type_hint; 5025 { 5026 // To make sure that all temporary registers are returned before generating 5027 // jumps below, we ensure that the result scope is deleted before doing so. 5028 // Dead registers might be materialized otherwise. 5029 TestResultScope test_result(this, then_labels, else_labels, fallthrough); 5030 Visit(expr); 5031 result_consumed = test_result.result_consumed_by_test(); 5032 type_hint = test_result.type_hint(); 5033 // Labels and fallthrough might have been mutated, so update based on 5034 // TestResultScope. 5035 then_labels = test_result.then_labels(); 5036 else_labels = test_result.else_labels(); 5037 fallthrough = test_result.fallthrough(); 5038 } 5039 if (!result_consumed) { 5040 BuildTest(ToBooleanModeFromTypeHint(type_hint), then_labels, else_labels, 5041 fallthrough); 5042 } 5043 } 5044 5045 void BytecodeGenerator::VisitInSameTestExecutionScope(Expression* expr) { 5046 DCHECK(execution_result()->IsTest()); 5047 { 5048 RegisterAllocationScope reg_scope(this); 5049 Visit(expr); 5050 } 5051 if (!execution_result()->AsTest()->result_consumed_by_test()) { 5052 TestResultScope* result_scope = execution_result()->AsTest(); 5053 BuildTest(ToBooleanModeFromTypeHint(result_scope->type_hint()), 5054 result_scope->then_labels(), result_scope->else_labels(), 5055 result_scope->fallthrough()); 5056 result_scope->SetResultConsumedByTest(); 5057 } 5058 } 5059 5060 void BytecodeGenerator::VisitInScope(Statement* stmt, Scope* scope) { 5061 DCHECK(scope->declarations()->is_empty()); 5062 CurrentScope current_scope(this, scope); 5063 ContextScope context_scope(this, scope); 5064 Visit(stmt); 5065 } 5066 5067 Register BytecodeGenerator::GetRegisterForLocalVariable(Variable* variable) { 5068 DCHECK_EQ(VariableLocation::LOCAL, variable->location()); 5069 return builder()->Local(variable->index()); 5070 } 5071 5072 FunctionKind BytecodeGenerator::function_kind() const { 5073 return info()->literal()->kind(); 5074 } 5075 5076 LanguageMode BytecodeGenerator::language_mode() const { 5077 return current_scope()->language_mode(); 5078 } 5079 5080 Register BytecodeGenerator::generator_object() const { 5081 DCHECK(info()->literal()->CanSuspend()); 5082 return incoming_new_target_or_generator_; 5083 } 5084 5085 FeedbackVectorSpec* BytecodeGenerator::feedback_spec() { 5086 return info()->feedback_vector_spec(); 5087 } 5088 5089 int BytecodeGenerator::feedback_index(FeedbackSlot slot) const { 5090 DCHECK(!slot.IsInvalid()); 5091 return FeedbackVector::GetIndex(slot); 5092 } 5093 5094 FeedbackSlot BytecodeGenerator::GetCachedLoadGlobalICSlot( 5095 TypeofMode typeof_mode, Variable* variable) { 5096 FeedbackSlotKind slot_kind = 5097 typeof_mode == INSIDE_TYPEOF 5098 ? FeedbackSlotKind::kLoadGlobalInsideTypeof 5099 : FeedbackSlotKind::kLoadGlobalNotInsideTypeof; 5100 FeedbackSlot slot = feedback_slot_cache()->Get(slot_kind, variable); 5101 if (!slot.IsInvalid()) { 5102 return slot; 5103 } 5104 slot = feedback_spec()->AddLoadGlobalICSlot(typeof_mode); 5105 feedback_slot_cache()->Put(slot_kind, variable, slot); 5106 return slot; 5107 } 5108 5109 FeedbackSlot BytecodeGenerator::GetCachedStoreGlobalICSlot( 5110 LanguageMode language_mode, Variable* variable) { 5111 FeedbackSlotKind slot_kind = is_strict(language_mode) 5112 ? FeedbackSlotKind::kStoreGlobalStrict 5113 : FeedbackSlotKind::kStoreGlobalSloppy; 5114 FeedbackSlot slot = feedback_slot_cache()->Get(slot_kind, variable); 5115 if (!slot.IsInvalid()) { 5116 return slot; 5117 } 5118 slot = feedback_spec()->AddStoreGlobalICSlot(language_mode); 5119 feedback_slot_cache()->Put(slot_kind, variable, slot); 5120 return slot; 5121 } 5122 5123 FeedbackSlot BytecodeGenerator::GetCachedLoadICSlot(const Expression* expr, 5124 const AstRawString* name) { 5125 if (!FLAG_ignition_share_named_property_feedback) { 5126 return feedback_spec()->AddLoadICSlot(); 5127 } 5128 FeedbackSlotKind slot_kind = FeedbackSlotKind::kLoadProperty; 5129 if (!expr->IsVariableProxy()) { 5130 return feedback_spec()->AddLoadICSlot(); 5131 } 5132 const VariableProxy* proxy = expr->AsVariableProxy(); 5133 FeedbackSlot slot = 5134 feedback_slot_cache()->Get(slot_kind, proxy->var()->index(), name); 5135 if (!slot.IsInvalid()) { 5136 return slot; 5137 } 5138 slot = feedback_spec()->AddLoadICSlot(); 5139 feedback_slot_cache()->Put(slot_kind, proxy->var()->index(), name, slot); 5140 return slot; 5141 } 5142 5143 FeedbackSlot BytecodeGenerator::GetCachedStoreICSlot(const Expression* expr, 5144 const AstRawString* name) { 5145 if (!FLAG_ignition_share_named_property_feedback) { 5146 return feedback_spec()->AddStoreICSlot(language_mode()); 5147 } 5148 FeedbackSlotKind slot_kind = is_strict(language_mode()) 5149 ? FeedbackSlotKind::kStoreNamedStrict 5150 : FeedbackSlotKind::kStoreNamedSloppy; 5151 if (!expr->IsVariableProxy()) { 5152 return feedback_spec()->AddStoreICSlot(language_mode()); 5153 } 5154 const VariableProxy* proxy = expr->AsVariableProxy(); 5155 FeedbackSlot slot = 5156 feedback_slot_cache()->Get(slot_kind, proxy->var()->index(), name); 5157 if (!slot.IsInvalid()) { 5158 return slot; 5159 } 5160 slot = feedback_spec()->AddStoreICSlot(language_mode()); 5161 feedback_slot_cache()->Put(slot_kind, proxy->var()->index(), name, slot); 5162 return slot; 5163 } 5164 5165 FeedbackSlot BytecodeGenerator::GetCachedCreateClosureSlot( 5166 FunctionLiteral* literal) { 5167 FeedbackSlotKind slot_kind = FeedbackSlotKind::kCreateClosure; 5168 FeedbackSlot slot = feedback_slot_cache()->Get(slot_kind, literal); 5169 if (!slot.IsInvalid()) { 5170 return slot; 5171 } 5172 slot = feedback_spec()->AddCreateClosureSlot(); 5173 feedback_slot_cache()->Put(slot_kind, literal, slot); 5174 return slot; 5175 } 5176 5177 FeedbackSlot BytecodeGenerator::GetDummyCompareICSlot() { 5178 if (!dummy_feedback_slot_.IsInvalid()) { 5179 return dummy_feedback_slot_; 5180 } 5181 dummy_feedback_slot_ = feedback_spec()->AddCompareICSlot(); 5182 return dummy_feedback_slot_; 5183 } 5184 5185 Runtime::FunctionId BytecodeGenerator::StoreToSuperRuntimeId() { 5186 return is_strict(language_mode()) ? Runtime::kStoreToSuper_Strict 5187 : Runtime::kStoreToSuper_Sloppy; 5188 } 5189 5190 Runtime::FunctionId BytecodeGenerator::StoreKeyedToSuperRuntimeId() { 5191 return is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict 5192 : Runtime::kStoreKeyedToSuper_Sloppy; 5193 } 5194 5195 } // namespace interpreter 5196 } // namespace internal 5197 } // namespace v8 5198