Index: runtime/vm/parser.cc |
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc |
index f255b0aab6053ecace84421e76975de14b562337..ca9a5408ecaa3799df2be79fef2cb1eb5144065f 100644 |
--- a/runtime/vm/parser.cc |
+++ b/runtime/vm/parser.cc |
@@ -5,7 +5,7 @@ |
#include "vm/parser.h" |
#include "lib/invocation_mirror.h" |
-#include "vm/bigint_operations.h" |
+#include "platform/utils.h" |
#include "vm/bootstrap.h" |
#include "vm/class_finalizer.h" |
#include "vm/compiler.h" |
@@ -14,14 +14,22 @@ |
#include "vm/dart_entry.h" |
#include "vm/flags.h" |
#include "vm/growable_array.h" |
+#include "vm/handles.h" |
+#include "vm/heap.h" |
+#include "vm/isolate.h" |
#include "vm/longjump.h" |
+#include "vm/native_arguments.h" |
#include "vm/native_entry.h" |
#include "vm/object.h" |
#include "vm/object_store.h" |
+#include "vm/os.h" |
#include "vm/resolver.h" |
+#include "vm/scanner.h" |
#include "vm/scopes.h" |
#include "vm/stack_frame.h" |
#include "vm/symbols.h" |
+#include "vm/timer.h" |
+#include "vm/zone.h" |
namespace dart { |
@@ -194,11 +202,14 @@ class Parser::TryBlocks : public ZoneAllocated { |
: try_block_(try_block), |
inlined_finally_nodes_(), |
outer_try_block_(outer_try_block), |
- try_index_(try_index) { } |
+ try_index_(try_index), |
+ inside_catch_(false) { } |
TryBlocks* outer_try_block() const { return outer_try_block_; } |
Block* try_block() const { return try_block_; } |
intptr_t try_index() const { return try_index_; } |
+ bool inside_catch() const { return inside_catch_; } |
+ void enter_catch() { inside_catch_ = true; } |
void AddNodeForFinallyInlining(AstNode* node); |
AstNode* GetNodeToInlineFinally(int index) { |
@@ -213,6 +224,7 @@ class Parser::TryBlocks : public ZoneAllocated { |
GrowableArray<AstNode*> inlined_finally_nodes_; |
TryBlocks* outer_try_block_; |
const intptr_t try_index_; |
+ bool inside_catch_; |
DISALLOW_COPY_AND_ASSIGN(TryBlocks); |
}; |
@@ -1072,10 +1084,10 @@ SequenceNode* Parser::ParseStaticInitializer(const Function& func) { |
current_block_->scope->AddVariable(catch_excp_var); |
} |
LocalVariable* catch_trace_var = |
- current_block_->scope->LocalLookupVariable(Symbols::StacktraceVar()); |
+ current_block_->scope->LocalLookupVariable(Symbols::StackTraceVar()); |
if (catch_trace_var == NULL) { |
catch_trace_var = new LocalVariable(token_pos, |
- Symbols::StacktraceVar(), |
+ Symbols::StackTraceVar(), |
Type::ZoneHandle(Type::DynamicType())); |
current_block_->scope->AddVariable(catch_trace_var); |
} |
@@ -1091,10 +1103,6 @@ SequenceNode* Parser::ParseStaticInitializer(const Function& func) { |
SequenceNode* try_block = CloseBlock(); // End try block. |
OpenBlock(); // Start catch handler list. |
- SourceLabel* end_catch_label = |
- SourceLabel::New(token_pos, NULL, SourceLabel::kCatch); |
- current_block_->scope->AddLabel(end_catch_label); |
- |
OpenBlock(); // Start catch clause. |
AstNode* compare_transition_sentinel = new ComparisonNode( |
token_pos, |
@@ -1115,8 +1123,6 @@ SequenceNode* Parser::ParseStaticInitializer(const Function& func) { |
new ThrowNode(token_pos, |
new LoadLocalNode(token_pos, catch_excp_var), |
new LoadLocalNode(token_pos, catch_trace_var))); |
- current_block_->statements->Add( |
- new JumpNode(token_pos, Token::kCONTINUE, end_catch_label)); |
SequenceNode* catch_clause = CloseBlock(); // End catch clause. |
current_block_->statements->Add(catch_clause); |
@@ -1133,7 +1139,6 @@ SequenceNode* Parser::ParseStaticInitializer(const Function& func) { |
AstNode* try_catch_node = new TryCatchNode(token_pos, |
try_block, |
- end_catch_label, |
context_var, |
catch_block, |
NULL, // No finally block. |
@@ -6647,36 +6652,39 @@ AstNode* Parser::ParseAssertStatement() { |
struct CatchParamDesc { |
CatchParamDesc() |
- : token_pos(0), type(NULL), var(NULL) { } |
+ : token_pos(0), type(NULL), name(NULL), var(NULL) { } |
intptr_t token_pos; |
const AbstractType* type; |
- const String* var; |
+ const String* name; |
+ LocalVariable* var; |
}; |
// Populate local scope of the catch block with the catch parameters. |
-void Parser::AddCatchParamsToScope(const CatchParamDesc& exception_param, |
- const CatchParamDesc& stack_trace_param, |
+void Parser::AddCatchParamsToScope(CatchParamDesc* exception_param, |
+ CatchParamDesc* stack_trace_param, |
LocalScope* scope) { |
- if (exception_param.var != NULL) { |
- LocalVariable* var = new LocalVariable(exception_param.token_pos, |
- *exception_param.var, |
- *exception_param.type); |
+ if (exception_param->name != NULL) { |
+ LocalVariable* var = new LocalVariable(exception_param->token_pos, |
+ *exception_param->name, |
+ *exception_param->type); |
var->set_is_final(); |
bool added_to_scope = scope->AddVariable(var); |
ASSERT(added_to_scope); |
+ exception_param->var = var; |
} |
- if (stack_trace_param.var != NULL) { |
- LocalVariable* var = new LocalVariable(TokenPos(), |
- *stack_trace_param.var, |
- *stack_trace_param.type); |
+ if (stack_trace_param->name != NULL) { |
+ LocalVariable* var = new LocalVariable(stack_trace_param->token_pos, |
+ *stack_trace_param->name, |
+ *stack_trace_param->type); |
var->set_is_final(); |
bool added_to_scope = scope->AddVariable(var); |
if (!added_to_scope) { |
- ErrorMsg(stack_trace_param.token_pos, |
+ ErrorMsg(stack_trace_param->token_pos, |
"name '%s' already exists in scope", |
- stack_trace_param.var->ToCString()); |
+ stack_trace_param->name->ToCString()); |
} |
+ stack_trace_param->var = var; |
} |
} |
@@ -6745,86 +6753,24 @@ void Parser::AddFinallyBlockToNode(AstNode* node, |
} |
-AstNode* Parser::ParseTryStatement(String* label_name) { |
- TRACE_PARSER("ParseTryStatement"); |
- |
- // We create three stack slots for exceptions here: |
- // ':saved_try_context_var' - Used to save the context before start of the try |
- // block. The context register is restored from |
- // this slot before processing the catch block |
- // handler. |
- // ':exception_var' - Used to save the current exception object that was |
- // thrown. |
- // ':stacktrace_var' - Used to save the current stack trace object into which |
- // the stack trace was copied into when an exception was |
- // thrown. |
- // :exception_var and :stacktrace_var get set with the exception object |
- // and the stacktrace object when an exception is thrown. |
- // These three implicit variables can never be captured variables. |
- LocalVariable* context_var = |
- current_block_->scope->LocalLookupVariable(Symbols::SavedTryContextVar()); |
- if (context_var == NULL) { |
- context_var = new LocalVariable(TokenPos(), |
- Symbols::SavedTryContextVar(), |
- Type::ZoneHandle(Type::DynamicType())); |
- current_block_->scope->AddVariable(context_var); |
- } |
- LocalVariable* catch_excp_var = |
- current_block_->scope->LocalLookupVariable(Symbols::ExceptionVar()); |
- if (catch_excp_var == NULL) { |
- catch_excp_var = new LocalVariable(TokenPos(), |
- Symbols::ExceptionVar(), |
- Type::ZoneHandle(Type::DynamicType())); |
- current_block_->scope->AddVariable(catch_excp_var); |
- } |
- LocalVariable* catch_trace_var = |
- current_block_->scope->LocalLookupVariable(Symbols::StacktraceVar()); |
- if (catch_trace_var == NULL) { |
- catch_trace_var = new LocalVariable(TokenPos(), |
- Symbols::StacktraceVar(), |
- Type::ZoneHandle(Type::DynamicType())); |
- current_block_->scope->AddVariable(catch_trace_var); |
- } |
- |
- const intptr_t try_pos = TokenPos(); |
- ConsumeToken(); // Consume the 'try'. |
- |
- SourceLabel* try_label = NULL; |
- if (label_name != NULL) { |
- try_label = SourceLabel::New(try_pos, label_name, SourceLabel::kStatement); |
- OpenBlock(); |
- current_block_->scope->AddLabel(try_label); |
- } |
- |
- // Now parse the 'try' block. |
- OpenBlock(); |
- PushTryBlock(current_block_); |
- ExpectToken(Token::kLBRACE); |
- ParseStatementSequence(); |
- ExpectToken(Token::kRBRACE); |
- SequenceNode* try_block = CloseBlock(); |
- |
- if ((CurrentToken() != Token::kCATCH) && !IsLiteral("on") && |
- (CurrentToken() != Token::kFINALLY)) { |
- ErrorMsg("catch or finally clause expected"); |
- } |
- |
- // Now create a label for the end of catch block processing so that we can |
- // jump over the catch block code after executing the try block. |
- SourceLabel* end_catch_label = |
- SourceLabel::New(TokenPos(), NULL, SourceLabel::kCatch); |
- |
- // Now parse the 'catch' blocks if any and merge all of them into |
- // an if-then sequence of the different types specified using the 'is' |
- // operator. |
+SequenceNode* Parser::ParseCatchClauses( |
+ intptr_t handler_pos, |
+ LocalVariable* exception_var, |
+ LocalVariable* stack_trace_var, |
+ const GrowableObjectArray& handler_types, |
+ bool* needs_stack_trace) { |
+ // All catch blocks are merged into an if-then-else sequence of the |
+ // different types specified using the 'is' operator. While parsing |
+ // record the type tests (either a ComparisonNode or else the LiteralNode |
+ // true for a generic catch) and the catch bodies in a pair of parallel |
+ // lists. Afterward, construct the nested if-then-else. |
bool generic_catch_seen = false; |
- const intptr_t handler_pos = TokenPos(); |
- OpenBlock(); // Start the catch block sequence. |
- current_block_->scope->AddLabel(end_catch_label); |
- const GrowableObjectArray& handler_types = |
- GrowableObjectArray::Handle(GrowableObjectArray::New()); |
- bool needs_stacktrace = false; |
+ GrowableArray<AstNode*> type_tests; |
+ GrowableArray<SequenceNode*> catch_blocks; |
while ((CurrentToken() == Token::kCATCH) || IsLiteral("on")) { |
+ // Open a block that contains the if or an unconditional body. It's |
+ // closed in the loop that builds the if-then-else nest. |
+ OpenBlock(); |
const intptr_t catch_pos = TokenPos(); |
CatchParamDesc exception_param; |
CatchParamDesc stack_trace_param; |
@@ -6839,116 +6785,223 @@ AstNode* Parser::ParseTryStatement(String* label_name) { |
ConsumeToken(); // Consume the 'catch'. |
ExpectToken(Token::kLPAREN); |
exception_param.token_pos = TokenPos(); |
- exception_param.var = ExpectIdentifier("identifier expected"); |
+ exception_param.name = ExpectIdentifier("identifier expected"); |
if (CurrentToken() == Token::kCOMMA) { |
ConsumeToken(); |
// TODO(hausner): Make implicit type be StackTrace, not dynamic. |
stack_trace_param.type = |
&AbstractType::ZoneHandle(Type::DynamicType()); |
stack_trace_param.token_pos = TokenPos(); |
- stack_trace_param.var = ExpectIdentifier("identifier expected"); |
+ stack_trace_param.name = ExpectIdentifier("identifier expected"); |
} |
ExpectToken(Token::kRPAREN); |
} |
- // Create a block containing the catch clause parameters and |
- // the following code: |
+ // Create a block containing the catch clause parameters and the |
+ // 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. |
- // 3) Unconditional JUMP to the end of the try block. |
OpenBlock(); |
- AddCatchParamsToScope(exception_param, |
- stack_trace_param, |
+ AddCatchParamsToScope(&exception_param, &stack_trace_param, |
current_block_->scope); |
if (exception_param.var != NULL) { |
// Generate code to load the exception object (:exception_var) into |
// the exception variable specified in this block. |
- LocalVariable* var = LookupLocalScope(*exception_param.var); |
- ASSERT(var != NULL); |
- ASSERT(catch_excp_var != NULL); |
+ ASSERT(exception_var != NULL); |
current_block_->statements->Add( |
- new StoreLocalNode(catch_pos, var, |
- new LoadLocalNode(catch_pos, catch_excp_var))); |
+ new StoreLocalNode(catch_pos, exception_param.var, |
+ new LoadLocalNode(catch_pos, exception_var))); |
} |
if (stack_trace_param.var != NULL) { |
// A stack trace variable is specified in this block, so generate code |
- // to load the stack trace object (:stacktrace_var) into the stack trace |
- // variable specified in this block. |
- needs_stacktrace = true; |
+ // to load the stack trace object (:stack_trace_var) into the stack |
+ // trace variable specified in this block. |
+ *needs_stack_trace = true; |
ArgumentListNode* no_args = new ArgumentListNode(catch_pos); |
- LocalVariable* trace = LookupLocalScope(*stack_trace_param.var); |
- ASSERT(catch_trace_var != NULL); |
+ ASSERT(stack_trace_var != NULL); |
current_block_->statements->Add( |
- new StoreLocalNode(catch_pos, trace, |
- new LoadLocalNode(catch_pos, catch_trace_var))); |
+ new StoreLocalNode(catch_pos, stack_trace_param.var, |
+ new LoadLocalNode(catch_pos, stack_trace_var))); |
current_block_->statements->Add( |
new InstanceCallNode( |
catch_pos, |
- new LoadLocalNode(catch_pos, trace), |
+ new LoadLocalNode(catch_pos, stack_trace_param.var), |
Library::PrivateCoreLibName(Symbols::_setupFullStackTrace()), |
no_args)); |
} |
- // Add nested block with user-defined code. |
+ // Add nested block with user-defined code. This blocks allows |
+ // declarations in the body to shadow the catch parameters. |
CheckToken(Token::kLBRACE); |
current_block_->statements->Add(ParseNestedStatement(false, NULL)); |
- |
- // Add unconditional jump to end of catch clause list. |
- current_block_->statements->Add( |
- new JumpNode(catch_pos, Token::kCONTINUE, end_catch_label)); |
- |
- SequenceNode* catch_clause = CloseBlock(); |
- |
- const bool is_bad_type = exception_param.type->IsMalformed() || |
- exception_param.type->IsMalbounded(); |
- if (!is_bad_type && !exception_param.type->IsDynamicType()) { |
- // Has a type specification that is not malformed or malbounded. |
- // Now form an 'if type check' to guard the catch handler code. |
+ catch_blocks.Add(CloseBlock()); |
+ |
+ const bool is_bad_type = |
+ exception_param.type->IsMalformed() || |
+ exception_param.type->IsMalbounded(); |
+ if (exception_param.type->IsDynamicType() || is_bad_type) { |
+ // There is no exception type or else it is malformed or malbounded. |
+ // In the first case, unconditionally execute the catch body. In the |
+ // second case, unconditionally throw. |
+ generic_catch_seen = true; |
+ type_tests.Add(new LiteralNode(catch_pos, Bool::True())); |
+ if (is_bad_type) { |
+ // Replace the body with one that throws. |
+ SequenceNode* block = new SequenceNode(catch_pos, NULL); |
+ block->Add(ThrowTypeError(catch_pos, *exception_param.type)); |
+ catch_blocks.Last() = block; |
+ } |
+ // This catch clause will handle all exceptions. We can safely forget |
+ // all previous catch clause types. |
+ handler_types.SetLength(0); |
+ handler_types.Add(*exception_param.type); |
+ } else { |
+ // Has a type specification that is not malformed or malbounded. Now |
+ // form an 'if type check' to guard the catch handler code. |
if (!exception_param.type->IsInstantiated() && |
(current_block_->scope->function_level() > 0)) { |
// Make sure that the instantiator is captured. |
CaptureInstantiator(); |
} |
TypeNode* exception_type = new TypeNode(catch_pos, *exception_param.type); |
- AstNode* exception_var = new LoadLocalNode(catch_pos, catch_excp_var); |
+ AstNode* exception_value = new LoadLocalNode(catch_pos, exception_var); |
if (!exception_type->type().IsInstantiated()) { |
EnsureExpressionTemp(); |
} |
- AstNode* type_cond_expr = new ComparisonNode( |
- catch_pos, Token::kIS, exception_var, exception_type); |
- current_block_->statements->Add( |
- new IfNode(catch_pos, type_cond_expr, catch_clause, NULL)); |
- |
- // Do not add uninstantiated types (e.g. type parameter T or |
- // generic type List<T>), since the debugger won't be able to |
- // instantiate it when walking the stack. |
- // This means that the debugger is not able to determine whether |
- // an exception is caught if the catch clause uses generic types. |
- // It will report the exception as uncaught when in fact it might |
- // be caught and handled when we unwind the stack. |
- if (exception_param.type->IsInstantiated()) { |
+ type_tests.Add(new ComparisonNode(catch_pos, Token::kIS, exception_value, |
+ exception_type)); |
+ |
+ // Do not add uninstantiated types (e.g. type parameter T or generic |
+ // type List<T>), since the debugger won't be able to instantiate it |
+ // when walking the stack. |
+ // |
+ // This means that the debugger is not able to determine whether an |
+ // exception is caught if the catch clause uses generic types. It |
+ // will report the exception as uncaught when in fact it might be |
+ // caught and handled when we unwind the stack. |
+ if (!generic_catch_seen && exception_param.type->IsInstantiated()) { |
handler_types.Add(*exception_param.type); |
} |
- } else { |
- if (is_bad_type) { |
- current_block_->statements->Add(ThrowTypeError(catch_pos, |
- *exception_param.type)); |
- // We still add the dead code below to satisfy the code generator. |
- } |
- // No exception type exists in the catch clause so execute the |
- // catch handler code unconditionally. |
- current_block_->statements->Add(catch_clause); |
- generic_catch_seen = true; |
- // This catch clause will handle all exceptions. We can safely forget |
- // all previous catch clause types. |
- handler_types.SetLength(0); |
- handler_types.Add(*exception_param.type); |
} |
+ |
+ ASSERT(type_tests.length() == catch_blocks.length()); |
+ } |
+ |
+ // Build the if/then/else nest from the inside out. Keep the AST simple |
+ // for the case of a single generic catch clause. The initial value of |
+ // current is the last (innermost) else block if there were any catch |
+ // clauses. |
+ SequenceNode* current = NULL; |
+ if (!generic_catch_seen) { |
+ // There isn't a generic catch clause so create a clause body that |
+ // rethrows the exception. This includes the case that there were no |
+ // catch clauses. |
+ current = new SequenceNode(handler_pos, NULL); |
+ current->Add( |
+ new ThrowNode(handler_pos, |
+ new LoadLocalNode(handler_pos, exception_var), |
+ new LoadLocalNode(handler_pos, stack_trace_var))); |
+ } else if (type_tests.Last()->IsLiteralNode()) { |
+ ASSERT(type_tests.Last()->AsLiteralNode()->literal().raw() == |
+ Bool::True().raw()); |
+ // The last body is entered unconditionally. Start building the |
+ // if/then/else nest with that body as the innermost else block. |
+ // Note that it is nested inside an extra block which we opened |
+ // before we knew the body was entered unconditionally. |
+ type_tests.RemoveLast(); |
+ current_block_->statements->Add(catch_blocks.RemoveLast()); |
+ current = CloseBlock(); |
+ } |
+ // If the last body was entered conditionally and there is no need to add |
+ // a rethrow, use an empty else body (current = NULL above). |
+ |
+ while (!type_tests.is_empty()) { |
+ AstNode* type_test = type_tests.RemoveLast(); |
+ SequenceNode* catch_block = catch_blocks.RemoveLast(); |
+ current_block_->statements->Add( |
+ new IfNode(type_test->token_pos(), type_test, catch_block, current)); |
+ current = CloseBlock(); |
+ } |
+ return current; |
+} |
+ |
+ |
+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. |
+ LocalVariable* context_var = |
+ current_block_->scope->LocalLookupVariable(Symbols::SavedTryContextVar()); |
+ if (context_var == NULL) { |
+ context_var = new LocalVariable(TokenPos(), |
+ Symbols::SavedTryContextVar(), |
+ Type::ZoneHandle(Type::DynamicType())); |
+ current_block_->scope->AddVariable(context_var); |
+ } |
+ LocalVariable* exception_var = |
+ current_block_->scope->LocalLookupVariable(Symbols::ExceptionVar()); |
+ if (exception_var == NULL) { |
+ exception_var = new LocalVariable(TokenPos(), |
+ Symbols::ExceptionVar(), |
+ Type::ZoneHandle(Type::DynamicType())); |
+ 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 LocalVariable(TokenPos(), |
+ Symbols::StackTraceVar(), |
+ Type::ZoneHandle(Type::DynamicType())); |
+ current_block_->scope->AddVariable(stack_trace_var); |
+ } |
+ |
+ const intptr_t try_pos = TokenPos(); |
+ ConsumeToken(); // Consume the 'try'. |
+ |
+ SourceLabel* try_label = NULL; |
+ if (label_name != NULL) { |
+ try_label = SourceLabel::New(try_pos, label_name, SourceLabel::kStatement); |
+ OpenBlock(); |
+ current_block_->scope->AddLabel(try_label); |
+ } |
+ |
+ // Now parse the 'try' block. |
+ OpenBlock(); |
+ PushTryBlock(current_block_); |
+ ExpectToken(Token::kLBRACE); |
+ ParseStatementSequence(); |
+ ExpectToken(Token::kRBRACE); |
+ SequenceNode* try_block = CloseBlock(); |
+ |
+ if ((CurrentToken() != Token::kCATCH) && !IsLiteral("on") && |
+ (CurrentToken() != Token::kFINALLY)) { |
+ ErrorMsg("catch or finally clause expected"); |
} |
- SequenceNode* catch_handler_list = CloseBlock(); |
+ // Now parse the 'catch' blocks if any. |
+ try_blocks_list_->enter_catch(); |
+ const intptr_t handler_pos = TokenPos(); |
+ const GrowableObjectArray& handler_types = |
+ GrowableObjectArray::Handle(GrowableObjectArray::New()); |
+ bool needs_stack_trace = false; |
+ SequenceNode* catch_handler_list = |
+ ParseCatchClauses(handler_pos, exception_var, stack_trace_var, |
+ handler_types, &needs_stack_trace); |
+ |
TryBlocks* inner_try_block = PopTryBlock(); |
const intptr_t try_index = inner_try_block->try_index(); |
TryBlocks* outer_try_block = try_blocks_list_; |
@@ -6980,32 +7033,24 @@ AstNode* Parser::ParseTryStatement(String* label_name) { |
finally_block = ParseFinallyBlock(); |
} |
- if (!generic_catch_seen) { |
- // No generic catch handler exists so rethrow the exception so that |
- // the next catch handler can deal with it. |
- catch_handler_list->Add( |
- new ThrowNode(handler_pos, |
- new LoadLocalNode(handler_pos, catch_excp_var), |
- new LoadLocalNode(handler_pos, catch_trace_var))); |
- } |
- CatchClauseNode* catch_block = |
+ CatchClauseNode* catch_clause = |
new CatchClauseNode(handler_pos, |
catch_handler_list, |
Array::ZoneHandle(Array::MakeArray(handler_types)), |
context_var, |
- catch_excp_var, |
- catch_trace_var, |
+ exception_var, |
+ stack_trace_var, |
(finally_block != NULL) |
? AllocateTryIndex() |
: CatchClauseNode::kInvalidTryIndex, |
- needs_stacktrace); |
+ needs_stack_trace); |
// Now create the try/catch ast node and return it. If there is a label |
// on the try/catch, close the block that's embedding the try statement |
// and attach the label to it. |
AstNode* try_catch_node = |
- new TryCatchNode(try_pos, try_block, end_catch_label, |
- context_var, catch_block, finally_block, try_index); |
+ new TryCatchNode(try_pos, try_block, context_var, catch_clause, |
+ finally_block, try_index); |
if (try_label != NULL) { |
current_block_->statements->Add(try_catch_node); |
@@ -7162,19 +7207,18 @@ AstNode* Parser::ParseStatement() { |
ConsumeToken(); |
ExpectSemicolon(); |
// Check if it is ok to do a rethrow. |
- SourceLabel* label = current_block_->scope->LookupInnermostCatchLabel(); |
- if (label == NULL || |
- label->FunctionLevel() != current_block_->scope->function_level()) { |
+ if ((try_blocks_list_ == NULL) || !try_blocks_list_->inside_catch()) { |
ErrorMsg(statement_pos, "rethrow of an exception is not valid here"); |
} |
- ASSERT(label->owner() != NULL); |
- LocalScope* scope = label->owner()->parent(); |
+ // 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()); |
ASSERT(excp_var != NULL); |
LocalVariable* trace_var = |
- scope->LocalLookupVariable(Symbols::StacktraceVar()); |
+ scope->LocalLookupVariable(Symbols::StackTraceVar()); |
ASSERT(trace_var != NULL); |
statement = new ThrowNode(statement_pos, |
new LoadLocalNode(statement_pos, excp_var), |