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

Unified Diff: runtime/vm/flow_graph_builder.cc

Issue 888463004: Add support for sync* and yield (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 5 years, 10 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/flow_graph_builder.h ('k') | runtime/vm/object.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/flow_graph_builder.cc
===================================================================
--- runtime/vm/flow_graph_builder.cc (revision 43515)
+++ runtime/vm/flow_graph_builder.cc (working copy)
@@ -1075,13 +1075,13 @@
//
// We distinguish those kinds of nodes via is_regular_return().
//
- if (function.is_async_closure() &&
+ if (function.IsAsyncClosure() &&
(node->return_type() == ReturnNode::kRegular)) {
// Temporary store the computed return value.
Do(BuildStoreExprTemp(return_value));
- LocalVariable* rcv_var = node->scope()->LookupVariable(
- Symbols::AsyncCompleter(), false);
+ LocalVariable* rcv_var =
+ node->scope()->LookupVariable(Symbols::AsyncCompleter(), false);
ASSERT(rcv_var != NULL && rcv_var->is_captured());
ZoneGrowableArray<PushArgumentInstr*>* arguments =
new(I) ZoneGrowableArray<PushArgumentInstr*>(2);
@@ -1109,10 +1109,9 @@
UnchainContexts(current_context_level);
}
-
AddReturnExit(node->token_pos(), return_value);
- if (function.is_async_closure() &&
+ if ((function.IsAsyncClosure() || function.IsSyncGenClosure()) &&
(node->return_type() == ReturnNode::kContinuationTarget)) {
JoinEntryInstr* const join = new(I) JoinEntryInstr(
owner()->AllocateBlockId(), owner()->try_index());
@@ -1484,6 +1483,62 @@
}
+void EffectGraphVisitor::BuildYieldJump(LocalVariable* old_context,
+ LocalVariable* iterator_param,
+ const intptr_t old_ctx_level,
+ JoinEntryInstr* target) {
+ // Building a jump consists of the following actions:
+ // * Load the generator body's iterator parameter (:iterator)
+ // from the current context into a temporary.
+ // * Restore the old context from :await_cxt_var.
+ // * Copy the iterator saved above into the restored context.
+ // * Append a Goto to the target's join.
+ ASSERT((iterator_param != NULL) && iterator_param->is_captured());
+ ASSERT((old_context != NULL) && old_context->is_captured());
+ // Before restoring the context we need to temporarily save the
+ // iterator parameter.
+ LocalVariable* temp_iterator_var =
+ EnterTempLocalScope(Bind(BuildLoadLocal(*iterator_param)));
+
+ // Restore the saved continuation context, i.e. the context that was
+ // saved into :await_ctx_var before the closure suspended.
+ BuildRestoreContext(*old_context);
+
+ // Store the continuation result and continuation error values into
+ // the restored context.
+
+ // FlowGraphBuilder is at top context level, but the continuation
+ // target has possibly been recorded in a nested context (old_ctx_level).
+ // We need to unroll manually here.
+ intptr_t delta =
+ old_ctx_level - iterator_param->owner()->context_level();
+ ASSERT(delta >= 0);
+ Value* context = Bind(BuildCurrentContext());
+ while (delta-- > 0) {
+ context = Bind(new(I) LoadFieldInstr(
+ context, Context::parent_offset(), Type::ZoneHandle(I, Type::null()),
+ Scanner::kNoSourcePos));
+ }
+ LocalVariable* temp_context_var = EnterTempLocalScope(context);
+
+ Value* context_val = Bind(new(I) LoadLocalInstr(*temp_context_var));
+ Value* store_val = Bind(new(I) LoadLocalInstr(*temp_iterator_var));
+ StoreInstanceFieldInstr* store = new(I) StoreInstanceFieldInstr(
+ Context::variable_offset(iterator_param->index()),
+ context_val,
+ store_val,
+ kEmitStoreBarrier,
+ Scanner::kNoSourcePos);
+ Do(store);
+
+ Do(ExitTempLocalScope(temp_context_var));
+ Do(ExitTempLocalScope(temp_iterator_var));
+
+ // Goto saved join.
+ Goto(target);
+}
+
+
void EffectGraphVisitor::BuildAwaitJump(LocalVariable* old_context,
LocalVariable* continuation_result,
LocalVariable* continuation_error,
@@ -1491,31 +1546,37 @@
const intptr_t old_ctx_level,
JoinEntryInstr* target) {
// Building a jump consists of the following actions:
- // * Record the current continuation result in a temporary.
- // * Restore the old context.
- // * Overwrite the old context's continuation result with the temporary.
+ // * Load the current continuation result parameter (:async_result)
+ // and continuation error parameter (:async_error_param) from
+ // the current context into temporaries.
+ // * Restore the old context from :await_cxt_var.
+ // * Copy the result and error parameters saved above into the restored
+ // context.
// * Append a Goto to the target's join.
ASSERT((continuation_result != NULL) && continuation_result->is_captured());
ASSERT((continuation_error != NULL) && continuation_error->is_captured());
ASSERT((old_context != NULL) && old_context->is_captured());
// Before restoring the continuation context we need to temporary save the
// result and error parameter.
- LocalVariable* temp_result_var = EnterTempLocalScope(
- Bind(BuildLoadLocal(*continuation_result)));
- LocalVariable* temp_error_var = EnterTempLocalScope(
- Bind(BuildLoadLocal(*continuation_error)));
- LocalVariable* temp_stack_trace_var = EnterTempLocalScope(
- Bind(BuildLoadLocal(*continuation_stack_trace)));
- // Restore the saved continuation context.
+ LocalVariable* temp_result_var =
+ EnterTempLocalScope(Bind(BuildLoadLocal(*continuation_result)));
+ LocalVariable* temp_error_var =
+ EnterTempLocalScope(Bind(BuildLoadLocal(*continuation_error)));
+ LocalVariable* temp_stack_trace_var =
+ EnterTempLocalScope(Bind(BuildLoadLocal(*continuation_stack_trace)));
+
+ // Restore the saved continuation context, i.e. the context that was
+ // saved into :await_ctx_var before the closure suspended.
BuildRestoreContext(*old_context);
- // Pass over the continuation result.
+ // Store the continuation result and continuation error values into
+ // the restored context.
// FlowGraphBuilder is at top context level, but the await target has possibly
// been recorded in a nested context (old_ctx_level). We need to unroll
// manually here.
- intptr_t delta = old_ctx_level -
- continuation_result->owner()->context_level();
+ intptr_t delta =
+ old_ctx_level - continuation_result->owner()->context_level();
ASSERT(delta >= 0);
Value* context = Bind(BuildCurrentContext());
while (delta-- > 0) {
@@ -3702,6 +3763,7 @@
// label: SourceLabel }
void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) {
LocalScope* scope = node->scope();
+ const Function& function = owner()->function();
const intptr_t num_context_variables =
(scope != NULL) ? scope->num_context_variables() : 0;
const bool is_top_level_sequence =
@@ -3734,7 +3796,6 @@
// the captured parameters from the frame into the context.
if (is_top_level_sequence) {
ASSERT(scope->context_level() == 1);
- const Function& function = owner()->function();
const int num_params = function.NumParameters();
int param_frame_index = (num_params == function.num_fixed_parameters()) ?
(kParamEndSlotFromFp + num_params) : kFirstLocalSlotFromFp;
@@ -3772,7 +3833,6 @@
// This check may be deleted if the generated code is leaf.
// Native functions don't need a stack check at entry.
- const Function& function = owner()->function();
if (is_top_level_sequence && !function.is_native()) {
// Always allocate CheckOverflowInstr so that deopt-ids match regardless
// if we inline or not.
@@ -3789,7 +3849,6 @@
}
if (Isolate::Current()->TypeChecksEnabled() && is_top_level_sequence) {
- const Function& function = owner()->function();
const int num_params = function.NumParameters();
int pos = 0;
if (function.IsConstructor()) {
@@ -3818,10 +3877,12 @@
}
// Continuation part:
- // If this node sequence is the body of an async closure leave room for a
- // preamble. The preamble is generated after visiting the body.
+ // If this node sequence is the body of a function with continuations,
+ // leave room for a preamble.
+ // The preamble is generated after visiting the body.
GotoInstr* preamble_start = NULL;
- if (is_top_level_sequence && (owner()->function().is_async_closure())) {
+ if (is_top_level_sequence &&
+ (function.IsAsyncClosure() || function.IsSyncGenClosure())) {
JoinEntryInstr* preamble_end = new(I) JoinEntryInstr(
owner()->AllocateBlockId(), owner()->try_index());
ASSERT(exit() != NULL);
@@ -3844,33 +3905,28 @@
}
// Continuation part:
- // After generating the CFG for the body we can create the preamble because we
- // know exactly how many continuation states we need.
- if (is_top_level_sequence && (owner()->function().is_async_closure())) {
+ // After generating the CFG for the body we can create the preamble
+ // because we know exactly how many continuation states we need.
+ if (is_top_level_sequence &&
+ (function.IsAsyncClosure() || function.IsSyncGenClosure())) {
ASSERT(preamble_start != NULL);
// We are at the top level. Fetch the corresponding scope.
LocalScope* top_scope = node->scope();
LocalVariable* jump_var = top_scope->LookupVariable(
Symbols::AwaitJumpVar(), false);
ASSERT(jump_var != NULL && jump_var->is_captured());
-
Instruction* saved_entry = entry_;
Instruction* saved_exit = exit_;
entry_ = NULL;
exit_ = NULL;
- LoadLocalNode* load_jump_count = new(I) LoadLocalNode(
- Scanner::kNoSourcePos, jump_var);
+ LoadLocalNode* load_jump_count =
+ new(I) LoadLocalNode(Scanner::kNoSourcePos, jump_var);
ComparisonNode* check_jump_count;
const intptr_t num_await_states = owner()->await_joins()->length();
+
LocalVariable* old_context = top_scope->LookupVariable(
Symbols::AwaitContextVar(), false);
- LocalVariable* continuation_result = top_scope->LookupVariable(
- Symbols::AsyncOperationParam(), false);
- LocalVariable* continuation_error = top_scope->LookupVariable(
- Symbols::AsyncOperationErrorParam(), false);
- LocalVariable* continuation_stack_trace = top_scope->LookupVariable(
- Symbols::AsyncOperationStackTraceParam(), false);
for (intptr_t i = 0; i < num_await_states; i++) {
check_jump_count = new(I) ComparisonNode(
Scanner::kNoSourcePos,
@@ -3883,14 +3939,32 @@
EffectGraphVisitor for_true(owner());
EffectGraphVisitor for_false(owner());
- for_true.BuildAwaitJump(old_context,
- continuation_result,
- continuation_error,
- continuation_stack_trace,
- (*owner()->await_levels())[i],
- (*owner()->await_joins())[i]);
+ if (function.IsAsyncClosure()) {
+ LocalVariable* result_param =
+ top_scope->LookupVariable(Symbols::AsyncOperationParam(), false);
+ LocalVariable* error_param =
+ top_scope->LookupVariable(Symbols::AsyncOperationErrorParam(),
+ false);
+ LocalVariable* stack_trace_param =
+ top_scope->LookupVariable(Symbols::AsyncOperationStackTraceParam(),
+ false);
+ for_true.BuildAwaitJump(old_context,
+ result_param,
+ error_param,
+ stack_trace_param,
+ (*owner()->await_levels())[i],
+ (*owner()->await_joins())[i]);
+ } else {
+ ASSERT(function.IsSyncGenClosure());
+ LocalVariable* iterator_param =
+ top_scope->LookupVariable(Symbols::IteratorParameter(), false);
+ for_true.BuildYieldJump(old_context,
+ iterator_param,
+ (*owner()->await_levels())[i],
+ (*owner()->await_joins())[i]);
+ }
+
Join(for_test, for_true, for_false);
-
if (i == 0) {
// Manually link up the preamble start.
preamble_start->previous()->set_next(for_test.entry());
« no previous file with comments | « runtime/vm/flow_graph_builder.h ('k') | runtime/vm/object.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698