| 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 import 'cps_fragment.dart'; |
| 8 | 9 |
| 9 /// Determines the effective nesting of loops. | 10 /// Determines the effective nesting of loops. |
| 10 /// | 11 /// |
| 11 /// The effective nesting of loops is different from the lexical nesting, since | 12 /// The effective nesting of loops is different from the lexical nesting, since |
| 12 /// recursive continuations can generally contain all the code following | 13 /// recursive continuations can generally contain all the code following |
| 13 /// after the loop in addition to the looping code itself. | 14 /// after the loop in addition to the looping code itself. |
| 14 /// | 15 /// |
| 15 /// For example, the 'else' branch below is not effectively part of the loop: | 16 /// For example, the 'else' branch below is not effectively part of the loop: |
| 16 /// | 17 /// |
| 17 /// let rec kont x = | 18 /// let rec kont x = |
| 18 /// if (<loop condition>) | 19 /// if (<loop condition>) |
| 19 /// <loop body> | 20 /// <loop body> |
| 20 /// InvokeContinuation kont x' | 21 /// InvokeContinuation kont x' |
| 21 /// else | 22 /// else |
| 22 /// <after loop> | 23 /// <after loop> |
| 23 /// return p.foo() | 24 /// return p.foo() |
| 24 /// | 25 /// |
| 25 /// We use the term "loop" to mean recursive continuation. | 26 /// We use the term "loop" to mean recursive continuation. |
| 26 /// The `null` value is used to represent a context not part of any loop. | 27 /// The `null` value is used to represent a context not part of any loop. |
| 27 class LoopHierarchy { | 28 class LoopHierarchy { |
| 28 /// Nesting depth of the given loop. | 29 /// Nesting depth of the given loop. |
| 29 Map<Continuation, int> loopDepth = <Continuation, int>{}; | 30 Map<Continuation, int> loopDepth = <Continuation, int>{}; |
| 30 | 31 |
| 31 /// The innermost loop (other than itself) that may be invoked recursively | 32 /// The innermost loop (other than itself) that may be invoked recursively |
| 32 /// as a result of invoking the given continuation. | 33 /// as a result of invoking the given continuation. |
| 33 Map<Continuation, Continuation> loopTarget = <Continuation, Continuation>{}; | 34 Map<Continuation, Continuation> loopTarget = <Continuation, Continuation>{}; |
| 34 | 35 |
| 35 /// Current nesting depth. | 36 /// Current nesting depth. |
| 36 int currentDepth = 0; | 37 int _currentDepth = 0; |
| 38 |
| 39 /// The loop target to use for missing code. Used by [update]. |
| 40 Continuation _exitLoop; |
| 37 | 41 |
| 38 /// Computes the loop hierarchy for the given function. | 42 /// Computes the loop hierarchy for the given function. |
| 39 /// | 43 /// |
| 40 /// Parent pointers must be computed for [node]. | 44 /// Parent pointers must be computed for [node]. |
| 41 LoopHierarchy(FunctionDefinition node) { | 45 LoopHierarchy(FunctionDefinition node) { |
| 42 _processBlock(node.body, null); | 46 _processBlock(node.body, null); |
| 43 } | 47 } |
| 44 | 48 |
| 45 /// Returns the innermost loop which [cont] is effectively part of. | 49 /// Returns the innermost loop which [cont] is effectively part of. |
| 46 Continuation getLoopHeader(Continuation cont) { | 50 Continuation getLoopHeader(Continuation cont) { |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 81 } | 85 } |
| 82 } | 86 } |
| 83 | 87 |
| 84 /// Analyzes the body of [cont] and returns the innermost loop | 88 /// Analyzes the body of [cont] and returns the innermost loop |
| 85 /// that can be invoked recursively from [cont] (other than [cont] itself). | 89 /// that can be invoked recursively from [cont] (other than [cont] itself). |
| 86 /// | 90 /// |
| 87 /// [catchLoop] is the innermost loop that can be invoked recursively | 91 /// [catchLoop] is the innermost loop that can be invoked recursively |
| 88 /// from the current exception handler. | 92 /// from the current exception handler. |
| 89 Continuation _processContinuation(Continuation cont, Continuation catchLoop) { | 93 Continuation _processContinuation(Continuation cont, Continuation catchLoop) { |
| 90 if (cont.isRecursive) { | 94 if (cont.isRecursive) { |
| 91 ++currentDepth; | 95 ++_currentDepth; |
| 92 loopDepth[cont] = currentDepth; | 96 loopDepth[cont] = _currentDepth; |
| 93 Continuation target = _processBlock(cont.body, catchLoop); | 97 Continuation target = _processBlock(cont.body, catchLoop); |
| 94 _markInnerLoop(loopTarget[cont], target); | 98 _markInnerLoop(loopTarget[cont], target); |
| 95 --currentDepth; | 99 --_currentDepth; |
| 96 } else { | 100 } else { |
| 97 loopTarget[cont] = _processBlock(cont.body, catchLoop); | 101 loopTarget[cont] = _processBlock(cont.body, catchLoop); |
| 98 } | 102 } |
| 99 return loopTarget[cont]; | 103 return loopTarget[cont]; |
| 100 } | 104 } |
| 101 | 105 |
| 102 /// Analyzes a basic block and returns the innermost loop that | 106 /// Analyzes a basic block and returns the innermost loop that |
| 103 /// can be invoked recursively from that block. | 107 /// can be invoked recursively from that block. |
| 104 Continuation _processBlock(Expression node, Continuation catchLoop) { | 108 Continuation _processBlock(Expression node, Continuation catchLoop) { |
| 105 for (; node is! TailExpression; node = node.next) { | 109 for (; node != null && node is! TailExpression; node = node.next) { |
| 106 if (node is LetCont) { | 110 if (node is LetCont) { |
| 107 for (Continuation cont in node.continuations) { | 111 for (Continuation cont in node.continuations) { |
| 108 _processContinuation(cont, catchLoop); | 112 _processContinuation(cont, catchLoop); |
| 109 } | 113 } |
| 110 } else if (node is LetHandler) { | 114 } else if (node is LetHandler) { |
| 111 catchLoop = _processContinuation(node.handler, catchLoop); | 115 catchLoop = _processContinuation(node.handler, catchLoop); |
| 112 } | 116 } |
| 113 } | 117 } |
| 114 Continuation target; | 118 Continuation target; |
| 115 if (node is InvokeContinuation) { | 119 if (node is InvokeContinuation) { |
| 116 if (node.isRecursive) { | 120 if (node.isRecursive) { |
| 117 target = node.continuation.definition; | 121 target = node.continuation.definition; |
| 118 } else { | 122 } else { |
| 119 target = loopTarget[node.continuation.definition]; | 123 target = loopTarget[node.continuation.definition]; |
| 120 } | 124 } |
| 121 } else if (node is Branch) { | 125 } else if (node is Branch) { |
| 122 target = _markInnerLoop( | 126 target = _markInnerLoop( |
| 123 loopTarget[node.trueContinuation.definition], | 127 loopTarget[node.trueContinuation.definition], |
| 124 loopTarget[node.falseContinuation.definition]); | 128 loopTarget[node.falseContinuation.definition]); |
| 129 } else if (node == null) { |
| 130 // If the code ends abruptly, use the exit loop provided in [update]. |
| 131 target = _exitLoop; |
| 125 } else { | 132 } else { |
| 126 assert(node is Unreachable || node is Throw); | 133 assert(node is Unreachable || node is Throw || node == null); |
| 127 } | 134 } |
| 128 return _markInnerLoop(target, catchLoop); | 135 return _markInnerLoop(target, catchLoop); |
| 129 } | 136 } |
| 130 | 137 |
| 131 /// Returns the the innermost loop that effectively encloses both | 138 /// Returns the the innermost loop that effectively encloses both |
| 132 /// c1 and c2 (or `null` if there is no such loop). | 139 /// c1 and c2 (or `null` if there is no such loop). |
| 133 Continuation lowestCommonAncestor(Continuation c1, Continuation c2) { | 140 Continuation lowestCommonAncestor(Continuation c1, Continuation c2) { |
| 134 int d1 = getDepth(c1), d2 = getDepth(c2); | 141 int d1 = getDepth(c1), d2 = getDepth(c2); |
| 135 while (c1 != c2) { | 142 while (c1 != c2) { |
| 136 if (d1 <= d2) { | 143 if (d1 <= d2) { |
| 137 c2 = getEnclosingLoop(c2); | 144 c2 = getEnclosingLoop(c2); |
| 138 d2 = getDepth(c2); | 145 d2 = getDepth(c2); |
| 139 } else { | 146 } else { |
| 140 c1 = getEnclosingLoop(c1); | 147 c1 = getEnclosingLoop(c1); |
| 141 d1 = getDepth(c1); | 148 d1 = getDepth(c1); |
| 142 } | 149 } |
| 143 } | 150 } |
| 144 return c1; | 151 return c1; |
| 145 } | 152 } |
| 146 | 153 |
| 147 /// Returns the lexical nesting depth of [loop]. | 154 /// Returns the lexical nesting depth of [loop]. |
| 148 int getDepth(Continuation loop) { | 155 int getDepth(Continuation loop) { |
| 149 if (loop == null) return 0; | 156 if (loop == null) return 0; |
| 150 return loopDepth[loop]; | 157 return loopDepth[loop]; |
| 151 } | 158 } |
| 159 |
| 160 /// Sets the loop header for each continuation bound inside the given |
| 161 /// fragment. |
| 162 /// |
| 163 /// If the fragment is open, [exitLoop] denotes the loop header for |
| 164 /// the code that will occur after the fragment. |
| 165 /// |
| 166 /// [catchLoop] is the loop target for the catch clause of the try/catch |
| 167 /// surrounding the inserted fragment. |
| 168 void update(CpsFragment fragment, |
| 169 {Continuation exitLoop, |
| 170 Continuation catchLoop}) { |
| 171 if (fragment.isEmpty) return; |
| 172 _exitLoop = exitLoop; |
| 173 _currentDepth = getDepth(exitLoop); |
| 174 _processBlock(fragment.root, catchLoop); |
| 175 _exitLoop = null; |
| 176 } |
| 152 } | 177 } |
| OLD | NEW |