OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/flow_graph_builder.h" | 5 #include "vm/flow_graph_builder.h" |
6 | 6 |
7 #include "lib/invocation_mirror.h" | 7 #include "lib/invocation_mirror.h" |
8 #include "vm/ast_printer.h" | 8 #include "vm/ast_printer.h" |
9 #include "vm/bit_vector.h" | 9 #include "vm/bit_vector.h" |
10 #include "vm/class_finalizer.h" | 10 #include "vm/class_finalizer.h" |
(...skipping 1057 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1068 | 1068 |
1069 // Async functions contain two types of return statements: | 1069 // Async functions contain two types of return statements: |
1070 // 1) Returns that should complete the completer once all finally blocks have | 1070 // 1) Returns that should complete the completer once all finally blocks have |
1071 // been inlined (call: :async_completer.complete(return_value)). These | 1071 // been inlined (call: :async_completer.complete(return_value)). These |
1072 // returns end up returning null in the end. | 1072 // returns end up returning null in the end. |
1073 // 2) "Continuation" returns that should not complete the completer but return | 1073 // 2) "Continuation" returns that should not complete the completer but return |
1074 // the value. | 1074 // the value. |
1075 // | 1075 // |
1076 // We distinguish those kinds of nodes via is_regular_return(). | 1076 // We distinguish those kinds of nodes via is_regular_return(). |
1077 // | 1077 // |
1078 if (function.is_async_closure() && | 1078 if (function.IsAsyncClosure() && |
1079 (node->return_type() == ReturnNode::kRegular)) { | 1079 (node->return_type() == ReturnNode::kRegular)) { |
1080 // Temporary store the computed return value. | 1080 // Temporary store the computed return value. |
1081 Do(BuildStoreExprTemp(return_value)); | 1081 Do(BuildStoreExprTemp(return_value)); |
1082 | 1082 |
1083 LocalVariable* rcv_var = node->scope()->LookupVariable( | 1083 LocalVariable* rcv_var = |
1084 Symbols::AsyncCompleter(), false); | 1084 node->scope()->LookupVariable(Symbols::AsyncCompleter(), false); |
1085 ASSERT(rcv_var != NULL && rcv_var->is_captured()); | 1085 ASSERT(rcv_var != NULL && rcv_var->is_captured()); |
1086 ZoneGrowableArray<PushArgumentInstr*>* arguments = | 1086 ZoneGrowableArray<PushArgumentInstr*>* arguments = |
1087 new(I) ZoneGrowableArray<PushArgumentInstr*>(2); | 1087 new(I) ZoneGrowableArray<PushArgumentInstr*>(2); |
1088 Value* rcv_value = Bind(BuildLoadLocal(*rcv_var)); | 1088 Value* rcv_value = Bind(BuildLoadLocal(*rcv_var)); |
1089 arguments->Add(PushArgument(rcv_value)); | 1089 arguments->Add(PushArgument(rcv_value)); |
1090 Value* returned_value = Bind(BuildLoadExprTemp()); | 1090 Value* returned_value = Bind(BuildLoadExprTemp()); |
1091 arguments->Add(PushArgument(returned_value)); | 1091 arguments->Add(PushArgument(returned_value)); |
1092 InstanceCallInstr* call = new(I) InstanceCallInstr( | 1092 InstanceCallInstr* call = new(I) InstanceCallInstr( |
1093 Scanner::kNoSourcePos, | 1093 Scanner::kNoSourcePos, |
1094 Symbols::CompleterComplete(), | 1094 Symbols::CompleterComplete(), |
1095 Token::kILLEGAL, | 1095 Token::kILLEGAL, |
1096 arguments, | 1096 arguments, |
1097 Object::null_array(), | 1097 Object::null_array(), |
1098 1, | 1098 1, |
1099 owner()->ic_data_array()); | 1099 owner()->ic_data_array()); |
1100 Do(call); | 1100 Do(call); |
1101 | 1101 |
1102 // Rebind the return value for the actual return call to be null. | 1102 // Rebind the return value for the actual return call to be null. |
1103 return_value = BuildNullValue(); | 1103 return_value = BuildNullValue(); |
1104 } | 1104 } |
1105 | 1105 |
1106 intptr_t current_context_level = owner()->context_level(); | 1106 intptr_t current_context_level = owner()->context_level(); |
1107 ASSERT(current_context_level >= 0); | 1107 ASSERT(current_context_level >= 0); |
1108 if (HasContextScope()) { | 1108 if (HasContextScope()) { |
1109 UnchainContexts(current_context_level); | 1109 UnchainContexts(current_context_level); |
1110 } | 1110 } |
1111 | 1111 |
1112 | |
1113 AddReturnExit(node->token_pos(), return_value); | 1112 AddReturnExit(node->token_pos(), return_value); |
1114 | 1113 |
1115 if (function.is_async_closure() && | 1114 if ((function.IsAsyncClosure() || function.IsSyncGenClosure()) && |
1116 (node->return_type() == ReturnNode::kContinuationTarget)) { | 1115 (node->return_type() == ReturnNode::kContinuationTarget)) { |
1117 JoinEntryInstr* const join = new(I) JoinEntryInstr( | 1116 JoinEntryInstr* const join = new(I) JoinEntryInstr( |
1118 owner()->AllocateBlockId(), owner()->try_index()); | 1117 owner()->AllocateBlockId(), owner()->try_index()); |
1119 owner()->await_joins()->Add(join); | 1118 owner()->await_joins()->Add(join); |
1120 exit_ = join; | 1119 exit_ = join; |
1121 } | 1120 } |
1122 } | 1121 } |
1123 | 1122 |
1124 | 1123 |
1125 // <Expression> ::= Literal { literal: Instance } | 1124 // <Expression> ::= Literal { literal: Instance } |
(...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1477 return new(I) AssertAssignableInstr(token_pos, | 1476 return new(I) AssertAssignableInstr(token_pos, |
1478 value, | 1477 value, |
1479 instantiator, | 1478 instantiator, |
1480 instantiator_type_arguments, | 1479 instantiator_type_arguments, |
1481 dst_type, | 1480 dst_type, |
1482 dst_name, | 1481 dst_name, |
1483 deopt_id); | 1482 deopt_id); |
1484 } | 1483 } |
1485 | 1484 |
1486 | 1485 |
| 1486 void EffectGraphVisitor::BuildYieldJump(LocalVariable* old_context, |
| 1487 LocalVariable* iterator_param, |
| 1488 const intptr_t old_ctx_level, |
| 1489 JoinEntryInstr* target) { |
| 1490 // Building a jump consists of the following actions: |
| 1491 // * Load the generator body's iterator parameter (:iterator) |
| 1492 // from the current context into a temporary. |
| 1493 // * Restore the old context from :await_cxt_var. |
| 1494 // * Copy the iterator saved above into the restored context. |
| 1495 // * Append a Goto to the target's join. |
| 1496 ASSERT((iterator_param != NULL) && iterator_param->is_captured()); |
| 1497 ASSERT((old_context != NULL) && old_context->is_captured()); |
| 1498 // Before restoring the context we need to temporarily save the |
| 1499 // iterator parameter. |
| 1500 LocalVariable* temp_iterator_var = |
| 1501 EnterTempLocalScope(Bind(BuildLoadLocal(*iterator_param))); |
| 1502 |
| 1503 // Restore the saved continuation context, i.e. the context that was |
| 1504 // saved into :await_ctx_var before the closure suspended. |
| 1505 BuildRestoreContext(*old_context); |
| 1506 |
| 1507 // Store the continuation result and continuation error values into |
| 1508 // the restored context. |
| 1509 |
| 1510 // FlowGraphBuilder is at top context level, but the continuation |
| 1511 // target has possibly been recorded in a nested context (old_ctx_level). |
| 1512 // We need to unroll manually here. |
| 1513 intptr_t delta = |
| 1514 old_ctx_level - iterator_param->owner()->context_level(); |
| 1515 ASSERT(delta >= 0); |
| 1516 Value* context = Bind(BuildCurrentContext()); |
| 1517 while (delta-- > 0) { |
| 1518 context = Bind(new(I) LoadFieldInstr( |
| 1519 context, Context::parent_offset(), Type::ZoneHandle(I, Type::null()), |
| 1520 Scanner::kNoSourcePos)); |
| 1521 } |
| 1522 LocalVariable* temp_context_var = EnterTempLocalScope(context); |
| 1523 |
| 1524 Value* context_val = Bind(new(I) LoadLocalInstr(*temp_context_var)); |
| 1525 Value* store_val = Bind(new(I) LoadLocalInstr(*temp_iterator_var)); |
| 1526 StoreInstanceFieldInstr* store = new(I) StoreInstanceFieldInstr( |
| 1527 Context::variable_offset(iterator_param->index()), |
| 1528 context_val, |
| 1529 store_val, |
| 1530 kEmitStoreBarrier, |
| 1531 Scanner::kNoSourcePos); |
| 1532 Do(store); |
| 1533 |
| 1534 Do(ExitTempLocalScope(temp_context_var)); |
| 1535 Do(ExitTempLocalScope(temp_iterator_var)); |
| 1536 |
| 1537 // Goto saved join. |
| 1538 Goto(target); |
| 1539 } |
| 1540 |
| 1541 |
1487 void EffectGraphVisitor::BuildAwaitJump(LocalVariable* old_context, | 1542 void EffectGraphVisitor::BuildAwaitJump(LocalVariable* old_context, |
1488 LocalVariable* continuation_result, | 1543 LocalVariable* continuation_result, |
1489 LocalVariable* continuation_error, | 1544 LocalVariable* continuation_error, |
1490 LocalVariable* continuation_stack_trace, | 1545 LocalVariable* continuation_stack_trace, |
1491 const intptr_t old_ctx_level, | 1546 const intptr_t old_ctx_level, |
1492 JoinEntryInstr* target) { | 1547 JoinEntryInstr* target) { |
1493 // Building a jump consists of the following actions: | 1548 // Building a jump consists of the following actions: |
1494 // * Record the current continuation result in a temporary. | 1549 // * Load the current continuation result parameter (:async_result) |
1495 // * Restore the old context. | 1550 // and continuation error parameter (:async_error_param) from |
1496 // * Overwrite the old context's continuation result with the temporary. | 1551 // the current context into temporaries. |
| 1552 // * Restore the old context from :await_cxt_var. |
| 1553 // * Copy the result and error parameters saved above into the restored |
| 1554 // context. |
1497 // * Append a Goto to the target's join. | 1555 // * Append a Goto to the target's join. |
1498 ASSERT((continuation_result != NULL) && continuation_result->is_captured()); | 1556 ASSERT((continuation_result != NULL) && continuation_result->is_captured()); |
1499 ASSERT((continuation_error != NULL) && continuation_error->is_captured()); | 1557 ASSERT((continuation_error != NULL) && continuation_error->is_captured()); |
1500 ASSERT((old_context != NULL) && old_context->is_captured()); | 1558 ASSERT((old_context != NULL) && old_context->is_captured()); |
1501 // Before restoring the continuation context we need to temporary save the | 1559 // Before restoring the continuation context we need to temporary save the |
1502 // result and error parameter. | 1560 // result and error parameter. |
1503 LocalVariable* temp_result_var = EnterTempLocalScope( | 1561 LocalVariable* temp_result_var = |
1504 Bind(BuildLoadLocal(*continuation_result))); | 1562 EnterTempLocalScope(Bind(BuildLoadLocal(*continuation_result))); |
1505 LocalVariable* temp_error_var = EnterTempLocalScope( | 1563 LocalVariable* temp_error_var = |
1506 Bind(BuildLoadLocal(*continuation_error))); | 1564 EnterTempLocalScope(Bind(BuildLoadLocal(*continuation_error))); |
1507 LocalVariable* temp_stack_trace_var = EnterTempLocalScope( | 1565 LocalVariable* temp_stack_trace_var = |
1508 Bind(BuildLoadLocal(*continuation_stack_trace))); | 1566 EnterTempLocalScope(Bind(BuildLoadLocal(*continuation_stack_trace))); |
1509 // Restore the saved continuation context. | 1567 |
| 1568 // Restore the saved continuation context, i.e. the context that was |
| 1569 // saved into :await_ctx_var before the closure suspended. |
1510 BuildRestoreContext(*old_context); | 1570 BuildRestoreContext(*old_context); |
1511 | 1571 |
1512 // Pass over the continuation result. | 1572 // Store the continuation result and continuation error values into |
| 1573 // the restored context. |
1513 | 1574 |
1514 // FlowGraphBuilder is at top context level, but the await target has possibly | 1575 // FlowGraphBuilder is at top context level, but the await target has possibly |
1515 // been recorded in a nested context (old_ctx_level). We need to unroll | 1576 // been recorded in a nested context (old_ctx_level). We need to unroll |
1516 // manually here. | 1577 // manually here. |
1517 intptr_t delta = old_ctx_level - | 1578 intptr_t delta = |
1518 continuation_result->owner()->context_level(); | 1579 old_ctx_level - continuation_result->owner()->context_level(); |
1519 ASSERT(delta >= 0); | 1580 ASSERT(delta >= 0); |
1520 Value* context = Bind(BuildCurrentContext()); | 1581 Value* context = Bind(BuildCurrentContext()); |
1521 while (delta-- > 0) { | 1582 while (delta-- > 0) { |
1522 context = Bind(new(I) LoadFieldInstr( | 1583 context = Bind(new(I) LoadFieldInstr( |
1523 context, Context::parent_offset(), Type::ZoneHandle(I, Type::null()), | 1584 context, Context::parent_offset(), Type::ZoneHandle(I, Type::null()), |
1524 Scanner::kNoSourcePos)); | 1585 Scanner::kNoSourcePos)); |
1525 } | 1586 } |
1526 LocalVariable* temp_context_var = EnterTempLocalScope(context); | 1587 LocalVariable* temp_context_var = EnterTempLocalScope(context); |
1527 | 1588 |
1528 Value* context_val = Bind(new(I) LoadLocalInstr(*temp_context_var)); | 1589 Value* context_val = Bind(new(I) LoadLocalInstr(*temp_context_var)); |
(...skipping 2166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3695 Do(BuildStoreContext(context)); | 3756 Do(BuildStoreContext(context)); |
3696 } | 3757 } |
3697 } | 3758 } |
3698 | 3759 |
3699 | 3760 |
3700 // <Statement> ::= Sequence { scope: LocalScope | 3761 // <Statement> ::= Sequence { scope: LocalScope |
3701 // nodes: <Statement>* | 3762 // nodes: <Statement>* |
3702 // label: SourceLabel } | 3763 // label: SourceLabel } |
3703 void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) { | 3764 void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) { |
3704 LocalScope* scope = node->scope(); | 3765 LocalScope* scope = node->scope(); |
| 3766 const Function& function = owner()->function(); |
3705 const intptr_t num_context_variables = | 3767 const intptr_t num_context_variables = |
3706 (scope != NULL) ? scope->num_context_variables() : 0; | 3768 (scope != NULL) ? scope->num_context_variables() : 0; |
3707 const bool is_top_level_sequence = | 3769 const bool is_top_level_sequence = |
3708 node == owner()->parsed_function().node_sequence(); | 3770 node == owner()->parsed_function().node_sequence(); |
3709 // The outermost function sequence cannot contain a label. | 3771 // The outermost function sequence cannot contain a label. |
3710 ASSERT((node->label() == NULL) || !is_top_level_sequence); | 3772 ASSERT((node->label() == NULL) || !is_top_level_sequence); |
3711 NestedBlock nested_block(owner(), node); | 3773 NestedBlock nested_block(owner(), node); |
3712 | 3774 |
3713 if (num_context_variables > 0) { | 3775 if (num_context_variables > 0) { |
3714 // The local scope declares variables that are captured. | 3776 // The local scope declares variables that are captured. |
(...skipping 12 matching lines...) Expand all Loading... |
3727 kEmitStoreBarrier, | 3789 kEmitStoreBarrier, |
3728 Scanner::kNoSourcePos)); | 3790 Scanner::kNoSourcePos)); |
3729 } | 3791 } |
3730 Do(BuildStoreContext(Bind(ExitTempLocalScope(tmp_var)))); | 3792 Do(BuildStoreContext(Bind(ExitTempLocalScope(tmp_var)))); |
3731 } | 3793 } |
3732 | 3794 |
3733 // If this node_sequence is the body of the function being compiled, copy | 3795 // If this node_sequence is the body of the function being compiled, copy |
3734 // the captured parameters from the frame into the context. | 3796 // the captured parameters from the frame into the context. |
3735 if (is_top_level_sequence) { | 3797 if (is_top_level_sequence) { |
3736 ASSERT(scope->context_level() == 1); | 3798 ASSERT(scope->context_level() == 1); |
3737 const Function& function = owner()->function(); | |
3738 const int num_params = function.NumParameters(); | 3799 const int num_params = function.NumParameters(); |
3739 int param_frame_index = (num_params == function.num_fixed_parameters()) ? | 3800 int param_frame_index = (num_params == function.num_fixed_parameters()) ? |
3740 (kParamEndSlotFromFp + num_params) : kFirstLocalSlotFromFp; | 3801 (kParamEndSlotFromFp + num_params) : kFirstLocalSlotFromFp; |
3741 for (int pos = 0; pos < num_params; param_frame_index--, pos++) { | 3802 for (int pos = 0; pos < num_params; param_frame_index--, pos++) { |
3742 const LocalVariable& parameter = *scope->VariableAt(pos); | 3803 const LocalVariable& parameter = *scope->VariableAt(pos); |
3743 ASSERT(parameter.owner() == scope); | 3804 ASSERT(parameter.owner() == scope); |
3744 if (parameter.is_captured()) { | 3805 if (parameter.is_captured()) { |
3745 // Create a temporary local describing the original position. | 3806 // Create a temporary local describing the original position. |
3746 const String& temp_name = Symbols::TempParam(); | 3807 const String& temp_name = Symbols::TempParam(); |
3747 LocalVariable* temp_local = new(I) LocalVariable( | 3808 LocalVariable* temp_local = new(I) LocalVariable( |
(...skipping 17 matching lines...) Expand all Loading... |
3765 Value* null_constant = Bind(new(I) ConstantInstr( | 3826 Value* null_constant = Bind(new(I) ConstantInstr( |
3766 Object::ZoneHandle(I, Object::null()))); | 3827 Object::ZoneHandle(I, Object::null()))); |
3767 Do(BuildStoreLocal(*temp_local, null_constant)); | 3828 Do(BuildStoreLocal(*temp_local, null_constant)); |
3768 } | 3829 } |
3769 } | 3830 } |
3770 } | 3831 } |
3771 } | 3832 } |
3772 | 3833 |
3773 // This check may be deleted if the generated code is leaf. | 3834 // This check may be deleted if the generated code is leaf. |
3774 // Native functions don't need a stack check at entry. | 3835 // Native functions don't need a stack check at entry. |
3775 const Function& function = owner()->function(); | |
3776 if (is_top_level_sequence && !function.is_native()) { | 3836 if (is_top_level_sequence && !function.is_native()) { |
3777 // Always allocate CheckOverflowInstr so that deopt-ids match regardless | 3837 // Always allocate CheckOverflowInstr so that deopt-ids match regardless |
3778 // if we inline or not. | 3838 // if we inline or not. |
3779 if (!function.IsImplicitGetterFunction() && | 3839 if (!function.IsImplicitGetterFunction() && |
3780 !function.IsImplicitSetterFunction()) { | 3840 !function.IsImplicitSetterFunction()) { |
3781 CheckStackOverflowInstr* check = | 3841 CheckStackOverflowInstr* check = |
3782 new(I) CheckStackOverflowInstr(function.token_pos(), 0); | 3842 new(I) CheckStackOverflowInstr(function.token_pos(), 0); |
3783 // If we are inlining don't actually attach the stack check. We must still | 3843 // If we are inlining don't actually attach the stack check. We must still |
3784 // create the stack check in order to allocate a deopt id. | 3844 // create the stack check in order to allocate a deopt id. |
3785 if (!owner()->IsInlining()) { | 3845 if (!owner()->IsInlining()) { |
3786 AddInstruction(check); | 3846 AddInstruction(check); |
3787 } | 3847 } |
3788 } | 3848 } |
3789 } | 3849 } |
3790 | 3850 |
3791 if (Isolate::Current()->TypeChecksEnabled() && is_top_level_sequence) { | 3851 if (Isolate::Current()->TypeChecksEnabled() && is_top_level_sequence) { |
3792 const Function& function = owner()->function(); | |
3793 const int num_params = function.NumParameters(); | 3852 const int num_params = function.NumParameters(); |
3794 int pos = 0; | 3853 int pos = 0; |
3795 if (function.IsConstructor()) { | 3854 if (function.IsConstructor()) { |
3796 // Skip type checking of receiver and phase for constructor functions. | 3855 // Skip type checking of receiver and phase for constructor functions. |
3797 pos = 2; | 3856 pos = 2; |
3798 } else if (function.IsFactory() || function.IsDynamicFunction()) { | 3857 } else if (function.IsFactory() || function.IsDynamicFunction()) { |
3799 // Skip type checking of type arguments for factory functions. | 3858 // Skip type checking of type arguments for factory functions. |
3800 // Skip type checking of receiver for instance functions. | 3859 // Skip type checking of receiver for instance functions. |
3801 pos = 1; | 3860 pos = 1; |
3802 } | 3861 } |
3803 while (pos < num_params) { | 3862 while (pos < num_params) { |
3804 const LocalVariable& parameter = *scope->VariableAt(pos); | 3863 const LocalVariable& parameter = *scope->VariableAt(pos); |
3805 ASSERT(parameter.owner() == scope); | 3864 ASSERT(parameter.owner() == scope); |
3806 if (!CanSkipTypeCheck(parameter.token_pos(), | 3865 if (!CanSkipTypeCheck(parameter.token_pos(), |
3807 NULL, | 3866 NULL, |
3808 parameter.type(), | 3867 parameter.type(), |
3809 parameter.name())) { | 3868 parameter.name())) { |
3810 Value* parameter_value = Bind(BuildLoadLocal(parameter)); | 3869 Value* parameter_value = Bind(BuildLoadLocal(parameter)); |
3811 Do(BuildAssertAssignable(parameter.token_pos(), | 3870 Do(BuildAssertAssignable(parameter.token_pos(), |
3812 parameter_value, | 3871 parameter_value, |
3813 parameter.type(), | 3872 parameter.type(), |
3814 parameter.name())); | 3873 parameter.name())); |
3815 } | 3874 } |
3816 pos++; | 3875 pos++; |
3817 } | 3876 } |
3818 } | 3877 } |
3819 | 3878 |
3820 // Continuation part: | 3879 // Continuation part: |
3821 // If this node sequence is the body of an async closure leave room for a | 3880 // If this node sequence is the body of a function with continuations, |
3822 // preamble. The preamble is generated after visiting the body. | 3881 // leave room for a preamble. |
| 3882 // The preamble is generated after visiting the body. |
3823 GotoInstr* preamble_start = NULL; | 3883 GotoInstr* preamble_start = NULL; |
3824 if (is_top_level_sequence && (owner()->function().is_async_closure())) { | 3884 if (is_top_level_sequence && |
| 3885 (function.IsAsyncClosure() || function.IsSyncGenClosure())) { |
3825 JoinEntryInstr* preamble_end = new(I) JoinEntryInstr( | 3886 JoinEntryInstr* preamble_end = new(I) JoinEntryInstr( |
3826 owner()->AllocateBlockId(), owner()->try_index()); | 3887 owner()->AllocateBlockId(), owner()->try_index()); |
3827 ASSERT(exit() != NULL); | 3888 ASSERT(exit() != NULL); |
3828 exit()->Goto(preamble_end); | 3889 exit()->Goto(preamble_end); |
3829 ASSERT(exit()->next()->IsGoto()); | 3890 ASSERT(exit()->next()->IsGoto()); |
3830 preamble_start = exit()->next()->AsGoto(); | 3891 preamble_start = exit()->next()->AsGoto(); |
3831 ASSERT(preamble_start->IsGoto()); | 3892 ASSERT(preamble_start->IsGoto()); |
3832 exit_ = preamble_end; | 3893 exit_ = preamble_end; |
3833 } | 3894 } |
3834 | 3895 |
3835 intptr_t i = 0; | 3896 intptr_t i = 0; |
3836 while (is_open() && (i < node->length())) { | 3897 while (is_open() && (i < node->length())) { |
3837 EffectGraphVisitor for_effect(owner()); | 3898 EffectGraphVisitor for_effect(owner()); |
3838 node->NodeAt(i++)->Visit(&for_effect); | 3899 node->NodeAt(i++)->Visit(&for_effect); |
3839 Append(for_effect); | 3900 Append(for_effect); |
3840 if (!is_open()) { | 3901 if (!is_open()) { |
3841 // E.g., because of a JumpNode. | 3902 // E.g., because of a JumpNode. |
3842 break; | 3903 break; |
3843 } | 3904 } |
3844 } | 3905 } |
3845 | 3906 |
3846 // Continuation part: | 3907 // Continuation part: |
3847 // After generating the CFG for the body we can create the preamble because we | 3908 // After generating the CFG for the body we can create the preamble |
3848 // know exactly how many continuation states we need. | 3909 // because we know exactly how many continuation states we need. |
3849 if (is_top_level_sequence && (owner()->function().is_async_closure())) { | 3910 if (is_top_level_sequence && |
| 3911 (function.IsAsyncClosure() || function.IsSyncGenClosure())) { |
3850 ASSERT(preamble_start != NULL); | 3912 ASSERT(preamble_start != NULL); |
3851 // We are at the top level. Fetch the corresponding scope. | 3913 // We are at the top level. Fetch the corresponding scope. |
3852 LocalScope* top_scope = node->scope(); | 3914 LocalScope* top_scope = node->scope(); |
3853 LocalVariable* jump_var = top_scope->LookupVariable( | 3915 LocalVariable* jump_var = top_scope->LookupVariable( |
3854 Symbols::AwaitJumpVar(), false); | 3916 Symbols::AwaitJumpVar(), false); |
3855 ASSERT(jump_var != NULL && jump_var->is_captured()); | 3917 ASSERT(jump_var != NULL && jump_var->is_captured()); |
3856 | |
3857 Instruction* saved_entry = entry_; | 3918 Instruction* saved_entry = entry_; |
3858 Instruction* saved_exit = exit_; | 3919 Instruction* saved_exit = exit_; |
3859 entry_ = NULL; | 3920 entry_ = NULL; |
3860 exit_ = NULL; | 3921 exit_ = NULL; |
3861 | 3922 |
3862 LoadLocalNode* load_jump_count = new(I) LoadLocalNode( | 3923 LoadLocalNode* load_jump_count = |
3863 Scanner::kNoSourcePos, jump_var); | 3924 new(I) LoadLocalNode(Scanner::kNoSourcePos, jump_var); |
3864 ComparisonNode* check_jump_count; | 3925 ComparisonNode* check_jump_count; |
3865 const intptr_t num_await_states = owner()->await_joins()->length(); | 3926 const intptr_t num_await_states = owner()->await_joins()->length(); |
| 3927 |
3866 LocalVariable* old_context = top_scope->LookupVariable( | 3928 LocalVariable* old_context = top_scope->LookupVariable( |
3867 Symbols::AwaitContextVar(), false); | 3929 Symbols::AwaitContextVar(), false); |
3868 LocalVariable* continuation_result = top_scope->LookupVariable( | |
3869 Symbols::AsyncOperationParam(), false); | |
3870 LocalVariable* continuation_error = top_scope->LookupVariable( | |
3871 Symbols::AsyncOperationErrorParam(), false); | |
3872 LocalVariable* continuation_stack_trace = top_scope->LookupVariable( | |
3873 Symbols::AsyncOperationStackTraceParam(), false); | |
3874 for (intptr_t i = 0; i < num_await_states; i++) { | 3930 for (intptr_t i = 0; i < num_await_states; i++) { |
3875 check_jump_count = new(I) ComparisonNode( | 3931 check_jump_count = new(I) ComparisonNode( |
3876 Scanner::kNoSourcePos, | 3932 Scanner::kNoSourcePos, |
3877 Token::kEQ, | 3933 Token::kEQ, |
3878 load_jump_count, | 3934 load_jump_count, |
3879 new(I) LiteralNode( | 3935 new(I) LiteralNode( |
3880 Scanner::kNoSourcePos, Smi::ZoneHandle(I, Smi::New(i)))); | 3936 Scanner::kNoSourcePos, Smi::ZoneHandle(I, Smi::New(i)))); |
3881 TestGraphVisitor for_test(owner(), Scanner::kNoSourcePos); | 3937 TestGraphVisitor for_test(owner(), Scanner::kNoSourcePos); |
3882 check_jump_count->Visit(&for_test); | 3938 check_jump_count->Visit(&for_test); |
3883 EffectGraphVisitor for_true(owner()); | 3939 EffectGraphVisitor for_true(owner()); |
3884 EffectGraphVisitor for_false(owner()); | 3940 EffectGraphVisitor for_false(owner()); |
3885 | 3941 |
3886 for_true.BuildAwaitJump(old_context, | 3942 if (function.IsAsyncClosure()) { |
3887 continuation_result, | 3943 LocalVariable* result_param = |
3888 continuation_error, | 3944 top_scope->LookupVariable(Symbols::AsyncOperationParam(), false); |
3889 continuation_stack_trace, | 3945 LocalVariable* error_param = |
3890 (*owner()->await_levels())[i], | 3946 top_scope->LookupVariable(Symbols::AsyncOperationErrorParam(), |
3891 (*owner()->await_joins())[i]); | 3947 false); |
| 3948 LocalVariable* stack_trace_param = |
| 3949 top_scope->LookupVariable(Symbols::AsyncOperationStackTraceParam(), |
| 3950 false); |
| 3951 for_true.BuildAwaitJump(old_context, |
| 3952 result_param, |
| 3953 error_param, |
| 3954 stack_trace_param, |
| 3955 (*owner()->await_levels())[i], |
| 3956 (*owner()->await_joins())[i]); |
| 3957 } else { |
| 3958 ASSERT(function.IsSyncGenClosure()); |
| 3959 LocalVariable* iterator_param = |
| 3960 top_scope->LookupVariable(Symbols::IteratorParameter(), false); |
| 3961 for_true.BuildYieldJump(old_context, |
| 3962 iterator_param, |
| 3963 (*owner()->await_levels())[i], |
| 3964 (*owner()->await_joins())[i]); |
| 3965 } |
| 3966 |
3892 Join(for_test, for_true, for_false); | 3967 Join(for_test, for_true, for_false); |
3893 | |
3894 if (i == 0) { | 3968 if (i == 0) { |
3895 // Manually link up the preamble start. | 3969 // Manually link up the preamble start. |
3896 preamble_start->previous()->set_next(for_test.entry()); | 3970 preamble_start->previous()->set_next(for_test.entry()); |
3897 for_test.entry()->set_previous(preamble_start->previous()); | 3971 for_test.entry()->set_previous(preamble_start->previous()); |
3898 } | 3972 } |
3899 if (i == (num_await_states - 1)) { | 3973 if (i == (num_await_states - 1)) { |
3900 // Link up preamble end. | 3974 // Link up preamble end. |
3901 if (exit_ == NULL) { | 3975 if (exit_ == NULL) { |
3902 exit_ = preamble_start; | 3976 exit_ = preamble_start; |
3903 } else { | 3977 } else { |
(...skipping 378 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4282 Report::MessageF(Report::kBailout, | 4356 Report::MessageF(Report::kBailout, |
4283 Script::Handle(function.script()), | 4357 Script::Handle(function.script()), |
4284 function.token_pos(), | 4358 function.token_pos(), |
4285 "FlowGraphBuilder Bailout: %s %s", | 4359 "FlowGraphBuilder Bailout: %s %s", |
4286 String::Handle(function.name()).ToCString(), | 4360 String::Handle(function.name()).ToCString(), |
4287 reason); | 4361 reason); |
4288 UNREACHABLE(); | 4362 UNREACHABLE(); |
4289 } | 4363 } |
4290 | 4364 |
4291 } // namespace dart | 4365 } // namespace dart |
OLD | NEW |