Index: runtime/vm/flow_graph_builder.cc |
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc |
index e13672d724ec4c4afb8d791c3cf0fc724b1db5f4..a6547d17415947ede1c55dc2df63c0765d8b60ae 100644 |
--- a/runtime/vm/flow_graph_builder.cc |
+++ b/runtime/vm/flow_graph_builder.cc |
@@ -1131,6 +1131,21 @@ void EffectGraphVisitor::VisitReturnNode(ReturnNode* node) { |
} |
} |
+ if (FLAG_causal_async_stacks && |
+ (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 Function& async_clear_thread_stack_trace = Function::ZoneHandle( |
+ Z, isolate()->object_store()->async_clear_thread_stack_trace()); |
+ 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 |
@@ -3792,6 +3807,34 @@ void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) { |
} |
} |
+ if (FLAG_causal_async_stacks && 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)); |
+ |
+ const Function& async_set_thread_stack_trace = Function::ZoneHandle( |
+ Z, isolate()->object_store()->async_set_thread_stack_trace()); |
+ ASSERT(!async_set_thread_stack_trace.IsNull()); |
+ // 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 |