| OLD | NEW |
| (Empty) |
| 1 library dart2js.cps_ir.loop_effects; | |
| 2 | |
| 3 import '../world.dart'; | |
| 4 import 'cps_ir_nodes.dart'; | |
| 5 import 'effects.dart'; | |
| 6 import 'loop_hierarchy.dart'; | |
| 7 | |
| 8 /// Determines the side effects that may occur in each loop. | |
| 9 class LoopSideEffects extends TrampolineRecursiveVisitor { | |
| 10 LoopHierarchy loopHierarchy; | |
| 11 final World world; | |
| 12 final Map<Continuation, List<Continuation>> exitContinuations = {}; | |
| 13 final Map<Continuation, int> loopSideEffects = {}; | |
| 14 Continuation currentLoopHeader; | |
| 15 | |
| 16 LoopSideEffects(FunctionDefinition node, this.world, {this.loopHierarchy}) { | |
| 17 if (loopHierarchy == null) { | |
| 18 loopHierarchy = new LoopHierarchy(node); | |
| 19 } | |
| 20 visit(node); | |
| 21 } | |
| 22 | |
| 23 /// Returns the accumulated effects and dependencies on all paths from the | |
| 24 /// loop entry to any recursive invocation of the loop. | |
| 25 int getSideEffectsInLoop(Continuation loop) { | |
| 26 return loopSideEffects[loop]; | |
| 27 } | |
| 28 | |
| 29 /// True if the length of an indexable object may change between the loop | |
| 30 /// entry and a recursive invocation of the loop. | |
| 31 bool changesIndexableLength(Continuation loop) { | |
| 32 return loopSideEffects[loop] & Effects.changesIndexableLength != 0; | |
| 33 } | |
| 34 | |
| 35 @override | |
| 36 Expression traverseContinuation(Continuation cont) { | |
| 37 if (cont.isRecursive) { | |
| 38 loopSideEffects[cont] = Effects.none; | |
| 39 exitContinuations[cont] = <Continuation>[]; | |
| 40 pushAction(() { | |
| 41 if (currentLoopHeader != null) { | |
| 42 loopSideEffects[currentLoopHeader] |= loopSideEffects[cont]; | |
| 43 } | |
| 44 exitContinuations[cont].forEach(push); | |
| 45 }); | |
| 46 } | |
| 47 Continuation oldLoopHeader = currentLoopHeader; | |
| 48 currentLoopHeader = loopHierarchy.getLoopHeader(cont); | |
| 49 pushAction(() { | |
| 50 currentLoopHeader = oldLoopHeader; | |
| 51 }); | |
| 52 return cont.body; | |
| 53 } | |
| 54 | |
| 55 @override | |
| 56 Expression traverseLetHandler(LetHandler node) { | |
| 57 enqueueContinuation(node.handler); | |
| 58 return node.body; | |
| 59 } | |
| 60 | |
| 61 @override | |
| 62 Expression traverseLetCont(LetCont node) { | |
| 63 node.continuations.forEach(enqueueContinuation); | |
| 64 return node.body; | |
| 65 } | |
| 66 | |
| 67 @override | |
| 68 Expression traverseLetPrim(LetPrim node) { | |
| 69 if (currentLoopHeader != null) { | |
| 70 loopSideEffects[currentLoopHeader] |= node.primitive.effects; | |
| 71 } | |
| 72 return node.body; | |
| 73 } | |
| 74 | |
| 75 void enqueueContinuation(Continuation cont) { | |
| 76 Continuation loop = loopHierarchy.getEnclosingLoop(cont); | |
| 77 if (loop == currentLoopHeader) { | |
| 78 push(cont); | |
| 79 } else { | |
| 80 // Multiple loops can be exited at once. | |
| 81 // Register as an exit from the outermost loop being exited. | |
| 82 Continuation inner = currentLoopHeader; | |
| 83 Continuation outer = loopHierarchy.getEnclosingLoop(currentLoopHeader); | |
| 84 while (outer != loop) { | |
| 85 if (inner == null) { | |
| 86 // The shrinking reductions pass must run before any pass that relies | |
| 87 // on computing loop side effects. | |
| 88 world.compiler.reporter.internalError( | |
| 89 null, | |
| 90 'Unreachable continuations must be removed before computing ' | |
| 91 'loop side effects.'); | |
| 92 } | |
| 93 inner = outer; | |
| 94 outer = loopHierarchy.getEnclosingLoop(outer); | |
| 95 } | |
| 96 exitContinuations[inner].add(cont); | |
| 97 } | |
| 98 } | |
| 99 } | |
| OLD | NEW |