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 |