Index: runtime/vm/parser.cc |
=================================================================== |
--- runtime/vm/parser.cc (revision 45079) |
+++ runtime/vm/parser.cc (working copy) |
@@ -8255,6 +8255,28 @@ |
} |
+static LocalVariable* LookupSavedTryContextVar(LocalScope* scope) { |
+ LocalVariable* var = |
+ scope->LocalLookupVariable(Symbols::SavedTryContextVar()); |
+ ASSERT((var != NULL) && !var->is_captured()); |
+ return var; |
+} |
+ |
+ |
+static LocalVariable* LookupAsyncSavedTryContextVar(LocalScope* scope, |
+ uint16_t try_index) { |
+ const String& async_saved_try_ctx_name = |
+ String::ZoneHandle(Symbols::New(String::Handle( |
+ String::NewFormatted( |
+ "%s%d", |
+ Symbols::AsyncSavedTryCtxVarPrefix().ToCString(), |
+ try_index)))); |
+ LocalVariable* var = scope->LocalLookupVariable(async_saved_try_ctx_name); |
+ ASSERT((var != NULL) && var->is_captured());\ |
+ return var; |
+} |
+ |
+ |
// If the await or yield being parsed is in a try block, the continuation code |
// needs to restore the corresponding stack-based variable :saved_try_ctx_var, |
// and the stack-based variable :saved_try_ctx_var of the outer try block. |
@@ -8269,32 +8291,33 @@ |
// Set the context variable for the outer try block. Note that the try |
// declaring the finally is popped before parsing the finally clause, so the |
// outer try block is at the top of the try block list. |
-// |
-// TODO(regis): Could we return the variables instead of their containing |
-// scopes? Check if they are already setup at this point. |
-void Parser::CheckAsyncOpInTryBlock(LocalScope** try_scope, |
- int16_t* try_index, |
- LocalScope** outer_try_scope, |
- int16_t* outer_try_index) const { |
- *try_scope = NULL; |
- *try_index = CatchClauseNode::kInvalidTryIndex; |
- *outer_try_scope = NULL; |
- *outer_try_index = CatchClauseNode::kInvalidTryIndex; |
+void Parser::CheckAsyncOpInTryBlock( |
+ LocalVariable** saved_try_ctx, |
+ LocalVariable** async_saved_try_ctx, |
+ LocalVariable** outer_saved_try_ctx, |
+ LocalVariable** outer_async_saved_try_ctx) const { |
+ *saved_try_ctx = NULL; |
+ *async_saved_try_ctx = NULL; |
+ *outer_saved_try_ctx = NULL; |
+ *outer_async_saved_try_ctx = NULL; |
if (try_stack_ != NULL) { |
LocalScope* scope = try_stack_->try_block()->scope; |
+ uint16_t try_index = try_stack_->try_index(); |
const int current_function_level = current_block_->scope->function_level(); |
if (scope->function_level() == current_function_level) { |
// The block declaring :saved_try_ctx_var variable is the parent of the |
// pushed try block. |
- *try_scope = scope->parent(); |
- *try_index = try_stack_->try_index(); |
+ *saved_try_ctx = LookupSavedTryContextVar(scope->parent()); |
+ *async_saved_try_ctx = LookupAsyncSavedTryContextVar(scope, try_index); |
if (try_stack_->outer_try() != NULL) { |
// TODO(regis): Collecting the outer try scope is not necessary if we |
// are in a finally block. Add support for try_stack_->inside_finally(). |
scope = try_stack_->outer_try()->try_block()->scope; |
+ try_index = try_stack_->outer_try()->try_index(); |
if (scope->function_level() == current_function_level) { |
- *outer_try_scope = scope->parent(); |
- *outer_try_index = try_stack_->outer_try()->try_index(); |
+ *outer_saved_try_ctx = LookupSavedTryContextVar(scope->parent()); |
+ *outer_async_saved_try_ctx = |
+ LookupAsyncSavedTryContextVar(scope, try_index); |
} |
} |
} |
@@ -8302,7 +8325,7 @@ |
// An async or async* has an implicitly created try-catch around the |
// function body, so the await or yield inside the async closure should always |
// be created with a try scope. |
- ASSERT((*try_scope != NULL) || |
+ ASSERT((*saved_try_ctx != NULL) || |
innermost_function().IsAsyncFunction() || |
innermost_function().IsAsyncGenerator() || |
innermost_function().IsSyncGenClosure() || |
@@ -8426,13 +8449,14 @@ |
// Build while loop condition. |
// while (await :for-in-iter.moveNext()) |
- LocalScope* try_scope; |
- int16_t try_index; |
- LocalScope* outer_try_scope; |
- int16_t outer_try_index; |
- CheckAsyncOpInTryBlock(&try_scope, &try_index, |
- &outer_try_scope, &outer_try_index); |
- |
+ LocalVariable* saved_try_ctx; |
+ LocalVariable* async_saved_try_ctx; |
+ LocalVariable* outer_saved_try_ctx; |
+ LocalVariable* outer_async_saved_try_ctx; |
+ CheckAsyncOpInTryBlock(&saved_try_ctx, |
+ &async_saved_try_ctx, |
+ &outer_saved_try_ctx, |
+ &outer_async_saved_try_ctx); |
ArgumentListNode* no_args = new(Z) ArgumentListNode(stream_pos); |
AstNode* iterator_moveNext = new(Z) InstanceCallNode( |
stream_pos, |
@@ -8442,10 +8466,10 @@ |
AstNode* await_moveNext = |
new(Z) AwaitNode(stream_pos, |
iterator_moveNext, |
- try_scope, |
- try_index, |
- outer_try_scope, |
- outer_try_index); |
+ saved_try_ctx, |
+ async_saved_try_ctx, |
+ outer_saved_try_ctx, |
+ outer_async_saved_try_ctx); |
OpenBlock(); |
AwaitTransformer at(current_block_->statements, async_temp_scope_); |
await_moveNext = at.Transform(await_moveNext); |
@@ -8523,9 +8547,12 @@ |
try_stack_->enter_catch(); |
SequenceNode* catch_block = new(Z) SequenceNode(await_for_pos, NULL); |
- if (outer_try_scope != NULL) { |
- catch_block->Add(AwaitTransformer::RestoreSavedTryContext( |
- Z, outer_try_scope, outer_try_index)); |
+ if (outer_saved_try_ctx != NULL) { |
+ catch_block->Add(new (Z) StoreLocalNode( |
+ Scanner::kNoSourcePos, |
+ outer_saved_try_ctx, |
+ new (Z) LoadLocalNode(Scanner::kNoSourcePos, |
+ outer_async_saved_try_ctx))); |
} |
// We don't need to copy the current exception and stack trace variables |
@@ -8539,7 +8566,10 @@ |
new(Z) LoadLocalNode(await_for_pos, stack_trace_var))); |
TryStack* try_statement = PopTry(); |
- ASSERT(try_index == try_statement->try_index()); |
+ const intptr_t try_index = try_statement->try_index(); |
+ TryStack* outer_try = try_stack_; |
+ const intptr_t outer_try_index = (outer_try != NULL) ? |
+ outer_try->try_index() : CatchClauseNode::kInvalidTryIndex; |
// The finally block contains a call to cancel the stream. |
// :for-in-iter.cancel() |
@@ -8942,9 +8972,17 @@ |
if (try_stack_ != NULL) { |
LocalScope* scope = try_stack_->try_block()->scope; |
if (scope->function_level() == current_block_->scope->function_level()) { |
+ LocalVariable* saved_try_ctx = |
+ LookupSavedTryContextVar(scope->parent()); |
+ LocalVariable* async_saved_try_ctx = |
+ LookupAsyncSavedTryContextVar(scope->parent(), |
+ try_stack_->try_index()); |
current_block_->statements->Add( |
- AwaitTransformer::RestoreSavedTryContext( |
- Z, scope->parent(), try_stack_->try_index())); |
+ new (Z) StoreLocalNode( |
+ Scanner::kNoSourcePos, |
+ saved_try_ctx, |
+ new (Z) LoadLocalNode(Scanner::kNoSourcePos, |
+ async_saved_try_ctx))); |
} |
} |
// We need to save the exception variables as in catch clauses, whether |
@@ -9202,11 +9240,18 @@ |
const TryStack* try_block = try_stack_->outer_try(); |
if (try_block != NULL) { |
LocalScope* scope = try_block->try_block()->scope; |
- if (scope->function_level() == |
- current_block_->scope->function_level()) { |
- async_code->Add( |
- AwaitTransformer::RestoreSavedTryContext( |
- Z, scope->parent(), try_block->try_index())); |
+ if (scope->function_level() == current_block_->scope->function_level()) { |
+ LocalVariable* saved_try_ctx = |
+ LookupSavedTryContextVar(scope->parent()); |
+ LocalVariable* async_saved_try_ctx = |
+ LookupAsyncSavedTryContextVar(scope->parent(), |
+ try_block->try_index()); |
+ current_block_->statements->Add( |
+ new (Z) StoreLocalNode( |
+ Scanner::kNoSourcePos, |
+ saved_try_ctx, |
+ new (Z) LoadLocalNode(Scanner::kNoSourcePos, |
+ async_saved_try_ctx))); |
} |
} |
SaveExceptionAndStacktrace(async_code, |
@@ -9572,25 +9617,29 @@ |
// If this expression is part of a try block, also append the code for |
// restoring the saved try context that lives on the stack and possibly the |
// saved try context of the outer try block. |
- LocalScope* try_scope; |
- int16_t try_index; |
- LocalScope* outer_try_scope; |
- int16_t outer_try_index; |
- CheckAsyncOpInTryBlock(&try_scope, &try_index, |
- &outer_try_scope, &outer_try_index); |
- if (try_scope != NULL) { |
- yield->AddNode( |
- AwaitTransformer::RestoreSavedTryContext(Z, |
- try_scope, |
- try_index)); |
- if (outer_try_scope != NULL) { |
- yield->AddNode( |
- AwaitTransformer::RestoreSavedTryContext(Z, |
- outer_try_scope, |
- outer_try_index)); |
+ LocalVariable* saved_try_ctx; |
+ LocalVariable* async_saved_try_ctx; |
+ LocalVariable* outer_saved_try_ctx; |
+ LocalVariable* outer_async_saved_try_ctx; |
+ CheckAsyncOpInTryBlock(&saved_try_ctx, |
+ &async_saved_try_ctx, |
+ &outer_saved_try_ctx, |
+ &outer_async_saved_try_ctx); |
+ if (saved_try_ctx != NULL) { |
+ yield->AddNode(new (Z) StoreLocalNode( |
+ Scanner::kNoSourcePos, |
+ saved_try_ctx, |
+ new (Z) LoadLocalNode(Scanner::kNoSourcePos, |
+ async_saved_try_ctx))); |
+ if (outer_saved_try_ctx != NULL) { |
+ yield->AddNode(new (Z) StoreLocalNode( |
+ Scanner::kNoSourcePos, |
+ outer_saved_try_ctx, |
+ new (Z) LoadLocalNode(Scanner::kNoSourcePos, |
+ outer_async_saved_try_ctx))); |
} |
} else { |
- ASSERT(outer_try_scope == NULL); |
+ ASSERT(outer_saved_try_ctx == NULL); |
} |
} else { |
// yield statement in async* function. |
@@ -9608,7 +9657,6 @@ |
is_yield_each ? Symbols::AddStream() : Symbols::add(), |
add_args); |
- |
// if (:controller.add[Stream](expr)) { |
// return; |
// } |
@@ -9635,25 +9683,29 @@ |
// If this expression is part of a try block, also append the code for |
// restoring the saved try context that lives on the stack and possibly the |
// saved try context of the outer try block. |
- LocalScope* try_scope; |
- int16_t try_index; |
- LocalScope* outer_try_scope; |
- int16_t outer_try_index; |
- CheckAsyncOpInTryBlock(&try_scope, &try_index, |
- &outer_try_scope, &outer_try_index); |
- if (try_scope != NULL) { |
- yield->AddNode( |
- AwaitTransformer::RestoreSavedTryContext(Z, |
- try_scope, |
- try_index)); |
- if (outer_try_scope != NULL) { |
- yield->AddNode( |
- AwaitTransformer::RestoreSavedTryContext(Z, |
- outer_try_scope, |
- outer_try_index)); |
+ LocalVariable* saved_try_ctx; |
+ LocalVariable* async_saved_try_ctx; |
+ LocalVariable* outer_saved_try_ctx; |
+ LocalVariable* outer_async_saved_try_ctx; |
+ CheckAsyncOpInTryBlock(&saved_try_ctx, |
+ &async_saved_try_ctx, |
+ &outer_saved_try_ctx, |
+ &outer_async_saved_try_ctx); |
+ if (saved_try_ctx != NULL) { |
+ yield->AddNode(new (Z) StoreLocalNode( |
+ Scanner::kNoSourcePos, |
+ saved_try_ctx, |
+ new (Z) LoadLocalNode(Scanner::kNoSourcePos, |
+ async_saved_try_ctx))); |
+ if (outer_saved_try_ctx != NULL) { |
+ yield->AddNode(new (Z) StoreLocalNode( |
+ Scanner::kNoSourcePos, |
+ outer_saved_try_ctx, |
+ new (Z) LoadLocalNode(Scanner::kNoSourcePos, |
+ outer_async_saved_try_ctx))); |
} |
} else { |
- ASSERT(outer_try_scope == NULL); |
+ ASSERT(outer_saved_try_ctx == NULL); |
} |
} |
return yield; |
@@ -10587,19 +10639,20 @@ |
ConsumeToken(); |
parsed_function()->record_await(); |
- LocalScope* try_scope; |
- int16_t try_index; |
- LocalScope* outer_try_scope; |
- int16_t outer_try_index; |
- CheckAsyncOpInTryBlock(&try_scope, &try_index, |
- &outer_try_scope, &outer_try_index); |
- |
+ LocalVariable* saved_try_ctx; |
+ LocalVariable* async_saved_try_ctx; |
+ LocalVariable* outer_saved_try_ctx; |
+ LocalVariable* outer_async_saved_try_ctx; |
+ CheckAsyncOpInTryBlock(&saved_try_ctx, |
+ &async_saved_try_ctx, |
+ &outer_saved_try_ctx, |
+ &outer_async_saved_try_ctx); |
expr = new (Z) AwaitNode(op_pos, |
ParseUnaryExpr(), |
- try_scope, |
- try_index, |
- outer_try_scope, |
- outer_try_index); |
+ saved_try_ctx, |
+ async_saved_try_ctx, |
+ outer_saved_try_ctx, |
+ outer_async_saved_try_ctx); |
} else if (IsPrefixOperator(CurrentToken())) { |
Token::Kind unary_op = CurrentToken(); |
if (unary_op == Token::kSUB) { |