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

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: Created 6 years, 4 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.cc » ('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(
1453 const LocalVariable& continuation_result,
1454 const LocalVariable& old_ctx,
1455 const intptr_t old_ctx_level,
1456 JoinEntryInstr* target) {
1457 // Building a jump consists of the following actions:
1458 // * Record the current continuation result in a temporary.
1459 // * Restore the old context.
1460 // * Overwrite the old context's continuation result with the temporary.
1461 // * Append a Goto to the target's join.
1462 ASSERT(continuation_result.is_captured());
1463 ASSERT(old_ctx.is_captured());
1464 // Before resoring the continuation context we need to temporary save the
1465 // current continuation result.
1466 Value* continuation_result_value = Bind(BuildLoadLocal(continuation_result));
1467 Do(BuildStoreExprTemp(continuation_result_value));
1468
1469 // Restore the saved continuation context.
1470 BuildRestoreContext(old_ctx);
1471
1472 // Pass over the continuation result.
1473 Value* saved_continuation_result = Bind(BuildLoadExprTemp());
1474 // FlowGraphBuilder is at top context level, but the await target has possibly
1475 // been recorded in a nested context (old_ctx_level). We need to unroll
1476 // manually here.
1477 LocalVariable* tmp_var = EnterTempLocalScope(saved_continuation_result);
1478 intptr_t delta = old_ctx_level - continuation_result.owner()->context_level();
1479 ASSERT(delta >= 0);
1480 Value* context = Bind(new(I) CurrentContextInstr());
1481 while (delta-- > 0) {
1482 context = Bind(new(I) LoadFieldInstr(
1483 context, Context::parent_offset(), Type::ZoneHandle(I, Type::null()),
1484 Scanner::kNoSourcePos));
1485 }
1486 Value* tmp_val = Bind(new(I) LoadLocalInstr(*tmp_var));
1487 StoreInstanceFieldInstr* store = new(I) StoreInstanceFieldInstr(
1488 Context::variable_offset(continuation_result.index()),
1489 context,
1490 tmp_val,
1491 kEmitStoreBarrier,
1492 Scanner::kNoSourcePos);
1493 Do(store);
1494 Do(ExitTempLocalScope(tmp_var));
1495
1496 // Goto saved join.
1497 Goto(target);
1498 }
1499
1500
1447 // Used for type casts and to test assignments. 1501 // Used for type casts and to test assignments.
1448 Value* EffectGraphVisitor::BuildAssignableValue(intptr_t token_pos, 1502 Value* EffectGraphVisitor::BuildAssignableValue(intptr_t token_pos,
1449 Value* value, 1503 Value* value,
1450 const AbstractType& dst_type, 1504 const AbstractType& dst_type,
1451 const String& dst_name) { 1505 const String& dst_name) {
1452 if (CanSkipTypeCheck(token_pos, value, dst_type, dst_name)) { 1506 if (CanSkipTypeCheck(token_pos, value, dst_type, dst_name)) {
1453 return value; 1507 return value;
1454 } 1508 }
1455 return Bind(BuildAssertAssignable(token_pos, value, dst_type, dst_name)); 1509 return Bind(BuildAssertAssignable(token_pos, value, dst_type, dst_name));
1456 } 1510 }
(...skipping 656 matching lines...) Expand 10 before | Expand all | Expand 10 after
2113 UNREACHABLE(); 2167 UNREACHABLE();
2114 } 2168 }
2115 2169
2116 2170
2117 void EffectGraphVisitor::VisitAwaitNode(AwaitNode* node) { 2171 void EffectGraphVisitor::VisitAwaitNode(AwaitNode* node) {
2118 // Await nodes are temporary during parsing. 2172 // Await nodes are temporary during parsing.
2119 UNREACHABLE(); 2173 UNREACHABLE();
2120 } 2174 }
2121 2175
2122 2176
2177 void EffectGraphVisitor::VisitAwaitMarkerNode(AwaitMarkerNode* node) {
2178 if (node->type() == AwaitMarkerNode::kNewContinuationState) {
2179 // We need to create a new await state which involves:
2180 // * Increase the jump counter. Sanity check against the list of targets.
2181 // * Save the current context for resuming.
2182 ASSERT(node->scope() != NULL);
2183 LocalVariable* jump_var = node->scope()->LookupVariable(
2184 Symbols::AwaitJumpVar(), false);
2185 LocalVariable* ctx_var = node->scope()->LookupVariable(
2186 Symbols::AwaitContextVar(), false);
2187 ASSERT(jump_var != NULL && jump_var->is_captured());
2188 ASSERT(ctx_var != NULL && ctx_var->is_captured());
2189 const intptr_t jump_cnt = owner()->next_await_counter();
2190 ASSERT(jump_cnt >= 0);
2191 // Sanity check that we always add a JoinEntryInstr before adding a new
2192 // state.
2193 ASSERT(jump_cnt == owner()->await_joins()->length());
2194 // Store the counter in :await_jump_var.
2195 Value* jump_val = Bind(new (I) ConstantInstr(
2196 Smi::ZoneHandle(I, Smi::New(jump_cnt))));
2197 Do(BuildStoreLocal(*jump_var, jump_val));
2198 // Save the current context for resuming.
2199 BuildSaveContext(*ctx_var);
2200 owner()->await_levels()->Add(owner()->context_level());
2201 return;
2202 }
2203 if (node->type() == AwaitMarkerNode::kTargetForContinuation) {
2204 // We need to create a new await target which involves:
2205 // * Append a join that is also added to the list that will later result in
2206 // a preamble.
2207 JoinEntryInstr* const join = new(I) JoinEntryInstr(
2208 owner()->AllocateBlockId(), owner()->try_index());
2209 owner()->await_joins()->Add(join);
2210 Goto(join);
2211 exit_ = join;
2212 return;
2213 }
2214 UNREACHABLE();
2215 }
2216
2217
2123 intptr_t EffectGraphVisitor::GetCurrentTempLocalIndex() const { 2218 intptr_t EffectGraphVisitor::GetCurrentTempLocalIndex() const {
2124 return kFirstLocalSlotFromFp 2219 return kFirstLocalSlotFromFp
2125 - owner()->num_stack_locals() 2220 - owner()->num_stack_locals()
2126 - owner()->num_copied_params() 2221 - owner()->num_copied_params()
2127 - owner()->args_pushed() 2222 - owner()->args_pushed()
2128 - owner()->temp_count() + 1; 2223 - owner()->temp_count() + 1;
2129 } 2224 }
2130 2225
2131 2226
2132 LocalVariable* EffectGraphVisitor::EnterTempLocalScope(Value* value) { 2227 LocalVariable* EffectGraphVisitor::EnterTempLocalScope(Value* value) {
(...skipping 1486 matching lines...) Expand 10 before | Expand all | Expand 10 after
3619 parameter_value = Bind(assert_assignable); 3714 parameter_value = Bind(assert_assignable);
3620 // Store the type checked argument back to its corresponding local 3715 // Store the type checked argument back to its corresponding local
3621 // variable so that ssa renaming detects the dependency and makes use 3716 // variable so that ssa renaming detects the dependency and makes use
3622 // of the checked type in type propagation. 3717 // of the checked type in type propagation.
3623 Do(BuildStoreLocal(parameter, parameter_value)); 3718 Do(BuildStoreLocal(parameter, parameter_value));
3624 } 3719 }
3625 pos++; 3720 pos++;
3626 } 3721 }
3627 } 3722 }
3628 3723
3724 // Continuation part:
3725 // If this node sequence is the body of an async closure leave room for a
3726 // preamble. The preamble is generated after visiting the body.
3727 GotoInstr* preamble_start = NULL;
3728 if ((node == owner()->parsed_function()->node_sequence()) &&
3729 (owner()->parsed_function()->function().is_async_closure())) {
3730 JoinEntryInstr* preamble_end = new(I) JoinEntryInstr(
3731 owner()->AllocateBlockId(), owner()->try_index());
3732 ASSERT(exit() != NULL);
3733 exit()->Goto(preamble_end);
3734 ASSERT(exit()->next()->IsGoto());
3735 preamble_start = exit()->next()->AsGoto();
3736 ASSERT(preamble_start->IsGoto());
3737 exit_ = preamble_end;
3738 }
3739
3629 intptr_t i = 0; 3740 intptr_t i = 0;
3630 while (is_open() && (i < node->length())) { 3741 while (is_open() && (i < node->length())) {
3631 EffectGraphVisitor for_effect(owner()); 3742 EffectGraphVisitor for_effect(owner());
3632 node->NodeAt(i++)->Visit(&for_effect); 3743 node->NodeAt(i++)->Visit(&for_effect);
3633 Append(for_effect); 3744 Append(for_effect);
3634 if (!is_open()) { 3745 if (!is_open()) {
3635 // E.g., because of a JumpNode. 3746 // E.g., because of a JumpNode.
3636 break; 3747 break;
3637 } 3748 }
3638 } 3749 }
3639 3750
3751 // Continuation part:
3752 // After generating the CFG for the body we can create the preamble because we
3753 // know exactly how many continuation states we need.
3754 if ((node == owner()->parsed_function()->node_sequence()) &&
3755 (owner()->parsed_function()->function().is_async_closure())) {
3756 ASSERT(preamble_start != NULL);
3757 // We are at the top level. Fetch the corresponding scope.
3758 LocalScope* top_scope = node->scope();
3759 LocalVariable* jump_var = top_scope->LookupVariable(
3760 Symbols::AwaitJumpVar(), false);
3761 LocalVariable* ctx_var = top_scope->LookupVariable(
3762 Symbols::AwaitContextVar(), false);
3763 ASSERT(jump_var != NULL && jump_var->is_captured());
3764 ASSERT(ctx_var != NULL && ctx_var->is_captured());
srdjan 2014/08/26 15:54:33 Add parantheses above
3765
3766 Instruction* saved_entry = entry_;
3767 Instruction* saved_exit = exit_;
3768 entry_ = NULL;
3769 exit_ = NULL;
3770
3771 LoadLocalNode* load_jump_cnt = new(I) LoadLocalNode(
3772 Scanner::kNoSourcePos, jump_var);
3773 ComparisonNode* check_jump_cnt;
3774 const intptr_t num_await_states = owner()->await_joins()->length();
3775 for (intptr_t i = 0; i < num_await_states; i++) {
3776 check_jump_cnt = new(I) ComparisonNode(
3777 Scanner::kNoSourcePos,
3778 Token::kEQ,
3779 load_jump_cnt,
3780 new(I) LiteralNode(
3781 Scanner::kNoSourcePos, Smi::ZoneHandle(I, Smi::New(i))));
3782 TestGraphVisitor for_test(owner(), Scanner::kNoSourcePos);
3783 check_jump_cnt->Visit(&for_test);
3784 EffectGraphVisitor for_true(owner());
3785 EffectGraphVisitor for_false(owner());
3786
3787 LocalVariable* continuation_result_var =
3788 top_scope->LookupVariable(Symbols::AsyncOperationParam(), false);
3789 ASSERT(continuation_result_var != NULL);
3790 for_true.BuildAwaitJump(*continuation_result_var,
3791 *ctx_var,
3792 (*owner()->await_levels())[i],
3793 (*owner()->await_joins())[i]);
3794 Join(for_test, for_true, for_false);
3795
3796 if (i == 0) {
3797 // Manually link up the preamble start.
3798 preamble_start->previous()->set_next(for_test.entry());
3799 for_test.entry()->set_previous(preamble_start->previous());
3800 }
3801 if (i == (num_await_states - 1)) {
3802 // Link up preamble end.
3803 if (exit_ == NULL) {
3804 exit_ = preamble_start;
3805 } else {
3806 exit_->LinkTo(preamble_start);
3807 }
3808 }
3809 }
3810 entry_ = saved_entry;
3811 exit_ = saved_exit;
3812 }
3813
3640 if (is_open()) { 3814 if (is_open()) {
3641 if (MustSaveRestoreContext(node)) { 3815 if (MustSaveRestoreContext(node)) {
3642 BuildRestoreContext( 3816 BuildRestoreContext(
3643 *owner()->parsed_function()->saved_entry_context_var()); 3817 *owner()->parsed_function()->saved_entry_context_var());
3644 } else if (num_context_variables > 0) { 3818 } else if (num_context_variables > 0) {
3645 UnchainContexts(1); 3819 UnchainContexts(1);
3646 } 3820 }
3647 } 3821 }
3648 3822
3649 // If this node sequence is labeled, a break out of the sequence will have 3823 // 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
4005 Report::MessageF(Report::kBailout, 4179 Report::MessageF(Report::kBailout,
4006 Script::Handle(function.script()), 4180 Script::Handle(function.script()),
4007 function.token_pos(), 4181 function.token_pos(),
4008 "FlowGraphBuilder Bailout: %s %s", 4182 "FlowGraphBuilder Bailout: %s %s",
4009 String::Handle(function.name()).ToCString(), 4183 String::Handle(function.name()).ToCString(),
4010 reason); 4184 reason);
4011 UNREACHABLE(); 4185 UNREACHABLE();
4012 } 4186 }
4013 4187
4014 } // namespace dart 4188 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_builder.h ('k') | runtime/vm/parser.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698