| 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.loop_hierarchy; | 5 library dart2js.cps_ir.loop_hierarchy; |
| 6 | 6 |
| 7 import 'cps_ir_nodes.dart'; | 7 import 'cps_ir_nodes.dart'; |
| 8 | 8 |
| 9 /// Determines the effective nesting of loops. | 9 /// Determines the effective nesting of loops. |
| 10 /// | 10 /// |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 92 loopDepth[cont] = currentDepth; | 92 loopDepth[cont] = currentDepth; |
| 93 Continuation target = _processBlock(cont.body, catchLoop); | 93 Continuation target = _processBlock(cont.body, catchLoop); |
| 94 _markInnerLoop(loopTarget[cont], target); | 94 _markInnerLoop(loopTarget[cont], target); |
| 95 --currentDepth; | 95 --currentDepth; |
| 96 } else { | 96 } else { |
| 97 loopTarget[cont] = _processBlock(cont.body, catchLoop); | 97 loopTarget[cont] = _processBlock(cont.body, catchLoop); |
| 98 } | 98 } |
| 99 return loopTarget[cont]; | 99 return loopTarget[cont]; |
| 100 } | 100 } |
| 101 | 101 |
| 102 bool _isCallContinuation(Continuation cont) { | |
| 103 return cont.hasExactlyOneUse && cont.firstRef.parent is CallExpression; | |
| 104 } | |
| 105 | |
| 106 /// Analyzes a basic block and returns the innermost loop that | 102 /// Analyzes a basic block and returns the innermost loop that |
| 107 /// can be invoked recursively from that block. | 103 /// can be invoked recursively from that block. |
| 108 Continuation _processBlock(Expression node, Continuation catchLoop) { | 104 Continuation _processBlock(Expression node, Continuation catchLoop) { |
| 109 List<Continuation> callContinuations = <Continuation>[]; | |
| 110 for (; node is! TailExpression; node = node.next) { | 105 for (; node is! TailExpression; node = node.next) { |
| 111 if (node is LetCont) { | 106 if (node is LetCont) { |
| 112 for (Continuation cont in node.continuations) { | 107 for (Continuation cont in node.continuations) { |
| 113 if (!_isCallContinuation(cont)) { | 108 _processContinuation(cont, catchLoop); |
| 114 // Process non-call continuations at the binding site, so they | |
| 115 // their loop target is known at all use sites. | |
| 116 _processContinuation(cont, catchLoop); | |
| 117 } else { | |
| 118 // To avoid deep recursion, do not analyze call continuations | |
| 119 // recursively. This basic block traversal steps into the | |
| 120 // call contiunation after visiting its use site. We store the | |
| 121 // continuations in a list so we can set the loop target once | |
| 122 // it is known. | |
| 123 callContinuations.add(cont); | |
| 124 } | |
| 125 } | 109 } |
| 126 } else if (node is LetHandler) { | 110 } else if (node is LetHandler) { |
| 127 catchLoop = _processContinuation(node.handler, catchLoop); | 111 catchLoop = _processContinuation(node.handler, catchLoop); |
| 128 } | 112 } |
| 129 } | 113 } |
| 130 Continuation target; | 114 Continuation target; |
| 131 if (node is InvokeContinuation) { | 115 if (node is InvokeContinuation) { |
| 132 if (node.isRecursive) { | 116 if (node.isRecursive) { |
| 133 target = node.continuation.definition; | 117 target = node.continuation.definition; |
| 134 } else { | 118 } else { |
| 135 target = loopTarget[node.continuation.definition]; | 119 target = loopTarget[node.continuation.definition]; |
| 136 } | 120 } |
| 137 } else if (node is Branch) { | 121 } else if (node is Branch) { |
| 138 target = _markInnerLoop( | 122 target = _markInnerLoop( |
| 139 loopTarget[node.trueContinuation.definition], | 123 loopTarget[node.trueContinuation.definition], |
| 140 loopTarget[node.falseContinuation.definition]); | 124 loopTarget[node.falseContinuation.definition]); |
| 141 } else { | 125 } else { |
| 142 assert(node is Unreachable || node is Throw); | 126 assert(node is Unreachable || node is Throw); |
| 143 } | 127 } |
| 144 target = _markInnerLoop(target, catchLoop); | 128 return _markInnerLoop(target, catchLoop); |
| 145 for (Continuation cont in callContinuations) { | |
| 146 // Store the loop target on each call continuation in the basic block. | |
| 147 // Because we walk over call continuations as part of the basic block | |
| 148 // traversal, these do not get their loop target set otherwise. | |
| 149 loopTarget[cont] = target; | |
| 150 } | |
| 151 return target; | |
| 152 } | 129 } |
| 153 } | 130 } |
| OLD | NEW |