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 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
673 | 674 |
674 InitializeAstVisitor(stack_limit); | 675 InitializeAstVisitor(stack_limit); |
675 | 676 |
676 // Initialize the incoming context. | 677 // Initialize the incoming context. |
677 ContextScope incoming_context(this, scope(), false); | 678 ContextScope incoming_context(this, scope(), false); |
678 | 679 |
679 // Initialize control scope. | 680 // Initialize control scope. |
680 ControlScopeForTopLevel control(this); | 681 ControlScopeForTopLevel control(this); |
681 | 682 |
682 RegisterAllocationScope register_scope(this); | 683 RegisterAllocationScope register_scope(this); |
683 | 684 if (IsResumableFunction(info()->literal()->kind()) || |
684 if (IsResumableFunction(info()->literal()->kind())) { | 685 scope()->is_module_scope()) { |
| 686 generator_object_ = register_allocator()->NewRegister(); |
685 generator_state_ = register_allocator()->NewRegister(); | 687 generator_state_ = register_allocator()->NewRegister(); |
| 688 if (IsAsyncFunction(info()->literal()->kind())) { |
| 689 promise_ = register_allocator()->NewRegister(); |
| 690 } |
686 VisitGeneratorPrologue(); | 691 VisitGeneratorPrologue(); |
687 } | 692 } |
688 | 693 |
689 if (scope()->NeedsContext()) { | 694 if (scope()->NeedsContext()) { |
690 // Push a new inner context scope for the function. | 695 // Push a new inner context scope for the function. |
691 BuildNewLocalActivationContext(); | 696 BuildNewLocalActivationContext(); |
692 ContextScope local_function_context(this, scope(), false); | 697 ContextScope local_function_context(this, scope(), false); |
693 BuildLocalActivationContextInitialization(); | 698 BuildLocalActivationContextInitialization(); |
694 GenerateBytecodeBody(); | 699 GenerateBytecodeBody(); |
695 } else { | 700 } else { |
(...skipping 11 matching lines...) Expand all Loading... |
707 // Emit an implicit return instruction in case control flow can fall off the | 712 // 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. | 713 // end of the function without an explicit return being present on all paths. |
709 if (builder()->RequiresImplicitReturn()) { | 714 if (builder()->RequiresImplicitReturn()) { |
710 builder()->LoadUndefined(); | 715 builder()->LoadUndefined(); |
711 BuildReturn(); | 716 BuildReturn(); |
712 } | 717 } |
713 DCHECK(!builder()->RequiresImplicitReturn()); | 718 DCHECK(!builder()->RequiresImplicitReturn()); |
714 } | 719 } |
715 | 720 |
716 void BytecodeGenerator::GenerateBytecodeBody() { | 721 void BytecodeGenerator::GenerateBytecodeBody() { |
| 722 const bool kIsModule = scope()->is_module_scope(); |
| 723 const bool kIsGeneratorFunction = |
| 724 IsGeneratorFunction(info()->literal()->kind()); |
| 725 const bool kIsResumableFunction = |
| 726 IsResumableFunction(info()->literal()->kind()); |
| 727 |
717 // Build the arguments object if it is used. | 728 // Build the arguments object if it is used. |
718 VisitArgumentsObject(scope()->arguments()); | 729 VisitArgumentsObject(scope()->arguments()); |
719 | 730 |
720 // Build rest arguments array if it is used. | 731 // Build rest arguments array if it is used. |
721 Variable* rest_parameter = scope()->rest_parameter(); | 732 Variable* rest_parameter = scope()->rest_parameter(); |
722 VisitRestArgumentsArray(rest_parameter); | 733 VisitRestArgumentsArray(rest_parameter); |
723 | 734 |
724 // Build assignment to {.this_function} variable if it is used. | 735 // Build assignment to {.this_function} variable if it is used. |
725 VisitThisFunctionVariable(scope()->this_function_var()); | 736 VisitThisFunctionVariable(scope()->this_function_var()); |
726 | 737 |
727 // Build assignment to {new.target} variable if it is used. | 738 // Build assignment to {new.target} variable if it is used. |
728 VisitNewTargetVariable(scope()->new_target_var()); | 739 VisitNewTargetVariable(scope()->new_target_var()); |
729 | 740 |
730 // Emit tracing call if requested to do so. | 741 // Emit tracing call if requested to do so. |
731 if (FLAG_trace) builder()->CallRuntime(Runtime::kTraceEnter); | 742 if (FLAG_trace) builder()->CallRuntime(Runtime::kTraceEnter); |
732 | 743 |
733 // Visit declarations within the function scope. | 744 // Visit declarations within the function scope. |
734 VisitDeclarations(scope()->declarations()); | 745 VisitDeclarations(scope()->declarations()); |
735 | 746 |
736 // Emit initializing assignments for module namespace imports (if any). | 747 // Emit initializing assignments for module namespace imports (if any). |
737 VisitModuleNamespaceImports(); | 748 VisitModuleNamespaceImports(); |
738 | 749 |
739 // Perform a stack-check before the body. | 750 // Perform a stack-check before the body. |
740 builder()->StackCheck(info()->literal()->start_position()); | 751 builder()->StackCheck(info()->literal()->start_position()); |
741 | 752 |
| 753 // Build assignment to variable <function name> if function is a named |
| 754 // expression and the variable is used. |
| 755 if (info()->literal()->is_named_expression()) { |
| 756 Variable* function_var = scope()->function_var(); |
| 757 if (function_var != nullptr && !function_var->IsUnallocated()) { |
| 758 builder()->LoadAccumulatorWithRegister(Register::function_closure()); |
| 759 BuildVariableAssignment(function_var, Token::INIT, |
| 760 FeedbackVectorSlot::Invalid(), |
| 761 HoleCheckMode::kElided); |
| 762 } |
| 763 } |
| 764 |
| 765 Block* parameter_init_block = info()->literal()->parameter_init_block(); |
| 766 |
| 767 if (kIsResumableFunction || kIsModule) { |
| 768 if (kIsResumableFunction) { |
| 769 // No need to store `undefined` in the generator register for Modules, |
| 770 // as there is no finally block. |
| 771 builder()->LoadUndefined().StoreAccumulatorInRegister(generator_object_); |
| 772 } |
| 773 |
| 774 auto try_block = [=]() { |
| 775 // Try ... |
| 776 if (parameter_init_block != nullptr) { |
| 777 // Initialize non-simple parameters before initial yield. |
| 778 VisitBlock(parameter_init_block); |
| 779 } |
| 780 // Allocate generator object |
| 781 RegisterAllocationScope register_scope(this); |
| 782 RegisterList args = register_allocator()->NewRegisterList(2); |
| 783 builder()->MoveRegister(Register::function_closure(), args[0]); |
| 784 |
| 785 int yield_position = info()->literal()->position(); |
| 786 builder()->SetExpressionPosition(yield_position); |
| 787 |
| 788 if (IsArrowFunction(info()->literal()->kind())) { |
| 789 builder()->LoadUndefined().StoreAccumulatorInRegister(args[1]); |
| 790 } else { |
| 791 builder()->MoveRegister(builder()->Receiver(), args[1]); |
| 792 } |
| 793 builder() |
| 794 ->CallRuntime(Runtime::kCreateJSGeneratorObject, args) |
| 795 .StoreAccumulatorInRegister(generator_object_); |
| 796 |
| 797 if (kIsGeneratorFunction || kIsModule) { |
| 798 BuildYield(0, Yield::kOnExceptionThrow, Yield::kNormal, |
| 799 generator_object_, yield_position); |
| 800 } |
| 801 VisitStatements(info()->literal()->body()); |
| 802 |
| 803 if (builder()->RequiresImplicitReturn()) { |
| 804 if (IsGeneratorFunction(info()->literal()->kind())) { |
| 805 // Add implicit `return { value: undefined, done: true }` |
| 806 builder() |
| 807 ->LoadUndefined() |
| 808 .StoreAccumulatorInRegister(args[0]) |
| 809 .LoadTrue() |
| 810 .StoreAccumulatorInRegister(args[1]) |
| 811 .CallRuntime(Runtime::kInlineCreateIterResultObject, args); |
| 812 execution_control()->ReturnAccumulator(); |
| 813 } |
| 814 } |
| 815 }; |
| 816 |
| 817 auto catch_block = [=](Register context) { |
| 818 // Catch ... |
| 819 if (IsAsyncFunction(info()->literal()->kind())) { |
| 820 RegisterAllocationScope register_scope(this); |
| 821 RegisterList args = register_allocator()->NewRegisterList(4); |
| 822 Register exception = args[2]; |
| 823 |
| 824 builder() |
| 825 ->StoreAccumulatorInRegister(exception) |
| 826 .LoadTheHole() |
| 827 .SetPendingMessage() |
| 828 .LoadUndefined() |
| 829 .StoreAccumulatorInRegister(args[0]) |
| 830 .MoveRegister(promise_, args[1]) |
| 831 .LoadFalse() |
| 832 .StoreAccumulatorInRegister(args[3]) |
| 833 .CallJSRuntime(Context::PROMISE_INTERNAL_REJECT_INDEX, args) |
| 834 .LoadAccumulatorWithRegister(promise_) |
| 835 .Return(); // No need to close the generator for async functions |
| 836 } |
| 837 }; |
| 838 |
| 839 auto finally_block = [=]() { |
| 840 // Finally ... |
| 841 if (kIsGeneratorFunction) { |
| 842 BytecodeLabel if_generatorundefined; |
| 843 builder()->LoadAccumulatorWithRegister(generator_object_); |
| 844 builder()->JumpIfUndefined(&if_generatorundefined); |
| 845 builder()->CallRuntime(Runtime::kInlineGeneratorClose, |
| 846 generator_object_); |
| 847 builder()->Bind(&if_generatorundefined); |
| 848 } |
| 849 }; |
| 850 |
| 851 const bool kNeedsTryCatch = IsAsyncFunction(info()->literal()->kind()); |
| 852 if (kNeedsTryCatch) { |
| 853 // Currently, only async functions need a special behaviour for top-level |
| 854 // exceptions |
| 855 HandlerTable::CatchPrediction catch_prediction = |
| 856 HandlerTable::ASYNC_AWAIT; |
| 857 BuildTryCatchFinally(HandlerTable::UNCAUGHT, catch_prediction, try_block, |
| 858 catch_block, finally_block); |
| 859 } else if (kIsGeneratorFunction) { |
| 860 BuildTryFinally(HandlerTable::UNCAUGHT, try_block, finally_block); |
| 861 } else { |
| 862 DCHECK(kIsModule); |
| 863 try_block(); |
| 864 } |
| 865 return; |
| 866 } |
| 867 |
742 // Visit statements in the function body. | 868 // Visit statements in the function body. |
| 869 if (parameter_init_block != nullptr) { |
| 870 VisitBlock(parameter_init_block); |
| 871 } |
743 VisitStatements(info()->literal()->body()); | 872 VisitStatements(info()->literal()->body()); |
744 } | 873 } |
745 | 874 |
746 void BytecodeGenerator::BuildIndexedJump(Register index, size_t start_index, | 875 void BytecodeGenerator::BuildIndexedJump(Register index, size_t start_index, |
747 size_t size, | 876 size_t size, |
748 ZoneVector<BytecodeLabel>& targets) { | 877 ZoneVector<BytecodeLabel>& targets) { |
749 // TODO(neis): Optimize this by using a proper jump table. | 878 // TODO(neis): Optimize this by using a proper jump table. |
750 DCHECK_LE(start_index + size, targets.size()); | 879 DCHECK_LE(start_index + size, targets.size()); |
751 for (size_t i = start_index; i < start_index + size; i++) { | 880 for (size_t i = start_index; i < start_index + size; i++) { |
752 builder() | 881 builder() |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
812 .PushContext(dummy) | 941 .PushContext(dummy) |
813 .ResumeGenerator(generator_object) | 942 .ResumeGenerator(generator_object) |
814 .StoreAccumulatorInRegister(generator_state_); | 943 .StoreAccumulatorInRegister(generator_state_); |
815 BuildIndexedJump(generator_state_, 0, generator_resume_points_.size(), | 944 BuildIndexedJump(generator_state_, 0, generator_resume_points_.size(), |
816 generator_resume_points_); | 945 generator_resume_points_); |
817 | 946 |
818 builder() | 947 builder() |
819 ->Bind(®ular_call) | 948 ->Bind(®ular_call) |
820 .LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)) | 949 .LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)) |
821 .StoreAccumulatorInRegister(generator_state_); | 950 .StoreAccumulatorInRegister(generator_state_); |
| 951 |
| 952 if (IsAsyncFunction(info()->literal()->kind())) { |
| 953 // Create initial async function promise |
| 954 RegisterAllocationScope register_scope(this); |
| 955 RegisterList args = register_allocator()->NewRegisterList(1); |
| 956 builder() |
| 957 ->LoadUndefined() |
| 958 .StoreAccumulatorInRegister(args[0]) |
| 959 .CallJSRuntime(Context::ASYNC_FUNCTION_PROMISE_CREATE_INDEX, args) |
| 960 .StoreAccumulatorInRegister(promise_); |
| 961 } |
| 962 |
822 // This is a regular call. Fall through to the ordinary function prologue, | 963 // This is a regular call. Fall through to the ordinary function prologue, |
823 // after which we will run into the generator object creation and other extra | 964 // after which we will run into the generator object creation and other extra |
824 // code inserted by the parser. | 965 // code inserted by the parser. |
825 } | 966 } |
826 | 967 |
827 void BytecodeGenerator::VisitBlock(Block* stmt) { | 968 void BytecodeGenerator::VisitBlock(Block* stmt) { |
828 // Visit declarations and statements. | 969 // Visit declarations and statements. |
829 if (stmt->scope() != nullptr && stmt->scope()->NeedsContext()) { | 970 if (stmt->scope() != nullptr && stmt->scope()->NeedsContext()) { |
830 BuildNewLocalBlockContext(stmt->scope()); | 971 BuildNewLocalBlockContext(stmt->scope()); |
831 ContextScope scope(this, stmt->scope()); | 972 ContextScope scope(this, stmt->scope()); |
(...skipping 495 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1327 VisitForEffect(stmt->next_result()); | 1468 VisitForEffect(stmt->next_result()); |
1328 VisitForAccumulatorValue(stmt->result_done()); | 1469 VisitForAccumulatorValue(stmt->result_done()); |
1329 loop_builder.BreakIfTrue(); | 1470 loop_builder.BreakIfTrue(); |
1330 | 1471 |
1331 VisitForEffect(stmt->assign_each()); | 1472 VisitForEffect(stmt->assign_each()); |
1332 VisitIterationBody(stmt, &loop_builder); | 1473 VisitIterationBody(stmt, &loop_builder); |
1333 loop_builder.JumpToHeader(loop_depth_); | 1474 loop_builder.JumpToHeader(loop_depth_); |
1334 loop_builder.EndLoop(); | 1475 loop_builder.EndLoop(); |
1335 } | 1476 } |
1336 | 1477 |
1337 void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { | 1478 void BytecodeGenerator::BuildTryCatch( |
1338 TryCatchBuilder try_control_builder(builder(), stmt->catch_prediction()); | 1479 HandlerTable::CatchPrediction catch_prediction, |
| 1480 std::function<void()> build_try, |
| 1481 std::function<void(Register)> build_catch) { |
| 1482 TryCatchBuilder try_control_builder(builder(), catch_prediction); |
1339 | 1483 |
1340 // Preserve the context in a dedicated register, so that it can be restored | 1484 // Preserve the context in a dedicated register, so that it can be restored |
1341 // when the handler is entered by the stack-unwinding machinery. | 1485 // when the handler is entered by the stack-unwinding machinery. |
1342 // TODO(mstarzinger): Be smarter about register allocation. | 1486 // TODO(mstarzinger): Be smarter about register allocation. |
1343 Register context = register_allocator()->NewRegister(); | 1487 Register context = register_allocator()->NewRegister(); |
1344 builder()->MoveRegister(Register::current_context(), context); | 1488 builder()->MoveRegister(Register::current_context(), context); |
1345 | 1489 |
1346 // Evaluate the try-block inside a control scope. This simulates a handler | 1490 // Evaluate the try-block inside a control scope. This simulates a handler |
1347 // that is intercepting 'throw' control commands. | 1491 // that is intercepting 'throw' control commands. |
1348 try_control_builder.BeginTry(context); | 1492 try_control_builder.BeginTry(context); |
1349 { | 1493 { |
1350 ControlScopeForTryCatch scope(this, &try_control_builder); | 1494 ControlScopeForTryCatch scope(this, &try_control_builder); |
1351 Visit(stmt->try_block()); | 1495 ScopedAssignment<HandlerTable::CatchPrediction> prediction( |
| 1496 catch_prediction_, catch_prediction); |
| 1497 build_try(); |
1352 } | 1498 } |
1353 try_control_builder.EndTry(); | 1499 try_control_builder.EndTry(); |
1354 | 1500 |
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. | 1501 // Evaluate the catch-block. |
1368 VisitInScope(stmt->catch_block(), stmt->scope()); | 1502 build_catch(context); |
1369 try_control_builder.EndCatch(); | 1503 try_control_builder.EndCatch(); |
1370 } | 1504 } |
1371 | 1505 |
1372 void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { | 1506 void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { |
1373 TryFinallyBuilder try_control_builder(builder(), stmt->catch_prediction()); | 1507 BuildTryCatch(stmt->catch_prediction(), [=]() { Visit(stmt->try_block()); }, |
| 1508 [=](Register context) { |
| 1509 // Create a catch scope that binds the exception. |
| 1510 BuildNewLocalCatchContext(stmt->variable(), stmt->scope()); |
| 1511 builder()->StoreAccumulatorInRegister(context); |
| 1512 |
| 1513 // If requested, clear message object as we enter the catch |
| 1514 // block. |
| 1515 if (stmt->clear_pending_message()) { |
| 1516 builder()->LoadTheHole().SetPendingMessage(); |
| 1517 } |
| 1518 |
| 1519 // Load the catch context into the accumulator. |
| 1520 builder()->LoadAccumulatorWithRegister(context); |
| 1521 |
| 1522 VisitInScope(stmt->catch_block(), stmt->scope()); |
| 1523 }); |
| 1524 } |
| 1525 |
| 1526 void BytecodeGenerator::BuildTryFinally( |
| 1527 HandlerTable::CatchPrediction catch_prediction, |
| 1528 std::function<void()> build_try, std::function<void()> build_finally) { |
| 1529 TryFinallyBuilder try_control_builder(builder(), catch_prediction); |
1374 | 1530 |
1375 // We keep a record of all paths that enter the finally-block to be able to | 1531 // 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 | 1532 // dispatch to the correct continuation point after the statements in the |
1377 // finally-block have been evaluated. | 1533 // finally-block have been evaluated. |
1378 // | 1534 // |
1379 // The try-finally construct can enter the finally-block in three ways: | 1535 // 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. | 1536 // 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 | 1537 // 2. By exiting the try-block with a function-local control flow transfer |
1382 // (i.e. through break/continue/return statements). | 1538 // (i.e. through break/continue/return statements). |
1383 // 3. By exiting the try-block with a thrown exception. | 1539 // 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. | 1551 // when the handler is entered by the stack-unwinding machinery. |
1396 // TODO(mstarzinger): Be smarter about register allocation. | 1552 // TODO(mstarzinger): Be smarter about register allocation. |
1397 Register context = register_allocator()->NewRegister(); | 1553 Register context = register_allocator()->NewRegister(); |
1398 builder()->MoveRegister(Register::current_context(), context); | 1554 builder()->MoveRegister(Register::current_context(), context); |
1399 | 1555 |
1400 // Evaluate the try-block inside a control scope. This simulates a handler | 1556 // Evaluate the try-block inside a control scope. This simulates a handler |
1401 // that is intercepting all control commands. | 1557 // that is intercepting all control commands. |
1402 try_control_builder.BeginTry(context); | 1558 try_control_builder.BeginTry(context); |
1403 { | 1559 { |
1404 ControlScopeForTryFinally scope(this, &try_control_builder, &commands); | 1560 ControlScopeForTryFinally scope(this, &try_control_builder, &commands); |
1405 Visit(stmt->try_block()); | 1561 build_try(); |
1406 } | 1562 } |
1407 try_control_builder.EndTry(); | 1563 try_control_builder.EndTry(); |
1408 | 1564 |
1409 // Record fall-through and exception cases. | 1565 // Record fall-through and exception cases. |
1410 commands.RecordFallThroughPath(); | 1566 commands.RecordFallThroughPath(); |
1411 try_control_builder.LeaveTry(); | 1567 try_control_builder.LeaveTry(); |
1412 try_control_builder.BeginHandler(); | 1568 try_control_builder.BeginHandler(); |
1413 commands.RecordHandlerReThrowPath(); | 1569 commands.RecordHandlerReThrowPath(); |
1414 | 1570 |
1415 // Pending message object is saved on entry. | 1571 // Pending message object is saved on entry. |
1416 try_control_builder.BeginFinally(); | 1572 try_control_builder.BeginFinally(); |
1417 Register message = context; // Reuse register. | 1573 Register message = context; // Reuse register. |
1418 | 1574 |
1419 // Clear message object as we enter the finally block. | 1575 // Clear message object as we enter the finally block. |
1420 builder()->LoadTheHole().SetPendingMessage().StoreAccumulatorInRegister( | 1576 builder()->LoadTheHole().SetPendingMessage().StoreAccumulatorInRegister( |
1421 message); | 1577 message); |
1422 | 1578 |
1423 // Evaluate the finally-block. | 1579 // Evaluate the finally-block. |
1424 Visit(stmt->finally_block()); | 1580 build_finally(); |
1425 try_control_builder.EndFinally(); | 1581 try_control_builder.EndFinally(); |
1426 | 1582 |
1427 // Pending message object is restored on exit. | 1583 // Pending message object is restored on exit. |
1428 builder()->LoadAccumulatorWithRegister(message).SetPendingMessage(); | 1584 builder()->LoadAccumulatorWithRegister(message).SetPendingMessage(); |
1429 | 1585 |
1430 // Dynamic dispatch after the finally-block. | 1586 // Dynamic dispatch after the finally-block. |
1431 commands.ApplyDeferredCommands(); | 1587 commands.ApplyDeferredCommands(); |
1432 } | 1588 } |
1433 | 1589 |
| 1590 void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { |
| 1591 BuildTryFinally(stmt->catch_prediction(), [=]() { Visit(stmt->try_block()); }, |
| 1592 [=]() { Visit(stmt->finally_block()); }); |
| 1593 } |
| 1594 |
| 1595 void BytecodeGenerator::BuildTryCatchFinally( |
| 1596 HandlerTable::CatchPrediction outer_catch_prediction, |
| 1597 HandlerTable::CatchPrediction inner_catch_prediction, |
| 1598 std::function<void()> build_try, std::function<void(Register)> build_catch, |
| 1599 std::function<void()> build_finally) { |
| 1600 BuildTryFinally( |
| 1601 outer_catch_prediction, |
| 1602 [=]() { BuildTryCatch(inner_catch_prediction, build_try, build_catch); }, |
| 1603 build_finally); |
| 1604 } |
| 1605 |
1434 void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) { | 1606 void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) { |
1435 builder()->SetStatementPosition(stmt); | 1607 builder()->SetStatementPosition(stmt); |
1436 builder()->Debugger(); | 1608 builder()->Debugger(); |
1437 } | 1609 } |
1438 | 1610 |
1439 void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { | 1611 void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { |
1440 uint8_t flags = CreateClosureFlags::Encode(expr->pretenure(), | 1612 uint8_t flags = CreateClosureFlags::Encode(expr->pretenure(), |
1441 scope()->is_function_scope()); | 1613 scope()->is_function_scope()); |
1442 size_t entry = builder()->AllocateConstantPoolEntry(); | 1614 size_t entry = builder()->AllocateConstantPoolEntry(); |
1443 int slot_index = feedback_index(expr->LiteralFeedbackSlot()); | 1615 int slot_index = feedback_index(expr->LiteralFeedbackSlot()); |
(...skipping 538 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1982 } | 2154 } |
1983 | 2155 |
1984 void BytecodeGenerator::BuildVariableLoadForAccumulatorValue( | 2156 void BytecodeGenerator::BuildVariableLoadForAccumulatorValue( |
1985 Variable* variable, FeedbackVectorSlot slot, HoleCheckMode hole_check_mode, | 2157 Variable* variable, FeedbackVectorSlot slot, HoleCheckMode hole_check_mode, |
1986 TypeofMode typeof_mode) { | 2158 TypeofMode typeof_mode) { |
1987 ValueResultScope accumulator_result(this); | 2159 ValueResultScope accumulator_result(this); |
1988 BuildVariableLoad(variable, slot, hole_check_mode, typeof_mode); | 2160 BuildVariableLoad(variable, slot, hole_check_mode, typeof_mode); |
1989 } | 2161 } |
1990 | 2162 |
1991 void BytecodeGenerator::BuildReturn() { | 2163 void BytecodeGenerator::BuildReturn() { |
1992 if (FLAG_trace) { | 2164 if (IsAsyncFunction(info()->literal()->kind())) { |
1993 RegisterAllocationScope register_scope(this); | 2165 RegisterList args = register_allocator()->NewRegisterList(3); |
1994 Register result = register_allocator()->NewRegister(); | 2166 Register receiver = args[0]; |
1995 // Runtime returns {result} value, preserving accumulator. | 2167 Register promise = args[1]; |
1996 builder()->StoreAccumulatorInRegister(result).CallRuntime( | 2168 Register return_value = args[2]; |
1997 Runtime::kTraceExit, result); | 2169 |
| 2170 builder() |
| 2171 ->StoreAccumulatorInRegister(return_value) |
| 2172 .LoadUndefined() |
| 2173 .StoreAccumulatorInRegister(receiver) |
| 2174 .MoveRegister(promise_, promise) |
| 2175 .CallJSRuntime(Context::PROMISE_RESOLVE_INDEX, args) |
| 2176 .LoadAccumulatorWithRegister(promise); |
1998 } | 2177 } |
| 2178 |
| 2179 BuildTraceExit(); |
1999 builder()->Return(); | 2180 builder()->Return(); |
2000 } | 2181 } |
2001 | 2182 |
| 2183 void BytecodeGenerator::BuildTraceExit() { |
| 2184 if (!FLAG_trace) return; |
| 2185 RegisterAllocationScope register_scope(this); |
| 2186 Register result = register_allocator()->NewRegister(); |
| 2187 // Runtime returns {result} value, preserving accumulator. |
| 2188 builder()->StoreAccumulatorInRegister(result).CallRuntime(Runtime::kTraceExit, |
| 2189 result); |
| 2190 } |
| 2191 |
2002 void BytecodeGenerator::BuildReThrow() { builder()->ReThrow(); } | 2192 void BytecodeGenerator::BuildReThrow() { builder()->ReThrow(); } |
2003 | 2193 |
2004 void BytecodeGenerator::BuildAbort(BailoutReason bailout_reason) { | 2194 void BytecodeGenerator::BuildAbort(BailoutReason bailout_reason) { |
2005 RegisterAllocationScope register_scope(this); | 2195 RegisterAllocationScope register_scope(this); |
2006 Register reason = register_allocator()->NewRegister(); | 2196 Register reason = register_allocator()->NewRegister(); |
2007 builder() | 2197 builder() |
2008 ->LoadLiteral(Smi::FromInt(static_cast<int>(bailout_reason))) | 2198 ->LoadLiteral(Smi::FromInt(static_cast<int>(bailout_reason))) |
2009 .StoreAccumulatorInRegister(reason) | 2199 .StoreAccumulatorInRegister(reason) |
2010 .CallRuntime(Runtime::kAbort, reason); | 2200 .CallRuntime(Runtime::kAbort, reason); |
2011 } | 2201 } |
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2278 } | 2468 } |
2279 case KEYED_SUPER_PROPERTY: { | 2469 case KEYED_SUPER_PROPERTY: { |
2280 builder() | 2470 builder() |
2281 ->StoreAccumulatorInRegister(super_property_args[3]) | 2471 ->StoreAccumulatorInRegister(super_property_args[3]) |
2282 .CallRuntime(StoreKeyedToSuperRuntimeId(), super_property_args); | 2472 .CallRuntime(StoreKeyedToSuperRuntimeId(), super_property_args); |
2283 break; | 2473 break; |
2284 } | 2474 } |
2285 } | 2475 } |
2286 } | 2476 } |
2287 | 2477 |
2288 void BytecodeGenerator::VisitYield(Yield* expr) { | 2478 void BytecodeGenerator::BuildYield(int yield_id, |
2289 builder()->SetExpressionPosition(expr); | 2479 Yield::OnException on_exception, |
2290 Register value = VisitForRegisterValue(expr->expression()); | 2480 Yield::YieldType yield_type, Register value, |
| 2481 int position) { |
| 2482 DCHECK_GE(yield_id, 0); |
| 2483 DCHECK_LT(yield_id, generator_resume_points_.size()); |
2291 | 2484 |
2292 Register generator = VisitForRegisterValue(expr->generator_object()); | 2485 Register generator = generator_object_; |
| 2486 DCHECK(generator.is_valid()); |
2293 | 2487 |
2294 // Save context, registers, and state. Then return. | 2488 if (IsAsyncFunction(info()->literal()->kind()) && |
2295 builder() | 2489 yield_type == Yield::kAwait) { |
2296 ->LoadLiteral(Smi::FromInt(expr->yield_id())) | 2490 RegisterAllocationScope register_scope(this); |
2297 .SuspendGenerator(generator) | 2491 RegisterList args = register_allocator()->NewRegisterList(4); |
2298 .LoadAccumulatorWithRegister(value) | |
2299 .Return(); // Hard return (ignore any finally blocks). | |
2300 | 2492 |
2301 builder()->Bind(&(generator_resume_points_[expr->yield_id()])); | 2493 int context_index = Context::ASYNC_FUNCTION_AWAIT_CAUGHT_INDEX; |
| 2494 if (catch_prediction_ == HandlerTable::ASYNC_AWAIT) |
| 2495 context_index = Context::ASYNC_FUNCTION_AWAIT_UNCAUGHT_INDEX; |
| 2496 |
| 2497 builder() |
| 2498 ->LoadUndefined() |
| 2499 .StoreAccumulatorInRegister(args[0]) |
| 2500 .MoveRegister(generator, args[1]) |
| 2501 .MoveRegister(value, args[2]) |
| 2502 .MoveRegister(promise_, args[3]) |
| 2503 .CallJSRuntime(context_index, args) |
| 2504 .LoadLiteral(Smi::FromInt(yield_id)) |
| 2505 .SuspendGenerator(generator) |
| 2506 .LoadAccumulatorWithRegister(promise_) |
| 2507 .Return(); // Hard return (ignore any finally blocks) |
| 2508 } else { |
| 2509 // Save context, registers, and state. Then return. |
| 2510 builder() |
| 2511 ->LoadLiteral(Smi::FromInt(yield_id)) |
| 2512 .SuspendGenerator(generator) |
| 2513 .LoadAccumulatorWithRegister(value) |
| 2514 .Return(); // Hard return (ignore any finally blocks). |
| 2515 } |
| 2516 |
| 2517 builder()->Bind(&(generator_resume_points_[yield_id])); |
2302 // Upon resume, we continue here. | 2518 // Upon resume, we continue here. |
2303 | 2519 |
2304 { | 2520 { |
2305 RegisterAllocationScope register_scope(this); | 2521 RegisterAllocationScope register_scope(this); |
2306 | 2522 |
2307 // Update state to indicate that we have finished resuming. Loop headers | 2523 // Update state to indicate that we have finished resuming. Loop headers |
2308 // rely on this. | 2524 // rely on this. |
2309 builder() | 2525 builder() |
2310 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)) | 2526 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)) |
2311 .StoreAccumulatorInRegister(generator_state_); | 2527 .StoreAccumulatorInRegister(generator_state_); |
(...skipping 28 matching lines...) Expand all Loading... |
2340 RegisterList args = register_allocator()->NewRegisterList(2); | 2556 RegisterList args = register_allocator()->NewRegisterList(2); |
2341 builder() | 2557 builder() |
2342 ->MoveRegister(input, args[0]) | 2558 ->MoveRegister(input, args[0]) |
2343 .LoadTrue() | 2559 .LoadTrue() |
2344 .StoreAccumulatorInRegister(args[1]) | 2560 .StoreAccumulatorInRegister(args[1]) |
2345 .CallRuntime(Runtime::kInlineCreateIterResultObject, args); | 2561 .CallRuntime(Runtime::kInlineCreateIterResultObject, args); |
2346 execution_control()->ReturnAccumulator(); | 2562 execution_control()->ReturnAccumulator(); |
2347 } | 2563 } |
2348 | 2564 |
2349 builder()->Bind(&resume_with_throw); | 2565 builder()->Bind(&resume_with_throw); |
2350 builder()->SetExpressionPosition(expr); | 2566 builder()->SetExpressionPosition(position); |
2351 builder()->LoadAccumulatorWithRegister(input); | 2567 builder()->LoadAccumulatorWithRegister(input); |
2352 if (expr->rethrow_on_exception()) { | 2568 if (on_exception == Yield::kOnExceptionRethrow) { |
2353 builder()->ReThrow(); | 2569 builder()->ReThrow(); |
2354 } else { | 2570 } else { |
2355 builder()->Throw(); | 2571 builder()->Throw(); |
2356 } | 2572 } |
2357 | 2573 |
2358 builder()->Bind(&resume_with_next); | 2574 builder()->Bind(&resume_with_next); |
2359 builder()->LoadAccumulatorWithRegister(input); | 2575 builder()->LoadAccumulatorWithRegister(input); |
2360 } | 2576 } |
2361 } | 2577 } |
2362 | 2578 |
| 2579 void BytecodeGenerator::VisitYield(Yield* expr) { |
| 2580 builder()->SetExpressionPosition(expr); |
| 2581 Register value = VisitForRegisterValue(expr->expression()); |
| 2582 |
| 2583 BuildYield(expr->yield_id(), expr->on_exception(), expr->yield_type(), value, |
| 2584 expr->position()); |
| 2585 } |
| 2586 |
2363 void BytecodeGenerator::VisitThrow(Throw* expr) { | 2587 void BytecodeGenerator::VisitThrow(Throw* expr) { |
2364 VisitForAccumulatorValue(expr->exception()); | 2588 VisitForAccumulatorValue(expr->exception()); |
2365 builder()->SetExpressionPosition(expr); | 2589 builder()->SetExpressionPosition(expr); |
2366 builder()->Throw(); | 2590 builder()->Throw(); |
2367 } | 2591 } |
2368 | 2592 |
2369 void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) { | 2593 void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) { |
2370 LhsKind property_kind = Property::GetAssignType(expr); | 2594 LhsKind property_kind = Property::GetAssignType(expr); |
2371 FeedbackVectorSlot slot = expr->PropertyFeedbackSlot(); | 2595 FeedbackVectorSlot slot = expr->PropertyFeedbackSlot(); |
2372 builder()->SetExpressionPosition(expr); | 2596 builder()->SetExpressionPosition(expr); |
(...skipping 552 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2925 builder()->SetExpressionPosition(expr); | 3149 builder()->SetExpressionPosition(expr); |
2926 builder()->BinaryOperation(expr->op(), lhs, feedback_index(slot)); | 3150 builder()->BinaryOperation(expr->op(), lhs, feedback_index(slot)); |
2927 } | 3151 } |
2928 | 3152 |
2929 void BytecodeGenerator::VisitSpread(Spread* expr) { Visit(expr->expression()); } | 3153 void BytecodeGenerator::VisitSpread(Spread* expr) { Visit(expr->expression()); } |
2930 | 3154 |
2931 void BytecodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) { | 3155 void BytecodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) { |
2932 UNREACHABLE(); | 3156 UNREACHABLE(); |
2933 } | 3157 } |
2934 | 3158 |
| 3159 void BytecodeGenerator::VisitInternalVariable(InternalVariable* expr) { |
| 3160 switch (expr->type()) { |
| 3161 case InternalVariable::kGeneratorObject: |
| 3162 DCHECK(IsGeneratorFunction(info()->literal()->kind())); |
| 3163 builder()->LoadAccumulatorWithRegister(generator_object_); |
| 3164 return; |
| 3165 |
| 3166 default: |
| 3167 break; |
| 3168 } |
| 3169 |
| 3170 UNREACHABLE(); |
| 3171 } |
| 3172 |
2935 void BytecodeGenerator::VisitGetIterator(GetIterator* expr) { | 3173 void BytecodeGenerator::VisitGetIterator(GetIterator* expr) { |
2936 FeedbackVectorSlot load_slot = expr->IteratorPropertyFeedbackSlot(); | 3174 FeedbackVectorSlot load_slot = expr->IteratorPropertyFeedbackSlot(); |
2937 FeedbackVectorSlot call_slot = expr->IteratorCallFeedbackSlot(); | 3175 FeedbackVectorSlot call_slot = expr->IteratorCallFeedbackSlot(); |
2938 | 3176 |
2939 RegisterList args = register_allocator()->NewRegisterList(1); | 3177 RegisterList args = register_allocator()->NewRegisterList(1); |
2940 Register method = register_allocator()->NewRegister(); | 3178 Register method = register_allocator()->NewRegister(); |
2941 Register obj = args[0]; | 3179 Register obj = args[0]; |
2942 | 3180 |
2943 VisitForAccumulatorValue(expr->iterable()); | 3181 VisitForAccumulatorValue(expr->iterable()); |
2944 | 3182 |
(...skipping 430 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3375 } | 3613 } |
3376 | 3614 |
3377 Runtime::FunctionId BytecodeGenerator::StoreKeyedToSuperRuntimeId() { | 3615 Runtime::FunctionId BytecodeGenerator::StoreKeyedToSuperRuntimeId() { |
3378 return is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict | 3616 return is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict |
3379 : Runtime::kStoreKeyedToSuper_Sloppy; | 3617 : Runtime::kStoreKeyedToSuper_Sloppy; |
3380 } | 3618 } |
3381 | 3619 |
3382 } // namespace interpreter | 3620 } // namespace interpreter |
3383 } // namespace internal | 3621 } // namespace internal |
3384 } // namespace v8 | 3622 } // namespace v8 |
OLD | NEW |