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

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: Fixed break/continue, incorporated comments. 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 492f1170833e9b4ae229a06f4d029581b42209d9..6cdec14b9abd7096ef4cddb4c1b865b65fdb8e32 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,152 @@ 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 the
+ // variables are unboxed in the catch block and at the join point.
+
+ 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. We check for them here because we can not
+ // 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).
+ Iterable<LocalVariableElement> boxedOnEntry =
+ tryInfo.boxedOnEntry.where((LocalVariableElement variable) {
+ return !tryCatchBuilder.mutableCapturedVariables.contains(variable);
+ });
+ for (LocalVariableElement variable in 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);
+
+ void interceptJumps(JumpCollector collector) {
+ collector.enterTry(boxedOnEntry);
+ }
+ void restoreJumps(JumpCollector collector) {
+ collector.leaveTry();
+ }
+ tryBuilder.state.breakCollectors.forEach(interceptJumps);
+ tryBuilder.state.continueCollectors.forEach(interceptJumps);
+ withBuilder(tryBuilder, () {
+ visit(node.tryBlock);
+ });
+ tryBuilder.state.breakCollectors.forEach(restoreJumps);
+ tryBuilder.state.continueCollectors.forEach(restoreJumps);
+ if (tryBuilder.isOpen) {
+ for (LocalVariableElement variable in boxedOnEntry) {
+ assert(tryBuilder.isInMutableVariable(variable));
+ ir.Primitive value = tryBuilder.buildLocalGet(variable);
+ tryBuilder.environment.update(variable, value);
+ }
+ tryBuilder.jumpTo(joinContinuation);
+ }
+
+ for (LocalVariableElement variable in 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);
+ LocalVariableElement exceptionElement = elements[catchClause.exception];
+ ir.Parameter exceptionParameter = new ir.Parameter(exceptionElement);
+ catchBuilder.environment.extend(exceptionElement, exceptionParameter);
+ ir.Parameter traceParameter;
+ if (catchClause.trace != null) {
+ LocalVariableElement traceElement = elements[catchClause.trace];
+ traceParameter = new ir.Parameter(traceElement);
+ catchBuilder.environment.extend(traceElement, traceParameter);
+ } else {
+ // Use a dummy continuation parameter for the stack trace parameter.
+ // This will ensure that all handlers have two parameters and so they
+ // can be treated uniformly.
+ traceParameter = new ir.Parameter(null);
+ }
+ withBuilder(catchBuilder, () {
+ visit(catchClause.block);
+ });
+ if (catchBuilder.isOpen) {
+ catchBuilder.jumpTo(joinContinuation);
+ }
+ List<ir.Parameter> catchParameters =
+ <ir.Parameter>[exceptionParameter, traceParameter];
+ 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(
@@ -984,8 +1130,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);
@@ -993,6 +1138,12 @@ class DartCapturedVariables extends ast.Visitor
bool insideInitializer = false;
Set<Local> capturedVariables = new Set<Local>();
+ Map<ast.TryStatement, TryStatementInfo> tryStatements =
+ <ast.TryStatement, TryStatementInfo>{};
+
+ List<TryStatementInfo> tryNestingStack = <TryStatementInfo>[];
+ bool get inTryStatement => tryNestingStack.isNotEmpty;
+
void markAsCaptured(Local local) {
capturedVariables.add(local);
}
@@ -1040,18 +1191,32 @@ 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);
+ // Search for the position of the try block containing the variable
+ // declaration, or -1 if it is declared outside the outermost try.
+ int i = tryNestingStack.length - 1;
+ while (i >= 0 && !tryNestingStack[i].declared.contains(local)) {
+ --i;
+ }
+ // If there is a next inner try, then the variable should be boxed on
+ // entry to it.
+ if (i + 1 < tryNestingStack.length) {
+ tryNestingStack[i + 1].boxedOnEntry.add(local);
+ }
+ }
}
node.visitChildren(this);
}
@@ -1070,6 +1235,32 @@ class DartCapturedVariables extends ast.Visitor
visit(node.body);
currentFunction = oldFunction;
}
+
+ visitTryStatement(ast.TryStatement node) {
+ TryStatementInfo info = new TryStatementInfo();
+ tryStatements[node] = info;
+ tryNestingStack.add(info);
+ visit(node.tryBlock);
+ assert(tryNestingStack.last == info);
+ tryNestingStack.removeLast();
+
+ 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);
+ tryNestingStack.last.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