| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 universe.function_set; | 5 library universe.function_set; |
| 6 | 6 |
| 7 import '../common/names.dart' show Identifiers, Selectors; | 7 import '../common/names.dart' show Identifiers, Selectors; |
| 8 import '../compiler.dart' show Compiler; | 8 import '../compiler.dart' show Compiler; |
| 9 import '../elements/elements.dart'; | 9 import '../elements/elements.dart'; |
| 10 import '../types/types.dart'; | 10 import '../types/types.dart'; |
| 11 import '../util/util.dart' show Hashing, Setlet; | 11 import '../util/util.dart' show Hashing, Setlet; |
| 12 import '../world.dart' show ClassWorld; | 12 import '../world.dart' show ClosedWorld; |
| 13 import 'selector.dart' show Selector; | 13 import 'selector.dart' show Selector; |
| 14 import 'universe.dart' show ReceiverConstraint; | 14 import 'universe.dart' show ReceiverConstraint; |
| 15 | 15 |
| 16 // TODO(kasperl): This actually holds getters and setters just fine | 16 // TODO(kasperl): This actually holds getters and setters just fine |
| 17 // too and stricly they aren't functions. Maybe this needs a better | 17 // too and stricly they aren't functions. Maybe this needs a better |
| 18 // name -- something like ElementSet seems a bit too generic. | 18 // name -- something like ElementSet seems a bit too generic. |
| 19 class FunctionSet { | 19 class FunctionSet { |
| 20 final Compiler compiler; | 20 final Compiler compiler; |
| 21 final Map<String, FunctionSetNode> nodes = new Map<String, FunctionSetNode>(); | 21 final Map<String, FunctionSetNode> nodes = new Map<String, FunctionSetNode>(); |
| 22 FunctionSet(this.compiler); | 22 FunctionSet(this.compiler); |
| 23 | 23 |
| 24 ClassWorld get classWorld => compiler.closedWorld; | 24 ClosedWorld get closedWorld => compiler.closedWorld; |
| 25 | 25 |
| 26 FunctionSetNode newNode(String name) => new FunctionSetNode(name); | 26 FunctionSetNode newNode(String name) => new FunctionSetNode(name); |
| 27 | 27 |
| 28 void add(Element element) { | 28 void add(Element element) { |
| 29 assert(element.isInstanceMember); | 29 assert(element.isInstanceMember); |
| 30 assert(!element.isAbstract); | 30 assert(!element.isAbstract); |
| 31 String name = element.name; | 31 String name = element.name; |
| 32 FunctionSetNode node = nodes.putIfAbsent(name, () => newNode(name)); | 32 FunctionSetNode node = nodes.putIfAbsent(name, () => newNode(name)); |
| 33 node.add(element); | 33 node.add(element); |
| 34 } | 34 } |
| (...skipping 22 matching lines...) Expand all Loading... |
| 57 return query(selector, constraint).functions; | 57 return query(selector, constraint).functions; |
| 58 } | 58 } |
| 59 | 59 |
| 60 /// Returns the mask for the potential receivers of a dynamic call to | 60 /// Returns the mask for the potential receivers of a dynamic call to |
| 61 /// [selector] on [constraint]. | 61 /// [selector] on [constraint]. |
| 62 /// | 62 /// |
| 63 /// This will narrow the constraints of [constraint] to a [TypeMask] of the | 63 /// This will narrow the constraints of [constraint] to a [TypeMask] of the |
| 64 /// set of classes that actually implement the selected member or implement | 64 /// set of classes that actually implement the selected member or implement |
| 65 /// the handling 'noSuchMethod' where the selected member is unimplemented. | 65 /// the handling 'noSuchMethod' where the selected member is unimplemented. |
| 66 TypeMask receiverType(Selector selector, ReceiverConstraint constraint) { | 66 TypeMask receiverType(Selector selector, ReceiverConstraint constraint) { |
| 67 return query(selector, constraint).computeMask(classWorld); | 67 return query(selector, constraint).computeMask(closedWorld); |
| 68 } | 68 } |
| 69 | 69 |
| 70 SelectorMask _createSelectorMask( | 70 SelectorMask _createSelectorMask(Selector selector, |
| 71 Selector selector, ReceiverConstraint constraint, ClassWorld classWorld) { | 71 ReceiverConstraint constraint, ClosedWorld closedWorld) { |
| 72 return constraint != null | 72 return constraint != null |
| 73 ? new SelectorMask(selector, constraint) | 73 ? new SelectorMask(selector, constraint) |
| 74 : new SelectorMask( | 74 : new SelectorMask( |
| 75 selector, | 75 selector, |
| 76 new TypeMask.subclass( | 76 new TypeMask.subclass( |
| 77 classWorld.coreClasses.objectClass, classWorld)); | 77 closedWorld.coreClasses.objectClass, closedWorld)); |
| 78 } | 78 } |
| 79 | 79 |
| 80 /// Returns the set of functions that can be the target of a call to | 80 /// Returns the set of functions that can be the target of a call to |
| 81 /// [selector] on a receiver constrained by [constraint] including | 81 /// [selector] on a receiver constrained by [constraint] including |
| 82 /// 'noSuchMethod' methods where applicable. | 82 /// 'noSuchMethod' methods where applicable. |
| 83 FunctionSetQuery query(Selector selector, ReceiverConstraint constraint) { | 83 FunctionSetQuery query(Selector selector, ReceiverConstraint constraint) { |
| 84 String name = selector.name; | 84 String name = selector.name; |
| 85 SelectorMask selectorMask = | 85 SelectorMask selectorMask = |
| 86 _createSelectorMask(selector, constraint, classWorld); | 86 _createSelectorMask(selector, constraint, closedWorld); |
| 87 SelectorMask noSuchMethodMask = | 87 SelectorMask noSuchMethodMask = |
| 88 new SelectorMask(Selectors.noSuchMethod_, selectorMask.constraint); | 88 new SelectorMask(Selectors.noSuchMethod_, selectorMask.constraint); |
| 89 FunctionSetNode node = nodes[name]; | 89 FunctionSetNode node = nodes[name]; |
| 90 FunctionSetNode noSuchMethods = nodes[Identifiers.noSuchMethod_]; | 90 FunctionSetNode noSuchMethods = nodes[Identifiers.noSuchMethod_]; |
| 91 if (node != null) { | 91 if (node != null) { |
| 92 return node.query( | 92 return node.query( |
| 93 selectorMask, classWorld, noSuchMethods, noSuchMethodMask); | 93 selectorMask, closedWorld, noSuchMethods, noSuchMethodMask); |
| 94 } | 94 } |
| 95 // If there is no method that matches [selector] we know we can | 95 // If there is no method that matches [selector] we know we can |
| 96 // only hit [:noSuchMethod:]. | 96 // only hit [:noSuchMethod:]. |
| 97 if (noSuchMethods == null) { | 97 if (noSuchMethods == null) { |
| 98 return const EmptyFunctionSetQuery(); | 98 return const EmptyFunctionSetQuery(); |
| 99 } | 99 } |
| 100 return noSuchMethods.query(noSuchMethodMask, classWorld); | 100 return noSuchMethods.query(noSuchMethodMask, closedWorld); |
| 101 } | 101 } |
| 102 | 102 |
| 103 void forEach(Function action) { | 103 void forEach(Function action) { |
| 104 nodes.forEach((String name, FunctionSetNode node) { | 104 nodes.forEach((String name, FunctionSetNode node) { |
| 105 node.forEach(action); | 105 node.forEach(action); |
| 106 }); | 106 }); |
| 107 } | 107 } |
| 108 } | 108 } |
| 109 | 109 |
| 110 /// A selector/constraint pair representing the dynamic invocation of [selector] | 110 /// A selector/constraint pair representing the dynamic invocation of [selector] |
| 111 /// on a receiver constrained by [constraint]. | 111 /// on a receiver constrained by [constraint]. |
| 112 class SelectorMask { | 112 class SelectorMask { |
| 113 final Selector selector; | 113 final Selector selector; |
| 114 final ReceiverConstraint constraint; | 114 final ReceiverConstraint constraint; |
| 115 final int hashCode; | 115 final int hashCode; |
| 116 | 116 |
| 117 SelectorMask(Selector selector, ReceiverConstraint constraint) | 117 SelectorMask(Selector selector, ReceiverConstraint constraint) |
| 118 : this.selector = selector, | 118 : this.selector = selector, |
| 119 this.constraint = constraint, | 119 this.constraint = constraint, |
| 120 this.hashCode = | 120 this.hashCode = |
| 121 Hashing.mixHashCodeBits(selector.hashCode, constraint.hashCode) { | 121 Hashing.mixHashCodeBits(selector.hashCode, constraint.hashCode) { |
| 122 assert(constraint != null); | 122 assert(constraint != null); |
| 123 } | 123 } |
| 124 | 124 |
| 125 String get name => selector.name; | 125 String get name => selector.name; |
| 126 | 126 |
| 127 bool applies(Element element, ClassWorld classWorld) { | 127 bool applies(Element element, ClosedWorld closedWorld) { |
| 128 if (!selector.appliesUnnamed(element, classWorld.backend)) return false; | 128 if (!selector.appliesUnnamed(element, closedWorld.backend)) return false; |
| 129 return constraint.canHit(element, selector, classWorld); | 129 return constraint.canHit(element, selector, closedWorld); |
| 130 } | 130 } |
| 131 | 131 |
| 132 bool needsNoSuchMethodHandling(ClassWorld classWorld) { | 132 bool needsNoSuchMethodHandling(ClosedWorld closedWorld) { |
| 133 return constraint.needsNoSuchMethodHandling(selector, classWorld); | 133 return constraint.needsNoSuchMethodHandling(selector, closedWorld); |
| 134 } | 134 } |
| 135 | 135 |
| 136 bool operator ==(other) { | 136 bool operator ==(other) { |
| 137 if (identical(this, other)) return true; | 137 if (identical(this, other)) return true; |
| 138 return selector == other.selector && constraint == other.constraint; | 138 return selector == other.selector && constraint == other.constraint; |
| 139 } | 139 } |
| 140 | 140 |
| 141 String toString() => '($selector,$constraint)'; | 141 String toString() => '($selector,$constraint)'; |
| 142 } | 142 } |
| 143 | 143 |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 198 assert(element.name == name); | 198 assert(element.name == name); |
| 199 return elements.contains(element); | 199 return elements.contains(element); |
| 200 } | 200 } |
| 201 | 201 |
| 202 void forEach(Function action) { | 202 void forEach(Function action) { |
| 203 elements.forEach(action); | 203 elements.forEach(action); |
| 204 } | 204 } |
| 205 | 205 |
| 206 /// Returns the set of functions that can be the target of [selectorMask] | 206 /// Returns the set of functions that can be the target of [selectorMask] |
| 207 /// including no such method handling where applicable. | 207 /// including no such method handling where applicable. |
| 208 FunctionSetQuery query(SelectorMask selectorMask, ClassWorld classWorld, | 208 FunctionSetQuery query(SelectorMask selectorMask, ClosedWorld closedWorld, |
| 209 [FunctionSetNode noSuchMethods, SelectorMask noSuchMethodMask]) { | 209 [FunctionSetNode noSuchMethods, SelectorMask noSuchMethodMask]) { |
| 210 assert(selectorMask.name == name); | 210 assert(selectorMask.name == name); |
| 211 FunctionSetQuery result = cache[selectorMask]; | 211 FunctionSetQuery result = cache[selectorMask]; |
| 212 if (result != null) return result; | 212 if (result != null) return result; |
| 213 | 213 |
| 214 Setlet<Element> functions; | 214 Setlet<Element> functions; |
| 215 for (Element element in elements) { | 215 for (Element element in elements) { |
| 216 if (selectorMask.applies(element, classWorld)) { | 216 if (selectorMask.applies(element, closedWorld)) { |
| 217 if (functions == null) { | 217 if (functions == null) { |
| 218 // Defer the allocation of the functions set until we are | 218 // Defer the allocation of the functions set until we are |
| 219 // sure we need it. This allows us to return immutable empty | 219 // sure we need it. This allows us to return immutable empty |
| 220 // lists when the filtering produced no results. | 220 // lists when the filtering produced no results. |
| 221 functions = new Setlet<Element>(); | 221 functions = new Setlet<Element>(); |
| 222 } | 222 } |
| 223 functions.add(element); | 223 functions.add(element); |
| 224 } | 224 } |
| 225 } | 225 } |
| 226 | 226 |
| 227 // If we cannot ensure a method will be found at runtime, we also | 227 // If we cannot ensure a method will be found at runtime, we also |
| 228 // add [noSuchMethod] implementations that apply to [mask] as | 228 // add [noSuchMethod] implementations that apply to [mask] as |
| 229 // potential targets. | 229 // potential targets. |
| 230 if (noSuchMethods != null && | 230 if (noSuchMethods != null && |
| 231 selectorMask.needsNoSuchMethodHandling(classWorld)) { | 231 selectorMask.needsNoSuchMethodHandling(closedWorld)) { |
| 232 FunctionSetQuery noSuchMethodQuery = | 232 FunctionSetQuery noSuchMethodQuery = |
| 233 noSuchMethods.query(noSuchMethodMask, classWorld); | 233 noSuchMethods.query(noSuchMethodMask, closedWorld); |
| 234 if (!noSuchMethodQuery.functions.isEmpty) { | 234 if (!noSuchMethodQuery.functions.isEmpty) { |
| 235 if (functions == null) { | 235 if (functions == null) { |
| 236 functions = new Setlet<Element>.from(noSuchMethodQuery.functions); | 236 functions = new Setlet<Element>.from(noSuchMethodQuery.functions); |
| 237 } else { | 237 } else { |
| 238 functions.addAll(noSuchMethodQuery.functions); | 238 functions.addAll(noSuchMethodQuery.functions); |
| 239 } | 239 } |
| 240 } | 240 } |
| 241 } | 241 } |
| 242 cache[selectorMask] = result = (functions != null) | 242 cache[selectorMask] = result = (functions != null) |
| 243 ? new FullFunctionSetQuery(functions) | 243 ? new FullFunctionSetQuery(functions) |
| 244 : const EmptyFunctionSetQuery(); | 244 : const EmptyFunctionSetQuery(); |
| 245 return result; | 245 return result; |
| 246 } | 246 } |
| 247 } | 247 } |
| 248 | 248 |
| 249 /// A set of functions that are the potential targets of all call sites sharing | 249 /// A set of functions that are the potential targets of all call sites sharing |
| 250 /// the same receiver mask and selector. | 250 /// the same receiver mask and selector. |
| 251 abstract class FunctionSetQuery { | 251 abstract class FunctionSetQuery { |
| 252 const FunctionSetQuery(); | 252 const FunctionSetQuery(); |
| 253 | 253 |
| 254 /// Compute the type of all potential receivers of this function set. | 254 /// Compute the type of all potential receivers of this function set. |
| 255 TypeMask computeMask(ClassWorld classWorld); | 255 TypeMask computeMask(ClosedWorld closedWorld); |
| 256 | 256 |
| 257 /// Returns all potential targets of this function set. | 257 /// Returns all potential targets of this function set. |
| 258 Iterable<Element> get functions; | 258 Iterable<Element> get functions; |
| 259 } | 259 } |
| 260 | 260 |
| 261 class EmptyFunctionSetQuery implements FunctionSetQuery { | 261 class EmptyFunctionSetQuery implements FunctionSetQuery { |
| 262 const EmptyFunctionSetQuery(); | 262 const EmptyFunctionSetQuery(); |
| 263 | 263 |
| 264 @override | 264 @override |
| 265 TypeMask computeMask(ClassWorld classWorld) => const TypeMask.nonNullEmpty(); | 265 TypeMask computeMask(ClosedWorld closedWorld) => |
| 266 const TypeMask.nonNullEmpty(); |
| 266 | 267 |
| 267 @override | 268 @override |
| 268 Iterable<Element> get functions => const <Element>[]; | 269 Iterable<Element> get functions => const <Element>[]; |
| 269 } | 270 } |
| 270 | 271 |
| 271 class FullFunctionSetQuery implements FunctionSetQuery { | 272 class FullFunctionSetQuery implements FunctionSetQuery { |
| 272 @override | 273 @override |
| 273 final Iterable<Element> functions; | 274 final Iterable<Element> functions; |
| 274 | 275 |
| 275 TypeMask _mask; | 276 TypeMask _mask; |
| 276 | 277 |
| 277 FullFunctionSetQuery(this.functions); | 278 FullFunctionSetQuery(this.functions); |
| 278 | 279 |
| 279 @override | 280 @override |
| 280 TypeMask computeMask(ClassWorld classWorld) { | 281 TypeMask computeMask(ClosedWorld closedWorld) { |
| 281 assert(classWorld.hasAnyStrictSubclass(classWorld.coreClasses.objectClass)); | 282 assert( |
| 283 closedWorld.hasAnyStrictSubclass(closedWorld.coreClasses.objectClass)); |
| 282 if (_mask != null) return _mask; | 284 if (_mask != null) return _mask; |
| 283 return _mask = new TypeMask.unionOf( | 285 return _mask = new TypeMask.unionOf( |
| 284 functions.expand((element) { | 286 functions.expand((element) { |
| 285 ClassElement cls = element.enclosingClass; | 287 ClassElement cls = element.enclosingClass; |
| 286 return [cls]..addAll(classWorld.mixinUsesOf(cls)); | 288 return [cls]..addAll(closedWorld.mixinUsesOf(cls)); |
| 287 }).map((cls) { | 289 }).map((cls) { |
| 288 if (classWorld.backend.isNullImplementation(cls)) { | 290 if (closedWorld.backend.isNullImplementation(cls)) { |
| 289 return const TypeMask.empty(); | 291 return const TypeMask.empty(); |
| 290 } else if (classWorld.isInstantiated(cls.declaration)) { | 292 } else if (closedWorld.isInstantiated(cls.declaration)) { |
| 291 return new TypeMask.nonNullSubclass(cls.declaration, classWorld); | 293 return new TypeMask.nonNullSubclass(cls.declaration, closedWorld); |
| 292 } else { | 294 } else { |
| 293 // TODO(johnniwinther): Avoid the need for this case. | 295 // TODO(johnniwinther): Avoid the need for this case. |
| 294 return const TypeMask.empty(); | 296 return const TypeMask.empty(); |
| 295 } | 297 } |
| 296 }), | 298 }), |
| 297 classWorld); | 299 closedWorld); |
| 298 } | 300 } |
| 299 } | 301 } |
| OLD | NEW |