| 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 | 
|---|