| 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);
|
|
|