| Index: runtime/vm/flow_graph_builder.cc
|
| diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
|
| index 265c3088f86794e090dc8e8031afc7559b43efc2..ffe1cd8c11d16cadfbc2068c2477fd25cec76886 100644
|
| --- a/runtime/vm/flow_graph_builder.cc
|
| +++ b/runtime/vm/flow_graph_builder.cc
|
| @@ -323,7 +323,8 @@ FlowGraphBuilder::FlowGraphBuilder(
|
| nesting_stack_(NULL),
|
| osr_id_(osr_id),
|
| jump_count_(0),
|
| - await_joins_(new (Z) ZoneGrowableArray<JoinEntryInstr*>()) {}
|
| + await_joins_(new (Z) ZoneGrowableArray<JoinEntryInstr*>()),
|
| + await_token_positions_(new (Z) ZoneGrowableArray<TokenPosition>()) {}
|
|
|
|
|
| void FlowGraphBuilder::AddCatchEntry(CatchBlockEntryInstr* entry) {
|
| @@ -1146,6 +1147,30 @@ void EffectGraphVisitor::VisitReturnNode(ReturnNode* node) {
|
| }
|
| }
|
|
|
| + if (function.IsAsyncClosure() || function.IsAsyncGenClosure()) {
|
| + // We are returning from an asynchronous closure. Before we do that, be
|
| + // sure to clear the thread's asynchronous stack trace.
|
| + const Library& async_lib = Library::Handle(Library::AsyncLibrary());
|
| + ASSERT(!async_lib.IsNull());
|
| + const String& private_name = String::ZoneHandle(
|
| + async_lib.PrivateName(Symbols::ClearAsyncThreadStackTrace()));
|
| + ASSERT(!private_name.IsNull());
|
| + const Function& async_clear_thread_stack_trace = Function::ZoneHandle(
|
| + Z,
|
| + Resolver::ResolveStatic(async_lib, String::ZoneHandle(String::null()),
|
| + private_name, 0, Object::null_array()));
|
| + ASSERT(!async_clear_thread_stack_trace.IsNull());
|
| + // Mark that this function is not debuggable.
|
| + async_clear_thread_stack_trace.set_is_debuggable(false);
|
| + ZoneGrowableArray<PushArgumentInstr*>* no_arguments =
|
| + new (Z) ZoneGrowableArray<PushArgumentInstr*>(0);
|
| + StaticCallInstr* call_async_clear_thread_stack_trace = new (Z)
|
| + StaticCallInstr(node->token_pos().ToSynthetic(),
|
| + async_clear_thread_stack_trace, Object::null_array(),
|
| + no_arguments, owner()->ic_data_array());
|
| + Do(call_async_clear_thread_stack_trace);
|
| + }
|
| +
|
| // Async functions contain two types of return statements:
|
| // 1) Returns that should complete the completer once all finally blocks have
|
| // been inlined (call: :async_completer.complete(return_value)). These
|
| @@ -1169,9 +1194,18 @@ void EffectGraphVisitor::VisitReturnNode(ReturnNode* node) {
|
| arguments->Add(PushArgument(rcv_value));
|
| Value* returned_value = Bind(BuildLoadExprTemp(node->token_pos()));
|
| arguments->Add(PushArgument(returned_value));
|
| - InstanceCallInstr* call = new (Z) InstanceCallInstr(
|
| - node->token_pos(), Symbols::CompleterComplete(), Token::kILLEGAL,
|
| - arguments, Object::null_array(), 1, owner()->ic_data_array());
|
| +
|
| + const Library& async_library = Library::Handle(Library::AsyncLibrary());
|
| + ASSERT(!async_library.IsNull());
|
| +
|
| + const Function& complete_on_async_return_function =
|
| + Function::ZoneHandle(async_library.LookupFunctionAllowPrivate(
|
| + Symbols::CompleterCompleteOnAsyncReturn()));
|
| + ASSERT(!complete_on_async_return_function.IsNull());
|
| +
|
| + StaticCallInstr* call = new (Z) StaticCallInstr(
|
| + node->token_pos().ToSynthetic(), complete_on_async_return_function,
|
| + Object::null_array(), arguments, owner()->ic_data_array());
|
| Do(call);
|
|
|
| // Rebind the return value for the actual return call to be null.
|
| @@ -2181,6 +2215,8 @@ void EffectGraphVisitor::VisitAwaitMarkerNode(AwaitMarkerNode* node) {
|
| Value* jump_val = Bind(new (Z) ConstantInstr(
|
| Smi::ZoneHandle(Z, Smi::New(jump_count)), node->token_pos()));
|
| Do(BuildStoreLocal(*jump_var, jump_val, node->token_pos()));
|
| + // Add a mapping from jump_count -> token_position.
|
| + owner()->AppendAwaitTokenPosition(node->token_pos());
|
| // Save the current context for resuming.
|
| BuildSaveContext(*ctx_var, node->token_pos());
|
| }
|
| @@ -3802,6 +3838,43 @@ void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) {
|
| }
|
| }
|
|
|
| + if (is_top_level_sequence &&
|
| + (function.IsAsyncClosure() || function.IsAsyncGenClosure())) {
|
| + LocalScope* top_scope = node->scope();
|
| + // Fetch the :async_stack_trace variable and store it into the thread.
|
| + LocalVariable* async_stack_trace_var =
|
| + top_scope->LookupVariable(Symbols::AsyncStackTraceVar(), false);
|
| + ASSERT((async_stack_trace_var != NULL) &&
|
| + async_stack_trace_var->is_captured());
|
| + // Load :async_stack_trace
|
| + Value* async_stack_trace_value = Bind(BuildLoadLocal(
|
| + *async_stack_trace_var, node->token_pos().ToSynthetic()));
|
| + // Setup arguments for _asyncSetThreadStackTrace.
|
| + ZoneGrowableArray<PushArgumentInstr*>* arguments =
|
| + new (Z) ZoneGrowableArray<PushArgumentInstr*>(1);
|
| + arguments->Add(PushArgument(async_stack_trace_value));
|
| +
|
| + // Lookup _asyncSetThreadStackTrace
|
| + const Library& async_lib = Library::Handle(Library::AsyncLibrary());
|
| + ASSERT(!async_lib.IsNull());
|
| + const String& private_name = String::ZoneHandle(
|
| + async_lib.PrivateName(Symbols::SetAsyncThreadStackTrace()));
|
| + ASSERT(!private_name.IsNull());
|
| + const Function& async_set_thread_stack_trace = Function::ZoneHandle(
|
| + Z,
|
| + Resolver::ResolveStatic(async_lib, String::ZoneHandle(String::null()),
|
| + private_name, 1, Object::null_array()));
|
| + ASSERT(!async_set_thread_stack_trace.IsNull());
|
| + // Mark that this function is not debuggable.
|
| + async_set_thread_stack_trace.set_is_debuggable(false);
|
| + // Call _asyncSetThreadStackTrace
|
| + StaticCallInstr* call_async_set_thread_stack_trace = new (Z)
|
| + StaticCallInstr(node->token_pos().ToSynthetic(),
|
| + async_set_thread_stack_trace, Object::null_array(),
|
| + arguments, owner()->ic_data_array());
|
| + Do(call_async_set_thread_stack_trace);
|
| + }
|
| +
|
| if (FLAG_support_debugger && is_top_level_sequence &&
|
| function.is_debuggable()) {
|
| // Place a debug check at method entry to ensure breaking on a method always
|
| @@ -3910,6 +3983,7 @@ void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) {
|
| entry_ = NULL;
|
| exit_ = NULL;
|
|
|
| + // Load the jump counter.
|
| LoadLocalNode* load_jump_count =
|
| new (Z) LoadLocalNode(node->token_pos(), jump_var);
|
| ComparisonNode* check_jump_count;
|
| @@ -4337,10 +4411,16 @@ FlowGraph* FlowGraphBuilder::BuildGraph() {
|
|
|
| FlowGraph* graph =
|
| new (Z) FlowGraph(parsed_function(), graph_entry_, last_used_block_id_);
|
| + graph->set_await_token_positions(await_token_positions_);
|
| return graph;
|
| }
|
|
|
|
|
| +void FlowGraphBuilder::AppendAwaitTokenPosition(TokenPosition token_pos) {
|
| + await_token_positions_->Add(token_pos);
|
| +}
|
| +
|
| +
|
| void FlowGraphBuilder::PruneUnreachable() {
|
| ASSERT(osr_id_ != Compiler::kNoOSRDeoptId);
|
| BitVector* block_marks = new (Z) BitVector(Z, last_used_block_id_ + 1);
|
|
|