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/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 583 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
594 function_literals_(0, info->zone()), | 594 function_literals_(0, info->zone()), |
595 native_function_literals_(0, info->zone()), | 595 native_function_literals_(0, info->zone()), |
596 object_literals_(0, info->zone()), | 596 object_literals_(0, info->zone()), |
597 array_literals_(0, info->zone()), | 597 array_literals_(0, info->zone()), |
598 execution_control_(nullptr), | 598 execution_control_(nullptr), |
599 execution_context_(nullptr), | 599 execution_context_(nullptr), |
600 execution_result_(nullptr), | 600 execution_result_(nullptr), |
601 generator_resume_points_(info->literal()->yield_count(), info->zone()), | 601 generator_resume_points_(info->literal()->yield_count(), info->zone()), |
602 generator_state_(), | 602 generator_state_(), |
603 loop_depth_(0), | 603 loop_depth_(0), |
604 catch_prediction_(HandlerTable::UNCAUGHT), | |
604 home_object_symbol_(info->isolate()->factory()->home_object_symbol()), | 605 home_object_symbol_(info->isolate()->factory()->home_object_symbol()), |
605 iterator_symbol_(info->isolate()->factory()->iterator_symbol()), | 606 iterator_symbol_(info->isolate()->factory()->iterator_symbol()), |
606 prototype_string_(info->isolate()->factory()->prototype_string()), | 607 prototype_string_(info->isolate()->factory()->prototype_string()), |
607 empty_fixed_array_(info->isolate()->factory()->empty_fixed_array()), | 608 empty_fixed_array_(info->isolate()->factory()->empty_fixed_array()), |
608 undefined_string_( | 609 undefined_string_( |
609 info->isolate()->ast_string_constants()->undefined_string()) {} | 610 info->isolate()->ast_string_constants()->undefined_string()) {} |
610 | 611 |
611 Handle<BytecodeArray> BytecodeGenerator::FinalizeBytecode(Isolate* isolate) { | 612 Handle<BytecodeArray> BytecodeGenerator::FinalizeBytecode(Isolate* isolate) { |
612 AllocateDeferredConstants(isolate); | 613 AllocateDeferredConstants(isolate); |
613 if (HasStackOverflow()) return Handle<BytecodeArray>(); | 614 if (HasStackOverflow()) return Handle<BytecodeArray>(); |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
689 if (scope()->NeedsContext()) { | 690 if (scope()->NeedsContext()) { |
690 // Push a new inner context scope for the function. | 691 // Push a new inner context scope for the function. |
691 BuildNewLocalActivationContext(); | 692 BuildNewLocalActivationContext(); |
692 ContextScope local_function_context(this, scope(), false); | 693 ContextScope local_function_context(this, scope(), false); |
693 BuildLocalActivationContextInitialization(); | 694 BuildLocalActivationContextInitialization(); |
694 GenerateBytecodeBody(); | 695 GenerateBytecodeBody(); |
695 } else { | 696 } else { |
696 GenerateBytecodeBody(); | 697 GenerateBytecodeBody(); |
697 } | 698 } |
698 | 699 |
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 | 700 // 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. | 701 // end of the function without an explicit return being present on all paths. |
709 if (builder()->RequiresImplicitReturn()) { | 702 if (builder()->RequiresImplicitReturn()) { |
710 builder()->LoadUndefined(); | 703 builder()->LoadUndefined(); |
711 BuildReturn(); | 704 BuildReturn(); |
712 } | 705 } |
713 DCHECK(!builder()->RequiresImplicitReturn()); | 706 DCHECK(!builder()->RequiresImplicitReturn()); |
714 } | 707 } |
715 | 708 |
716 void BytecodeGenerator::GenerateBytecodeBody() { | 709 void BytecodeGenerator::GenerateBytecodeBody() { |
(...skipping 15 matching lines...) Expand all Loading... | |
732 | 725 |
733 // Visit declarations within the function scope. | 726 // Visit declarations within the function scope. |
734 VisitDeclarations(scope()->declarations()); | 727 VisitDeclarations(scope()->declarations()); |
735 | 728 |
736 // Emit initializing assignments for module namespace imports (if any). | 729 // Emit initializing assignments for module namespace imports (if any). |
737 VisitModuleNamespaceImports(); | 730 VisitModuleNamespaceImports(); |
738 | 731 |
739 // Perform a stack-check before the body. | 732 // Perform a stack-check before the body. |
740 builder()->StackCheck(info()->literal()->start_position()); | 733 builder()->StackCheck(info()->literal()->start_position()); |
741 | 734 |
735 // Build assignment to variable <function name> if function is a named | |
736 // expression and the variable is used. | |
737 if (info()->literal()->is_named_expression()) { | |
738 Variable* function_var = scope()->function_var(); | |
739 if (function_var != nullptr && !function_var->IsUnallocated()) { | |
740 builder()->LoadAccumulatorWithRegister(Register::function_closure()); | |
741 BuildVariableAssignment(function_var, Token::INIT, | |
742 FeedbackVectorSlot::Invalid(), | |
743 HoleCheckMode::kElided); | |
744 } | |
745 } | |
rmcilroy
2017/02/06 22:27:50
This change doesn't seem related to the generator
caitp
2017/02/06 22:48:23
well, I would love to do it in a separate CL, but
rmcilroy
2017/02/07 17:24:41
OK I can live with this change in this CL, thanks
caitp
2017/02/07 18:13:08
Actually, I brought this up in the meeting today,
| |
746 | |
747 if (IsAsyncFunction(info()->literal()->kind())) { | |
748 return GenerateBytecodeBodyForAsyncFunction(); | |
749 } | |
750 if (IsGeneratorFunction(info()->literal()->kind())) { | |
751 return GenerateBytecodeBodyForGenerator(); | |
752 } | |
753 if (IsModule(info()->literal()->kind())) { | |
754 return GenerateBytecodeBodyForModule(); | |
755 } | |
rmcilroy
2017/02/06 22:27:50
Thanks for splitting the logic out of GenerateByte
caitp
2017/02/06 22:48:23
I'm not entirely sure how this would work due to h
rmcilroy
2017/02/07 17:24:41
Yeah your right regarding RAII ControlScopes. I'd
| |
756 | |
757 Block* parameter_init_block = info()->literal()->parameter_init_block(); | |
742 // Visit statements in the function body. | 758 // Visit statements in the function body. |
759 if (parameter_init_block != nullptr) { | |
760 VisitBlock(parameter_init_block); | |
761 } | |
rmcilroy
2017/02/06 22:27:50
Any reason for this change? Could we just do this
caitp
2017/02/06 22:48:24
Async functions need to incorporate the parameter
rmcilroy
2017/02/07 17:24:41
I see. Is it necessary that the parameter initiali
| |
743 VisitStatements(info()->literal()->body()); | 762 VisitStatements(info()->literal()->body()); |
744 } | 763 } |
745 | 764 |
765 void BytecodeGenerator::BuildAllocateAndStoreJSGeneratorObject( | |
766 BuildJSGeneratorObject tag) { | |
767 RegisterAllocationScope register_scope(this); | |
768 RegisterList args = register_allocator()->NewRegisterList(2); | |
769 builder()->MoveRegister(Register::function_closure(), args[0]); | |
770 | |
771 int yield_position = info()->literal()->position(); | |
rmcilroy
2017/02/06 22:27:50
Could you pass through literal as an argument rath
caitp
2017/02/06 22:48:23
For the cases that would use this, aren't they alw
caitp
2017/02/06 23:29:36
nvm, thought this was specifically about yield_pos
rmcilroy
2017/02/07 17:24:41
Yeah I was meaning for all the uses in the new fun
| |
772 builder()->SetExpressionPosition(yield_position); | |
773 | |
774 if (IsArrowFunction(info()->literal()->kind())) { | |
775 // Lexical `this` | |
776 builder()->LoadUndefined().StoreAccumulatorInRegister(args[1]); | |
777 } else { | |
778 // Receiver parameter | |
779 builder()->MoveRegister(builder()->Parameter(0), args[1]); | |
780 } | |
781 builder()->CallRuntime(Runtime::kCreateJSGeneratorObject, args); | |
782 | |
783 Variable* var_generator = scope()->generator_object_var(); | |
784 DCHECK_NOT_NULL(var_generator); | |
785 | |
786 switch (tag) { | |
787 case BuildJSGeneratorObject::kInitialYield: { | |
788 Register generator = args[0]; | |
789 builder()->StoreAccumulatorInRegister(generator); | |
790 BuildVariableAssignment(var_generator, Token::INIT, | |
791 FeedbackVectorSlot::Invalid(), | |
792 HoleCheckMode::kElided); | |
793 BuildYield(0, generator, generator); | |
794 BuildYieldResumePoint(0, Yield::kOnExceptionThrow, generator, | |
795 yield_position); | |
796 break; | |
797 } | |
798 case BuildJSGeneratorObject::kNoInitialYield: { | |
799 BuildVariableAssignment(var_generator, Token::INIT, | |
800 FeedbackVectorSlot::Invalid(), | |
801 HoleCheckMode::kElided); | |
802 break; | |
803 } | |
804 } | |
805 } | |
806 | |
807 void BytecodeGenerator::BuildAllocateAndStoreJSPromise() { | |
808 Variable* var_promise = scope()->promise_var(); | |
809 DCHECK_NOT_NULL(var_promise); | |
810 | |
811 RegisterAllocationScope register_scope(this); | |
812 RegisterList args = register_allocator()->NewRegisterList(1); | |
813 builder()->LoadUndefined().StoreAccumulatorInRegister(args[0]).CallJSRuntime( | |
814 Context::ASYNC_FUNCTION_PROMISE_CREATE_INDEX, args); | |
815 BuildVariableAssignment(var_promise, Token::INIT, | |
816 FeedbackVectorSlot::Invalid(), | |
817 HoleCheckMode::kElided); | |
818 } | |
819 | |
820 void BytecodeGenerator::BindUnboundGeneratorResumePoints() { | |
821 DCHECK(IsResumableFunction(info()->literal()->kind())); | |
822 for (auto& label : generator_resume_points_) { | |
823 if (!label.is_bound()) builder()->Bind(&label); | |
824 } | |
825 } | |
826 | |
827 void BytecodeGenerator::GenerateBytecodeBodyForGenerator() { | |
828 DCHECK(IsGeneratorFunction(info()->literal()->kind())); | |
829 | |
830 // Desugar parameters before generator is allocated. | |
831 Block* const parameter_init_block = info()->literal()->parameter_init_block(); | |
832 if (parameter_init_block != nullptr) { | |
833 // Initialize non-simple parameters before initial yield. | |
834 VisitBlock(parameter_init_block); | |
835 } | |
836 | |
837 BuildTryFinally( | |
838 [=]() { // Try ... | |
839 BuildAllocateAndStoreJSGeneratorObject( | |
840 BuildJSGeneratorObject::kInitialYield); | |
841 VisitStatements(info()->literal()->body()); | |
842 }, | |
843 [=]() { // Finally ... | |
844 Variable* var_generator = scope()->generator_object_var(); | |
845 DCHECK_NOT_NULL(var_generator); | |
846 | |
847 BuildVariableLoad(var_generator, FeedbackVectorSlot::Invalid(), | |
848 HoleCheckMode::kElided); | |
849 RegisterAllocationScope register_scope(this); | |
850 Register generator = register_allocator()->NewRegister(); | |
851 builder()->StoreAccumulatorInRegister(generator).CallRuntime( | |
852 Runtime::kInlineGeneratorClose, generator); | |
853 }); | |
854 | |
855 // In generator functions, we may not have visited every yield in the AST | |
856 // since we skip some obviously dead code. Hence the generated bytecode may | |
857 // contain jumps to unbound labels (resume points that will never be used). | |
858 // We bind these now. | |
859 BindUnboundGeneratorResumePoints(); | |
860 | |
861 if (builder()->RequiresImplicitReturn()) { | |
rmcilroy
2017/02/06 22:27:50
From here to the end shouldn't be necessary (it's
caitp
2017/02/06 22:48:24
The one in GenerateBytecode uses BuildReturn(), wh
rmcilroy
2017/02/07 17:24:41
Let's make that change in the followup CL which ch
| |
862 // Unreachable, but required for BytecodeArrayBuilder | |
863 builder()->LoadUndefined().Return(); | |
864 } | |
865 DCHECK(!builder()->RequiresImplicitReturn()); | |
866 } | |
867 | |
868 void BytecodeGenerator::GenerateBytecodeBodyForModule() { | |
869 DCHECK(IsModule(info()->literal()->kind())); | |
870 | |
871 // Modules do not have non-simple parameters | |
872 DCHECK_NULL(info()->literal()->parameter_init_block()); | |
873 | |
874 BuildAllocateAndStoreJSGeneratorObject(BuildJSGeneratorObject::kInitialYield); | |
875 VisitStatements(info()->literal()->body()); | |
876 | |
877 // In modules, we may not have visited every yield in the AST | |
878 // since we skip some obviously dead code. Hence the generated bytecode may | |
879 // contain jumps to unbound labels (resume points that will never be used). | |
880 // We bind these now. | |
881 BindUnboundGeneratorResumePoints(); | |
882 } | |
883 | |
884 void BytecodeGenerator::GenerateBytecodeBodyForAsyncFunction() { | |
885 DCHECK(IsAsyncFunction(info()->literal()->kind())); | |
886 | |
887 BuildAllocateAndStoreJSPromise(); | |
888 | |
889 BuildTryCatch( | |
890 HandlerTable::ASYNC_AWAIT, | |
891 [=]() { | |
rmcilroy
2017/02/06 22:27:49
I don't like these lambdas, and the function point
caitp
2017/02/06 22:48:24
I'll give that a try.
| |
892 // Try ... | |
893 Block* const parameter_init_block = | |
894 info()->literal()->parameter_init_block(); | |
895 if (parameter_init_block != nullptr) { | |
896 // Initialize non-simple parameters if necessary, reject Promise in | |
897 // case of exception | |
898 VisitBlock(parameter_init_block); | |
899 } | |
900 | |
901 BuildAllocateAndStoreJSGeneratorObject( | |
902 BuildJSGeneratorObject::kNoInitialYield); | |
903 | |
904 // Finish generating function body | |
905 VisitStatements(info()->literal()->body()); | |
906 }, | |
907 [=](Register) { | |
908 // Catch ... | |
909 // Caught exception is used to reject Promise without emitting a debug | |
910 // event. | |
911 RegisterAllocationScope register_scope(this); | |
912 RegisterList args = register_allocator()->NewRegisterList(4); | |
913 Register promise = args[1]; | |
914 Register exception = args[2]; | |
915 | |
916 builder() | |
917 ->StoreAccumulatorInRegister(exception) | |
918 .LoadTheHole() | |
919 .SetPendingMessage(); | |
920 | |
921 Variable* var_promise = scope()->promise_var(); | |
922 DCHECK_NOT_NULL(var_promise); | |
923 BuildVariableLoad(var_promise, FeedbackVectorSlot::Invalid(), | |
924 HoleCheckMode::kElided); | |
925 builder() | |
926 ->StoreAccumulatorInRegister(promise) | |
927 .LoadUndefined() | |
928 .StoreAccumulatorInRegister(args[0]) | |
929 .LoadFalse() | |
930 .StoreAccumulatorInRegister(args[3]) | |
931 .CallJSRuntime(Context::PROMISE_INTERNAL_REJECT_INDEX, args) | |
932 .LoadAccumulatorWithRegister(promise) | |
933 .Return(); | |
934 }); | |
935 | |
936 // In async functions, we may not have visited every yield in the AST | |
937 // since we skip some obviously dead code. Hence the generated bytecode may | |
938 // contain jumps to unbound labels (resume points that will never be used). | |
939 // We bind these now. | |
940 BindUnboundGeneratorResumePoints(); | |
941 | |
942 if (builder()->RequiresImplicitReturn()) { | |
rmcilroy
2017/02/06 22:27:50
Ditto
| |
943 // Unreachable, but required for BytecodeArrayBuilder | |
944 builder()->LoadUndefined().Return(); | |
945 } | |
946 DCHECK(!builder()->RequiresImplicitReturn()); | |
947 } | |
948 | |
746 void BytecodeGenerator::BuildIndexedJump(Register index, size_t start_index, | 949 void BytecodeGenerator::BuildIndexedJump(Register index, size_t start_index, |
747 size_t size, | 950 size_t size, |
748 ZoneVector<BytecodeLabel>& targets) { | 951 ZoneVector<BytecodeLabel>& targets) { |
749 // TODO(neis): Optimize this by using a proper jump table. | 952 // TODO(neis): Optimize this by using a proper jump table. |
750 DCHECK_LE(start_index + size, targets.size()); | 953 DCHECK_LE(start_index + size, targets.size()); |
751 for (size_t i = start_index; i < start_index + size; i++) { | 954 for (size_t i = start_index; i < start_index + size; i++) { |
752 builder() | 955 builder() |
753 ->LoadLiteral(Smi::FromInt(static_cast<int>(i))) | 956 ->LoadLiteral(Smi::FromInt(static_cast<int>(i))) |
754 .CompareOperation(Token::Value::EQ_STRICT, index) | 957 .CompareOperation(Token::Value::EQ_STRICT, index) |
755 .JumpIfTrue(&(targets[i])); | 958 .JumpIfTrue(&(targets[i])); |
(...skipping 571 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1327 VisitForEffect(stmt->next_result()); | 1530 VisitForEffect(stmt->next_result()); |
1328 VisitForAccumulatorValue(stmt->result_done()); | 1531 VisitForAccumulatorValue(stmt->result_done()); |
1329 loop_builder.BreakIfTrue(); | 1532 loop_builder.BreakIfTrue(); |
1330 | 1533 |
1331 VisitForEffect(stmt->assign_each()); | 1534 VisitForEffect(stmt->assign_each()); |
1332 VisitIterationBody(stmt, &loop_builder); | 1535 VisitIterationBody(stmt, &loop_builder); |
1333 loop_builder.JumpToHeader(loop_depth_); | 1536 loop_builder.JumpToHeader(loop_depth_); |
1334 loop_builder.EndLoop(); | 1537 loop_builder.EndLoop(); |
1335 } | 1538 } |
1336 | 1539 |
1337 void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { | 1540 void BytecodeGenerator::BuildTryCatch( |
1338 TryCatchBuilder try_control_builder(builder(), stmt->catch_prediction()); | 1541 HandlerTable::CatchPrediction catch_prediction, |
1542 std::function<void()> build_try, | |
1543 std::function<void(Register)> build_catch) { | |
1544 TryCatchBuilder try_control_builder(builder(), catch_prediction); | |
1339 | 1545 |
1340 // Preserve the context in a dedicated register, so that it can be restored | 1546 // Preserve the context in a dedicated register, so that it can be restored |
1341 // when the handler is entered by the stack-unwinding machinery. | 1547 // when the handler is entered by the stack-unwinding machinery. |
1342 // TODO(mstarzinger): Be smarter about register allocation. | 1548 // TODO(mstarzinger): Be smarter about register allocation. |
1343 Register context = register_allocator()->NewRegister(); | 1549 Register context = register_allocator()->NewRegister(); |
1344 builder()->MoveRegister(Register::current_context(), context); | 1550 builder()->MoveRegister(Register::current_context(), context); |
1345 | 1551 |
1346 // Evaluate the try-block inside a control scope. This simulates a handler | 1552 // Evaluate the try-block inside a control scope. This simulates a handler |
1347 // that is intercepting 'throw' control commands. | 1553 // that is intercepting 'throw' control commands. |
1348 try_control_builder.BeginTry(context); | 1554 try_control_builder.BeginTry(context); |
1349 { | 1555 { |
1350 ControlScopeForTryCatch scope(this, &try_control_builder); | 1556 ControlScopeForTryCatch scope(this, &try_control_builder); |
1351 Visit(stmt->try_block()); | 1557 HandlerTable::CatchPrediction last_catch_prediction = catch_prediction_; |
1558 if (catch_prediction != HandlerTable::UNCAUGHT) { | |
1559 catch_prediction_ = catch_prediction; | |
1560 } | |
1561 build_try(); | |
1562 catch_prediction_ = last_catch_prediction; | |
1352 } | 1563 } |
1353 try_control_builder.EndTry(); | 1564 try_control_builder.EndTry(); |
1354 | 1565 |
1355 // Create a catch scope that binds the exception. | |
1356 BuildNewLocalCatchContext(stmt->variable(), stmt->scope()); | |
1357 builder()->StoreAccumulatorInRegister(context); | |
1358 | |
1359 // If requested, clear message object as we enter the catch block. | |
1360 if (stmt->clear_pending_message()) { | |
1361 builder()->LoadTheHole().SetPendingMessage(); | |
1362 } | |
1363 | |
1364 // Load the catch context into the accumulator. | |
1365 builder()->LoadAccumulatorWithRegister(context); | |
1366 | |
1367 // Evaluate the catch-block. | 1566 // Evaluate the catch-block. |
1368 VisitInScope(stmt->catch_block(), stmt->scope()); | 1567 build_catch(context); |
1369 try_control_builder.EndCatch(); | 1568 try_control_builder.EndCatch(); |
1370 } | 1569 } |
1371 | 1570 |
1372 void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { | 1571 void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { |
1373 TryFinallyBuilder try_control_builder(builder(), stmt->catch_prediction()); | 1572 BuildTryCatch(stmt->catch_prediction(), [=]() { Visit(stmt->try_block()); }, |
1573 [=](Register context) { | |
1574 // Create a catch scope that binds the exception. | |
1575 BuildNewLocalCatchContext(stmt->variable(), stmt->scope()); | |
1576 builder()->StoreAccumulatorInRegister(context); | |
1577 | |
1578 // I requested, clear message object as we enter the catch | |
1579 // block. | |
1580 if (stmt->clear_pending_message()) { | |
1581 builder()->LoadTheHole().SetPendingMessage(); | |
1582 } | |
1583 | |
1584 // Load the catch context into the accumulator. | |
1585 builder()->LoadAccumulatorWithRegister(context); | |
1586 | |
1587 VisitInScope(stmt->catch_block(), stmt->scope()); | |
1588 }); | |
1589 } | |
1590 | |
1591 void BytecodeGenerator::BuildTryFinally(std::function<void()> build_try, | |
1592 std::function<void()> build_finally) { | |
1593 TryFinallyBuilder try_control_builder(builder(), catch_prediction_); | |
1374 | 1594 |
1375 // We keep a record of all paths that enter the finally-block to be able to | 1595 // 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 | 1596 // dispatch to the correct continuation point after the statements in the |
1377 // finally-block have been evaluated. | 1597 // finally-block have been evaluated. |
1378 // | 1598 // |
1379 // The try-finally construct can enter the finally-block in three ways: | 1599 // 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. | 1600 // 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 | 1601 // 2. By exiting the try-block with a function-local control flow transfer |
1382 // (i.e. through break/continue/return statements). | 1602 // (i.e. through break/continue/return statements). |
1383 // 3. By exiting the try-block with a thrown exception. | 1603 // 3. By exiting the try-block with a thrown exception. |
(...skipping 11 matching lines...) Expand all Loading... | |
1395 // when the handler is entered by the stack-unwinding machinery. | 1615 // when the handler is entered by the stack-unwinding machinery. |
1396 // TODO(mstarzinger): Be smarter about register allocation. | 1616 // TODO(mstarzinger): Be smarter about register allocation. |
1397 Register context = register_allocator()->NewRegister(); | 1617 Register context = register_allocator()->NewRegister(); |
1398 builder()->MoveRegister(Register::current_context(), context); | 1618 builder()->MoveRegister(Register::current_context(), context); |
1399 | 1619 |
1400 // Evaluate the try-block inside a control scope. This simulates a handler | 1620 // Evaluate the try-block inside a control scope. This simulates a handler |
1401 // that is intercepting all control commands. | 1621 // that is intercepting all control commands. |
1402 try_control_builder.BeginTry(context); | 1622 try_control_builder.BeginTry(context); |
1403 { | 1623 { |
1404 ControlScopeForTryFinally scope(this, &try_control_builder, &commands); | 1624 ControlScopeForTryFinally scope(this, &try_control_builder, &commands); |
1405 Visit(stmt->try_block()); | 1625 build_try(); |
1406 } | 1626 } |
1407 try_control_builder.EndTry(); | 1627 try_control_builder.EndTry(); |
1408 | 1628 |
1409 // Record fall-through and exception cases. | 1629 // Record fall-through and exception cases. |
1410 commands.RecordFallThroughPath(); | 1630 commands.RecordFallThroughPath(); |
1411 try_control_builder.LeaveTry(); | 1631 try_control_builder.LeaveTry(); |
1412 try_control_builder.BeginHandler(); | 1632 try_control_builder.BeginHandler(); |
1413 commands.RecordHandlerReThrowPath(); | 1633 commands.RecordHandlerReThrowPath(); |
1414 | 1634 |
1415 // Pending message object is saved on entry. | 1635 // Pending message object is saved on entry. |
1416 try_control_builder.BeginFinally(); | 1636 try_control_builder.BeginFinally(); |
1417 Register message = context; // Reuse register. | 1637 Register message = context; // Reuse register. |
1418 | 1638 |
1419 // Clear message object as we enter the finally block. | 1639 // Clear message object as we enter the finally block. |
1420 builder()->LoadTheHole().SetPendingMessage().StoreAccumulatorInRegister( | 1640 builder()->LoadTheHole().SetPendingMessage().StoreAccumulatorInRegister( |
1421 message); | 1641 message); |
1422 | 1642 |
1423 // Evaluate the finally-block. | 1643 // Evaluate the finally-block. |
1424 Visit(stmt->finally_block()); | 1644 build_finally(); |
1425 try_control_builder.EndFinally(); | 1645 try_control_builder.EndFinally(); |
1426 | 1646 |
1427 // Pending message object is restored on exit. | 1647 // Pending message object is restored on exit. |
1428 builder()->LoadAccumulatorWithRegister(message).SetPendingMessage(); | 1648 builder()->LoadAccumulatorWithRegister(message).SetPendingMessage(); |
1429 | 1649 |
1430 // Dynamic dispatch after the finally-block. | 1650 // Dynamic dispatch after the finally-block. |
1431 commands.ApplyDeferredCommands(); | 1651 commands.ApplyDeferredCommands(); |
1432 } | 1652 } |
1433 | 1653 |
1654 void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { | |
1655 BuildTryFinally([=]() { Visit(stmt->try_block()); }, | |
1656 [=]() { Visit(stmt->finally_block()); }); | |
1657 } | |
1658 | |
1434 void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) { | 1659 void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) { |
1435 builder()->SetStatementPosition(stmt); | 1660 builder()->SetStatementPosition(stmt); |
1436 builder()->Debugger(); | 1661 builder()->Debugger(); |
1437 } | 1662 } |
1438 | 1663 |
1439 void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { | 1664 void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { |
1440 uint8_t flags = CreateClosureFlags::Encode(expr->pretenure(), | 1665 uint8_t flags = CreateClosureFlags::Encode(expr->pretenure(), |
1441 scope()->is_function_scope()); | 1666 scope()->is_function_scope()); |
1442 size_t entry = builder()->AllocateConstantPoolEntry(); | 1667 size_t entry = builder()->AllocateConstantPoolEntry(); |
1443 int slot_index = feedback_index(expr->LiteralFeedbackSlot()); | 1668 int slot_index = feedback_index(expr->LiteralFeedbackSlot()); |
(...skipping 836 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2280 } | 2505 } |
2281 case KEYED_SUPER_PROPERTY: { | 2506 case KEYED_SUPER_PROPERTY: { |
2282 builder() | 2507 builder() |
2283 ->StoreAccumulatorInRegister(super_property_args[3]) | 2508 ->StoreAccumulatorInRegister(super_property_args[3]) |
2284 .CallRuntime(StoreKeyedToSuperRuntimeId(), super_property_args); | 2509 .CallRuntime(StoreKeyedToSuperRuntimeId(), super_property_args); |
2285 break; | 2510 break; |
2286 } | 2511 } |
2287 } | 2512 } |
2288 } | 2513 } |
2289 | 2514 |
2290 void BytecodeGenerator::VisitYield(Yield* expr) { | 2515 void BytecodeGenerator::BuildYield(int yield_id, Register generator, |
2291 builder()->SetExpressionPosition(expr); | 2516 Register value) { |
2292 Register value = VisitForRegisterValue(expr->expression()); | 2517 DCHECK_GE(yield_id, 0); |
2293 | 2518 DCHECK_LT(yield_id, generator_resume_points_.size()); |
2294 Register generator = VisitForRegisterValue(expr->generator_object()); | 2519 DCHECK(generator.is_valid()); |
2520 DCHECK(value.is_valid()); | |
2295 | 2521 |
2296 // Save context, registers, and state. Then return. | 2522 // Save context, registers, and state. Then return. |
2297 builder() | 2523 builder() |
2298 ->LoadLiteral(Smi::FromInt(expr->yield_id())) | 2524 ->LoadLiteral(Smi::FromInt(yield_id)) |
2299 .SuspendGenerator(generator) | 2525 .SuspendGenerator(generator) |
2300 .LoadAccumulatorWithRegister(value) | 2526 .LoadAccumulatorWithRegister(value) |
2301 .Return(); // Hard return (ignore any finally blocks). | 2527 .Return(); // Hard return (ignore any finally blocks). |
2528 } | |
2302 | 2529 |
2303 builder()->Bind(&(generator_resume_points_[expr->yield_id()])); | 2530 void BytecodeGenerator::BuildYieldResumePoint(int yield_id, |
2531 Yield::OnException on_exception, | |
2532 Register generator, | |
2533 int position) { | |
2534 DCHECK_GE(yield_id, 0); | |
2535 DCHECK_LT(yield_id, generator_resume_points_.size()); | |
2536 DCHECK(generator.is_valid()); | |
2537 | |
2538 DCHECK(!generator_resume_points_[yield_id].is_bound()); | |
2539 builder()->Bind(&(generator_resume_points_[yield_id])); | |
2304 // Upon resume, we continue here. | 2540 // Upon resume, we continue here. |
2305 | 2541 |
2306 { | 2542 { |
2307 RegisterAllocationScope register_scope(this); | 2543 RegisterAllocationScope register_scope(this); |
2308 | 2544 |
2309 // Update state to indicate that we have finished resuming. Loop headers | 2545 // Update state to indicate that we have finished resuming. Loop headers |
2310 // rely on this. | 2546 // rely on this. |
2311 builder() | 2547 builder() |
2312 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)) | 2548 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)) |
2313 .StoreAccumulatorInRegister(generator_state_); | 2549 .StoreAccumulatorInRegister(generator_state_); |
2314 | 2550 |
2315 Register input = register_allocator()->NewRegister(); | 2551 Register input = register_allocator()->NewRegister(); |
2316 builder() | 2552 builder() |
2317 ->CallRuntime(Runtime::kInlineGeneratorGetInputOrDebugPos, generator) | 2553 ->CallRuntime(Runtime::kInlineGeneratorGetInputOrDebugPos, generator) |
2318 .StoreAccumulatorInRegister(input); | 2554 .StoreAccumulatorInRegister(input); |
2319 | 2555 |
2320 Register resume_mode = register_allocator()->NewRegister(); | 2556 Register resume_mode = register_allocator()->NewRegister(); |
2321 builder() | 2557 builder() |
2322 ->CallRuntime(Runtime::kInlineGeneratorGetResumeMode, generator) | 2558 ->CallRuntime(Runtime::kInlineGeneratorGetResumeMode, generator) |
2323 .StoreAccumulatorInRegister(resume_mode); | 2559 .StoreAccumulatorInRegister(resume_mode); |
2324 | 2560 |
2325 // Now dispatch on resume mode. | 2561 // Now dispatch on resume mode. |
2326 | 2562 |
2327 BytecodeLabel resume_with_next; | 2563 BytecodeLabel resume_with_next; |
2328 BytecodeLabel resume_with_return; | 2564 BytecodeLabel resume_with_return; |
2329 BytecodeLabel resume_with_throw; | 2565 BytecodeLabel resume_with_throw; |
2330 | 2566 |
2567 // TODO(caitp): Don't generate `resume_with_return` block for non-generators | |
2331 builder() | 2568 builder() |
2332 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kNext)) | 2569 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kNext)) |
2333 .CompareOperation(Token::EQ_STRICT, resume_mode) | 2570 .CompareOperation(Token::EQ_STRICT, resume_mode) |
2334 .JumpIfTrue(&resume_with_next) | 2571 .JumpIfTrue(&resume_with_next) |
2335 .LoadLiteral(Smi::FromInt(JSGeneratorObject::kThrow)) | 2572 .LoadLiteral(Smi::FromInt(JSGeneratorObject::kThrow)) |
2336 .CompareOperation(Token::EQ_STRICT, resume_mode) | 2573 .CompareOperation(Token::EQ_STRICT, resume_mode) |
2337 .JumpIfTrue(&resume_with_throw) | 2574 .JumpIfTrue(&resume_with_throw) |
2338 .Jump(&resume_with_return); | 2575 .Jump(&resume_with_return); |
2339 | 2576 |
2340 builder()->Bind(&resume_with_return); | 2577 builder()->Bind(&resume_with_return); |
2341 { | 2578 { |
2342 RegisterList args = register_allocator()->NewRegisterList(2); | 2579 RegisterList args = register_allocator()->NewRegisterList(2); |
2343 builder() | 2580 builder() |
2344 ->MoveRegister(input, args[0]) | 2581 ->MoveRegister(input, args[0]) |
2345 .LoadTrue() | 2582 .LoadTrue() |
2346 .StoreAccumulatorInRegister(args[1]) | 2583 .StoreAccumulatorInRegister(args[1]) |
2347 .CallRuntime(Runtime::kInlineCreateIterResultObject, args); | 2584 .CallRuntime(Runtime::kInlineCreateIterResultObject, args); |
2348 execution_control()->ReturnAccumulator(); | 2585 execution_control()->ReturnAccumulator(); |
2349 } | 2586 } |
2350 | 2587 |
2351 builder()->Bind(&resume_with_throw); | 2588 builder()->Bind(&resume_with_throw); |
2352 builder()->SetExpressionPosition(expr); | 2589 builder()->SetExpressionPosition(position); |
2353 builder()->LoadAccumulatorWithRegister(input); | 2590 builder()->LoadAccumulatorWithRegister(input); |
2354 if (expr->rethrow_on_exception()) { | 2591 if (on_exception == Yield::kOnExceptionRethrow) { |
2355 builder()->ReThrow(); | 2592 builder()->ReThrow(); |
2356 } else { | 2593 } else { |
2357 builder()->Throw(); | 2594 builder()->Throw(); |
2358 } | 2595 } |
2359 | 2596 |
2360 builder()->Bind(&resume_with_next); | 2597 builder()->Bind(&resume_with_next); |
2361 builder()->LoadAccumulatorWithRegister(input); | 2598 builder()->LoadAccumulatorWithRegister(input); |
2362 } | 2599 } |
2363 } | 2600 } |
2364 | 2601 |
2602 void BytecodeGenerator::VisitYield(Yield* expr) { | |
2603 Register generator = VisitForRegisterValue(expr->generator_object()); | |
2604 | |
2605 builder()->SetExpressionPosition(expr); | |
2606 Register value = VisitForRegisterValue(expr->expression()); | |
2607 | |
2608 BuildYield(expr->yield_id(), generator, value); | |
2609 BuildYieldResumePoint(expr->yield_id(), expr->on_exception(), generator, | |
2610 expr->position()); | |
2611 } | |
2612 | |
2365 void BytecodeGenerator::VisitThrow(Throw* expr) { | 2613 void BytecodeGenerator::VisitThrow(Throw* expr) { |
2366 VisitForAccumulatorValue(expr->exception()); | 2614 VisitForAccumulatorValue(expr->exception()); |
2367 builder()->SetExpressionPosition(expr); | 2615 builder()->SetExpressionPosition(expr); |
2368 builder()->Throw(); | 2616 builder()->Throw(); |
2369 } | 2617 } |
2370 | 2618 |
2371 void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) { | 2619 void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) { |
2372 LhsKind property_kind = Property::GetAssignType(expr); | 2620 LhsKind property_kind = Property::GetAssignType(expr); |
2373 FeedbackVectorSlot slot = expr->PropertyFeedbackSlot(); | 2621 FeedbackVectorSlot slot = expr->PropertyFeedbackSlot(); |
2374 builder()->SetExpressionPosition(expr); | 2622 builder()->SetExpressionPosition(expr); |
(...skipping 1002 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3377 } | 3625 } |
3378 | 3626 |
3379 Runtime::FunctionId BytecodeGenerator::StoreKeyedToSuperRuntimeId() { | 3627 Runtime::FunctionId BytecodeGenerator::StoreKeyedToSuperRuntimeId() { |
3380 return is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict | 3628 return is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict |
3381 : Runtime::kStoreKeyedToSuper_Sloppy; | 3629 : Runtime::kStoreKeyedToSuper_Sloppy; |
3382 } | 3630 } |
3383 | 3631 |
3384 } // namespace interpreter | 3632 } // namespace interpreter |
3385 } // namespace internal | 3633 } // namespace internal |
3386 } // namespace v8 | 3634 } // namespace v8 |
OLD | NEW |