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

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: finally try to catch all issues in try/catch/finally 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
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());
srdjan 2014/08/26 15:54:33 Add parentheses
Michael Lippautz (Google) 2014/08/26 16:45:48 Done.
1465 ASSERT(old_ctx != NULL && old_ctx->is_captured());
srdjan 2014/08/26 15:54:33 ditto
Michael Lippautz (Google) 2014/08/26 16:45:48 Done.
1466 // Before resoring the continuation context we need to temporary save the
srdjan 2014/08/26 15:54:33 s/resoring/restoring/
Michael Lippautz (Google) 2014/08/26 16:45:48 Done.
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->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());
srdjan 2014/08/26 15:54:33 parentheses
Michael Lippautz (Google) 2014/08/26 16:45:48 Done.
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->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 1486 matching lines...) Expand 10 before | Expand all | Expand 10 after
3619 parameter_value = Bind(assert_assignable); 3717 parameter_value = Bind(assert_assignable);
3620 // Store the type checked argument back to its corresponding local 3718 // Store the type checked argument back to its corresponding local
3621 // variable so that ssa renaming detects the dependency and makes use 3719 // variable so that ssa renaming detects the dependency and makes use
3622 // of the checked type in type propagation. 3720 // of the checked type in type propagation.
3623 Do(BuildStoreLocal(parameter, parameter_value)); 3721 Do(BuildStoreLocal(parameter, parameter_value));
3624 } 3722 }
3625 pos++; 3723 pos++;
3626 } 3724 }
3627 } 3725 }
3628 3726
3727 // Continuation part:
3728 // If this node sequence is the body of an async closure leave room for a
3729 // preamble. The preamble is generated after visiting the body.
3730 GotoInstr* preamble_start = NULL;
3731 if ((node == owner()->parsed_function()->node_sequence()) &&
3732 (owner()->parsed_function()->function().is_async_closure())) {
3733 JoinEntryInstr* preamble_end = new(I) JoinEntryInstr(
3734 owner()->AllocateBlockId(), owner()->try_index());
3735 ASSERT(exit() != NULL);
3736 exit()->Goto(preamble_end);
3737 ASSERT(exit()->next()->IsGoto());
3738 preamble_start = exit()->next()->AsGoto();
3739 ASSERT(preamble_start->IsGoto());
3740 exit_ = preamble_end;
3741 }
3742
3629 intptr_t i = 0; 3743 intptr_t i = 0;
3630 while (is_open() && (i < node->length())) { 3744 while (is_open() && (i < node->length())) {
3631 EffectGraphVisitor for_effect(owner()); 3745 EffectGraphVisitor for_effect(owner());
3632 node->NodeAt(i++)->Visit(&for_effect); 3746 node->NodeAt(i++)->Visit(&for_effect);
3633 Append(for_effect); 3747 Append(for_effect);
3634 if (!is_open()) { 3748 if (!is_open()) {
3635 // E.g., because of a JumpNode. 3749 // E.g., because of a JumpNode.
3636 break; 3750 break;
3637 } 3751 }
3638 } 3752 }
3639 3753
3754 // Continuation part:
3755 // After generating the CFG for the body we can create the preamble because we
3756 // know exactly how many continuation states we need.
3757 if ((node == owner()->parsed_function()->node_sequence()) &&
3758 (owner()->parsed_function()->function().is_async_closure())) {
3759 ASSERT(preamble_start != NULL);
3760 // We are at the top level. Fetch the corresponding scope.
3761 LocalScope* top_scope = node->scope();
3762 LocalVariable* jump_var = top_scope->LookupVariable(
3763 Symbols::AwaitJumpVar(), false);
3764 ASSERT(jump_var != NULL && jump_var->is_captured());
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 for_true.BuildAwaitJump(top_scope,
3788 (*owner()->await_levels())[i],
3789 (*owner()->await_joins())[i]);
3790 Join(for_test, for_true, for_false);
3791
3792 if (i == 0) {
3793 // Manually link up the preamble start.
3794 preamble_start->previous()->set_next(for_test.entry());
3795 for_test.entry()->set_previous(preamble_start->previous());
3796 }
3797 if (i == (num_await_states - 1)) {
3798 // Link up preamble end.
3799 if (exit_ == NULL) {
3800 exit_ = preamble_start;
3801 } else {
3802 exit_->LinkTo(preamble_start);
3803 }
3804 }
3805 }
3806 entry_ = saved_entry;
3807 exit_ = saved_exit;
3808 }
3809
3640 if (is_open()) { 3810 if (is_open()) {
3641 if (MustSaveRestoreContext(node)) { 3811 if (MustSaveRestoreContext(node)) {
3642 BuildRestoreContext( 3812 BuildRestoreContext(
3643 *owner()->parsed_function()->saved_entry_context_var()); 3813 *owner()->parsed_function()->saved_entry_context_var());
3644 } else if (num_context_variables > 0) { 3814 } else if (num_context_variables > 0) {
3645 UnchainContexts(1); 3815 UnchainContexts(1);
3646 } 3816 }
3647 } 3817 }
3648 3818
3649 // If this node sequence is labeled, a break out of the sequence will have 3819 // 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, 4175 Report::MessageF(Report::kBailout,
4006 Script::Handle(function.script()), 4176 Script::Handle(function.script()),
4007 function.token_pos(), 4177 function.token_pos(),
4008 "FlowGraphBuilder Bailout: %s %s", 4178 "FlowGraphBuilder Bailout: %s %s",
4009 String::Handle(function.name()).ToCString(), 4179 String::Handle(function.name()).ToCString(),
4010 reason); 4180 reason);
4011 UNREACHABLE(); 4181 UNREACHABLE();
4012 } 4182 }
4013 4183
4014 } // namespace dart 4184 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698