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