| 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 5c8313bdace0c090f944f4babfe2479ebc0ff5b5..45aa779f74af8d91ad87ae9daa9ceb2793880105 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
|
| @@ -453,8 +453,7 @@ abstract class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
|
| return null;
|
| }
|
|
|
| - ir.Primitive visitTryStatement(ast.TryStatement node) {
|
| - assert(this.irBuilder.isOpen);
|
| + visitTryStatement(ast.TryStatement node) {
|
| // Try/catch is not yet implemented in the JS backend.
|
| if (this.irBuilder.tryStatements == null) {
|
| return giveup(node, 'try/catch in the JS backend');
|
| @@ -473,130 +472,24 @@ abstract class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
|
| 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);
|
| + List<CatchClauseInfo> catchClauseInfos = <CatchClauseInfo>[];
|
| + for (ast.CatchBlock catchClause in node.catchBlocks.nodes) {
|
| + assert(catchClause.exception != null);
|
| + LocalVariableElement exceptionVariable = elements[catchClause.exception];
|
| + LocalVariableElement stackTraceVariable;
|
| + if (catchClause.trace != null) {
|
| + stackTraceVariable = elements[catchClause.trace];
|
| }
|
| - tryBuilder.jumpTo(joinContinuation);
|
| + catchClauseInfos.add(new CatchClauseInfo(
|
| + exceptionVariable: exceptionVariable,
|
| + stackTraceVariable: stackTraceVariable,
|
| + buildCatchBlock: subbuild(catchClause.block)));
|
| }
|
|
|
| - 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;
|
| + irBuilder.buildTry(
|
| + tryStatementInfo: irBuilder.tryStatements[node],
|
| + buildTryBlock: subbuild(node.tryBlock),
|
| + catchClauseInfos: catchClauseInfos);
|
| }
|
|
|
| // ==== Expressions ====
|
|
|