| Index: runtime/vm/parser.cc
 | 
| diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
 | 
| index 43d909f4e3af2f0b7a8f627314052ef065da7f46..9a016fc2ebb591aba477efc976ab898719a2650b 100644
 | 
| --- a/runtime/vm/parser.cc
 | 
| +++ b/runtime/vm/parser.cc
 | 
| @@ -296,7 +296,8 @@ Parser::Parser(const Script& script, const Library& library, intptr_t token_pos)
 | 
|        library_(Library::Handle(isolate_, library.raw())),
 | 
|        try_blocks_list_(NULL),
 | 
|        last_used_try_index_(0),
 | 
| -      unregister_pending_function_(false) {
 | 
| +      unregister_pending_function_(false),
 | 
| +      async_temp_scope_(NULL) {
 | 
|    ASSERT(tokens_iterator_.IsValid());
 | 
|    ASSERT(!library.IsNull());
 | 
|  }
 | 
| @@ -327,7 +328,8 @@ Parser::Parser(const Script& script,
 | 
|            parsed_function->function().origin()).library())),
 | 
|        try_blocks_list_(NULL),
 | 
|        last_used_try_index_(0),
 | 
| -      unregister_pending_function_(false) {
 | 
| +      unregister_pending_function_(false),
 | 
| +      async_temp_scope_(NULL) {
 | 
|    ASSERT(tokens_iterator_.IsValid());
 | 
|    ASSERT(!current_function().IsNull());
 | 
|    if (FLAG_enable_type_checks) {
 | 
| @@ -2942,6 +2944,15 @@ SequenceNode* Parser::ParseFunc(const Function& func,
 | 
|    intptr_t formal_params_pos = TokenPos();
 | 
|    // TODO(12455) : Need better validation mechanism.
 | 
|  
 | 
| +  // In case of nested async functions we also need to save the currently saved
 | 
| +  // try context, the corresponding stack variable, and the scope where
 | 
| +  // temporaries are added.
 | 
| +  LocalVariable* saved_saved_try_ctx = parsed_function()->saved_try_ctx();
 | 
| +  const String& saved_async_saved_try_ctx_name =
 | 
| +      String::Handle(I, parsed_function()->async_saved_try_ctx_name());
 | 
| +  parsed_function()->reset_saved_try_ctx_vars();
 | 
| +  LocalScope* saved_async_temp_scope = async_temp_scope_;
 | 
| +
 | 
|    if (func.IsConstructor()) {
 | 
|      SequenceNode* statements = ParseConstructor(func, default_parameter_values);
 | 
|      innermost_function_ = saved_innermost_function.raw();
 | 
| @@ -3051,8 +3062,10 @@ SequenceNode* Parser::ParseFunc(const Function& func,
 | 
|    Function& async_closure = Function::ZoneHandle(I);
 | 
|    if (func.IsAsyncFunction() && !func.is_async_closure()) {
 | 
|      async_closure = OpenAsyncFunction(formal_params_pos);
 | 
| +    async_temp_scope_ = current_block_->scope;
 | 
|    } else if (func.is_async_closure()) {
 | 
|      OpenAsyncClosure();
 | 
| +    async_temp_scope_ = current_block_->scope;
 | 
|    }
 | 
|  
 | 
|    bool saved_await_is_keyword = await_is_keyword_;
 | 
| @@ -3129,6 +3142,10 @@ SequenceNode* Parser::ParseFunc(const Function& func,
 | 
|    innermost_function_ = saved_innermost_function.raw();
 | 
|    last_used_try_index_ = saved_try_index;
 | 
|    await_is_keyword_ = saved_await_is_keyword;
 | 
| +  async_temp_scope_ = saved_async_temp_scope;
 | 
| +  parsed_function()->set_saved_try_ctx(saved_saved_try_ctx);
 | 
| +  parsed_function()->set_async_saved_try_ctx_name(
 | 
| +      saved_async_saved_try_ctx_name);
 | 
|    return CloseBlock();
 | 
|  }
 | 
|  
 | 
| @@ -5528,12 +5545,14 @@ void Parser::OpenFunctionBlock(const Function& func) {
 | 
|  
 | 
|  void Parser::OpenAsyncClosure() {
 | 
|    TRACE_PARSER("OpenAsyncClosure");
 | 
| -  parsed_function()->set_await_temps_scope(current_block_->scope);
 | 
|  }
 | 
|  
 | 
|  
 | 
|  RawFunction* Parser::OpenAsyncFunction(intptr_t formal_param_pos) {
 | 
|    TRACE_PARSER("OpenAsyncFunction");
 | 
| +
 | 
| +  AddAsyncClosureVariables();
 | 
| +
 | 
|    // Create the closure containing the old body of this function.
 | 
|    Class& sig_cls = Class::ZoneHandle(I);
 | 
|    Type& sig_type = Type::ZoneHandle(I);
 | 
| @@ -5579,6 +5598,36 @@ RawFunction* Parser::OpenAsyncFunction(intptr_t formal_param_pos) {
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void Parser::AddAsyncClosureVariables() {
 | 
| +  // Add to AST:
 | 
| +  //   var :await_jump_var;
 | 
| +  //   var :await_ctx_var;
 | 
| +  //   var :async_op;
 | 
| +  //   var :async_completer;
 | 
| +  const Type& dynamic_type = Type::ZoneHandle(I, Type::DynamicType());
 | 
| +  LocalVariable* await_jump_var = new (I) LocalVariable(
 | 
| +      Scanner::kNoSourcePos, Symbols::AwaitJumpVar(), dynamic_type);
 | 
| +  current_block_->scope->AddVariable(await_jump_var);
 | 
| +  current_block_->scope->CaptureVariable(Symbols::AwaitJumpVar());
 | 
| +  await_jump_var->set_is_captured();
 | 
| +  LocalVariable* await_ctx_var = new (I) LocalVariable(
 | 
| +      Scanner::kNoSourcePos, Symbols::AwaitContextVar(), dynamic_type);
 | 
| +  current_block_->scope->AddVariable(await_ctx_var);
 | 
| +  current_block_->scope->CaptureVariable(Symbols::AwaitContextVar());
 | 
| +  await_ctx_var->set_is_captured();
 | 
| +  LocalVariable* async_op_var = new (I) LocalVariable(
 | 
| +      Scanner::kNoSourcePos, Symbols::AsyncOperation(), dynamic_type);
 | 
| +  current_block_->scope->AddVariable(async_op_var);
 | 
| +  current_block_->scope->CaptureVariable(Symbols::AsyncOperation());
 | 
| +  async_op_var->set_is_captured();
 | 
| +  LocalVariable* async_completer = new (I) LocalVariable(
 | 
| +      Scanner::kNoSourcePos, Symbols::AsyncCompleter(), dynamic_type);
 | 
| +  current_block_->scope->AddVariable(async_completer);
 | 
| +  current_block_->scope->CaptureVariable(Symbols::AsyncCompleter());
 | 
| +  async_completer->set_is_captured();
 | 
| +}
 | 
| +
 | 
| +
 | 
|  SequenceNode* Parser::CloseBlock() {
 | 
|    SequenceNode* statements = current_block_->statements;
 | 
|    if (current_block_->scope != NULL) {
 | 
| @@ -5611,6 +5660,9 @@ SequenceNode* Parser::CloseAsyncFunction(const Function& closure,
 | 
|    // corresponding function block.
 | 
|    CloseBlock();
 | 
|  
 | 
| +  closure_body->scope()->LookupVariable(Symbols::AwaitJumpVar(), false);
 | 
| +  closure_body->scope()->CaptureVariable(Symbols::AsyncCompleter());
 | 
| +
 | 
|    // Create and return a new future that executes a closure with the current
 | 
|    // body.
 | 
|  
 | 
| @@ -5630,44 +5682,8 @@ SequenceNode* Parser::CloseAsyncFunction(const Function& closure,
 | 
|        completer.LookupFunction(Symbols::CompleterConstructor()));
 | 
|    ASSERT(!completer_constructor.IsNull());
 | 
|  
 | 
| -  bool found = false;
 | 
| -  // Add to AST:
 | 
| -  //   var :async_op;
 | 
| -  //   var :async_completer;
 | 
| -  //   var :await_jump_var;
 | 
| -  //   var :await_ctx_var;
 | 
| -  // Add as many variables to saved the try block ctx as there were try blocks.
 | 
| -  //   var :async_saved_try_ctx_var_<x>;
 | 
| -  const Type& dynamic_type = Type::ZoneHandle(I, Type::DynamicType());
 | 
| -  LocalVariable* async_op_var = new (I) LocalVariable(
 | 
| -      Scanner::kNoSourcePos, Symbols::AsyncOperation(), dynamic_type);
 | 
| -  current_block_->scope->AddVariable(async_op_var);
 | 
| -  found = closure_body->scope()->CaptureVariable(Symbols::AsyncOperation());
 | 
| -  ASSERT(found);
 | 
| -  LocalVariable* async_completer = new (I) LocalVariable(
 | 
| -      Scanner::kNoSourcePos, Symbols::AsyncCompleter(), dynamic_type);
 | 
| -  current_block_->scope->AddVariable(async_completer);
 | 
| -  found = closure_body->scope()->CaptureVariable(Symbols::AsyncCompleter());
 | 
| -  ASSERT(found);
 | 
| -  LocalVariable* await_jump_var = new (I) LocalVariable(
 | 
| -      Scanner::kNoSourcePos, Symbols::AwaitJumpVar(), dynamic_type);
 | 
| -  current_block_->scope->AddVariable(await_jump_var);
 | 
| -  found = closure_body->scope()->CaptureVariable(Symbols::AwaitJumpVar());
 | 
| -  ASSERT(found);
 | 
| -  LocalVariable* await_ctx_var = new (I) LocalVariable(
 | 
| -      Scanner::kNoSourcePos, Symbols::AwaitContextVar(), dynamic_type);
 | 
| -  current_block_->scope->AddVariable(await_ctx_var);
 | 
| -  found = closure_body->scope()->CaptureVariable(Symbols::AwaitContextVar());
 | 
| -  ASSERT(found);
 | 
| -  LocalVariable* async_saved_try_ctx_var;
 | 
| -  for (int16_t i = 0; i < last_used_try_index_; i++) {
 | 
| -    String& async_saved_try_ctx_name = BuildAsyncSavedTryContextName(I, i);
 | 
| -    async_saved_try_ctx_var = new (I) LocalVariable(
 | 
| -        Scanner::kNoSourcePos, async_saved_try_ctx_name, dynamic_type);
 | 
| -    current_block_->scope->AddVariable(async_saved_try_ctx_var);
 | 
| -    found = closure_body->scope()->CaptureVariable(async_saved_try_ctx_name);
 | 
| -    ASSERT(found);
 | 
| -  }
 | 
| +  LocalVariable* async_completer = current_block_->scope->LookupVariable(
 | 
| +      Symbols::AsyncCompleter(), false);
 | 
|  
 | 
|    // Add to AST:
 | 
|    //   :async_completer = new Completer();
 | 
| @@ -5686,6 +5702,8 @@ SequenceNode* Parser::CloseAsyncFunction(const Function& closure,
 | 
|  
 | 
|    // Add to AST:
 | 
|    //   :async_op = <closure>;  (containing the original body)
 | 
| +  LocalVariable* async_op_var = current_block_->scope->LookupVariable(
 | 
| +      Symbols::AsyncOperation(), false);
 | 
|    ClosureNode* cn = new(I) ClosureNode(
 | 
|        Scanner::kNoSourcePos, closure, NULL, closure_body->scope());
 | 
|    StoreLocalNode* store_async_op = new (I) StoreLocalNode(
 | 
| @@ -5726,9 +5744,9 @@ void Parser::CloseAsyncClosure(SequenceNode* body) {
 | 
|    // Implicitly mark those variables below as captured. We currently mark all
 | 
|    // variables of all scopes as captured (below), but as soon as we do something
 | 
|    // smarter we rely on these internal variables to be available.
 | 
| -  body->scope()->LookupVariable(Symbols::Completer(), false);
 | 
|    body->scope()->LookupVariable(Symbols::AwaitJumpVar(), false);
 | 
|    body->scope()->LookupVariable(Symbols::AwaitContextVar(), false);
 | 
| +  body->scope()->LookupVariable(Symbols::AsyncCompleter(), false);
 | 
|    body->scope()->RecursivelyCaptureAllVariables();
 | 
|  }
 | 
|  
 | 
| @@ -7268,11 +7286,13 @@ SequenceNode* Parser::ParseFinallyBlock() {
 | 
|    // In case of async closures we need to restore the saved try index of an
 | 
|    // outer try block (if it exists).  The current try block has already been
 | 
|    // removed from the stack of try blocks.
 | 
| -  if (current_function().is_async_closure() && (try_blocks_list_ != NULL)) {
 | 
| +  if ((innermost_function().is_async_closure() ||
 | 
| +       innermost_function().IsAsyncFunction()) &&
 | 
| +      (try_blocks_list_ != NULL)) {
 | 
|      // We need two unchain two scopes: finally clause, and the try block level.
 | 
| -    SetupSavedTryContext(current_block_->scope->parent()->parent(),
 | 
| -                         try_blocks_list_->try_index(),
 | 
| -                         current_block_->statements);
 | 
| +    RestoreSavedTryContext(current_block_->scope->parent()->parent(),
 | 
| +                           try_blocks_list_->try_index(),
 | 
| +                           current_block_->statements);
 | 
|    } else {
 | 
|      parsed_function()->reset_saved_try_ctx_vars();
 | 
|    }
 | 
| @@ -7426,15 +7446,21 @@ SequenceNode* Parser::ParseCatchClauses(
 | 
|      // In case of async closures we need to restore the saved try index of an
 | 
|      // outer try block (if it exists).
 | 
|      ASSERT(try_blocks_list_ != NULL);
 | 
| -    if (current_function().is_async_closure() &&
 | 
| -        (try_blocks_list_->outer_try_block() != NULL)) {
 | 
| -      // We need to unchain three scope levels: catch clause, catch parameters,
 | 
| -      // and the general try block.
 | 
| -      SetupSavedTryContext(current_block_->scope->parent()->parent()->parent(),
 | 
| -                           try_blocks_list_->outer_try_block()->try_index(),
 | 
| -                           current_block_->statements);
 | 
| -    } else {
 | 
| -      parsed_function()->reset_saved_try_ctx_vars();
 | 
| +    if (innermost_function().is_async_closure() ||
 | 
| +        innermost_function().IsAsyncFunction()) {
 | 
| +      if ((try_blocks_list_->outer_try_block() != NULL) &&
 | 
| +          (try_blocks_list_->outer_try_block()->try_block()
 | 
| +              ->scope->function_level() ==
 | 
| +           current_block_->scope->function_level())) {
 | 
| +        // We need to unchain three scope levels: catch clause, catch
 | 
| +        // parameters, and the general try block.
 | 
| +        RestoreSavedTryContext(
 | 
| +            current_block_->scope->parent()->parent()->parent(),
 | 
| +            try_blocks_list_->outer_try_block()->try_index(),
 | 
| +            current_block_->statements);
 | 
| +      } else {
 | 
| +        parsed_function()->reset_saved_try_ctx_vars();
 | 
| +      }
 | 
|      }
 | 
|  
 | 
|      current_block_->statements->Add(ParseNestedStatement(false, NULL));
 | 
| @@ -7532,6 +7558,27 @@ SequenceNode* Parser::ParseCatchClauses(
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void Parser::SetupSavedTryContext(LocalVariable* saved_try_context) {
 | 
| +  const String& async_saved_try_ctx_name =
 | 
| +      BuildAsyncSavedTryContextName(I, last_used_try_index_ - 1);
 | 
| +  LocalVariable* async_saved_try_ctx = new (I) LocalVariable(
 | 
| +      Scanner::kNoSourcePos,
 | 
| +      async_saved_try_ctx_name,
 | 
| +      Type::ZoneHandle(I, Type::DynamicType()));
 | 
| +  async_temp_scope_->AddVariable(async_saved_try_ctx);
 | 
| +  async_saved_try_ctx->set_is_captured();
 | 
| +  async_saved_try_ctx = current_block_->scope->LookupVariable(
 | 
| +      async_saved_try_ctx_name, false);
 | 
| +  ASSERT(async_saved_try_ctx != NULL);
 | 
| +  ASSERT(saved_try_context != NULL);
 | 
| +  current_block_->statements->Add(new (I) StoreLocalNode(
 | 
| +      Scanner::kNoSourcePos, async_saved_try_ctx, new (I) LoadLocalNode(
 | 
| +          Scanner::kNoSourcePos, saved_try_context)));
 | 
| +  parsed_function()->set_saved_try_ctx(saved_try_context);
 | 
| +  parsed_function()->set_async_saved_try_ctx_name(async_saved_try_ctx_name);
 | 
| +}
 | 
| +
 | 
| +
 | 
|  // Set up the currently relevant :saved_try_context_var on the stack:
 | 
|  // * Try blocks: Set the context variable for this try block.
 | 
|  // * Catch/finally blocks: Set the context variable for any outer try block (if
 | 
| @@ -7539,9 +7586,9 @@ SequenceNode* Parser::ParseCatchClauses(
 | 
|  //
 | 
|  // Also save the captured variable and the stack variable to be able to set
 | 
|  // it after a function continues execution (await).
 | 
| -void Parser::SetupSavedTryContext(LocalScope* saved_try_context_scope,
 | 
| -                                  int16_t try_index,
 | 
| -                                  SequenceNode* target) {
 | 
| +void Parser::RestoreSavedTryContext(LocalScope* saved_try_context_scope,
 | 
| +                                    int16_t try_index,
 | 
| +                                    SequenceNode* target) {
 | 
|    LocalVariable* saved_try_ctx = saved_try_context_scope->LookupVariable(
 | 
|        Symbols::SavedTryContextVar(), false);
 | 
|    ASSERT((saved_try_ctx != NULL) && !saved_try_ctx->is_captured());
 | 
| @@ -7549,13 +7596,15 @@ void Parser::SetupSavedTryContext(LocalScope* saved_try_context_scope,
 | 
|        BuildAsyncSavedTryContextName(I, try_index);
 | 
|    LocalVariable* async_saved_try_ctx =
 | 
|        target->scope()->LookupVariable(async_saved_try_ctx_name, false);
 | 
| -  ASSERT((async_saved_try_ctx != NULL) && async_saved_try_ctx->is_captured());
 | 
| +  ASSERT(async_saved_try_ctx != NULL);
 | 
| +  ASSERT(async_saved_try_ctx->is_captured());
 | 
|    target->Add(new (I) StoreLocalNode(
 | 
| -      Scanner::kNoSourcePos, saved_try_ctx, new (I) LoadLocalNode(
 | 
| -          Scanner::kNoSourcePos, async_saved_try_ctx)));
 | 
| +      Scanner::kNoSourcePos,
 | 
| +      saved_try_ctx,
 | 
| +      new (I) LoadLocalNode(Scanner::kNoSourcePos, async_saved_try_ctx)));
 | 
|  
 | 
|    parsed_function()->set_saved_try_ctx(saved_try_ctx);
 | 
| -  parsed_function()->set_async_saved_try_ctx(async_saved_try_ctx);
 | 
| +  parsed_function()->set_async_saved_try_ctx_name(async_saved_try_ctx_name);
 | 
|  }
 | 
|  
 | 
|  
 | 
| @@ -7618,19 +7667,9 @@ AstNode* Parser::ParseTryStatement(String* label_name) {
 | 
|    PushTryBlock(current_block_);
 | 
|    ExpectToken(Token::kLBRACE);
 | 
|  
 | 
| -  if (current_function().is_async_closure()) {
 | 
| -    const String& async_saved_try_ctx_name =
 | 
| -        BuildAsyncSavedTryContextName(I, last_used_try_index_ - 1);
 | 
| -    LocalVariable* async_saved_try_ctx =
 | 
| -        current_block_->scope->LookupVariable(
 | 
| -            async_saved_try_ctx_name, false);
 | 
| -    ASSERT(async_saved_try_ctx != NULL);
 | 
| -    ASSERT(context_var != NULL);
 | 
| -    current_block_->statements->Add(new (I) StoreLocalNode(
 | 
| -        Scanner::kNoSourcePos, async_saved_try_ctx, new (I) LoadLocalNode(
 | 
| -            Scanner::kNoSourcePos, context_var)));
 | 
| -    parsed_function()->set_saved_try_ctx(context_var);
 | 
| -    parsed_function()->set_async_saved_try_ctx(async_saved_try_ctx);
 | 
| +  if (innermost_function().is_async_closure() ||
 | 
| +      innermost_function().IsAsyncFunction()) {
 | 
| +    SetupSavedTryContext(context_var);
 | 
|    }
 | 
|  
 | 
|    ParseStatementSequence();
 | 
| @@ -7706,20 +7745,6 @@ AstNode* Parser::ParseTryStatement(String* label_name) {
 | 
|      try_catch_node = sequence;
 | 
|    }
 | 
|  
 | 
| -  // In case of async closures we need to restore the saved try index of an
 | 
| -  // outer try block (if it exists).
 | 
| -  if (current_function().is_async_closure() &&
 | 
| -      (outer_try_index != CatchClauseNode::kInvalidTryIndex)) {
 | 
| -    SequenceNode* try_catch_and_restore_try_ctx = new (I) SequenceNode(
 | 
| -        Scanner::kNoSourcePos, current_block_->scope);
 | 
| -    try_catch_and_restore_try_ctx->Add(try_catch_node);
 | 
| -    SetupSavedTryContext(
 | 
| -        current_block_->scope, outer_try_index, try_catch_and_restore_try_ctx);
 | 
| -    return try_catch_and_restore_try_ctx;
 | 
| -  } else {
 | 
| -    parsed_function()->reset_saved_try_ctx_vars();
 | 
| -  }
 | 
| -
 | 
|    return try_catch_node;
 | 
|  }
 | 
|  
 | 
| @@ -8557,18 +8582,17 @@ AstNode* Parser::ParseAwaitableExpr(bool require_compiletime_const,
 | 
|    parsed_function()->reset_have_seen_await();
 | 
|    AstNode* expr = ParseExpr(require_compiletime_const, consume_cascades);
 | 
|    if (parsed_function()->have_seen_await()) {
 | 
| -    if (!current_block_->scope->LookupVariable(
 | 
| -          Symbols::AsyncOperation(), true)) {
 | 
| -      // Async operations are always encapsulated into a local function. We only
 | 
| -      // need to transform the expression when generating code for this inner
 | 
| -      // function.
 | 
| -      return expr;
 | 
| -    }
 | 
| -    SequenceNode* intermediates_block = new(I) SequenceNode(
 | 
| -        Scanner::kNoSourcePos, current_block_->scope);
 | 
| -    AwaitTransformer at(intermediates_block, library_, parsed_function());
 | 
| +    // Make sure we do not reuse the scope to avoid creating contexts that we
 | 
| +    // are unaware of, i.e, creating contexts that have already been covered.
 | 
| +    // See FlowGraphBuilder::VisitSequenceNode() for details on when contexts
 | 
| +    // are created.
 | 
| +    OpenBlock();
 | 
| +    AwaitTransformer at(current_block_->statements,
 | 
| +                        library_,
 | 
| +                        parsed_function(),
 | 
| +                        async_temp_scope_);
 | 
|      AstNode* result = at.Transform(expr);
 | 
| -    current_block_->statements->Add(intermediates_block);
 | 
| +    current_block_->statements->Add(CloseBlock());
 | 
|      parsed_function()->reset_have_seen_await();
 | 
|      return result;
 | 
|    }
 | 
| 
 |