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