| Index: pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
|
| diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
|
| index 3181b59be3448c22e0a9d4ccfecf4ca6c5606f53..5d3cb519d2b99e2a7fa4b14d1eb1a670c5344ce5 100644
|
| --- a/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
|
| +++ b/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
|
| @@ -57,6 +57,15 @@ class Builder extends cps_ir.Visitor<Node> {
|
| // is the mapping from continuations to labels.
|
| final Map<cps_ir.Continuation, Label> labels = <cps_ir.Continuation, Label>{};
|
|
|
| + /// A stack of singly-used labels that can be safely inlined at their use
|
| + /// site.
|
| + ///
|
| + /// Code for continuations with exactly one use is inlined at the use site.
|
| + /// This is not safe if the code is moved inside the scope of an exception
|
| + /// handler (i.e., into a try block). We keep a stack of singly-referenced
|
| + /// continuations that are in scope without crossing a binding for a handler.
|
| + List<cps_ir.Continuation> safeForInlining = <cps_ir.Continuation>[];
|
| +
|
| ExecutableElement currentElement;
|
| cps_ir.Continuation returnContinuation;
|
|
|
| @@ -372,12 +381,16 @@ class Builder extends cps_ir.Visitor<Node> {
|
|
|
| Statement visitLetCont(cps_ir.LetCont node) {
|
| // Introduce labels for continuations that need them.
|
| + int safeForInliningLengthOnEntry = safeForInlining.length;
|
| for (cps_ir.Continuation continuation in node.continuations) {
|
| if (continuation.hasMultipleUses) {
|
| labels[continuation] = new Label();
|
| + } else {
|
| + safeForInlining.add(continuation);
|
| }
|
| }
|
| Statement body = visit(node.body);
|
| + safeForInlining.length = safeForInliningLengthOnEntry;
|
| // Continuations are bound at the same level, but they have to be
|
| // translated as if nested. This is because the body can invoke any
|
| // of them from anywhere, so it must be nested inside all of them.
|
| @@ -401,6 +414,17 @@ class Builder extends cps_ir.Visitor<Node> {
|
| return current;
|
| }
|
|
|
| + Statement visitLetHandler(cps_ir.LetHandler node) {
|
| + List<cps_ir.Continuation> saved = safeForInlining;
|
| + safeForInlining = <cps_ir.Continuation>[];
|
| + Statement tryBody = visit(node.body);
|
| + safeForInlining = saved;
|
| + List<Variable> catchParameters =
|
| + node.handler.parameters.map(getVariable).toList();
|
| + Statement catchBody = visit(node.handler.body);
|
| + return new Try(tryBody, catchParameters, catchBody);
|
| + }
|
| +
|
| Statement visitInvokeStatic(cps_ir.InvokeStatic node) {
|
| // Calls are translated to direct style.
|
| List<Expression> arguments = translateArguments(node.arguments);
|
| @@ -509,9 +533,13 @@ class Builder extends cps_ir.Visitor<Node> {
|
| ? new Continue(labels[cont])
|
| : new WhileTrue(labels[cont], visit(cont.body));
|
| } else {
|
| - return cont.hasExactlyOneUse
|
| - ? visit(cont.body)
|
| - : new Break(labels[cont]);
|
| + if (cont.hasExactlyOneUse) {
|
| + if (safeForInlining.contains(cont)) {
|
| + return visit(cont.body);
|
| + }
|
| + labels[cont] = new Label();
|
| + }
|
| + return new Break(labels[cont]);
|
| }
|
| });
|
| }
|
|
|