Index: runtime/vm/parser.cc |
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc |
index 51bca8edb4ca6ceafe29d1e8a11f00b97bdd2c92..167ea1ea98c23ff637ae53577500ee1c9c714eac 100644 |
--- a/runtime/vm/parser.cc |
+++ b/runtime/vm/parser.cc |
@@ -3571,10 +3571,16 @@ SequenceNode* Parser::ParseFunc(const Function& func, bool check_semicolon) { |
ASSERT(!func.is_generated_body()); |
// The code of an async function is synthesized. Disable debugging. |
func.set_is_debuggable(false); |
+ // In order to collect causal asynchronous stacks efficiently we rely on |
+ // this function not being inlined. |
+ func.set_is_inlinable(!FLAG_causal_async_stacks); |
generated_body_closure = OpenAsyncFunction(func.token_pos()); |
} else if (func.IsAsyncClosure()) { |
// The closure containing the body of an async function is debuggable. |
ASSERT(func.is_debuggable()); |
+ // In order to collect causal asynchronous stacks efficiently we rely on |
+ // this function not being inlined. |
+ func.set_is_inlinable(!FLAG_causal_async_stacks); |
OpenAsyncClosure(); |
} else if (func.IsSyncGenerator()) { |
// The code of a sync generator is synthesized. Disable debugging. |
@@ -3586,10 +3592,16 @@ SequenceNode* Parser::ParseFunc(const Function& func, bool check_semicolon) { |
async_temp_scope_ = current_block_->scope; |
} else if (func.IsAsyncGenerator()) { |
func.set_is_debuggable(false); |
+ // In order to collect causal asynchronous stacks efficiently we rely on |
+ // this function not being inlined. |
+ func.set_is_inlinable(!FLAG_causal_async_stacks); |
generated_body_closure = OpenAsyncGeneratorFunction(func.token_pos()); |
} else if (func.IsAsyncGenClosure()) { |
// The closure containing the body of an async* function is debuggable. |
ASSERT(func.is_debuggable()); |
+ // In order to collect causal asynchronous stacks efficiently we rely on |
+ // this function not being inlined. |
+ func.set_is_inlinable(!FLAG_causal_async_stacks); |
OpenAsyncGeneratorClosure(); |
} |
@@ -7037,6 +7049,7 @@ void Parser::AddAsyncClosureVariables() { |
// var :async_then_callback; |
// var :async_catch_error_callback; |
// var :async_completer; |
+ // var :async_stack_trace; |
LocalVariable* async_op_var = |
new (Z) LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource, |
Symbols::AsyncOperation(), Object::dynamic_type()); |
@@ -7053,6 +7066,10 @@ void Parser::AddAsyncClosureVariables() { |
new (Z) LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource, |
Symbols::AsyncCompleter(), Object::dynamic_type()); |
current_block_->scope->AddVariable(async_completer); |
+ LocalVariable* async_stack_trace = new (Z) |
+ LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource, |
+ Symbols::AsyncStackTraceVar(), Object::dynamic_type()); |
+ current_block_->scope->AddVariable(async_stack_trace); |
} |
@@ -7065,6 +7082,7 @@ void Parser::AddAsyncGeneratorVariables() { |
// var :async_op; |
// var :async_then_callback; |
// var :async_catch_error_callback; |
+ // var :async_stack_trace; |
// These variables are used to store the async generator closure containing |
// the body of the async* function. They are used by the await operator. |
LocalVariable* controller_var = |
@@ -7083,6 +7101,10 @@ void Parser::AddAsyncGeneratorVariables() { |
LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource, |
Symbols::AsyncCatchErrorCallback(), Object::dynamic_type()); |
current_block_->scope->AddVariable(async_catch_error_callback_var); |
+ LocalVariable* async_stack_trace = new (Z) |
+ LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource, |
+ Symbols::AsyncStackTraceVar(), Object::dynamic_type()); |
+ current_block_->scope->AddVariable(async_stack_trace); |
} |
@@ -7180,6 +7202,9 @@ SequenceNode* Parser::CloseAsyncGeneratorFunction(const Function& closure_func, |
existing_var = closure_body->scope()->LookupVariable( |
Symbols::AsyncCatchErrorCallback(), false); |
ASSERT((existing_var != NULL) && existing_var->is_captured()); |
+ existing_var = closure_body->scope()->LookupVariable( |
+ Symbols::AsyncStackTraceVar(), false); |
+ ASSERT((existing_var != NULL) && existing_var->is_captured()); |
const Library& async_lib = Library::Handle(Library::AsyncLibrary()); |
@@ -7199,6 +7224,28 @@ SequenceNode* Parser::CloseAsyncGeneratorFunction(const Function& closure_func, |
current_block_->statements->Add( |
new (Z) StoreLocalNode(TokenPosition::kNoSource, jump_var, init_value)); |
+ TokenPosition token_pos = TokenPosition::kNoSource; |
+ |
+ if (FLAG_causal_async_stacks) { |
+ // Add to AST: |
+ // :async_stack_trace = _asyncStackTraceHelper(); |
+ const Function& async_stack_trace_helper = Function::ZoneHandle( |
+ Z, |
+ async_lib.LookupFunctionAllowPrivate(Symbols::AsyncStackTraceHelper())); |
+ ASSERT(!async_stack_trace_helper.IsNull()); |
+ ArgumentListNode* async_stack_trace_helper_args = |
+ new (Z) ArgumentListNode(TokenPosition::kNoSource); |
+ StaticCallNode* async_stack_trace_helper_call = new (Z) StaticCallNode( |
+ token_pos, async_stack_trace_helper, async_stack_trace_helper_args); |
+ LocalVariable* async_stack_trace_var = |
+ current_block_->scope->LookupVariable(Symbols::AsyncStackTraceVar(), |
+ false); |
+ StoreLocalNode* store_async_stack_trace = new (Z) StoreLocalNode( |
+ token_pos, async_stack_trace_var, async_stack_trace_helper_call); |
+ current_block_->statements->Add(store_async_stack_trace); |
+ } |
+ |
+ |
// Add to AST: |
// :async_op = <closure>; (containing the original body) |
LocalVariable* async_op_var = |
@@ -7342,6 +7389,9 @@ SequenceNode* Parser::CloseAsyncFunction(const Function& closure, |
existing_var = |
closure_body->scope()->LookupVariable(Symbols::AsyncCompleter(), false); |
ASSERT((existing_var != NULL) && existing_var->is_captured()); |
+ existing_var = closure_body->scope()->LookupVariable( |
+ Symbols::AsyncStackTraceVar(), false); |
+ ASSERT((existing_var != NULL) && existing_var->is_captured()); |
// Create and return a new future that executes a closure with the current |
// body. |
@@ -7394,6 +7444,26 @@ SequenceNode* Parser::CloseAsyncFunction(const Function& closure, |
current_block_->statements->Add(store_async_op); |
const Library& async_lib = Library::Handle(Library::AsyncLibrary()); |
+ |
+ if (FLAG_causal_async_stacks) { |
+ // Add to AST: |
+ // :async_stack_trace = _asyncStackTraceHelper(); |
+ const Function& async_stack_trace_helper = Function::ZoneHandle( |
+ Z, |
+ async_lib.LookupFunctionAllowPrivate(Symbols::AsyncStackTraceHelper())); |
+ ASSERT(!async_stack_trace_helper.IsNull()); |
+ ArgumentListNode* async_stack_trace_helper_args = |
+ new (Z) ArgumentListNode(token_pos); |
+ StaticCallNode* async_stack_trace_helper_call = new (Z) StaticCallNode( |
+ token_pos, async_stack_trace_helper, async_stack_trace_helper_args); |
+ LocalVariable* async_stack_trace_var = |
+ current_block_->scope->LookupVariable(Symbols::AsyncStackTraceVar(), |
+ false); |
+ StoreLocalNode* store_async_stack_trace = new (Z) StoreLocalNode( |
+ token_pos, async_stack_trace_var, async_stack_trace_helper_call); |
+ current_block_->statements->Add(store_async_stack_trace); |
+ } |
+ |
// :async_then_callback = _asyncThenWrapperHelper(:async_op) |
const Function& async_then_wrapper_helper = Function::ZoneHandle( |
Z, |