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()->InsertConstantPoolEntryAt(globals_builder->constant_pool_entry(), |
| 612 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()->AllocateConstantPoolEntry()); |
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 2328 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3179 return execution_context()->scope()->language_mode(); | 3239 return execution_context()->scope()->language_mode(); |
3180 } | 3240 } |
3181 | 3241 |
3182 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { | 3242 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { |
3183 return TypeFeedbackVector::GetIndex(slot); | 3243 return TypeFeedbackVector::GetIndex(slot); |
3184 } | 3244 } |
3185 | 3245 |
3186 } // namespace interpreter | 3246 } // namespace interpreter |
3187 } // namespace internal | 3247 } // namespace internal |
3188 } // namespace v8 | 3248 } // namespace v8 |
OLD | NEW |