| 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 'dart:math' show min; | 7 import 'dart:math' show min; |
| 8 import 'optimizers.dart' show Pass; | 8 import 'optimizers.dart' show Pass; |
| 9 import 'cps_ir_nodes.dart'; | 9 import 'cps_ir_nodes.dart'; |
| 10 import '../elements/elements.dart'; | 10 import '../elements/elements.dart'; |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 67 // Create a new LetCont binding only this continuation. | 67 // Create a new LetCont binding only this continuation. |
| 68 let.continuations.remove(cont); | 68 let.continuations.remove(cont); |
| 69 let = new LetCont(cont, null); | 69 let = new LetCont(cont, null); |
| 70 } else { | 70 } else { |
| 71 let.remove(); // Reuse the existing LetCont. | 71 let.remove(); // Reuse the existing LetCont. |
| 72 } | 72 } |
| 73 let.insertAbove(use); | 73 let.insertAbove(use); |
| 74 } | 74 } |
| 75 | 75 |
| 76 Primitive unfoldInterceptor(Primitive prim) { | 76 Primitive unfoldInterceptor(Primitive prim) { |
| 77 return prim is Interceptor ? prim.input.definition : prim; | 77 return prim is Interceptor ? prim.input : prim; |
| 78 } | 78 } |
| 79 | 79 |
| 80 /// Sets [refined] to be the current refinement for its value, and pushes an | 80 /// Sets [refined] to be the current refinement for its value, and pushes an |
| 81 /// action that will restore the original scope again. | 81 /// action that will restore the original scope again. |
| 82 /// | 82 /// |
| 83 /// The refinement is inserted as the child of [insertionParent] if it has | 83 /// The refinement is inserted as the child of [insertionParent] if it has |
| 84 /// at least one use after its scope has been processed. | 84 /// at least one use after its scope has been processed. |
| 85 void applyRefinement(InteriorNode insertionParent, Refinement refined) { | 85 void applyRefinement(InteriorNode insertionParent, Refinement refined) { |
| 86 Primitive value = refined.effectiveDefinition; | 86 Primitive value = refined.effectiveDefinition; |
| 87 Primitive currentRefinement = refinementFor[value]; | 87 Primitive currentRefinement = refinementFor[value]; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 121 | 121 |
| 122 // Skip arguments that provide no refinement. | 122 // Skip arguments that provide no refinement. |
| 123 if (argSuccessType == types.dynamicType) continue; | 123 if (argSuccessType == types.dynamicType) continue; |
| 124 | 124 |
| 125 applyRefinement(node.parent, | 125 applyRefinement(node.parent, |
| 126 new Refinement(node.dartArgument(i), argSuccessType)); | 126 new Refinement(node.dartArgument(i), argSuccessType)); |
| 127 } | 127 } |
| 128 } | 128 } |
| 129 | 129 |
| 130 void visitInvokeStatic(InvokeStatic node) { | 130 void visitInvokeStatic(InvokeStatic node) { |
| 131 node.arguments.forEach(processReference); | 131 node.argumentRefs.forEach(processReference); |
| 132 _refineArguments(node, | 132 _refineArguments(node, |
| 133 _getSuccessTypesForStaticMethod(types, node.target)); | 133 _getSuccessTypesForStaticMethod(types, node.target)); |
| 134 } | 134 } |
| 135 | 135 |
| 136 void visitInvokeMethod(InvokeMethod node) { | 136 void visitInvokeMethod(InvokeMethod node) { |
| 137 // Update references to their current refined values. | 137 // Update references to their current refined values. |
| 138 processReference(node.receiver); | 138 processReference(node.receiverRef); |
| 139 node.arguments.forEach(processReference); | 139 node.argumentRefs.forEach(processReference); |
| 140 | 140 |
| 141 // If the call is intercepted, we want to refine the actual receiver, | 141 // If the call is intercepted, we want to refine the actual receiver, |
| 142 // not the interceptor. | 142 // not the interceptor. |
| 143 Primitive receiver = unfoldInterceptor(node.receiver.definition); | 143 Primitive receiver = unfoldInterceptor(node.receiver); |
| 144 | 144 |
| 145 // Do not try to refine the receiver of closure calls; the class world | 145 // Do not try to refine the receiver of closure calls; the class world |
| 146 // does not know about closure classes. | 146 // does not know about closure classes. |
| 147 Selector selector = node.selector; | 147 Selector selector = node.selector; |
| 148 if (!selector.isClosureCall) { | 148 if (!selector.isClosureCall) { |
| 149 // Filter away receivers that throw on this selector. | 149 // Filter away receivers that throw on this selector. |
| 150 TypeMask type = types.receiverTypeFor(selector, node.mask); | 150 TypeMask type = types.receiverTypeFor(selector, node.mask); |
| 151 Refinement refinement = new Refinement(receiver, type); | 151 Refinement refinement = new Refinement(receiver, type); |
| 152 LetPrim letPrim = node.parent; | 152 LetPrim letPrim = node.parent; |
| 153 applyRefinement(letPrim, refinement); | 153 applyRefinement(letPrim, refinement); |
| 154 | 154 |
| 155 // Refine arguments of methods on numbers which we know will throw on | 155 // Refine arguments of methods on numbers which we know will throw on |
| 156 // invalid argument values. | 156 // invalid argument values. |
| 157 _refineArguments(node, | 157 _refineArguments(node, |
| 158 _getSuccessTypesForInstanceMethod(types, type, selector)); | 158 _getSuccessTypesForInstanceMethod(types, type, selector)); |
| 159 } | 159 } |
| 160 } | 160 } |
| 161 | 161 |
| 162 void visitTypeCast(TypeCast node) { | 162 void visitTypeCast(TypeCast node) { |
| 163 Primitive value = node.value.definition; | 163 Primitive value = node.value; |
| 164 | 164 |
| 165 processReference(node.value); | 165 processReference(node.valueRef); |
| 166 node.typeArguments.forEach(processReference); | 166 node.typeArgumentRefs.forEach(processReference); |
| 167 | 167 |
| 168 // Refine the type of the input. | 168 // Refine the type of the input. |
| 169 TypeMask type = types.subtypesOf(node.dartType).nullable(); | 169 TypeMask type = types.subtypesOf(node.dartType).nullable(); |
| 170 Refinement refinement = new Refinement(value, type); | 170 Refinement refinement = new Refinement(value, type); |
| 171 LetPrim letPrim = node.parent; | 171 LetPrim letPrim = node.parent; |
| 172 applyRefinement(letPrim, refinement); | 172 applyRefinement(letPrim, refinement); |
| 173 } | 173 } |
| 174 | 174 |
| 175 void visitRefinement(Refinement node) { | 175 void visitRefinement(Refinement node) { |
| 176 // We found a pre-existing refinement node. These are generated by the | 176 // We found a pre-existing refinement node. These are generated by the |
| 177 // IR builder to hold information from --trust-type-annotations. | 177 // IR builder to hold information from --trust-type-annotations. |
| 178 // Update its input to use our own current refinement, then update the | 178 // Update its input to use our own current refinement, then update the |
| 179 // environment to use this refinement. | 179 // environment to use this refinement. |
| 180 processReference(node.value); | 180 processReference(node.value); |
| 181 Primitive value = node.value.definition.effectiveDefinition; | 181 Primitive value = node.value.definition.effectiveDefinition; |
| 182 Primitive oldRefinement = refinementFor[value]; | 182 Primitive oldRefinement = refinementFor[value]; |
| 183 refinementFor[value] = node; | 183 refinementFor[value] = node; |
| 184 pushAction(() { | 184 pushAction(() { |
| 185 refinementFor[value] = oldRefinement; | 185 refinementFor[value] = oldRefinement; |
| 186 }); | 186 }); |
| 187 } | 187 } |
| 188 | 188 |
| 189 bool isTrue(Primitive prim) { | 189 bool isTrue(Primitive prim) { |
| 190 return prim is Constant && prim.value.isTrue; | 190 return prim is Constant && prim.value.isTrue; |
| 191 } | 191 } |
| 192 | 192 |
| 193 void visitBranch(Branch node) { | 193 void visitBranch(Branch node) { |
| 194 processReference(node.condition); | 194 processReference(node.conditionRef); |
| 195 Primitive condition = node.condition.definition; | 195 Primitive condition = node.condition; |
| 196 | 196 |
| 197 Continuation trueCont = node.trueContinuation.definition; | 197 Continuation trueCont = node.trueContinuation; |
| 198 Continuation falseCont = node.falseContinuation.definition; | 198 Continuation falseCont = node.falseContinuation; |
| 199 | 199 |
| 200 // Sink both continuations to the Branch to ensure everything in scope | 200 // Sink both continuations to the Branch to ensure everything in scope |
| 201 // here is also in scope inside the continuations. | 201 // here is also in scope inside the continuations. |
| 202 sinkContinuationToUse(trueCont, node); | 202 sinkContinuationToUse(trueCont, node); |
| 203 sinkContinuationToUse(falseCont, node); | 203 sinkContinuationToUse(falseCont, node); |
| 204 | 204 |
| 205 // If the condition is an 'is' check, promote the checked value. | 205 // If the condition is an 'is' check, promote the checked value. |
| 206 if (condition is TypeTest) { | 206 if (condition is TypeTest) { |
| 207 Primitive value = condition.value.definition; | 207 Primitive value = condition.value; |
| 208 TypeMask type = types.subtypesOf(condition.dartType); | 208 TypeMask type = types.subtypesOf(condition.dartType); |
| 209 Primitive refinedValue = new Refinement(value, type); | 209 Primitive refinedValue = new Refinement(value, type); |
| 210 pushRefinement(trueCont, refinedValue); | 210 pushRefinement(trueCont, refinedValue); |
| 211 push(falseCont); | 211 push(falseCont); |
| 212 return; | 212 return; |
| 213 } | 213 } |
| 214 | 214 |
| 215 // If the condition is comparison with a constant, promote the other value. | 215 // If the condition is comparison with a constant, promote the other value. |
| 216 // This can happen either for calls to `==` or `identical` calls, such | 216 // This can happen either for calls to `==` or `identical` calls, such |
| 217 // as the ones inserted by the unsugaring pass. | 217 // as the ones inserted by the unsugaring pass. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 239 if (condition is InvokeMethod && condition.selector == Selectors.equals) { | 239 if (condition is InvokeMethod && condition.selector == Selectors.equals) { |
| 240 refineEquality(condition.dartReceiver, | 240 refineEquality(condition.dartReceiver, |
| 241 condition.dartArgument(0), | 241 condition.dartArgument(0), |
| 242 trueCont, | 242 trueCont, |
| 243 falseCont); | 243 falseCont); |
| 244 return; | 244 return; |
| 245 } | 245 } |
| 246 | 246 |
| 247 if (condition is ApplyBuiltinOperator && | 247 if (condition is ApplyBuiltinOperator && |
| 248 condition.operator == BuiltinOperator.Identical) { | 248 condition.operator == BuiltinOperator.Identical) { |
| 249 refineEquality(condition.arguments[0].definition, | 249 refineEquality(condition.argument(0), |
| 250 condition.arguments[1].definition, | 250 condition.argument(1), |
| 251 trueCont, | 251 trueCont, |
| 252 falseCont); | 252 falseCont); |
| 253 return; | 253 return; |
| 254 } | 254 } |
| 255 | 255 |
| 256 push(trueCont); | 256 push(trueCont); |
| 257 push(falseCont); | 257 push(falseCont); |
| 258 } | 258 } |
| 259 | 259 |
| 260 @override | 260 @override |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 426 case 'exp': | 426 case 'exp': |
| 427 case 'log': | 427 case 'log': |
| 428 return [types.numType]; | 428 return [types.numType]; |
| 429 case 'pow': | 429 case 'pow': |
| 430 return [types.numType, types.numType]; | 430 return [types.numType, types.numType]; |
| 431 } | 431 } |
| 432 } | 432 } |
| 433 | 433 |
| 434 return null; | 434 return null; |
| 435 } | 435 } |
| OLD | NEW |