Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1083)

Side by Side Diff: runtime/vm/flow_graph_builder.cc

Issue 484933003: Await it! (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: rebase Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/flow_graph_builder.h ('k') | runtime/vm/parser.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 242 matching lines...) Expand 10 before | Expand all | Expand 10 after
253 guarded_fields_(new(I) ZoneGrowableArray<const Field*>()), 253 guarded_fields_(new(I) ZoneGrowableArray<const Field*>()),
254 last_used_block_id_(0), // 0 is used for the graph entry. 254 last_used_block_id_(0), // 0 is used for the graph entry.
255 try_index_(CatchClauseNode::kInvalidTryIndex), 255 try_index_(CatchClauseNode::kInvalidTryIndex),
256 catch_try_index_(CatchClauseNode::kInvalidTryIndex), 256 catch_try_index_(CatchClauseNode::kInvalidTryIndex),
257 loop_depth_(0), 257 loop_depth_(0),
258 graph_entry_(NULL), 258 graph_entry_(NULL),
259 temp_count_(0), 259 temp_count_(0),
260 args_pushed_(0), 260 args_pushed_(0),
261 nesting_stack_(NULL), 261 nesting_stack_(NULL),
262 osr_id_(osr_id), 262 osr_id_(osr_id),
263 is_optimizing_(is_optimizing) { } 263 is_optimizing_(is_optimizing),
264 jump_cnt_(0),
265 await_joins_(new(I) ZoneGrowableArray<JoinEntryInstr*>()),
266 await_levels_(new(I) ZoneGrowableArray<intptr_t>()) { }
264 267
265 268
266 void FlowGraphBuilder::AddCatchEntry(CatchBlockEntryInstr* entry) { 269 void FlowGraphBuilder::AddCatchEntry(CatchBlockEntryInstr* entry) {
267 graph_entry_->AddCatchEntry(entry); 270 graph_entry_->AddCatchEntry(entry);
268 } 271 }
269 272
270 273
271 void InlineExitCollector::PrepareGraphs(FlowGraph* callee_graph) { 274 void InlineExitCollector::PrepareGraphs(FlowGraph* callee_graph) {
272 ASSERT(callee_graph->graph_entry()->SuccessorCount() == 1); 275 ASSERT(callee_graph->graph_entry()->SuccessorCount() == 1);
273 ASSERT(callee_graph->max_block_id() > caller_graph_->max_block_id()); 276 ASSERT(callee_graph->max_block_id() > caller_graph_->max_block_id());
(...skipping 757 matching lines...) Expand 10 before | Expand all | Expand 10 after
1031 if (!is_implicit_dynamic_getter && !function.IsConstructor()) { 1034 if (!is_implicit_dynamic_getter && !function.IsConstructor()) {
1032 const AbstractType& dst_type = 1035 const AbstractType& dst_type =
1033 AbstractType::ZoneHandle(I, function.result_type()); 1036 AbstractType::ZoneHandle(I, function.result_type());
1034 return_value = BuildAssignableValue(node->value()->token_pos(), 1037 return_value = BuildAssignableValue(node->value()->token_pos(),
1035 return_value, 1038 return_value,
1036 dst_type, 1039 dst_type,
1037 Symbols::FunctionResult()); 1040 Symbols::FunctionResult());
1038 } 1041 }
1039 } 1042 }
1040 1043
1041 intptr_t current_context_level = owner()->context_level();
1042 ASSERT(current_context_level >= 0);
1043 if (owner()->parsed_function()->saved_entry_context_var() != NULL) {
1044 // CTX on entry was saved, but not linked as context parent.
1045 BuildRestoreContext(*owner()->parsed_function()->saved_entry_context_var());
1046 } else {
1047 UnchainContexts(current_context_level);
1048 }
1049
1050 // Async functions contain two types of return statements: 1044 // Async functions contain two types of return statements:
1051 // 1) Returns that should complete the completer once all finally blocks have 1045 // 1) Returns that should complete the completer once all finally blocks have
1052 // been inlined (call: :async_completer.complete(return_value)). These 1046 // been inlined (call: :async_completer.complete(return_value)). These
1053 // returns end up returning null in the end. 1047 // returns end up returning null in the end.
1054 // 2) "Continuation" returns that should not complete the completer but return 1048 // 2) "Continuation" returns that should not complete the completer but return
1055 // the value. 1049 // the value.
1056 // 1050 //
1057 // We distinguish those kinds of nodes via is_regular_return(). 1051 // We distinguish those kinds of nodes via is_regular_return().
1058 // 1052 //
1059 if (function.is_async_closure() && node->is_regular_return()) { 1053 if (function.is_async_closure() &&
1054 (node->return_type() == ReturnNode::kRegular)) {
1060 // Temporary store the computed return value. 1055 // Temporary store the computed return value.
1061 Do(BuildStoreExprTemp(return_value)); 1056 Do(BuildStoreExprTemp(return_value));
1062 1057
1063 LocalVariable* rcv_var = node->scope()->LookupVariable( 1058 LocalVariable* rcv_var = node->scope()->LookupVariable(
1064 Symbols::AsyncCompleter(), false); 1059 Symbols::AsyncCompleter(), false);
1065 ASSERT(rcv_var != NULL && rcv_var->is_captured()); 1060 ASSERT(rcv_var != NULL && rcv_var->is_captured());
1066 ZoneGrowableArray<PushArgumentInstr*>* arguments = 1061 ZoneGrowableArray<PushArgumentInstr*>* arguments =
1067 new(I) ZoneGrowableArray<PushArgumentInstr*>(2); 1062 new(I) ZoneGrowableArray<PushArgumentInstr*>(2);
1068 Value* rcv_value = Bind(BuildLoadLocal(*rcv_var)); 1063 Value* rcv_value = Bind(BuildLoadLocal(*rcv_var));
1069 arguments->Add(PushArgument(rcv_value)); 1064 arguments->Add(PushArgument(rcv_value));
1070 Value* returned_value = Bind(BuildLoadExprTemp()); 1065 Value* returned_value = Bind(BuildLoadExprTemp());
1071 arguments->Add(PushArgument(returned_value)); 1066 arguments->Add(PushArgument(returned_value));
1072 InstanceCallInstr* call = new(I) InstanceCallInstr( 1067 InstanceCallInstr* call = new(I) InstanceCallInstr(
1073 Scanner::kNoSourcePos, 1068 Scanner::kNoSourcePos,
1074 Symbols::CompleterComplete(), 1069 Symbols::CompleterComplete(),
1075 Token::kILLEGAL, 1070 Token::kILLEGAL,
1076 arguments, 1071 arguments,
1077 Object::null_array(), 1072 Object::null_array(),
1078 1, 1073 1,
1079 owner()->ic_data_array()); 1074 owner()->ic_data_array());
1080 Do(call); 1075 Do(call);
1081 1076
1082 // Rebind the return value for the actual return call to be null. 1077 // Rebind the return value for the actual return call to be null.
1083 return_value = BuildNullValue(); 1078 return_value = BuildNullValue();
1084 } 1079 }
1085 1080
1081 intptr_t current_context_level = owner()->context_level();
1082 ASSERT(current_context_level >= 0);
1083 if (owner()->parsed_function()->saved_entry_context_var() != NULL) {
1084 // CTX on entry was saved, but not linked as context parent.
1085 BuildRestoreContext(*owner()->parsed_function()->saved_entry_context_var());
1086 } else {
1087 UnchainContexts(current_context_level);
1088 }
1089
1090
1086 AddReturnExit(node->token_pos(), return_value); 1091 AddReturnExit(node->token_pos(), return_value);
1087 } 1092 }
1088 1093
1089 1094
1090 // <Expression> ::= Literal { literal: Instance } 1095 // <Expression> ::= Literal { literal: Instance }
1091 void EffectGraphVisitor::VisitLiteralNode(LiteralNode* node) { 1096 void EffectGraphVisitor::VisitLiteralNode(LiteralNode* node) {
1092 ReturnDefinition(new(I) ConstantInstr(node->literal())); 1097 ReturnDefinition(new(I) ConstantInstr(node->literal()));
1093 } 1098 }
1094 1099
1095 1100
(...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after
1437 } 1442 }
1438 return new(I) AssertAssignableInstr(token_pos, 1443 return new(I) AssertAssignableInstr(token_pos,
1439 value, 1444 value,
1440 instantiator, 1445 instantiator,
1441 instantiator_type_arguments, 1446 instantiator_type_arguments,
1442 dst_type, 1447 dst_type,
1443 dst_name); 1448 dst_name);
1444 } 1449 }
1445 1450
1446 1451
1452 void EffectGraphVisitor::BuildAwaitJump(LocalScope* lookup_scope,
1453 const intptr_t old_ctx_level,
1454 JoinEntryInstr* target) {
1455 // Building a jump consists of the following actions:
1456 // * Record the current continuation result in a temporary.
1457 // * Restore the old context.
1458 // * Overwrite the old context's continuation result with the temporary.
1459 // * Append a Goto to the target's join.
1460 LocalVariable* old_ctx = lookup_scope->LookupVariable(
1461 Symbols::AwaitContextVar(), false);
1462 LocalVariable* continuation_result = lookup_scope->LookupVariable(
1463 Symbols::AsyncOperationParam(), false);
1464 ASSERT((continuation_result != NULL) && continuation_result->is_captured());
1465 ASSERT((old_ctx != NULL) && old_ctx->is_captured());
1466 // Before restoring the continuation context we need to temporary save the
1467 // current continuation result.
1468 Value* continuation_result_value = Bind(BuildLoadLocal(*continuation_result));
1469 Do(BuildStoreExprTemp(continuation_result_value));
1470
1471 // Restore the saved continuation context.
1472 BuildRestoreContext(*old_ctx);
1473
1474 // Pass over the continuation result.
1475 Value* saved_continuation_result = Bind(BuildLoadExprTemp());
1476 // FlowGraphBuilder is at top context level, but the await target has possibly
1477 // been recorded in a nested context (old_ctx_level). We need to unroll
1478 // manually here.
1479 LocalVariable* tmp_var = EnterTempLocalScope(saved_continuation_result);
1480 intptr_t delta = old_ctx_level -
1481 continuation_result->owner()->context_level();
1482 ASSERT(delta >= 0);
1483 Value* context = Bind(new(I) CurrentContextInstr());
1484 while (delta-- > 0) {
1485 context = Bind(new(I) LoadFieldInstr(
1486 context, Context::parent_offset(), Type::ZoneHandle(I, Type::null()),
1487 Scanner::kNoSourcePos));
1488 }
1489 Value* tmp_val = Bind(new(I) LoadLocalInstr(*tmp_var));
1490 StoreInstanceFieldInstr* store = new(I) StoreInstanceFieldInstr(
1491 Context::variable_offset(continuation_result->index()),
1492 context,
1493 tmp_val,
1494 kEmitStoreBarrier,
1495 Scanner::kNoSourcePos);
1496 Do(store);
1497 Do(ExitTempLocalScope(tmp_var));
1498
1499 // Goto saved join.
1500 Goto(target);
1501 }
1502
1503
1447 // Used for type casts and to test assignments. 1504 // Used for type casts and to test assignments.
1448 Value* EffectGraphVisitor::BuildAssignableValue(intptr_t token_pos, 1505 Value* EffectGraphVisitor::BuildAssignableValue(intptr_t token_pos,
1449 Value* value, 1506 Value* value,
1450 const AbstractType& dst_type, 1507 const AbstractType& dst_type,
1451 const String& dst_name) { 1508 const String& dst_name) {
1452 if (CanSkipTypeCheck(token_pos, value, dst_type, dst_name)) { 1509 if (CanSkipTypeCheck(token_pos, value, dst_type, dst_name)) {
1453 return value; 1510 return value;
1454 } 1511 }
1455 return Bind(BuildAssertAssignable(token_pos, value, dst_type, dst_name)); 1512 return Bind(BuildAssertAssignable(token_pos, value, dst_type, dst_name));
1456 } 1513 }
(...skipping 656 matching lines...) Expand 10 before | Expand all | Expand 10 after
2113 UNREACHABLE(); 2170 UNREACHABLE();
2114 } 2171 }
2115 2172
2116 2173
2117 void EffectGraphVisitor::VisitAwaitNode(AwaitNode* node) { 2174 void EffectGraphVisitor::VisitAwaitNode(AwaitNode* node) {
2118 // Await nodes are temporary during parsing. 2175 // Await nodes are temporary during parsing.
2119 UNREACHABLE(); 2176 UNREACHABLE();
2120 } 2177 }
2121 2178
2122 2179
2180 void EffectGraphVisitor::VisitAwaitMarkerNode(AwaitMarkerNode* node) {
2181 if (node->marker_type() == AwaitMarkerNode::kNewContinuationState) {
2182 // We need to create a new await state which involves:
2183 // * Increase the jump counter. Sanity check against the list of targets.
2184 // * Save the current context for resuming.
2185 ASSERT(node->scope() != NULL);
2186 LocalVariable* jump_var = node->scope()->LookupVariable(
2187 Symbols::AwaitJumpVar(), false);
2188 LocalVariable* ctx_var = node->scope()->LookupVariable(
2189 Symbols::AwaitContextVar(), false);
2190 ASSERT((jump_var != NULL) && jump_var->is_captured());
2191 ASSERT((ctx_var != NULL) && ctx_var->is_captured());
2192 const intptr_t jump_cnt = owner()->next_await_counter();
2193 ASSERT(jump_cnt >= 0);
2194 // Sanity check that we always add a JoinEntryInstr before adding a new
2195 // state.
2196 ASSERT(jump_cnt == owner()->await_joins()->length());
2197 // Store the counter in :await_jump_var.
2198 Value* jump_val = Bind(new (I) ConstantInstr(
2199 Smi::ZoneHandle(I, Smi::New(jump_cnt))));
2200 Do(BuildStoreLocal(*jump_var, jump_val));
2201 // Save the current context for resuming.
2202 BuildSaveContext(*ctx_var);
2203 owner()->await_levels()->Add(owner()->context_level());
2204 return;
2205 }
2206 if (node->marker_type() == AwaitMarkerNode::kTargetForContinuation) {
2207 // We need to create a new await target which involves:
2208 // * Append a join that is also added to the list that will later result in
2209 // a preamble.
2210 JoinEntryInstr* const join = new(I) JoinEntryInstr(
2211 owner()->AllocateBlockId(), owner()->try_index());
2212 owner()->await_joins()->Add(join);
2213 Goto(join);
2214 exit_ = join;
2215 return;
2216 }
2217 UNREACHABLE();
2218 }
2219
2220
2123 intptr_t EffectGraphVisitor::GetCurrentTempLocalIndex() const { 2221 intptr_t EffectGraphVisitor::GetCurrentTempLocalIndex() const {
2124 return kFirstLocalSlotFromFp 2222 return kFirstLocalSlotFromFp
2125 - owner()->num_stack_locals() 2223 - owner()->num_stack_locals()
2126 - owner()->num_copied_params() 2224 - owner()->num_copied_params()
2127 - owner()->args_pushed() 2225 - owner()->args_pushed()
2128 - owner()->temp_count() + 1; 2226 - owner()->temp_count() + 1;
2129 } 2227 }
2130 2228
2131 2229
2132 LocalVariable* EffectGraphVisitor::EnterTempLocalScope(Value* value) { 2230 LocalVariable* EffectGraphVisitor::EnterTempLocalScope(Value* value) {
(...skipping 1498 matching lines...) Expand 10 before | Expand all | Expand 10 after
3631 parameter_value = Bind(assert_assignable); 3729 parameter_value = Bind(assert_assignable);
3632 // Store the type checked argument back to its corresponding local 3730 // Store the type checked argument back to its corresponding local
3633 // variable so that ssa renaming detects the dependency and makes use 3731 // variable so that ssa renaming detects the dependency and makes use
3634 // of the checked type in type propagation. 3732 // of the checked type in type propagation.
3635 Do(BuildStoreLocal(parameter, parameter_value)); 3733 Do(BuildStoreLocal(parameter, parameter_value));
3636 } 3734 }
3637 pos++; 3735 pos++;
3638 } 3736 }
3639 } 3737 }
3640 3738
3739 // Continuation part:
3740 // If this node sequence is the body of an async closure leave room for a
3741 // preamble. The preamble is generated after visiting the body.
3742 GotoInstr* preamble_start = NULL;
3743 if ((node == owner()->parsed_function()->node_sequence()) &&
3744 (owner()->parsed_function()->function().is_async_closure())) {
3745 JoinEntryInstr* preamble_end = new(I) JoinEntryInstr(
3746 owner()->AllocateBlockId(), owner()->try_index());
3747 ASSERT(exit() != NULL);
3748 exit()->Goto(preamble_end);
3749 ASSERT(exit()->next()->IsGoto());
3750 preamble_start = exit()->next()->AsGoto();
3751 ASSERT(preamble_start->IsGoto());
3752 exit_ = preamble_end;
3753 }
3754
3641 intptr_t i = 0; 3755 intptr_t i = 0;
3642 while (is_open() && (i < node->length())) { 3756 while (is_open() && (i < node->length())) {
3643 EffectGraphVisitor for_effect(owner()); 3757 EffectGraphVisitor for_effect(owner());
3644 node->NodeAt(i++)->Visit(&for_effect); 3758 node->NodeAt(i++)->Visit(&for_effect);
3645 Append(for_effect); 3759 Append(for_effect);
3646 if (!is_open()) { 3760 if (!is_open()) {
3647 // E.g., because of a JumpNode. 3761 // E.g., because of a JumpNode.
3648 break; 3762 break;
3649 } 3763 }
3650 } 3764 }
3651 3765
3766 // Continuation part:
3767 // After generating the CFG for the body we can create the preamble because we
3768 // know exactly how many continuation states we need.
3769 if ((node == owner()->parsed_function()->node_sequence()) &&
3770 (owner()->parsed_function()->function().is_async_closure())) {
3771 ASSERT(preamble_start != NULL);
3772 // We are at the top level. Fetch the corresponding scope.
3773 LocalScope* top_scope = node->scope();
3774 LocalVariable* jump_var = top_scope->LookupVariable(
3775 Symbols::AwaitJumpVar(), false);
3776 ASSERT(jump_var != NULL && jump_var->is_captured());
3777
3778 Instruction* saved_entry = entry_;
3779 Instruction* saved_exit = exit_;
3780 entry_ = NULL;
3781 exit_ = NULL;
3782
3783 LoadLocalNode* load_jump_cnt = new(I) LoadLocalNode(
3784 Scanner::kNoSourcePos, jump_var);
3785 ComparisonNode* check_jump_cnt;
3786 const intptr_t num_await_states = owner()->await_joins()->length();
3787 for (intptr_t i = 0; i < num_await_states; i++) {
3788 check_jump_cnt = new(I) ComparisonNode(
3789 Scanner::kNoSourcePos,
3790 Token::kEQ,
3791 load_jump_cnt,
3792 new(I) LiteralNode(
3793 Scanner::kNoSourcePos, Smi::ZoneHandle(I, Smi::New(i))));
3794 TestGraphVisitor for_test(owner(), Scanner::kNoSourcePos);
3795 check_jump_cnt->Visit(&for_test);
3796 EffectGraphVisitor for_true(owner());
3797 EffectGraphVisitor for_false(owner());
3798
3799 for_true.BuildAwaitJump(top_scope,
3800 (*owner()->await_levels())[i],
3801 (*owner()->await_joins())[i]);
3802 Join(for_test, for_true, for_false);
3803
3804 if (i == 0) {
3805 // Manually link up the preamble start.
3806 preamble_start->previous()->set_next(for_test.entry());
3807 for_test.entry()->set_previous(preamble_start->previous());
3808 }
3809 if (i == (num_await_states - 1)) {
3810 // Link up preamble end.
3811 if (exit_ == NULL) {
3812 exit_ = preamble_start;
3813 } else {
3814 exit_->LinkTo(preamble_start);
3815 }
3816 }
3817 }
3818 entry_ = saved_entry;
3819 exit_ = saved_exit;
3820 }
3821
3652 if (is_open()) { 3822 if (is_open()) {
3653 if (MustSaveRestoreContext(node)) { 3823 if (MustSaveRestoreContext(node)) {
3654 BuildRestoreContext( 3824 BuildRestoreContext(
3655 *owner()->parsed_function()->saved_entry_context_var()); 3825 *owner()->parsed_function()->saved_entry_context_var());
3656 } else if (num_context_variables > 0) { 3826 } else if (num_context_variables > 0) {
3657 UnchainContexts(1); 3827 UnchainContexts(1);
3658 } 3828 }
3659 } 3829 }
3660 3830
3661 // If this node sequence is labeled, a break out of the sequence will have 3831 // If this node sequence is labeled, a break out of the sequence will have
(...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after
4017 Report::MessageF(Report::kBailout, 4187 Report::MessageF(Report::kBailout,
4018 Script::Handle(function.script()), 4188 Script::Handle(function.script()),
4019 function.token_pos(), 4189 function.token_pos(),
4020 "FlowGraphBuilder Bailout: %s %s", 4190 "FlowGraphBuilder Bailout: %s %s",
4021 String::Handle(function.name()).ToCString(), 4191 String::Handle(function.name()).ToCString(),
4022 reason); 4192 reason);
4023 UNREACHABLE(); 4193 UNREACHABLE();
4024 } 4194 }
4025 4195
4026 } // namespace dart 4196 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_builder.h ('k') | runtime/vm/parser.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698