| Index: runtime/vm/parser.cc
|
| diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
|
| index 1c526729885dd2e6c84107fec63d6ee46ac7557f..f2a6422d17c4e74fda206aa5d0cef4d6bd4d472c 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,25 @@ 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) {
|
| + // Shift remaining entries left and delete last entry.
|
| + for (int j = i + 1; j < inlined_finally_nodes_.length(); j++) {
|
| + inlined_finally_nodes_[j - 1] = inlined_finally_nodes_[j];
|
| + }
|
| + inlined_finally_nodes_.RemoveLast();
|
| + continue;
|
| + }
|
| + }
|
| + i++;
|
| + }
|
| +}
|
| +
|
| +
|
| // For parsing a compilation unit.
|
| Parser::Parser(const Script& script,
|
| const Library& library,
|
| @@ -8441,6 +8461,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 +9370,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 +9385,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,
|
|
|