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

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

Issue 923013002: dart2dart: Implementation of simple try/catch. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 10 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
Index: pkg/compiler/lib/src/cps_ir/cps_ir_builder_visitor.dart
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_visitor.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_visitor.dart
index ea7bf3a1fe80c63bc88acd16a83908be7d0c4354..95030b63f4262584433946b16f7591d724965d90 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_visitor.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_visitor.dart
@@ -451,6 +451,147 @@ abstract class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
return null;
}
+ ir.Primitive visitTryStatement(ast.TryStatement node) {
+ assert(this.irBuilder.isOpen);
+ // Try/catch is not yet implemented in the JS backend.
+ if (this.irBuilder.tryStatements == null) {
+ return giveup(node, 'try/catch in the JS backend');
+ }
+ // Multiple catch blocks are not yet implemented.
+ if (node.catchBlocks.isEmpty ||
+ node.catchBlocks.nodes.tail == null) {
+ return giveup(node, 'not exactly one catch block');
+ }
+ // 'on T' catch blocks are not yet implemented.
+ if ((node.catchBlocks.nodes.head as ast.CatchBlock).onKeyword != null) {
+ return giveup(node, '"on T" catch block');
+ }
+ // Finally blocks are not yet implemented.
+ if (node.finallyBlock != null) {
+ return giveup(node, 'try/finally');
+ }
+
+ // Catch handlers are in scope for their body. The CPS translation of
+ // [[try tryBlock catch (e) catchBlock; successor]] is:
+ //
+ // let cont join(v0, v1, ...) = [[successor]] in
+ // let mutable m0 = x0 in
+ // let mutable m1 = x1 in
+ // ...
+ // let handler catch_(e) =
+ // let prim p0 = GetMutable(m0) in
+ // let prim p1 = GetMutable(m1) in
+ // ...
+ // [[catchBlock]]
+ // join(p0, p1, ...)
+ // in
+ // [[tryBlock]]
+ // let prim p0' = GetMutable(m0) in
+ // let prim p1' = GetMutable(m1) in
+ // ...
+ // join(p0', p1', ...)
+ //
+ // In other words, both the try and catch block are in the scope of the
+ // join-point continuation, and they are both in the scope of a sequence
+ // of mutable bindings for the variables assigned in the try. The join-
+ // point continuation is not in the scope of these mutable bindings.
+ // The tryBlock is in the scope of a binding for the catch handler. Each
+ // instruction (specifically, each call) in the tryBlock is in the dynamic
+ // 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 th
floitsch 2015/02/16 14:54:07 the
+ // variables are unboxed in the catch block and at the join point.
floitsch 2015/02/16 14:54:07 I guess they are also unboxed before calls to "con
Kevin Millikin (Google) 2015/02/24 11:59:25 It does require an update to the comment, and a fi
+
+ IrBuilder tryCatchBuilder = irBuilder.makeDelimitedBuilder();
+ TryStatementInfo tryInfo = tryCatchBuilder.tryStatements[node];
+ // Variables that are boxed due to being captured in a closure are boxed
+ // for their entire lifetime, and so they do not need to be boxed on entry
+ // to any try block. They are only removed here because we cannot
+ // identify all of them in the same pass where we identify the variables
+ // assigned in the try (the may be captured by a closure after the try
+ // statement).
+ tryInfo.boxedOnEntry.removeAll(tryCatchBuilder.mutableCapturedVariables);
floitsch 2015/02/16 14:54:07 I'm not a fan of these kind of side-effects in a b
Kevin Millikin (Google) 2015/02/24 11:59:25 Hmmm. The other approach that we use a lot is to
+ for (LocalVariableElement variable in tryInfo.boxedOnEntry) {
+ assert(!tryCatchBuilder.isInMutableVariable(variable));
+ ir.Primitive value = tryCatchBuilder.buildLocalGet(variable);
+ tryCatchBuilder.makeMutableVariable(variable);
+ tryCatchBuilder.declareLocalVariable(variable, initialValue: value);
+ }
+
+ IrBuilder catchBuilder = tryCatchBuilder.makeDelimitedBuilder();
+ IrBuilder tryBuilder = tryCatchBuilder.makeDelimitedBuilder();
+ List<ir.Parameter> joinParameters =
+ new List<ir.Parameter>.generate(irBuilder.environment.length, (i) {
+ return new ir.Parameter(irBuilder.environment.index2variable[i]);
+ });
+ ir.Continuation joinContinuation = new ir.Continuation(joinParameters);
+ withBuilder(tryBuilder, () {
+ visit(node.tryBlock);
+ });
+ if (tryBuilder.isOpen) {
+ for (LocalVariableElement variable in tryInfo.boxedOnEntry) {
+ assert(tryBuilder.isInMutableVariable(variable));
+ ir.Primitive value = tryBuilder.buildLocalGet(variable);
+ tryBuilder.environment.update(variable, value);
+ }
+ assert(tryBuilder.environment.length >= irBuilder.environment.length);
+ ir.InvokeContinuation jump = new ir.InvokeContinuation.uninitialized();
+ jump.continuation = new ir.Reference(joinContinuation);
+ jump.arguments = new List<ir.Reference>.generate(
+ irBuilder.environment.length, (i) {
+ return new ir.Reference(tryBuilder.environment[i]);
+ });
+ tryBuilder.add(jump);
+ tryBuilder._current = null;
asgerf 2015/02/20 10:10:07 Would it make sense to extract these 8 lines into
Kevin Millikin (Google) 2015/02/24 11:59:25 Yes. It also occurs when breaking from a labeled
+ }
+
+ for (LocalVariableElement variable in tryInfo.boxedOnEntry) {
+ assert(catchBuilder.isInMutableVariable(variable));
+ ir.Primitive value = catchBuilder.buildLocalGet(variable);
+ // Note that we remove the variable from the set of mutable variables
+ // here (and not above for the try body). This is because the set of
+ // mutable variables is global for the whole function and not local to
+ // a delimited builder.
+ catchBuilder.removeMutableVariable(variable);
+ catchBuilder.environment.update(variable, value);
+ }
+ ast.CatchBlock catchClause = node.catchBlocks.nodes.head;
+ assert(catchClause.exception != null);
+ List<ir.Parameter> catchParameters =
+ <ir.Parameter>[new ir.Parameter(elements[catchClause.exception])];
+ catchBuilder.environment.extend(elements[catchClause.exception] as Local,
karlklose 2015/02/16 10:15:48 Why do you cast to Local here and below?
Kevin Millikin (Google) 2015/02/24 11:59:25 Otherwise the editor reports "The argument type 'E
+ catchParameters[0]);
+ if (catchClause.trace != null) {
+ catchParameters.add(new ir.Parameter(elements[catchClause.trace]));
+ catchBuilder.environment.extend(elements[catchClause.trace] as Local,
+ catchParameters[1]);
+ }
+ withBuilder(catchBuilder, () {
+ visit(catchClause.block);
+ });
+ if (catchBuilder.isOpen) {
+ assert(catchBuilder.environment.length >= irBuilder.environment.length);
+ ir.InvokeContinuation jump = new ir.InvokeContinuation.uninitialized();
+ jump.continuation = new ir.Reference(joinContinuation);
+ jump.arguments = new List<ir.Reference>.generate(
+ irBuilder.environment.length, (i) {
+ return new ir.Reference(catchBuilder.environment[i]);
+ });
+ catchBuilder.add(jump);
+ catchBuilder._current = null;
+ }
+ ir.Continuation catchContinuation = new ir.Continuation(catchParameters);
+ catchContinuation.body = catchBuilder._root;
+
+ tryCatchBuilder.add(new ir.LetHandler(catchContinuation, tryBuilder._root));
+ tryCatchBuilder._current = null;
+
+ irBuilder.add(new ir.LetCont(joinContinuation, tryCatchBuilder._root));
+ for (int i = 0; i < irBuilder.environment.length; ++i) {
+ irBuilder.environment.index2value[i] = joinParameters[i];
+ }
+ return null;
+ }
+
// ==== Expressions ====
ir.Primitive visitConditional(ast.Conditional node) {
return irBuilder.buildConditional(
@@ -960,8 +1101,7 @@ dynamic giveup(ast.Node node, [String reason]) {
/// sees a feature that is currently unsupport by that builder. In particular,
/// loop variables captured in a for-loop initializer, condition, or update
/// expression are unsupported.
-class DartCapturedVariables extends ast.Visitor
- implements DartCapturedVariableInfo {
+class DartCapturedVariables extends ast.Visitor {
final TreeElements elements;
DartCapturedVariables(this.elements);
@@ -969,6 +1109,12 @@ class DartCapturedVariables extends ast.Visitor
bool insideInitializer = false;
Set<Local> capturedVariables = new Set<Local>();
+ Map<ast.TryStatement, TryStatementInfo> tryStatements =
+ <ast.TryStatement, TryStatementInfo>{};
+
+ TryStatementInfo currentTryInfo;
+ bool get inTryStatement => currentTryInfo != null;
+
void markAsCaptured(Local local) {
capturedVariables.add(local);
}
@@ -1016,18 +1162,28 @@ class DartCapturedVariables extends ast.Visitor
visitSendSet(ast.SendSet node) {
handleSend(node);
Element element = elements[node];
- // Initializers in an initializer-list can communicate via parameters.
- // If a parameter is stored in an initializer list we box it.
- if (insideInitializer &&
- Elements.isLocal(element) &&
- element.isParameter) {
+ if (Elements.isLocal(element)) {
LocalElement local = element;
- // TODO(sigurdm): Fix this.
- // Though these variables do not outlive the activation of the function,
- // they still need to be boxed. As a simplification, we treat them as if
- // they are captured by a closure (i.e., they do outlive the activation of
- // the function).
- markAsCaptured(local);
+ if (insideInitializer) {
+ assert(local.isParameter);
+ // Initializers in an initializer-list can communicate via parameters.
+ // If a parameter is stored in an initializer list we box it.
+ // TODO(sigurdm): Fix this.
+ // Though these variables do not outlive the activation of the
+ // function, they still need to be boxed. As a simplification, we
+ // treat them as if they are captured by a closure (i.e., they do
+ // outlive the activation of the function).
+ markAsCaptured(local);
+ } else if (inTryStatement) {
+ assert(local.isParameter || local.isVariable);
+ if (!currentTryInfo.declared.contains(local)) {
+ // If a variable is assigned in a try and not declared in that try
+ // then it has to be boxed on entry to the try.
+ // Later we will remove such variables that will be boxed in an
+ // enclosing try.
+ currentTryInfo.boxedOnEntry.add(local);
+ }
+ }
}
node.visitChildren(this);
}
@@ -1046,6 +1202,35 @@ class DartCapturedVariables extends ast.Visitor
visit(node.body);
currentFunction = oldFunction;
}
+
+ visitTryStatement(ast.TryStatement node) {
+ TryStatementInfo outer = currentTryInfo;
+ tryStatements[node] = currentTryInfo = new TryStatementInfo(outer);
+ visit(node.tryBlock);
+ if (outer == null) {
+ // For each top-level try, compute the variables boxed on entry to it
+ // and each nested try in a top-down manner.
+ currentTryInfo.computeVariablesBoxedOnEntry(null);
+ }
+ currentTryInfo = outer;
+
+ visit(node.catchBlocks);
+ if (node.finallyBlock != null) visit(node.finallyBlock);
+ }
+
+ visitVariableDefinitions(ast.VariableDefinitions node) {
+ if (inTryStatement) {
+ for (ast.Node definition in node.definitions.nodes) {
+ LocalVariableElement local = elements[definition];
+ assert(local != null);
+ // In the closure conversion pass we check for isInitializingFormal,
+ // but I'm not sure it can arise.
+ assert(!local.isInitializingFormal);
+ currentTryInfo.declared.add(local);
+ }
+ }
+ node.visitChildren(this);
+ }
}
/// IR builder specific to the Dart backend, coupled to the [DartIrBuilder].

Powered by Google App Engine
This is Rietveld 408576698