| 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 part of universe; | 5 part of universe; |
| 6 | 6 |
| 7 // TODO(kasperl): This actually holds getters and setters just fine | 7 // TODO(kasperl): This actually holds getters and setters just fine |
| 8 // too and stricly they aren't functions. Maybe this needs a better | 8 // too and stricly they aren't functions. Maybe this needs a better |
| 9 // name -- something like ElementSet seems a bit too generic. | 9 // name -- something like ElementSet seems a bit too generic. |
| 10 class FunctionSet { | 10 class FunctionSet { |
| 11 final Compiler compiler; | 11 final Compiler compiler; |
| 12 final Map<String, FunctionSetNode> nodes = | 12 final Map<String, FunctionSetNode> nodes = |
| 13 new Map<String, FunctionSetNode>(); | 13 new Map<String, FunctionSetNode>(); |
| 14 FunctionSet(this.compiler); | 14 FunctionSet(this.compiler); |
| 15 | 15 |
| 16 ClassWorld get classWorld => compiler.world; |
| 17 |
| 16 FunctionSetNode newNode(String name) | 18 FunctionSetNode newNode(String name) |
| 17 => new FunctionSetNode(name); | 19 => new FunctionSetNode(name); |
| 18 | 20 |
| 19 void add(Element element) { | 21 void add(Element element) { |
| 20 assert(element.isInstanceMember); | 22 assert(element.isInstanceMember); |
| 21 assert(!element.isAbstract); | 23 assert(!element.isAbstract); |
| 22 String name = element.name; | 24 String name = element.name; |
| 23 FunctionSetNode node = nodes.putIfAbsent(name, () => newNode(name)); | 25 FunctionSetNode node = nodes.putIfAbsent(name, () => newNode(name)); |
| 24 node.add(element); | 26 node.add(element); |
| 25 } | 27 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 37 bool contains(Element element) { | 39 bool contains(Element element) { |
| 38 assert(element.isInstanceMember); | 40 assert(element.isInstanceMember); |
| 39 assert(!element.isAbstract); | 41 assert(!element.isAbstract); |
| 40 String name = element.name; | 42 String name = element.name; |
| 41 FunctionSetNode node = nodes[name]; | 43 FunctionSetNode node = nodes[name]; |
| 42 return (node != null) | 44 return (node != null) |
| 43 ? node.contains(element) | 45 ? node.contains(element) |
| 44 : false; | 46 : false; |
| 45 } | 47 } |
| 46 | 48 |
| 47 /** | 49 /// Returns an object that allows iterating over all the functions |
| 48 * Returns an object that allows iterating over all the functions | 50 /// that may be invoked with the given [selector]. |
| 49 * that may be invoked with the given [selector]. | |
| 50 */ | |
| 51 Iterable<Element> filter(Selector selector, TypeMask mask) { | 51 Iterable<Element> filter(Selector selector, TypeMask mask) { |
| 52 return query(selector, mask).functions; | 52 return query(selector, mask).functions; |
| 53 } | 53 } |
| 54 | 54 |
| 55 /// Returns the mask for the potential receivers of a dynamic call to |
| 56 /// [selector] on [mask]. |
| 57 /// |
| 58 /// This will reduce the set of classes in [mask] to a [TypeMask] of the set |
| 59 /// of classes that actually implement the selected member or implement the |
| 60 /// handling 'noSuchMethod' where the selected member is unimplemented. |
| 55 TypeMask receiverType(Selector selector, TypeMask mask) { | 61 TypeMask receiverType(Selector selector, TypeMask mask) { |
| 56 return query(selector, mask).computeMask(compiler.world); | 62 return query(selector, mask).computeMask(classWorld); |
| 57 } | 63 } |
| 58 | 64 |
| 65 SelectorMask _createSelectorMask( |
| 66 Selector selector, TypeMask mask, ClassWorld classWorld) { |
| 67 return mask != null |
| 68 ? new SelectorMask(selector, mask) |
| 69 : new SelectorMask(selector, |
| 70 new TypeMask.subclass(classWorld.objectClass, classWorld)); |
| 71 } |
| 72 |
| 73 /// Returns the set of functions that can be the target of a call to |
| 74 /// [selector] on a receiver of type [mask] including 'noSuchMethod' methods |
| 75 /// where applicable. |
| 59 FunctionSetQuery query(Selector selector, TypeMask mask) { | 76 FunctionSetQuery query(Selector selector, TypeMask mask) { |
| 60 String name = selector.name; | 77 String name = selector.name; |
| 78 SelectorMask selectorMask = _createSelectorMask(selector, mask, classWorld); |
| 79 SelectorMask noSuchMethodMask = |
| 80 new SelectorMask(Selectors.noSuchMethod_, selectorMask.mask); |
| 61 FunctionSetNode node = nodes[name]; | 81 FunctionSetNode node = nodes[name]; |
| 62 FunctionSetNode noSuchMethods = nodes[Identifiers.noSuchMethod_]; | 82 FunctionSetNode noSuchMethods = nodes[Identifiers.noSuchMethod_]; |
| 63 if (node != null) { | 83 if (node != null) { |
| 64 return node.query(selector, mask, compiler, noSuchMethods); | 84 return node.query( |
| 85 selectorMask, classWorld, noSuchMethods, noSuchMethodMask); |
| 65 } | 86 } |
| 66 // If there is no method that matches [selector] we know we can | 87 // If there is no method that matches [selector] we know we can |
| 67 // only hit [:noSuchMethod:]. | 88 // only hit [:noSuchMethod:]. |
| 68 if (noSuchMethods == null) return const FunctionSetQuery(const <Element>[]); | 89 if (noSuchMethods == null) { |
| 69 return noSuchMethods.query( | 90 return const EmptyFunctionSetQuery(); |
| 70 Selectors.noSuchMethod_, mask, compiler, null); | 91 } |
| 92 return noSuchMethods.query(noSuchMethodMask, classWorld); |
| 71 } | 93 } |
| 72 | 94 |
| 73 void forEach(Function action) { | 95 void forEach(Function action) { |
| 74 nodes.forEach((String name, FunctionSetNode node) { | 96 nodes.forEach((String name, FunctionSetNode node) { |
| 75 node.forEach(action); | 97 node.forEach(action); |
| 76 }); | 98 }); |
| 77 } | 99 } |
| 78 } | 100 } |
| 79 | 101 |
| 102 /// A selector/mask pair representing the dynamic invocation of [selector] on |
| 103 /// a receiver of type [mask]. |
| 80 class SelectorMask { | 104 class SelectorMask { |
| 81 final Selector selector; | 105 final Selector selector; |
| 82 final TypeMask mask; | 106 final TypeMask mask; |
| 83 final int hashCode; | 107 final int hashCode; |
| 84 | 108 |
| 85 SelectorMask(Selector selector, TypeMask mask) | 109 SelectorMask(Selector selector, TypeMask mask) |
| 86 : this.selector = selector, | 110 : this.selector = selector, |
| 87 this.mask = mask, | 111 this.mask = mask, |
| 88 this.hashCode = | 112 this.hashCode = |
| 89 Hashing.mixHashCodeBits(selector.hashCode, mask.hashCode); | 113 Hashing.mixHashCodeBits(selector.hashCode, mask.hashCode) { |
| 114 assert(mask != null); |
| 115 } |
| 90 | 116 |
| 91 String get name => selector.name; | 117 String get name => selector.name; |
| 92 | 118 |
| 93 bool applies(Element element, ClassWorld classWorld) { | 119 bool applies(Element element, ClassWorld classWorld) { |
| 94 if (!selector.appliesUnnamed(element, classWorld)) return false; | 120 if (!selector.appliesUnnamed(element, classWorld)) return false; |
| 95 if (mask == null) return true; | |
| 96 return mask.canHit(element, selector, classWorld); | 121 return mask.canHit(element, selector, classWorld); |
| 97 } | 122 } |
| 98 | 123 |
| 124 bool needsNoSuchMethodHandling(ClassWorld classWorld) { |
| 125 return mask.needsNoSuchMethodHandling(selector, classWorld); |
| 126 } |
| 127 |
| 99 bool operator ==(other) { | 128 bool operator ==(other) { |
| 100 if (identical(this, other)) return true; | 129 if (identical(this, other)) return true; |
| 101 return selector == other.selector && mask == other.mask; | 130 return selector == other.selector && mask == other.mask; |
| 102 } | 131 } |
| 103 | 132 |
| 104 String toString() => '($selector,$mask)'; | 133 String toString() => '($selector,$mask)'; |
| 105 } | 134 } |
| 106 | 135 |
| 136 /// A node in the [FunctionSet] caching all [FunctionSetQuery] object for |
| 137 /// selectors with the same [name]. |
| 107 class FunctionSetNode { | 138 class FunctionSetNode { |
| 108 final String name; | 139 final String name; |
| 109 final Map<SelectorMask, FunctionSetQuery> cache = | 140 final Map<SelectorMask, FunctionSetQuery> cache = |
| 110 <SelectorMask, FunctionSetQuery>{}; | 141 <SelectorMask, FunctionSetQuery>{}; |
| 111 | 142 |
| 112 // Initially, we keep the elements in a list because it is more | 143 // Initially, we keep the elements in a list because it is more |
| 113 // compact than a hash set. Once we get enough elements, we change | 144 // compact than a hash set. Once we get enough elements, we change |
| 114 // the representation to be a set to get faster contains checks. | 145 // the representation to be a set to get faster contains checks. |
| 115 static const int MAX_ELEMENTS_IN_LIST = 8; | 146 static const int MAX_ELEMENTS_IN_LIST = 8; |
| 116 var elements = <Element>[]; | 147 var elements = <Element>[]; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 157 | 188 |
| 158 bool contains(Element element) { | 189 bool contains(Element element) { |
| 159 assert(element.name == name); | 190 assert(element.name == name); |
| 160 return elements.contains(element); | 191 return elements.contains(element); |
| 161 } | 192 } |
| 162 | 193 |
| 163 void forEach(Function action) { | 194 void forEach(Function action) { |
| 164 elements.forEach(action); | 195 elements.forEach(action); |
| 165 } | 196 } |
| 166 | 197 |
| 167 TypeMask getNonNullTypeMaskOfSelector(TypeMask mask, ClassWorld classWorld) { | 198 /// Returns the set of functions that can be the target of [selectorMask] |
| 168 // TODO(ngeoffray): We should probably change untyped selector | 199 /// including no such method handling where applicable. |
| 169 // to always be a subclass of Object. | 200 FunctionSetQuery query(SelectorMask selectorMask, |
| 170 return mask != null | 201 ClassWorld classWorld, |
| 171 ? mask | 202 [FunctionSetNode noSuchMethods, |
| 172 : new TypeMask.subclass(classWorld.objectClass, classWorld); | 203 SelectorMask noSuchMethodMask]) { |
| 173 } | 204 assert(selectorMask.name == name); |
| 174 | |
| 175 // TODO(johnniwinther): Use [SelectorMask] instead of [Selector] and | |
| 176 // [TypeMask]. | |
| 177 FunctionSetQuery query(Selector selector, | |
| 178 TypeMask mask, | |
| 179 Compiler compiler, | |
| 180 FunctionSetNode noSuchMethods) { | |
| 181 mask = getNonNullTypeMaskOfSelector(mask, compiler.world); | |
| 182 SelectorMask selectorMask = new SelectorMask(selector, mask); | |
| 183 ClassWorld classWorld = compiler.world; | |
| 184 assert(selector.name == name); | |
| 185 FunctionSetQuery result = cache[selectorMask]; | 205 FunctionSetQuery result = cache[selectorMask]; |
| 186 if (result != null) return result; | 206 if (result != null) return result; |
| 187 | 207 |
| 188 Setlet<Element> functions; | 208 Setlet<Element> functions; |
| 189 for (Element element in elements) { | 209 for (Element element in elements) { |
| 190 if (selectorMask.applies(element, classWorld)) { | 210 if (selectorMask.applies(element, classWorld)) { |
| 191 if (functions == null) { | 211 if (functions == null) { |
| 192 // Defer the allocation of the functions set until we are | 212 // Defer the allocation of the functions set until we are |
| 193 // sure we need it. This allows us to return immutable empty | 213 // sure we need it. This allows us to return immutable empty |
| 194 // lists when the filtering produced no results. | 214 // lists when the filtering produced no results. |
| 195 functions = new Setlet<Element>(); | 215 functions = new Setlet<Element>(); |
| 196 } | 216 } |
| 197 functions.add(element); | 217 functions.add(element); |
| 198 } | 218 } |
| 199 } | 219 } |
| 200 | 220 |
| 201 // If we cannot ensure a method will be found at runtime, we also | 221 // If we cannot ensure a method will be found at runtime, we also |
| 202 // add [noSuchMethod] implementations that apply to [mask] as | 222 // add [noSuchMethod] implementations that apply to [mask] as |
| 203 // potential targets. | 223 // potential targets. |
| 204 if (noSuchMethods != null | 224 if (noSuchMethods != null && |
| 205 && mask.needsNoSuchMethodHandling(selector, classWorld)) { | 225 selectorMask.needsNoSuchMethodHandling(classWorld)) { |
| 206 FunctionSetQuery noSuchMethodQuery = noSuchMethods.query( | 226 FunctionSetQuery noSuchMethodQuery = |
| 207 Selectors.noSuchMethod_, | 227 noSuchMethods.query(noSuchMethodMask, classWorld); |
| 208 mask, | |
| 209 compiler, | |
| 210 null); | |
| 211 if (!noSuchMethodQuery.functions.isEmpty) { | 228 if (!noSuchMethodQuery.functions.isEmpty) { |
| 212 if (functions == null) { | 229 if (functions == null) { |
| 213 functions = new Setlet<Element>.from(noSuchMethodQuery.functions); | 230 functions = new Setlet<Element>.from(noSuchMethodQuery.functions); |
| 214 } else { | 231 } else { |
| 215 functions.addAll(noSuchMethodQuery.functions); | 232 functions.addAll(noSuchMethodQuery.functions); |
| 216 } | 233 } |
| 217 } | 234 } |
| 218 } | 235 } |
| 219 cache[selectorMask] = result = (functions != null) | 236 cache[selectorMask] = result = (functions != null) |
| 220 ? newQuery(functions, selector, mask, compiler) | 237 ? new FullFunctionSetQuery(functions) |
| 221 : const FunctionSetQuery(const <Element>[]); | 238 : const EmptyFunctionSetQuery(); |
| 222 return result; | 239 return result; |
| 223 } | 240 } |
| 224 | |
| 225 FunctionSetQuery newQuery(Iterable<Element> functions, | |
| 226 Selector selector, | |
| 227 TypeMask mask, | |
| 228 Compiler compiler) { | |
| 229 return new FullFunctionSetQuery(functions); | |
| 230 } | |
| 231 } | 241 } |
| 232 | 242 |
| 233 class FunctionSetQuery { | 243 /// A set of functions that are the potential targets of all call sites sharing |
| 234 final Iterable<Element> functions; | 244 /// the same receiver mask and selector. |
| 235 TypeMask computeMask(ClassWorld classWorld) => const TypeMask.nonNullEmpty(); | 245 abstract class FunctionSetQuery { |
| 236 const FunctionSetQuery(this.functions); | 246 const FunctionSetQuery(); |
| 247 |
| 248 /// Compute the type of all potential receivers of this function set. |
| 249 TypeMask computeMask(ClassWorld classWorld); |
| 250 |
| 251 /// Returns all potential targets of this function set. |
| 252 Iterable<Element> get functions; |
| 237 } | 253 } |
| 238 | 254 |
| 239 class FullFunctionSetQuery extends FunctionSetQuery { | 255 class EmptyFunctionSetQuery implements FunctionSetQuery { |
| 256 const EmptyFunctionSetQuery(); |
| 257 |
| 258 @override |
| 259 TypeMask computeMask(ClassWorld classWorld) => const TypeMask.nonNullEmpty(); |
| 260 |
| 261 @override |
| 262 Iterable<Element> get functions => const <Element>[]; |
| 263 } |
| 264 |
| 265 class FullFunctionSetQuery implements FunctionSetQuery { |
| 266 @override |
| 267 final Iterable<Element> functions; |
| 268 |
| 240 TypeMask _mask; | 269 TypeMask _mask; |
| 241 | 270 |
| 242 /** | 271 FullFunctionSetQuery(this.functions); |
| 243 * Compute the type of all potential receivers of this function set. | 272 |
| 244 */ | 273 @override |
| 245 TypeMask computeMask(ClassWorld classWorld) { | 274 TypeMask computeMask(ClassWorld classWorld) { |
| 246 assert(classWorld.hasAnyStrictSubclass(classWorld.objectClass)); | 275 assert(classWorld.hasAnyStrictSubclass(classWorld.objectClass)); |
| 247 if (_mask != null) return _mask; | 276 if (_mask != null) return _mask; |
| 248 return _mask = new TypeMask.unionOf(functions | 277 return _mask = new TypeMask.unionOf(functions |
| 249 .expand((element) { | 278 .expand((element) { |
| 250 ClassElement cls = element.enclosingClass; | 279 ClassElement cls = element.enclosingClass; |
| 251 return [cls]..addAll(classWorld.mixinUsesOf(cls)); | 280 return [cls]..addAll(classWorld.mixinUsesOf(cls)); |
| 252 }) | 281 }) |
| 253 .map((cls) { | 282 .map((cls) { |
| 254 if (classWorld.backend.isNullImplementation(cls)) { | 283 if (classWorld.backend.isNullImplementation(cls)) { |
| 255 return const TypeMask.empty(); | 284 return const TypeMask.empty(); |
| 256 } else { | 285 } else { |
| 257 return new TypeMask.nonNullSubclass(cls.declaration, classWorld); | 286 return new TypeMask.nonNullSubclass(cls.declaration, classWorld); |
| 258 } | 287 } |
| 259 }), | 288 }), |
| 260 classWorld); | 289 classWorld); |
| 261 } | 290 } |
| 262 | |
| 263 FullFunctionSetQuery(functions) : super(functions); | |
| 264 } | 291 } |
| OLD | NEW |