Chromium Code Reviews| 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 cps_ir.optimization.insert_refinements; | 5 library cps_ir.optimization.insert_refinements; |
| 6 | 6 |
| 7 import 'optimizers.dart' show Pass; | 7 import 'optimizers.dart' show Pass; |
| 8 import 'cps_ir_nodes.dart'; | 8 import 'cps_ir_nodes.dart'; |
| 9 import '../common/names.dart'; | 9 import '../common/names.dart'; |
| 10 import '../types/types.dart' show TypeMask; | 10 import '../types/types.dart' show TypeMask; |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 68 } else { | 68 } else { |
| 69 let.remove(); // Reuse the existing LetCont. | 69 let.remove(); // Reuse the existing LetCont. |
| 70 } | 70 } |
| 71 let.insertAbove(use); | 71 let.insertAbove(use); |
| 72 } | 72 } |
| 73 | 73 |
| 74 Primitive unfoldInterceptor(Primitive prim) { | 74 Primitive unfoldInterceptor(Primitive prim) { |
| 75 return prim is Interceptor ? prim.input.definition : prim; | 75 return prim is Interceptor ? prim.input.definition : prim; |
| 76 } | 76 } |
| 77 | 77 |
| 78 /// Enqueues [cont] for processing in a context where [refined] is the | 78 /// Sets [refined] to be the current current refinement for its value, |
|
sra1
2015/11/19 21:41:46
current current?
asgerf
2015/11/20 16:23:54
It is even more current than usual
| |
| 79 /// current refinement for its value. | 79 /// and pushes an action that will restore the original scope again. |
| 80 void pushRefinement(Continuation cont, Refinement refined) { | 80 /// |
| 81 /// The refinement is inserted as the child of [insertionParent] if it has | |
| 82 /// at least one use after its scope has been processed. | |
| 83 void applyRefinement(InteriorNode insertionParent, Refinement refined) { | |
| 81 Primitive value = refined.effectiveDefinition; | 84 Primitive value = refined.effectiveDefinition; |
| 82 Primitive currentRefinement = refinementFor[value]; | 85 Primitive currentRefinement = refinementFor[value]; |
| 83 pushAction(() { | 86 pushAction(() { |
| 84 refinementFor[value] = currentRefinement; | 87 refinementFor[value] = currentRefinement; |
| 85 if (refined.hasNoUses) { | 88 if (refined.hasNoUses) { |
| 86 // Clean up refinements that are not used. | 89 // Clean up refinements that are not used. |
| 87 refined.destroy(); | 90 refined.destroy(); |
| 88 } else { | 91 } else { |
| 89 LetPrim let = new LetPrim(refined); | 92 LetPrim let = new LetPrim(refined); |
| 90 let.insertBelow(cont); | 93 let.insertBelow(insertionParent); |
| 91 } | 94 } |
| 92 }); | 95 }); |
| 93 push(cont); | 96 refinementFor[value] = refined; |
|
sra1
2015/11/19 21:41:46
I think I prefer pushAction to be the last thing s
asgerf
2015/11/20 16:23:54
Done.
| |
| 97 } | |
| 98 | |
| 99 /// Enqueues [cont] for processing in a context where [refined] is the | |
| 100 /// current refinement for its value. | |
| 101 void pushRefinement(Continuation cont, Refinement refined) { | |
| 94 pushAction(() { | 102 pushAction(() { |
| 95 refinementFor[value] = refined; | 103 applyRefinement(cont, refined); |
| 104 push(cont); | |
| 96 }); | 105 }); |
| 97 } | 106 } |
| 98 | 107 |
| 99 void visitInvokeMethod(InvokeMethod node) { | 108 void visitInvokeMethod(InvokeMethod node) { |
| 100 Continuation cont = node.continuation.definition; | |
| 101 | |
| 102 // Update references to their current refined values. | 109 // Update references to their current refined values. |
| 103 processReference(node.receiver); | 110 processReference(node.receiver); |
| 104 node.arguments.forEach(processReference); | 111 node.arguments.forEach(processReference); |
| 105 | 112 |
| 106 // If the call is intercepted, we want to refine the actual receiver, | 113 // If the call is intercepted, we want to refine the actual receiver, |
| 107 // not the interceptor. | 114 // not the interceptor. |
| 108 Primitive receiver = unfoldInterceptor(node.receiver.definition); | 115 Primitive receiver = unfoldInterceptor(node.receiver.definition); |
| 109 | 116 |
| 110 // Sink the continuation to the call to ensure everything in scope | |
| 111 // here is also in scope inside the continuations. | |
| 112 sinkContinuationToUse(cont, node); | |
| 113 | |
| 114 if (node.selector.isClosureCall) { | 117 if (node.selector.isClosureCall) { |
| 115 // Do not try to refine the receiver of closure calls; the class world | 118 // Do not try to refine the receiver of closure calls; the class world |
| 116 // does not know about closure classes. | 119 // does not know about closure classes. |
| 117 push(cont); | |
| 118 } else { | 120 } else { |
| 119 // Filter away receivers that throw on this selector. | 121 // Filter away receivers that throw on this selector. |
| 120 TypeMask type = types.receiverTypeFor(node.selector, node.mask); | 122 TypeMask type = types.receiverTypeFor(node.selector, node.mask); |
| 121 Refinement refinement = new Refinement(receiver, type); | 123 Refinement refinement = new Refinement(receiver, type); |
| 122 pushRefinement(cont, refinement); | 124 LetPrim letPrim = node.parent; |
| 125 applyRefinement(letPrim, refinement); | |
| 123 } | 126 } |
| 124 } | 127 } |
| 125 | 128 |
| 126 void visitTypeCast(TypeCast node) { | 129 void visitTypeCast(TypeCast node) { |
| 127 Continuation cont = node.continuation.definition; | |
| 128 Primitive value = node.value.definition; | 130 Primitive value = node.value.definition; |
| 129 | 131 |
| 130 processReference(node.value); | 132 processReference(node.value); |
| 131 node.typeArguments.forEach(processReference); | 133 node.typeArguments.forEach(processReference); |
| 132 | 134 |
| 133 // Refine the type of the input. | 135 // Refine the type of the input. |
| 134 sinkContinuationToUse(cont, node); | |
| 135 TypeMask type = types.subtypesOf(node.dartType).nullable(); | 136 TypeMask type = types.subtypesOf(node.dartType).nullable(); |
| 136 Refinement refinement = new Refinement(value, type); | 137 Refinement refinement = new Refinement(value, type); |
| 137 pushRefinement(cont, refinement); | 138 LetPrim letPrim = node.parent; |
| 139 applyRefinement(letPrim, refinement); | |
| 138 } | 140 } |
| 139 | 141 |
| 140 void visitRefinement(Refinement node) { | 142 void visitRefinement(Refinement node) { |
| 141 // We found a pre-existing refinement node. These are generated by the | 143 // We found a pre-existing refinement node. These are generated by the |
| 142 // IR builder to hold information from --trust-type-annotations. | 144 // IR builder to hold information from --trust-type-annotations. |
| 143 // Update its input to use our own current refinement, then update the | 145 // Update its input to use our own current refinement, then update the |
| 144 // environment to use this refinement. | 146 // environment to use this refinement. |
| 145 processReference(node.value); | 147 processReference(node.value); |
| 146 Primitive value = node.value.definition.effectiveDefinition; | 148 Primitive value = node.value.definition.effectiveDefinition; |
| 147 Primitive oldRefinement = refinementFor[value]; | 149 Primitive oldRefinement = refinementFor[value]; |
| 148 refinementFor[value] = node; | 150 refinementFor[value] = node; |
| 149 pushAction(() { | 151 pushAction(() { |
| 150 refinementFor[value] = oldRefinement; | 152 refinementFor[value] = oldRefinement; |
| 151 }); | 153 }); |
| 152 } | 154 } |
| 153 | 155 |
| 154 CallExpression getCallWithResult(Primitive prim) { | |
| 155 if (prim is Parameter && prim.parent is Continuation) { | |
| 156 Continuation cont = prim.parent; | |
| 157 if (cont.hasExactlyOneUse && cont.firstRef.parent is CallExpression) { | |
| 158 return cont.firstRef.parent; | |
| 159 } | |
| 160 } | |
| 161 return null; | |
| 162 } | |
| 163 | |
| 164 bool isTrue(Primitive prim) { | 156 bool isTrue(Primitive prim) { |
| 165 return prim is Constant && prim.value.isTrue; | 157 return prim is Constant && prim.value.isTrue; |
| 166 } | 158 } |
| 167 | 159 |
| 168 void visitBranch(Branch node) { | 160 void visitBranch(Branch node) { |
| 169 processReference(node.condition); | 161 processReference(node.condition); |
| 170 Primitive condition = node.condition.definition; | 162 Primitive condition = node.condition.definition; |
| 171 CallExpression call = getCallWithResult(condition); | |
| 172 | 163 |
| 173 Continuation trueCont = node.trueContinuation.definition; | 164 Continuation trueCont = node.trueContinuation.definition; |
| 174 Continuation falseCont = node.falseContinuation.definition; | 165 Continuation falseCont = node.falseContinuation.definition; |
| 175 | 166 |
| 176 // Sink both continuations to the Branch to ensure everything in scope | 167 // Sink both continuations to the Branch to ensure everything in scope |
| 177 // here is also in scope inside the continuations. | 168 // here is also in scope inside the continuations. |
| 178 sinkContinuationToUse(trueCont, node); | 169 sinkContinuationToUse(trueCont, node); |
| 179 sinkContinuationToUse(falseCont, node); | 170 sinkContinuationToUse(falseCont, node); |
| 180 | 171 |
| 181 // If the condition is an 'is' check, promote the checked value. | 172 // If the condition is an 'is' check, promote the checked value. |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 205 Refinement refinedTrue = new Refinement(second, types.nullType); | 196 Refinement refinedTrue = new Refinement(second, types.nullType); |
| 206 Refinement refinedFalse = new Refinement(second, types.nonNullType); | 197 Refinement refinedFalse = new Refinement(second, types.nonNullType); |
| 207 pushRefinement(trueCont, refinedTrue); | 198 pushRefinement(trueCont, refinedTrue); |
| 208 pushRefinement(falseCont, refinedFalse); | 199 pushRefinement(falseCont, refinedFalse); |
| 209 } else { | 200 } else { |
| 210 push(trueCont); | 201 push(trueCont); |
| 211 push(falseCont); | 202 push(falseCont); |
| 212 } | 203 } |
| 213 } | 204 } |
| 214 | 205 |
| 215 if (call is InvokeMethod && call.selector == Selectors.equals) { | 206 if (condition is InvokeMethod && condition.selector == Selectors.equals) { |
| 216 refineEquality(call.arguments[0].definition, | 207 refineEquality(condition.dartReceiver, |
| 217 call.arguments[1].definition, | 208 condition.getDartArgument(0), |
| 218 trueCont, | 209 trueCont, |
| 219 falseCont); | 210 falseCont); |
| 220 return; | 211 return; |
| 221 } | 212 } |
| 222 | 213 |
| 223 if (condition is ApplyBuiltinOperator && | 214 if (condition is ApplyBuiltinOperator && |
| 224 condition.operator == BuiltinOperator.Identical) { | 215 condition.operator == BuiltinOperator.Identical) { |
| 225 refineEquality(condition.arguments[0].definition, | 216 refineEquality(condition.arguments[0].definition, |
| 226 condition.arguments[1].definition, | 217 condition.arguments[1].definition, |
| 227 trueCont, | 218 trueCont, |
| 228 falseCont); | 219 falseCont); |
| 229 return; | 220 return; |
| 230 } | 221 } |
| 231 | 222 |
| 232 push(trueCont); | 223 push(trueCont); |
| 233 push(falseCont); | 224 push(falseCont); |
| 234 } | 225 } |
| 235 | 226 |
| 236 @override | 227 @override |
| 237 Expression traverseLetCont(LetCont node) { | 228 Expression traverseLetCont(LetCont node) { |
| 238 for (Continuation cont in node.continuations) { | 229 for (Continuation cont in node.continuations) { |
| 239 if (cont.hasExactlyOneUse && | 230 if (cont.hasExactlyOneUse && cont.firstRef.parent is Branch) { |
| 240 (cont.firstRef.parent is InvokeMethod || | 231 // Do not push the branch continuations here. visitBranch will do that. |
| 241 cont.firstRef.parent is TypeCast || | |
| 242 cont.firstRef.parent is Branch)) { | |
| 243 // Do not push the continuation here. | |
| 244 // visitInvokeMethod, visitBranch, and visitTypeCast will do that. | |
| 245 } else { | 232 } else { |
| 246 push(cont); | 233 push(cont); |
| 247 } | 234 } |
| 248 } | 235 } |
| 249 return node.body; | 236 return node.body; |
| 250 } | 237 } |
| 251 } | 238 } |
| OLD | NEW |