Chromium Code Reviews| Index: runtime/vm/parser.cc |
| diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc |
| index 1c526729885dd2e6c84107fec63d6ee46ac7557f..6d998dd58a84dea413163dfcc97d5784c132682c 100644 |
| --- a/runtime/vm/parser.cc |
| +++ b/runtime/vm/parser.cc |
| @@ -365,6 +365,7 @@ class Parser::TryStack : public ZoneAllocated { |
| void exit_finally() { inside_finally_ = false; } |
| void AddNodeForFinallyInlining(AstNode* node); |
| + void RemoveJumpToLabel(SourceLabel *label); |
| AstNode* GetNodeToInlineFinally(int index) { |
| if (0 <= index && index < inlined_finally_nodes_.length()) { |
| return inlined_finally_nodes_[index]; |
| @@ -390,6 +391,24 @@ void Parser::TryStack::AddNodeForFinallyInlining(AstNode* node) { |
| } |
| +void Parser::TryStack::RemoveJumpToLabel(SourceLabel *label) { |
| + int i = 0; |
| + while (i < inlined_finally_nodes_.length()) { |
| + if (inlined_finally_nodes_[i]->IsJumpNode()) { |
| + JumpNode* jump = inlined_finally_nodes_[i]->AsJumpNode(); |
| + if (jump->label() == label) { |
| + for (int j = i + 1; j < inlined_finally_nodes_.length(); j++) { |
| + inlined_finally_nodes_[i] = inlined_finally_nodes_[j]; |
|
regis
2016/06/02 01:13:25
Did you mean j-1 instead of i, which is not increm
hausner
2016/06/02 15:38:51
Ahem, yes. Good catch, thank you!
|
| + } |
| + inlined_finally_nodes_.RemoveLast(); |
| + continue; |
| + } |
| + } |
| + i++; |
| + } |
| +} |
| + |
| + |
| // For parsing a compilation unit. |
| Parser::Parser(const Script& script, |
| const Library& library, |
| @@ -8441,6 +8460,7 @@ AstNode* Parser::ParseSwitchStatement(String* label_name) { |
| // We have seen a 'continue' with this label name. Resolve |
| // the forward reference. |
| case_label->ResolveForwardReference(); |
| + RemoveNodesForFinallyInlining(case_label); |
| } else { |
| ReportError(label_pos, "label '%s' already exists in scope", |
| label_name->ToCString()); |
| @@ -9349,7 +9369,12 @@ void Parser::AddNodeForFinallyInlining(AstNode* node) { |
| // so we do not need to inline the finally code. Otherwise we need |
| // to inline the finally code of this try block and then move on to the |
| // next outer try block. |
| - if (label->owner()->IsNestedWithin(try_scope)) { |
| + // For unresolved forward jumps to switch cases, we don't yet know |
| + // to which scope the label will be resolved. Tentatively add the |
| + // jump to all nested try statements and remove the outermost ones |
| + // when we know the exact jump target. (See |
| + // RemoveNodesForFinallyInlining below.) |
| + if (!label->IsUnresolved() && label->owner()->IsNestedWithin(try_scope)) { |
| break; |
| } |
| } |
| @@ -9359,6 +9384,17 @@ void Parser::AddNodeForFinallyInlining(AstNode* node) { |
| } |
| +void Parser::RemoveNodesForFinallyInlining(SourceLabel* label) { |
| + TryStack* iterator = try_stack_; |
| + const intptr_t func_level = FunctionLevel(); |
| + while ((iterator != NULL) && |
| + (iterator->try_block()->scope->function_level() == func_level)) { |
| + iterator->RemoveJumpToLabel(label); |
| + iterator = iterator->outer_try(); |
| + } |
| +} |
| + |
| + |
| // Add the inlined finally clause to the specified node. |
| void Parser::AddFinallyClauseToNode(bool is_async, |
| AstNode* node, |