| 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.optimize_interceptors; | 5 library dart2js.cps_ir.optimize_interceptors; |
| 6 | 6 |
| 7 import 'optimizers.dart'; | 7 import 'optimizers.dart'; |
| 8 import 'cps_ir_nodes.dart'; | 8 import 'cps_ir_nodes.dart'; |
| 9 import 'loop_hierarchy.dart'; | 9 import 'loop_hierarchy.dart'; |
| 10 import 'cps_fragment.dart'; | 10 import 'cps_fragment.dart'; |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 97 } | 97 } |
| 98 return prim; | 98 return prim; |
| 99 } | 99 } |
| 100 | 100 |
| 101 void computeInterceptedClasses(Interceptor interceptor) { | 101 void computeInterceptedClasses(Interceptor interceptor) { |
| 102 Set<ClassElement> intercepted = interceptor.interceptedClasses; | 102 Set<ClassElement> intercepted = interceptor.interceptedClasses; |
| 103 intercepted.clear(); | 103 intercepted.clear(); |
| 104 for (Reference ref = interceptor.firstRef; ref != null; ref = ref.next) { | 104 for (Reference ref = interceptor.firstRef; ref != null; ref = ref.next) { |
| 105 Node use = ref.parent; | 105 Node use = ref.parent; |
| 106 if (use is InvokeMethod) { | 106 if (use is InvokeMethod) { |
| 107 TypeMask type = use.dartReceiver.type; | 107 TypeMask type = use.receiver.type; |
| 108 bool canOccurAsReceiver(ClassElement elem) { | 108 bool canOccurAsReceiver(ClassElement elem) { |
| 109 return classWorld.isInstantiated(elem) && | 109 return classWorld.isInstantiated(elem) && |
| 110 !typeSystem.areDisjoint(type, | 110 !typeSystem.areDisjoint(type, |
| 111 typeSystem.getInterceptorSubtypes(elem)); | 111 typeSystem.getInterceptorSubtypes(elem)); |
| 112 } | 112 } |
| 113 Iterable<ClassElement> classes = | 113 Iterable<ClassElement> classes = |
| 114 backend.getInterceptedClassesOn(use.selector.name); | 114 backend.getInterceptedClassesOn(use.selector.name); |
| 115 intercepted.addAll(classes.where(canOccurAsReceiver)); | 115 intercepted.addAll(classes.where(canOccurAsReceiver)); |
| 116 } else { | 116 } else { |
| 117 intercepted.clear(); | 117 intercepted.clear(); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 130 | 130 |
| 131 /// True if [node] may return [JSNumber] instead of [JSInt] or [JSDouble]. | 131 /// True if [node] may return [JSNumber] instead of [JSInt] or [JSDouble]. |
| 132 bool jsNumberClassSuffices(Interceptor node) { | 132 bool jsNumberClassSuffices(Interceptor node) { |
| 133 // No methods on JSNumber call 'down' to methods on JSInt or JSDouble. If | 133 // No methods on JSNumber call 'down' to methods on JSInt or JSDouble. If |
| 134 // all uses of the interceptor are for methods is defined only on JSNumber | 134 // all uses of the interceptor are for methods is defined only on JSNumber |
| 135 // then JSNumber will suffice in place of choosing between JSInt or | 135 // then JSNumber will suffice in place of choosing between JSInt or |
| 136 // JSDouble. | 136 // JSDouble. |
| 137 for (Reference ref = node.firstRef; ref != null; ref = ref.next) { | 137 for (Reference ref = node.firstRef; ref != null; ref = ref.next) { |
| 138 if (ref.parent is InvokeMethod) { | 138 if (ref.parent is InvokeMethod) { |
| 139 InvokeMethod invoke = ref.parent; | 139 InvokeMethod invoke = ref.parent; |
| 140 if (invoke.receiverRef != ref) return false; | 140 if (invoke.interceptorRef != ref) return false; |
| 141 var interceptedClasses = | 141 var interceptedClasses = |
| 142 backend.getInterceptedClassesOn(invoke.selector.name); | 142 backend.getInterceptedClassesOn(invoke.selector.name); |
| 143 if (interceptedClasses.contains(helpers.jsDoubleClass)) return false; | 143 if (interceptedClasses.contains(helpers.jsDoubleClass)) return false; |
| 144 if (interceptedClasses.contains(helpers.jsIntClass)) return false; | 144 if (interceptedClasses.contains(helpers.jsIntClass)) return false; |
| 145 continue; | 145 continue; |
| 146 } | 146 } |
| 147 // Other uses need full distinction. | 147 // Other uses need full distinction. |
| 148 return false; | 148 return false; |
| 149 } | 149 } |
| 150 return true; | 150 return true; |
| 151 } | 151 } |
| 152 | 152 |
| 153 /// True if [node] can intercept a `null` value and return the [JSNull] | 153 /// True if [node] can intercept a `null` value and return the [JSNull] |
| 154 /// interceptor. | 154 /// interceptor. |
| 155 bool canInterceptNull(Interceptor node) { | 155 bool canInterceptNull(Interceptor node) { |
| 156 for (Reference ref = node.firstRef; ref != null; ref = ref.next) { | 156 for (Reference ref = node.firstRef; ref != null; ref = ref.next) { |
| 157 Node use = ref.parent; | 157 Node use = ref.parent; |
| 158 if (use is InvokeMethod) { | 158 if (use is InvokeMethod) { |
| 159 if (selectorsOnNull.contains(use.selector) && | 159 if (selectorsOnNull.contains(use.selector) && |
| 160 use.dartReceiver.type.isNullable) { | 160 use.receiver.type.isNullable) { |
| 161 return true; | 161 return true; |
| 162 } | 162 } |
| 163 } else { | 163 } else { |
| 164 return true; | 164 return true; |
| 165 } | 165 } |
| 166 } | 166 } |
| 167 return false; | 167 return false; |
| 168 } | 168 } |
| 169 | 169 |
| 170 /// Returns the only interceptor class that may be returned by [node], or | 170 /// Returns the only interceptor class that may be returned by [node], or |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 254 if (node.hasExactlyOneUse) { | 254 if (node.hasExactlyOneUse) { |
| 255 // Set the loop header on single-use interceptors so [visitInvokeMethod] | 255 // Set the loop header on single-use interceptors so [visitInvokeMethod] |
| 256 // can determine if it should become a one-shot interceptor. | 256 // can determine if it should become a one-shot interceptor. |
| 257 loopHeaderFor[node] = currentLoopHeader; | 257 loopHeaderFor[node] = currentLoopHeader; |
| 258 } | 258 } |
| 259 } | 259 } |
| 260 | 260 |
| 261 @override | 261 @override |
| 262 void visitInvokeMethod(InvokeMethod node) { | 262 void visitInvokeMethod(InvokeMethod node) { |
| 263 if (node.callingConvention != CallingConvention.Intercepted) return; | 263 if (node.callingConvention != CallingConvention.Intercepted) return; |
| 264 Primitive interceptor = node.receiver; | 264 Primitive interceptor = node.interceptor; |
| 265 if (interceptor is! Interceptor || | 265 if (interceptor is! Interceptor || |
| 266 interceptor.hasMultipleUses || | 266 interceptor.hasMultipleUses || |
| 267 loopHeaderFor[interceptor] != currentLoopHeader) { | 267 loopHeaderFor[interceptor] != currentLoopHeader) { |
| 268 return; | 268 return; |
| 269 } | 269 } |
| 270 // TODO(asgerf): Consider heuristics for when to use one-shot interceptors. | 270 // TODO(asgerf): Consider heuristics for when to use one-shot interceptors. |
| 271 // E.g. using only one-shot interceptors with a fast path. | 271 // E.g. using only one-shot interceptors with a fast path. |
| 272 node.callingConvention = CallingConvention.OneShotIntercepted; | 272 node.makeOneShotIntercepted(); |
| 273 node..receiverRef.unlink()..receiverRef = node.argumentRefs.removeAt(0); | |
| 274 } | 273 } |
| 275 | 274 |
| 276 @override | 275 @override |
| 277 void visitTypeTestViaFlag(TypeTestViaFlag node) { | 276 void visitTypeTestViaFlag(TypeTestViaFlag node) { |
| 278 Primitive interceptor = node.interceptor; | 277 Primitive interceptor = node.interceptor; |
| 279 if (interceptor is! Interceptor || | 278 if (interceptor is! Interceptor || |
| 280 interceptor.hasMultipleUses || | 279 interceptor.hasMultipleUses || |
| 281 loopHeaderFor[interceptor] != currentLoopHeader || | 280 loopHeaderFor[interceptor] != currentLoopHeader || |
| 282 !backend.mayGenerateInstanceofCheck(node.dartType)) { | 281 !backend.mayGenerateInstanceofCheck(node.dartType)) { |
| 283 return; | 282 return; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 314 sharedConstantFor.remove(prim.value); | 313 sharedConstantFor.remove(prim.value); |
| 315 }); | 314 }); |
| 316 } | 315 } |
| 317 return next; | 316 return next; |
| 318 } | 317 } |
| 319 | 318 |
| 320 bool shouldShareConstant(Constant constant) { | 319 bool shouldShareConstant(Constant constant) { |
| 321 return constant.value.isInterceptor; | 320 return constant.value.isInterceptor; |
| 322 } | 321 } |
| 323 } | 322 } |
| OLD | NEW |