| OLD | NEW |
| 1 library dart2js.cps_ir.loop_effects; | 1 library dart2js.cps_ir.loop_effects; |
| 2 | 2 |
| 3 import 'cps_ir_nodes.dart'; | 3 import 'cps_ir_nodes.dart'; |
| 4 import 'loop_hierarchy.dart'; | 4 import 'loop_hierarchy.dart'; |
| 5 import '../universe/side_effects.dart'; | |
| 6 import '../elements/elements.dart'; | |
| 7 import '../world.dart'; | 5 import '../world.dart'; |
| 6 import 'effects.dart'; |
| 8 | 7 |
| 9 /// Determines which the [SideEffects] that may occur during each loop in | 8 /// Determines the side effects that may occur in each loop. |
| 10 /// a given function, in addition to whether the loop may change the length | |
| 11 /// of an indexable object. | |
| 12 /// | |
| 13 /// TODO(asgerf): Make length a flag on [SideEffects] for better precision and | |
| 14 /// so we don't need to special case the length in this class. | |
| 15 class LoopSideEffects extends TrampolineRecursiveVisitor { | 9 class LoopSideEffects extends TrampolineRecursiveVisitor { |
| 16 LoopHierarchy loopHierarchy; | 10 LoopHierarchy loopHierarchy; |
| 17 final World world; | 11 final World world; |
| 18 final Map<Continuation, List<Continuation>> exitContinuations = {}; | 12 final Map<Continuation, List<Continuation>> exitContinuations = {}; |
| 19 final Map<Continuation, SideEffects> loopSideEffects = {}; | 13 final Map<Continuation, int> loopSideEffects = {}; |
| 20 final Set<Continuation> loopsChangingLength = new Set<Continuation>(); | |
| 21 Continuation currentLoopHeader; | 14 Continuation currentLoopHeader; |
| 22 SideEffects currentLoopSideEffects = new SideEffects.empty(); | |
| 23 bool currentLoopChangesLength = false; | |
| 24 | 15 |
| 25 LoopSideEffects(FunctionDefinition node, this.world, {this.loopHierarchy}) { | 16 LoopSideEffects(FunctionDefinition node, this.world, {this.loopHierarchy}) { |
| 26 if (loopHierarchy == null) { | 17 if (loopHierarchy == null) { |
| 27 loopHierarchy = new LoopHierarchy(node); | 18 loopHierarchy = new LoopHierarchy(node); |
| 28 } | 19 } |
| 29 visit(node); | 20 visit(node); |
| 30 } | 21 } |
| 31 | 22 |
| 32 /// Returns the accumulated effects and dependencies on all paths from the | 23 /// Returns the accumulated effects and dependencies on all paths from the |
| 33 /// loop entry to any recursive invocation of the loop. | 24 /// loop entry to any recursive invocation of the loop. |
| 34 SideEffects getSideEffectsInLoop(Continuation loop) { | 25 int getSideEffectsInLoop(Continuation loop) { |
| 35 return loopSideEffects[loop]; | 26 return loopSideEffects[loop]; |
| 36 } | 27 } |
| 37 | 28 |
| 38 /// True if the length of an indexable object may change between the loop | 29 /// True if the length of an indexable object may change between the loop |
| 39 /// entry and a recursive invocation of the loop. | 30 /// entry and a recursive invocation of the loop. |
| 40 bool loopChangesLength(Continuation loop) { | 31 bool changesIndexableLength(Continuation loop) { |
| 41 return loopsChangingLength.contains(loop); | 32 return loopSideEffects[loop] & Effects.changesIndexableLength != 0; |
| 42 } | 33 } |
| 43 | 34 |
| 44 @override | 35 @override |
| 45 Expression traverseContinuation(Continuation cont) { | 36 Expression traverseContinuation(Continuation cont) { |
| 46 if (cont.isRecursive) { | 37 if (cont.isRecursive) { |
| 47 SideEffects oldEffects = currentLoopSideEffects; | 38 loopSideEffects[cont] = Effects.none; |
| 48 bool oldChangesLength = currentLoopChangesLength; | |
| 49 loopSideEffects[cont] = currentLoopSideEffects = new SideEffects.empty(); | |
| 50 exitContinuations[cont] = <Continuation>[]; | 39 exitContinuations[cont] = <Continuation>[]; |
| 51 pushAction(() { | 40 pushAction(() { |
| 52 oldEffects.add(currentLoopSideEffects); | 41 if (currentLoopHeader != null) { |
| 53 if (currentLoopChangesLength) { | 42 loopSideEffects[currentLoopHeader] |= loopSideEffects[cont]; |
| 54 loopsChangingLength.add(cont); | |
| 55 } | 43 } |
| 56 currentLoopChangesLength = currentLoopChangesLength || oldChangesLength; | |
| 57 currentLoopSideEffects = oldEffects; | |
| 58 exitContinuations[cont].forEach(push); | 44 exitContinuations[cont].forEach(push); |
| 59 }); | 45 }); |
| 60 } | 46 } |
| 61 Continuation oldLoopHeader = currentLoopHeader; | 47 Continuation oldLoopHeader = currentLoopHeader; |
| 62 currentLoopHeader = loopHierarchy.getLoopHeader(cont); | 48 currentLoopHeader = loopHierarchy.getLoopHeader(cont); |
| 63 pushAction(() { | 49 pushAction(() { |
| 64 currentLoopHeader = oldLoopHeader; | 50 currentLoopHeader = oldLoopHeader; |
| 65 }); | 51 }); |
| 66 return cont.body; | 52 return cont.body; |
| 67 } | 53 } |
| 68 | 54 |
| 69 @override | 55 @override |
| 70 Expression traverseLetHandler(LetHandler node) { | 56 Expression traverseLetHandler(LetHandler node) { |
| 71 enqueueContinuation(node.handler); | 57 enqueueContinuation(node.handler); |
| 72 return node.body; | 58 return node.body; |
| 73 } | 59 } |
| 74 | 60 |
| 75 @override | 61 @override |
| 76 Expression traverseLetCont(LetCont node) { | 62 Expression traverseLetCont(LetCont node) { |
| 77 node.continuations.forEach(enqueueContinuation); | 63 node.continuations.forEach(enqueueContinuation); |
| 78 return node.body; | 64 return node.body; |
| 79 } | 65 } |
| 80 | 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 |
| 81 void enqueueContinuation(Continuation cont) { | 75 void enqueueContinuation(Continuation cont) { |
| 82 Continuation loop = loopHierarchy.getEnclosingLoop(cont); | 76 Continuation loop = loopHierarchy.getEnclosingLoop(cont); |
| 83 if (loop == currentLoopHeader) { | 77 if (loop == currentLoopHeader) { |
| 84 push(cont); | 78 push(cont); |
| 85 } else { | 79 } else { |
| 86 // Multiple loops can be exited at once. | 80 // Multiple loops can be exited at once. |
| 87 // Register as an exit from the outermost loop being exited. | 81 // Register as an exit from the outermost loop being exited. |
| 88 Continuation inner = currentLoopHeader; | 82 Continuation inner = currentLoopHeader; |
| 89 Continuation outer = loopHierarchy.getEnclosingLoop(currentLoopHeader); | 83 Continuation outer = loopHierarchy.getEnclosingLoop(currentLoopHeader); |
| 90 while (outer != loop) { | 84 while (outer != loop) { |
| 91 if (inner == null) { | 85 if (inner == null) { |
| 92 // The shrinking reductions pass must run before any pass that relies | 86 // The shrinking reductions pass must run before any pass that relies |
| 93 // on computing loop side effects. | 87 // on computing loop side effects. |
| 94 world.compiler.reporter.internalError(null, | 88 world.compiler.reporter.internalError(null, |
| 95 'Unreachable continuations must be removed before computing ' | 89 'Unreachable continuations must be removed before computing ' |
| 96 'loop side effects.'); | 90 'loop side effects.'); |
| 97 } | 91 } |
| 98 inner = outer; | 92 inner = outer; |
| 99 outer = loopHierarchy.getEnclosingLoop(outer); | 93 outer = loopHierarchy.getEnclosingLoop(outer); |
| 100 } | 94 } |
| 101 exitContinuations[inner].add(cont); | 95 exitContinuations[inner].add(cont); |
| 102 } | 96 } |
| 103 } | 97 } |
| 104 | |
| 105 void addSideEffects(SideEffects effects) { | |
| 106 currentLoopSideEffects.add(effects); | |
| 107 if (effects.changesIndex()) { | |
| 108 currentLoopChangesLength = true; | |
| 109 } | |
| 110 } | |
| 111 | |
| 112 void addAllSideEffects() { | |
| 113 currentLoopSideEffects.setAllSideEffects(); | |
| 114 currentLoopSideEffects.setDependsOnSomething(); | |
| 115 currentLoopChangesLength = true; | |
| 116 } | |
| 117 | |
| 118 void visitInvokeMethod(InvokeMethod node) { | |
| 119 addSideEffects(world.getSideEffectsOfSelector(node.selector, node.mask)); | |
| 120 } | |
| 121 | |
| 122 void visitInvokeStatic(InvokeStatic node) { | |
| 123 addSideEffects(world.getSideEffectsOfElement(node.target)); | |
| 124 } | |
| 125 | |
| 126 void visitInvokeMethodDirectly(InvokeMethodDirectly node) { | |
| 127 FunctionElement target = node.target; | |
| 128 if (target is ConstructorBodyElement) { | |
| 129 ConstructorBodyElement body = target; | |
| 130 target = body.constructor; | |
| 131 } | |
| 132 addSideEffects(world.getSideEffectsOfElement(target)); | |
| 133 } | |
| 134 | |
| 135 void visitInvokeConstructor(InvokeConstructor node) { | |
| 136 addSideEffects(world.getSideEffectsOfElement(node.target)); | |
| 137 } | |
| 138 | |
| 139 void visitSetStatic(SetStatic node) { | |
| 140 currentLoopSideEffects.setChangesStaticProperty(); | |
| 141 } | |
| 142 | |
| 143 void visitGetStatic(GetStatic node) { | |
| 144 currentLoopSideEffects.setDependsOnStaticPropertyStore(); | |
| 145 } | |
| 146 | |
| 147 void visitGetField(GetField node) { | |
| 148 currentLoopSideEffects.setDependsOnInstancePropertyStore(); | |
| 149 } | |
| 150 | |
| 151 void visitSetField(SetField node) { | |
| 152 currentLoopSideEffects.setChangesInstanceProperty(); | |
| 153 } | |
| 154 | |
| 155 void visitGetIndex(GetIndex node) { | |
| 156 currentLoopSideEffects.setDependsOnIndexStore(); | |
| 157 } | |
| 158 | |
| 159 void visitSetIndex(SetIndex node) { | |
| 160 // Set the change index flag without setting the change length flag. | |
| 161 currentLoopSideEffects.setChangesIndex(); | |
| 162 } | |
| 163 | |
| 164 void visitForeignCode(ForeignCode node) { | |
| 165 addSideEffects(node.nativeBehavior.sideEffects); | |
| 166 } | |
| 167 | |
| 168 void visitGetLazyStatic(GetLazyStatic node) { | |
| 169 // TODO(asgerf): How do we get the side effects of a lazy field initializer? | |
| 170 addAllSideEffects(); | |
| 171 } | |
| 172 | |
| 173 void visitAwait(Await node) { | |
| 174 addAllSideEffects(); | |
| 175 } | |
| 176 | |
| 177 void visitYield(Yield node) { | |
| 178 addAllSideEffects(); | |
| 179 } | |
| 180 | |
| 181 void visitApplyBuiltinMethod(ApplyBuiltinMethod node) { | |
| 182 currentLoopSideEffects.setChangesIndex(); | |
| 183 currentLoopChangesLength = true; // Push and pop. | |
| 184 } | |
| 185 } | 98 } |
| OLD | NEW |