| Index: pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart | 
| diff --git a/pkg/compiler/lib/src/cps_ir/let_sinking.dart b/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart | 
| similarity index 60% | 
| copy from pkg/compiler/lib/src/cps_ir/let_sinking.dart | 
| copy to pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart | 
| index 4c4736a967efe944fc6ed9b57193414213f33894..fc639442a227812c311a8ddefdb2cca163151edf 100644 | 
| --- a/pkg/compiler/lib/src/cps_ir/let_sinking.dart | 
| +++ b/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart | 
| @@ -2,119 +2,9 @@ | 
| // for details. All rights reserved. Use of this source code is governed by a | 
| // BSD-style license that can be found in the LICENSE file. | 
|  | 
| -library dart2js.cps_ir.let_sinking; | 
| +library dart2js.cps_ir.loop_hierarchy; | 
|  | 
| import 'cps_ir_nodes.dart'; | 
| -import 'optimizers.dart'; | 
| - | 
| -/// Sinks single-use primitives to the use when this is safe and profitable. | 
| -/// | 
| -/// To avoid sinking non-constant primitives into loops, this pass performs a | 
| -/// control-flow analysis to determine the effective nesting of loops. | 
| -/// | 
| -/// In the example below, the value 'p' can be sunk to its use site in the | 
| -/// 'else' branch because that branch is not effectively part of a loop, | 
| -/// despite being lexically nested in a recursive continuation. | 
| -/// | 
| -///   let prim p = getInterceptor(<something>) | 
| -///   let rec kont x = | 
| -///     if (<loop condition>) | 
| -///       <loop body> | 
| -///       InvokeContinuation kont x' | 
| -///     else | 
| -///       <after loop> | 
| -///       return p.foo() | 
| -/// | 
| -class LetSinker extends RecursiveVisitor implements Pass { | 
| -  String get passName => 'Let sinking'; | 
| - | 
| -  LoopHierarchy loopHierarchy; | 
| -  List<Continuation> stack = <Continuation>[]; | 
| - | 
| -  /// Maps a sinkable primitive to its loop header. | 
| -  Map<Primitive, Continuation> loopHeaderForPrimitive = | 
| -      <Primitive, Continuation>{}; | 
| - | 
| -  Continuation currentLoopHeader; | 
| - | 
| -  void rewrite(FunctionDefinition node) { | 
| -    new ParentVisitor().visit(node); | 
| -    loopHierarchy = new LoopHierarchy(node); | 
| -    visit(node.body); | 
| -  } | 
| - | 
| -  @override | 
| -  Expression traverseLetPrim(LetPrim node) { | 
| -    Primitive prim = node.primitive; | 
| -    if (prim.hasExactlyOneUse && prim.isSafeForReordering) { | 
| -      // This can potentially be sunk. Register the loop header, so when we | 
| -      // find the use site, we can check if they are in the same loop. | 
| -      loopHeaderForPrimitive[prim] = currentLoopHeader; | 
| -      pushAction(() { | 
| -        if (node.primitive != null) { | 
| -          // The primitive could not be sunk. Try to sink dependencies here. | 
| -          visit(node.primitive); | 
| -        } else { | 
| -          // The primitive was sunk. Destroy the old LetPrim. | 
| -          InteriorNode parent = node.parent; | 
| -          parent.body = node.body; | 
| -          node.body.parent = parent; | 
| -        } | 
| -      }); | 
| -    } else { | 
| -      visit(node.primitive); | 
| -    } | 
| - | 
| -    // Visit the body, wherein this primitive may be sunk to its use site. | 
| -    return node.body; | 
| -  } | 
| - | 
| -  @override | 
| -  Expression traverseContinuation(Continuation cont) { | 
| -    Continuation oldLoopHeader = currentLoopHeader; | 
| -    pushAction(() { | 
| -      currentLoopHeader = oldLoopHeader; | 
| -    }); | 
| -    currentLoopHeader = loopHierarchy.getLoopHeader(cont); | 
| -    return cont.body; | 
| -  } | 
| - | 
| -  void processReference(Reference ref) { | 
| -    Definition definition = ref.definition; | 
| -    if (definition is Primitive && | 
| -        definition is! Parameter && | 
| -        definition.hasExactlyOneUse && | 
| -        definition.isSafeForReordering) { | 
| -      // Check if use is in the same loop. | 
| -      Continuation bindingLoop = loopHeaderForPrimitive.remove(definition); | 
| -      if (bindingLoop == currentLoopHeader || definition is Constant) { | 
| -        // Sink the definition. | 
| - | 
| -        Expression use = getEnclosingExpression(ref.parent); | 
| -        LetPrim binding = definition.parent; | 
| -        binding.primitive = null;  // Mark old binding for deletion. | 
| -        LetPrim newBinding = new LetPrim(definition); | 
| -        definition.parent = newBinding; | 
| -        InteriorNode useParent = use.parent; | 
| -        useParent.body = newBinding; | 
| -        newBinding.body = use; | 
| -        use.parent = newBinding; | 
| -        newBinding.parent = useParent; | 
| - | 
| -        // Now that the final binding location has been found, sink the | 
| -        // dependencies of the definition down here as well. | 
| -        visit(definition); | 
| -      } | 
| -    } | 
| -  } | 
| - | 
| -  Expression getEnclosingExpression(Node node) { | 
| -    while (node is! Expression) { | 
| -      node = node.parent; | 
| -    } | 
| -    return node; | 
| -  } | 
| -} | 
|  | 
| /// Determines the effective nesting of loops. | 
| /// | 
| @@ -157,6 +47,12 @@ class LoopHierarchy { | 
| return cont.isRecursive ? cont : loopTarget[cont]; | 
| } | 
|  | 
| +  /// Returns the innermost loop which the given loop is part of, other | 
| +  /// than itself. | 
| +  Continuation getEnclosingLoop(Continuation loop) { | 
| +    return loopTarget[loop]; | 
| +  } | 
| + | 
| /// Marks the innermost loop as a subloop of the other loop. | 
| /// | 
| /// Returns the innermost loop. | 
|  |