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

Unified Diff: runtime/vm/parser.cc

Issue 974073002: Fix async machinery for finally clauses (issues 22445, 22300). (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 5 years, 10 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/parser.h ('k') | tests/language/language.status » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/parser.cc
===================================================================
--- runtime/vm/parser.cc (revision 44206)
+++ runtime/vm/parser.cc (working copy)
@@ -5985,6 +5985,7 @@
// The try-block (closure body code) has been parsed. We are now
// generating the code for the catch block.
+ LocalScope* try_scope = current_block_->scope;
try_blocks_list_->enter_catch();
OpenBlock(); // Catch handler list.
OpenBlock(); // Catch block.
@@ -6006,12 +6007,12 @@
// Generate code to save the exception object and stack trace
// in local variables.
- LocalVariable* context_var = current_block_->scope->LookupVariable(
- Symbols::SavedTryContextVar(), false);
+ LocalVariable* context_var = try_scope->LocalLookupVariable(
+ Symbols::SavedTryContextVar());
ASSERT(context_var != NULL);
- LocalVariable* exception_var = current_block_->scope->LookupVariable(
- Symbols::ExceptionVar(), false);
+ LocalVariable* exception_var = try_scope->LocalLookupVariable(
+ Symbols::ExceptionVar());
ASSERT(exception_var != NULL);
if (exception_param.var != NULL) {
// Generate code to load the exception object (:exception_var) into
@@ -6023,7 +6024,7 @@
}
LocalVariable* stack_trace_var =
- current_block_->scope->LookupVariable(Symbols::StackTraceVar(), false);
+ try_scope->LocalLookupVariable(Symbols::StackTraceVar());
ASSERT(stack_trace_var != NULL);
if (stack_trace_param.var != NULL) {
// A stack trace variable is specified in this block, so generate code
@@ -6034,11 +6035,12 @@
stack_trace_param.var,
new(Z) LoadLocalNode(Scanner::kNoSourcePos, stack_trace_var)));
}
- LocalVariable* saved_exception_var = current_block_->scope->LookupVariable(
- Symbols::SavedExceptionVar(), false);
- LocalVariable* saved_stack_trace_var = current_block_->scope->LookupVariable(
- Symbols::SavedStackTraceVar(), false);
- SaveExceptionAndStacktrace(exception_var,
+ LocalVariable* saved_exception_var = try_scope->LocalLookupVariable(
hausner 2015/03/03 23:19:11 Nit: the initializer value for the variable may no
regis 2015/03/03 23:47:09 It does not.
+ Symbols::SavedExceptionVar());
+ LocalVariable* saved_stack_trace_var = try_scope->LocalLookupVariable(
+ Symbols::SavedStackTraceVar());
+ SaveExceptionAndStacktrace(current_block_->statements,
+ exception_var,
stack_trace_var,
saved_exception_var,
saved_stack_trace_var);
@@ -6139,6 +6141,7 @@
ASSERT(try_blocks_list_ != NULL);
ASSERT(try_blocks_list_->outer_try_block() == NULL);
ASSERT(innermost_function().IsAsyncClosure());
+ LocalScope* try_scope = current_block_->scope;
try_blocks_list_->enter_catch();
@@ -6158,12 +6161,12 @@
AddCatchParamsToScope(
&exception_param, &stack_trace_param, current_block_->scope);
- LocalVariable* context_var = current_block_->scope->LookupVariable(
- Symbols::SavedTryContextVar(), false);
+ LocalVariable* context_var = try_scope->LocalLookupVariable(
hausner 2015/03/03 23:19:11 Nit: line break after =
regis 2015/03/03 23:47:09 ditto
+ Symbols::SavedTryContextVar());
ASSERT(context_var != NULL);
- LocalVariable* exception_var = current_block_->scope->LookupVariable(
- Symbols::ExceptionVar(), false);
+ LocalVariable* exception_var = try_scope->LocalLookupVariable(
+ Symbols::ExceptionVar());
if (exception_param.var != NULL) {
// Generate code to load the exception object (:exception_var) into
// the exception variable specified in this block.
@@ -6175,7 +6178,7 @@
}
LocalVariable* stack_trace_var =
- current_block_->scope->LookupVariable(Symbols::StackTraceVar(), false);
+ try_scope->LocalLookupVariable(Symbols::StackTraceVar());
if (stack_trace_param.var != NULL) {
// A stack trace variable is specified in this block, so generate code
// to load the stack trace object (:stack_trace_var) into the stack
@@ -6186,11 +6189,12 @@
stack_trace_param.var,
new(Z) LoadLocalNode(Scanner::kNoSourcePos, stack_trace_var)));
}
- LocalVariable* saved_exception_var = current_block_->scope->LookupVariable(
- Symbols::SavedExceptionVar(), false);
- LocalVariable* saved_stack_trace_var = current_block_->scope->LookupVariable(
- Symbols::SavedStackTraceVar(), false);
- SaveExceptionAndStacktrace(exception_var,
+ LocalVariable* saved_exception_var = try_scope->LocalLookupVariable(
+ Symbols::SavedExceptionVar());
+ LocalVariable* saved_stack_trace_var = try_scope->LocalLookupVariable(
+ Symbols::SavedStackTraceVar());
+ SaveExceptionAndStacktrace(current_block_->statements,
+ exception_var,
stack_trace_var,
saved_exception_var,
saved_stack_trace_var);
@@ -6250,58 +6254,23 @@
}
-// Wrap the body of the async or arync* closure in a try/catch block.
+// Wrap the body of the async or async* closure in a try/catch block.
void Parser::OpenAsyncTryBlock() {
ASSERT(innermost_function().IsAsyncClosure() ||
innermost_function().IsAsyncGenClosure());
+ LocalVariable* context_var = NULL;
+ LocalVariable* exception_var = NULL;
+ LocalVariable* stack_trace_var = NULL;
+ LocalVariable* saved_exception_var = NULL;
+ LocalVariable* saved_stack_trace_var = NULL;
+ SetupExceptionVariables(current_block_->scope,
+ true,
+ &context_var,
+ &exception_var,
+ &stack_trace_var,
+ &saved_exception_var,
+ &saved_stack_trace_var);
- const Type& dynamic_type = Type::ZoneHandle(Z, Type::DynamicType());
- LocalVariable* context_var =
- current_block_->scope->LocalLookupVariable(Symbols::SavedTryContextVar());
- if (context_var == NULL) {
- context_var = new(Z) LocalVariable(
- TokenPos(),
- Symbols::SavedTryContextVar(),
- dynamic_type);
- current_block_->scope->AddVariable(context_var);
- }
- LocalVariable* exception_var =
- current_block_->scope->LocalLookupVariable(Symbols::ExceptionVar());
- if (exception_var == NULL) {
- exception_var = new(Z) LocalVariable(
- TokenPos(),
- Symbols::ExceptionVar(),
- dynamic_type);
- current_block_->scope->AddVariable(exception_var);
- }
- LocalVariable* stack_trace_var =
- current_block_->scope->LocalLookupVariable(Symbols::StackTraceVar());
- if (stack_trace_var == NULL) {
- stack_trace_var = new(Z) LocalVariable(
- TokenPos(),
- Symbols::StackTraceVar(),
- dynamic_type);
- current_block_->scope->AddVariable(stack_trace_var);
- }
- LocalVariable* saved_exception_var =
- current_block_->scope->LocalLookupVariable(Symbols::SavedExceptionVar());
- if (saved_exception_var == NULL) {
- saved_exception_var = new(Z) LocalVariable(
- TokenPos(),
- Symbols::SavedExceptionVar(),
- dynamic_type);
- current_block_->scope->AddVariable(saved_exception_var);
- }
- LocalVariable* saved_stack_trace_var =
- current_block_->scope->LocalLookupVariable(Symbols::SavedStackTraceVar());
- if (saved_stack_trace_var == NULL) {
- saved_stack_trace_var = new(Z) LocalVariable(
- TokenPos(),
- Symbols::SavedStackTraceVar(),
- dynamic_type);
- current_block_->scope->AddVariable(saved_stack_trace_var);
- }
-
// Open the try block.
OpenBlock();
// This is the outermost try-catch in the function.
@@ -8689,7 +8658,8 @@
// the saved exception variable (:saved_exception_var) used to rethrow.
// Generate code to load the stack trace object (:stack_trace_var) into
// the saved stacktrace variable (:saved_stack_trace_var) used to rethrow.
-void Parser::SaveExceptionAndStacktrace(LocalVariable* exception_var,
+void Parser::SaveExceptionAndStacktrace(SequenceNode* statements,
+ LocalVariable* exception_var,
LocalVariable* stack_trace_var,
LocalVariable* saved_exception_var,
LocalVariable* saved_stack_trace_var) {
@@ -8702,7 +8672,7 @@
ASSERT(saved_exception_var != NULL);
ASSERT(exception_var != NULL);
- current_block_->statements->Add(new(Z) StoreLocalNode(
+ statements->Add(new(Z) StoreLocalNode(
Scanner::kNoSourcePos,
saved_exception_var,
new(Z) LoadLocalNode(Scanner::kNoSourcePos, exception_var)));
@@ -8709,7 +8679,7 @@
ASSERT(saved_stack_trace_var != NULL);
ASSERT(stack_trace_var != NULL);
- current_block_->statements->Add(new(Z) StoreLocalNode(
+ statements->Add(new(Z) StoreLocalNode(
Scanner::kNoSourcePos,
saved_stack_trace_var,
new(Z) LoadLocalNode(Scanner::kNoSourcePos, stack_trace_var)));
@@ -8716,7 +8686,12 @@
}
-SequenceNode* Parser::ParseFinallyBlock() {
+SequenceNode* Parser::ParseFinallyBlock(
+ bool is_async,
+ LocalVariable* exception_var,
+ LocalVariable* stack_trace_var,
+ LocalVariable* rethrow_exception_var,
+ LocalVariable* rethrow_stack_trace_var) {
TRACE_PARSER("ParseFinallyBlock");
OpenBlock();
ExpectToken(Token::kLBRACE);
@@ -8724,13 +8699,7 @@
// 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 ((innermost_function().IsAsyncClosure() ||
- innermost_function().IsAsyncFunction() ||
- innermost_function().IsSyncGenClosure() ||
- innermost_function().IsSyncGenerator() ||
- innermost_function().IsAsyncGenerator() ||
- innermost_function().IsAsyncGenClosure()) &&
- (try_blocks_list_ != NULL)) {
+ if (is_async && (try_blocks_list_ != NULL)) {
LocalScope* scope = try_blocks_list_->try_block()->scope;
if (scope->function_level() == current_block_->scope->function_level()) {
current_block_->statements->Add(
@@ -8737,6 +8706,11 @@
AwaitTransformer::RestoreSavedTryContext(
Z, scope->parent(), try_blocks_list_->try_index()));
}
+ SaveExceptionAndStacktrace(current_block_->statements,
hausner 2015/03/03 23:19:11 Strictly speaking, this is only necessary if the f
regis 2015/03/03 23:47:09 Yes, I added a comment and a TODO(hausner) :-) I
+ exception_var,
+ stack_trace_var,
+ rethrow_exception_var,
+ rethrow_stack_trace_var);
}
ParseStatementSequence();
@@ -8805,6 +8779,7 @@
SequenceNode* Parser::ParseCatchClauses(
intptr_t handler_pos,
+ bool is_async,
LocalVariable* exception_var,
LocalVariable* stack_trace_var,
LocalVariable* rethrow_exception_var,
@@ -8882,31 +8857,6 @@
// 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 (innermost_function().IsAsyncClosure() ||
- innermost_function().IsAsyncFunction() ||
- innermost_function().IsSyncGenClosure() ||
- innermost_function().IsSyncGenerator() ||
- innermost_function().IsAsyncGenerator() ||
- innermost_function().IsAsyncGenClosure()) {
- const TryBlocks* try_block = try_blocks_list_->outer_try_block();
- if (try_block != NULL) {
- LocalScope* scope = try_block->try_block()->scope;
- if (scope->function_level() ==
- current_block_->scope->function_level()) {
- current_block_->statements->Add(
- AwaitTransformer::RestoreSavedTryContext(
- Z, scope->parent(), try_block->try_index()));
- }
- }
- SaveExceptionAndStacktrace(exception_var,
- stack_trace_var,
- rethrow_exception_var,
- rethrow_stack_trace_var);
- }
-
current_block_->statements->Add(ParseNestedStatement(false, NULL));
catch_blocks.Add(CloseBlock());
@@ -9000,28 +8950,29 @@
type_test->token_pos(), type_test, catch_block, current));
current = CloseBlock();
}
- // Restore :saved_try_context_var before executing the catch clauses.
+ // In case of async closures, restore :saved_try_context_var before executing
+ // the catch clauses.
if (current != NULL) {
hausner 2015/03/03 23:19:11 Can this be simplified to if (is_async && (current
regis 2015/03/03 23:47:09 Done.
ASSERT(try_blocks_list_ != NULL);
- if (innermost_function().IsAsyncClosure() ||
- innermost_function().IsAsyncFunction() ||
- innermost_function().IsSyncGenClosure() ||
- innermost_function().IsSyncGenerator() ||
- innermost_function().IsAsyncGenerator() ||
- innermost_function().IsAsyncGenClosure()) {
+ if (is_async) {
+ SequenceNode* async_code = new(Z) SequenceNode(handler_pos, NULL);
const TryBlocks* try_block = try_blocks_list_->outer_try_block();
if (try_block != NULL) {
LocalScope* scope = try_block->try_block()->scope;
if (scope->function_level() ==
current_block_->scope->function_level()) {
- SequenceNode* restore_code = new(Z) SequenceNode(handler_pos, NULL);
- restore_code->Add(
+ async_code->Add(
AwaitTransformer::RestoreSavedTryContext(
Z, scope->parent(), try_block->try_index()));
- restore_code->Add(current);
- current = restore_code;
}
}
+ SaveExceptionAndStacktrace(async_code,
Ivan Posva 2015/03/03 22:57:57 Please add comment what is being saved here and wh
regis 2015/03/03 23:47:09 Done.
+ exception_var,
+ stack_trace_var,
+ rethrow_exception_var,
+ rethrow_stack_trace_var);
+ async_code->Add(current);
+ current = async_code;
}
}
return current;
@@ -9052,80 +9003,100 @@
}
-AstNode* Parser::ParseTryStatement(String* label_name) {
- TRACE_PARSER("ParseTryStatement");
-
- // We create three variables for exceptions here:
- // ':saved_try_context_var' - Used to save the context before the start of
- // the try block. The context register is
- // restored from this variable before
- // processing the catch block handler.
- // ':exception_var' - Used to save the current exception object that was
- // thrown.
- // ':stack_trace_var' - Used to save the current stack trace object which
- // the stack trace was copied into when an exception
- // was thrown.
- // :exception_var and :stack_trace_var get set with the exception object
- // and the stack trace object when an exception is thrown. These three
- // implicit variables can never be captured.
+// We create three variables for exceptions:
+// ':saved_try_context_var' - Used to save the context before the start of
+// the try block. The context register is
+// restored from this variable before
+// processing the catch block handler.
+// ':exception_var' - Used to save the current exception object that was
+// thrown.
+// ':stack_trace_var' - Used to save the current stack trace object which
+// the stack trace was copied into when an exception
+// was thrown.
+// :exception_var and :stack_trace_var get set with the exception object
+// and the stack trace object when an exception is thrown. These three
+// implicit variables can never be captured.
+//
+// In case of async code, we create two additional variables:
+// ':saved_exception_var' - Used to capture the exception object above.
+// ':saved_stack_trace_var' - Used to capture the stack trace object above.
+void Parser::SetupExceptionVariables(LocalScope* try_scope,
+ bool is_async,
+ LocalVariable** context_var,
+ LocalVariable** exception_var,
+ LocalVariable** stack_trace_var,
+ LocalVariable** saved_exception_var,
+ LocalVariable** saved_stack_trace_var) {
const Type& dynamic_type = Type::ZoneHandle(Z, Type::DynamicType());
// Consecutive try statements share the same set of variables.
- LocalVariable* context_var =
- current_block_->scope->LocalLookupVariable(Symbols::SavedTryContextVar());
- if (context_var == NULL) {
- context_var = new(Z) LocalVariable(
+ *context_var = try_scope->LocalLookupVariable(Symbols::SavedTryContextVar());
+ if (*context_var == NULL) {
+ *context_var = new(Z) LocalVariable(
TokenPos(),
Symbols::SavedTryContextVar(),
dynamic_type);
- current_block_->scope->AddVariable(context_var);
+ try_scope->AddVariable(*context_var);
}
- LocalVariable* exception_var =
- current_block_->scope->LocalLookupVariable(Symbols::ExceptionVar());
- if (exception_var == NULL) {
- exception_var = new(Z) LocalVariable(
+ *exception_var = try_scope->LocalLookupVariable(Symbols::ExceptionVar());
+ if (*exception_var == NULL) {
+ *exception_var = new(Z) LocalVariable(
TokenPos(),
Symbols::ExceptionVar(),
dynamic_type);
- current_block_->scope->AddVariable(exception_var);
+ try_scope->AddVariable(*exception_var);
}
- LocalVariable* stack_trace_var =
- current_block_->scope->LocalLookupVariable(Symbols::StackTraceVar());
- if (stack_trace_var == NULL) {
- stack_trace_var = new(Z) LocalVariable(
+ *stack_trace_var = try_scope->LocalLookupVariable(Symbols::StackTraceVar());
+ if (*stack_trace_var == NULL) {
+ *stack_trace_var = new(Z) LocalVariable(
TokenPos(),
Symbols::StackTraceVar(),
dynamic_type);
- current_block_->scope->AddVariable(stack_trace_var);
+ try_scope->AddVariable(*stack_trace_var);
}
- LocalVariable* saved_exception_var = NULL;
- LocalVariable* saved_stack_trace_var = NULL;
- const bool is_async = innermost_function().IsAsyncClosure() ||
- innermost_function().IsAsyncFunction() ||
- innermost_function().IsSyncGenClosure() ||
- innermost_function().IsSyncGenerator() ||
- innermost_function().IsAsyncGenClosure() ||
- innermost_function().IsAsyncGenerator();
if (is_async) {
- saved_exception_var = current_block_->scope->LocalLookupVariable(
+ *saved_exception_var = try_scope->LocalLookupVariable(
Symbols::SavedExceptionVar());
- if (saved_exception_var == NULL) {
- saved_exception_var = new(Z) LocalVariable(
+ if (*saved_exception_var == NULL) {
+ *saved_exception_var = new(Z) LocalVariable(
TokenPos(),
Symbols::SavedExceptionVar(),
dynamic_type);
- current_block_->scope->AddVariable(saved_exception_var);
+ try_scope->AddVariable(*saved_exception_var);
}
- saved_stack_trace_var = current_block_->scope->LocalLookupVariable(
+ *saved_stack_trace_var = try_scope->LocalLookupVariable(
Symbols::SavedStackTraceVar());
- if (saved_stack_trace_var == NULL) {
- saved_stack_trace_var = new(Z) LocalVariable(
+ if (*saved_stack_trace_var == NULL) {
+ *saved_stack_trace_var = new(Z) LocalVariable(
TokenPos(),
Symbols::SavedStackTraceVar(),
dynamic_type);
- current_block_->scope->AddVariable(saved_stack_trace_var);
+ try_scope->AddVariable(*saved_stack_trace_var);
}
}
+}
+
+AstNode* Parser::ParseTryStatement(String* label_name) {
+ TRACE_PARSER("ParseTryStatement");
+ const bool is_async = innermost_function().IsAsyncClosure() ||
+ innermost_function().IsAsyncFunction() ||
+ innermost_function().IsSyncGenClosure() ||
+ innermost_function().IsSyncGenerator() ||
+ innermost_function().IsAsyncGenClosure() ||
+ innermost_function().IsAsyncGenerator();
+ LocalVariable* context_var = NULL;
+ LocalVariable* exception_var = NULL;
+ LocalVariable* stack_trace_var = NULL;
+ LocalVariable* saved_exception_var = NULL;
+ LocalVariable* saved_stack_trace_var = NULL;
+ SetupExceptionVariables(current_block_->scope,
+ is_async,
+ &context_var,
+ &exception_var,
+ &stack_trace_var,
+ &saved_exception_var,
+ &saved_stack_trace_var);
+
const intptr_t try_pos = TokenPos();
ConsumeToken(); // Consume the 'try'.
@@ -9161,10 +9132,14 @@
GrowableObjectArray::Handle(Z, GrowableObjectArray::New());
bool needs_stack_trace = false;
SequenceNode* catch_handler_list =
- ParseCatchClauses(handler_pos, exception_var, stack_trace_var,
+ ParseCatchClauses(handler_pos,
+ is_async,
+ exception_var,
+ stack_trace_var,
is_async ? saved_exception_var : exception_var,
is_async ? saved_stack_trace_var : stack_trace_var,
- handler_types, &needs_stack_trace);
+ handler_types,
+ &needs_stack_trace);
TryBlocks* inner_try_block = PopTryBlock();
const intptr_t try_index = inner_try_block->try_index();
@@ -9183,7 +9158,12 @@
AstNode* node_to_inline =
inner_try_block->GetNodeToInlineFinally(node_index);
while (node_to_inline != NULL) {
- finally_block = ParseFinallyBlock();
+ finally_block = ParseFinallyBlock(
+ is_async,
+ exception_var,
+ stack_trace_var,
+ is_async ? saved_exception_var : exception_var,
+ is_async ? saved_stack_trace_var : stack_trace_var);
InlinedFinallyNode* node = new(Z) InlinedFinallyNode(finally_pos,
finally_block,
context_var,
@@ -9193,7 +9173,12 @@
node_to_inline = inner_try_block->GetNodeToInlineFinally(node_index);
tokens_iterator_.SetCurrentPosition(finally_pos);
}
- finally_block = ParseFinallyBlock();
+ finally_block = ParseFinallyBlock(
+ is_async,
+ exception_var,
+ stack_trace_var,
+ is_async ? saved_exception_var : exception_var,
+ is_async ? saved_stack_trace_var : stack_trace_var);
}
CatchClauseNode* catch_clause = new(Z) CatchClauseNode(
« no previous file with comments | « runtime/vm/parser.h ('k') | tests/language/language.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698