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

Unified Diff: runtime/vm/parser.cc

Issue 956583003: Save exception and stack trace variables in async catch clauses and use them (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') | runtime/vm/symbols.h » ('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 43993)
+++ runtime/vm/parser.cc (working copy)
@@ -5973,24 +5973,26 @@
LocalVariable* context_var = current_block_->scope->LookupVariable(
Symbols::SavedTryContextVar(), false);
ASSERT(context_var != NULL);
+
LocalVariable* exception_var = current_block_->scope->LookupVariable(
Symbols::ExceptionVar(), false);
+ ASSERT(exception_var != NULL);
if (exception_param.var != NULL) {
// Generate code to load the exception object (:exception_var) into
// the exception variable specified in this block.
- ASSERT(exception_var != NULL);
current_block_->statements->Add(new(Z) StoreLocalNode(
Scanner::kNoSourcePos,
exception_param.var,
new(Z) LoadLocalNode(Scanner::kNoSourcePos, exception_var)));
}
+
LocalVariable* stack_trace_var =
current_block_->scope->LookupVariable(Symbols::StackTraceVar(), false);
+ ASSERT(stack_trace_var != NULL);
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
// trace variable specified in this block.
- ASSERT(stack_trace_var != NULL);
current_block_->statements->Add(new(Z) StoreLocalNode(
Scanner::kNoSourcePos,
stack_trace_param.var,
@@ -5997,6 +5999,9 @@
new(Z) LoadLocalNode(Scanner::kNoSourcePos, stack_trace_var)));
}
+ AddSavedExceptionAndStacktraceToScope(
+ exception_var, stack_trace_var, current_block_->scope);
+
ASSERT(try_blocks_list_ != NULL);
ASSERT(innermost_function().IsAsyncClosure() ||
innermost_function().IsAsyncFunction());
@@ -8203,15 +8208,65 @@
var->set_is_final();
bool added_to_scope = scope->AddVariable(var);
if (!added_to_scope) {
+ // The name of the exception param is reused for the stack trace param.
ReportError(stack_trace_param->token_pos,
"name '%s' already exists in scope",
stack_trace_param->name->ToCString());
- }
+ }
stack_trace_param->var = var;
}
}
+// Populate local scope of the catch block with the saved exception and saved
+// stack trace.
+void Parser::AddSavedExceptionAndStacktraceToScope(
+ LocalVariable* exception_var,
+ LocalVariable* stack_trace_var,
+ LocalScope* scope) {
+ ASSERT(innermost_function().IsAsyncClosure() ||
+ innermost_function().IsAsyncFunction() ||
+ innermost_function().IsSyncGenClosure() ||
+ innermost_function().IsSyncGenerator());
+ // Add :saved_exception_var and :saved_stack_trace_var to scope.
+ // They will automatically get captured.
+ LocalVariable* saved_exception_var = new (Z) LocalVariable(
+ Scanner::kNoSourcePos,
+ Symbols::SavedExceptionVar(),
+ Type::ZoneHandle(Z, Type::DynamicType()));
+ saved_exception_var->set_is_final();
+ scope->AddVariable(saved_exception_var);
+ LocalVariable* saved_stack_trace_var = new (Z) LocalVariable(
+ Scanner::kNoSourcePos,
+ Symbols::SavedStackTraceVar(),
+ Type::ZoneHandle(Z, Type::DynamicType()));
+ saved_exception_var->set_is_final();
+ scope->AddVariable(saved_stack_trace_var);
+
+ // Generate code to load the exception object (:exception_var) into
+ // the saved exception variable (:saved_exception_var) used to rethrow.
+ saved_exception_var = current_block_->scope->LookupVariable(
+ Symbols::SavedExceptionVar(), false);
+ ASSERT(saved_exception_var != NULL);
+ ASSERT(exception_var != NULL);
+ current_block_->statements->Add(new(Z) StoreLocalNode(
+ Scanner::kNoSourcePos,
+ saved_exception_var,
+ new(Z) LoadLocalNode(Scanner::kNoSourcePos, exception_var)));
+
+ // Generate code to load the stack trace object (:stack_trace_var) into
+ // the saved stacktrace variable (:saved_stack_trace_var) used to rethrow.
+ saved_stack_trace_var = current_block_->scope->LookupVariable(
+ Symbols::SavedStackTraceVar(), false);
+ ASSERT(saved_stack_trace_var != NULL);
+ ASSERT(stack_trace_var != NULL);
+ current_block_->statements->Add(new(Z) StoreLocalNode(
+ Scanner::kNoSourcePos,
+ saved_stack_trace_var,
+ new(Z) LoadLocalNode(Scanner::kNoSourcePos, stack_trace_var)));
+}
+
+
SequenceNode* Parser::ParseFinallyBlock() {
TRACE_PARSER("ParseFinallyBlock");
OpenBlock();
@@ -8345,7 +8400,9 @@
// following code:
// 1) Store exception object and stack trace object into user-defined
// variables (as needed).
- // 2) Nested block with source code from catch clause block.
+ // 2) In async code, save exception object and stack trace object into
+ // captured :saved_exception_var and :saved_stack_trace_var.
+ // 3) Nested block with source code from catch clause block.
OpenBlock();
AddCatchParamsToScope(&exception_param, &stack_trace_param,
current_block_->scope);
@@ -8393,6 +8450,8 @@
} else {
parsed_function()->reset_saved_try_ctx_vars();
}
+ AddSavedExceptionAndStacktraceToScope(
+ exception_var, stack_trace_var, current_block_->scope);
}
current_block_->statements->Add(ParseNestedStatement(false, NULL));
@@ -8537,7 +8596,7 @@
// Restore the currently relevant :saved_try_context_var on the stack
-// from the captured :async_saved_try_cts_var.
+// from the captured :async_saved_try_ctx_var_.
// * Try blocks: Set the context variable for this try block.
// * Catch/finally blocks: Set the context variable for any outer try block (if
// existent).
@@ -8931,16 +8990,31 @@
if ((try_blocks_list_ == NULL) || !try_blocks_list_->inside_catch()) {
ReportError(statement_pos, "rethrow of an exception is not valid here");
}
- // The exception and stack trace variables are bound in the block
- // containing the try.
- LocalScope* scope = try_blocks_list_->try_block()->scope->parent();
- ASSERT(scope != NULL);
- LocalVariable* excp_var =
- scope->LocalLookupVariable(Symbols::ExceptionVar());
+
+ // If in async code, use :saved_exception_var and :saved_stack_trace_var
+ // instead of :exception_var and :stack_trace_var.
+ LocalVariable* excp_var;
+ LocalVariable* trace_var;
+ if (innermost_function().IsAsyncClosure() ||
+ innermost_function().IsAsyncFunction() ||
+ innermost_function().IsSyncGenClosure() ||
+ innermost_function().IsSyncGenerator()) {
+ // The saved exception and stack trace variables are bound in the block
+ // containing the catch. So start looking in the current scope.
+ LocalScope* scope = current_block_->scope;
+ excp_var = scope->LookupVariable(Symbols::SavedExceptionVar(), false);
+ trace_var = scope->LookupVariable(Symbols::SavedStackTraceVar(), false);
+ } else {
+ // The exception and stack trace variables are bound in the block
+ // containing the try. Look in the try scope directly.
+ LocalScope* scope = try_blocks_list_->try_block()->scope->parent();
+ ASSERT(scope != NULL);
+ excp_var = scope->LocalLookupVariable(Symbols::ExceptionVar());
+ trace_var = scope->LocalLookupVariable(Symbols::StackTraceVar());
+ }
ASSERT(excp_var != NULL);
- LocalVariable* trace_var =
- scope->LocalLookupVariable(Symbols::StackTraceVar());
ASSERT(trace_var != NULL);
+
statement = new(Z) ThrowNode(
statement_pos,
new(Z) LoadLocalNode(statement_pos, excp_var),
« no previous file with comments | « runtime/vm/parser.h ('k') | runtime/vm/symbols.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698