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

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
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() && node->is_regular_return()) {
(...skipping 16 matching lines...) Expand all
1076 arguments, 1070 arguments,
1077 Object::null_array(), 1071 Object::null_array(),
1078 1, 1072 1,
1079 owner()->ic_data_array()); 1073 owner()->ic_data_array());
1080 Do(call); 1074 Do(call);
1081 1075
1082 // Rebind the return value for the actual return call to be null. 1076 // Rebind the return value for the actual return call to be null.
1083 return_value = BuildNullValue(); 1077 return_value = BuildNullValue();
1084 } 1078 }
1085 1079
1080 intptr_t current_context_level = owner()->context_level();
1081 ASSERT(current_context_level >= 0);
1082 if (owner()->parsed_function()->saved_entry_context_var() != NULL) {
1083 // CTX on entry was saved, but not linked as context parent.
1084 BuildRestoreContext(*owner()->parsed_function()->saved_entry_context_var());
1085 } else {
1086 UnchainContexts(current_context_level);
1087 }
1088
1089
1086 AddReturnExit(node->token_pos(), return_value); 1090 AddReturnExit(node->token_pos(), return_value);
1087 } 1091 }
1088 1092
1089 1093
1090 // <Expression> ::= Literal { literal: Instance } 1094 // <Expression> ::= Literal { literal: Instance }
1091 void EffectGraphVisitor::VisitLiteralNode(LiteralNode* node) { 1095 void EffectGraphVisitor::VisitLiteralNode(LiteralNode* node) {
1092 ReturnDefinition(new(I) ConstantInstr(node->literal())); 1096 ReturnDefinition(new(I) ConstantInstr(node->literal()));
1093 } 1097 }
1094 1098
1095 1099
(...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after
1437 } 1441 }
1438 return new(I) AssertAssignableInstr(token_pos, 1442 return new(I) AssertAssignableInstr(token_pos,
1439 value, 1443 value,
1440 instantiator, 1444 instantiator,
1441 instantiator_type_arguments, 1445 instantiator_type_arguments,
1442 dst_type, 1446 dst_type,
1443 dst_name); 1447 dst_name);
1444 } 1448 }
1445 1449
1446 1450
1451 void EffectGraphVisitor::BuildAwaitJump(
1452 const LocalVariable& continuation_result,
1453 const LocalVariable& old_ctx,
1454 const intptr_t old_ctx_level,
1455 JoinEntryInstr* target) {
1456 // Building a jump consists of the following actions:
1457 // * Record the current continuation result in a temporary.
1458 // * Restore the old context.
1459 // * Overwrite the old context's continuation result with the temporary.
1460 // * Append a Goto to the target's join.
1461 ASSERT(continuation_result.is_captured());
1462 ASSERT(old_ctx.is_captured());
1463 // Before resoring the continuation context we need to temporary save the
1464 // current continuation result.
1465 Value* continuation_result_value = Bind(BuildLoadLocal(continuation_result));
1466 Do(BuildStoreExprTemp(continuation_result_value));
1467
1468 // Restore the saved continuation context.
1469 BuildRestoreContext(old_ctx);
1470
1471 // Pass over the continuation result.
1472 Value* saved_continuation_result = Bind(BuildLoadExprTemp());
1473 // FGB is at top context level, but the await target has possibly been
srdjan 2014/08/20 17:50:06 ditto for FGB
Michael Lippautz (Google) 2014/08/20 20:56:06 Done.
1474 // recorded in a nested context (old_ctx_level). We need to unroll manually
1475 // here.
1476 LocalVariable* tmp_var = EnterTempLocalScope(saved_continuation_result);
1477 intptr_t delta = old_ctx_level - continuation_result.owner()->context_level();
1478 ASSERT(delta >= 0);
1479 Value* context = Bind(new(I) CurrentContextInstr());
1480 while (delta-- > 0) {
1481 context = Bind(new(I) LoadFieldInstr(
1482 context, Context::parent_offset(), Type::ZoneHandle(I, Type::null()),
1483 Scanner::kNoSourcePos));
1484 }
1485 Value* tmp_val = Bind(new(I) LoadLocalInstr(*tmp_var));
1486 StoreInstanceFieldInstr* store = new(I) StoreInstanceFieldInstr(
1487 Context::variable_offset(continuation_result.index()),
1488 context,
1489 tmp_val,
1490 kEmitStoreBarrier,
1491 Scanner::kNoSourcePos);
1492 Do(store);
1493 Do(ExitTempLocalScope(tmp_var));
1494
1495 // Goto saved join.
1496 Goto(target);
1497 }
1498
1499
1447 // Used for type casts and to test assignments. 1500 // Used for type casts and to test assignments.
1448 Value* EffectGraphVisitor::BuildAssignableValue(intptr_t token_pos, 1501 Value* EffectGraphVisitor::BuildAssignableValue(intptr_t token_pos,
1449 Value* value, 1502 Value* value,
1450 const AbstractType& dst_type, 1503 const AbstractType& dst_type,
1451 const String& dst_name) { 1504 const String& dst_name) {
1452 if (CanSkipTypeCheck(token_pos, value, dst_type, dst_name)) { 1505 if (CanSkipTypeCheck(token_pos, value, dst_type, dst_name)) {
1453 return value; 1506 return value;
1454 } 1507 }
1455 return Bind(BuildAssertAssignable(token_pos, value, dst_type, dst_name)); 1508 return Bind(BuildAssertAssignable(token_pos, value, dst_type, dst_name));
1456 } 1509 }
(...skipping 656 matching lines...) Expand 10 before | Expand all | Expand 10 after
2113 UNREACHABLE(); 2166 UNREACHABLE();
2114 } 2167 }
2115 2168
2116 2169
2117 void EffectGraphVisitor::VisitAwaitNode(AwaitNode* node) { 2170 void EffectGraphVisitor::VisitAwaitNode(AwaitNode* node) {
2118 // Await nodes are temporary during parsing. 2171 // Await nodes are temporary during parsing.
2119 UNREACHABLE(); 2172 UNREACHABLE();
2120 } 2173 }
2121 2174
2122 2175
2176 void EffectGraphVisitor::VisitAwaitMarkerNode(AwaitMarkerNode* node) {
2177 if (node->type() == AwaitMarkerNode::kNewContinuationState) {
2178 // We need to create a new await state which involves:
2179 // * Increase the jump counter. Sanity check against the list of targets.
2180 // * Save the current context for resuming.
2181 ASSERT(node->scope() != NULL);
2182 LocalVariable* jump_var = node->scope()->LookupVariable(
2183 Symbols::AwaitJumpVar(), false);
2184 LocalVariable* ctx_var = node->scope()->LookupVariable(
2185 Symbols::AwaitContextVar(), false);
2186 ASSERT(jump_var != NULL && jump_var->is_captured());
2187 ASSERT(ctx_var != NULL && ctx_var->is_captured());
2188 const int32_t jump_cnt = owner()->next_await_counter();
2189 ASSERT(jump_cnt >= 0);
2190 // Sanity check that we always add a JoinEntryInstr before adding a new
2191 // state.
2192 ASSERT(jump_cnt == owner()->await_joins()->length());
2193 // Store the counter in :await_jump_var.
2194 StoreLocalNode* store_jump_cnt = new(I) StoreLocalNode(
Florian Schneider 2014/08/21 11:09:29 Why do you create an AST node first, only to visit
Michael Lippautz (Google) 2014/08/21 16:39:14 Yes and no :) I inlined the IL instructions, but
2195 Scanner::kNoSourcePos,
2196 jump_var,
2197 new(I) LiteralNode(
2198 Scanner::kNoSourcePos, Smi::ZoneHandle(I, Smi::New(jump_cnt))));
2199 EffectGraphVisitor for_effect(owner());
2200 store_jump_cnt->Visit(&for_effect);
2201 Append(for_effect);
2202 // Save the current context for resuming.
2203 BuildSaveContext(*ctx_var);
2204 owner()->await_levels()->Add(owner()->context_level());
2205 return;
2206 } else if (node->type() == AwaitMarkerNode::kTargetForContinuation) {
Florian Schneider 2014/08/21 11:09:29 No need for "else if" if you return inside the if-
Michael Lippautz (Google) 2014/08/21 16:39:14 Done.
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() &&
srdjan 2014/08/20 17:50:06 Add parentheses.
Michael Lippautz (Google) 2014/08/20 20:56:06 Done.
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() &&
srdjan 2014/08/20 17:50:06 ditto
Michael Lippautz (Google) 2014/08/20 20:56:06 Done.
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 LocalVariable* ctx_var = top_scope->LookupVariable(
3765 Symbols::AwaitContextVar(), false);
3766 ASSERT(jump_var != NULL && jump_var->is_captured());
3767 ASSERT(ctx_var != NULL && ctx_var->is_captured());
3768
3769 Instruction* saved_entry = entry_;
3770 Instruction* saved_exit = exit_;
3771 entry_ = NULL;
3772 exit_ = NULL;
3773
3774 LoadLocalNode* load_jump_cnt = new(I) LoadLocalNode(
3775 Scanner::kNoSourcePos, jump_var);
3776 ComparisonNode* check_jump_cnt;
3777 const int32_t num_await_states = owner()->await_joins()->length();
3778 for (int32_t i = 0; i < num_await_states; i++) {
3779 check_jump_cnt = new(I) ComparisonNode(
3780 Scanner::kNoSourcePos,
3781 Token::kEQ,
3782 load_jump_cnt,
3783 new(I) LiteralNode(
3784 Scanner::kNoSourcePos, Smi::ZoneHandle(I, Smi::New(i))));
3785 TestGraphVisitor for_test(owner(), Scanner::kNoSourcePos);
3786 check_jump_cnt->Visit(&for_test);
3787 EffectGraphVisitor for_true(owner());
3788 EffectGraphVisitor for_false(owner());
3789
3790 LocalVariable* continuation_result_var =
3791 top_scope->LookupVariable(Symbols::AsyncOperationParam(), false);
3792 ASSERT(continuation_result_var != NULL);
3793 for_true.BuildAwaitJump(*continuation_result_var,
3794 *ctx_var,
3795 (*owner()->await_levels())[i],
3796 (*owner()->await_joins())[i]);
3797 Join(for_test, for_true, for_false);
3798
3799 if (i == 0) {
3800 // Link up the preamble start.
3801 preamble_start->previous()->set_next(for_test.entry());
3802 }
3803 if (i == (num_await_states - 1)) {
3804 // Link up preamble end.
3805 if (exit_ == NULL) {
3806 exit_ = preamble_start;
3807 } else {
3808 exit_->LinkTo(preamble_start);
3809 }
3810 }
3811 }
3812 entry_ = saved_entry;
3813 exit_ = saved_exit;
3814 }
3815
3640 if (is_open()) { 3816 if (is_open()) {
3641 if (MustSaveRestoreContext(node)) { 3817 if (MustSaveRestoreContext(node)) {
3642 BuildRestoreContext( 3818 BuildRestoreContext(
3643 *owner()->parsed_function()->saved_entry_context_var()); 3819 *owner()->parsed_function()->saved_entry_context_var());
3644 } else if (num_context_variables > 0) { 3820 } else if (num_context_variables > 0) {
3645 UnchainContexts(1); 3821 UnchainContexts(1);
3646 } 3822 }
3647 } 3823 }
3648 3824
3649 // If this node sequence is labeled, a break out of the sequence will have 3825 // 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, 4181 Report::MessageF(Report::kBailout,
4006 Script::Handle(function.script()), 4182 Script::Handle(function.script()),
4007 function.token_pos(), 4183 function.token_pos(),
4008 "FlowGraphBuilder Bailout: %s %s", 4184 "FlowGraphBuilder Bailout: %s %s",
4009 String::Handle(function.name()).ToCString(), 4185 String::Handle(function.name()).ToCString(),
4010 reason); 4186 reason);
4011 UNREACHABLE(); 4187 UNREACHABLE();
4012 } 4188 }
4013 4189
4014 } // namespace dart 4190 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698