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

Unified Diff: runtime/vm/parser.cc

Issue 2603383004: Sane asynchronous debugging and stack traces (Closed)
Patch Set: rebase Created 3 years, 11 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/object.cc ('k') | runtime/vm/raw_object.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/parser.cc
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 923526885ecea9685b32b527aa03bcd12b6b9592..25d83e7bd725a320e01f56268f37f15562bb131b 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -3468,6 +3468,9 @@ 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 produce sane asynchronous stacks we rely on this function
+ // not being inlined.
+ func.set_is_inlinable(false);
generated_body_closure = OpenAsyncFunction(func.token_pos());
} else if (func.IsAsyncClosure()) {
// The closure containing the body of an async function is debuggable.
@@ -6808,6 +6811,9 @@ RawFunction* Parser::OpenAsyncFunction(TokenPosition async_func_pos) {
closure = Function::NewClosureFunction(closure_name, innermost_function(),
async_func_pos);
closure.set_is_generated_body(true);
+ // In order to generate sane asynchronous stacks we rely on this function
+ // not being inlined.
+ closure.set_is_inlinable(false);
closure.set_result_type(Object::dynamic_type());
is_new_closure = true;
}
@@ -6861,6 +6867,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());
@@ -6877,6 +6884,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);
}
@@ -6889,6 +6900,8 @@ void Parser::AddAsyncGeneratorVariables() {
// var :async_op;
// var :async_then_callback;
// var :async_catch_error_callback;
+ // var :async_stack_trace;
+ // var :controller_stream
// 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 =
@@ -6907,6 +6920,14 @@ 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);
+ LocalVariable* controller_stream = new (Z)
+ LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
+ Symbols::ControllerStream(), Object::dynamic_type());
+ current_block_->scope->AddVariable(controller_stream);
}
@@ -6936,6 +6957,7 @@ RawFunction* Parser::OpenAsyncGeneratorFunction(TokenPosition async_func_pos) {
closure = Function::NewClosureFunction(closure_name, innermost_function(),
async_func_pos);
closure.set_is_generated_body(true);
+ closure.set_is_inlinable(false);
closure.set_result_type(Object::dynamic_type());
is_new_closure = true;
}
@@ -6976,7 +6998,8 @@ RawFunction* Parser::OpenAsyncGeneratorFunction(TokenPosition async_func_pos) {
// var :async_then_callback = _asyncThenWrapperHelper(:async_op);
// var :async_catch_error_callback = _asyncCatchErrorWrapperHelper(:async_op);
// :controller = new _AsyncStarStreamController(:async_op);
-// return :controller.stream;
+// var :controller_stream = :controller.stream;
+// return :controller_stream;
// }
SequenceNode* Parser::CloseAsyncGeneratorFunction(const Function& closure_func,
SequenceNode* closure_body) {
@@ -7004,6 +7027,12 @@ 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());
+ existing_var =
+ closure_body->scope()->LookupVariable(Symbols::ControllerStream(), false);
+ ASSERT((existing_var != NULL) && existing_var->is_captured());
const Library& async_lib = Library::Handle(Library::AsyncLibrary());
@@ -7015,6 +7044,8 @@ SequenceNode* Parser::CloseAsyncGeneratorFunction(const Function& closure_func,
Z, controller_class.LookupConstructorAllowPrivate(
Symbols::_AsyncStarStreamControllerConstructor()));
+ TokenPosition token_pos = TokenPosition::kNoSource;
+
// :await_jump_var = -1;
LocalVariable* jump_var =
current_block_->scope->LookupVariable(Symbols::AwaitJumpVar(), false);
@@ -7034,6 +7065,24 @@ SequenceNode* Parser::CloseAsyncGeneratorFunction(const Function& closure_func,
current_block_->statements->Add(store_async_op);
+ // Add to AST:
+ // :async_stack_trace = _asyncStackTraceHelper(:async_op);
+ 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);
+ async_stack_trace_helper_args->Add(
+ new (Z) LoadLocalNode(TokenPosition::kNoSource, async_op_var));
+ 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,
@@ -7090,13 +7139,28 @@ SequenceNode* Parser::CloseAsyncGeneratorFunction(const Function& closure_func,
TokenPosition::kNoSource, controller_var, controller_constructor_call);
current_block_->statements->Add(store_controller);
- // return :controller.stream;
+ // Grab :controller.stream
+ InstanceGetterNode* controller_stream = new (Z) InstanceGetterNode(
+ TokenPosition::kNoSource,
+ new (Z) LoadLocalNode(TokenPosition::kNoSource, controller_var),
+ Symbols::Stream());
+
+ // Store :controller.stream into :controller_stream inside the closure.
+ // We have to remember the stream because a new instance is generated for
+ // each getter invocation and in order to recreate the linkage, we need the
+ // awaited on instance.
+ LocalVariable* controller_stream_var =
+ current_block_->scope->LookupVariable(Symbols::ControllerStream(), false);
+ ASSERT(controller_stream_var != NULL);
+
+ StoreLocalNode* store_controller_stream = new (Z) StoreLocalNode(
+ TokenPosition::kNoSource, controller_stream_var, controller_stream);
+ current_block_->statements->Add(store_controller_stream);
+
+ // return :controller_stream;
ReturnNode* return_node = new (Z) ReturnNode(
TokenPosition::kNoSource,
- new (Z) InstanceGetterNode(
- TokenPosition::kNoSource,
- new (Z) LoadLocalNode(TokenPosition::kNoSource, controller_var),
- Symbols::Stream()));
+ new (Z) LoadLocalNode(TokenPosition::kNoSource, controller_stream_var));
current_block_->statements->Add(return_node);
return CloseBlock();
}
@@ -7166,6 +7230,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.
@@ -7185,6 +7252,8 @@ SequenceNode* Parser::CloseAsyncFunction(const Function& closure,
Z, completer.LookupFunction(Symbols::CompleterSyncConstructor()));
ASSERT(!completer_constructor.IsNull());
+ const Library& async_lib = Library::Handle(Library::AsyncLibrary());
+
LocalVariable* async_completer =
current_block_->scope->LookupVariable(Symbols::AsyncCompleter(), false);
@@ -7217,7 +7286,24 @@ SequenceNode* Parser::CloseAsyncFunction(const Function& closure,
new (Z) StoreLocalNode(token_pos, async_op_var, cn);
current_block_->statements->Add(store_async_op);
- const Library& async_lib = Library::Handle(Library::AsyncLibrary());
+ // Add to AST:
+ // :async_stack_trace = _asyncStackTraceHelper(:async_op);
+ 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);
+ async_stack_trace_helper_args->Add(
+ new (Z) LoadLocalNode(token_pos, async_op_var));
+ 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,
@@ -8779,6 +8865,36 @@ AstNode* Parser::ParseAwaitForStatement(String* label_name) {
ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL);
ExpectToken(Token::kRPAREN);
+ // Create :stream to store the stream into temporarily.
+ LocalVariable* stream_var =
+ new (Z) LocalVariable(stream_expr_pos, stream_expr_pos,
+ Symbols::ColonStream(), Object::dynamic_type());
+ current_block_->scope->AddVariable(stream_var);
+
+ // Store the stream expression into a variable.
+ StoreLocalNode* store_stream_var =
+ new (Z) StoreLocalNode(stream_expr_pos, stream_var, stream_expr);
+ current_block_->statements->Add(store_stream_var);
+
+ // Register the awaiter on the stream by invoking `_asyncStarListenHelper`.
+ const Library& async_lib = Library::Handle(Library::AsyncLibrary());
+ const Function& async_star_listen_helper = Function::ZoneHandle(
+ Z,
+ async_lib.LookupFunctionAllowPrivate(Symbols::_AsyncStarListenHelper()));
+ ASSERT(!async_star_listen_helper.IsNull());
+ LocalVariable* async_op_var =
+ current_block_->scope->LookupVariable(Symbols::AsyncOperation(), false);
+ ASSERT(async_op_var != NULL);
+ ArgumentListNode* async_star_listen_helper_args =
+ new (Z) ArgumentListNode(stream_expr_pos);
+ async_star_listen_helper_args->Add(
+ new (Z) LoadLocalNode(stream_expr_pos, stream_var));
+ async_star_listen_helper_args->Add(
+ new (Z) LoadLocalNode(stream_expr_pos, async_op_var));
+ StaticCallNode* async_star_listen_helper_call = new (Z) StaticCallNode(
+ stream_expr_pos, async_star_listen_helper, async_star_listen_helper_args);
+ current_block_->statements->Add(async_star_listen_helper_call);
+
// Build creation of implicit StreamIterator.
// var :for-in-iter = new StreamIterator(stream_expr).
const Class& stream_iterator_cls =
@@ -8789,7 +8905,7 @@ AstNode* Parser::ParseAwaitForStatement(String* label_name) {
stream_iterator_cls.LookupFunction(Symbols::StreamIteratorConstructor()));
ASSERT(!iterator_ctor.IsNull());
ArgumentListNode* ctor_args = new (Z) ArgumentListNode(stream_expr_pos);
- ctor_args->Add(stream_expr);
+ ctor_args->Add(new (Z) LoadLocalNode(stream_expr_pos, stream_var));
ConstructorCallNode* ctor_call = new (Z) ConstructorCallNode(
stream_expr_pos, TypeArguments::ZoneHandle(Z), iterator_ctor, ctor_args);
const AbstractType& iterator_type = Object::dynamic_type();
@@ -8834,7 +8950,23 @@ AstNode* Parser::ParseAwaitForStatement(String* label_name) {
AstNode* iterator_moveNext = new (Z) InstanceCallNode(
stream_expr_pos, new (Z) LoadLocalNode(stream_expr_pos, iterator_var),
Symbols::MoveNext(), no_args);
+
OpenBlock();
+ // Give the debugger an opportunity to 'step into' the generator by
+ // calling '_asyncStarMoveNextHelper'.
+ const Function& async_star_move_next_helper =
+ Function::ZoneHandle(Z, async_lib.LookupFunctionAllowPrivate(
+ Symbols::_AsyncStarMoveNextHelper()));
+ ASSERT(!async_star_move_next_helper.IsNull());
+ ASSERT(async_op_var != NULL);
+ ArgumentListNode* async_star_move_next_helper_args =
+ new (Z) ArgumentListNode(stream_expr_pos);
+ async_star_move_next_helper_args->Add(
+ new (Z) LoadLocalNode(stream_expr_pos, stream_var));
+ StaticCallNode* async_star_move_next_helper_call =
+ new (Z) StaticCallNode(stream_expr_pos, async_star_move_next_helper,
+ async_star_move_next_helper_args);
+ current_block_->statements->Add(async_star_move_next_helper_call);
AstNode* await_moveNext = new (Z) AwaitNode(
stream_expr_pos, iterator_moveNext, saved_try_ctx, async_saved_try_ctx,
outer_saved_try_ctx, outer_async_saved_try_ctx, current_block_->scope);
« no previous file with comments | « runtime/vm/object.cc ('k') | runtime/vm/raw_object.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698