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