| OLD | NEW |
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/interpreter/bytecode-generator.h" | 5 #include "src/interpreter/bytecode-generator.h" |
| 6 | 6 |
| 7 #include "src/ast/scopes.h" | 7 #include "src/ast/scopes.h" |
| 8 #include "src/code-stubs.h" | 8 #include "src/code-stubs.h" |
| 9 #include "src/compiler.h" | 9 #include "src/compiler.h" |
| 10 #include "src/interpreter/bytecode-flags.h" | 10 #include "src/interpreter/bytecode-flags.h" |
| (...skipping 514 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 525 if (generator()->HasStackOverflow() && !result_identified()) { | 525 if (generator()->HasStackOverflow() && !result_identified()) { |
| 526 SetResultInAccumulator(); | 526 SetResultInAccumulator(); |
| 527 } | 527 } |
| 528 return result_register_; | 528 return result_register_; |
| 529 } | 529 } |
| 530 | 530 |
| 531 private: | 531 private: |
| 532 Register result_register_; | 532 Register result_register_; |
| 533 }; | 533 }; |
| 534 | 534 |
| 535 // Used to build a list of global declaration initial value pairs. |
| 536 class BytecodeGenerator::GlobalDeclarationsBuilder final : public ZoneObject { |
| 537 public: |
| 538 GlobalDeclarationsBuilder(Isolate* isolate, Zone* zone) |
| 539 : isolate_(isolate), |
| 540 declaration_pairs_(0, zone), |
| 541 constant_pool_entry_(0), |
| 542 has_constant_pool_entry_(false) {} |
| 543 |
| 544 void AddDeclaration(FeedbackVectorSlot slot, Handle<Object> initial_value) { |
| 545 DCHECK(!slot.IsInvalid()); |
| 546 declaration_pairs_.push_back(handle(Smi::FromInt(slot.ToInt()), isolate_)); |
| 547 declaration_pairs_.push_back(initial_value); |
| 548 } |
| 549 |
| 550 Handle<FixedArray> AllocateDeclarationPairs() { |
| 551 DCHECK(has_constant_pool_entry_); |
| 552 int array_index = 0; |
| 553 Handle<FixedArray> data = isolate_->factory()->NewFixedArray( |
| 554 static_cast<int>(declaration_pairs_.size()), TENURED); |
| 555 for (Handle<Object> obj : declaration_pairs_) { |
| 556 data->set(array_index++, *obj); |
| 557 } |
| 558 return data; |
| 559 } |
| 560 |
| 561 size_t constant_pool_entry() { |
| 562 DCHECK(has_constant_pool_entry_); |
| 563 return constant_pool_entry_; |
| 564 } |
| 565 |
| 566 void set_constant_pool_entry(size_t constant_pool_entry) { |
| 567 DCHECK(!empty()); |
| 568 DCHECK(!has_constant_pool_entry_); |
| 569 constant_pool_entry_ = constant_pool_entry; |
| 570 has_constant_pool_entry_ = true; |
| 571 } |
| 572 |
| 573 bool empty() { return declaration_pairs_.empty(); } |
| 574 |
| 575 private: |
| 576 Isolate* isolate_; |
| 577 ZoneVector<Handle<Object>> declaration_pairs_; |
| 578 size_t constant_pool_entry_; |
| 579 bool has_constant_pool_entry_; |
| 580 }; |
| 581 |
| 535 BytecodeGenerator::BytecodeGenerator(CompilationInfo* info) | 582 BytecodeGenerator::BytecodeGenerator(CompilationInfo* info) |
| 536 : isolate_(info->isolate()), | 583 : isolate_(info->isolate()), |
| 537 zone_(info->zone()), | 584 zone_(info->zone()), |
| 538 builder_(new (zone()) BytecodeArrayBuilder( | 585 builder_(new (zone()) BytecodeArrayBuilder( |
| 539 info->isolate(), info->zone(), info->num_parameters_including_this(), | 586 info->isolate(), info->zone(), info->num_parameters_including_this(), |
| 540 info->scope()->MaxNestedContextChainLength(), | 587 info->scope()->MaxNestedContextChainLength(), |
| 541 info->scope()->num_stack_slots(), info->literal(), | 588 info->scope()->num_stack_slots(), info->literal(), |
| 542 info->SourcePositionRecordingMode())), | 589 info->SourcePositionRecordingMode())), |
| 543 info_(info), | 590 info_(info), |
| 544 scope_(info->scope()), | 591 scope_(info->scope()), |
| 545 globals_(0, info->zone()), | 592 globals_builder_(new (zone()) GlobalDeclarationsBuilder(info->isolate(), |
| 593 info->zone())), |
| 594 global_declarations_(0, info->zone()), |
| 546 execution_control_(nullptr), | 595 execution_control_(nullptr), |
| 547 execution_context_(nullptr), | 596 execution_context_(nullptr), |
| 548 execution_result_(nullptr), | 597 execution_result_(nullptr), |
| 549 register_allocator_(nullptr), | 598 register_allocator_(nullptr), |
| 550 generator_resume_points_(info->literal()->yield_count(), info->zone()), | 599 generator_resume_points_(info->literal()->yield_count(), info->zone()), |
| 551 generator_state_() { | 600 generator_state_() { |
| 552 InitializeAstVisitor(isolate()->stack_guard()->real_climit()); | 601 InitializeAstVisitor(isolate()->stack_guard()->real_climit()); |
| 553 } | 602 } |
| 554 | 603 |
| 555 Handle<BytecodeArray> BytecodeGenerator::MakeBytecode() { | 604 Handle<BytecodeArray> BytecodeGenerator::MakeBytecode() { |
| 605 GenerateBytecode(); |
| 606 |
| 607 // Build global declaration pair arrays. |
| 608 for (GlobalDeclarationsBuilder* globals_builder : global_declarations_) { |
| 609 Handle<FixedArray> declarations = |
| 610 globals_builder->AllocateDeclarationPairs(); |
| 611 builder()->InsertReservedConstantPoolEntry( |
| 612 globals_builder->constant_pool_entry(), declarations); |
| 613 } |
| 614 |
| 615 return builder()->ToBytecodeArray(); |
| 616 } |
| 617 |
| 618 void BytecodeGenerator::GenerateBytecode() { |
| 556 // Initialize the incoming context. | 619 // Initialize the incoming context. |
| 557 ContextScope incoming_context(this, scope(), false); | 620 ContextScope incoming_context(this, scope(), false); |
| 558 | 621 |
| 559 // Initialize control scope. | 622 // Initialize control scope. |
| 560 ControlScopeForTopLevel control(this); | 623 ControlScopeForTopLevel control(this); |
| 561 | 624 |
| 562 RegisterAllocationScope register_scope(this); | 625 RegisterAllocationScope register_scope(this); |
| 563 | 626 |
| 564 if (IsResumableFunction(info()->literal()->kind())) { | 627 if (IsResumableFunction(info()->literal()->kind())) { |
| 565 generator_state_ = register_allocator()->NewRegister(); | 628 generator_state_ = register_allocator()->NewRegister(); |
| 566 VisitGeneratorPrologue(); | 629 VisitGeneratorPrologue(); |
| 567 } | 630 } |
| 568 | 631 |
| 569 // Build function context only if there are context allocated variables. | 632 // Build function context only if there are context allocated variables. |
| 570 if (scope()->NeedsContext()) { | 633 if (scope()->NeedsContext()) { |
| 571 // Push a new inner context scope for the function. | 634 // Push a new inner context scope for the function. |
| 572 VisitNewLocalFunctionContext(); | 635 VisitNewLocalFunctionContext(); |
| 573 ContextScope local_function_context(this, scope(), false); | 636 ContextScope local_function_context(this, scope(), false); |
| 574 VisitBuildLocalActivationContext(); | 637 VisitBuildLocalActivationContext(); |
| 575 MakeBytecodeBody(); | 638 GenerateBytecodeBody(); |
| 576 } else { | 639 } else { |
| 577 MakeBytecodeBody(); | 640 GenerateBytecodeBody(); |
| 578 } | 641 } |
| 579 | 642 |
| 580 // In generator functions, we may not have visited every yield in the AST | 643 // In generator functions, we may not have visited every yield in the AST |
| 581 // since we skip some obviously dead code. Hence the generated bytecode may | 644 // since we skip some obviously dead code. Hence the generated bytecode may |
| 582 // contain jumps to unbound labels (resume points that will never be used). | 645 // contain jumps to unbound labels (resume points that will never be used). |
| 583 // We bind these now. | 646 // We bind these now. |
| 584 for (auto& label : generator_resume_points_) { | 647 for (auto& label : generator_resume_points_) { |
| 585 if (!label.is_bound()) builder()->Bind(&label); | 648 if (!label.is_bound()) builder()->Bind(&label); |
| 586 } | 649 } |
| 587 | 650 |
| 588 builder()->EnsureReturn(); | 651 builder()->EnsureReturn(); |
| 589 return builder()->ToBytecodeArray(); | |
| 590 } | 652 } |
| 591 | 653 |
| 592 void BytecodeGenerator::MakeBytecodeBody() { | 654 void BytecodeGenerator::GenerateBytecodeBody() { |
| 593 // Build the arguments object if it is used. | 655 // Build the arguments object if it is used. |
| 594 VisitArgumentsObject(scope()->arguments()); | 656 VisitArgumentsObject(scope()->arguments()); |
| 595 | 657 |
| 596 // Build rest arguments array if it is used. | 658 // Build rest arguments array if it is used. |
| 597 int rest_index; | 659 int rest_index; |
| 598 Variable* rest_parameter = scope()->rest_parameter(&rest_index); | 660 Variable* rest_parameter = scope()->rest_parameter(&rest_index); |
| 599 VisitRestArgumentsArray(rest_parameter); | 661 VisitRestArgumentsArray(rest_parameter); |
| 600 | 662 |
| 601 // Build assignment to {.this_function} variable if it is used. | 663 // Build assignment to {.this_function} variable if it is used. |
| 602 VisitThisFunctionVariable(scope()->this_function_var()); | 664 VisitThisFunctionVariable(scope()->this_function_var()); |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 716 Variable* variable = decl->proxy()->var(); | 778 Variable* variable = decl->proxy()->var(); |
| 717 VariableMode mode = decl->mode(); | 779 VariableMode mode = decl->mode(); |
| 718 // Const and let variables are initialized with the hole so that we can | 780 // Const and let variables are initialized with the hole so that we can |
| 719 // check that they are only assigned once. | 781 // check that they are only assigned once. |
| 720 bool hole_init = mode == CONST || mode == LET; | 782 bool hole_init = mode == CONST || mode == LET; |
| 721 switch (variable->location()) { | 783 switch (variable->location()) { |
| 722 case VariableLocation::GLOBAL: | 784 case VariableLocation::GLOBAL: |
| 723 case VariableLocation::UNALLOCATED: { | 785 case VariableLocation::UNALLOCATED: { |
| 724 DCHECK(!variable->binding_needs_init()); | 786 DCHECK(!variable->binding_needs_init()); |
| 725 FeedbackVectorSlot slot = decl->proxy()->VariableFeedbackSlot(); | 787 FeedbackVectorSlot slot = decl->proxy()->VariableFeedbackSlot(); |
| 726 DCHECK(!slot.IsInvalid()); | 788 globals_builder()->AddDeclaration( |
| 727 globals()->push_back(handle(Smi::FromInt(slot.ToInt()), isolate())); | 789 slot, isolate()->factory()->undefined_value()); |
| 728 globals()->push_back(isolate()->factory()->undefined_value()); | |
| 729 break; | 790 break; |
| 730 } | 791 } |
| 731 case VariableLocation::LOCAL: | 792 case VariableLocation::LOCAL: |
| 732 if (hole_init) { | 793 if (hole_init) { |
| 733 Register destination(variable->index()); | 794 Register destination(variable->index()); |
| 734 builder()->LoadTheHole().StoreAccumulatorInRegister(destination); | 795 builder()->LoadTheHole().StoreAccumulatorInRegister(destination); |
| 735 } | 796 } |
| 736 break; | 797 break; |
| 737 case VariableLocation::PARAMETER: | 798 case VariableLocation::PARAMETER: |
| 738 if (hole_init) { | 799 if (hole_init) { |
| (...skipping 27 matching lines...) Expand all Loading... |
| 766 void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) { | 827 void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) { |
| 767 Variable* variable = decl->proxy()->var(); | 828 Variable* variable = decl->proxy()->var(); |
| 768 switch (variable->location()) { | 829 switch (variable->location()) { |
| 769 case VariableLocation::GLOBAL: | 830 case VariableLocation::GLOBAL: |
| 770 case VariableLocation::UNALLOCATED: { | 831 case VariableLocation::UNALLOCATED: { |
| 771 Handle<SharedFunctionInfo> function = Compiler::GetSharedFunctionInfo( | 832 Handle<SharedFunctionInfo> function = Compiler::GetSharedFunctionInfo( |
| 772 decl->fun(), info()->script(), info()); | 833 decl->fun(), info()->script(), info()); |
| 773 // Check for stack-overflow exception. | 834 // Check for stack-overflow exception. |
| 774 if (function.is_null()) return SetStackOverflow(); | 835 if (function.is_null()) return SetStackOverflow(); |
| 775 FeedbackVectorSlot slot = decl->proxy()->VariableFeedbackSlot(); | 836 FeedbackVectorSlot slot = decl->proxy()->VariableFeedbackSlot(); |
| 776 DCHECK(!slot.IsInvalid()); | 837 globals_builder()->AddDeclaration(slot, function); |
| 777 globals()->push_back(handle(Smi::FromInt(slot.ToInt()), isolate())); | |
| 778 globals()->push_back(function); | |
| 779 break; | 838 break; |
| 780 } | 839 } |
| 781 case VariableLocation::PARAMETER: | 840 case VariableLocation::PARAMETER: |
| 782 case VariableLocation::LOCAL: { | 841 case VariableLocation::LOCAL: { |
| 783 VisitForAccumulatorValue(decl->fun()); | 842 VisitForAccumulatorValue(decl->fun()); |
| 784 DCHECK(variable->mode() == LET || variable->mode() == VAR || | 843 DCHECK(variable->mode() == LET || variable->mode() == VAR || |
| 785 variable->mode() == CONST); | 844 variable->mode() == CONST); |
| 786 VisitVariableAssignment(variable, Token::INIT, | 845 VisitVariableAssignment(variable, Token::INIT, |
| 787 FeedbackVectorSlot::Invalid()); | 846 FeedbackVectorSlot::Invalid()); |
| 788 break; | 847 break; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 803 VisitForAccumulatorValue(decl->fun()); | 862 VisitForAccumulatorValue(decl->fun()); |
| 804 builder()->StoreAccumulatorInRegister(literal).CallRuntime( | 863 builder()->StoreAccumulatorInRegister(literal).CallRuntime( |
| 805 Runtime::kDeclareEvalFunction, name, 2); | 864 Runtime::kDeclareEvalFunction, name, 2); |
| 806 } | 865 } |
| 807 } | 866 } |
| 808 } | 867 } |
| 809 | 868 |
| 810 void BytecodeGenerator::VisitDeclarations( | 869 void BytecodeGenerator::VisitDeclarations( |
| 811 ZoneList<Declaration*>* declarations) { | 870 ZoneList<Declaration*>* declarations) { |
| 812 RegisterAllocationScope register_scope(this); | 871 RegisterAllocationScope register_scope(this); |
| 813 DCHECK(globals()->empty()); | 872 DCHECK(globals_builder()->empty()); |
| 814 for (int i = 0; i < declarations->length(); i++) { | 873 for (int i = 0; i < declarations->length(); i++) { |
| 815 RegisterAllocationScope register_scope(this); | 874 RegisterAllocationScope register_scope(this); |
| 816 Visit(declarations->at(i)); | 875 Visit(declarations->at(i)); |
| 817 } | 876 } |
| 818 if (globals()->empty()) return; | 877 if (globals_builder()->empty()) return; |
| 819 int array_index = 0; | 878 |
| 820 Handle<FixedArray> data = isolate()->factory()->NewFixedArray( | 879 globals_builder()->set_constant_pool_entry( |
| 821 static_cast<int>(globals()->size()), TENURED); | 880 builder()->ReserveConstantPoolEntry()); |
| 822 for (Handle<Object> obj : *globals()) data->set(array_index++, *obj); | |
| 823 int encoded_flags = info()->GetDeclareGlobalsFlags(); | 881 int encoded_flags = info()->GetDeclareGlobalsFlags(); |
| 824 | 882 |
| 825 register_allocator()->PrepareForConsecutiveAllocations(3); | 883 register_allocator()->PrepareForConsecutiveAllocations(3); |
| 826 | 884 |
| 827 Register pairs = register_allocator()->NextConsecutiveRegister(); | 885 Register pairs = register_allocator()->NextConsecutiveRegister(); |
| 828 builder()->LoadLiteral(data); | 886 Register flags = register_allocator()->NextConsecutiveRegister(); |
| 829 builder()->StoreAccumulatorInRegister(pairs); | 887 Register function = register_allocator()->NextConsecutiveRegister(); |
| 830 | 888 |
| 831 Register flags = register_allocator()->NextConsecutiveRegister(); | 889 // Emit code to declare globals. |
| 832 builder()->LoadLiteral(Smi::FromInt(encoded_flags)); | 890 builder() |
| 833 builder()->StoreAccumulatorInRegister(flags); | 891 ->LoadConstantPoolEntry(globals_builder()->constant_pool_entry()) |
| 834 DCHECK(flags.index() == pairs.index() + 1); | 892 .StoreAccumulatorInRegister(pairs) |
| 893 .LoadLiteral(Smi::FromInt(encoded_flags)) |
| 894 .StoreAccumulatorInRegister(flags) |
| 895 .MoveRegister(Register::function_closure(), function) |
| 896 .CallRuntime(Runtime::kDeclareGlobalsForInterpreter, pairs, 3); |
| 835 | 897 |
| 836 Register function = register_allocator()->NextConsecutiveRegister(); | 898 // Push and reset globals builder. |
| 837 builder()->MoveRegister(Register::function_closure(), function); | 899 global_declarations_.push_back(globals_builder()); |
| 838 | 900 globals_builder_ = new (zone()) GlobalDeclarationsBuilder(isolate(), zone()); |
| 839 builder()->CallRuntime(Runtime::kDeclareGlobalsForInterpreter, pairs, 3); | |
| 840 globals()->clear(); | |
| 841 } | 901 } |
| 842 | 902 |
| 843 void BytecodeGenerator::VisitStatements(ZoneList<Statement*>* statements) { | 903 void BytecodeGenerator::VisitStatements(ZoneList<Statement*>* statements) { |
| 844 for (int i = 0; i < statements->length(); i++) { | 904 for (int i = 0; i < statements->length(); i++) { |
| 845 // Allocate an outer register allocations scope for the statement. | 905 // Allocate an outer register allocations scope for the statement. |
| 846 RegisterAllocationScope allocation_scope(this); | 906 RegisterAllocationScope allocation_scope(this); |
| 847 Statement* stmt = statements->at(i); | 907 Statement* stmt = statements->at(i); |
| 848 Visit(stmt); | 908 Visit(stmt); |
| 849 if (stmt->IsJump()) break; | 909 if (stmt->IsJump()) break; |
| 850 } | 910 } |
| (...skipping 2329 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3180 return execution_context()->scope()->language_mode(); | 3240 return execution_context()->scope()->language_mode(); |
| 3181 } | 3241 } |
| 3182 | 3242 |
| 3183 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { | 3243 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { |
| 3184 return TypeFeedbackVector::GetIndex(slot); | 3244 return TypeFeedbackVector::GetIndex(slot); |
| 3185 } | 3245 } |
| 3186 | 3246 |
| 3187 } // namespace interpreter | 3247 } // namespace interpreter |
| 3188 } // namespace internal | 3248 } // namespace internal |
| 3189 } // namespace v8 | 3249 } // namespace v8 |
| OLD | NEW |