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

Unified Diff: pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart

Issue 1201983002: Implement try/finally by inlining the finally code. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Merge, rebase test expectations. Created 5 years, 6 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 | « no previous file | pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
index c491237d77c5ef5996ee166a103224f0b060894f..8be9b21676f8a222743fbfb3fba93dc0357d7475 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
@@ -68,24 +68,25 @@ class Environment {
void extend(Local element, ir.Primitive value) {
// Assert that the name is not already in the environment. `null` is used
- // as the name of anonymous variables. Because the variable2index map is
- // shared, `null` can already occur. This is safe because such variables
- // are not looked up by name.
- //
- // TODO(kmillikin): This is still kind of fishy. Refactor to not share
- // name maps or else garbage collect unneeded names.
- assert(element == null || !variable2index.containsKey(element));
- variable2index[element] = index2variable.length;
+ // as the name of anonymous variables.
+ assert(!variable2index.containsKey(element));
+ if (element != null) variable2index[element] = index2variable.length;
index2variable.add(element);
index2value.add(value);
}
- void discard(int count) {
+ /// Drop [count] values from the environment.
+ ///
+ /// Return the previous last value in the environment for convenience.
+ ir.Primitive discard(int count) {
+ assert(count > 0);
assert(count <= index2variable.length);
+ ir.Primitive value = index2value.last;
// The map from variables to their index are shared, so we cannot remove
// the mapping in `variable2index`.
index2variable.length -= count;
index2value.length -= count;
+ return value;
}
ir.Primitive lookup(Local element) {
@@ -108,10 +109,12 @@ class Environment {
Local variable = index2variable[i];
if (variable != other.index2variable[i]) return false;
- // The variable maps to the same index in both environments.
- int index = variable2index[variable];
- if (index == null || index != other.variable2index[variable]) {
- return false;
+ // A named variable maps to the same index in both environments.
+ if (variable != null) {
+ int index = variable2index[variable];
+ if (index == null || index != other.variable2index[variable]) {
+ return false;
+ }
}
}
return true;
@@ -131,7 +134,15 @@ abstract class JumpCollector {
final List<Iterable<LocalVariableElement>> _boxedTryVariables =
<Iterable<LocalVariableElement>>[];
- JumpCollector(this._continuationEnvironment, this.target);
+ /// Construct a collector for a given environment and optionally a target.
+ ///
+ /// The environment is the one in effect at the point where the jump's
+ /// continuation will be bound. Continuations can take an extra argument
+ /// (see [addJump]).
+ JumpCollector(this._continuationEnvironment, this.target,
+ bool hasExtraArgument) {
+ if (hasExtraArgument) _continuationEnvironment.extend(null, null);
+ }
/// True if the collector has not recorded any jumps to its continuation.
bool get isEmpty;
@@ -144,7 +155,12 @@ abstract class JumpCollector {
Environment get environment;
/// Emit a jump to the continuation for a given [IrBuilder].
- void addJump(IrBuilder builder);
+ ///
+ /// Jumps can take a single extra argument. This is used to pass return
+ /// values to finally blocks for returns inside try/finally and to pass
+ /// values of expressions that have internal control flow to their join-point
+ /// continuations.
+ void addJump(IrBuilder builder, [ir.Primitive value]);
/// Add a set of variables that were boxed on entry to a try block.
///
@@ -206,8 +222,9 @@ class ForwardJumpCollector extends JumpCollector {
/// continuation represented by this collector will be bound. The
/// environment is copied by the collector. Subsequent mutation of the
/// original environment will not affect the collector.
- ForwardJumpCollector(Environment environment, {JumpTarget target: null})
- : super(new Environment.from(environment), target);
+ ForwardJumpCollector(Environment environment,
+ {JumpTarget target, bool hasExtraArgument: false})
+ : super(new Environment.from(environment), target, hasExtraArgument);
bool get isEmpty => _invocations.isEmpty;
@@ -221,12 +238,20 @@ class ForwardJumpCollector extends JumpCollector {
return _continuationEnvironment;
}
- void addJump(IrBuilder builder) {
+ void addJump(IrBuilder builder, [ir.Primitive value]) {
assert(_continuation == null);
_buildTryExit(builder);
ir.InvokeContinuation invoke = new ir.InvokeContinuation.uninitialized();
builder.add(invoke);
_invocations.add(invoke);
+ // Truncate the environment at the invocation site so it only includes
+ // values that will be continuation arguments. If an extra value is passed
+ // it will already be included in the continuation environment, but it is
+ // not present in the invocation environment.
+ int delta = builder.environment.length - _continuationEnvironment.length;
+ if (value != null) ++delta;
+ if (delta > 0) builder.environment.discard(delta);
+ if (value != null) builder.environment.extend(null, value);
_invocationEnvironments.add(builder.environment);
builder._current = null;
// TODO(kmillikin): Can we set builder.environment to null to make it
@@ -308,8 +333,9 @@ class BackwardJumpCollector extends JumpCollector {
/// continuation represented by this collector will be bound. The
/// translation of the continuation body will use an environment with the
/// same shape, but with fresh continuation parameters for each variable.
- BackwardJumpCollector(Environment environment, {JumpTarget target: null})
- : super(new Environment.fresh(environment), target) {
+ BackwardJumpCollector(Environment environment,
+ {JumpTarget target, bool hasExtraArgument: false})
+ : super(new Environment.fresh(environment), target, hasExtraArgument) {
List<ir.Parameter> parameters =
new List<ir.Parameter>.from(_continuationEnvironment.index2value);
_continuation = new ir.Continuation(parameters, isRecursive: true);
@@ -320,13 +346,20 @@ class BackwardJumpCollector extends JumpCollector {
ir.Continuation get continuation => _continuation;
Environment get environment => _continuationEnvironment;
- void addJump(IrBuilder builder) {
+ void addJump(IrBuilder builder, [ir.Primitive value]) {
assert(_continuation.parameters.length <= builder.environment.length);
isEmpty = false;
_buildTryExit(builder);
+ // Truncate the environment at the invocation site so it only includes
+ // values that will be continuation arguments. If an extra value is passed
+ // it will already be included in the continuation environment, but it is
+ // not present in the invocation environment.
+ int delta = builder.environment.length - _continuationEnvironment.length;
+ if (value != null) ++delta;
+ if (delta > 0) builder.environment.discard(delta);
+ if (value != null) builder.environment.extend(null, value);
builder.add(new ir.InvokeContinuation(_continuation,
- builder.environment.index2value.take(_continuation.parameters.length)
- .toList(),
+ builder.environment.index2value,
isRecursive: true));
builder._current = null;
}
@@ -394,14 +427,22 @@ class IrBuilderSharedState {
ConstantSystem get constantSystem => constants.constantSystem;
/// A stack of collectors for breaks.
- final List<JumpCollector> breakCollectors = <JumpCollector>[];
+ List<JumpCollector> breakCollectors = <JumpCollector>[];
/// A stack of collectors for continues.
- final List<JumpCollector> continueCollectors = <JumpCollector>[];
+ List<JumpCollector> continueCollectors = <JumpCollector>[];
final ExecutableElement currentElement;
final ir.Continuation returnContinuation = new ir.Continuation.retrn();
+
+ /// The target of a return from the function.
+ ///
+ /// A null value indicates that the target is the function's return
+ /// continuation. Otherwise, when inside the try block of try/finally
+ /// a return is intercepted to give a place to generate the finally code.
+ JumpCollector returnCollector = null;
+
ir.Parameter _thisParameter;
ir.Parameter enclosingMethodThisParameter;
@@ -750,20 +791,10 @@ abstract class IrBuilder {
// expressions cannot introduce variable bindings.
assert(environment.length == thenBuilder.environment.length);
assert(environment.length == elseBuilder.environment.length);
- // Extend the join-point environment with a placeholder for the value of
- // the expression. Optimistically assume that the value is the value of
- // the first subexpression. This value might noe even be in scope at the
- // join-point because it's bound in the first subexpression. However, if
- // that is the case, it will necessarily differ from the value of the
- // other subexpression and cause the introduction of a join-point
- // continuation parameter. If the two values do happen to be the same,
- // this will avoid inserting a useless continuation parameter.
- environment.extend(null, thenValue);
- thenBuilder.environment.extend(null, thenValue);
- elseBuilder.environment.extend(null, elseValue);
- JumpCollector join = new ForwardJumpCollector(environment);
- thenBuilder.jumpTo(join);
- elseBuilder.jumpTo(join);
+ JumpCollector join =
+ new ForwardJumpCollector(environment, hasExtraArgument: true);
+ thenBuilder.jumpTo(join, thenValue);
+ elseBuilder.jumpTo(join, elseValue);
// Build the term
// let cont join(x, ..., result) = [] in
@@ -782,10 +813,7 @@ abstract class IrBuilder {
thenContinuation,
elseContinuation))));
environment = join.environment;
- environment.discard(1);
- return (thenValue == elseValue)
- ? thenValue
- : join.continuation.parameters.last;
+ return environment.discard(1);
}
/**
@@ -1169,8 +1197,8 @@ abstract class IrBuilder {
}
}
- void jumpTo(JumpCollector collector) {
- collector.addJump(this);
+ void jumpTo(JumpCollector collector, [ir.Primitive value]) {
+ collector.addJump(this, value);
}
void addRecursiveContinuation(BackwardJumpCollector collector) {
@@ -1715,6 +1743,7 @@ abstract class IrBuilder {
{TryStatementInfo tryStatementInfo,
SubbuildFunction buildTryBlock,
List<CatchClauseInfo> catchClauseInfos: const <CatchClauseInfo>[],
+ SubbuildFunction buildFinallyBlock,
ClosureClassMap closureClassMap}) {
assert(isOpen);
@@ -1747,125 +1776,230 @@ abstract class IrBuilder {
// scope of the handler. The mutable bindings are dereferenced at the end
// of the try block and at the beginning of the catch block, so the
// variables are unboxed in the catch block and at the join point.
- JumpCollector join = new ForwardJumpCollector(environment);
- IrBuilder tryCatchBuilder = makeDelimitedBuilder();
-
- // Variables treated as mutable in a try are not mutable outside of it.
- // Work with a copy of the outer builder's mutable variables.
- tryCatchBuilder.mutableVariables =
- new Map<Local, ir.MutableVariable>.from(mutableVariables);
- for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) {
- assert(!tryCatchBuilder.isInMutableVariable(variable));
- ir.Primitive value = tryCatchBuilder.buildLocalVariableGet(variable);
- tryCatchBuilder.makeMutableVariable(variable);
- tryCatchBuilder.declareLocalVariable(variable, initialValue: value);
- }
+ if (catchClauseInfos.isNotEmpty) {
+ JumpCollector join = new ForwardJumpCollector(environment);
+ IrBuilder tryCatchBuilder = makeDelimitedBuilder();
+
+ // Variables treated as mutable in a try are not mutable outside of it.
+ // Work with a copy of the outer builder's mutable variables.
+ tryCatchBuilder.mutableVariables =
+ new Map<Local, ir.MutableVariable>.from(mutableVariables);
+ for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) {
+ assert(!tryCatchBuilder.isInMutableVariable(variable));
+ ir.Primitive value = tryCatchBuilder.buildLocalVariableGet(variable);
+ tryCatchBuilder.makeMutableVariable(variable);
+ tryCatchBuilder.declareLocalVariable(variable, initialValue: value);
+ }
- IrBuilder tryBuilder = tryCatchBuilder.makeDelimitedBuilder();
+ IrBuilder tryBuilder = tryCatchBuilder.makeDelimitedBuilder();
- void interceptJumps(JumpCollector collector) {
- collector.enterTry(tryStatementInfo.boxedOnEntry);
- }
- void restoreJumps(JumpCollector collector) {
- collector.leaveTry();
- }
- tryBuilder.state.breakCollectors.forEach(interceptJumps);
- tryBuilder.state.continueCollectors.forEach(interceptJumps);
- buildTryBlock(tryBuilder);
- if (tryBuilder.isOpen) {
- interceptJumps(join);
- tryBuilder.jumpTo(join);
- restoreJumps(join);
- }
- tryBuilder.state.breakCollectors.forEach(restoreJumps);
- tryBuilder.state.continueCollectors.forEach(restoreJumps);
-
- IrBuilder catchBuilder = tryCatchBuilder.makeDelimitedBuilder();
- for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) {
- assert(catchBuilder.isInMutableVariable(variable));
- ir.Primitive value = catchBuilder.buildLocalVariableGet(variable);
- // After this point, the variables that were boxed on entry to the try
- // are no longer treated as mutable.
- catchBuilder.removeMutableVariable(variable);
- catchBuilder.environment.update(variable, value);
- }
+ void interceptJump(JumpCollector collector) {
+ collector.enterTry(tryStatementInfo.boxedOnEntry);
+ }
+ void restoreJump(JumpCollector collector) {
+ collector.leaveTry();
+ }
+ tryBuilder.state.breakCollectors.forEach(interceptJump);
+ tryBuilder.state.continueCollectors.forEach(interceptJump);
+ buildTryBlock(tryBuilder);
+ if (tryBuilder.isOpen) {
+ interceptJump(join);
+ tryBuilder.jumpTo(join);
+ restoreJump(join);
+ }
+ tryBuilder.state.breakCollectors.forEach(restoreJump);
+ tryBuilder.state.continueCollectors.forEach(restoreJump);
+
+ IrBuilder catchBuilder = tryCatchBuilder.makeDelimitedBuilder();
+ for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) {
+ assert(catchBuilder.isInMutableVariable(variable));
+ ir.Primitive value = catchBuilder.buildLocalVariableGet(variable);
+ // After this point, the variables that were boxed on entry to the try
+ // are no longer treated as mutable.
+ catchBuilder.removeMutableVariable(variable);
+ catchBuilder.environment.update(variable, value);
+ }
- // Handlers are always translated as having both exception and stack trace
- // parameters. Multiple clauses do not have to use the same names for
- // them. Choose the first of each as the name hint for the respective
- // handler parameter.
- ir.Parameter exceptionParameter =
- new ir.Parameter(catchClauseInfos.first.exceptionVariable);
- LocalVariableElement traceVariable;
- CatchClauseInfo catchAll;
- for (int i = 0; i < catchClauseInfos.length; ++i) {
- CatchClauseInfo info = catchClauseInfos[i];
- if (info.type == null) {
- catchAll = info;
- catchClauseInfos.length = i;
- break;
+ // Handlers are always translated as having both exception and stack trace
+ // parameters. Multiple clauses do not have to use the same names for
+ // them. Choose the first of each as the name hint for the respective
+ // handler parameter.
+ ir.Parameter exceptionParameter =
+ new ir.Parameter(catchClauseInfos.first.exceptionVariable);
+ LocalVariableElement traceVariable;
+ CatchClauseInfo catchAll;
+ for (int i = 0; i < catchClauseInfos.length; ++i) {
+ CatchClauseInfo info = catchClauseInfos[i];
+ if (info.type == null) {
+ catchAll = info;
+ catchClauseInfos.length = i;
+ break;
+ }
+ if (traceVariable == null) {
+ traceVariable = info.stackTraceVariable;
+ }
}
- if (traceVariable == null) {
- traceVariable = info.stackTraceVariable;
+ ir.Parameter traceParameter = new ir.Parameter(traceVariable);
+ // Expand multiple catch clauses into an explicit if/then/else. Iterate
+ // them in reverse so the current block becomes the next else block.
+ ir.Expression catchBody;
+ if (catchAll == null) {
+ catchBody = new ir.Rethrow();
+ } else {
+ IrBuilder clauseBuilder = catchBuilder.makeDelimitedBuilder();
+ clauseBuilder.declareLocalVariable(catchAll.exceptionVariable,
+ initialValue: exceptionParameter);
+ if (catchAll.stackTraceVariable != null) {
+ clauseBuilder.declareLocalVariable(catchAll.stackTraceVariable,
+ initialValue: traceParameter);
+ }
+ catchAll.buildCatchBlock(clauseBuilder);
+ if (clauseBuilder.isOpen) clauseBuilder.jumpTo(join);
+ catchBody = clauseBuilder._root;
}
- }
- ir.Parameter traceParameter = new ir.Parameter(traceVariable);
- // Expand multiple catch clauses into an explicit if/then/else. Iterate
- // them in reverse so the current block becomes the next else block.
- ir.Expression catchBody;
- if (catchAll == null) {
- catchBody = new ir.Rethrow();
- } else {
- IrBuilder clauseBuilder = catchBuilder.makeDelimitedBuilder();
- clauseBuilder.declareLocalVariable(catchAll.exceptionVariable,
- initialValue: exceptionParameter);
- if (catchAll.stackTraceVariable != null) {
- clauseBuilder.declareLocalVariable(catchAll.stackTraceVariable,
- initialValue: traceParameter);
+ for (CatchClauseInfo clause in catchClauseInfos.reversed) {
+ IrBuilder clauseBuilder = catchBuilder.makeDelimitedBuilder();
+ clauseBuilder.declareLocalVariable(clause.exceptionVariable,
+ initialValue: exceptionParameter);
+ if (clause.stackTraceVariable != null) {
+ clauseBuilder.declareLocalVariable(clause.stackTraceVariable,
+ initialValue: traceParameter);
+ }
+ clause.buildCatchBlock(clauseBuilder);
+ if (clauseBuilder.isOpen) clauseBuilder.jumpTo(join);
+ ir.Continuation thenContinuation = new ir.Continuation([]);
+ thenContinuation.body = clauseBuilder._root;
+ ir.Continuation elseContinuation = new ir.Continuation([]);
+ elseContinuation.body = catchBody;
+
+ // Build the type test guarding this clause. We can share the
+ // environment with the nested builder because this part cannot mutate
+ // it.
+ IrBuilder checkBuilder = catchBuilder.makeDelimitedBuilder(environment);
+ ir.Primitive typeMatches =
+ checkBuilder.buildTypeOperator(exceptionParameter,
+ clause.type,
+ isTypeTest: true);
+ checkBuilder.add(new ir.LetCont.many([thenContinuation,
+ elseContinuation],
+ new ir.Branch(new ir.IsTrue(typeMatches),
+ thenContinuation,
+ elseContinuation)));
+ catchBody = checkBuilder._root;
}
- catchAll.buildCatchBlock(clauseBuilder);
- if (clauseBuilder.isOpen) clauseBuilder.jumpTo(join);
- catchBody = clauseBuilder._root;
- }
- for (CatchClauseInfo clause in catchClauseInfos.reversed) {
- IrBuilder clauseBuilder = catchBuilder.makeDelimitedBuilder();
- clauseBuilder.declareLocalVariable(clause.exceptionVariable,
- initialValue: exceptionParameter);
- if (clause.stackTraceVariable != null) {
- clauseBuilder.declareLocalVariable(clause.stackTraceVariable,
- initialValue: traceParameter);
+
+ List<ir.Parameter> catchParameters =
+ <ir.Parameter>[exceptionParameter, traceParameter];
+ ir.Continuation catchContinuation = new ir.Continuation(catchParameters);
+ catchBuilder.add(catchBody);
+ catchContinuation.body = catchBuilder._root;
+
+ tryCatchBuilder.add(
+ new ir.LetHandler(catchContinuation, tryBuilder._root));
+ add(new ir.LetCont(join.continuation, tryCatchBuilder._root));
+ environment = join.environment;
+ } else {
+ // Try/finally.
+ JumpCollector join = new ForwardJumpCollector(environment);
+ IrBuilder tryFinallyBuilder = makeDelimitedBuilder();
+
+ tryFinallyBuilder.mutableVariables =
+ new Map<Local, ir.MutableVariable>.from(mutableVariables);
+ for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) {
+ assert(!tryFinallyBuilder.isInMutableVariable(variable));
+ ir.Primitive value = tryFinallyBuilder.buildLocalVariableGet(variable);
+ tryFinallyBuilder.makeMutableVariable(variable);
+ tryFinallyBuilder.declareLocalVariable(variable, initialValue: value);
}
- clause.buildCatchBlock(clauseBuilder);
- if (clauseBuilder.isOpen) clauseBuilder.jumpTo(join);
- ir.Continuation thenContinuation = new ir.Continuation([]);
- thenContinuation.body = clauseBuilder._root;
- ir.Continuation elseContinuation = new ir.Continuation([]);
- elseContinuation.body = catchBody;
-
- // Build the type test guarding this clause. We can share the environment
- // with the nested builder because this part cannot mutate it.
- IrBuilder checkBuilder = catchBuilder.makeDelimitedBuilder(environment);
- ir.Primitive typeMatches =
- checkBuilder.buildTypeOperator(exceptionParameter,
- clause.type,
- isTypeTest: true);
- checkBuilder.add(new ir.LetCont.many([thenContinuation, elseContinuation],
- new ir.Branch(new ir.IsTrue(typeMatches),
- thenContinuation,
- elseContinuation)));
- catchBody = checkBuilder._root;
- }
- List<ir.Parameter> catchParameters =
- <ir.Parameter>[exceptionParameter, traceParameter];
- ir.Continuation catchContinuation = new ir.Continuation(catchParameters);
- catchBuilder.add(catchBody);
- catchContinuation.body = catchBuilder._root;
+ IrBuilder tryBuilder = tryFinallyBuilder.makeDelimitedBuilder();
- tryCatchBuilder.add(
- new ir.LetHandler(catchContinuation, tryBuilder._root));
- add(new ir.LetCont(join.continuation, tryCatchBuilder._root));
- environment = join.environment;
+ JumpCollector interceptJump(JumpCollector collector) {
+ JumpCollector result =
+ new ForwardJumpCollector(environment, target: collector.target);
+ result.enterTry(tryStatementInfo.boxedOnEntry);
+ return result;
+ }
+ void restoreJump(JumpCollector collector) {
+ collector.leaveTry();
+ }
+ List<JumpCollector> savedBreaks = tryBuilder.state.breakCollectors;
+ List<JumpCollector> savedContinues = tryBuilder.state.continueCollectors;
+ JumpCollector savedReturn = tryBuilder.state.returnCollector;
+
+ List<JumpCollector> newBreaks = tryBuilder.state.breakCollectors =
+ savedBreaks.map(interceptJump).toList();
+ List<JumpCollector> newContinues = tryBuilder.state.continueCollectors =
+ savedContinues.map(interceptJump).toList();
+ JumpCollector newReturn = tryBuilder.state.returnCollector =
+ new ForwardJumpCollector(environment, hasExtraArgument: true);
+ newReturn.enterTry(tryStatementInfo.boxedOnEntry);
+ buildTryBlock(tryBuilder);
+ if (tryBuilder.isOpen) {
+ // To cover control falling off the end of the try block, the finally
+ // code is translated at the join point. This ensures that it is
+ // correctly outside the scope of the catch handler.
+ join.enterTry(tryStatementInfo.boxedOnEntry);
+ tryBuilder.jumpTo(join);
+ join.leaveTry();
+ }
+ newBreaks.forEach(restoreJump);
+ newContinues.forEach(restoreJump);
+ newReturn.leaveTry();
+ tryBuilder.state.breakCollectors = savedBreaks;
+ tryBuilder.state.continueCollectors = savedContinues;
+ tryBuilder.state.returnCollector = savedReturn;
+
+ IrBuilder catchBuilder = tryFinallyBuilder.makeDelimitedBuilder();
+ for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) {
+ assert(catchBuilder.isInMutableVariable(variable));
+ ir.Primitive value = catchBuilder.buildLocalVariableGet(variable);
+ catchBuilder.removeMutableVariable(variable);
+ catchBuilder.environment.update(variable, value);
+ }
+
+ buildFinallyBlock(catchBuilder);
+ if (catchBuilder.isOpen) {
+ catchBuilder.add(new ir.Rethrow());
+ catchBuilder._current = null;
+ }
+ List<ir.Parameter> catchParameters =
+ <ir.Parameter>[new ir.Parameter(null), new ir.Parameter(null)];
+ ir.Continuation catchContinuation = new ir.Continuation(catchParameters);
+ catchContinuation.body = catchBuilder._root;
+ tryFinallyBuilder.add(
+ new ir.LetHandler(catchContinuation, tryBuilder._root));
+
+ // Build a list of continuations for jumps from the try block and
+ // duplicate the finally code before jumping to the actual target.
+ List<ir.Continuation> exits = <ir.Continuation>[join.continuation];
+ void addJump(JumpCollector newCollector,
+ JumpCollector originalCollector) {
+ if (newCollector.isEmpty) return;
+ IrBuilder builder = makeDelimitedBuilder(newCollector.environment);
+ buildFinallyBlock(builder);
+ if (builder.isOpen) builder.jumpTo(originalCollector);
+ newCollector.continuation.body = builder._root;
+ exits.add(newCollector.continuation);
+ }
+ for (int i = 0; i < newBreaks.length; ++i) {
+ addJump(newBreaks[i], savedBreaks[i]);
+ }
+ for (int i = 0; i < newContinues.length; ++i) {
+ addJump(newContinues[i], savedContinues[i]);
+ }
+ if (!newReturn.isEmpty) {
+ IrBuilder builder = makeDelimitedBuilder(newReturn.environment);
+ ir.Primitive value = builder.environment.discard(1);
+ buildFinallyBlock(builder);
+ if (builder.isOpen) builder.buildReturn(value);
+ newReturn.continuation.body = builder._root;
+ exits.add(newReturn.continuation);
+ }
+ add(new ir.LetCont.many(exits, tryFinallyBuilder._root));
+ environment = join.environment;
+ buildFinallyBlock(this);
+ }
}
/// Create a return statement `return value;` or `return;` if [value] is
@@ -1879,8 +2013,15 @@ abstract class IrBuilder {
if (value == null) {
value = buildNullConstant();
}
- add(new ir.InvokeContinuation(state.returnContinuation, [value]));
- _current = null;
+ if (state.returnCollector == null) {
+ add(new ir.InvokeContinuation(state.returnContinuation, [value]));
+ _current = null;
+ } else {
+ // Inside the try block of try/finally, all returns go to a join-point
+ // continuation that contains the finally code. The return value is
+ // passed as an extra argument.
+ jumpTo(state.returnCollector, value);
+ }
}
/// Create a blocks of [statements] by applying [build] to all reachable
@@ -2037,24 +2178,19 @@ abstract class IrBuilder {
ir.Constant rightTrue = rightTrueBuilder.buildBooleanConstant(true);
ir.Constant rightFalse = rightFalseBuilder.buildBooleanConstant(false);
- // Treat the result values as named values in the environment, so they
- // will be treated as arguments to the join-point continuation.
+ // Result values are passed as continuation arguments, which are
+ // constructed based on environments. These assertions are a sanity check.
assert(environment.length == emptyBuilder.environment.length);
assert(environment.length == rightTrueBuilder.environment.length);
assert(environment.length == rightFalseBuilder.environment.length);
- // Treat the value of the expression as a local variable so it will get
- // a continuation parameter.
- environment.extend(null, null);
- emptyBuilder.environment.extend(null, leftBool);
- rightTrueBuilder.environment.extend(null, rightTrue);
- rightFalseBuilder.environment.extend(null, rightFalse);
// Wire up two continuations for the left subexpression, two continuations
// for the right subexpression, and a three-way join continuation.
- JumpCollector join = new ForwardJumpCollector(environment);
- emptyBuilder.jumpTo(join);
- rightTrueBuilder.jumpTo(join);
- rightFalseBuilder.jumpTo(join);
+ JumpCollector join =
+ new ForwardJumpCollector(environment, hasExtraArgument: true);
+ emptyBuilder.jumpTo(join, leftBool);
+ rightTrueBuilder.jumpTo(join, rightTrue);
+ rightFalseBuilder.jumpTo(join, rightFalse);
ir.Continuation leftTrueContinuation = new ir.Continuation([]);
ir.Continuation leftFalseContinuation = new ir.Continuation([]);
ir.Continuation rightTrueContinuation = new ir.Continuation([]);
@@ -2086,10 +2222,7 @@ abstract class IrBuilder {
leftTrueContinuation,
leftFalseContinuation))));
environment = join.environment;
- environment.discard(1);
- // There is always a join parameter for the result value, because it
- // is different on at least two paths.
- return join.continuation.parameters.last;
+ return environment.discard(1);
}
ir.Primitive buildIdentical(ir.Primitive x, ir.Primitive y) {
@@ -2630,4 +2763,4 @@ class SwitchCaseInfo {
SwitchCaseInfo(this.buildBody);
void addConstant(ir.Primitive constant) => constants.add(constant);
-}
+}
« no previous file with comments | « no previous file | pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698