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

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

Issue 2664083002: [ignition] desugar async functions/generators/modules in BytecodeGenerator
Patch Set: make it a little easier to read 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/parsing/parser.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 583 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/interpreter/bytecode-generator.h ('k') | src/parsing/parser.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698