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

Unified Diff: runtime/vm/parser.cc

Issue 484933003: Await it! (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: finally try to catch all issues in try/catch/finally Created 6 years, 4 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
Index: runtime/vm/parser.cc
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 62a6a071305fee4fc0a3b29cd3063d186b444fd0..9d8d088db127f06e1f95a5342086704835cbb10f 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -5425,7 +5425,6 @@ void Parser::OpenFunctionBlock(const Function& func) {
void Parser::OpenAsyncClosure() {
TRACE_PARSER("OpenAsyncClosure");
parsed_function()->set_await_temps_scope(current_block_->scope);
- // TODO(mlippautz): Set up explicit jump table for await continuations.
}
@@ -5501,8 +5500,6 @@ SequenceNode* Parser::CloseAsyncFunction(const Function& closure,
// Create and return a new future that executes a closure with the current
// body.
- bool found = false;
-
// No need to capture parameters or other variables, since they have already
// been captured in the corresponding scope as the body has been parsed within
// a nested block (contained in the async funtion's block).
@@ -5519,28 +5516,52 @@ 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 :await_saved_try_ctx_var_<x>;
hausner 2014/08/25 20:26:14 is the name :await_saved_try_ctx_var_ or :async_sa
Michael Lippautz (Google) 2014/08/26 16:45:48 Done. Using :async_...
+ Type& dynamic_type = Type::ZoneHandle(I, Type::DynamicType());
hausner 2014/08/25 20:26:14 const
Michael Lippautz (Google) 2014/08/26 16:45:48 Done.
LocalVariable* async_op_var = new (I) LocalVariable(
- Scanner::kNoSourcePos,
- Symbols::AsyncOperation(),
- Type::ZoneHandle(I, Type::DynamicType()));
+ 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(),
- Type::ZoneHandle(I, Type::DynamicType()));
+ 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;
+ const char* async_saved_prefix = ":async_saved_try_ctx_var_";
+ for (int16_t i = 0; i < last_used_try_index_; i++) {
+ const String& cnt_str = String::ZoneHandle(
hausner 2014/08/25 20:26:14 cnt_str can be a regular handle, need not be a zon
Michael Lippautz (Google) 2014/08/26 16:45:48 Done: BuildAsyncSavedTryContextName()
+ I, String::NewFormatted("%s%d", async_saved_prefix, i));
+ const String& symbol = String::ZoneHandle(I, Symbols::New(cnt_str));
+ async_saved_try_ctx_var = new (I) LocalVariable(
+ Scanner::kNoSourcePos, symbol, dynamic_type);
+ current_block_->scope->AddVariable(async_saved_try_ctx_var);
+ found = closure_body->scope()->CaptureVariable(symbol);
+ ASSERT(found);
+ }
// Add to AST:
// :async_completer = new Completer();
- ArgumentListNode* empty_args = new (I) ArgumentListNode(
- Scanner::kNoSourcePos);
+ ArgumentListNode* empty_args =
+ new (I) ArgumentListNode(Scanner::kNoSourcePos);
ConstructorCallNode* completer_constructor_node = new (I) ConstructorCallNode(
Scanner::kNoSourcePos,
TypeArguments::ZoneHandle(I),
@@ -5591,6 +5612,13 @@ void Parser::CloseAsyncClosure(SequenceNode* body) {
TRACE_PARSER("CloseAsyncClosure");
// We need a temporary expression to store intermediate return values.
parsed_function()->EnsureExpressionTemp();
+ // 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()->RecursivelyCaptureAllVariables();
}
@@ -7125,6 +7153,19 @@ SequenceNode* Parser::ParseFinallyBlock() {
TRACE_PARSER("ParseFinallyBlock");
OpenBlock();
ExpectToken(Token::kLBRACE);
+
+ // 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)) {
+ // 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);
+ } else {
+ parsed_function()->reset_saved_try_ctx_vars();
+ }
+
ParseStatementSequence();
ExpectToken(Token::kRBRACE);
SequenceNode* finally_block = CloseBlock();
@@ -7270,6 +7311,21 @@ SequenceNode* Parser::ParseCatchClauses(
// Add nested block with user-defined code. This blocks allows
// declarations in the body to shadow the catch parameters.
CheckToken(Token::kLBRACE);
+
+ // 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();
+ }
+
current_block_->statements->Add(ParseNestedStatement(false, NULL));
catch_blocks.Add(CloseBlock());
@@ -7365,6 +7421,30 @@ SequenceNode* Parser::ParseCatchClauses(
}
hausner 2014/08/25 20:26:14 Could you add a short comment describing what this
Michael Lippautz (Google) 2014/08/26 16:45:48 Done.
+void Parser::SetupSavedTryContext(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());
+ const char* async_saved_prefix = ":async_saved_try_ctx_var_";
+ const String& cnt_str = String::ZoneHandle(
hausner 2014/08/25 20:26:14 cnt_str probably doesn't need to be a ZoneHandle;
Michael Lippautz (Google) 2014/08/26 16:45:48 Done.
+ I, String::NewFormatted("%s%d", async_saved_prefix, try_index));
+ const String& current_await_saved_try_ctx_symbol = String::ZoneHandle(
+ I, Symbols::New(cnt_str));
+ LocalVariable* async_saved_try_ctx =
+ target->scope()->LookupVariable(
+ current_await_saved_try_ctx_symbol, false);
+ ASSERT((async_saved_try_ctx != NULL) && 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)));
+
+ parsed_function()->set_saved_try_ctx(saved_try_ctx);
+ parsed_function()->set_async_saved_try_ctx(async_saved_try_ctx);
+}
+
+
AstNode* Parser::ParseTryStatement(String* label_name) {
TRACE_PARSER("ParseTryStatement");
@@ -7423,6 +7503,26 @@ AstNode* Parser::ParseTryStatement(String* label_name) {
OpenBlock();
PushTryBlock(current_block_);
ExpectToken(Token::kLBRACE);
+
+ const char* async_saved_prefix = ":async_saved_try_ctx_var_";
+ if (current_function().is_async_closure()) {
+ const String& cnt_str = String::ZoneHandle(
srdjan 2014/08/26 15:54:33 Regular handle: use ZoneHandle-s only if the varia
Michael Lippautz (Google) 2014/08/26 16:45:48 Done. Code is now refactored but uses a regular ha
+ I, String::NewFormatted("%s%d",
+ async_saved_prefix, last_used_try_index_-1));
+ const String& current_await_saved_try_ctx_symbol =
+ String::ZoneHandle(I, Symbols::New(cnt_str));
+ LocalVariable* async_saved_try_ctx =
+ current_block_->scope->LookupVariable(
+ current_await_saved_try_ctx_symbol, false);
+ ASSERT(async_saved_try_ctx != NULL);
+ ASSERT(context_var);
+ 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);
+ }
+
ParseStatementSequence();
ExpectToken(Token::kRBRACE);
SequenceNode* try_block = CloseBlock();
@@ -7495,6 +7595,21 @@ AstNode* Parser::ParseTryStatement(String* label_name) {
sequence->set_label(try_label);
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;
}

Powered by Google App Engine
This is Rietveld 408576698