Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(241)

Side by Side Diff: src/interpreter/bytecode-generator.cc

Issue 2664083002: [ignition] desugar async functions/generators/modules in BytecodeGenerator
Patch Set: get rid of lambdas, for better or worse.. Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/interpreter/bytecode-generator.h ('k') | src/interpreter/control-flow-builders.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/compile-time-value.h" 7 #include "src/ast/compile-time-value.h"
8 #include "src/ast/scopes.h" 8 #include "src/ast/scopes.h"
9 #include "src/builtins/builtins-constructor.h" 9 #include "src/builtins/builtins-constructor.h"
10 #include "src/code-stubs.h" 10 #include "src/code-stubs.h"
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after
192 builder()->LoadAccumulatorWithRegister(result_register_); 192 builder()->LoadAccumulatorWithRegister(result_register_);
193 execution_control()->PerformCommand(entry.command, entry.statement); 193 execution_control()->PerformCommand(entry.command, entry.statement);
194 } 194 }
195 dispatch.SetCaseTarget(static_cast<int>(deferred_.size())); 195 dispatch.SetCaseTarget(static_cast<int>(deferred_.size()));
196 } 196 }
197 197
198 BytecodeArrayBuilder* builder() { return generator_->builder(); } 198 BytecodeArrayBuilder* builder() { return generator_->builder(); }
199 ControlScope* execution_control() { return generator_->execution_control(); } 199 ControlScope* execution_control() { return generator_->execution_control(); }
200 200
201 private: 201 private:
202 BytecodeGenerator* generator_; 202 BytecodeGenerator* generator_ = nullptr;
rmcilroy 2017/02/07 17:24:41 Why was this change made? The constructor should s
203 ZoneVector<Entry> deferred_; 203 ZoneVector<Entry> deferred_;
204 Register token_register_; 204 Register token_register_;
205 Register result_register_; 205 Register result_register_;
206 }; 206 };
207 207
208 // Scoped class for dealing with control flow reaching the function level. 208 // Scoped class for dealing with control flow reaching the function level.
209 class BytecodeGenerator::ControlScopeForTopLevel final 209 class BytecodeGenerator::ControlScopeForTopLevel final
210 : public BytecodeGenerator::ControlScope { 210 : public BytecodeGenerator::ControlScope {
211 public: 211 public:
212 explicit ControlScopeForTopLevel(BytecodeGenerator* generator) 212 explicit ControlScopeForTopLevel(BytecodeGenerator* generator)
(...skipping 360 matching lines...) Expand 10 before | Expand all | Expand 10 after
573 Handle<String> name; 573 Handle<String> name;
574 FeedbackVectorSlot slot; 574 FeedbackVectorSlot slot;
575 FeedbackVectorSlot literal_slot; 575 FeedbackVectorSlot literal_slot;
576 FunctionLiteral* func; 576 FunctionLiteral* func;
577 }; 577 };
578 ZoneVector<Declaration> declarations_; 578 ZoneVector<Declaration> declarations_;
579 size_t constant_pool_entry_; 579 size_t constant_pool_entry_;
580 bool has_constant_pool_entry_; 580 bool has_constant_pool_entry_;
581 }; 581 };
582 582
583 template <class T>
584 class TryBlockBuilder;
585 class BytecodeGenerator::SimpleTryCatchBuilder : private TryCatchBuilder {
586 public:
587 typedef ControlScopeForTryCatch TryControlScope;
588
589 explicit SimpleTryCatchBuilder(BytecodeGenerator* generator,
590 HandlerTable::CatchPrediction catch_prediction)
591 : TryCatchBuilder(generator->builder(), catch_prediction),
592 generator_(generator) {}
593
594 Register context() const {
595 DCHECK(context_.is_valid());
596 return context_;
597 }
598
599 private:
600 friend class TryBlockBuilder<SimpleTryCatchBuilder>;
601 friend class CatchBlockBuilder;
602
603 void BeginTry(ControlScopeForTryCatch* scope) {
604 DCHECK_NULL(control_scope_);
605 control_scope_ = scope;
606
607 // Preserve the context in a dedicated register, so that it can be restored
608 // when the handler is entered by the stack-unwinding machinery.
609 // TODO(mstarzinger): Be smarter about register allocation.
610 DCHECK(!context_.is_valid());
611 context_ = generator_->register_allocator()->NewRegister();
612 builder()->MoveRegister(Register::current_context(), context_);
613
614 TryCatchBuilder::BeginTry(context_);
615 last_catch_prediction_ = generator_->catch_prediction_;
616 if (catch_prediction() != HandlerTable::UNCAUGHT) {
617 generator_->catch_prediction_ = catch_prediction();
618 }
rmcilroy 2017/02/07 17:24:41 I'm not sure why we need to update the catch predi
619 }
620
621 void EndTry() {
622 DCHECK_NOT_NULL(control_scope_);
623 generator_->catch_prediction_ = last_catch_prediction_;
624 last_catch_prediction_ = HandlerTable::UNCAUGHT;
625
626 TryCatchBuilder::EndTry();
627 control_scope_ = nullptr;
628 }
629
630 void BeginCatch() {
631 DCHECK_NULL(control_scope_);
632 DCHECK(context_.is_valid());
633 }
634
635 void EndCatch() { TryCatchBuilder::EndCatch(); }
636
637 BytecodeGenerator* generator_;
638 Register context_;
639 ControlScopeForTryCatch* control_scope_ = nullptr;
640 HandlerTable::CatchPrediction last_catch_prediction_;
641 };
642
643 class BytecodeGenerator::SimpleTryFinallyBuilder : public TryFinallyBuilder {
rmcilroy 2017/02/07 17:24:41 I'm not sure on the naming, why is this SimpleTryF
644 public:
645 typedef ControlScopeForTryFinally TryControlScope;
646
647 explicit SimpleTryFinallyBuilder(BytecodeGenerator* generator)
648 : TryFinallyBuilder(generator->builder(), generator->catch_prediction_),
649 generator_(generator),
650 token_(generator->register_allocator()->NewRegister()),
651 result_(generator->register_allocator()->NewRegister()),
652 commands_(generator, token_, result_) {
653 // We keep a record of all paths that enter the finally-block to be able to
654 // dispatch to the correct continuation point after the statements in the
655 // finally-block have been evaluated.
656 //
657 // The try-finally construct can enter the finally-block in three ways:
658 // 1. By exiting the try-block normally, falling through at the end.
659 // 2. By exiting the try-block with a function-local control flow transfer
660 // (i.e. through break/continue/return statements).
661 // 3. By exiting the try-block with a thrown exception.
662 //
663 // The result register semantics depend on how the block was entered:
664 // - ReturnStatement: It represents the return value being returned.
665 // - ThrowStatement: It represents the exception being thrown.
666 // - BreakStatement/ContinueStatement: Undefined and not used.
667 // - Falling through into finally-block: Undefined and not used.
668 }
669
670 private:
671 friend class TryBlockBuilder<SimpleTryFinallyBuilder>;
672 friend class FinallyBlockBuilder;
673
674 void BeginTry(ControlScopeForTryFinally* control_scope) {
675 DCHECK_NULL(control_scope_);
676 control_scope_ = control_scope;
677
678 // Preserve the context in a dedicated register, so that it can be restored
679 // when the handler is entered by the stack-unwinding machinery.
680 // TODO(mstarzinger): Be smarter about register allocation.
681 DCHECK(!context_or_message_.is_valid());
682 context_or_message_ = generator_->register_allocator()->NewRegister();
683 generator_->builder()->MoveRegister(Register::current_context(),
684 context_or_message_);
685
686 TryFinallyBuilder::BeginTry(context_or_message_);
687 }
688
689 void EndTry() {
690 DCHECK_NOT_NULL(control_scope_);
691 TryFinallyBuilder::EndTry();
692 control_scope_ = nullptr;
693
694 // Record fall-through and exception cases.
695 commands_.RecordFallThroughPath();
696 TryFinallyBuilder::LeaveTry();
697 TryFinallyBuilder::BeginHandler();
698 commands_.RecordHandlerReThrowPath();
699 }
700
701 void BeginFinally() {
702 TryFinallyBuilder::BeginFinally();
703 generator_->builder()
704 ->LoadTheHole()
705 .SetPendingMessage()
706 .StoreAccumulatorInRegister(context_or_message_);
707 }
708
709 void EndFinally() {
710 TryFinallyBuilder::EndFinally();
711
712 // Pending message object is restored on exit.
713 generator_->builder()
714 ->LoadAccumulatorWithRegister(context_or_message_)
715 .SetPendingMessage();
716
717 // Dynamic dispatch after the finally-block.
718 commands_.ApplyDeferredCommands();
719 }
720
721 ControlScopeForTryFinally* control_scope_ = nullptr;
722 BytecodeGenerator* generator_;
723 Register token_;
724 Register result_;
725 ControlScope::DeferredCommands commands_;
726 Register context_or_message_;
727 };
728
729 template <class T>
730 class BytecodeGenerator::TryBlockBuilder {
rmcilroy 2017/02/07 17:24:41 I don't think the scoped builders are necessary, I
731 public:
732 typedef T SimpleControlBuilder;
733 explicit TryBlockBuilder(SimpleControlBuilder& builder);
734 ~TryBlockBuilder();
735
736 private:
737 SimpleControlBuilder* builder_;
738 typename SimpleControlBuilder::TryControlScope scope_;
739 };
740
741 template <>
742 BytecodeGenerator::TryBlockBuilder<BytecodeGenerator::SimpleTryCatchBuilder>::
743 TryBlockBuilder(SimpleTryCatchBuilder& builder)
744 : builder_(&builder), scope_(builder_->generator_, builder_) {
745 builder_->BeginTry(&scope_);
746 }
747
748 template <>
749 BytecodeGenerator::TryBlockBuilder<
750 BytecodeGenerator::SimpleTryCatchBuilder>::~TryBlockBuilder() {
751 builder_->EndTry();
752 }
753
754 template <>
755 BytecodeGenerator::TryBlockBuilder<BytecodeGenerator::SimpleTryFinallyBuilder>::
756 TryBlockBuilder(SimpleTryFinallyBuilder& builder)
757 : builder_(&builder),
758 scope_(builder_->generator_, builder_, &builder_->commands_) {
759 builder_->BeginTry(&scope_);
760 }
761
762 template <>
763 BytecodeGenerator::TryBlockBuilder<
764 BytecodeGenerator::SimpleTryFinallyBuilder>::~TryBlockBuilder() {
765 builder_->EndTry();
766 }
767
768 class BytecodeGenerator::CatchBlockBuilder {
769 public:
770 explicit CatchBlockBuilder(SimpleTryCatchBuilder& builder)
771 : builder_(&builder) {
772 builder_->BeginCatch();
773 }
774
775 ~CatchBlockBuilder() { builder_->EndCatch(); }
776
777 private:
778 SimpleTryCatchBuilder* builder_;
779 };
780
781 class BytecodeGenerator::FinallyBlockBuilder {
782 public:
783 explicit FinallyBlockBuilder(SimpleTryFinallyBuilder& builder)
784 : builder_(&builder) {
785 builder_->BeginFinally();
786 }
787
788 ~FinallyBlockBuilder() { builder_->EndFinally(); }
789
790 private:
791 SimpleTryFinallyBuilder* builder_;
792 };
793
583 BytecodeGenerator::BytecodeGenerator(CompilationInfo* info) 794 BytecodeGenerator::BytecodeGenerator(CompilationInfo* info)
584 : zone_(info->zone()), 795 : zone_(info->zone()),
585 builder_(new (zone()) BytecodeArrayBuilder( 796 builder_(new (zone()) BytecodeArrayBuilder(
586 info->isolate(), info->zone(), info->num_parameters_including_this(), 797 info->isolate(), info->zone(), info->num_parameters_including_this(),
587 info->scope()->MaxNestedContextChainLength(), 798 info->scope()->MaxNestedContextChainLength(),
588 info->scope()->num_stack_slots(), info->literal(), 799 info->scope()->num_stack_slots(), info->literal(),
589 info->SourcePositionRecordingMode())), 800 info->SourcePositionRecordingMode())),
590 info_(info), 801 info_(info),
591 scope_(info->scope()), 802 scope_(info->scope()),
592 globals_builder_(new (zone()) GlobalDeclarationsBuilder(info->zone())), 803 globals_builder_(new (zone()) GlobalDeclarationsBuilder(info->zone())),
593 global_declarations_(0, info->zone()), 804 global_declarations_(0, info->zone()),
594 function_literals_(0, info->zone()), 805 function_literals_(0, info->zone()),
595 native_function_literals_(0, info->zone()), 806 native_function_literals_(0, info->zone()),
596 object_literals_(0, info->zone()), 807 object_literals_(0, info->zone()),
597 array_literals_(0, info->zone()), 808 array_literals_(0, info->zone()),
598 execution_control_(nullptr), 809 execution_control_(nullptr),
599 execution_context_(nullptr), 810 execution_context_(nullptr),
600 execution_result_(nullptr), 811 execution_result_(nullptr),
601 generator_resume_points_(info->literal()->yield_count(), info->zone()), 812 generator_resume_points_(info->literal()->yield_count(), info->zone()),
602 generator_state_(), 813 generator_state_(),
603 loop_depth_(0), 814 loop_depth_(0),
815 catch_prediction_(HandlerTable::UNCAUGHT),
604 home_object_symbol_(info->isolate()->factory()->home_object_symbol()), 816 home_object_symbol_(info->isolate()->factory()->home_object_symbol()),
605 iterator_symbol_(info->isolate()->factory()->iterator_symbol()), 817 iterator_symbol_(info->isolate()->factory()->iterator_symbol()),
606 prototype_string_(info->isolate()->factory()->prototype_string()), 818 prototype_string_(info->isolate()->factory()->prototype_string()),
607 empty_fixed_array_(info->isolate()->factory()->empty_fixed_array()), 819 empty_fixed_array_(info->isolate()->factory()->empty_fixed_array()),
608 undefined_string_( 820 undefined_string_(
609 info->isolate()->ast_string_constants()->undefined_string()) {} 821 info->isolate()->ast_string_constants()->undefined_string()) {}
610 822
611 Handle<BytecodeArray> BytecodeGenerator::FinalizeBytecode(Isolate* isolate) { 823 Handle<BytecodeArray> BytecodeGenerator::FinalizeBytecode(Isolate* isolate) {
612 AllocateDeferredConstants(isolate); 824 AllocateDeferredConstants(isolate);
613 if (HasStackOverflow()) return Handle<BytecodeArray>(); 825 if (HasStackOverflow()) return Handle<BytecodeArray>();
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
689 if (scope()->NeedsContext()) { 901 if (scope()->NeedsContext()) {
690 // Push a new inner context scope for the function. 902 // Push a new inner context scope for the function.
691 BuildNewLocalActivationContext(); 903 BuildNewLocalActivationContext();
692 ContextScope local_function_context(this, scope(), false); 904 ContextScope local_function_context(this, scope(), false);
693 BuildLocalActivationContextInitialization(); 905 BuildLocalActivationContextInitialization();
694 GenerateBytecodeBody(); 906 GenerateBytecodeBody();
695 } else { 907 } else {
696 GenerateBytecodeBody(); 908 GenerateBytecodeBody();
697 } 909 }
698 910
699 // In generator functions, we may not have visited every yield in the AST
700 // since we skip some obviously dead code. Hence the generated bytecode may
701 // contain jumps to unbound labels (resume points that will never be used).
702 // We bind these now.
703 for (auto& label : generator_resume_points_) {
704 if (!label.is_bound()) builder()->Bind(&label);
705 }
706
707 // Emit an implicit return instruction in case control flow can fall off the 911 // Emit an implicit return instruction in case control flow can fall off the
708 // end of the function without an explicit return being present on all paths. 912 // end of the function without an explicit return being present on all paths.
709 if (builder()->RequiresImplicitReturn()) { 913 if (builder()->RequiresImplicitReturn()) {
710 builder()->LoadUndefined(); 914 builder()->LoadUndefined();
711 BuildReturn(); 915 BuildReturn();
712 } 916 }
713 DCHECK(!builder()->RequiresImplicitReturn()); 917 DCHECK(!builder()->RequiresImplicitReturn());
714 } 918 }
715 919
716 void BytecodeGenerator::GenerateBytecodeBody() { 920 void BytecodeGenerator::GenerateBytecodeBody() {
(...skipping 12 matching lines...) Expand all
729 933
730 // Emit tracing call if requested to do so. 934 // Emit tracing call if requested to do so.
731 if (FLAG_trace) builder()->CallRuntime(Runtime::kTraceEnter); 935 if (FLAG_trace) builder()->CallRuntime(Runtime::kTraceEnter);
732 936
733 // Visit declarations within the function scope. 937 // Visit declarations within the function scope.
734 VisitDeclarations(scope()->declarations()); 938 VisitDeclarations(scope()->declarations());
735 939
736 // Emit initializing assignments for module namespace imports (if any). 940 // Emit initializing assignments for module namespace imports (if any).
737 VisitModuleNamespaceImports(); 941 VisitModuleNamespaceImports();
738 942
943 FunctionLiteral* literal = info()->literal();
944
739 // Perform a stack-check before the body. 945 // Perform a stack-check before the body.
740 builder()->StackCheck(info()->literal()->start_position()); 946 builder()->StackCheck(literal->start_position());
741 947
948 // Build assignment to variable <function name> if function is a named
949 // expression and the variable is used.
950 if (literal->is_named_expression()) {
951 Variable* function_var = scope()->function_var();
952 if (function_var != nullptr && !function_var->IsUnallocated()) {
953 builder()->LoadAccumulatorWithRegister(Register::function_closure());
954 BuildVariableAssignment(function_var, Token::INIT,
955 FeedbackVectorSlot::Invalid(),
956 HoleCheckMode::kElided);
957 }
958 }
959
960 if (IsAsyncFunction(literal->kind())) {
961 return GenerateBytecodeBodyForAsyncFunction(literal);
962 }
963 if (IsGeneratorFunction(literal->kind())) {
964 return GenerateBytecodeBodyForGenerator(literal);
965 }
966 if (IsModule(literal->kind())) {
967 return GenerateBytecodeBodyForModule(literal);
968 }
969
970 Block* parameter_init_block = literal->parameter_init_block();
742 // Visit statements in the function body. 971 // Visit statements in the function body.
743 VisitStatements(info()->literal()->body()); 972 if (parameter_init_block != nullptr) {
973 VisitBlock(parameter_init_block);
974 }
975 VisitStatements(literal->body());
976 }
977
978 void BytecodeGenerator::BuildAllocateAndStoreJSGeneratorObject(
979 FunctionLiteral* literal, BuildJSGeneratorObject tag) {
980 RegisterAllocationScope register_scope(this);
981 RegisterList args = register_allocator()->NewRegisterList(2);
982 builder()->MoveRegister(Register::function_closure(), args[0]);
983
984 int yield_position = literal->position();
985 builder()->SetExpressionPosition(yield_position);
986
987 if (IsArrowFunction(literal->kind())) {
988 // Lexical `this`
989 builder()->LoadUndefined().StoreAccumulatorInRegister(args[1]);
990 } else {
991 // Receiver parameter
992 builder()->MoveRegister(builder()->Parameter(0), args[1]);
993 }
994 builder()->CallRuntime(Runtime::kCreateJSGeneratorObject, args);
995
996 Variable* var_generator = scope()->generator_object_var();
997 DCHECK_NOT_NULL(var_generator);
998
999 switch (tag) {
1000 case BuildJSGeneratorObject::kInitialYield: {
1001 Register generator = args[0];
1002 builder()->StoreAccumulatorInRegister(generator);
1003 BuildVariableAssignment(var_generator, Token::INIT,
1004 FeedbackVectorSlot::Invalid(),
1005 HoleCheckMode::kElided);
1006 BuildYield(0, generator, generator);
1007 BuildYieldResumePoint(0, Yield::kOnExceptionThrow, generator,
1008 yield_position);
1009 break;
1010 }
1011 case BuildJSGeneratorObject::kNoInitialYield: {
1012 BuildVariableAssignment(var_generator, Token::INIT,
1013 FeedbackVectorSlot::Invalid(),
1014 HoleCheckMode::kElided);
1015 break;
1016 }
1017 }
1018 }
1019
1020 void BytecodeGenerator::BuildAllocateAndStoreJSPromise() {
1021 Variable* var_promise = scope()->promise_var();
1022 DCHECK_NOT_NULL(var_promise);
1023
1024 RegisterAllocationScope register_scope(this);
1025 RegisterList args = register_allocator()->NewRegisterList(1);
1026 builder()->LoadUndefined().StoreAccumulatorInRegister(args[0]).CallJSRuntime(
1027 Context::ASYNC_FUNCTION_PROMISE_CREATE_INDEX, args);
1028 BuildVariableAssignment(var_promise, Token::INIT,
1029 FeedbackVectorSlot::Invalid(),
1030 HoleCheckMode::kElided);
1031 }
1032
1033 void BytecodeGenerator::BindUnboundGeneratorResumePoints() {
1034 DCHECK(IsResumableFunction(info()->literal()->kind()));
1035 for (auto& label : generator_resume_points_) {
1036 if (!label.is_bound()) builder()->Bind(&label);
1037 }
1038 }
1039
1040 void BytecodeGenerator::GenerateBytecodeBodyForGenerator(
1041 FunctionLiteral* literal) {
1042 DCHECK(IsGeneratorFunction(literal->kind()));
1043
1044 // Desugar parameters before generator is allocated.
1045 Block* const parameter_init_block = literal->parameter_init_block();
1046 if (parameter_init_block != nullptr) {
1047 // Initialize non-simple parameters before initial yield.
1048 VisitBlock(parameter_init_block);
1049 }
1050
1051 {
1052 RegisterAllocationScope register_scope(this);
1053 SimpleTryFinallyBuilder try_control_builder(this);
1054 { // Try ...
1055 TryBlockBuilderForFinally try_builder(try_control_builder);
1056 BuildAllocateAndStoreJSGeneratorObject(
1057 literal, BuildJSGeneratorObject::kInitialYield);
1058 VisitStatements(literal->body());
1059 }
1060
1061 { // Finally ...
1062 FinallyBlockBuilder finally_builder(try_control_builder);
1063 Variable* var_generator = scope()->generator_object_var();
1064 DCHECK_NOT_NULL(var_generator);
1065
1066 RegisterAllocationScope register_scope(this);
1067 BuildVariableLoad(var_generator, FeedbackVectorSlot::Invalid(),
1068 HoleCheckMode::kElided);
1069 Register generator = register_allocator()->NewRegister();
1070 builder()->StoreAccumulatorInRegister(generator).CallRuntime(
1071 Runtime::kInlineGeneratorClose, generator);
1072 }
1073 }
1074
1075 // In generator functions, we may not have visited every yield in the AST
1076 // since we skip some obviously dead code. Hence the generated bytecode may
1077 // contain jumps to unbound labels (resume points that will never be used).
1078 // We bind these now.
1079 BindUnboundGeneratorResumePoints();
1080
1081 if (builder()->RequiresImplicitReturn()) {
1082 // Unreachable, but required for BytecodeArrayBuilder
1083 builder()->LoadUndefined().Return();
1084 }
1085 DCHECK(!builder()->RequiresImplicitReturn());
1086 }
1087
1088 void BytecodeGenerator::GenerateBytecodeBodyForModule(
1089 FunctionLiteral* literal) {
1090 DCHECK(IsModule(literal->kind()));
1091
1092 // Modules do not have non-simple parameters
1093 DCHECK_NULL(literal->parameter_init_block());
1094
1095 BuildAllocateAndStoreJSGeneratorObject(literal,
1096 BuildJSGeneratorObject::kInitialYield);
1097 VisitStatements(literal->body());
1098
1099 // In modules, we may not have visited every yield in the AST
1100 // since we skip some obviously dead code. Hence the generated bytecode may
1101 // contain jumps to unbound labels (resume points that will never be used).
1102 // We bind these now.
1103 BindUnboundGeneratorResumePoints();
1104 }
1105
1106 void BytecodeGenerator::GenerateBytecodeBodyForAsyncFunction(
1107 FunctionLiteral* literal) {
1108 DCHECK(IsAsyncFunction(literal->kind()));
1109
1110 BuildAllocateAndStoreJSPromise();
1111
1112 {
1113 RegisterAllocationScope register_scope(this);
1114 SimpleTryCatchBuilder try_control_builder(this, HandlerTable::ASYNC_AWAIT);
1115 {
1116 TryBlockBuilderForCatch try_block(try_control_builder);
1117
1118 Block* const parameter_init_block = literal->parameter_init_block();
1119 if (parameter_init_block != nullptr) {
1120 // Initialize non-simple parameters if necessary, reject Promise in
1121 // case of exception
1122 RegisterAllocationScope register_scope(this);
1123 VisitBlock(parameter_init_block);
1124 }
1125
1126 BuildAllocateAndStoreJSGeneratorObject(
1127 literal, BuildJSGeneratorObject::kNoInitialYield);
1128
1129 // Finish generating function body
1130 VisitStatements(literal->body());
1131 }
1132
1133 {
1134 CatchBlockBuilder catch_block(try_control_builder);
1135 RegisterList args = register_allocator()->NewRegisterList(4);
1136 Register promise = args[1];
1137 Register exception = args[2];
1138
1139 builder()
1140 ->StoreAccumulatorInRegister(exception)
1141 .LoadTheHole()
1142 .SetPendingMessage();
1143
1144 Variable* var_promise = scope()->promise_var();
1145 DCHECK_NOT_NULL(var_promise);
1146 BuildVariableLoad(var_promise, FeedbackVectorSlot::Invalid(),
1147 HoleCheckMode::kElided);
1148 builder()
1149 ->StoreAccumulatorInRegister(promise)
1150 .LoadUndefined()
1151 .StoreAccumulatorInRegister(args[0])
1152 .LoadFalse()
1153 .StoreAccumulatorInRegister(args[3])
1154 .CallJSRuntime(Context::PROMISE_INTERNAL_REJECT_INDEX, args)
1155 .LoadAccumulatorWithRegister(promise)
1156 .Return();
1157 }
1158 }
1159
1160 // In async functions, we may not have visited every yield in the AST
1161 // since we skip some obviously dead code. Hence the generated bytecode may
1162 // contain jumps to unbound labels (resume points that will never be used).
1163 // We bind these now.
1164 BindUnboundGeneratorResumePoints();
1165
1166 if (builder()->RequiresImplicitReturn()) {
1167 // Unreachable, but required for BytecodeArrayBuilder
1168 builder()->LoadUndefined().Return();
1169 }
1170 DCHECK(!builder()->RequiresImplicitReturn());
744 } 1171 }
745 1172
746 void BytecodeGenerator::BuildIndexedJump(Register index, size_t start_index, 1173 void BytecodeGenerator::BuildIndexedJump(Register index, size_t start_index,
747 size_t size, 1174 size_t size,
748 ZoneVector<BytecodeLabel>& targets) { 1175 ZoneVector<BytecodeLabel>& targets) {
749 // TODO(neis): Optimize this by using a proper jump table. 1176 // TODO(neis): Optimize this by using a proper jump table.
750 DCHECK_LE(start_index + size, targets.size()); 1177 DCHECK_LE(start_index + size, targets.size());
751 for (size_t i = start_index; i < start_index + size; i++) { 1178 for (size_t i = start_index; i < start_index + size; i++) {
752 builder() 1179 builder()
753 ->LoadLiteral(Smi::FromInt(static_cast<int>(i))) 1180 ->LoadLiteral(Smi::FromInt(static_cast<int>(i)))
(...skipping 574 matching lines...) Expand 10 before | Expand all | Expand 10 after
1328 VisitForAccumulatorValue(stmt->result_done()); 1755 VisitForAccumulatorValue(stmt->result_done());
1329 loop_builder.BreakIfTrue(); 1756 loop_builder.BreakIfTrue();
1330 1757
1331 VisitForEffect(stmt->assign_each()); 1758 VisitForEffect(stmt->assign_each());
1332 VisitIterationBody(stmt, &loop_builder); 1759 VisitIterationBody(stmt, &loop_builder);
1333 loop_builder.JumpToHeader(loop_depth_); 1760 loop_builder.JumpToHeader(loop_depth_);
1334 loop_builder.EndLoop(); 1761 loop_builder.EndLoop();
1335 } 1762 }
1336 1763
1337 void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { 1764 void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
1338 TryCatchBuilder try_control_builder(builder(), stmt->catch_prediction()); 1765 SimpleTryCatchBuilder try_control_builder(this, stmt->catch_prediction());
1339
1340 // Preserve the context in a dedicated register, so that it can be restored
1341 // when the handler is entered by the stack-unwinding machinery.
1342 // TODO(mstarzinger): Be smarter about register allocation.
1343 Register context = register_allocator()->NewRegister();
1344 builder()->MoveRegister(Register::current_context(), context);
1345
1346 // Evaluate the try-block inside a control scope. This simulates a handler
1347 // that is intercepting 'throw' control commands.
1348 try_control_builder.BeginTry(context);
1349 { 1766 {
1350 ControlScopeForTryCatch scope(this, &try_control_builder); 1767 TryBlockBuilderForCatch try_block(try_control_builder);
1351 Visit(stmt->try_block()); 1768 Visit(stmt->try_block());
1352 } 1769 }
1353 try_control_builder.EndTry();
1354 1770
1771 // Evaluate the catch-block.
1355 // Create a catch scope that binds the exception. 1772 // Create a catch scope that binds the exception.
1773 CatchBlockBuilder catch_block(try_control_builder);
1774 Register context = try_control_builder.context();
1356 BuildNewLocalCatchContext(stmt->variable(), stmt->scope()); 1775 BuildNewLocalCatchContext(stmt->variable(), stmt->scope());
1357 builder()->StoreAccumulatorInRegister(context); 1776 builder()->StoreAccumulatorInRegister(context);
1358 1777
1359 // If requested, clear message object as we enter the catch block. 1778 // If requested, clear message object as we enter the catch block.
1360 if (stmt->clear_pending_message()) { 1779 if (stmt->clear_pending_message()) {
1361 builder()->LoadTheHole().SetPendingMessage(); 1780 builder()->LoadTheHole().SetPendingMessage();
1362 } 1781 }
1363 1782
1364 // Load the catch context into the accumulator. 1783 // Load the catch context into the accumulator.
1365 builder()->LoadAccumulatorWithRegister(context); 1784 builder()->LoadAccumulatorWithRegister(context);
1366
1367 // Evaluate the catch-block.
1368 VisitInScope(stmt->catch_block(), stmt->scope()); 1785 VisitInScope(stmt->catch_block(), stmt->scope());
1369 try_control_builder.EndCatch();
1370 } 1786 }
1371 1787
1372 void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { 1788 void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
1373 TryFinallyBuilder try_control_builder(builder(), stmt->catch_prediction()); 1789 SimpleTryFinallyBuilder try_control_builder(this);
1374
1375 // We keep a record of all paths that enter the finally-block to be able to
1376 // dispatch to the correct continuation point after the statements in the
1377 // finally-block have been evaluated.
1378 //
1379 // The try-finally construct can enter the finally-block in three ways:
1380 // 1. By exiting the try-block normally, falling through at the end.
1381 // 2. By exiting the try-block with a function-local control flow transfer
1382 // (i.e. through break/continue/return statements).
1383 // 3. By exiting the try-block with a thrown exception.
1384 //
1385 // The result register semantics depend on how the block was entered:
1386 // - ReturnStatement: It represents the return value being returned.
1387 // - ThrowStatement: It represents the exception being thrown.
1388 // - BreakStatement/ContinueStatement: Undefined and not used.
1389 // - Falling through into finally-block: Undefined and not used.
1390 Register token = register_allocator()->NewRegister();
1391 Register result = register_allocator()->NewRegister();
1392 ControlScope::DeferredCommands commands(this, token, result);
1393
1394 // Preserve the context in a dedicated register, so that it can be restored
1395 // when the handler is entered by the stack-unwinding machinery.
1396 // TODO(mstarzinger): Be smarter about register allocation.
1397 Register context = register_allocator()->NewRegister();
1398 builder()->MoveRegister(Register::current_context(), context);
1399
1400 // Evaluate the try-block inside a control scope. This simulates a handler
1401 // that is intercepting all control commands.
1402 try_control_builder.BeginTry(context);
1403 { 1790 {
1404 ControlScopeForTryFinally scope(this, &try_control_builder, &commands); 1791 TryBlockBuilderForFinally try_block(try_control_builder);
1405 Visit(stmt->try_block()); 1792 Visit(stmt->try_block());
1406 } 1793 }
1407 try_control_builder.EndTry();
1408 1794
1409 // Record fall-through and exception cases. 1795 FinallyBlockBuilder finally_block(try_control_builder);
1410 commands.RecordFallThroughPath();
1411 try_control_builder.LeaveTry();
1412 try_control_builder.BeginHandler();
1413 commands.RecordHandlerReThrowPath();
1414
1415 // Pending message object is saved on entry.
1416 try_control_builder.BeginFinally();
1417 Register message = context; // Reuse register.
1418
1419 // Clear message object as we enter the finally block.
1420 builder()->LoadTheHole().SetPendingMessage().StoreAccumulatorInRegister(
1421 message);
1422
1423 // Evaluate the finally-block.
1424 Visit(stmt->finally_block()); 1796 Visit(stmt->finally_block());
1425 try_control_builder.EndFinally();
1426
1427 // Pending message object is restored on exit.
1428 builder()->LoadAccumulatorWithRegister(message).SetPendingMessage();
1429
1430 // Dynamic dispatch after the finally-block.
1431 commands.ApplyDeferredCommands();
1432 } 1797 }
1433 1798
1434 void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) { 1799 void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
1435 builder()->SetStatementPosition(stmt); 1800 builder()->SetStatementPosition(stmt);
1436 builder()->Debugger(); 1801 builder()->Debugger();
1437 } 1802 }
1438 1803
1439 void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { 1804 void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
1440 uint8_t flags = CreateClosureFlags::Encode(expr->pretenure(), 1805 uint8_t flags = CreateClosureFlags::Encode(expr->pretenure(),
1441 scope()->is_function_scope()); 1806 scope()->is_function_scope());
(...skipping 838 matching lines...) Expand 10 before | Expand all | Expand 10 after
2280 } 2645 }
2281 case KEYED_SUPER_PROPERTY: { 2646 case KEYED_SUPER_PROPERTY: {
2282 builder() 2647 builder()
2283 ->StoreAccumulatorInRegister(super_property_args[3]) 2648 ->StoreAccumulatorInRegister(super_property_args[3])
2284 .CallRuntime(StoreKeyedToSuperRuntimeId(), super_property_args); 2649 .CallRuntime(StoreKeyedToSuperRuntimeId(), super_property_args);
2285 break; 2650 break;
2286 } 2651 }
2287 } 2652 }
2288 } 2653 }
2289 2654
2290 void BytecodeGenerator::VisitYield(Yield* expr) { 2655 void BytecodeGenerator::BuildYield(int yield_id, Register generator,
2291 builder()->SetExpressionPosition(expr); 2656 Register value) {
2292 Register value = VisitForRegisterValue(expr->expression()); 2657 DCHECK_GE(yield_id, 0);
2293 2658 DCHECK_LT(yield_id, generator_resume_points_.size());
2294 Register generator = VisitForRegisterValue(expr->generator_object()); 2659 DCHECK(generator.is_valid());
2660 DCHECK(value.is_valid());
2295 2661
2296 // Save context, registers, and state. Then return. 2662 // Save context, registers, and state. Then return.
2297 builder() 2663 builder()
2298 ->LoadLiteral(Smi::FromInt(expr->yield_id())) 2664 ->LoadLiteral(Smi::FromInt(yield_id))
2299 .SuspendGenerator(generator) 2665 .SuspendGenerator(generator)
2300 .LoadAccumulatorWithRegister(value) 2666 .LoadAccumulatorWithRegister(value)
2301 .Return(); // Hard return (ignore any finally blocks). 2667 .Return(); // Hard return (ignore any finally blocks).
2668 }
2302 2669
2303 builder()->Bind(&(generator_resume_points_[expr->yield_id()])); 2670 void BytecodeGenerator::BuildYieldResumePoint(int yield_id,
2671 Yield::OnException on_exception,
2672 Register generator,
2673 int position) {
2674 DCHECK_GE(yield_id, 0);
2675 DCHECK_LT(yield_id, generator_resume_points_.size());
2676 DCHECK(generator.is_valid());
2677
2678 DCHECK(!generator_resume_points_[yield_id].is_bound());
2679 builder()->Bind(&(generator_resume_points_[yield_id]));
2304 // Upon resume, we continue here. 2680 // Upon resume, we continue here.
2305 2681
2306 { 2682 {
2307 RegisterAllocationScope register_scope(this); 2683 RegisterAllocationScope register_scope(this);
2308 2684
2309 // Update state to indicate that we have finished resuming. Loop headers 2685 // Update state to indicate that we have finished resuming. Loop headers
2310 // rely on this. 2686 // rely on this.
2311 builder() 2687 builder()
2312 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)) 2688 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting))
2313 .StoreAccumulatorInRegister(generator_state_); 2689 .StoreAccumulatorInRegister(generator_state_);
2314 2690
2315 Register input = register_allocator()->NewRegister(); 2691 Register input = register_allocator()->NewRegister();
2316 builder() 2692 builder()
2317 ->CallRuntime(Runtime::kInlineGeneratorGetInputOrDebugPos, generator) 2693 ->CallRuntime(Runtime::kInlineGeneratorGetInputOrDebugPos, generator)
2318 .StoreAccumulatorInRegister(input); 2694 .StoreAccumulatorInRegister(input);
2319 2695
2320 Register resume_mode = register_allocator()->NewRegister(); 2696 Register resume_mode = register_allocator()->NewRegister();
2321 builder() 2697 builder()
2322 ->CallRuntime(Runtime::kInlineGeneratorGetResumeMode, generator) 2698 ->CallRuntime(Runtime::kInlineGeneratorGetResumeMode, generator)
2323 .StoreAccumulatorInRegister(resume_mode); 2699 .StoreAccumulatorInRegister(resume_mode);
2324 2700
2325 // Now dispatch on resume mode. 2701 // Now dispatch on resume mode.
2326 2702
2327 BytecodeLabel resume_with_next; 2703 BytecodeLabel resume_with_next;
2328 BytecodeLabel resume_with_return; 2704 BytecodeLabel resume_with_return;
2329 BytecodeLabel resume_with_throw; 2705 BytecodeLabel resume_with_throw;
2330 2706
2707 // TODO(caitp): Don't generate `resume_with_return` block for non-generators
2331 builder() 2708 builder()
2332 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kNext)) 2709 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kNext))
2333 .CompareOperation(Token::EQ_STRICT, resume_mode) 2710 .CompareOperation(Token::EQ_STRICT, resume_mode)
2334 .JumpIfTrue(&resume_with_next) 2711 .JumpIfTrue(&resume_with_next)
2335 .LoadLiteral(Smi::FromInt(JSGeneratorObject::kThrow)) 2712 .LoadLiteral(Smi::FromInt(JSGeneratorObject::kThrow))
2336 .CompareOperation(Token::EQ_STRICT, resume_mode) 2713 .CompareOperation(Token::EQ_STRICT, resume_mode)
2337 .JumpIfTrue(&resume_with_throw) 2714 .JumpIfTrue(&resume_with_throw)
2338 .Jump(&resume_with_return); 2715 .Jump(&resume_with_return);
2339 2716
2340 builder()->Bind(&resume_with_return); 2717 builder()->Bind(&resume_with_return);
2341 { 2718 {
2342 RegisterList args = register_allocator()->NewRegisterList(2); 2719 RegisterList args = register_allocator()->NewRegisterList(2);
2343 builder() 2720 builder()
2344 ->MoveRegister(input, args[0]) 2721 ->MoveRegister(input, args[0])
2345 .LoadTrue() 2722 .LoadTrue()
2346 .StoreAccumulatorInRegister(args[1]) 2723 .StoreAccumulatorInRegister(args[1])
2347 .CallRuntime(Runtime::kInlineCreateIterResultObject, args); 2724 .CallRuntime(Runtime::kInlineCreateIterResultObject, args);
2348 execution_control()->ReturnAccumulator(); 2725 execution_control()->ReturnAccumulator();
2349 } 2726 }
2350 2727
2351 builder()->Bind(&resume_with_throw); 2728 builder()->Bind(&resume_with_throw);
2352 builder()->SetExpressionPosition(expr); 2729 builder()->SetExpressionPosition(position);
2353 builder()->LoadAccumulatorWithRegister(input); 2730 builder()->LoadAccumulatorWithRegister(input);
2354 if (expr->rethrow_on_exception()) { 2731 if (on_exception == Yield::kOnExceptionRethrow) {
2355 builder()->ReThrow(); 2732 builder()->ReThrow();
2356 } else { 2733 } else {
2357 builder()->Throw(); 2734 builder()->Throw();
2358 } 2735 }
2359 2736
2360 builder()->Bind(&resume_with_next); 2737 builder()->Bind(&resume_with_next);
2361 builder()->LoadAccumulatorWithRegister(input); 2738 builder()->LoadAccumulatorWithRegister(input);
2362 } 2739 }
2363 } 2740 }
2364 2741
2742 void BytecodeGenerator::VisitYield(Yield* expr) {
2743 Register generator = VisitForRegisterValue(expr->generator_object());
2744
2745 builder()->SetExpressionPosition(expr);
2746 Register value = VisitForRegisterValue(expr->expression());
2747
2748 BuildYield(expr->yield_id(), generator, value);
2749 BuildYieldResumePoint(expr->yield_id(), expr->on_exception(), generator,
2750 expr->position());
2751 }
2752
2365 void BytecodeGenerator::VisitThrow(Throw* expr) { 2753 void BytecodeGenerator::VisitThrow(Throw* expr) {
2366 VisitForAccumulatorValue(expr->exception()); 2754 VisitForAccumulatorValue(expr->exception());
2367 builder()->SetExpressionPosition(expr); 2755 builder()->SetExpressionPosition(expr);
2368 builder()->Throw(); 2756 builder()->Throw();
2369 } 2757 }
2370 2758
2371 void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) { 2759 void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) {
2372 LhsKind property_kind = Property::GetAssignType(expr); 2760 LhsKind property_kind = Property::GetAssignType(expr);
2373 FeedbackVectorSlot slot = expr->PropertyFeedbackSlot(); 2761 FeedbackVectorSlot slot = expr->PropertyFeedbackSlot();
2374 builder()->SetExpressionPosition(expr); 2762 builder()->SetExpressionPosition(expr);
(...skipping 1002 matching lines...) Expand 10 before | Expand all | Expand 10 after
3377 } 3765 }
3378 3766
3379 Runtime::FunctionId BytecodeGenerator::StoreKeyedToSuperRuntimeId() { 3767 Runtime::FunctionId BytecodeGenerator::StoreKeyedToSuperRuntimeId() {
3380 return is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict 3768 return is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict
3381 : Runtime::kStoreKeyedToSuper_Sloppy; 3769 : Runtime::kStoreKeyedToSuper_Sloppy;
3382 } 3770 }
3383 3771
3384 } // namespace interpreter 3772 } // namespace interpreter
3385 } // namespace internal 3773 } // namespace internal
3386 } // namespace v8 3774 } // namespace v8
OLDNEW
« no previous file with comments | « src/interpreter/bytecode-generator.h ('k') | src/interpreter/control-flow-builders.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698