| Index: pkg/compiler/lib/src/ssa/optimize.dart | 
| diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart | 
| index bcce27c42180e6c42e97b63c02b7a7559ba78023..d872aec0e47305ae4f8590e1b5c7361c4db4580c 100644 | 
| --- a/pkg/compiler/lib/src/ssa/optimize.dart | 
| +++ b/pkg/compiler/lib/src/ssa/optimize.dart | 
| @@ -63,7 +63,7 @@ class SsaOptimizerTask extends CompilerTask { | 
| void runPhase(OptimizationPhase phase) { | 
| measureSubtask(phase.name, () => phase.visitGraph(graph)); | 
| _backend.tracer.traceGraph(phase.name, graph); | 
| -      assert(graph.isValid()); | 
| +      assert(graph.isValid(), 'Graph not valid after ${phase.name}'); | 
| } | 
|  | 
| bool trustPrimitives = _options.trustPrimitives; | 
| @@ -733,10 +733,29 @@ class SsaInstructionSimplifier extends HBaseVisitor | 
|  | 
| void simplifyCondition( | 
| HBasicBlock block, HInstruction condition, bool value) { | 
| -    condition.dominatedUsers(block.first).forEach((user) { | 
| -      HInstruction newCondition = _graph.addConstantBool(value, _closedWorld); | 
| -      user.changeUse(condition, newCondition); | 
| -    }); | 
| +    // `excludePhiOutEdges: true` prevents replacing a partially dominated phi | 
| +    // node input with a constant. This tends to add unnecessary assignments, by | 
| +    // transforming the following, which has phi(false, x), | 
| +    // | 
| +    //    if (x) { init(); x = false; } | 
| +    // | 
| +    // into this, which has phi(false, false) | 
| +    // | 
| +    //    if (x) { init(); x = false; } else { x = false; } | 
| +    // | 
| +    // which is further simplifed to: | 
| +    // | 
| +    //    if (x) { init(); } | 
| +    //    ... | 
| +    //    x = false; | 
| +    // | 
| +    // This is mostly harmless (if a little confusing) but does cause a lot of | 
| +    // `x = false;` copies to be inserted when a loop body has many continue | 
| +    // statements or ends with a switch. | 
| +    var uses = | 
| +        DominatedUses.of(condition, block.first, excludePhiOutEdges: true); | 
| +    if (uses.isEmpty) return; | 
| +    uses.replaceWith(_graph.addConstantBool(value, _closedWorld)); | 
| } | 
|  | 
| HInstruction visitIf(HIf node) { | 
| @@ -1622,6 +1641,10 @@ class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase { | 
| } | 
| // Run through the phis of the block and replace them with their input | 
| // that comes from the only live predecessor if that dominates the phi. | 
| +      // | 
| +      // TODO(sra): If the input is directly in the only live predecessor, it | 
| +      // might be possible to move it into [block] (e.g. all its inputs are | 
| +      // dominating.) | 
| block.forEachPhi((HPhi phi) { | 
| HInstruction replacement = | 
| (indexOfLive >= 0) ? phi.inputs[indexOfLive] : zapInstruction; | 
| @@ -2170,14 +2193,12 @@ class SsaTypeConversionInserter extends HBaseVisitor | 
| // non-movable. | 
| void insertTypePropagationForDominatedUsers( | 
| HBasicBlock dominator, HInstruction input, TypeMask convertedType) { | 
| -    Setlet<HInstruction> dominatedUsers = input.dominatedUsers(dominator.first); | 
| -    if (dominatedUsers.isEmpty) return; | 
| +    DominatedUses dominatedUses = DominatedUses.of(input, dominator.first); | 
| +    if (dominatedUses.isEmpty) return; | 
|  | 
| HTypeKnown newInput = new HTypeKnown.pinned(convertedType, input); | 
| dominator.addBefore(dominator.first, newInput); | 
| -    dominatedUsers.forEach((HInstruction user) { | 
| -      user.changeUse(input, newInput); | 
| -    }); | 
| +    dominatedUses.replaceWith(newInput); | 
| } | 
|  | 
| void visitIs(HIs instruction) { | 
|  |