| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library dart2js.cps_ir.redundant_join_elimination; | 5 library dart2js.cps_ir.redundant_join_elimination; |
| 6 | 6 |
| 7 import 'cps_ir_nodes.dart'; | 7 import 'cps_ir_nodes.dart'; |
| 8 import 'optimizers.dart'; | 8 import 'optimizers.dart'; |
| 9 | 9 |
| 10 /// Eliminates redundant join points. | 10 /// Eliminates redundant join points. |
| 11 /// | 11 /// |
| 12 /// A redundant join point is a continuation that immediately branches | 12 /// A redundant join point is a continuation that immediately branches |
| 13 /// based on one of its parameters, and that parameter is a constant value | 13 /// based on one of its parameters, and that parameter is a constant value |
| 14 /// at every invocation. Each invocation is redirected to jump directly | 14 /// at every invocation. Each invocation is redirected to jump directly |
| 15 /// to the branch target. | 15 /// to the branch target. |
| 16 /// | 16 /// |
| 17 /// Internally in this pass, parameters are treated as names with lexical | 17 /// Internally in this pass, parameters are treated as names with lexical |
| 18 /// scoping, and a given parameter "name" may be declared by more than | 18 /// scoping, and a given parameter "name" may be declared by more than |
| 19 /// one continuation. The reference chains for parameters are therefore | 19 /// one continuation. The reference chains for parameters are therefore |
| 20 /// meaningless during this pass, until repaired by [AlphaRenamer] at | 20 /// meaningless during this pass, until repaired by [AlphaRenamer] at |
| 21 /// the end. | 21 /// the end. |
| 22 class RedundantJoinEliminator extends TrampolineRecursiveVisitor implements Pass
{ | 22 class RedundantJoinEliminator extends TrampolineRecursiveVisitor implements Pass
{ |
| 23 String get passName => 'Redundant join elimination'; | 23 String get passName => 'Redundant join elimination'; |
| 24 | 24 |
| 25 final Set<Branch> workSet = new Set<Branch>(); | 25 final Set<Branch> workSet = new Set<Branch>(); |
| 26 | 26 |
| 27 void rewrite(FunctionDefinition node) { | 27 void rewrite(FunctionDefinition node) { |
| 28 visit(node); | 28 visit(node); |
| 29 | 29 |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 106 | 106 |
| 107 // The optimization is now known to be safe, but it only pays off if | 107 // The optimization is now known to be safe, but it only pays off if |
| 108 // one of the callers can inline its target, since otherwise we end up | 108 // one of the callers can inline its target, since otherwise we end up |
| 109 // replacing a boolean variable with a labeled break. | 109 // replacing a boolean variable with a labeled break. |
| 110 // TODO(asgerf): The labeled break might be better? Evaluate. | 110 // TODO(asgerf): The labeled break might be better? Evaluate. |
| 111 if (!(trueHits == 1 && !trueCall.isEscapingTry || | 111 if (!(trueHits == 1 && !trueCall.isEscapingTry || |
| 112 falseHits == 1 && !falseCall.isEscapingTry)) { | 112 falseHits == 1 && !falseCall.isEscapingTry)) { |
| 113 return; | 113 return; |
| 114 } | 114 } |
| 115 | 115 |
| 116 // Lift any continuations bound inside branchCont so they are in scope at | 116 // Lift any continuations bound inside branchCont so they are in scope at |
| 117 // the call sites. When lifting, the parameters of branchCont fall out of | 117 // the call sites. When lifting, the parameters of branchCont fall out of |
| 118 // scope, so they are added as parameters on each lifted continuation. | 118 // scope, so they are added as parameters on each lifted continuation. |
| 119 // Schematically: | 119 // Schematically: |
| 120 // | 120 // |
| 121 // (LetCont (branchCont (x1, x2, x3) = | 121 // (LetCont (branchCont (x1, x2, x3) = |
| 122 // (LetCont (innerCont (y) = ...) in | 122 // (LetCont (innerCont (y) = ...) in |
| 123 // [... innerCont(y') ...])) | 123 // [... innerCont(y') ...])) |
| 124 // | 124 // |
| 125 // => | 125 // => |
| 126 // | 126 // |
| 127 // (LetCont (innerCont (y, x1, x2, x3) = ...) in | 127 // (LetCont (innerCont (y, x1, x2, x3) = ...) in |
| 128 // (LetCont (branchCont (x1, x2, x3) = | 128 // (LetCont (branchCont (x1, x2, x3) = |
| 129 // [... innerCont(y', x1, x2, x3) ...]) | 129 // [... innerCont(y', x1, x2, x3) ...]) |
| 130 // | 130 // |
| 131 // Parameter objects become shared between branchCont and the lifted | 131 // Parameter objects become shared between branchCont and the lifted |
| 132 // continuations. [AlphaRenamer] will clean up at the end of this pass. | 132 // continuations. [AlphaRenamer] will clean up at the end of this pass. |
| 133 LetCont outerLetCont = branchCont.parent; | 133 LetCont outerLetCont = branchCont.parent; |
| 134 while (branchCont.body is LetCont) { | 134 while (branchCont.body is LetCont) { |
| 135 LetCont innerLetCont = branchCont.body; | 135 LetCont innerLetCont = branchCont.body; |
| 136 for (Continuation innerCont in innerLetCont.continuations) { | 136 for (Continuation innerCont in innerLetCont.continuations) { |
| 137 innerCont.parameters.addAll(branchCont.parameters); | 137 innerCont.parameters.addAll(branchCont.parameters); |
| 138 for (Reference ref = innerCont.firstRef; ref != null; ref = ref.next) { | 138 for (Reference ref = innerCont.firstRef; ref != null; ref = ref.next) { |
| 139 Expression use = ref.parent; | 139 Expression use = ref.parent; |
| 140 if (use is InvokeContinuation) { | 140 if (use is InvokeContinuation) { |
| 141 for (Parameter param in branchCont.parameters) { | 141 for (Parameter param in branchCont.parameters) { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 195 Expression body = getEffectiveBody(cont); | 195 Expression body = getEffectiveBody(cont); |
| 196 if (body is Branch) { | 196 if (body is Branch) { |
| 197 workSet.add(body); | 197 workSet.add(body); |
| 198 } | 198 } |
| 199 } | 199 } |
| 200 } | 200 } |
| 201 | 201 |
| 202 /// Ensures parameter objects are not shared between different continuations, | 202 /// Ensures parameter objects are not shared between different continuations, |
| 203 /// akin to alpha-renaming variables so every variable is named uniquely. | 203 /// akin to alpha-renaming variables so every variable is named uniquely. |
| 204 /// For example: | 204 /// For example: |
| 205 /// | 205 /// |
| 206 /// LetCont (k1 x = (return x)) in | 206 /// LetCont (k1 x = (return x)) in |
| 207 /// LetCont (k2 x = (InvokeContinuation k3 x)) in ... | 207 /// LetCont (k2 x = (InvokeContinuation k3 x)) in ... |
| 208 /// => | 208 /// => |
| 209 /// LetCont (k1 x = (return x)) in | 209 /// LetCont (k1 x = (return x)) in |
| 210 /// LetCont (k2 x' = (InvokeContinuation k3 x')) in ... | 210 /// LetCont (k2 x' = (InvokeContinuation k3 x')) in ... |
| 211 /// | 211 /// |
| 212 /// After lifting LetConts in the main pass above, parameter objects can have | 212 /// After lifting LetConts in the main pass above, parameter objects can have |
| 213 /// multiple bindings. Each reference implicitly refers to the binding that | 213 /// multiple bindings. Each reference implicitly refers to the binding that |
| 214 /// is currently in scope. | 214 /// is currently in scope. |
| 215 /// | 215 /// |
| 216 /// This returns the IR to its normal form after redundant joins have been | 216 /// This returns the IR to its normal form after redundant joins have been |
| 217 /// eliminated. | 217 /// eliminated. |
| 218 class AlphaRenamer extends TrampolineRecursiveVisitor { | 218 class AlphaRenamer extends TrampolineRecursiveVisitor { |
| 219 Map<Parameter, Parameter> renaming = <Parameter, Parameter>{}; | 219 Map<Parameter, Parameter> renaming = <Parameter, Parameter>{}; |
| 220 | 220 |
| 221 processContinuation(Continuation cont) { | 221 processContinuation(Continuation cont) { |
| (...skipping 29 matching lines...) Expand all Loading... |
| 251 }); | 251 }); |
| 252 } | 252 } |
| 253 | 253 |
| 254 processReference(Reference ref) { | 254 processReference(Reference ref) { |
| 255 Parameter target = renaming[ref.definition]; | 255 Parameter target = renaming[ref.definition]; |
| 256 if (target != null) { | 256 if (target != null) { |
| 257 ref.changeTo(target); | 257 ref.changeTo(target); |
| 258 } | 258 } |
| 259 } | 259 } |
| 260 } | 260 } |
| OLD | NEW |