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, generator_object_, |
| 799 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 BuildTryCatchFinally(HandlerTable::ASYNC_AWAIT, try_block, catch_block, |
| 856 finally_block); |
| 857 } else if (kIsGeneratorFunction) { |
| 858 BuildTryFinally(try_block, finally_block); |
| 859 } else { |
| 860 DCHECK(kIsModule); |
| 861 try_block(); |
| 862 } |
| 863 return; |
| 864 } |
| 865 |
742 // Visit statements in the function body. | 866 // Visit statements in the function body. |
| 867 if (parameter_init_block != nullptr) { |
| 868 VisitBlock(parameter_init_block); |
| 869 } |
743 VisitStatements(info()->literal()->body()); | 870 VisitStatements(info()->literal()->body()); |
744 } | 871 } |
745 | 872 |
746 void BytecodeGenerator::BuildIndexedJump(Register index, size_t start_index, | 873 void BytecodeGenerator::BuildIndexedJump(Register index, size_t start_index, |
747 size_t size, | 874 size_t size, |
748 ZoneVector<BytecodeLabel>& targets) { | 875 ZoneVector<BytecodeLabel>& targets) { |
749 // TODO(neis): Optimize this by using a proper jump table. | 876 // TODO(neis): Optimize this by using a proper jump table. |
750 DCHECK_LE(start_index + size, targets.size()); | 877 DCHECK_LE(start_index + size, targets.size()); |
751 for (size_t i = start_index; i < start_index + size; i++) { | 878 for (size_t i = start_index; i < start_index + size; i++) { |
752 builder() | 879 builder() |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
812 .PushContext(dummy) | 939 .PushContext(dummy) |
813 .ResumeGenerator(generator_object) | 940 .ResumeGenerator(generator_object) |
814 .StoreAccumulatorInRegister(generator_state_); | 941 .StoreAccumulatorInRegister(generator_state_); |
815 BuildIndexedJump(generator_state_, 0, generator_resume_points_.size(), | 942 BuildIndexedJump(generator_state_, 0, generator_resume_points_.size(), |
816 generator_resume_points_); | 943 generator_resume_points_); |
817 | 944 |
818 builder() | 945 builder() |
819 ->Bind(®ular_call) | 946 ->Bind(®ular_call) |
820 .LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)) | 947 .LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)) |
821 .StoreAccumulatorInRegister(generator_state_); | 948 .StoreAccumulatorInRegister(generator_state_); |
| 949 |
| 950 if (IsAsyncFunction(info()->literal()->kind())) { |
| 951 // Create initial async function promise |
| 952 RegisterAllocationScope register_scope(this); |
| 953 RegisterList args = register_allocator()->NewRegisterList(1); |
| 954 builder() |
| 955 ->LoadUndefined() |
| 956 .StoreAccumulatorInRegister(args[0]) |
| 957 .CallJSRuntime(Context::ASYNC_FUNCTION_PROMISE_CREATE_INDEX, args) |
| 958 .StoreAccumulatorInRegister(promise_); |
| 959 } |
| 960 |
822 // This is a regular call. Fall through to the ordinary function prologue, | 961 // 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 | 962 // after which we will run into the generator object creation and other extra |
824 // code inserted by the parser. | 963 // code inserted by the parser. |
825 } | 964 } |
826 | 965 |
827 void BytecodeGenerator::VisitBlock(Block* stmt) { | 966 void BytecodeGenerator::VisitBlock(Block* stmt) { |
828 // Visit declarations and statements. | 967 // Visit declarations and statements. |
829 if (stmt->scope() != nullptr && stmt->scope()->NeedsContext()) { | 968 if (stmt->scope() != nullptr && stmt->scope()->NeedsContext()) { |
830 BuildNewLocalBlockContext(stmt->scope()); | 969 BuildNewLocalBlockContext(stmt->scope()); |
831 ContextScope scope(this, stmt->scope()); | 970 ContextScope scope(this, stmt->scope()); |
(...skipping 495 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1327 VisitForEffect(stmt->next_result()); | 1466 VisitForEffect(stmt->next_result()); |
1328 VisitForAccumulatorValue(stmt->result_done()); | 1467 VisitForAccumulatorValue(stmt->result_done()); |
1329 loop_builder.BreakIfTrue(); | 1468 loop_builder.BreakIfTrue(); |
1330 | 1469 |
1331 VisitForEffect(stmt->assign_each()); | 1470 VisitForEffect(stmt->assign_each()); |
1332 VisitIterationBody(stmt, &loop_builder); | 1471 VisitIterationBody(stmt, &loop_builder); |
1333 loop_builder.JumpToHeader(loop_depth_); | 1472 loop_builder.JumpToHeader(loop_depth_); |
1334 loop_builder.EndLoop(); | 1473 loop_builder.EndLoop(); |
1335 } | 1474 } |
1336 | 1475 |
1337 void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { | 1476 void BytecodeGenerator::BuildTryCatch( |
1338 TryCatchBuilder try_control_builder(builder(), stmt->catch_prediction()); | 1477 HandlerTable::CatchPrediction catch_prediction, |
| 1478 std::function<void()> build_try, |
| 1479 std::function<void(Register)> build_catch) { |
| 1480 TryCatchBuilder try_control_builder(builder(), catch_prediction); |
1339 | 1481 |
1340 // Preserve the context in a dedicated register, so that it can be restored | 1482 // Preserve the context in a dedicated register, so that it can be restored |
1341 // when the handler is entered by the stack-unwinding machinery. | 1483 // when the handler is entered by the stack-unwinding machinery. |
1342 // TODO(mstarzinger): Be smarter about register allocation. | 1484 // TODO(mstarzinger): Be smarter about register allocation. |
1343 Register context = register_allocator()->NewRegister(); | 1485 Register context = register_allocator()->NewRegister(); |
1344 builder()->MoveRegister(Register::current_context(), context); | 1486 builder()->MoveRegister(Register::current_context(), context); |
1345 | 1487 |
1346 // Evaluate the try-block inside a control scope. This simulates a handler | 1488 // Evaluate the try-block inside a control scope. This simulates a handler |
1347 // that is intercepting 'throw' control commands. | 1489 // that is intercepting 'throw' control commands. |
1348 try_control_builder.BeginTry(context); | 1490 try_control_builder.BeginTry(context); |
1349 { | 1491 { |
1350 ControlScopeForTryCatch scope(this, &try_control_builder); | 1492 ControlScopeForTryCatch scope(this, &try_control_builder); |
1351 Visit(stmt->try_block()); | 1493 if (catch_prediction == HandlerTable::UNCAUGHT) { |
| 1494 catch_prediction = catch_prediction_; |
| 1495 } |
| 1496 ScopedAssignment<HandlerTable::CatchPrediction> prediction( |
| 1497 catch_prediction_, catch_prediction); |
| 1498 build_try(); |
1352 } | 1499 } |
1353 try_control_builder.EndTry(); | 1500 try_control_builder.EndTry(); |
1354 | 1501 |
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. | 1502 // Evaluate the catch-block. |
1368 VisitInScope(stmt->catch_block(), stmt->scope()); | 1503 build_catch(context); |
1369 try_control_builder.EndCatch(); | 1504 try_control_builder.EndCatch(); |
1370 } | 1505 } |
1371 | 1506 |
1372 void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { | 1507 void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { |
1373 TryFinallyBuilder try_control_builder(builder(), stmt->catch_prediction()); | 1508 BuildTryCatch(stmt->catch_prediction(), [=]() { Visit(stmt->try_block()); }, |
| 1509 [=](Register context) { |
| 1510 // Create a catch scope that binds the exception. |
| 1511 BuildNewLocalCatchContext(stmt->variable(), stmt->scope()); |
| 1512 builder()->StoreAccumulatorInRegister(context); |
| 1513 |
| 1514 // If requested, clear message object as we enter the catch |
| 1515 // block. |
| 1516 if (stmt->clear_pending_message()) { |
| 1517 builder()->LoadTheHole().SetPendingMessage(); |
| 1518 } |
| 1519 |
| 1520 // Load the catch context into the accumulator. |
| 1521 builder()->LoadAccumulatorWithRegister(context); |
| 1522 |
| 1523 VisitInScope(stmt->catch_block(), stmt->scope()); |
| 1524 }); |
| 1525 } |
| 1526 |
| 1527 void BytecodeGenerator::BuildTryFinally(std::function<void()> build_try, |
| 1528 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([=]() { Visit(stmt->try_block()); }, |
| 1592 [=]() { Visit(stmt->finally_block()); }); |
| 1593 } |
| 1594 |
| 1595 void BytecodeGenerator::BuildTryCatchFinally( |
| 1596 HandlerTable::CatchPrediction catch_prediction, |
| 1597 std::function<void()> build_try, std::function<void(Register)> build_catch, |
| 1598 std::function<void()> build_finally) { |
| 1599 BuildTryFinally( |
| 1600 [=]() { BuildTryCatch(catch_prediction, build_try, build_catch); }, |
| 1601 build_finally); |
| 1602 } |
| 1603 |
1434 void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) { | 1604 void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) { |
1435 builder()->SetStatementPosition(stmt); | 1605 builder()->SetStatementPosition(stmt); |
1436 builder()->Debugger(); | 1606 builder()->Debugger(); |
1437 } | 1607 } |
1438 | 1608 |
1439 void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { | 1609 void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { |
1440 uint8_t flags = CreateClosureFlags::Encode(expr->pretenure(), | 1610 uint8_t flags = CreateClosureFlags::Encode(expr->pretenure(), |
1441 scope()->is_function_scope()); | 1611 scope()->is_function_scope()); |
1442 size_t entry = builder()->AllocateConstantPoolEntry(); | 1612 size_t entry = builder()->AllocateConstantPoolEntry(); |
1443 int slot_index = feedback_index(expr->LiteralFeedbackSlot()); | 1613 int slot_index = feedback_index(expr->LiteralFeedbackSlot()); |
(...skipping 540 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1984 } | 2154 } |
1985 | 2155 |
1986 void BytecodeGenerator::BuildVariableLoadForAccumulatorValue( | 2156 void BytecodeGenerator::BuildVariableLoadForAccumulatorValue( |
1987 Variable* variable, FeedbackVectorSlot slot, HoleCheckMode hole_check_mode, | 2157 Variable* variable, FeedbackVectorSlot slot, HoleCheckMode hole_check_mode, |
1988 TypeofMode typeof_mode) { | 2158 TypeofMode typeof_mode) { |
1989 ValueResultScope accumulator_result(this); | 2159 ValueResultScope accumulator_result(this); |
1990 BuildVariableLoad(variable, slot, hole_check_mode, typeof_mode); | 2160 BuildVariableLoad(variable, slot, hole_check_mode, typeof_mode); |
1991 } | 2161 } |
1992 | 2162 |
1993 void BytecodeGenerator::BuildReturn() { | 2163 void BytecodeGenerator::BuildReturn() { |
1994 if (FLAG_trace) { | 2164 if (IsAsyncFunction(info()->literal()->kind())) { |
1995 RegisterAllocationScope register_scope(this); | 2165 RegisterList args = register_allocator()->NewRegisterList(3); |
1996 Register result = register_allocator()->NewRegister(); | 2166 Register receiver = args[0]; |
1997 // Runtime returns {result} value, preserving accumulator. | 2167 Register promise = args[1]; |
1998 builder()->StoreAccumulatorInRegister(result).CallRuntime( | 2168 Register return_value = args[2]; |
1999 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); |
2000 } | 2177 } |
| 2178 |
| 2179 BuildTraceExit(); |
2001 builder()->Return(); | 2180 builder()->Return(); |
2002 } | 2181 } |
2003 | 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 |
2004 void BytecodeGenerator::BuildReThrow() { builder()->ReThrow(); } | 2192 void BytecodeGenerator::BuildReThrow() { builder()->ReThrow(); } |
2005 | 2193 |
2006 void BytecodeGenerator::BuildAbort(BailoutReason bailout_reason) { | 2194 void BytecodeGenerator::BuildAbort(BailoutReason bailout_reason) { |
2007 RegisterAllocationScope register_scope(this); | 2195 RegisterAllocationScope register_scope(this); |
2008 Register reason = register_allocator()->NewRegister(); | 2196 Register reason = register_allocator()->NewRegister(); |
2009 builder() | 2197 builder() |
2010 ->LoadLiteral(Smi::FromInt(static_cast<int>(bailout_reason))) | 2198 ->LoadLiteral(Smi::FromInt(static_cast<int>(bailout_reason))) |
2011 .StoreAccumulatorInRegister(reason) | 2199 .StoreAccumulatorInRegister(reason) |
2012 .CallRuntime(Runtime::kAbort, reason); | 2200 .CallRuntime(Runtime::kAbort, reason); |
2013 } | 2201 } |
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2280 } | 2468 } |
2281 case KEYED_SUPER_PROPERTY: { | 2469 case KEYED_SUPER_PROPERTY: { |
2282 builder() | 2470 builder() |
2283 ->StoreAccumulatorInRegister(super_property_args[3]) | 2471 ->StoreAccumulatorInRegister(super_property_args[3]) |
2284 .CallRuntime(StoreKeyedToSuperRuntimeId(), super_property_args); | 2472 .CallRuntime(StoreKeyedToSuperRuntimeId(), super_property_args); |
2285 break; | 2473 break; |
2286 } | 2474 } |
2287 } | 2475 } |
2288 } | 2476 } |
2289 | 2477 |
2290 void BytecodeGenerator::VisitYield(Yield* expr) { | 2478 void BytecodeGenerator::BuildYieldResumePoint(int yield_id, |
2291 builder()->SetExpressionPosition(expr); | 2479 Yield::OnException on_exception, |
2292 Register value = VisitForRegisterValue(expr->expression()); | 2480 int position) { |
| 2481 DCHECK_GE(yield_id, 0); |
| 2482 DCHECK_LT(yield_id, generator_resume_points_.size()); |
2293 | 2483 |
2294 Register generator = VisitForRegisterValue(expr->generator_object()); | 2484 Register generator = generator_object_; |
| 2485 DCHECK(generator.is_valid()); |
2295 | 2486 |
2296 // Save context, registers, and state. Then return. | 2487 builder()->Bind(&(generator_resume_points_[yield_id])); |
2297 builder() | |
2298 ->LoadLiteral(Smi::FromInt(expr->yield_id())) | |
2299 .SuspendGenerator(generator) | |
2300 .LoadAccumulatorWithRegister(value) | |
2301 .Return(); // Hard return (ignore any finally blocks). | |
2302 | |
2303 builder()->Bind(&(generator_resume_points_[expr->yield_id()])); | |
2304 // Upon resume, we continue here. | 2488 // Upon resume, we continue here. |
2305 | 2489 |
2306 { | 2490 { |
2307 RegisterAllocationScope register_scope(this); | 2491 RegisterAllocationScope register_scope(this); |
2308 | 2492 |
2309 // Update state to indicate that we have finished resuming. Loop headers | 2493 // Update state to indicate that we have finished resuming. Loop headers |
2310 // rely on this. | 2494 // rely on this. |
2311 builder() | 2495 builder() |
2312 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)) | 2496 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)) |
2313 .StoreAccumulatorInRegister(generator_state_); | 2497 .StoreAccumulatorInRegister(generator_state_); |
(...skipping 28 matching lines...) Expand all Loading... |
2342 RegisterList args = register_allocator()->NewRegisterList(2); | 2526 RegisterList args = register_allocator()->NewRegisterList(2); |
2343 builder() | 2527 builder() |
2344 ->MoveRegister(input, args[0]) | 2528 ->MoveRegister(input, args[0]) |
2345 .LoadTrue() | 2529 .LoadTrue() |
2346 .StoreAccumulatorInRegister(args[1]) | 2530 .StoreAccumulatorInRegister(args[1]) |
2347 .CallRuntime(Runtime::kInlineCreateIterResultObject, args); | 2531 .CallRuntime(Runtime::kInlineCreateIterResultObject, args); |
2348 execution_control()->ReturnAccumulator(); | 2532 execution_control()->ReturnAccumulator(); |
2349 } | 2533 } |
2350 | 2534 |
2351 builder()->Bind(&resume_with_throw); | 2535 builder()->Bind(&resume_with_throw); |
2352 builder()->SetExpressionPosition(expr); | 2536 builder()->SetExpressionPosition(position); |
2353 builder()->LoadAccumulatorWithRegister(input); | 2537 builder()->LoadAccumulatorWithRegister(input); |
2354 if (expr->rethrow_on_exception()) { | 2538 if (on_exception == Yield::kOnExceptionRethrow) { |
2355 builder()->ReThrow(); | 2539 builder()->ReThrow(); |
2356 } else { | 2540 } else { |
2357 builder()->Throw(); | 2541 builder()->Throw(); |
2358 } | 2542 } |
2359 | 2543 |
2360 builder()->Bind(&resume_with_next); | 2544 builder()->Bind(&resume_with_next); |
2361 builder()->LoadAccumulatorWithRegister(input); | 2545 builder()->LoadAccumulatorWithRegister(input); |
2362 } | 2546 } |
2363 } | 2547 } |
2364 | 2548 |
| 2549 void BytecodeGenerator::BuildYield(int yield_id, |
| 2550 Yield::OnException on_exception, |
| 2551 Register value, int position) { |
| 2552 DCHECK_GE(yield_id, 0); |
| 2553 DCHECK_LT(yield_id, generator_resume_points_.size()); |
| 2554 |
| 2555 Register generator = generator_object_; |
| 2556 DCHECK(generator.is_valid()); |
| 2557 |
| 2558 // Save context, registers, and state. Then return. |
| 2559 builder() |
| 2560 ->LoadLiteral(Smi::FromInt(yield_id)) |
| 2561 .SuspendGenerator(generator) |
| 2562 .LoadAccumulatorWithRegister(value) |
| 2563 .Return(); // Hard return (ignore any finally blocks). |
| 2564 |
| 2565 BuildYieldResumePoint(yield_id, on_exception, position); |
| 2566 } |
| 2567 |
| 2568 void BytecodeGenerator::BuildAwait(int yield_id, |
| 2569 Yield::OnException on_exception, |
| 2570 Register value, int position) { |
| 2571 DCHECK_GE(yield_id, 0); |
| 2572 DCHECK_LT(yield_id, generator_resume_points_.size()); |
| 2573 |
| 2574 Register generator = generator_object_; |
| 2575 DCHECK(generator.is_valid()); |
| 2576 |
| 2577 int context_index = Context::ASYNC_FUNCTION_AWAIT_CAUGHT_INDEX; |
| 2578 if (catch_prediction_ == HandlerTable::ASYNC_AWAIT) { |
| 2579 context_index = Context::ASYNC_FUNCTION_AWAIT_UNCAUGHT_INDEX; |
| 2580 } |
| 2581 |
| 2582 { |
| 2583 RegisterAllocationScope register_scope(this); |
| 2584 RegisterList args = register_allocator()->NewRegisterList(4); |
| 2585 builder()->SetStatementPosition(position); |
| 2586 builder() |
| 2587 ->LoadUndefined() |
| 2588 .StoreAccumulatorInRegister(args[0]) |
| 2589 .MoveRegister(generator, args[1]) |
| 2590 .MoveRegister(value, args[2]) |
| 2591 .MoveRegister(promise_, args[3]) |
| 2592 .CallJSRuntime(context_index, args) |
| 2593 .LoadLiteral(Smi::FromInt(yield_id)) |
| 2594 .SuspendGenerator(generator) |
| 2595 .LoadAccumulatorWithRegister(promise_) |
| 2596 .Return(); // Hard return (ignore any finally blocks) |
| 2597 } |
| 2598 |
| 2599 BuildYieldResumePoint(yield_id, on_exception, kNoSourcePosition); |
| 2600 } |
| 2601 |
| 2602 void BytecodeGenerator::VisitYield(Yield* expr) { |
| 2603 if (expr->yield_type() == Yield::kAwait) { |
| 2604 builder()->SetExpressionPosition(kNoSourcePosition); |
| 2605 builder()->SetStatementPosition(expr->expression()->position()); |
| 2606 Register value = VisitForRegisterValue(expr->expression()); |
| 2607 BuildAwait(expr->yield_id(), expr->on_exception(), value, expr->position()); |
| 2608 } else { |
| 2609 builder()->SetExpressionPosition(expr); |
| 2610 Register value = VisitForRegisterValue(expr->expression()); |
| 2611 BuildYield(expr->yield_id(), expr->on_exception(), value, expr->position()); |
| 2612 } |
| 2613 } |
| 2614 |
2365 void BytecodeGenerator::VisitThrow(Throw* expr) { | 2615 void BytecodeGenerator::VisitThrow(Throw* expr) { |
2366 VisitForAccumulatorValue(expr->exception()); | 2616 VisitForAccumulatorValue(expr->exception()); |
2367 builder()->SetExpressionPosition(expr); | 2617 builder()->SetExpressionPosition(expr); |
2368 builder()->Throw(); | 2618 builder()->Throw(); |
2369 } | 2619 } |
2370 | 2620 |
2371 void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) { | 2621 void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) { |
2372 LhsKind property_kind = Property::GetAssignType(expr); | 2622 LhsKind property_kind = Property::GetAssignType(expr); |
2373 FeedbackVectorSlot slot = expr->PropertyFeedbackSlot(); | 2623 FeedbackVectorSlot slot = expr->PropertyFeedbackSlot(); |
2374 builder()->SetExpressionPosition(expr); | 2624 builder()->SetExpressionPosition(expr); |
(...skipping 552 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2927 builder()->SetExpressionPosition(expr); | 3177 builder()->SetExpressionPosition(expr); |
2928 builder()->BinaryOperation(expr->op(), lhs, feedback_index(slot)); | 3178 builder()->BinaryOperation(expr->op(), lhs, feedback_index(slot)); |
2929 } | 3179 } |
2930 | 3180 |
2931 void BytecodeGenerator::VisitSpread(Spread* expr) { Visit(expr->expression()); } | 3181 void BytecodeGenerator::VisitSpread(Spread* expr) { Visit(expr->expression()); } |
2932 | 3182 |
2933 void BytecodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) { | 3183 void BytecodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) { |
2934 UNREACHABLE(); | 3184 UNREACHABLE(); |
2935 } | 3185 } |
2936 | 3186 |
| 3187 void BytecodeGenerator::VisitInternalVariable(InternalVariable* expr) { |
| 3188 switch (expr->type()) { |
| 3189 case InternalVariable::kGeneratorObject: |
| 3190 DCHECK(IsGeneratorFunction(info()->literal()->kind())); |
| 3191 builder()->LoadAccumulatorWithRegister(generator_object_); |
| 3192 return; |
| 3193 |
| 3194 default: |
| 3195 break; |
| 3196 } |
| 3197 |
| 3198 UNREACHABLE(); |
| 3199 } |
| 3200 |
2937 void BytecodeGenerator::VisitGetIterator(GetIterator* expr) { | 3201 void BytecodeGenerator::VisitGetIterator(GetIterator* expr) { |
2938 FeedbackVectorSlot load_slot = expr->IteratorPropertyFeedbackSlot(); | 3202 FeedbackVectorSlot load_slot = expr->IteratorPropertyFeedbackSlot(); |
2939 FeedbackVectorSlot call_slot = expr->IteratorCallFeedbackSlot(); | 3203 FeedbackVectorSlot call_slot = expr->IteratorCallFeedbackSlot(); |
2940 | 3204 |
2941 RegisterList args = register_allocator()->NewRegisterList(1); | 3205 RegisterList args = register_allocator()->NewRegisterList(1); |
2942 Register method = register_allocator()->NewRegister(); | 3206 Register method = register_allocator()->NewRegister(); |
2943 Register obj = args[0]; | 3207 Register obj = args[0]; |
2944 | 3208 |
2945 VisitForAccumulatorValue(expr->iterable()); | 3209 VisitForAccumulatorValue(expr->iterable()); |
2946 | 3210 |
(...skipping 430 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3377 } | 3641 } |
3378 | 3642 |
3379 Runtime::FunctionId BytecodeGenerator::StoreKeyedToSuperRuntimeId() { | 3643 Runtime::FunctionId BytecodeGenerator::StoreKeyedToSuperRuntimeId() { |
3380 return is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict | 3644 return is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict |
3381 : Runtime::kStoreKeyedToSuper_Sloppy; | 3645 : Runtime::kStoreKeyedToSuper_Sloppy; |
3382 } | 3646 } |
3383 | 3647 |
3384 } // namespace interpreter | 3648 } // namespace interpreter |
3385 } // namespace internal | 3649 } // namespace internal |
3386 } // namespace v8 | 3650 } // namespace v8 |
OLD | NEW |