Add support for finalizer of TryFinally in labeled statements

When a break is encountered in the body of a TryFinally statement to an
enclosing label, the finalizer statement of the TryFinally is executed.

BUG=
R=dmitryas@google.com

Review-Url: https://codereview.chromium.org/2991113002 .
This commit is contained in:
Zhivka Gucevska 2017-08-03 16:17:12 +02:00
parent 771415a7c0
commit 115232ada2
3 changed files with 105 additions and 22 deletions

View file

@ -317,7 +317,8 @@ class State {
continuation = null; continuation = null;
State withBreak(Statement stmt, Environment env) { State withBreak(Statement stmt, Environment env) {
Label breakLabels = new Label(stmt, env, continuation, labels); var cont = new BreakBK(continuation, env);
Label breakLabels = new Label(stmt, cont, labels);
return new State( return new State(
breakLabels, exceptionComponents, returnContinuation, continuation); breakLabels, exceptionComponents, returnContinuation, continuation);
} }
@ -344,18 +345,23 @@ class State {
/// enclosing label. /// enclosing label.
class Label { class Label {
final LabeledStatement statement; final LabeledStatement statement;
final Environment environment; final BreakContinuation continuation;
final StatementContinuation continuation;
final Label enclosingLabel; final Label enclosingLabel;
Label( Label(this.statement, this.continuation, this.enclosingLabel);
this.statement, this.environment, this.continuation, this.enclosingLabel);
Label lookupLabel(LabeledStatement s) { Label lookupLabel(LabeledStatement s) {
if (identical(s, statement)) return this; if (identical(s, statement)) return this;
assert(enclosingLabel != null); assert(enclosingLabel != null);
return enclosingLabel.lookupLabel(s); return enclosingLabel.lookupLabel(s);
} }
// Recursively install finally break to all labels.
Label withFinalizer(Statement finalizer, Environment env, State state) {
var label = enclosingLabel?.withFinalizer(finalizer, env, state);
var finallyCont = new FinallyBK(finalizer, env, state, continuation);
return new Label(statement, finallyCont, label);
}
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -456,6 +462,50 @@ class ThrowConfiguration extends Configuration {
Configuration step(StatementExecuter _) => handler(exception, stacktrace); Configuration step(StatementExecuter _) => handler(exception, stacktrace);
} }
class BreakConfiguration extends Configuration {
final BreakContinuation continuation;
BreakConfiguration(this.continuation);
Configuration step(StatementExecuter _) => continuation();
}
abstract class BreakContinuation extends Continuation {
Configuration call();
}
class BreakBK extends BreakContinuation {
final StatementContinuation continuation;
final Environment environment;
BreakBK(this.continuation, this.environment);
Configuration call() => new ForwardConfiguration(continuation, environment);
}
class FinallyBK extends BreakContinuation {
final Statement finalizer;
final Environment environment;
final State state;
final BreakContinuation continuation;
FinallyBK(this.finalizer, this.environment, this.state, this.continuation);
Configuration call() {
var cont = new BreakSK(continuation);
return new ExecConfiguration(
finalizer, environment, state.withContinuation(cont));
}
}
class BreakSK extends StatementContinuation {
final BreakContinuation continuation;
BreakSK(this.continuation);
Configuration call(Environment _) => new BreakConfiguration(continuation);
}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Interpreter Expressions and Values // Interpreter Expressions and Values
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -1341,21 +1391,16 @@ class CatchHandler extends ExceptionHandler {
class FinallyHandler extends ExceptionHandler { class FinallyHandler extends ExceptionHandler {
final Statement finallyStatement; final Statement finallyStatement;
final Environment environment; final Environment environment;
final Label labels; final State state;
final ExceptionComponents exceptionComponents;
final ExpressionContinuation expressionContinuation;
FinallyHandler(this.finallyStatement, this.environment, this.labels,
this.exceptionComponents, this.expressionContinuation);
FinallyHandler(this.finallyStatement, this.environment, this.state);
Configuration call(Value exception, StackTrace stackTrace) { Configuration call(Value exception, StackTrace stackTrace) {
// A finally handler can't handle an exception, only execute the // A finally handler can't handle an exception, only execute the
// corresponding finally statement and rethrow. // corresponding finally statement and rethrow.
var cont = var cont =
new RethrowSK(exceptionComponents.handler, exception, stackTrace); new RethrowSK(state.exceptionComponents.handler, exception, stackTrace);
var state = var newState = state.withContinuation(cont);
new State(labels, exceptionComponents, expressionContinuation, cont); return new ExecConfiguration(finallyStatement, environment, newState);
return new ExecConfiguration(finallyStatement, environment, state);
} }
} }
@ -1364,7 +1409,7 @@ class FinallyHandler extends ExceptionHandler {
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/// Represents the components for Exception handling. /// Represents the components for Exception handling.
/// ///
/// It contains the list of exception handlers, a stack trace and optional /// It contains the current of exception handler, a stack trace and optional
/// components, current stacktrace and exception. /// components, current stacktrace and exception.
class ExceptionComponents { class ExceptionComponents {
final ExceptionHandler handler; final ExceptionHandler handler;
@ -1483,7 +1528,7 @@ class StatementExecuter
Configuration visitBreakStatement( Configuration visitBreakStatement(
BreakStatement node, ExecConfiguration conf) { BreakStatement node, ExecConfiguration conf) {
Label l = conf.state.lookupLabel(node.target); Label l = conf.state.lookupLabel(node.target);
return new ForwardConfiguration(l.continuation, l.environment); return new BreakConfiguration(l.continuation);
} }
Configuration visitWhileStatement( Configuration visitWhileStatement(
@ -1517,22 +1562,30 @@ class StatementExecuter
Configuration visitTryCatch(TryCatch node, ExecConfiguration conf) { Configuration visitTryCatch(TryCatch node, ExecConfiguration conf) {
var handler = new CatchHandler(node.catches, conf.environment, conf.state); var handler = new CatchHandler(node.catches, conf.environment, conf.state);
var handlers = new ExceptionComponents( var exceptionComponents = new ExceptionComponents(
handler, handler,
conf.state.exceptionComponents.stackTrace, conf.state.exceptionComponents.stackTrace,
conf.state.exceptionComponents.currentStackTrace, conf.state.exceptionComponents.currentStackTrace,
conf.state.exceptionComponents.currentException); conf.state.exceptionComponents.currentException);
var state = conf.state.withException(handlers); var state = conf.state.withException(exceptionComponents);
return new ExecConfiguration(node.body, conf.environment, state); return new ExecConfiguration(node.body, conf.environment, state);
} }
Configuration visitTryFinally(TryFinally node, ExecConfiguration conf) { Configuration visitTryFinally(TryFinally node, ExecConfiguration conf) {
// TODO(zhivkag): Add FinallyBreak to break labels.
var cont = new FinallySK(node.finalizer, conf.environment, conf.state); var cont = new FinallySK(node.finalizer, conf.environment, conf.state);
var returnCont = var returnCont =
new FinallyReturnEK(node.finalizer, conf.environment, conf.state); new FinallyReturnEK(node.finalizer, conf.environment, conf.state);
return new ExecConfiguration(node.body, conf.environment, var labels = conf.state.labels
conf.state.withContinuation(cont).withReturnContinuation(returnCont)); ?.withFinalizer(node.finalizer, conf.environment, conf.state);
var handler =
new FinallyHandler(node.finalizer, conf.environment, conf.state);
var exceptionComponents = new ExceptionComponents(
handler,
conf.state.exceptionComponents.stackTrace,
conf.state.exceptionComponents.currentStackTrace,
conf.state.exceptionComponents.currentException);
var state = new State(labels, exceptionComponents, returnCont, cont);
return new ExecConfiguration(node.body, conf.environment, state);
} }
Configuration visitVariableDeclaration( Configuration visitVariableDeclaration(

View file

@ -0,0 +1,18 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
main() {
int i = 0;
while (true) {
try {
if (i == 5) {
break;
}
} catch (e, _) {} finally {
print('Finally with i=$i');
}
print(i);
i++;
}
}

View file

@ -0,0 +1,12 @@
print(String: Finally with i=0)
print(int: 0)
print(String: Finally with i=1)
print(int: 1)
print(String: Finally with i=2)
print(int: 2)
print(String: Finally with i=3)
print(int: 3)
print(String: Finally with i=4)
print(int: 4)
if-then
print(String: Finally with i=5)