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/ast/compile-time-value.h" 8#include "src/ast/scopes.h" 9#include "src/builtins/builtins-constructor.h" 10#include "src/code-stubs.h" 11#include "src/compilation-info.h" 12#include "src/compiler.h" 13#include "src/interpreter/bytecode-flags.h" 14#include "src/interpreter/bytecode-label.h" 15#include "src/interpreter/bytecode-register-allocator.h" 16#include "src/interpreter/control-flow-builders.h" 17#include "src/objects-inl.h" 18#include "src/parsing/parse-info.h" 19#include "src/parsing/token.h" 20 21namespace v8 { 22namespace internal { 23namespace interpreter { 24 25// Scoped class tracking context objects created by the visitor. Represents 26// mutations of the context chain within the function body, allowing pushing and 27// popping of the current {context_register} during visitation. 28class BytecodeGenerator::ContextScope BASE_EMBEDDED { 29 public: 30 ContextScope(BytecodeGenerator* generator, Scope* scope, 31 bool should_pop_context = true) 32 : generator_(generator), 33 scope_(scope), 34 outer_(generator_->execution_context()), 35 register_(Register::current_context()), 36 depth_(0), 37 should_pop_context_(should_pop_context) { 38 DCHECK(scope->NeedsContext() || outer_ == nullptr); 39 if (outer_) { 40 depth_ = outer_->depth_ + 1; 41 42 // Push the outer context into a new context register. 43 Register outer_context_reg(builder()->first_context_register().index() + 44 outer_->depth_); 45 outer_->set_register(outer_context_reg); 46 generator_->builder()->PushContext(outer_context_reg); 47 } 48 generator_->set_execution_context(this); 49 } 50 51 ~ContextScope() { 52 if (outer_ && should_pop_context_) { 53 DCHECK_EQ(register_.index(), Register::current_context().index()); 54 generator_->builder()->PopContext(outer_->reg()); 55 outer_->set_register(register_); 56 } 57 generator_->set_execution_context(outer_); 58 } 59 60 // Returns the depth of the given |scope| for the current execution context. 61 int ContextChainDepth(Scope* scope) { 62 return scope_->ContextChainLength(scope); 63 } 64 65 // Returns the execution context at |depth| in the current context chain if it 66 // is a function local execution context, otherwise returns nullptr. 67 ContextScope* Previous(int depth) { 68 if (depth > depth_) { 69 return nullptr; 70 } 71 72 ContextScope* previous = this; 73 for (int i = depth; i > 0; --i) { 74 previous = previous->outer_; 75 } 76 return previous; 77 } 78 79 Register reg() const { return register_; } 80 bool ShouldPopContext() { return should_pop_context_; } 81 82 private: 83 const BytecodeArrayBuilder* builder() const { return generator_->builder(); } 84 85 void set_register(Register reg) { register_ = reg; } 86 87 BytecodeGenerator* generator_; 88 Scope* scope_; 89 ContextScope* outer_; 90 Register register_; 91 int depth_; 92 bool should_pop_context_; 93}; 94 95// Scoped class for tracking control statements entered by the 96// visitor. The pattern derives AstGraphBuilder::ControlScope. 97class 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) { PerformCommand(CMD_BREAK, stmt); } 107 void Continue(Statement* stmt) { PerformCommand(CMD_CONTINUE, stmt); } 108 void ReturnAccumulator() { PerformCommand(CMD_RETURN, nullptr); } 109 void AsyncReturnAccumulator() { PerformCommand(CMD_ASYNC_RETURN, nullptr); } 110 void ReThrowAccumulator() { PerformCommand(CMD_RETHROW, nullptr); } 111 112 class DeferredCommands; 113 114 protected: 115 enum Command { 116 CMD_BREAK, 117 CMD_CONTINUE, 118 CMD_RETURN, 119 CMD_ASYNC_RETURN, 120 CMD_RETHROW 121 }; 122 void PerformCommand(Command command, Statement* statement); 123 virtual bool Execute(Command command, Statement* statement) = 0; 124 125 BytecodeGenerator* generator() const { return generator_; } 126 ControlScope* outer() const { return outer_; } 127 ContextScope* context() const { return context_; } 128 129 private: 130 BytecodeGenerator* generator_; 131 ControlScope* outer_; 132 ContextScope* context_; 133 134 DISALLOW_COPY_AND_ASSIGN(ControlScope); 135}; 136 137// Helper class for a try-finally control scope. It can record intercepted 138// control-flow commands that cause entry into a finally-block, and re-apply 139// them after again leaving that block. Special tokens are used to identify 140// paths going through the finally-block to dispatch after leaving the block. 141class BytecodeGenerator::ControlScope::DeferredCommands final { 142 public: 143 DeferredCommands(BytecodeGenerator* generator, Register token_register, 144 Register result_register) 145 : generator_(generator), 146 deferred_(generator->zone()), 147 token_register_(token_register), 148 result_register_(result_register) {} 149 150 // One recorded control-flow command. 151 struct Entry { 152 Command command; // The command type being applied on this path. 153 Statement* statement; // The target statement for the command or {nullptr}. 154 int token; // A token identifying this particular path. 155 }; 156 157 // Records a control-flow command while entering the finally-block. This also 158 // generates a new dispatch token that identifies one particular path. This 159 // expects the result to be in the accumulator. 160 void RecordCommand(Command command, Statement* statement) { 161 int token = static_cast<int>(deferred_.size()); 162 deferred_.push_back({command, statement, token}); 163 164 builder()->StoreAccumulatorInRegister(result_register_); 165 builder()->LoadLiteral(Smi::FromInt(token)); 166 builder()->StoreAccumulatorInRegister(token_register_); 167 } 168 169 // Records the dispatch token to be used to identify the re-throw path when 170 // the finally-block has been entered through the exception handler. This 171 // expects the exception to be in the accumulator. 172 void RecordHandlerReThrowPath() { 173 // The accumulator contains the exception object. 174 RecordCommand(CMD_RETHROW, nullptr); 175 } 176 177 // Records the dispatch token to be used to identify the implicit fall-through 178 // path at the end of a try-block into the corresponding finally-block. 179 void RecordFallThroughPath() { 180 builder()->LoadLiteral(Smi::FromInt(-1)); 181 builder()->StoreAccumulatorInRegister(token_register_); 182 } 183 184 // Applies all recorded control-flow commands after the finally-block again. 185 // This generates a dynamic dispatch on the token from the entry point. 186 void ApplyDeferredCommands() { 187 // The fall-through path is covered by the default case, hence +1 here. 188 SwitchBuilder dispatch(builder(), static_cast<int>(deferred_.size() + 1)); 189 for (size_t i = 0; i < deferred_.size(); ++i) { 190 Entry& entry = deferred_[i]; 191 builder()->LoadLiteral(Smi::FromInt(entry.token)); 192 builder()->CompareOperation(Token::EQ_STRICT, token_register_); 193 dispatch.Case(static_cast<int>(i)); 194 } 195 dispatch.DefaultAt(static_cast<int>(deferred_.size())); 196 for (size_t i = 0; i < deferred_.size(); ++i) { 197 Entry& entry = deferred_[i]; 198 dispatch.SetCaseTarget(static_cast<int>(i)); 199 builder()->LoadAccumulatorWithRegister(result_register_); 200 execution_control()->PerformCommand(entry.command, entry.statement); 201 } 202 dispatch.SetCaseTarget(static_cast<int>(deferred_.size())); 203 } 204 205 BytecodeArrayBuilder* builder() { return generator_->builder(); } 206 ControlScope* execution_control() { return generator_->execution_control(); } 207 208 private: 209 BytecodeGenerator* generator_; 210 ZoneVector<Entry> deferred_; 211 Register token_register_; 212 Register result_register_; 213}; 214 215// Scoped class for dealing with control flow reaching the function level. 216class BytecodeGenerator::ControlScopeForTopLevel final 217 : public BytecodeGenerator::ControlScope { 218 public: 219 explicit ControlScopeForTopLevel(BytecodeGenerator* generator) 220 : ControlScope(generator) {} 221 222 protected: 223 bool Execute(Command command, Statement* statement) override { 224 switch (command) { 225 case CMD_BREAK: // We should never see break/continue in top-level. 226 case CMD_CONTINUE: 227 UNREACHABLE(); 228 case CMD_RETURN: 229 generator()->BuildReturn(); 230 return true; 231 case CMD_ASYNC_RETURN: 232 generator()->BuildAsyncReturn(); 233 return true; 234 case CMD_RETHROW: 235 generator()->BuildReThrow(); 236 return true; 237 } 238 return false; 239 } 240}; 241 242// Scoped class for enabling break inside blocks and switch blocks. 243class BytecodeGenerator::ControlScopeForBreakable final 244 : public BytecodeGenerator::ControlScope { 245 public: 246 ControlScopeForBreakable(BytecodeGenerator* generator, 247 BreakableStatement* statement, 248 BreakableControlFlowBuilder* control_builder) 249 : ControlScope(generator), 250 statement_(statement), 251 control_builder_(control_builder) {} 252 253 protected: 254 bool Execute(Command command, Statement* statement) override { 255 if (statement != statement_) return false; 256 switch (command) { 257 case CMD_BREAK: 258 control_builder_->Break(); 259 return true; 260 case CMD_CONTINUE: 261 case CMD_RETURN: 262 case CMD_ASYNC_RETURN: 263 case CMD_RETHROW: 264 break; 265 } 266 return false; 267 } 268 269 private: 270 Statement* statement_; 271 BreakableControlFlowBuilder* control_builder_; 272}; 273 274// Scoped class for enabling 'break' and 'continue' in iteration 275// constructs, e.g. do...while, while..., for... 276class BytecodeGenerator::ControlScopeForIteration final 277 : public BytecodeGenerator::ControlScope { 278 public: 279 ControlScopeForIteration(BytecodeGenerator* generator, 280 IterationStatement* statement, 281 LoopBuilder* loop_builder) 282 : ControlScope(generator), 283 statement_(statement), 284 loop_builder_(loop_builder) { 285 generator->loop_depth_++; 286 } 287 ~ControlScopeForIteration() { generator()->loop_depth_--; } 288 289 protected: 290 bool Execute(Command command, Statement* statement) override { 291 if (statement != statement_) return false; 292 switch (command) { 293 case CMD_BREAK: 294 loop_builder_->Break(); 295 return true; 296 case CMD_CONTINUE: 297 loop_builder_->Continue(); 298 return true; 299 case CMD_RETURN: 300 case CMD_ASYNC_RETURN: 301 case CMD_RETHROW: 302 break; 303 } 304 return false; 305 } 306 307 private: 308 Statement* statement_; 309 LoopBuilder* loop_builder_; 310}; 311 312// Scoped class for enabling 'throw' in try-catch constructs. 313class BytecodeGenerator::ControlScopeForTryCatch final 314 : public BytecodeGenerator::ControlScope { 315 public: 316 ControlScopeForTryCatch(BytecodeGenerator* generator, 317 TryCatchBuilder* try_catch_builder) 318 : ControlScope(generator) {} 319 320 protected: 321 bool Execute(Command command, Statement* statement) override { 322 switch (command) { 323 case CMD_BREAK: 324 case CMD_CONTINUE: 325 case CMD_RETURN: 326 case CMD_ASYNC_RETURN: 327 break; 328 case CMD_RETHROW: 329 generator()->BuildReThrow(); 330 return true; 331 } 332 return false; 333 } 334}; 335 336// Scoped class for enabling control flow through try-finally constructs. 337class BytecodeGenerator::ControlScopeForTryFinally final 338 : public BytecodeGenerator::ControlScope { 339 public: 340 ControlScopeForTryFinally(BytecodeGenerator* generator, 341 TryFinallyBuilder* try_finally_builder, 342 DeferredCommands* commands) 343 : ControlScope(generator), 344 try_finally_builder_(try_finally_builder), 345 commands_(commands) {} 346 347 protected: 348 bool Execute(Command command, Statement* statement) override { 349 switch (command) { 350 case CMD_BREAK: 351 case CMD_CONTINUE: 352 case CMD_RETURN: 353 case CMD_ASYNC_RETURN: 354 case CMD_RETHROW: 355 commands_->RecordCommand(command, statement); 356 try_finally_builder_->LeaveTry(); 357 return true; 358 } 359 return false; 360 } 361 362 private: 363 TryFinallyBuilder* try_finally_builder_; 364 DeferredCommands* commands_; 365}; 366 367void BytecodeGenerator::ControlScope::PerformCommand(Command command, 368 Statement* statement) { 369 ControlScope* current = this; 370 ContextScope* context = generator()->execution_context(); 371 // Pop context to the expected depth but do not pop the outermost context. 372 if (context != current->context() && context->ShouldPopContext()) { 373 generator()->builder()->PopContext(current->context()->reg()); 374 } 375 do { 376 if (current->Execute(command, statement)) { 377 return; 378 } 379 current = current->outer(); 380 if (current->context() != context && context->ShouldPopContext()) { 381 // Pop context to the expected depth. 382 // TODO(rmcilroy): Only emit a single context pop. 383 generator()->builder()->PopContext(current->context()->reg()); 384 } 385 } while (current != nullptr); 386 UNREACHABLE(); 387} 388 389class BytecodeGenerator::RegisterAllocationScope { 390 public: 391 explicit RegisterAllocationScope(BytecodeGenerator* generator) 392 : generator_(generator), 393 outer_next_register_index_( 394 generator->register_allocator()->next_register_index()) {} 395 396 virtual ~RegisterAllocationScope() { 397 generator_->register_allocator()->ReleaseRegisters( 398 outer_next_register_index_); 399 } 400 401 private: 402 BytecodeGenerator* generator_; 403 int outer_next_register_index_; 404 405 DISALLOW_COPY_AND_ASSIGN(RegisterAllocationScope); 406}; 407 408// Scoped base class for determining how the result of an expression will be 409// used. 410class BytecodeGenerator::ExpressionResultScope { 411 public: 412 ExpressionResultScope(BytecodeGenerator* generator, Expression::Context kind) 413 : generator_(generator), 414 kind_(kind), 415 outer_(generator->execution_result()), 416 allocator_(generator) { 417 generator_->set_execution_result(this); 418 } 419 420 virtual ~ExpressionResultScope() { 421 generator_->set_execution_result(outer_); 422 } 423 424 bool IsEffect() const { return kind_ == Expression::kEffect; } 425 bool IsValue() const { return kind_ == Expression::kValue; } 426 bool IsTest() const { return kind_ == Expression::kTest; } 427 428 TestResultScope* AsTest() { 429 DCHECK(IsTest()); 430 return reinterpret_cast<TestResultScope*>(this); 431 } 432 433 private: 434 BytecodeGenerator* generator_; 435 Expression::Context kind_; 436 ExpressionResultScope* outer_; 437 RegisterAllocationScope allocator_; 438 439 DISALLOW_COPY_AND_ASSIGN(ExpressionResultScope); 440}; 441 442// Scoped class used when the result of the current expression is not 443// expected to produce a result. 444class BytecodeGenerator::EffectResultScope final 445 : public ExpressionResultScope { 446 public: 447 explicit EffectResultScope(BytecodeGenerator* generator) 448 : ExpressionResultScope(generator, Expression::kEffect) {} 449}; 450 451// Scoped class used when the result of the current expression to be 452// evaluated should go into the interpreter's accumulator. 453class BytecodeGenerator::ValueResultScope final : public ExpressionResultScope { 454 public: 455 explicit ValueResultScope(BytecodeGenerator* generator) 456 : ExpressionResultScope(generator, Expression::kValue) {} 457}; 458 459// Scoped class used when the result of the current expression to be 460// evaluated is only tested with jumps to two branches. 461class BytecodeGenerator::TestResultScope final : public ExpressionResultScope { 462 public: 463 TestResultScope(BytecodeGenerator* generator, BytecodeLabels* then_labels, 464 BytecodeLabels* else_labels, TestFallthrough fallthrough) 465 : ExpressionResultScope(generator, Expression::kTest), 466 then_labels_(then_labels), 467 else_labels_(else_labels), 468 fallthrough_(fallthrough), 469 result_consumed_by_test_(false) {} 470 471 // Used when code special cases for TestResultScope and consumes any 472 // possible value by testing and jumping to a then/else label. 473 void SetResultConsumedByTest() { 474 result_consumed_by_test_ = true; 475 } 476 477 bool ResultConsumedByTest() { return result_consumed_by_test_; } 478 479 BytecodeLabel* NewThenLabel() { return then_labels_->New(); } 480 BytecodeLabel* NewElseLabel() { return else_labels_->New(); } 481 482 BytecodeLabels* then_labels() const { return then_labels_; } 483 BytecodeLabels* else_labels() const { return else_labels_; } 484 485 TestFallthrough fallthrough() const { return fallthrough_; } 486 TestFallthrough inverted_fallthrough() const { 487 switch (fallthrough_) { 488 case TestFallthrough::kThen: 489 return TestFallthrough::kElse; 490 case TestFallthrough::kElse: 491 return TestFallthrough::kThen; 492 default: 493 return TestFallthrough::kNone; 494 } 495 } 496 497 private: 498 BytecodeLabels* then_labels_; 499 BytecodeLabels* else_labels_; 500 TestFallthrough fallthrough_; 501 bool result_consumed_by_test_; 502 503 DISALLOW_COPY_AND_ASSIGN(TestResultScope); 504}; 505 506// Used to build a list of global declaration initial value pairs. 507class BytecodeGenerator::GlobalDeclarationsBuilder final : public ZoneObject { 508 public: 509 explicit GlobalDeclarationsBuilder(Zone* zone) 510 : declarations_(0, zone), 511 constant_pool_entry_(0), 512 has_constant_pool_entry_(false) {} 513 514 void AddFunctionDeclaration(const AstRawString* name, FeedbackSlot slot, 515 FeedbackSlot literal_slot, 516 FunctionLiteral* func) { 517 DCHECK(!slot.IsInvalid()); 518 declarations_.push_back(Declaration(name, slot, literal_slot, func)); 519 } 520 521 void AddUndefinedDeclaration(const AstRawString* name, FeedbackSlot slot) { 522 DCHECK(!slot.IsInvalid()); 523 declarations_.push_back(Declaration(name, slot, nullptr)); 524 } 525 526 Handle<FixedArray> AllocateDeclarations(CompilationInfo* info) { 527 DCHECK(has_constant_pool_entry_); 528 int array_index = 0; 529 Handle<FixedArray> data = info->isolate()->factory()->NewFixedArray( 530 static_cast<int>(declarations_.size() * 4), TENURED); 531 for (const Declaration& declaration : declarations_) { 532 FunctionLiteral* func = declaration.func; 533 Handle<Object> initial_value; 534 if (func == nullptr) { 535 initial_value = info->isolate()->factory()->undefined_value(); 536 } else { 537 initial_value = 538 Compiler::GetSharedFunctionInfo(func, info->script(), info); 539 } 540 541 // Return a null handle if any initial values can't be created. Caller 542 // will set stack overflow. 543 if (initial_value.is_null()) return Handle<FixedArray>(); 544 545 data->set(array_index++, *declaration.name->string()); 546 data->set(array_index++, Smi::FromInt(declaration.slot.ToInt())); 547 Object* undefined_or_literal_slot; 548 if (declaration.literal_slot.IsInvalid()) { 549 undefined_or_literal_slot = info->isolate()->heap()->undefined_value(); 550 } else { 551 undefined_or_literal_slot = 552 Smi::FromInt(declaration.literal_slot.ToInt()); 553 } 554 data->set(array_index++, undefined_or_literal_slot); 555 data->set(array_index++, *initial_value); 556 } 557 return data; 558 } 559 560 size_t constant_pool_entry() { 561 DCHECK(has_constant_pool_entry_); 562 return constant_pool_entry_; 563 } 564 565 void set_constant_pool_entry(size_t constant_pool_entry) { 566 DCHECK(!empty()); 567 DCHECK(!has_constant_pool_entry_); 568 constant_pool_entry_ = constant_pool_entry; 569 has_constant_pool_entry_ = true; 570 } 571 572 bool empty() { return declarations_.empty(); } 573 574 private: 575 struct Declaration { 576 Declaration() : slot(FeedbackSlot::Invalid()), func(nullptr) {} 577 Declaration(const AstRawString* name, FeedbackSlot slot, 578 FeedbackSlot literal_slot, FunctionLiteral* func) 579 : name(name), slot(slot), literal_slot(literal_slot), func(func) {} 580 Declaration(const AstRawString* name, FeedbackSlot slot, 581 FunctionLiteral* func) 582 : name(name), 583 slot(slot), 584 literal_slot(FeedbackSlot::Invalid()), 585 func(func) {} 586 587 const AstRawString* name; 588 FeedbackSlot slot; 589 FeedbackSlot literal_slot; 590 FunctionLiteral* func; 591 }; 592 ZoneVector<Declaration> declarations_; 593 size_t constant_pool_entry_; 594 bool has_constant_pool_entry_; 595}; 596 597class BytecodeGenerator::CurrentScope final { 598 public: 599 CurrentScope(BytecodeGenerator* generator, Scope* scope) 600 : generator_(generator), outer_scope_(generator->current_scope()) { 601 if (scope != nullptr) { 602 generator_->set_current_scope(scope); 603 } 604 } 605 ~CurrentScope() { 606 if (outer_scope_ != generator_->current_scope()) { 607 generator_->set_current_scope(outer_scope_); 608 } 609 } 610 611 private: 612 BytecodeGenerator* generator_; 613 Scope* outer_scope_; 614}; 615 616BytecodeGenerator::BytecodeGenerator(CompilationInfo* info) 617 : zone_(info->zone()), 618 builder_(new (zone()) BytecodeArrayBuilder( 619 info->isolate(), info->zone(), info->num_parameters_including_this(), 620 info->scope()->MaxNestedContextChainLength(), 621 info->scope()->num_stack_slots(), info->literal(), 622 info->SourcePositionRecordingMode())), 623 info_(info), 624 closure_scope_(info->scope()), 625 current_scope_(info->scope()), 626 globals_builder_(new (zone()) GlobalDeclarationsBuilder(info->zone())), 627 global_declarations_(0, info->zone()), 628 function_literals_(0, info->zone()), 629 native_function_literals_(0, info->zone()), 630 object_literals_(0, info->zone()), 631 array_literals_(0, info->zone()), 632 execution_control_(nullptr), 633 execution_context_(nullptr), 634 execution_result_(nullptr), 635 generator_resume_points_(info->literal()->yield_count(), info->zone()), 636 generator_state_(), 637 loop_depth_(0), 638 prototype_string_( 639 info->isolate()->ast_string_constants()->prototype_string()), 640 undefined_string_( 641 info->isolate()->ast_string_constants()->undefined_string()) { 642 DCHECK_EQ(closure_scope(), closure_scope()->GetClosureScope()); 643} 644 645Handle<BytecodeArray> BytecodeGenerator::FinalizeBytecode(Isolate* isolate) { 646 AllocateDeferredConstants(isolate); 647 if (HasStackOverflow()) return Handle<BytecodeArray>(); 648 return builder()->ToBytecodeArray(isolate); 649} 650 651void BytecodeGenerator::AllocateDeferredConstants(Isolate* isolate) { 652 // Build global declaration pair arrays. 653 for (GlobalDeclarationsBuilder* globals_builder : global_declarations_) { 654 Handle<FixedArray> declarations = 655 globals_builder->AllocateDeclarations(info()); 656 if (declarations.is_null()) return SetStackOverflow(); 657 builder()->SetDeferredConstantPoolEntry( 658 globals_builder->constant_pool_entry(), declarations); 659 } 660 661 // Find or build shared function infos. 662 for (std::pair<FunctionLiteral*, size_t> literal : function_literals_) { 663 FunctionLiteral* expr = literal.first; 664 Handle<SharedFunctionInfo> shared_info = 665 Compiler::GetSharedFunctionInfo(expr, info()->script(), info()); 666 if (shared_info.is_null()) return SetStackOverflow(); 667 builder()->SetDeferredConstantPoolEntry(literal.second, shared_info); 668 } 669 670 // Find or build shared function infos for the native function templates. 671 for (std::pair<NativeFunctionLiteral*, size_t> literal : 672 native_function_literals_) { 673 NativeFunctionLiteral* expr = literal.first; 674 Handle<SharedFunctionInfo> shared_info = 675 Compiler::GetSharedFunctionInfoForNative(expr->extension(), 676 expr->name()); 677 if (shared_info.is_null()) return SetStackOverflow(); 678 builder()->SetDeferredConstantPoolEntry(literal.second, shared_info); 679 } 680 681 // Build object literal constant properties 682 for (std::pair<ObjectLiteral*, size_t> literal : object_literals_) { 683 ObjectLiteral* object_literal = literal.first; 684 if (object_literal->properties_count() > 0) { 685 // If constant properties is an empty fixed array, we've already added it 686 // to the constant pool when visiting the object literal. 687 Handle<BoilerplateDescription> constant_properties = 688 object_literal->GetOrBuildConstantProperties(isolate); 689 690 builder()->SetDeferredConstantPoolEntry(literal.second, 691 constant_properties); 692 } 693 } 694 695 // Build array literal constant elements 696 for (std::pair<ArrayLiteral*, size_t> literal : array_literals_) { 697 ArrayLiteral* array_literal = literal.first; 698 Handle<ConstantElementsPair> constant_elements = 699 array_literal->GetOrBuildConstantElements(isolate); 700 builder()->SetDeferredConstantPoolEntry(literal.second, constant_elements); 701 } 702} 703 704void BytecodeGenerator::GenerateBytecode(uintptr_t stack_limit) { 705 DisallowHeapAllocation no_allocation; 706 DisallowHandleAllocation no_handles; 707 DisallowHandleDereference no_deref; 708 709 InitializeAstVisitor(stack_limit); 710 711 // Initialize the incoming context. 712 ContextScope incoming_context(this, closure_scope(), false); 713 714 // Initialize control scope. 715 ControlScopeForTopLevel control(this); 716 717 RegisterAllocationScope register_scope(this); 718 719 if (IsResumableFunction(info()->literal()->kind())) { 720 generator_state_ = register_allocator()->NewRegister(); 721 VisitGeneratorPrologue(); 722 } 723 724 if (closure_scope()->NeedsContext()) { 725 // Push a new inner context scope for the function. 726 BuildNewLocalActivationContext(); 727 ContextScope local_function_context(this, closure_scope(), false); 728 BuildLocalActivationContextInitialization(); 729 GenerateBytecodeBody(); 730 } else { 731 GenerateBytecodeBody(); 732 } 733 734 // In generator functions, we may not have visited every yield in the AST 735 // since we skip some obviously dead code. Hence the generated bytecode may 736 // contain jumps to unbound labels (resume points that will never be used). 737 // We bind these now. 738 for (auto& label : generator_resume_points_) { 739 if (!label.is_bound()) builder()->Bind(&label); 740 } 741 742 // Emit an implicit return instruction in case control flow can fall off the 743 // end of the function without an explicit return being present on all paths. 744 if (builder()->RequiresImplicitReturn()) { 745 builder()->LoadUndefined(); 746 BuildReturn(); 747 } 748 DCHECK(!builder()->RequiresImplicitReturn()); 749} 750 751void BytecodeGenerator::GenerateBytecodeBody() { 752 // Build the arguments object if it is used. 753 VisitArgumentsObject(closure_scope()->arguments()); 754 755 // Build rest arguments array if it is used. 756 Variable* rest_parameter = closure_scope()->rest_parameter(); 757 VisitRestArgumentsArray(rest_parameter); 758 759 // Build assignment to {.this_function} variable if it is used. 760 VisitThisFunctionVariable(closure_scope()->this_function_var()); 761 762 // Build assignment to {new.target} variable if it is used. 763 VisitNewTargetVariable(closure_scope()->new_target_var()); 764 765 // Emit tracing call if requested to do so. 766 if (FLAG_trace) builder()->CallRuntime(Runtime::kTraceEnter); 767 768 // Visit declarations within the function scope. 769 VisitDeclarations(closure_scope()->declarations()); 770 771 // Emit initializing assignments for module namespace imports (if any). 772 VisitModuleNamespaceImports(); 773 774 // Perform a stack-check before the body. 775 builder()->StackCheck(info()->literal()->start_position()); 776 777 // Visit statements in the function body. 778 VisitStatements(info()->literal()->body()); 779} 780 781void BytecodeGenerator::BuildIndexedJump(Register index, size_t start_index, 782 size_t size, 783 ZoneVector<BytecodeLabel>& targets) { 784 // TODO(neis): Optimize this by using a proper jump table. 785 DCHECK_LE(start_index + size, targets.size()); 786 for (size_t i = start_index; i < start_index + size; i++) { 787 builder() 788 ->LoadLiteral(Smi::FromInt(static_cast<int>(i))) 789 .CompareOperation(Token::Value::EQ_STRICT, index) 790 .JumpIfTrue(&(targets[i])); 791 } 792 BuildAbort(BailoutReason::kInvalidJumpTableIndex); 793} 794 795void BytecodeGenerator::VisitIterationHeader(IterationStatement* stmt, 796 LoopBuilder* loop_builder) { 797 // Recall that stmt->yield_count() is always zero inside ordinary 798 // (i.e. non-generator) functions. 799 if (stmt->yield_count() == 0) { 800 loop_builder->LoopHeader(); 801 } else { 802 // Collect all labels for generator resume points within the loop (if any) 803 // so that they can be bound to the loop header below. Also create fresh 804 // labels for these resume points, to be used inside the loop. 805 ZoneVector<BytecodeLabel> resume_points_in_loop(zone()); 806 size_t first_yield = stmt->first_yield_id(); 807 DCHECK_LE(first_yield + stmt->yield_count(), 808 generator_resume_points_.size()); 809 for (size_t id = first_yield; id < first_yield + stmt->yield_count(); 810 id++) { 811 auto& label = generator_resume_points_[id]; 812 resume_points_in_loop.push_back(label); 813 generator_resume_points_[id] = BytecodeLabel(); 814 } 815 816 loop_builder->LoopHeader(&resume_points_in_loop); 817 818 // If we are not resuming, fall through to loop body. 819 // If we are resuming, perform state dispatch. 820 BytecodeLabel not_resuming; 821 builder() 822 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)) 823 .CompareOperation(Token::Value::EQ, generator_state_) 824 .JumpIfTrue(¬_resuming); 825 BuildIndexedJump(generator_state_, first_yield, 826 stmt->yield_count(), generator_resume_points_); 827 builder()->Bind(¬_resuming); 828 } 829} 830 831void BytecodeGenerator::VisitGeneratorPrologue() { 832 // The generator resume trampoline abuses the new.target register both to 833 // indicate that this is a resume call and to pass in the generator object. 834 // In ordinary calls, new.target is always undefined because generator 835 // functions are non-constructable. 836 Register generator_object = Register::new_target(); 837 BytecodeLabel regular_call; 838 builder() 839 ->LoadAccumulatorWithRegister(generator_object) 840 .JumpIfUndefined(®ular_call); 841 842 // This is a resume call. Restore the current context and the registers, then 843 // perform state dispatch. 844 Register dummy = register_allocator()->NewRegister(); 845 builder() 846 ->CallRuntime(Runtime::kInlineGeneratorGetContext, generator_object) 847 .PushContext(dummy) 848 .ResumeGenerator(generator_object) 849 .StoreAccumulatorInRegister(generator_state_); 850 BuildIndexedJump(generator_state_, 0, generator_resume_points_.size(), 851 generator_resume_points_); 852 853 builder() 854 ->Bind(®ular_call) 855 .LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)) 856 .StoreAccumulatorInRegister(generator_state_); 857 // This is a regular call. Fall through to the ordinary function prologue, 858 // after which we will run into the generator object creation and other extra 859 // code inserted by the parser. 860} 861 862void BytecodeGenerator::VisitBlock(Block* stmt) { 863 // Visit declarations and statements. 864 CurrentScope current_scope(this, stmt->scope()); 865 if (stmt->scope() != nullptr && stmt->scope()->NeedsContext()) { 866 BuildNewLocalBlockContext(stmt->scope()); 867 ContextScope scope(this, stmt->scope()); 868 VisitBlockDeclarationsAndStatements(stmt); 869 } else { 870 VisitBlockDeclarationsAndStatements(stmt); 871 } 872} 873 874void BytecodeGenerator::VisitBlockDeclarationsAndStatements(Block* stmt) { 875 BlockBuilder block_builder(builder()); 876 ControlScopeForBreakable execution_control(this, stmt, &block_builder); 877 if (stmt->scope() != nullptr) { 878 VisitDeclarations(stmt->scope()->declarations()); 879 } 880 VisitStatements(stmt->statements()); 881 if (stmt->labels() != nullptr) block_builder.EndBlock(); 882} 883 884void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) { 885 Variable* variable = decl->proxy()->var(); 886 switch (variable->location()) { 887 case VariableLocation::UNALLOCATED: { 888 DCHECK(!variable->binding_needs_init()); 889 FeedbackSlot slot = decl->proxy()->VariableFeedbackSlot(); 890 globals_builder()->AddUndefinedDeclaration(variable->raw_name(), slot); 891 break; 892 } 893 case VariableLocation::LOCAL: 894 if (variable->binding_needs_init()) { 895 Register destination(builder()->Local(variable->index())); 896 builder()->LoadTheHole().StoreAccumulatorInRegister(destination); 897 } 898 break; 899 case VariableLocation::PARAMETER: 900 if (variable->binding_needs_init()) { 901 // The parameter indices are shifted by 1 (receiver is variable 902 // index -1 but is parameter index 0 in BytecodeArrayBuilder). 903 Register destination(builder()->Parameter(variable->index() + 1)); 904 builder()->LoadTheHole().StoreAccumulatorInRegister(destination); 905 } 906 break; 907 case VariableLocation::CONTEXT: 908 if (variable->binding_needs_init()) { 909 DCHECK_EQ(0, execution_context()->ContextChainDepth(variable->scope())); 910 builder()->LoadTheHole().StoreContextSlot(execution_context()->reg(), 911 variable->index(), 0); 912 } 913 break; 914 case VariableLocation::LOOKUP: { 915 DCHECK_EQ(VAR, variable->mode()); 916 DCHECK(!variable->binding_needs_init()); 917 918 Register name = register_allocator()->NewRegister(); 919 920 builder() 921 ->LoadLiteral(variable->raw_name()) 922 .StoreAccumulatorInRegister(name) 923 .CallRuntime(Runtime::kDeclareEvalVar, name); 924 break; 925 } 926 case VariableLocation::MODULE: 927 if (variable->IsExport() && variable->binding_needs_init()) { 928 builder()->LoadTheHole(); 929 BuildVariableAssignment(variable, Token::INIT, FeedbackSlot::Invalid(), 930 HoleCheckMode::kElided); 931 } 932 // Nothing to do for imports. 933 break; 934 } 935} 936 937void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) { 938 Variable* variable = decl->proxy()->var(); 939 DCHECK(variable->mode() == LET || variable->mode() == VAR); 940 switch (variable->location()) { 941 case VariableLocation::UNALLOCATED: { 942 FeedbackSlot slot = decl->proxy()->VariableFeedbackSlot(); 943 globals_builder()->AddFunctionDeclaration( 944 variable->raw_name(), slot, decl->fun()->LiteralFeedbackSlot(), 945 decl->fun()); 946 break; 947 } 948 case VariableLocation::PARAMETER: 949 case VariableLocation::LOCAL: { 950 VisitForAccumulatorValue(decl->fun()); 951 BuildVariableAssignment(variable, Token::INIT, FeedbackSlot::Invalid(), 952 HoleCheckMode::kElided); 953 break; 954 } 955 case VariableLocation::CONTEXT: { 956 DCHECK_EQ(0, execution_context()->ContextChainDepth(variable->scope())); 957 VisitForAccumulatorValue(decl->fun()); 958 builder()->StoreContextSlot(execution_context()->reg(), variable->index(), 959 0); 960 break; 961 } 962 case VariableLocation::LOOKUP: { 963 RegisterList args = register_allocator()->NewRegisterList(2); 964 builder() 965 ->LoadLiteral(variable->raw_name()) 966 .StoreAccumulatorInRegister(args[0]); 967 VisitForAccumulatorValue(decl->fun()); 968 builder()->StoreAccumulatorInRegister(args[1]).CallRuntime( 969 Runtime::kDeclareEvalFunction, args); 970 break; 971 } 972 case VariableLocation::MODULE: 973 DCHECK_EQ(variable->mode(), LET); 974 DCHECK(variable->IsExport()); 975 VisitForAccumulatorValue(decl->fun()); 976 BuildVariableAssignment(variable, Token::INIT, FeedbackSlot::Invalid(), 977 HoleCheckMode::kElided); 978 break; 979 } 980} 981 982void BytecodeGenerator::VisitModuleNamespaceImports() { 983 if (!closure_scope()->is_module_scope()) return; 984 985 RegisterAllocationScope register_scope(this); 986 Register module_request = register_allocator()->NewRegister(); 987 988 ModuleDescriptor* descriptor = closure_scope()->AsModuleScope()->module(); 989 for (auto entry : descriptor->namespace_imports()) { 990 builder() 991 ->LoadLiteral(Smi::FromInt(entry->module_request)) 992 .StoreAccumulatorInRegister(module_request) 993 .CallRuntime(Runtime::kGetModuleNamespace, module_request); 994 Variable* var = closure_scope()->LookupLocal(entry->local_name); 995 DCHECK_NOT_NULL(var); 996 BuildVariableAssignment(var, Token::INIT, FeedbackSlot::Invalid(), 997 HoleCheckMode::kElided); 998 } 999} 1000 1001void BytecodeGenerator::VisitDeclarations(Declaration::List* declarations) { 1002 RegisterAllocationScope register_scope(this); 1003 DCHECK(globals_builder()->empty()); 1004 for (Declaration* decl : *declarations) { 1005 RegisterAllocationScope register_scope(this); 1006 Visit(decl); 1007 } 1008 if (globals_builder()->empty()) return; 1009 1010 globals_builder()->set_constant_pool_entry( 1011 builder()->AllocateDeferredConstantPoolEntry()); 1012 int encoded_flags = info()->GetDeclareGlobalsFlags(); 1013 1014 // Emit code to declare globals. 1015 RegisterList args = register_allocator()->NewRegisterList(3); 1016 builder() 1017 ->LoadConstantPoolEntry(globals_builder()->constant_pool_entry()) 1018 .StoreAccumulatorInRegister(args[0]) 1019 .LoadLiteral(Smi::FromInt(encoded_flags)) 1020 .StoreAccumulatorInRegister(args[1]) 1021 .MoveRegister(Register::function_closure(), args[2]) 1022 .CallRuntime(Runtime::kDeclareGlobalsForInterpreter, args); 1023 1024 // Push and reset globals builder. 1025 global_declarations_.push_back(globals_builder()); 1026 globals_builder_ = new (zone()) GlobalDeclarationsBuilder(zone()); 1027} 1028 1029void BytecodeGenerator::VisitStatements(ZoneList<Statement*>* statements) { 1030 for (int i = 0; i < statements->length(); i++) { 1031 // Allocate an outer register allocations scope for the statement. 1032 RegisterAllocationScope allocation_scope(this); 1033 Statement* stmt = statements->at(i); 1034 Visit(stmt); 1035 if (stmt->IsJump()) break; 1036 } 1037} 1038 1039void BytecodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { 1040 builder()->SetStatementPosition(stmt); 1041 VisitForEffect(stmt->expression()); 1042} 1043 1044void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) { 1045} 1046 1047void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) { 1048 builder()->SetStatementPosition(stmt); 1049 if (stmt->condition()->ToBooleanIsTrue()) { 1050 // Generate then block unconditionally as always true. 1051 Visit(stmt->then_statement()); 1052 } else if (stmt->condition()->ToBooleanIsFalse()) { 1053 // Generate else block unconditionally if it exists. 1054 if (stmt->HasElseStatement()) { 1055 Visit(stmt->else_statement()); 1056 } 1057 } else { 1058 // TODO(oth): If then statement is BreakStatement or 1059 // ContinueStatement we can reduce number of generated 1060 // jump/jump_ifs here. See BasicLoops test. 1061 BytecodeLabel end_label; 1062 BytecodeLabels then_labels(zone()), else_labels(zone()); 1063 VisitForTest(stmt->condition(), &then_labels, &else_labels, 1064 TestFallthrough::kThen); 1065 1066 then_labels.Bind(builder()); 1067 Visit(stmt->then_statement()); 1068 1069 if (stmt->HasElseStatement()) { 1070 builder()->Jump(&end_label); 1071 else_labels.Bind(builder()); 1072 Visit(stmt->else_statement()); 1073 } else { 1074 else_labels.Bind(builder()); 1075 } 1076 builder()->Bind(&end_label); 1077 } 1078} 1079 1080void BytecodeGenerator::VisitSloppyBlockFunctionStatement( 1081 SloppyBlockFunctionStatement* stmt) { 1082 Visit(stmt->statement()); 1083} 1084 1085void BytecodeGenerator::VisitContinueStatement(ContinueStatement* stmt) { 1086 builder()->SetStatementPosition(stmt); 1087 execution_control()->Continue(stmt->target()); 1088} 1089 1090void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) { 1091 builder()->SetStatementPosition(stmt); 1092 execution_control()->Break(stmt->target()); 1093} 1094 1095void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { 1096 builder()->SetStatementPosition(stmt); 1097 VisitForAccumulatorValue(stmt->expression()); 1098 1099 if (stmt->is_async_return()) { 1100 execution_control()->AsyncReturnAccumulator(); 1101 } else { 1102 execution_control()->ReturnAccumulator(); 1103 } 1104} 1105 1106void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) { 1107 builder()->SetStatementPosition(stmt); 1108 VisitForAccumulatorValue(stmt->expression()); 1109 BuildNewLocalWithContext(stmt->scope()); 1110 VisitInScope(stmt->statement(), stmt->scope()); 1111} 1112 1113void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { 1114 // We need this scope because we visit for register values. We have to 1115 // maintain a execution result scope where registers can be allocated. 1116 ZoneList<CaseClause*>* clauses = stmt->cases(); 1117 SwitchBuilder switch_builder(builder(), clauses->length()); 1118 ControlScopeForBreakable scope(this, stmt, &switch_builder); 1119 int default_index = -1; 1120 1121 builder()->SetStatementPosition(stmt); 1122 1123 // Keep the switch value in a register until a case matches. 1124 Register tag = VisitForRegisterValue(stmt->tag()); 1125 1126 // Iterate over all cases and create nodes for label comparison. 1127 for (int i = 0; i < clauses->length(); i++) { 1128 CaseClause* clause = clauses->at(i); 1129 1130 // The default is not a test, remember index. 1131 if (clause->is_default()) { 1132 default_index = i; 1133 continue; 1134 } 1135 1136 // Perform label comparison as if via '===' with tag. 1137 VisitForAccumulatorValue(clause->label()); 1138 builder()->CompareOperation( 1139 Token::Value::EQ_STRICT, tag, 1140 feedback_index(clause->CompareOperationFeedbackSlot())); 1141 switch_builder.Case(i); 1142 } 1143 1144 if (default_index >= 0) { 1145 // Emit default jump if there is a default case. 1146 switch_builder.DefaultAt(default_index); 1147 } else { 1148 // Otherwise if we have reached here none of the cases matched, so jump to 1149 // the end. 1150 switch_builder.Break(); 1151 } 1152 1153 // Iterate over all cases and create the case bodies. 1154 for (int i = 0; i < clauses->length(); i++) { 1155 CaseClause* clause = clauses->at(i); 1156 switch_builder.SetCaseTarget(i); 1157 VisitStatements(clause->statements()); 1158 } 1159 switch_builder.BindBreakTarget(); 1160} 1161 1162void BytecodeGenerator::VisitCaseClause(CaseClause* clause) { 1163 // Handled entirely in VisitSwitchStatement. 1164 UNREACHABLE(); 1165} 1166 1167void BytecodeGenerator::VisitIterationBody(IterationStatement* stmt, 1168 LoopBuilder* loop_builder) { 1169 ControlScopeForIteration execution_control(this, stmt, loop_builder); 1170 builder()->StackCheck(stmt->position()); 1171 Visit(stmt->body()); 1172 loop_builder->BindContinueTarget(); 1173} 1174 1175void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { 1176 LoopBuilder loop_builder(builder()); 1177 if (stmt->cond()->ToBooleanIsFalse()) { 1178 VisitIterationBody(stmt, &loop_builder); 1179 } else if (stmt->cond()->ToBooleanIsTrue()) { 1180 VisitIterationHeader(stmt, &loop_builder); 1181 VisitIterationBody(stmt, &loop_builder); 1182 loop_builder.JumpToHeader(loop_depth_); 1183 } else { 1184 VisitIterationHeader(stmt, &loop_builder); 1185 VisitIterationBody(stmt, &loop_builder); 1186 builder()->SetExpressionAsStatementPosition(stmt->cond()); 1187 BytecodeLabels loop_backbranch(zone()); 1188 VisitForTest(stmt->cond(), &loop_backbranch, loop_builder.break_labels(), 1189 TestFallthrough::kThen); 1190 loop_backbranch.Bind(builder()); 1191 loop_builder.JumpToHeader(loop_depth_); 1192 } 1193 loop_builder.EndLoop(); 1194} 1195 1196void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) { 1197 if (stmt->cond()->ToBooleanIsFalse()) { 1198 // If the condition is false there is no need to generate the loop. 1199 return; 1200 } 1201 1202 LoopBuilder loop_builder(builder()); 1203 VisitIterationHeader(stmt, &loop_builder); 1204 if (!stmt->cond()->ToBooleanIsTrue()) { 1205 builder()->SetExpressionAsStatementPosition(stmt->cond()); 1206 BytecodeLabels loop_body(zone()); 1207 VisitForTest(stmt->cond(), &loop_body, loop_builder.break_labels(), 1208 TestFallthrough::kThen); 1209 loop_body.Bind(builder()); 1210 } 1211 VisitIterationBody(stmt, &loop_builder); 1212 loop_builder.JumpToHeader(loop_depth_); 1213 loop_builder.EndLoop(); 1214} 1215 1216void BytecodeGenerator::VisitForStatement(ForStatement* stmt) { 1217 if (stmt->init() != nullptr) { 1218 Visit(stmt->init()); 1219 } 1220 if (stmt->cond() && stmt->cond()->ToBooleanIsFalse()) { 1221 // If the condition is known to be false there is no need to generate 1222 // body, next or condition blocks. Init block should be generated. 1223 return; 1224 } 1225 1226 LoopBuilder loop_builder(builder()); 1227 VisitIterationHeader(stmt, &loop_builder); 1228 if (stmt->cond() && !stmt->cond()->ToBooleanIsTrue()) { 1229 builder()->SetExpressionAsStatementPosition(stmt->cond()); 1230 BytecodeLabels loop_body(zone()); 1231 VisitForTest(stmt->cond(), &loop_body, loop_builder.break_labels(), 1232 TestFallthrough::kThen); 1233 loop_body.Bind(builder()); 1234 } 1235 VisitIterationBody(stmt, &loop_builder); 1236 if (stmt->next() != nullptr) { 1237 builder()->SetStatementPosition(stmt->next()); 1238 Visit(stmt->next()); 1239 } 1240 loop_builder.JumpToHeader(loop_depth_); 1241 loop_builder.EndLoop(); 1242} 1243 1244void BytecodeGenerator::VisitForInAssignment(Expression* expr, 1245 FeedbackSlot slot) { 1246 DCHECK(expr->IsValidReferenceExpression()); 1247 1248 // Evaluate assignment starting with the value to be stored in the 1249 // accumulator. 1250 Property* property = expr->AsProperty(); 1251 LhsKind assign_type = Property::GetAssignType(property); 1252 switch (assign_type) { 1253 case VARIABLE: { 1254 VariableProxy* proxy = expr->AsVariableProxy(); 1255 BuildVariableAssignment(proxy->var(), Token::ASSIGN, slot, 1256 proxy->hole_check_mode()); 1257 break; 1258 } 1259 case NAMED_PROPERTY: { 1260 RegisterAllocationScope register_scope(this); 1261 Register value = register_allocator()->NewRegister(); 1262 builder()->StoreAccumulatorInRegister(value); 1263 Register object = VisitForRegisterValue(property->obj()); 1264 const AstRawString* name = 1265 property->key()->AsLiteral()->AsRawPropertyName(); 1266 builder()->LoadAccumulatorWithRegister(value); 1267 builder()->StoreNamedProperty(object, name, feedback_index(slot), 1268 language_mode()); 1269 break; 1270 } 1271 case KEYED_PROPERTY: { 1272 RegisterAllocationScope register_scope(this); 1273 Register value = register_allocator()->NewRegister(); 1274 builder()->StoreAccumulatorInRegister(value); 1275 Register object = VisitForRegisterValue(property->obj()); 1276 Register key = VisitForRegisterValue(property->key()); 1277 builder()->LoadAccumulatorWithRegister(value); 1278 builder()->StoreKeyedProperty(object, key, feedback_index(slot), 1279 language_mode()); 1280 break; 1281 } 1282 case NAMED_SUPER_PROPERTY: { 1283 RegisterAllocationScope register_scope(this); 1284 RegisterList args = register_allocator()->NewRegisterList(4); 1285 builder()->StoreAccumulatorInRegister(args[3]); 1286 SuperPropertyReference* super_property = 1287 property->obj()->AsSuperPropertyReference(); 1288 VisitForRegisterValue(super_property->this_var(), args[0]); 1289 VisitForRegisterValue(super_property->home_object(), args[1]); 1290 builder() 1291 ->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName()) 1292 .StoreAccumulatorInRegister(args[2]) 1293 .CallRuntime(StoreToSuperRuntimeId(), args); 1294 break; 1295 } 1296 case KEYED_SUPER_PROPERTY: { 1297 RegisterAllocationScope register_scope(this); 1298 RegisterList args = register_allocator()->NewRegisterList(4); 1299 builder()->StoreAccumulatorInRegister(args[3]); 1300 SuperPropertyReference* super_property = 1301 property->obj()->AsSuperPropertyReference(); 1302 VisitForRegisterValue(super_property->this_var(), args[0]); 1303 VisitForRegisterValue(super_property->home_object(), args[1]); 1304 VisitForRegisterValue(property->key(), args[2]); 1305 builder()->CallRuntime(StoreKeyedToSuperRuntimeId(), args); 1306 break; 1307 } 1308 } 1309} 1310 1311void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) { 1312 if (stmt->subject()->IsNullLiteral() || 1313 stmt->subject()->IsUndefinedLiteral()) { 1314 // ForIn generates lots of code, skip if it wouldn't produce any effects. 1315 return; 1316 } 1317 1318 LoopBuilder loop_builder(builder()); 1319 BytecodeLabel subject_null_label, subject_undefined_label; 1320 1321 // Prepare the state for executing ForIn. 1322 builder()->SetExpressionAsStatementPosition(stmt->subject()); 1323 VisitForAccumulatorValue(stmt->subject()); 1324 builder()->JumpIfUndefined(&subject_undefined_label); 1325 builder()->JumpIfNull(&subject_null_label); 1326 Register receiver = register_allocator()->NewRegister(); 1327 builder()->ConvertAccumulatorToObject(receiver); 1328 1329 // Used as kRegTriple and kRegPair in ForInPrepare and ForInNext. 1330 RegisterList triple = register_allocator()->NewRegisterList(3); 1331 Register cache_length = triple[2]; 1332 builder()->ForInPrepare(receiver, triple); 1333 1334 // Set up loop counter 1335 Register index = register_allocator()->NewRegister(); 1336 builder()->LoadLiteral(Smi::kZero); 1337 builder()->StoreAccumulatorInRegister(index); 1338 1339 // The loop 1340 VisitIterationHeader(stmt, &loop_builder); 1341 builder()->SetExpressionAsStatementPosition(stmt->each()); 1342 builder()->ForInContinue(index, cache_length); 1343 loop_builder.BreakIfFalse(); 1344 FeedbackSlot slot = stmt->ForInFeedbackSlot(); 1345 builder()->ForInNext(receiver, index, triple.Truncate(2), 1346 feedback_index(slot)); 1347 loop_builder.ContinueIfUndefined(); 1348 VisitForInAssignment(stmt->each(), stmt->EachFeedbackSlot()); 1349 VisitIterationBody(stmt, &loop_builder); 1350 builder()->ForInStep(index); 1351 builder()->StoreAccumulatorInRegister(index); 1352 loop_builder.JumpToHeader(loop_depth_); 1353 loop_builder.EndLoop(); 1354 builder()->Bind(&subject_null_label); 1355 builder()->Bind(&subject_undefined_label); 1356} 1357 1358void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { 1359 LoopBuilder loop_builder(builder()); 1360 1361 builder()->SetExpressionAsStatementPosition(stmt->assign_iterator()); 1362 VisitForEffect(stmt->assign_iterator()); 1363 1364 VisitIterationHeader(stmt, &loop_builder); 1365 builder()->SetExpressionAsStatementPosition(stmt->next_result()); 1366 VisitForEffect(stmt->next_result()); 1367 VisitForAccumulatorValue(stmt->result_done()); 1368 loop_builder.BreakIfTrue(); 1369 1370 VisitForEffect(stmt->assign_each()); 1371 VisitIterationBody(stmt, &loop_builder); 1372 loop_builder.JumpToHeader(loop_depth_); 1373 loop_builder.EndLoop(); 1374} 1375 1376void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { 1377 TryCatchBuilder try_control_builder(builder(), stmt->catch_prediction()); 1378 1379 // Preserve the context in a dedicated register, so that it can be restored 1380 // when the handler is entered by the stack-unwinding machinery. 1381 // TODO(mstarzinger): Be smarter about register allocation. 1382 Register context = register_allocator()->NewRegister(); 1383 builder()->MoveRegister(Register::current_context(), context); 1384 1385 // Evaluate the try-block inside a control scope. This simulates a handler 1386 // that is intercepting 'throw' control commands. 1387 try_control_builder.BeginTry(context); 1388 { 1389 ControlScopeForTryCatch scope(this, &try_control_builder); 1390 Visit(stmt->try_block()); 1391 } 1392 try_control_builder.EndTry(); 1393 1394 // Create a catch scope that binds the exception. 1395 BuildNewLocalCatchContext(stmt->variable(), stmt->scope()); 1396 builder()->StoreAccumulatorInRegister(context); 1397 1398 // If requested, clear message object as we enter the catch block. 1399 if (stmt->clear_pending_message()) { 1400 builder()->LoadTheHole().SetPendingMessage(); 1401 } 1402 1403 // Load the catch context into the accumulator. 1404 builder()->LoadAccumulatorWithRegister(context); 1405 1406 // Evaluate the catch-block. 1407 VisitInScope(stmt->catch_block(), stmt->scope()); 1408 try_control_builder.EndCatch(); 1409} 1410 1411void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { 1412 TryFinallyBuilder try_control_builder(builder(), stmt->catch_prediction()); 1413 1414 // We keep a record of all paths that enter the finally-block to be able to 1415 // dispatch to the correct continuation point after the statements in the 1416 // finally-block have been evaluated. 1417 // 1418 // The try-finally construct can enter the finally-block in three ways: 1419 // 1. By exiting the try-block normally, falling through at the end. 1420 // 2. By exiting the try-block with a function-local control flow transfer 1421 // (i.e. through break/continue/return statements). 1422 // 3. By exiting the try-block with a thrown exception. 1423 // 1424 // The result register semantics depend on how the block was entered: 1425 // - ReturnStatement: It represents the return value being returned. 1426 // - ThrowStatement: It represents the exception being thrown. 1427 // - BreakStatement/ContinueStatement: Undefined and not used. 1428 // - Falling through into finally-block: Undefined and not used. 1429 Register token = register_allocator()->NewRegister(); 1430 Register result = register_allocator()->NewRegister(); 1431 ControlScope::DeferredCommands commands(this, token, result); 1432 1433 // Preserve the context in a dedicated register, so that it can be restored 1434 // when the handler is entered by the stack-unwinding machinery. 1435 // TODO(mstarzinger): Be smarter about register allocation. 1436 Register context = register_allocator()->NewRegister(); 1437 builder()->MoveRegister(Register::current_context(), context); 1438 1439 // Evaluate the try-block inside a control scope. This simulates a handler 1440 // that is intercepting all control commands. 1441 try_control_builder.BeginTry(context); 1442 { 1443 ControlScopeForTryFinally scope(this, &try_control_builder, &commands); 1444 Visit(stmt->try_block()); 1445 } 1446 try_control_builder.EndTry(); 1447 1448 // Record fall-through and exception cases. 1449 commands.RecordFallThroughPath(); 1450 try_control_builder.LeaveTry(); 1451 try_control_builder.BeginHandler(); 1452 commands.RecordHandlerReThrowPath(); 1453 1454 // Pending message object is saved on entry. 1455 try_control_builder.BeginFinally(); 1456 Register message = context; // Reuse register. 1457 1458 // Clear message object as we enter the finally block. 1459 builder()->LoadTheHole().SetPendingMessage().StoreAccumulatorInRegister( 1460 message); 1461 1462 // Evaluate the finally-block. 1463 Visit(stmt->finally_block()); 1464 try_control_builder.EndFinally(); 1465 1466 // Pending message object is restored on exit. 1467 builder()->LoadAccumulatorWithRegister(message).SetPendingMessage(); 1468 1469 // Dynamic dispatch after the finally-block. 1470 commands.ApplyDeferredCommands(); 1471} 1472 1473void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) { 1474 builder()->SetStatementPosition(stmt); 1475 builder()->Debugger(); 1476} 1477 1478void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { 1479 uint8_t flags = CreateClosureFlags::Encode( 1480 expr->pretenure(), closure_scope()->is_function_scope()); 1481 size_t entry = builder()->AllocateDeferredConstantPoolEntry(); 1482 int slot_index = feedback_index(expr->LiteralFeedbackSlot()); 1483 builder()->CreateClosure(entry, slot_index, flags); 1484 function_literals_.push_back(std::make_pair(expr, entry)); 1485} 1486 1487void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr) { 1488 Register constructor = VisitForRegisterValue(expr->constructor()); 1489 { 1490 RegisterAllocationScope register_scope(this); 1491 RegisterList args = register_allocator()->NewRegisterList(4); 1492 VisitForAccumulatorValueOrTheHole(expr->extends()); 1493 builder() 1494 ->StoreAccumulatorInRegister(args[0]) 1495 .MoveRegister(constructor, args[1]) 1496 .LoadLiteral(Smi::FromInt(expr->start_position())) 1497 .StoreAccumulatorInRegister(args[2]) 1498 .LoadLiteral(Smi::FromInt(expr->end_position())) 1499 .StoreAccumulatorInRegister(args[3]) 1500 .CallRuntime(Runtime::kDefineClass, args); 1501 } 1502 Register prototype = register_allocator()->NewRegister(); 1503 builder()->StoreAccumulatorInRegister(prototype); 1504 1505 if (FunctionLiteral::NeedsHomeObject(expr->constructor())) { 1506 // Prototype is already in the accumulator. 1507 builder()->StoreHomeObjectProperty( 1508 constructor, feedback_index(expr->HomeObjectSlot()), language_mode()); 1509 } 1510 1511 VisitClassLiteralProperties(expr, constructor, prototype); 1512 BuildClassLiteralNameProperty(expr, constructor); 1513 builder()->CallRuntime(Runtime::kToFastProperties, constructor); 1514 // Assign to class variable. 1515 if (expr->class_variable_proxy() != nullptr) { 1516 VariableProxy* proxy = expr->class_variable_proxy(); 1517 FeedbackSlot slot = 1518 expr->NeedsProxySlot() ? expr->ProxySlot() : FeedbackSlot::Invalid(); 1519 BuildVariableAssignment(proxy->var(), Token::INIT, slot, 1520 HoleCheckMode::kElided); 1521 } 1522} 1523 1524void BytecodeGenerator::VisitClassLiteralProperties(ClassLiteral* expr, 1525 Register constructor, 1526 Register prototype) { 1527 RegisterAllocationScope register_scope(this); 1528 RegisterList args = register_allocator()->NewRegisterList(4); 1529 Register receiver = args[0], key = args[1], value = args[2], attr = args[3]; 1530 1531 bool attr_assigned = false; 1532 Register old_receiver = Register::invalid_value(); 1533 1534 // Create nodes to store method values into the literal. 1535 for (int i = 0; i < expr->properties()->length(); i++) { 1536 ClassLiteral::Property* property = expr->properties()->at(i); 1537 1538 // Set-up receiver. 1539 Register new_receiver = property->is_static() ? constructor : prototype; 1540 if (new_receiver != old_receiver) { 1541 builder()->MoveRegister(new_receiver, receiver); 1542 old_receiver = new_receiver; 1543 } 1544 1545 if (property->key()->IsStringLiteral()) { 1546 VisitForRegisterValue(property->key(), key); 1547 } else { 1548 VisitForAccumulatorValue(property->key()); 1549 builder()->ConvertAccumulatorToName(key); 1550 } 1551 1552 if (property->is_static() && property->is_computed_name()) { 1553 // The static prototype property is read only. We handle the non computed 1554 // property name case in the parser. Since this is the only case where we 1555 // need to check for an own read only property we special case this so we 1556 // do not need to do this for every property. 1557 BytecodeLabel done; 1558 builder() 1559 ->LoadLiteral(prototype_string()) 1560 .CompareOperation(Token::Value::EQ_STRICT, key) 1561 .JumpIfFalse(&done) 1562 .CallRuntime(Runtime::kThrowStaticPrototypeError) 1563 .Bind(&done); 1564 } 1565 1566 VisitForRegisterValue(property->value(), value); 1567 VisitSetHomeObject(value, receiver, property); 1568 1569 if (!attr_assigned) { 1570 builder() 1571 ->LoadLiteral(Smi::FromInt(DONT_ENUM)) 1572 .StoreAccumulatorInRegister(attr); 1573 attr_assigned = true; 1574 } 1575 1576 switch (property->kind()) { 1577 case ClassLiteral::Property::METHOD: { 1578 DataPropertyInLiteralFlags flags = DataPropertyInLiteralFlag::kDontEnum; 1579 if (property->NeedsSetFunctionName()) { 1580 flags |= DataPropertyInLiteralFlag::kSetFunctionName; 1581 } 1582 1583 FeedbackSlot slot = property->GetStoreDataPropertySlot(); 1584 DCHECK(!slot.IsInvalid()); 1585 1586 builder() 1587 ->LoadAccumulatorWithRegister(value) 1588 .StoreDataPropertyInLiteral(receiver, key, flags, 1589 feedback_index(slot)); 1590 break; 1591 } 1592 case ClassLiteral::Property::GETTER: { 1593 builder()->CallRuntime(Runtime::kDefineGetterPropertyUnchecked, args); 1594 break; 1595 } 1596 case ClassLiteral::Property::SETTER: { 1597 builder()->CallRuntime(Runtime::kDefineSetterPropertyUnchecked, args); 1598 break; 1599 } 1600 case ClassLiteral::Property::FIELD: { 1601 UNREACHABLE(); 1602 break; 1603 } 1604 } 1605 } 1606} 1607 1608void BytecodeGenerator::BuildClassLiteralNameProperty(ClassLiteral* expr, 1609 Register literal) { 1610 if (!expr->has_name_static_property() && 1611 !expr->constructor()->raw_name()->IsEmpty()) { 1612 Runtime::FunctionId runtime_id = 1613 expr->has_static_computed_names() 1614 ? Runtime::kInstallClassNameAccessorWithCheck 1615 : Runtime::kInstallClassNameAccessor; 1616 builder()->CallRuntime(runtime_id, literal); 1617 } 1618} 1619 1620void BytecodeGenerator::VisitNativeFunctionLiteral( 1621 NativeFunctionLiteral* expr) { 1622 size_t entry = builder()->AllocateDeferredConstantPoolEntry(); 1623 int slot_index = feedback_index(expr->LiteralFeedbackSlot()); 1624 builder()->CreateClosure(entry, slot_index, NOT_TENURED); 1625 native_function_literals_.push_back(std::make_pair(expr, entry)); 1626} 1627 1628void BytecodeGenerator::VisitDoExpression(DoExpression* expr) { 1629 VisitBlock(expr->block()); 1630 VisitVariableProxy(expr->result()); 1631} 1632 1633void BytecodeGenerator::VisitConditional(Conditional* expr) { 1634 if (expr->condition()->ToBooleanIsTrue()) { 1635 // Generate then block unconditionally as always true. 1636 VisitForAccumulatorValue(expr->then_expression()); 1637 } else if (expr->condition()->ToBooleanIsFalse()) { 1638 // Generate else block unconditionally if it exists. 1639 VisitForAccumulatorValue(expr->else_expression()); 1640 } else { 1641 BytecodeLabel end_label; 1642 BytecodeLabels then_labels(zone()), else_labels(zone()); 1643 1644 VisitForTest(expr->condition(), &then_labels, &else_labels, 1645 TestFallthrough::kThen); 1646 1647 then_labels.Bind(builder()); 1648 VisitForAccumulatorValue(expr->then_expression()); 1649 builder()->Jump(&end_label); 1650 1651 else_labels.Bind(builder()); 1652 VisitForAccumulatorValue(expr->else_expression()); 1653 builder()->Bind(&end_label); 1654 } 1655} 1656 1657void BytecodeGenerator::VisitLiteral(Literal* expr) { 1658 if (!execution_result()->IsEffect()) { 1659 const AstValue* raw_value = expr->raw_value(); 1660 builder()->LoadLiteral(raw_value); 1661 } 1662} 1663 1664void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { 1665 // Materialize a regular expression literal. 1666 builder()->CreateRegExpLiteral( 1667 expr->raw_pattern(), feedback_index(expr->literal_slot()), expr->flags()); 1668} 1669 1670void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { 1671 // Deep-copy the literal boilerplate. 1672 uint8_t flags = CreateObjectLiteralFlags::Encode( 1673 expr->IsFastCloningSupported(), 1674 ConstructorBuiltinsAssembler::FastCloneShallowObjectPropertiesCount( 1675 expr->properties_count()), 1676 expr->ComputeFlags()); 1677 1678 Register literal = register_allocator()->NewRegister(); 1679 size_t entry; 1680 // If constant properties is an empty fixed array, use a cached empty fixed 1681 // array to ensure it's only added to the constant pool once. 1682 if (expr->properties_count() == 0) { 1683 entry = builder()->EmptyFixedArrayConstantPoolEntry(); 1684 } else { 1685 entry = builder()->AllocateDeferredConstantPoolEntry(); 1686 object_literals_.push_back(std::make_pair(expr, entry)); 1687 } 1688 builder()->CreateObjectLiteral(entry, feedback_index(expr->literal_slot()), 1689 flags, literal); 1690 1691 // Store computed values into the literal. 1692 int property_index = 0; 1693 AccessorTable accessor_table(zone()); 1694 for (; property_index < expr->properties()->length(); property_index++) { 1695 ObjectLiteral::Property* property = expr->properties()->at(property_index); 1696 if (property->is_computed_name()) break; 1697 if (property->IsCompileTimeValue()) continue; 1698 1699 RegisterAllocationScope inner_register_scope(this); 1700 Literal* key = property->key()->AsLiteral(); 1701 switch (property->kind()) { 1702 case ObjectLiteral::Property::SPREAD: 1703 case ObjectLiteral::Property::CONSTANT: 1704 UNREACHABLE(); 1705 case ObjectLiteral::Property::MATERIALIZED_LITERAL: 1706 DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value())); 1707 // Fall through. 1708 case ObjectLiteral::Property::COMPUTED: { 1709 // It is safe to use [[Put]] here because the boilerplate already 1710 // contains computed properties with an uninitialized value. 1711 if (key->IsStringLiteral()) { 1712 DCHECK(key->IsPropertyName()); 1713 if (property->emit_store()) { 1714 VisitForAccumulatorValue(property->value()); 1715 if (FunctionLiteral::NeedsHomeObject(property->value())) { 1716 RegisterAllocationScope register_scope(this); 1717 Register value = register_allocator()->NewRegister(); 1718 builder()->StoreAccumulatorInRegister(value); 1719 builder()->StoreNamedOwnProperty( 1720 literal, key->AsRawPropertyName(), 1721 feedback_index(property->GetSlot(0))); 1722 VisitSetHomeObject(value, literal, property, 1); 1723 } else { 1724 builder()->StoreNamedOwnProperty( 1725 literal, key->AsRawPropertyName(), 1726 feedback_index(property->GetSlot(0))); 1727 } 1728 } else { 1729 VisitForEffect(property->value()); 1730 } 1731 } else { 1732 RegisterList args = register_allocator()->NewRegisterList(4); 1733 1734 builder()->MoveRegister(literal, args[0]); 1735 VisitForRegisterValue(property->key(), args[1]); 1736 VisitForRegisterValue(property->value(), args[2]); 1737 if (property->emit_store()) { 1738 builder() 1739 ->LoadLiteral(Smi::FromInt(SLOPPY)) 1740 .StoreAccumulatorInRegister(args[3]) 1741 .CallRuntime(Runtime::kSetProperty, args); 1742 Register value = args[2]; 1743 VisitSetHomeObject(value, literal, property); 1744 } 1745 } 1746 break; 1747 } 1748 case ObjectLiteral::Property::PROTOTYPE: { 1749 DCHECK(property->emit_store()); 1750 RegisterList args = register_allocator()->NewRegisterList(2); 1751 builder()->MoveRegister(literal, args[0]); 1752 VisitForRegisterValue(property->value(), args[1]); 1753 builder()->CallRuntime(Runtime::kInternalSetPrototype, args); 1754 break; 1755 } 1756 case ObjectLiteral::Property::GETTER: 1757 if (property->emit_store()) { 1758 accessor_table.lookup(key)->second->getter = property; 1759 } 1760 break; 1761 case ObjectLiteral::Property::SETTER: 1762 if (property->emit_store()) { 1763 accessor_table.lookup(key)->second->setter = property; 1764 } 1765 break; 1766 } 1767 } 1768 1769 // Define accessors, using only a single call to the runtime for each pair of 1770 // corresponding getters and setters. 1771 for (AccessorTable::Iterator it = accessor_table.begin(); 1772 it != accessor_table.end(); ++it) { 1773 RegisterAllocationScope inner_register_scope(this); 1774 RegisterList args = register_allocator()->NewRegisterList(5); 1775 builder()->MoveRegister(literal, args[0]); 1776 VisitForRegisterValue(it->first, args[1]); 1777 VisitObjectLiteralAccessor(literal, it->second->getter, args[2]); 1778 VisitObjectLiteralAccessor(literal, it->second->setter, args[3]); 1779 builder() 1780 ->LoadLiteral(Smi::FromInt(NONE)) 1781 .StoreAccumulatorInRegister(args[4]) 1782 .CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, args); 1783 } 1784 1785 // Object literals have two parts. The "static" part on the left contains no 1786 // computed property names, and so we can compute its map ahead of time; see 1787 // Runtime_CreateObjectLiteralBoilerplate. The second "dynamic" part starts 1788 // with the first computed property name and continues with all properties to 1789 // its right. All the code from above initializes the static component of the 1790 // object literal, and arranges for the map of the result to reflect the 1791 // static order in which the keys appear. For the dynamic properties, we 1792 // compile them into a series of "SetOwnProperty" runtime calls. This will 1793 // preserve insertion order. 1794 for (; property_index < expr->properties()->length(); property_index++) { 1795 ObjectLiteral::Property* property = expr->properties()->at(property_index); 1796 RegisterAllocationScope inner_register_scope(this); 1797 1798 if (property->kind() == ObjectLiteral::Property::PROTOTYPE) { 1799 DCHECK(property->emit_store()); 1800 RegisterList args = register_allocator()->NewRegisterList(2); 1801 builder()->MoveRegister(literal, args[0]); 1802 VisitForRegisterValue(property->value(), args[1]); 1803 builder()->CallRuntime(Runtime::kInternalSetPrototype, args); 1804 continue; 1805 } 1806 1807 switch (property->kind()) { 1808 case ObjectLiteral::Property::CONSTANT: 1809 case ObjectLiteral::Property::COMPUTED: 1810 case ObjectLiteral::Property::MATERIALIZED_LITERAL: { 1811 Register key = register_allocator()->NewRegister(); 1812 VisitForAccumulatorValue(property->key()); 1813 builder()->ConvertAccumulatorToName(key); 1814 1815 Register value = VisitForRegisterValue(property->value()); 1816 VisitSetHomeObject(value, literal, property); 1817 1818 DataPropertyInLiteralFlags data_property_flags = 1819 DataPropertyInLiteralFlag::kNoFlags; 1820 if (property->NeedsSetFunctionName()) { 1821 data_property_flags |= DataPropertyInLiteralFlag::kSetFunctionName; 1822 } 1823 1824 FeedbackSlot slot = property->GetStoreDataPropertySlot(); 1825 DCHECK(!slot.IsInvalid()); 1826 1827 builder() 1828 ->LoadAccumulatorWithRegister(value) 1829 .StoreDataPropertyInLiteral(literal, key, data_property_flags, 1830 feedback_index(slot)); 1831 break; 1832 } 1833 case ObjectLiteral::Property::GETTER: 1834 case ObjectLiteral::Property::SETTER: { 1835 RegisterList args = register_allocator()->NewRegisterList(4); 1836 builder()->MoveRegister(literal, args[0]); 1837 VisitForAccumulatorValue(property->key()); 1838 builder()->ConvertAccumulatorToName(args[1]); 1839 VisitForRegisterValue(property->value(), args[2]); 1840 VisitSetHomeObject(args[2], literal, property); 1841 builder() 1842 ->LoadLiteral(Smi::FromInt(NONE)) 1843 .StoreAccumulatorInRegister(args[3]); 1844 Runtime::FunctionId function_id = 1845 property->kind() == ObjectLiteral::Property::GETTER 1846 ? Runtime::kDefineGetterPropertyUnchecked 1847 : Runtime::kDefineSetterPropertyUnchecked; 1848 builder()->CallRuntime(function_id, args); 1849 break; 1850 } 1851 case ObjectLiteral::Property::SPREAD: { 1852 RegisterList args = register_allocator()->NewRegisterList(2); 1853 builder()->MoveRegister(literal, args[0]); 1854 VisitForRegisterValue(property->value(), args[1]); 1855 builder()->CallRuntime(Runtime::kCopyDataProperties, args); 1856 break; 1857 } 1858 case ObjectLiteral::Property::PROTOTYPE: 1859 UNREACHABLE(); // Handled specially above. 1860 break; 1861 } 1862 } 1863 1864 builder()->LoadAccumulatorWithRegister(literal); 1865} 1866 1867void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { 1868 // Deep-copy the literal boilerplate. 1869 uint8_t flags = CreateArrayLiteralFlags::Encode( 1870 expr->IsFastCloningSupported(), expr->ComputeFlags()); 1871 1872 size_t entry = builder()->AllocateDeferredConstantPoolEntry(); 1873 builder()->CreateArrayLiteral(entry, feedback_index(expr->literal_slot()), 1874 flags); 1875 array_literals_.push_back(std::make_pair(expr, entry)); 1876 1877 Register index, literal; 1878 1879 // Evaluate all the non-constant subexpressions and store them into the 1880 // newly cloned array. 1881 bool literal_in_accumulator = true; 1882 for (int array_index = 0; array_index < expr->values()->length(); 1883 array_index++) { 1884 Expression* subexpr = expr->values()->at(array_index); 1885 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; 1886 DCHECK(!subexpr->IsSpread()); 1887 1888 if (literal_in_accumulator) { 1889 index = register_allocator()->NewRegister(); 1890 literal = register_allocator()->NewRegister(); 1891 builder()->StoreAccumulatorInRegister(literal); 1892 literal_in_accumulator = false; 1893 } 1894 1895 FeedbackSlot slot = expr->LiteralFeedbackSlot(); 1896 builder() 1897 ->LoadLiteral(Smi::FromInt(array_index)) 1898 .StoreAccumulatorInRegister(index); 1899 VisitForAccumulatorValue(subexpr); 1900 builder()->StoreKeyedProperty(literal, index, feedback_index(slot), 1901 language_mode()); 1902 } 1903 1904 if (!literal_in_accumulator) { 1905 // Restore literal array into accumulator. 1906 builder()->LoadAccumulatorWithRegister(literal); 1907 } 1908} 1909 1910void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) { 1911 builder()->SetExpressionPosition(proxy); 1912 BuildVariableLoad(proxy->var(), proxy->VariableFeedbackSlot(), 1913 proxy->hole_check_mode()); 1914} 1915 1916void BytecodeGenerator::BuildVariableLoad(Variable* variable, FeedbackSlot slot, 1917 HoleCheckMode hole_check_mode, 1918 TypeofMode typeof_mode) { 1919 switch (variable->location()) { 1920 case VariableLocation::LOCAL: { 1921 Register source(builder()->Local(variable->index())); 1922 // We need to load the variable into the accumulator, even when in a 1923 // VisitForRegisterScope, in order to avoid register aliasing if 1924 // subsequent expressions assign to the same variable. 1925 builder()->LoadAccumulatorWithRegister(source); 1926 if (hole_check_mode == HoleCheckMode::kRequired) { 1927 BuildThrowIfHole(variable->raw_name()); 1928 } 1929 break; 1930 } 1931 case VariableLocation::PARAMETER: { 1932 // The parameter indices are shifted by 1 (receiver is variable 1933 // index -1 but is parameter index 0 in BytecodeArrayBuilder). 1934 Register source = builder()->Parameter(variable->index() + 1); 1935 // We need to load the variable into the accumulator, even when in a 1936 // VisitForRegisterScope, in order to avoid register aliasing if 1937 // subsequent expressions assign to the same variable. 1938 builder()->LoadAccumulatorWithRegister(source); 1939 if (hole_check_mode == HoleCheckMode::kRequired) { 1940 BuildThrowIfHole(variable->raw_name()); 1941 } 1942 break; 1943 } 1944 case VariableLocation::UNALLOCATED: { 1945 // The global identifier "undefined" is immutable. Everything 1946 // else could be reassigned. For performance, we do a pointer comparison 1947 // rather than checking if the raw_name is really "undefined". 1948 if (variable->raw_name() == undefined_string()) { 1949 builder()->LoadUndefined(); 1950 } else { 1951 builder()->LoadGlobal(variable->raw_name(), feedback_index(slot), 1952 typeof_mode); 1953 } 1954 break; 1955 } 1956 case VariableLocation::CONTEXT: { 1957 int depth = execution_context()->ContextChainDepth(variable->scope()); 1958 ContextScope* context = execution_context()->Previous(depth); 1959 Register context_reg; 1960 if (context) { 1961 context_reg = context->reg(); 1962 depth = 0; 1963 } else { 1964 context_reg = execution_context()->reg(); 1965 } 1966 1967 BytecodeArrayBuilder::ContextSlotMutability immutable = 1968 (variable->maybe_assigned() == kNotAssigned) 1969 ? BytecodeArrayBuilder::kImmutableSlot 1970 : BytecodeArrayBuilder::kMutableSlot; 1971 1972 builder()->LoadContextSlot(context_reg, variable->index(), depth, 1973 immutable); 1974 if (hole_check_mode == HoleCheckMode::kRequired) { 1975 BuildThrowIfHole(variable->raw_name()); 1976 } 1977 break; 1978 } 1979 case VariableLocation::LOOKUP: { 1980 switch (variable->mode()) { 1981 case DYNAMIC_LOCAL: { 1982 Variable* local_variable = variable->local_if_not_shadowed(); 1983 int depth = 1984 execution_context()->ContextChainDepth(local_variable->scope()); 1985 builder()->LoadLookupContextSlot(variable->raw_name(), typeof_mode, 1986 local_variable->index(), depth); 1987 if (hole_check_mode == HoleCheckMode::kRequired) { 1988 BuildThrowIfHole(variable->raw_name()); 1989 } 1990 break; 1991 } 1992 case DYNAMIC_GLOBAL: { 1993 int depth = 1994 closure_scope()->ContextChainLengthUntilOutermostSloppyEval(); 1995 builder()->LoadLookupGlobalSlot(variable->raw_name(), typeof_mode, 1996 feedback_index(slot), depth); 1997 break; 1998 } 1999 default: 2000 builder()->LoadLookupSlot(variable->raw_name(), typeof_mode); 2001 } 2002 break; 2003 } 2004 case VariableLocation::MODULE: { 2005 int depth = execution_context()->ContextChainDepth(variable->scope()); 2006 builder()->LoadModuleVariable(variable->index(), depth); 2007 if (hole_check_mode == HoleCheckMode::kRequired) { 2008 BuildThrowIfHole(variable->raw_name()); 2009 } 2010 break; 2011 } 2012 } 2013} 2014 2015void BytecodeGenerator::BuildVariableLoadForAccumulatorValue( 2016 Variable* variable, FeedbackSlot slot, HoleCheckMode hole_check_mode, 2017 TypeofMode typeof_mode) { 2018 ValueResultScope accumulator_result(this); 2019 BuildVariableLoad(variable, slot, hole_check_mode, typeof_mode); 2020} 2021 2022void BytecodeGenerator::BuildReturn() { 2023 if (FLAG_trace) { 2024 RegisterAllocationScope register_scope(this); 2025 Register result = register_allocator()->NewRegister(); 2026 // Runtime returns {result} value, preserving accumulator. 2027 builder()->StoreAccumulatorInRegister(result).CallRuntime( 2028 Runtime::kTraceExit, result); 2029 } 2030 builder()->Return(); 2031} 2032 2033void BytecodeGenerator::BuildAsyncReturn() { 2034 DCHECK(IsAsyncFunction(info()->literal()->kind())); 2035 RegisterAllocationScope register_scope(this); 2036 RegisterList args = register_allocator()->NewRegisterList(3); 2037 Register receiver = args[0]; 2038 Register promise = args[1]; 2039 Register return_value = args[2]; 2040 builder()->StoreAccumulatorInRegister(return_value); 2041 2042 Variable* var_promise = closure_scope()->promise_var(); 2043 DCHECK_NOT_NULL(var_promise); 2044 BuildVariableLoad(var_promise, FeedbackSlot::Invalid(), 2045 HoleCheckMode::kElided); 2046 builder() 2047 ->StoreAccumulatorInRegister(promise) 2048 .LoadUndefined() 2049 .StoreAccumulatorInRegister(receiver) 2050 .CallJSRuntime(Context::PROMISE_RESOLVE_INDEX, args) 2051 .LoadAccumulatorWithRegister(promise); 2052 BuildReturn(); 2053} 2054 2055void BytecodeGenerator::BuildReThrow() { builder()->ReThrow(); } 2056 2057void BytecodeGenerator::BuildAbort(BailoutReason bailout_reason) { 2058 RegisterAllocationScope register_scope(this); 2059 Register reason = register_allocator()->NewRegister(); 2060 builder() 2061 ->LoadLiteral(Smi::FromInt(static_cast<int>(bailout_reason))) 2062 .StoreAccumulatorInRegister(reason) 2063 .CallRuntime(Runtime::kAbort, reason); 2064} 2065 2066void BytecodeGenerator::BuildThrowReferenceError(const AstRawString* name) { 2067 RegisterAllocationScope register_scope(this); 2068 Register name_reg = register_allocator()->NewRegister(); 2069 builder()->LoadLiteral(name).StoreAccumulatorInRegister(name_reg).CallRuntime( 2070 Runtime::kThrowReferenceError, name_reg); 2071} 2072 2073void BytecodeGenerator::BuildThrowIfHole(const AstRawString* name) { 2074 // TODO(interpreter): Can the parser reduce the number of checks 2075 // performed? Or should there be a ThrowIfHole bytecode. 2076 BytecodeLabel no_reference_error; 2077 builder()->JumpIfNotHole(&no_reference_error); 2078 BuildThrowReferenceError(name); 2079 builder()->Bind(&no_reference_error); 2080} 2081 2082void BytecodeGenerator::BuildHoleCheckForVariableAssignment(Variable* variable, 2083 Token::Value op) { 2084 if (variable->is_this() && variable->mode() == CONST && op == Token::INIT) { 2085 // Perform an initialization check for 'this'. 'this' variable is the 2086 // only variable able to trigger bind operations outside the TDZ 2087 // via 'super' calls. 2088 BytecodeLabel no_reference_error, reference_error; 2089 builder() 2090 ->JumpIfNotHole(&reference_error) 2091 .Jump(&no_reference_error) 2092 .Bind(&reference_error) 2093 .CallRuntime(Runtime::kThrowSuperAlreadyCalledError) 2094 .Bind(&no_reference_error); 2095 } else { 2096 // Perform an initialization check for let/const declared variables. 2097 // E.g. let x = (x = 20); is not allowed. 2098 DCHECK(IsLexicalVariableMode(variable->mode())); 2099 BuildThrowIfHole(variable->raw_name()); 2100 } 2101} 2102 2103void BytecodeGenerator::BuildVariableAssignment(Variable* variable, 2104 Token::Value op, 2105 FeedbackSlot slot, 2106 HoleCheckMode hole_check_mode) { 2107 VariableMode mode = variable->mode(); 2108 RegisterAllocationScope assignment_register_scope(this); 2109 BytecodeLabel end_label; 2110 switch (variable->location()) { 2111 case VariableLocation::PARAMETER: 2112 case VariableLocation::LOCAL: { 2113 Register destination; 2114 if (VariableLocation::PARAMETER == variable->location()) { 2115 destination = builder()->Parameter(variable->index() + 1); 2116 } else { 2117 destination = builder()->Local(variable->index()); 2118 } 2119 2120 if (hole_check_mode == HoleCheckMode::kRequired) { 2121 // Load destination to check for hole. 2122 Register value_temp = register_allocator()->NewRegister(); 2123 builder() 2124 ->StoreAccumulatorInRegister(value_temp) 2125 .LoadAccumulatorWithRegister(destination); 2126 2127 BuildHoleCheckForVariableAssignment(variable, op); 2128 builder()->LoadAccumulatorWithRegister(value_temp); 2129 } 2130 2131 if (mode != CONST || op == Token::INIT) { 2132 builder()->StoreAccumulatorInRegister(destination); 2133 } else if (variable->throw_on_const_assignment(language_mode())) { 2134 builder()->CallRuntime(Runtime::kThrowConstAssignError); 2135 } 2136 break; 2137 } 2138 case VariableLocation::UNALLOCATED: { 2139 builder()->StoreGlobal(variable->raw_name(), feedback_index(slot), 2140 language_mode()); 2141 break; 2142 } 2143 case VariableLocation::CONTEXT: { 2144 int depth = execution_context()->ContextChainDepth(variable->scope()); 2145 ContextScope* context = execution_context()->Previous(depth); 2146 Register context_reg; 2147 2148 if (context) { 2149 context_reg = context->reg(); 2150 depth = 0; 2151 } else { 2152 context_reg = execution_context()->reg(); 2153 } 2154 2155 if (hole_check_mode == HoleCheckMode::kRequired) { 2156 // Load destination to check for hole. 2157 Register value_temp = register_allocator()->NewRegister(); 2158 builder() 2159 ->StoreAccumulatorInRegister(value_temp) 2160 .LoadContextSlot(context_reg, variable->index(), depth, 2161 BytecodeArrayBuilder::kMutableSlot); 2162 2163 BuildHoleCheckForVariableAssignment(variable, op); 2164 builder()->LoadAccumulatorWithRegister(value_temp); 2165 } 2166 2167 if (mode != CONST || op == Token::INIT) { 2168 builder()->StoreContextSlot(context_reg, variable->index(), depth); 2169 } else if (variable->throw_on_const_assignment(language_mode())) { 2170 builder()->CallRuntime(Runtime::kThrowConstAssignError); 2171 } 2172 break; 2173 } 2174 case VariableLocation::LOOKUP: { 2175 builder()->StoreLookupSlot(variable->raw_name(), language_mode()); 2176 break; 2177 } 2178 case VariableLocation::MODULE: { 2179 DCHECK(IsDeclaredVariableMode(mode)); 2180 2181 if (mode == CONST && op != Token::INIT) { 2182 builder()->CallRuntime(Runtime::kThrowConstAssignError); 2183 break; 2184 } 2185 2186 // If we don't throw above, we know that we're dealing with an 2187 // export because imports are const and we do not generate initializing 2188 // assignments for them. 2189 DCHECK(variable->IsExport()); 2190 2191 int depth = execution_context()->ContextChainDepth(variable->scope()); 2192 if (hole_check_mode == HoleCheckMode::kRequired) { 2193 Register value_temp = register_allocator()->NewRegister(); 2194 builder() 2195 ->StoreAccumulatorInRegister(value_temp) 2196 .LoadModuleVariable(variable->index(), depth); 2197 BuildHoleCheckForVariableAssignment(variable, op); 2198 builder()->LoadAccumulatorWithRegister(value_temp); 2199 } 2200 builder()->StoreModuleVariable(variable->index(), depth); 2201 break; 2202 } 2203 } 2204} 2205 2206void BytecodeGenerator::VisitAssignment(Assignment* expr) { 2207 DCHECK(expr->target()->IsValidReferenceExpressionOrThis()); 2208 Register object, key; 2209 RegisterList super_property_args; 2210 const AstRawString* name; 2211 2212 // Left-hand side can only be a property, a global or a variable slot. 2213 Property* property = expr->target()->AsProperty(); 2214 LhsKind assign_type = Property::GetAssignType(property); 2215 2216 // Evaluate LHS expression. 2217 switch (assign_type) { 2218 case VARIABLE: 2219 // Nothing to do to evaluate variable assignment LHS. 2220 break; 2221 case NAMED_PROPERTY: { 2222 object = VisitForRegisterValue(property->obj()); 2223 name = property->key()->AsLiteral()->AsRawPropertyName(); 2224 break; 2225 } 2226 case KEYED_PROPERTY: { 2227 object = VisitForRegisterValue(property->obj()); 2228 key = VisitForRegisterValue(property->key()); 2229 break; 2230 } 2231 case NAMED_SUPER_PROPERTY: { 2232 super_property_args = register_allocator()->NewRegisterList(4); 2233 SuperPropertyReference* super_property = 2234 property->obj()->AsSuperPropertyReference(); 2235 VisitForRegisterValue(super_property->this_var(), super_property_args[0]); 2236 VisitForRegisterValue(super_property->home_object(), 2237 super_property_args[1]); 2238 builder() 2239 ->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName()) 2240 .StoreAccumulatorInRegister(super_property_args[2]); 2241 break; 2242 } 2243 case KEYED_SUPER_PROPERTY: { 2244 super_property_args = register_allocator()->NewRegisterList(4); 2245 SuperPropertyReference* super_property = 2246 property->obj()->AsSuperPropertyReference(); 2247 VisitForRegisterValue(super_property->this_var(), super_property_args[0]); 2248 VisitForRegisterValue(super_property->home_object(), 2249 super_property_args[1]); 2250 VisitForRegisterValue(property->key(), super_property_args[2]); 2251 break; 2252 } 2253 } 2254 2255 // Evaluate the value and potentially handle compound assignments by loading 2256 // the left-hand side value and performing a binary operation. 2257 if (expr->is_compound()) { 2258 Register old_value = register_allocator()->NewRegister(); 2259 switch (assign_type) { 2260 case VARIABLE: { 2261 VariableProxy* proxy = expr->target()->AsVariableProxy(); 2262 BuildVariableLoad(proxy->var(), proxy->VariableFeedbackSlot(), 2263 proxy->hole_check_mode()); 2264 builder()->StoreAccumulatorInRegister(old_value); 2265 break; 2266 } 2267 case NAMED_PROPERTY: { 2268 FeedbackSlot slot = property->PropertyFeedbackSlot(); 2269 builder() 2270 ->LoadNamedProperty(object, name, feedback_index(slot)) 2271 .StoreAccumulatorInRegister(old_value); 2272 break; 2273 } 2274 case KEYED_PROPERTY: { 2275 // Key is already in accumulator at this point due to evaluating the 2276 // LHS above. 2277 FeedbackSlot slot = property->PropertyFeedbackSlot(); 2278 builder() 2279 ->LoadKeyedProperty(object, feedback_index(slot)) 2280 .StoreAccumulatorInRegister(old_value); 2281 break; 2282 } 2283 case NAMED_SUPER_PROPERTY: { 2284 builder() 2285 ->CallRuntime(Runtime::kLoadFromSuper, 2286 super_property_args.Truncate(3)) 2287 .StoreAccumulatorInRegister(old_value); 2288 break; 2289 } 2290 case KEYED_SUPER_PROPERTY: { 2291 builder() 2292 ->CallRuntime(Runtime::kLoadKeyedFromSuper, 2293 super_property_args.Truncate(3)) 2294 .StoreAccumulatorInRegister(old_value); 2295 break; 2296 } 2297 } 2298 VisitForAccumulatorValue(expr->value()); 2299 FeedbackSlot slot = expr->binary_operation()->BinaryOperationFeedbackSlot(); 2300 builder()->BinaryOperation(expr->binary_op(), old_value, 2301 feedback_index(slot)); 2302 } else { 2303 VisitForAccumulatorValue(expr->value()); 2304 } 2305 2306 // Store the value. 2307 builder()->SetExpressionPosition(expr); 2308 FeedbackSlot slot = expr->AssignmentSlot(); 2309 switch (assign_type) { 2310 case VARIABLE: { 2311 // TODO(oth): The BuildVariableAssignment() call is hard to reason about. 2312 // Is the value in the accumulator safe? Yes, but scary. 2313 VariableProxy* proxy = expr->target()->AsVariableProxy(); 2314 BuildVariableAssignment(proxy->var(), expr->op(), slot, 2315 proxy->hole_check_mode()); 2316 break; 2317 } 2318 case NAMED_PROPERTY: 2319 builder()->StoreNamedProperty(object, name, feedback_index(slot), 2320 language_mode()); 2321 break; 2322 case KEYED_PROPERTY: 2323 builder()->StoreKeyedProperty(object, key, feedback_index(slot), 2324 language_mode()); 2325 break; 2326 case NAMED_SUPER_PROPERTY: { 2327 builder() 2328 ->StoreAccumulatorInRegister(super_property_args[3]) 2329 .CallRuntime(StoreToSuperRuntimeId(), super_property_args); 2330 break; 2331 } 2332 case KEYED_SUPER_PROPERTY: { 2333 builder() 2334 ->StoreAccumulatorInRegister(super_property_args[3]) 2335 .CallRuntime(StoreKeyedToSuperRuntimeId(), super_property_args); 2336 break; 2337 } 2338 } 2339} 2340 2341void BytecodeGenerator::VisitYield(Yield* expr) { 2342 builder()->SetExpressionPosition(expr); 2343 Register value = VisitForRegisterValue(expr->expression()); 2344 2345 Register generator = VisitForRegisterValue(expr->generator_object()); 2346 2347 // Save context, registers, and state. Then return. 2348 builder() 2349 ->LoadLiteral(Smi::FromInt(expr->yield_id())) 2350 .SuspendGenerator(generator) 2351 .LoadAccumulatorWithRegister(value) 2352 .Return(); // Hard return (ignore any finally blocks). 2353 2354 builder()->Bind(&(generator_resume_points_[expr->yield_id()])); 2355 // Upon resume, we continue here. 2356 2357 { 2358 RegisterAllocationScope register_scope(this); 2359 2360 // Update state to indicate that we have finished resuming. Loop headers 2361 // rely on this. 2362 builder() 2363 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)) 2364 .StoreAccumulatorInRegister(generator_state_); 2365 2366 Register input = register_allocator()->NewRegister(); 2367 builder() 2368 ->CallRuntime(Runtime::kInlineGeneratorGetInputOrDebugPos, generator) 2369 .StoreAccumulatorInRegister(input); 2370 2371 Register resume_mode = register_allocator()->NewRegister(); 2372 builder() 2373 ->CallRuntime(Runtime::kInlineGeneratorGetResumeMode, generator) 2374 .StoreAccumulatorInRegister(resume_mode); 2375 2376 // Now dispatch on resume mode. 2377 2378 BytecodeLabel resume_with_next; 2379 BytecodeLabel resume_with_return; 2380 BytecodeLabel resume_with_throw; 2381 2382 builder() 2383 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kNext)) 2384 .CompareOperation(Token::EQ_STRICT, resume_mode) 2385 .JumpIfTrue(&resume_with_next) 2386 .LoadLiteral(Smi::FromInt(JSGeneratorObject::kThrow)) 2387 .CompareOperation(Token::EQ_STRICT, resume_mode) 2388 .JumpIfTrue(&resume_with_throw) 2389 .Jump(&resume_with_return); 2390 2391 builder()->Bind(&resume_with_return); 2392 { 2393 RegisterList args = register_allocator()->NewRegisterList(2); 2394 builder() 2395 ->MoveRegister(input, args[0]) 2396 .LoadTrue() 2397 .StoreAccumulatorInRegister(args[1]) 2398 .CallRuntime(Runtime::kInlineCreateIterResultObject, args); 2399 execution_control()->ReturnAccumulator(); 2400 } 2401 2402 builder()->Bind(&resume_with_throw); 2403 builder()->SetExpressionPosition(expr); 2404 builder()->LoadAccumulatorWithRegister(input); 2405 if (expr->rethrow_on_exception()) { 2406 builder()->ReThrow(); 2407 } else { 2408 builder()->Throw(); 2409 } 2410 2411 builder()->Bind(&resume_with_next); 2412 builder()->LoadAccumulatorWithRegister(input); 2413 } 2414} 2415 2416void BytecodeGenerator::VisitThrow(Throw* expr) { 2417 VisitForAccumulatorValue(expr->exception()); 2418 builder()->SetExpressionPosition(expr); 2419 builder()->Throw(); 2420} 2421 2422void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) { 2423 LhsKind property_kind = Property::GetAssignType(expr); 2424 FeedbackSlot slot = expr->PropertyFeedbackSlot(); 2425 builder()->SetExpressionPosition(expr); 2426 switch (property_kind) { 2427 case VARIABLE: 2428 UNREACHABLE(); 2429 case NAMED_PROPERTY: { 2430 builder()->LoadNamedProperty( 2431 obj, expr->key()->AsLiteral()->AsRawPropertyName(), 2432 feedback_index(slot)); 2433 break; 2434 } 2435 case KEYED_PROPERTY: { 2436 VisitForAccumulatorValue(expr->key()); 2437 builder()->LoadKeyedProperty(obj, feedback_index(slot)); 2438 break; 2439 } 2440 case NAMED_SUPER_PROPERTY: 2441 VisitNamedSuperPropertyLoad(expr, Register::invalid_value()); 2442 break; 2443 case KEYED_SUPER_PROPERTY: 2444 VisitKeyedSuperPropertyLoad(expr, Register::invalid_value()); 2445 break; 2446 } 2447} 2448 2449void BytecodeGenerator::VisitPropertyLoadForRegister(Register obj, 2450 Property* expr, 2451 Register destination) { 2452 ValueResultScope result_scope(this); 2453 VisitPropertyLoad(obj, expr); 2454 builder()->StoreAccumulatorInRegister(destination); 2455} 2456 2457void BytecodeGenerator::VisitNamedSuperPropertyLoad(Property* property, 2458 Register opt_receiver_out) { 2459 RegisterAllocationScope register_scope(this); 2460 SuperPropertyReference* super_property = 2461 property->obj()->AsSuperPropertyReference(); 2462 RegisterList args = register_allocator()->NewRegisterList(3); 2463 VisitForRegisterValue(super_property->this_var(), args[0]); 2464 VisitForRegisterValue(super_property->home_object(), args[1]); 2465 builder() 2466 ->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName()) 2467 .StoreAccumulatorInRegister(args[2]) 2468 .CallRuntime(Runtime::kLoadFromSuper, args); 2469 2470 if (opt_receiver_out.is_valid()) { 2471 builder()->MoveRegister(args[0], opt_receiver_out); 2472 } 2473} 2474 2475void BytecodeGenerator::VisitKeyedSuperPropertyLoad(Property* property, 2476 Register opt_receiver_out) { 2477 RegisterAllocationScope register_scope(this); 2478 SuperPropertyReference* super_property = 2479 property->obj()->AsSuperPropertyReference(); 2480 RegisterList args = register_allocator()->NewRegisterList(3); 2481 VisitForRegisterValue(super_property->this_var(), args[0]); 2482 VisitForRegisterValue(super_property->home_object(), args[1]); 2483 VisitForRegisterValue(property->key(), args[2]); 2484 builder()->CallRuntime(Runtime::kLoadKeyedFromSuper, args); 2485 2486 if (opt_receiver_out.is_valid()) { 2487 builder()->MoveRegister(args[0], opt_receiver_out); 2488 } 2489} 2490 2491void BytecodeGenerator::VisitProperty(Property* expr) { 2492 LhsKind property_kind = Property::GetAssignType(expr); 2493 if (property_kind != NAMED_SUPER_PROPERTY && 2494 property_kind != KEYED_SUPER_PROPERTY) { 2495 Register obj = VisitForRegisterValue(expr->obj()); 2496 VisitPropertyLoad(obj, expr); 2497 } else { 2498 VisitPropertyLoad(Register::invalid_value(), expr); 2499 } 2500} 2501 2502void BytecodeGenerator::VisitArguments(ZoneList<Expression*>* args, 2503 RegisterList* arg_regs) { 2504 // Visit arguments. 2505 for (int i = 0; i < static_cast<int>(args->length()); i++) { 2506 VisitAndPushIntoRegisterList(args->at(i), arg_regs); 2507 } 2508} 2509 2510void BytecodeGenerator::VisitCall(Call* expr) { 2511 Expression* callee_expr = expr->expression(); 2512 Call::CallType call_type = expr->GetCallType(); 2513 2514 if (call_type == Call::SUPER_CALL) { 2515 return VisitCallSuper(expr); 2516 } 2517 2518 // Grow the args list as we visit receiver / arguments to avoid allocating all 2519 // the registers up-front. Otherwise these registers are unavailable during 2520 // receiver / argument visiting and we can end up with memory leaks due to 2521 // registers keeping objects alive. 2522 Register callee = register_allocator()->NewRegister(); 2523 RegisterList args = register_allocator()->NewGrowableRegisterList(); 2524 2525 // TODO(petermarshall): We have a lot of call bytecodes that are very similar, 2526 // see if we can reduce the number by adding a separate argument which 2527 // specifies the call type (e.g., property, spread, tailcall, etc.). 2528 2529 // Prepare the callee and the receiver to the function call. This depends on 2530 // the semantics of the underlying call type. 2531 switch (call_type) { 2532 case Call::NAMED_PROPERTY_CALL: 2533 case Call::KEYED_PROPERTY_CALL: { 2534 Property* property = callee_expr->AsProperty(); 2535 VisitAndPushIntoRegisterList(property->obj(), &args); 2536 VisitPropertyLoadForRegister(args.last_register(), property, callee); 2537 break; 2538 } 2539 case Call::GLOBAL_CALL: { 2540 // Receiver is undefined for global calls. 2541 BuildPushUndefinedIntoRegisterList(&args); 2542 // Load callee as a global variable. 2543 VariableProxy* proxy = callee_expr->AsVariableProxy(); 2544 BuildVariableLoadForAccumulatorValue(proxy->var(), 2545 proxy->VariableFeedbackSlot(), 2546 proxy->hole_check_mode()); 2547 builder()->StoreAccumulatorInRegister(callee); 2548 break; 2549 } 2550 case Call::WITH_CALL: { 2551 Register receiver = register_allocator()->GrowRegisterList(&args); 2552 DCHECK(callee_expr->AsVariableProxy()->var()->IsLookupSlot()); 2553 { 2554 RegisterAllocationScope inner_register_scope(this); 2555 Register name = register_allocator()->NewRegister(); 2556 2557 // Call %LoadLookupSlotForCall to get the callee and receiver. 2558 DCHECK(Register::AreContiguous(callee, receiver)); 2559 RegisterList result_pair(callee.index(), 2); 2560 USE(receiver); 2561 Variable* variable = callee_expr->AsVariableProxy()->var(); 2562 builder() 2563 ->LoadLiteral(variable->raw_name()) 2564 .StoreAccumulatorInRegister(name) 2565 .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, name, 2566 result_pair); 2567 } 2568 break; 2569 } 2570 case Call::OTHER_CALL: { 2571 BuildPushUndefinedIntoRegisterList(&args); 2572 VisitForRegisterValue(callee_expr, callee); 2573 break; 2574 } 2575 case Call::NAMED_SUPER_PROPERTY_CALL: { 2576 Register receiver = register_allocator()->GrowRegisterList(&args); 2577 Property* property = callee_expr->AsProperty(); 2578 VisitNamedSuperPropertyLoad(property, receiver); 2579 builder()->StoreAccumulatorInRegister(callee); 2580 break; 2581 } 2582 case Call::KEYED_SUPER_PROPERTY_CALL: { 2583 Register receiver = register_allocator()->GrowRegisterList(&args); 2584 Property* property = callee_expr->AsProperty(); 2585 VisitKeyedSuperPropertyLoad(property, receiver); 2586 builder()->StoreAccumulatorInRegister(callee); 2587 break; 2588 } 2589 case Call::SUPER_CALL: 2590 UNREACHABLE(); 2591 break; 2592 } 2593 2594 // Evaluate all arguments to the function call and store in sequential args 2595 // registers. 2596 VisitArguments(expr->arguments(), &args); 2597 CHECK_EQ(expr->arguments()->length() + 1, args.register_count()); 2598 2599 // Resolve callee for a potential direct eval call. This block will mutate the 2600 // callee value. 2601 if (expr->is_possibly_eval() && expr->arguments()->length() > 0) { 2602 RegisterAllocationScope inner_register_scope(this); 2603 // Set up arguments for ResolvePossiblyDirectEval by copying callee, source 2604 // strings and function closure, and loading language and 2605 // position. 2606 RegisterList runtime_call_args = register_allocator()->NewRegisterList(6); 2607 builder() 2608 ->MoveRegister(callee, runtime_call_args[0]) 2609 .MoveRegister(args[1], runtime_call_args[1]) 2610 .MoveRegister(Register::function_closure(), runtime_call_args[2]) 2611 .LoadLiteral(Smi::FromInt(language_mode())) 2612 .StoreAccumulatorInRegister(runtime_call_args[3]) 2613 .LoadLiteral(Smi::FromInt(current_scope()->start_position())) 2614 .StoreAccumulatorInRegister(runtime_call_args[4]) 2615 .LoadLiteral(Smi::FromInt(expr->position())) 2616 .StoreAccumulatorInRegister(runtime_call_args[5]); 2617 2618 // Call ResolvePossiblyDirectEval and modify the callee. 2619 builder() 2620 ->CallRuntime(Runtime::kResolvePossiblyDirectEval, runtime_call_args) 2621 .StoreAccumulatorInRegister(callee); 2622 } 2623 2624 builder()->SetExpressionPosition(expr); 2625 2626 // When a call contains a spread, a Call AST node is only created if there is 2627 // exactly one spread, and it is the last argument. 2628 if (expr->only_last_arg_is_spread()) { 2629 DCHECK_EQ(TailCallMode::kDisallow, expr->tail_call_mode()); 2630 builder()->CallWithSpread(callee, args); 2631 } else { 2632 int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot()); 2633 builder()->Call(callee, args, feedback_slot_index, call_type, 2634 expr->tail_call_mode()); 2635 } 2636} 2637 2638void BytecodeGenerator::VisitCallSuper(Call* expr) { 2639 RegisterAllocationScope register_scope(this); 2640 SuperCallReference* super = expr->expression()->AsSuperCallReference(); 2641 2642 // Prepare the constructor to the super call. 2643 VisitForAccumulatorValue(super->this_function_var()); 2644 Register constructor = register_allocator()->NewRegister(); 2645 builder()->GetSuperConstructor(constructor); 2646 2647 ZoneList<Expression*>* args = expr->arguments(); 2648 RegisterList args_regs = register_allocator()->NewGrowableRegisterList(); 2649 VisitArguments(args, &args_regs); 2650 // The new target is loaded into the accumulator from the 2651 // {new.target} variable. 2652 VisitForAccumulatorValue(super->new_target_var()); 2653 builder()->SetExpressionPosition(expr); 2654 2655 // When a super call contains a spread, a CallSuper AST node is only created 2656 // if there is exactly one spread, and it is the last argument. 2657 if (expr->only_last_arg_is_spread()) { 2658 // TODO(petermarshall): Collect type on the feedback slot. 2659 builder()->ConstructWithSpread(constructor, args_regs); 2660 } else { 2661 // Call construct. 2662 // TODO(turbofan): For now we do gather feedback on super constructor 2663 // calls, utilizing the existing machinery to inline the actual call 2664 // target and the JSCreate for the implicit receiver allocation. This 2665 // is not an ideal solution for super constructor calls, but it gets 2666 // the job done for now. In the long run we might want to revisit this 2667 // and come up with a better way. 2668 int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot()); 2669 builder()->Construct(constructor, args_regs, feedback_slot_index); 2670 } 2671} 2672 2673void BytecodeGenerator::VisitCallNew(CallNew* expr) { 2674 Register constructor = VisitForRegisterValue(expr->expression()); 2675 RegisterList args = register_allocator()->NewGrowableRegisterList(); 2676 VisitArguments(expr->arguments(), &args); 2677 2678 // The accumulator holds new target which is the same as the 2679 // constructor for CallNew. 2680 builder()->SetExpressionPosition(expr); 2681 builder()->LoadAccumulatorWithRegister(constructor); 2682 2683 if (expr->only_last_arg_is_spread()) { 2684 // TODO(petermarshall): Collect type on the feedback slot. 2685 builder()->ConstructWithSpread(constructor, args); 2686 } else { 2687 builder()->Construct(constructor, args, 2688 feedback_index(expr->CallNewFeedbackSlot())); 2689 } 2690} 2691 2692void BytecodeGenerator::VisitCallRuntime(CallRuntime* expr) { 2693 if (expr->is_jsruntime()) { 2694 RegisterList args = register_allocator()->NewGrowableRegisterList(); 2695 // Allocate a register for the receiver and load it with undefined. 2696 BuildPushUndefinedIntoRegisterList(&args); 2697 VisitArguments(expr->arguments(), &args); 2698 builder()->CallJSRuntime(expr->context_index(), args); 2699 } else { 2700 // Evaluate all arguments to the runtime call. 2701 RegisterList args = register_allocator()->NewGrowableRegisterList(); 2702 VisitArguments(expr->arguments(), &args); 2703 Runtime::FunctionId function_id = expr->function()->function_id; 2704 builder()->CallRuntime(function_id, args); 2705 } 2706} 2707 2708void BytecodeGenerator::VisitVoid(UnaryOperation* expr) { 2709 VisitForEffect(expr->expression()); 2710 builder()->LoadUndefined(); 2711} 2712 2713void BytecodeGenerator::VisitTypeOf(UnaryOperation* expr) { 2714 if (expr->expression()->IsVariableProxy()) { 2715 // Typeof does not throw a reference error on global variables, hence we 2716 // perform a non-contextual load in case the operand is a variable proxy. 2717 VariableProxy* proxy = expr->expression()->AsVariableProxy(); 2718 BuildVariableLoadForAccumulatorValue( 2719 proxy->var(), proxy->VariableFeedbackSlot(), proxy->hole_check_mode(), 2720 INSIDE_TYPEOF); 2721 } else { 2722 VisitForAccumulatorValue(expr->expression()); 2723 } 2724 builder()->TypeOf(); 2725} 2726 2727void BytecodeGenerator::VisitNot(UnaryOperation* expr) { 2728 if (execution_result()->IsEffect()) { 2729 VisitForEffect(expr->expression()); 2730 } else if (execution_result()->IsTest()) { 2731 TestResultScope* test_result = execution_result()->AsTest(); 2732 // No actual logical negation happening, we just swap the control flow by 2733 // swapping the target labels and the fallthrough branch. 2734 VisitForTest(expr->expression(), test_result->else_labels(), 2735 test_result->then_labels(), 2736 test_result->inverted_fallthrough()); 2737 test_result->SetResultConsumedByTest(); 2738 } else { 2739 VisitForAccumulatorValue(expr->expression()); 2740 builder()->LogicalNot(); 2741 } 2742} 2743 2744void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { 2745 switch (expr->op()) { 2746 case Token::Value::NOT: 2747 VisitNot(expr); 2748 break; 2749 case Token::Value::TYPEOF: 2750 VisitTypeOf(expr); 2751 break; 2752 case Token::Value::VOID: 2753 VisitVoid(expr); 2754 break; 2755 case Token::Value::DELETE: 2756 VisitDelete(expr); 2757 break; 2758 case Token::Value::BIT_NOT: 2759 case Token::Value::ADD: 2760 case Token::Value::SUB: 2761 // These operators are converted to an equivalent binary operators in 2762 // the parser. These operators are not expected to be visited here. 2763 UNREACHABLE(); 2764 default: 2765 UNREACHABLE(); 2766 } 2767} 2768 2769void BytecodeGenerator::VisitDelete(UnaryOperation* expr) { 2770 if (expr->expression()->IsProperty()) { 2771 // Delete of an object property is allowed both in sloppy 2772 // and strict modes. 2773 Property* property = expr->expression()->AsProperty(); 2774 Register object = VisitForRegisterValue(property->obj()); 2775 VisitForAccumulatorValue(property->key()); 2776 builder()->Delete(object, language_mode()); 2777 } else if (expr->expression()->IsVariableProxy()) { 2778 // Delete of an unqualified identifier is allowed in sloppy mode but is 2779 // not allowed in strict mode. Deleting 'this' is allowed in both modes. 2780 VariableProxy* proxy = expr->expression()->AsVariableProxy(); 2781 Variable* variable = proxy->var(); 2782 DCHECK(is_sloppy(language_mode()) || variable->is_this()); 2783 switch (variable->location()) { 2784 case VariableLocation::UNALLOCATED: { 2785 // Global var, let, const or variables not explicitly declared. 2786 Register native_context = register_allocator()->NewRegister(); 2787 Register global_object = register_allocator()->NewRegister(); 2788 builder() 2789 ->LoadContextSlot(execution_context()->reg(), 2790 Context::NATIVE_CONTEXT_INDEX, 0, 2791 BytecodeArrayBuilder::kMutableSlot) 2792 .StoreAccumulatorInRegister(native_context) 2793 .LoadContextSlot(native_context, Context::EXTENSION_INDEX, 0, 2794 BytecodeArrayBuilder::kMutableSlot) 2795 .StoreAccumulatorInRegister(global_object) 2796 .LoadLiteral(variable->raw_name()) 2797 .Delete(global_object, language_mode()); 2798 break; 2799 } 2800 case VariableLocation::PARAMETER: 2801 case VariableLocation::LOCAL: 2802 case VariableLocation::CONTEXT: { 2803 // Deleting local var/let/const, context variables, and arguments 2804 // does not have any effect. 2805 if (variable->is_this()) { 2806 builder()->LoadTrue(); 2807 } else { 2808 builder()->LoadFalse(); 2809 } 2810 break; 2811 } 2812 case VariableLocation::LOOKUP: { 2813 Register name_reg = register_allocator()->NewRegister(); 2814 builder() 2815 ->LoadLiteral(variable->raw_name()) 2816 .StoreAccumulatorInRegister(name_reg) 2817 .CallRuntime(Runtime::kDeleteLookupSlot, name_reg); 2818 break; 2819 } 2820 default: 2821 UNREACHABLE(); 2822 } 2823 } else { 2824 // Delete of an unresolvable reference returns true. 2825 VisitForEffect(expr->expression()); 2826 builder()->LoadTrue(); 2827 } 2828} 2829 2830void BytecodeGenerator::VisitCountOperation(CountOperation* expr) { 2831 DCHECK(expr->expression()->IsValidReferenceExpressionOrThis()); 2832 2833 // Left-hand side can only be a property, a global or a variable slot. 2834 Property* property = expr->expression()->AsProperty(); 2835 LhsKind assign_type = Property::GetAssignType(property); 2836 2837 bool is_postfix = expr->is_postfix() && !execution_result()->IsEffect(); 2838 2839 // Evaluate LHS expression and get old value. 2840 Register object, key, old_value; 2841 RegisterList super_property_args; 2842 const AstRawString* name; 2843 switch (assign_type) { 2844 case VARIABLE: { 2845 VariableProxy* proxy = expr->expression()->AsVariableProxy(); 2846 BuildVariableLoadForAccumulatorValue(proxy->var(), 2847 proxy->VariableFeedbackSlot(), 2848 proxy->hole_check_mode()); 2849 break; 2850 } 2851 case NAMED_PROPERTY: { 2852 FeedbackSlot slot = property->PropertyFeedbackSlot(); 2853 object = VisitForRegisterValue(property->obj()); 2854 name = property->key()->AsLiteral()->AsRawPropertyName(); 2855 builder()->LoadNamedProperty(object, name, feedback_index(slot)); 2856 break; 2857 } 2858 case KEYED_PROPERTY: { 2859 FeedbackSlot slot = property->PropertyFeedbackSlot(); 2860 object = VisitForRegisterValue(property->obj()); 2861 // Use visit for accumulator here since we need the key in the accumulator 2862 // for the LoadKeyedProperty. 2863 key = register_allocator()->NewRegister(); 2864 VisitForAccumulatorValue(property->key()); 2865 builder()->StoreAccumulatorInRegister(key).LoadKeyedProperty( 2866 object, feedback_index(slot)); 2867 break; 2868 } 2869 case NAMED_SUPER_PROPERTY: { 2870 super_property_args = register_allocator()->NewRegisterList(4); 2871 RegisterList load_super_args = super_property_args.Truncate(3); 2872 SuperPropertyReference* super_property = 2873 property->obj()->AsSuperPropertyReference(); 2874 VisitForRegisterValue(super_property->this_var(), load_super_args[0]); 2875 VisitForRegisterValue(super_property->home_object(), load_super_args[1]); 2876 builder() 2877 ->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName()) 2878 .StoreAccumulatorInRegister(load_super_args[2]) 2879 .CallRuntime(Runtime::kLoadFromSuper, load_super_args); 2880 break; 2881 } 2882 case KEYED_SUPER_PROPERTY: { 2883 super_property_args = register_allocator()->NewRegisterList(4); 2884 RegisterList load_super_args = super_property_args.Truncate(3); 2885 SuperPropertyReference* super_property = 2886 property->obj()->AsSuperPropertyReference(); 2887 VisitForRegisterValue(super_property->this_var(), load_super_args[0]); 2888 VisitForRegisterValue(super_property->home_object(), load_super_args[1]); 2889 VisitForRegisterValue(property->key(), load_super_args[2]); 2890 builder()->CallRuntime(Runtime::kLoadKeyedFromSuper, load_super_args); 2891 break; 2892 } 2893 } 2894 2895 // Save result for postfix expressions. 2896 if (is_postfix) { 2897 // Convert old value into a number before saving it. 2898 old_value = register_allocator()->NewRegister(); 2899 builder() 2900 ->ConvertAccumulatorToNumber(old_value) 2901 .LoadAccumulatorWithRegister(old_value); 2902 } 2903 2904 // Perform +1/-1 operation. 2905 FeedbackSlot slot = expr->CountBinaryOpFeedbackSlot(); 2906 builder()->CountOperation(expr->binary_op(), feedback_index(slot)); 2907 2908 // Store the value. 2909 builder()->SetExpressionPosition(expr); 2910 FeedbackSlot feedback_slot = expr->CountSlot(); 2911 switch (assign_type) { 2912 case VARIABLE: { 2913 VariableProxy* proxy = expr->expression()->AsVariableProxy(); 2914 BuildVariableAssignment(proxy->var(), expr->op(), feedback_slot, 2915 proxy->hole_check_mode()); 2916 break; 2917 } 2918 case NAMED_PROPERTY: { 2919 builder()->StoreNamedProperty(object, name, feedback_index(feedback_slot), 2920 language_mode()); 2921 break; 2922 } 2923 case KEYED_PROPERTY: { 2924 builder()->StoreKeyedProperty(object, key, feedback_index(feedback_slot), 2925 language_mode()); 2926 break; 2927 } 2928 case NAMED_SUPER_PROPERTY: { 2929 builder() 2930 ->StoreAccumulatorInRegister(super_property_args[3]) 2931 .CallRuntime(StoreToSuperRuntimeId(), super_property_args); 2932 break; 2933 } 2934 case KEYED_SUPER_PROPERTY: { 2935 builder() 2936 ->StoreAccumulatorInRegister(super_property_args[3]) 2937 .CallRuntime(StoreKeyedToSuperRuntimeId(), super_property_args); 2938 break; 2939 } 2940 } 2941 2942 // Restore old value for postfix expressions. 2943 if (is_postfix) { 2944 builder()->LoadAccumulatorWithRegister(old_value); 2945 } 2946} 2947 2948void BytecodeGenerator::VisitBinaryOperation(BinaryOperation* binop) { 2949 switch (binop->op()) { 2950 case Token::COMMA: 2951 VisitCommaExpression(binop); 2952 break; 2953 case Token::OR: 2954 VisitLogicalOrExpression(binop); 2955 break; 2956 case Token::AND: 2957 VisitLogicalAndExpression(binop); 2958 break; 2959 default: 2960 VisitArithmeticExpression(binop); 2961 break; 2962 } 2963} 2964 2965void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) { 2966 Register lhs = VisitForRegisterValue(expr->left()); 2967 VisitForAccumulatorValue(expr->right()); 2968 builder()->SetExpressionPosition(expr); 2969 FeedbackSlot slot = expr->CompareOperationFeedbackSlot(); 2970 builder()->CompareOperation(expr->op(), lhs, feedback_index(slot)); 2971} 2972 2973void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) { 2974 // TODO(rmcilroy): Special case "x * 1.0" and "x * -1" which are generated for 2975 // +x and -x by the parser. 2976 Register lhs = VisitForRegisterValue(expr->left()); 2977 VisitForAccumulatorValue(expr->right()); 2978 FeedbackSlot slot = expr->BinaryOperationFeedbackSlot(); 2979 builder()->SetExpressionPosition(expr); 2980 builder()->BinaryOperation(expr->op(), lhs, feedback_index(slot)); 2981} 2982 2983void BytecodeGenerator::VisitSpread(Spread* expr) { Visit(expr->expression()); } 2984 2985void BytecodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) { 2986 UNREACHABLE(); 2987} 2988 2989void BytecodeGenerator::VisitGetIterator(GetIterator* expr) { 2990 FeedbackSlot load_slot = expr->IteratorPropertyFeedbackSlot(); 2991 FeedbackSlot call_slot = expr->IteratorCallFeedbackSlot(); 2992 2993 RegisterList args = register_allocator()->NewRegisterList(1); 2994 Register method = register_allocator()->NewRegister(); 2995 Register obj = args[0]; 2996 2997 VisitForAccumulatorValue(expr->iterable()); 2998 2999 if (expr->hint() == IteratorType::kAsync) { 3000 FeedbackSlot async_load_slot = expr->AsyncIteratorPropertyFeedbackSlot(); 3001 FeedbackSlot async_call_slot = expr->AsyncIteratorCallFeedbackSlot(); 3002 3003 // Set method to GetMethod(obj, @@asyncIterator) 3004 builder()->StoreAccumulatorInRegister(obj).LoadAsyncIteratorProperty( 3005 obj, feedback_index(async_load_slot)); 3006 3007 BytecodeLabel async_iterator_undefined, async_iterator_null, done; 3008 // TODO(ignition): Add a single opcode for JumpIfNullOrUndefined 3009 builder()->JumpIfUndefined(&async_iterator_undefined); 3010 builder()->JumpIfNull(&async_iterator_null); 3011 3012 // Let iterator be Call(method, obj) 3013 builder()->StoreAccumulatorInRegister(method).Call( 3014 method, args, feedback_index(async_call_slot), 3015 Call::NAMED_PROPERTY_CALL); 3016 3017 // If Type(iterator) is not Object, throw a TypeError exception. 3018 builder()->JumpIfJSReceiver(&done); 3019 builder()->CallRuntime(Runtime::kThrowSymbolAsyncIteratorInvalid); 3020 3021 builder()->Bind(&async_iterator_undefined); 3022 builder()->Bind(&async_iterator_null); 3023 // If method is undefined, 3024 // Let syncMethod be GetMethod(obj, @@iterator) 3025 builder() 3026 ->LoadIteratorProperty(obj, feedback_index(load_slot)) 3027 .StoreAccumulatorInRegister(method); 3028 3029 // Let syncIterator be Call(syncMethod, obj) 3030 builder()->Call(method, args, feedback_index(call_slot), 3031 Call::NAMED_PROPERTY_CALL); 3032 3033 // Return CreateAsyncFromSyncIterator(syncIterator) 3034 // alias `method` register as it's no longer used 3035 Register sync_iter = method; 3036 builder()->StoreAccumulatorInRegister(sync_iter).CallRuntime( 3037 Runtime::kInlineCreateAsyncFromSyncIterator, sync_iter); 3038 3039 builder()->Bind(&done); 3040 } else { 3041 // Let method be GetMethod(obj, @@iterator). 3042 builder() 3043 ->StoreAccumulatorInRegister(obj) 3044 .LoadIteratorProperty(obj, feedback_index(load_slot)) 3045 .StoreAccumulatorInRegister(method); 3046 3047 // Let iterator be Call(method, obj). 3048 builder()->Call(method, args, feedback_index(call_slot), 3049 Call::NAMED_PROPERTY_CALL); 3050 3051 // If Type(iterator) is not Object, throw a TypeError exception. 3052 BytecodeLabel no_type_error; 3053 builder()->JumpIfJSReceiver(&no_type_error); 3054 builder()->CallRuntime(Runtime::kThrowSymbolIteratorInvalid); 3055 builder()->Bind(&no_type_error); 3056 } 3057} 3058 3059void BytecodeGenerator::VisitThisFunction(ThisFunction* expr) { 3060 builder()->LoadAccumulatorWithRegister(Register::function_closure()); 3061} 3062 3063void BytecodeGenerator::VisitSuperCallReference(SuperCallReference* expr) { 3064 // Handled by VisitCall(). 3065 UNREACHABLE(); 3066} 3067 3068void BytecodeGenerator::VisitSuperPropertyReference( 3069 SuperPropertyReference* expr) { 3070 builder()->CallRuntime(Runtime::kThrowUnsupportedSuperError); 3071} 3072 3073void BytecodeGenerator::VisitCommaExpression(BinaryOperation* binop) { 3074 VisitForEffect(binop->left()); 3075 Visit(binop->right()); 3076} 3077 3078void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) { 3079 Expression* left = binop->left(); 3080 Expression* right = binop->right(); 3081 3082 if (execution_result()->IsTest()) { 3083 TestResultScope* test_result = execution_result()->AsTest(); 3084 3085 if (left->ToBooleanIsTrue()) { 3086 builder()->Jump(test_result->NewThenLabel()); 3087 } else if (left->ToBooleanIsFalse() && right->ToBooleanIsFalse()) { 3088 builder()->Jump(test_result->NewElseLabel()); 3089 } else { 3090 BytecodeLabels test_right(zone()); 3091 VisitForTest(left, test_result->then_labels(), &test_right, 3092 TestFallthrough::kElse); 3093 test_right.Bind(builder()); 3094 VisitForTest(right, test_result->then_labels(), 3095 test_result->else_labels(), test_result->fallthrough()); 3096 } 3097 test_result->SetResultConsumedByTest(); 3098 } else { 3099 if (left->ToBooleanIsTrue()) { 3100 VisitForAccumulatorValue(left); 3101 } else if (left->ToBooleanIsFalse()) { 3102 VisitForAccumulatorValue(right); 3103 } else { 3104 BytecodeLabel end_label; 3105 VisitForAccumulatorValue(left); 3106 builder()->JumpIfTrue(&end_label); 3107 VisitForAccumulatorValue(right); 3108 builder()->Bind(&end_label); 3109 } 3110 } 3111} 3112 3113void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) { 3114 Expression* left = binop->left(); 3115 Expression* right = binop->right(); 3116 3117 if (execution_result()->IsTest()) { 3118 TestResultScope* test_result = execution_result()->AsTest(); 3119 3120 if (left->ToBooleanIsFalse()) { 3121 builder()->Jump(test_result->NewElseLabel()); 3122 } else if (left->ToBooleanIsTrue() && right->ToBooleanIsTrue()) { 3123 builder()->Jump(test_result->NewThenLabel()); 3124 } else { 3125 BytecodeLabels test_right(zone()); 3126 VisitForTest(left, &test_right, test_result->else_labels(), 3127 TestFallthrough::kThen); 3128 test_right.Bind(builder()); 3129 VisitForTest(right, test_result->then_labels(), 3130 test_result->else_labels(), test_result->fallthrough()); 3131 } 3132 test_result->SetResultConsumedByTest(); 3133 } else { 3134 if (left->ToBooleanIsFalse()) { 3135 VisitForAccumulatorValue(left); 3136 } else if (left->ToBooleanIsTrue()) { 3137 VisitForAccumulatorValue(right); 3138 } else { 3139 BytecodeLabel end_label; 3140 VisitForAccumulatorValue(left); 3141 builder()->JumpIfFalse(&end_label); 3142 VisitForAccumulatorValue(right); 3143 builder()->Bind(&end_label); 3144 } 3145 } 3146} 3147 3148void BytecodeGenerator::VisitRewritableExpression(RewritableExpression* expr) { 3149 Visit(expr->expression()); 3150} 3151 3152void BytecodeGenerator::BuildNewLocalActivationContext() { 3153 ValueResultScope value_execution_result(this); 3154 Scope* scope = closure_scope(); 3155 3156 // Create the appropriate context. 3157 if (scope->is_script_scope()) { 3158 RegisterList args = register_allocator()->NewRegisterList(2); 3159 builder() 3160 ->LoadAccumulatorWithRegister(Register::function_closure()) 3161 .StoreAccumulatorInRegister(args[0]) 3162 .LoadLiteral(scope) 3163 .StoreAccumulatorInRegister(args[1]) 3164 .CallRuntime(Runtime::kNewScriptContext, args); 3165 } else if (scope->is_module_scope()) { 3166 // We don't need to do anything for the outer script scope. 3167 DCHECK(scope->outer_scope()->is_script_scope()); 3168 3169 // A JSFunction representing a module is called with the module object as 3170 // its sole argument, which we pass on to PushModuleContext. 3171 RegisterList args = register_allocator()->NewRegisterList(3); 3172 builder() 3173 ->MoveRegister(builder()->Parameter(1), args[0]) 3174 .LoadAccumulatorWithRegister(Register::function_closure()) 3175 .StoreAccumulatorInRegister(args[1]) 3176 .LoadLiteral(scope) 3177 .StoreAccumulatorInRegister(args[2]) 3178 .CallRuntime(Runtime::kPushModuleContext, args); 3179 } else { 3180 DCHECK(scope->is_function_scope() || scope->is_eval_scope()); 3181 int slot_count = scope->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; 3182 if (slot_count <= 3183 ConstructorBuiltinsAssembler::MaximumFunctionContextSlots()) { 3184 switch (scope->scope_type()) { 3185 case EVAL_SCOPE: 3186 builder()->CreateEvalContext(slot_count); 3187 break; 3188 case FUNCTION_SCOPE: 3189 builder()->CreateFunctionContext(slot_count); 3190 break; 3191 default: 3192 UNREACHABLE(); 3193 } 3194 } else { 3195 RegisterList args = register_allocator()->NewRegisterList(2); 3196 builder() 3197 ->MoveRegister(Register::function_closure(), args[0]) 3198 .LoadLiteral(Smi::FromInt(scope->scope_type())) 3199 .StoreAccumulatorInRegister(args[1]) 3200 .CallRuntime(Runtime::kNewFunctionContext, args); 3201 } 3202 } 3203} 3204 3205void BytecodeGenerator::BuildLocalActivationContextInitialization() { 3206 DeclarationScope* scope = closure_scope(); 3207 3208 if (scope->has_this_declaration() && scope->receiver()->IsContextSlot()) { 3209 Variable* variable = scope->receiver(); 3210 Register receiver(builder()->Parameter(0)); 3211 // Context variable (at bottom of the context chain). 3212 DCHECK_EQ(0, scope->ContextChainLength(variable->scope())); 3213 builder()->LoadAccumulatorWithRegister(receiver).StoreContextSlot( 3214 execution_context()->reg(), variable->index(), 0); 3215 } 3216 3217 // Copy parameters into context if necessary. 3218 int num_parameters = scope->num_parameters(); 3219 for (int i = 0; i < num_parameters; i++) { 3220 Variable* variable = scope->parameter(i); 3221 if (!variable->IsContextSlot()) continue; 3222 3223 // The parameter indices are shifted by 1 (receiver is variable 3224 // index -1 but is parameter index 0 in BytecodeArrayBuilder). 3225 Register parameter(builder()->Parameter(i + 1)); 3226 // Context variable (at bottom of the context chain). 3227 DCHECK_EQ(0, scope->ContextChainLength(variable->scope())); 3228 builder()->LoadAccumulatorWithRegister(parameter).StoreContextSlot( 3229 execution_context()->reg(), variable->index(), 0); 3230 } 3231} 3232 3233void BytecodeGenerator::BuildNewLocalBlockContext(Scope* scope) { 3234 ValueResultScope value_execution_result(this); 3235 DCHECK(scope->is_block_scope()); 3236 3237 VisitFunctionClosureForContext(); 3238 builder()->CreateBlockContext(scope); 3239} 3240 3241void BytecodeGenerator::BuildNewLocalWithContext(Scope* scope) { 3242 ValueResultScope value_execution_result(this); 3243 3244 Register extension_object = register_allocator()->NewRegister(); 3245 3246 builder()->ConvertAccumulatorToObject(extension_object); 3247 VisitFunctionClosureForContext(); 3248 builder()->CreateWithContext(extension_object, scope); 3249} 3250 3251void BytecodeGenerator::BuildNewLocalCatchContext(Variable* variable, 3252 Scope* scope) { 3253 ValueResultScope value_execution_result(this); 3254 DCHECK(variable->IsContextSlot()); 3255 3256 Register exception = register_allocator()->NewRegister(); 3257 builder()->StoreAccumulatorInRegister(exception); 3258 VisitFunctionClosureForContext(); 3259 builder()->CreateCatchContext(exception, variable->raw_name(), scope); 3260} 3261 3262void BytecodeGenerator::VisitObjectLiteralAccessor( 3263 Register home_object, ObjectLiteralProperty* property, Register value_out) { 3264 if (property == nullptr) { 3265 builder()->LoadNull().StoreAccumulatorInRegister(value_out); 3266 } else { 3267 VisitForRegisterValue(property->value(), value_out); 3268 VisitSetHomeObject(value_out, home_object, property); 3269 } 3270} 3271 3272void BytecodeGenerator::VisitSetHomeObject(Register value, Register home_object, 3273 LiteralProperty* property, 3274 int slot_number) { 3275 Expression* expr = property->value(); 3276 if (FunctionLiteral::NeedsHomeObject(expr)) { 3277 FeedbackSlot slot = property->GetSlot(slot_number); 3278 builder() 3279 ->LoadAccumulatorWithRegister(home_object) 3280 .StoreHomeObjectProperty(value, feedback_index(slot), language_mode()); 3281 } 3282} 3283 3284void BytecodeGenerator::VisitArgumentsObject(Variable* variable) { 3285 if (variable == nullptr) return; 3286 3287 DCHECK(variable->IsContextSlot() || variable->IsStackAllocated()); 3288 3289 // Allocate and initialize a new arguments object and assign to the 3290 // {arguments} variable. 3291 CreateArgumentsType type = 3292 is_strict(language_mode()) || !info()->has_simple_parameters() 3293 ? CreateArgumentsType::kUnmappedArguments 3294 : CreateArgumentsType::kMappedArguments; 3295 builder()->CreateArguments(type); 3296 BuildVariableAssignment(variable, Token::ASSIGN, FeedbackSlot::Invalid(), 3297 HoleCheckMode::kElided); 3298} 3299 3300void BytecodeGenerator::VisitRestArgumentsArray(Variable* rest) { 3301 if (rest == nullptr) return; 3302 3303 // Allocate and initialize a new rest parameter and assign to the {rest} 3304 // variable. 3305 builder()->CreateArguments(CreateArgumentsType::kRestParameter); 3306 DCHECK(rest->IsContextSlot() || rest->IsStackAllocated()); 3307 BuildVariableAssignment(rest, Token::ASSIGN, FeedbackSlot::Invalid(), 3308 HoleCheckMode::kElided); 3309} 3310 3311void BytecodeGenerator::VisitThisFunctionVariable(Variable* variable) { 3312 if (variable == nullptr) return; 3313 3314 // Store the closure we were called with in the given variable. 3315 builder()->LoadAccumulatorWithRegister(Register::function_closure()); 3316 BuildVariableAssignment(variable, Token::INIT, FeedbackSlot::Invalid(), 3317 HoleCheckMode::kElided); 3318} 3319 3320void BytecodeGenerator::VisitNewTargetVariable(Variable* variable) { 3321 if (variable == nullptr) return; 3322 3323 // Store the new target we were called with in the given variable. 3324 builder()->LoadAccumulatorWithRegister(Register::new_target()); 3325 BuildVariableAssignment(variable, Token::INIT, FeedbackSlot::Invalid(), 3326 HoleCheckMode::kElided); 3327 3328 // TODO(mstarzinger): The <new.target> register is not set by the deoptimizer 3329 // and we need to make sure {BytecodeRegisterOptimizer} flushes its state 3330 // before a local variable containing the <new.target> is used. Using a label 3331 // as below flushes the entire pipeline, we should be more specific here. 3332 BytecodeLabel flush_state_label; 3333 builder()->Bind(&flush_state_label); 3334} 3335 3336void BytecodeGenerator::VisitFunctionClosureForContext() { 3337 ValueResultScope value_execution_result(this); 3338 if (closure_scope()->is_script_scope()) { 3339 // Contexts nested in the native context have a canonical empty function as 3340 // their closure, not the anonymous closure containing the global code. 3341 Register native_context = register_allocator()->NewRegister(); 3342 builder() 3343 ->LoadContextSlot(execution_context()->reg(), 3344 Context::NATIVE_CONTEXT_INDEX, 0, 3345 BytecodeArrayBuilder::kMutableSlot) 3346 .StoreAccumulatorInRegister(native_context) 3347 .LoadContextSlot(native_context, Context::CLOSURE_INDEX, 0, 3348 BytecodeArrayBuilder::kMutableSlot); 3349 } else if (closure_scope()->is_eval_scope()) { 3350 // Contexts created by a call to eval have the same closure as the 3351 // context calling eval, not the anonymous closure containing the eval 3352 // code. Fetch it from the context. 3353 builder()->LoadContextSlot(execution_context()->reg(), 3354 Context::CLOSURE_INDEX, 0, 3355 BytecodeArrayBuilder::kMutableSlot); 3356 } else { 3357 DCHECK(closure_scope()->is_function_scope() || 3358 closure_scope()->is_module_scope()); 3359 builder()->LoadAccumulatorWithRegister(Register::function_closure()); 3360 } 3361} 3362 3363// Visits the expression |expr| and places the result in the accumulator. 3364void BytecodeGenerator::VisitForAccumulatorValue(Expression* expr) { 3365 ValueResultScope accumulator_scope(this); 3366 Visit(expr); 3367} 3368 3369void BytecodeGenerator::VisitForAccumulatorValueOrTheHole(Expression* expr) { 3370 if (expr == nullptr) { 3371 builder()->LoadTheHole(); 3372 } else { 3373 VisitForAccumulatorValue(expr); 3374 } 3375} 3376 3377// Visits the expression |expr| and discards the result. 3378void BytecodeGenerator::VisitForEffect(Expression* expr) { 3379 EffectResultScope effect_scope(this); 3380 Visit(expr); 3381} 3382 3383// Visits the expression |expr| and returns the register containing 3384// the expression result. 3385Register BytecodeGenerator::VisitForRegisterValue(Expression* expr) { 3386 VisitForAccumulatorValue(expr); 3387 Register result = register_allocator()->NewRegister(); 3388 builder()->StoreAccumulatorInRegister(result); 3389 return result; 3390} 3391 3392// Visits the expression |expr| and stores the expression result in 3393// |destination|. 3394void BytecodeGenerator::VisitForRegisterValue(Expression* expr, 3395 Register destination) { 3396 ValueResultScope register_scope(this); 3397 Visit(expr); 3398 builder()->StoreAccumulatorInRegister(destination); 3399} 3400 3401// Visits the expression |expr| and pushes the result into a new register 3402// added to the end of |reg_list|. 3403void BytecodeGenerator::VisitAndPushIntoRegisterList(Expression* expr, 3404 RegisterList* reg_list) { 3405 { 3406 ValueResultScope register_scope(this); 3407 Visit(expr); 3408 } 3409 // Grow the register list after visiting the expression to avoid reserving 3410 // the register across the expression evaluation, which could cause memory 3411 // leaks for deep expressions due to dead objects being kept alive by pointers 3412 // in registers. 3413 Register destination = register_allocator()->GrowRegisterList(reg_list); 3414 builder()->StoreAccumulatorInRegister(destination); 3415} 3416 3417void BytecodeGenerator::BuildPushUndefinedIntoRegisterList( 3418 RegisterList* reg_list) { 3419 Register reg = register_allocator()->GrowRegisterList(reg_list); 3420 builder()->LoadUndefined().StoreAccumulatorInRegister(reg); 3421} 3422 3423// Visits the expression |expr| for testing its boolean value and jumping to the 3424// |then| or |other| label depending on value and short-circuit semantics 3425void BytecodeGenerator::VisitForTest(Expression* expr, 3426 BytecodeLabels* then_labels, 3427 BytecodeLabels* else_labels, 3428 TestFallthrough fallthrough) { 3429 bool result_consumed; 3430 { 3431 // To make sure that all temporary registers are returned before generating 3432 // jumps below, we ensure that the result scope is deleted before doing so. 3433 // Dead registers might be materialized otherwise. 3434 TestResultScope test_result(this, then_labels, else_labels, fallthrough); 3435 Visit(expr); 3436 result_consumed = test_result.ResultConsumedByTest(); 3437 } 3438 if (!result_consumed) { 3439 switch (fallthrough) { 3440 case TestFallthrough::kThen: 3441 builder()->JumpIfFalse(else_labels->New()); 3442 break; 3443 case TestFallthrough::kElse: 3444 builder()->JumpIfTrue(then_labels->New()); 3445 break; 3446 case TestFallthrough::kNone: 3447 builder()->JumpIfTrue(then_labels->New()); 3448 builder()->Jump(else_labels->New()); 3449 } 3450 } 3451} 3452 3453void BytecodeGenerator::VisitInScope(Statement* stmt, Scope* scope) { 3454 DCHECK(scope->declarations()->is_empty()); 3455 CurrentScope current_scope(this, scope); 3456 ContextScope context_scope(this, scope); 3457 Visit(stmt); 3458} 3459 3460LanguageMode BytecodeGenerator::language_mode() const { 3461 return current_scope()->language_mode(); 3462} 3463 3464int BytecodeGenerator::feedback_index(FeedbackSlot slot) const { 3465 return FeedbackVector::GetIndex(slot); 3466} 3467 3468Runtime::FunctionId BytecodeGenerator::StoreToSuperRuntimeId() { 3469 return is_strict(language_mode()) ? Runtime::kStoreToSuper_Strict 3470 : Runtime::kStoreToSuper_Sloppy; 3471} 3472 3473Runtime::FunctionId BytecodeGenerator::StoreKeyedToSuperRuntimeId() { 3474 return is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict 3475 : Runtime::kStoreKeyedToSuper_Sloppy; 3476} 3477 3478} // namespace interpreter 3479} // namespace internal 3480} // namespace v8 3481