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

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: Run all the finally blocks. 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 d411ee447d6c30eb897f48d287c059f2754ca35b..416279c8443a95db5dfc61c75e148f9ec3cd2921 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
@@ -131,6 +131,11 @@ abstract class JumpCollector {
final List<Iterable<LocalVariableElement>> _boxedTryVariables =
<Iterable<LocalVariableElement>>[];
+ /// A stack of all the enclosing finally blocks up to the target of the jump.
+ ///
+ /// There are null entries which correspond to try/catch (no finally).
+ final List<SubbuildFunction> _finallyBlocks = <SubbuildFunction>[];
+
JumpCollector(this._continuationEnvironment, this.target);
/// True if the collector has not recorded any jumps to its continuation.
@@ -152,9 +157,11 @@ abstract class JumpCollector {
/// variables that were boxed on entry before invoking the target
/// continuation. Call this function before translating a try block and
/// call [leaveTry] after translating it.
- void enterTry(Iterable<LocalVariableElement> boxedOnEntry) {
+ void enterTry(Iterable<LocalVariableElement> boxedOnEntry,
+ [SubbuildFunction buildFinallyBlock]) {
// The boxed variables are maintained as a stack to make leaving easy.
_boxedTryVariables.add(boxedOnEntry);
+ _finallyBlocks.add(buildFinallyBlock);
}
/// Remove the most recently added set of variables boxed on entry to a try
@@ -164,6 +171,7 @@ abstract class JumpCollector {
/// after translating it.
void leaveTry() {
_boxedTryVariables.removeLast();
+ _finallyBlocks.removeLast();
}
void _buildTryExit(IrBuilder builder) {
@@ -174,6 +182,9 @@ abstract class JumpCollector {
builder.environment.update(variable, value);
}
}
+ for (SubbuildFunction buildFinallyBlock in _finallyBlocks.reversed) {
+ if (buildFinallyBlock != null) buildFinallyBlock(builder);
+ }
}
}
@@ -399,6 +410,9 @@ class IrBuilderSharedState {
/// A stack of collectors for continues.
final List<JumpCollector> continueCollectors = <JumpCollector>[];
+ /// A stack of enclosing finally blocks, used when translating return.
+ final List<SubbuildFunction> finallyBlocks = <SubbuildFunction>[];
+
final List<ConstDeclaration> localConstants = <ConstDeclaration>[];
final ExecutableElement currentElement;
@@ -1731,6 +1745,7 @@ abstract class IrBuilder {
{TryStatementInfo tryStatementInfo,
SubbuildFunction buildTryBlock,
List<CatchClauseInfo> catchClauseInfos: const <CatchClauseInfo>[],
+ SubbuildFunction buildFinallyBlock,
ClosureClassMap closureClassMap}) {
assert(isOpen);
@@ -1763,125 +1778,189 @@ 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);
Kevin Millikin (Google) 2015/06/22 15:36:42 This is the code for try/catch. It is unchanged e
+ 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.
Kevin Millikin (Google) 2015/06/22 15:36:42 This is the code for try/finally. There is a lot
+ 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;
+ void interceptJump(JumpCollector collector) {
+ collector.enterTry(tryStatementInfo.boxedOnEntry, buildFinallyBlock);
+ }
+ void restoreJump(JumpCollector collector) {
+ collector.leaveTry();
+ }
+ tryBuilder.state.breakCollectors.forEach(interceptJump);
+ tryBuilder.state.continueCollectors.forEach(interceptJump);
+ tryBuilder.state.finallyBlocks.add(buildFinallyBlock);
+ 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();
+ }
+ tryBuilder.state.breakCollectors.forEach(restoreJump);
+ tryBuilder.state.continueCollectors.forEach(restoreJump);
+ tryBuilder.state.finallyBlocks.removeLast();
+
+ 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));
+ add(new ir.LetCont(join.continuation, tryFinallyBuilder._root));
+ environment = join.environment;
+ buildFinallyBlock(this);
+ }
}
/// Create a return statement `return value;` or `return;` if [value] is
@@ -1895,8 +1974,14 @@ abstract class IrBuilder {
if (value == null) {
value = buildNullConstant();
}
- add(new ir.InvokeContinuation(state.returnContinuation, [value]));
- _current = null;
+ for (SubbuildFunction buildFinallyBlock in state.finallyBlocks.reversed) {
+ buildFinallyBlock(this);
+ if (!isOpen) break;
+ }
+ if (isOpen) {
+ add(new ir.InvokeContinuation(state.returnContinuation, [value]));
+ _current = null;
+ }
}
/// Create a blocks of [statements] by applying [build] to all reachable
@@ -2636,4 +2721,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