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