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 { |
(...skipping 30 matching lines...) Expand all Loading... |
41 FunctionSetNode node = nodes[name]; | 41 FunctionSetNode node = nodes[name]; |
42 return (node != null) | 42 return (node != null) |
43 ? node.contains(element) | 43 ? node.contains(element) |
44 : false; | 44 : false; |
45 } | 45 } |
46 | 46 |
47 /** | 47 /** |
48 * Returns an object that allows iterating over all the functions | 48 * Returns an object that allows iterating over all the functions |
49 * that may be invoked with the given [selector]. | 49 * that may be invoked with the given [selector]. |
50 */ | 50 */ |
51 Iterable<Element> filter(Selector selector, TypeMask mask) { | 51 Iterable<Element> filter(Selector selector) { |
52 return query(selector, mask).functions; | 52 return query(selector).functions; |
53 } | 53 } |
54 | 54 |
55 TypeMask receiverType(Selector selector, TypeMask mask) { | 55 TypeMask receiverType(Selector selector) { |
56 return query(selector, mask).computeMask(compiler.world); | 56 return query(selector).computeMask(compiler.world); |
57 } | 57 } |
58 | 58 |
59 FunctionSetQuery query(Selector selector, TypeMask mask) { | 59 FunctionSetQuery query(Selector selector) { |
60 String name = selector.name; | 60 String name = selector.name; |
61 FunctionSetNode node = nodes[name]; | 61 FunctionSetNode node = nodes[name]; |
62 FunctionSetNode noSuchMethods = nodes[Compiler.NO_SUCH_METHOD]; | 62 FunctionSetNode noSuchMethods = nodes[Compiler.NO_SUCH_METHOD]; |
63 if (node != null) { | 63 if (node != null) { |
64 return node.query(selector, mask, compiler, noSuchMethods); | 64 return node.query(selector, compiler, noSuchMethods); |
65 } | 65 } |
66 // If there is no method that matches [selector] we know we can | 66 // If there is no method that matches [selector] we know we can |
67 // only hit [:noSuchMethod:]. | 67 // only hit [:noSuchMethod:]. |
68 if (noSuchMethods == null) return const FunctionSetQuery(const <Element>[]); | 68 if (noSuchMethods == null) return const FunctionSetQuery(const <Element>[]); |
69 return noSuchMethods.query( | 69 selector = (selector.mask == null) |
70 compiler.noSuchMethodSelector, mask, compiler, null); | 70 ? compiler.noSuchMethodSelector |
| 71 : new TypedSelector(selector.mask, compiler.noSuchMethodSelector, |
| 72 compiler.world); |
| 73 |
| 74 return noSuchMethods.query(selector, compiler, null); |
71 } | 75 } |
72 | 76 |
73 void forEach(Function action) { | 77 void forEach(Function action) { |
74 nodes.forEach((String name, FunctionSetNode node) { | 78 nodes.forEach((String name, FunctionSetNode node) { |
75 node.forEach(action); | 79 node.forEach(action); |
76 }); | 80 }); |
77 } | 81 } |
78 } | 82 } |
79 | 83 |
80 | 84 |
81 class FunctionSetNode { | 85 class FunctionSetNode { |
82 final String name; | 86 final String name; |
83 final Map<Selector, Map<TypeMask, FunctionSetQuery>> cache = | 87 final Map<Selector, FunctionSetQuery> cache = |
84 <Selector, Map<TypeMask, FunctionSetQuery>>{}; | 88 new Map<Selector, FunctionSetQuery>(); |
85 | 89 |
86 // Initially, we keep the elements in a list because it is more | 90 // Initially, we keep the elements in a list because it is more |
87 // compact than a hash set. Once we get enough elements, we change | 91 // compact than a hash set. Once we get enough elements, we change |
88 // the representation to be a set to get faster contains checks. | 92 // the representation to be a set to get faster contains checks. |
89 static const int MAX_ELEMENTS_IN_LIST = 8; | 93 static const int MAX_ELEMENTS_IN_LIST = 8; |
90 var elements = <Element>[]; | 94 var elements = <Element>[]; |
91 bool isList = true; | 95 bool isList = true; |
92 | 96 |
93 FunctionSetNode(this.name); | 97 FunctionSetNode(this.name); |
94 | 98 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
131 | 135 |
132 bool contains(Element element) { | 136 bool contains(Element element) { |
133 assert(element.name == name); | 137 assert(element.name == name); |
134 return elements.contains(element); | 138 return elements.contains(element); |
135 } | 139 } |
136 | 140 |
137 void forEach(Function action) { | 141 void forEach(Function action) { |
138 elements.forEach(action); | 142 elements.forEach(action); |
139 } | 143 } |
140 | 144 |
141 TypeMask getNonNullTypeMaskOfSelector(TypeMask mask, Compiler compiler) { | 145 TypeMask getNonNullTypeMaskOfSelector(Selector selector, Compiler compiler) { |
142 // TODO(ngeoffray): We should probably change untyped selector | 146 // TODO(ngeoffray): We should probably change untyped selector |
143 // to always be a subclass of Object. | 147 // to always be a subclass of Object. |
144 return mask != null | 148 return selector.mask != null |
145 ? mask | 149 ? selector.mask |
146 : new TypeMask.subclass(compiler.objectClass, compiler.world); | 150 : new TypeMask.subclass(compiler.objectClass, compiler.world); |
147 } | 151 } |
148 | 152 |
149 FunctionSetQuery query(Selector selector, | 153 FunctionSetQuery query(Selector selector, |
150 TypeMask mask, | |
151 Compiler compiler, | 154 Compiler compiler, |
152 FunctionSetNode noSuchMethods) { | 155 FunctionSetNode noSuchMethods) { |
153 ClassWorld classWorld = compiler.world; | 156 ClassWorld classWorld = compiler.world; |
154 assert(selector.name == name); | 157 assert(selector.name == name); |
155 Map<TypeMask, FunctionSetQuery> cacheMap = | 158 FunctionSetQuery result = cache[selector]; |
156 cache.putIfAbsent( | |
157 selector, () => new Maplet<TypeMask, FunctionSetQuery>()); | |
158 FunctionSetQuery result = cacheMap[mask]; | |
159 if (result != null) return result; | 159 if (result != null) return result; |
160 | |
161 Setlet<Element> functions; | 160 Setlet<Element> functions; |
162 for (Element element in elements) { | 161 for (Element element in elements) { |
163 if (selector.appliesUnnamed(element, classWorld) && | 162 if (selector.appliesUnnamed(element, classWorld)) { |
164 (mask == null || mask.canHit(element, selector, classWorld))) { | |
165 if (functions == null) { | 163 if (functions == null) { |
166 // Defer the allocation of the functions set until we are | 164 // Defer the allocation of the functions set until we are |
167 // sure we need it. This allows us to return immutable empty | 165 // sure we need it. This allows us to return immutable empty |
168 // lists when the filtering produced no results. | 166 // lists when the filtering produced no results. |
169 functions = new Setlet<Element>(); | 167 functions = new Setlet<Element>(); |
170 } | 168 } |
171 functions.add(element); | 169 functions.add(element); |
172 } | 170 } |
173 } | 171 } |
174 | 172 |
175 mask = getNonNullTypeMaskOfSelector(mask, compiler); | 173 TypeMask mask = getNonNullTypeMaskOfSelector(selector, compiler); |
176 // If we cannot ensure a method will be found at runtime, we also | 174 // If we cannot ensure a method will be found at runtime, we also |
177 // add [noSuchMethod] implementations that apply to [mask] as | 175 // add [noSuchMethod] implementations that apply to [mask] as |
178 // potential targets. | 176 // potential targets. |
179 if (noSuchMethods != null | 177 if (noSuchMethods != null |
180 && mask.needsNoSuchMethodHandling(selector, classWorld)) { | 178 && mask.needsNoSuchMethodHandling(selector, classWorld)) { |
181 FunctionSetQuery noSuchMethodQuery = noSuchMethods.query( | 179 FunctionSetQuery noSuchMethodQuery = noSuchMethods.query( |
182 compiler.noSuchMethodSelector, | 180 new TypedSelector( |
183 mask, | 181 mask, compiler.noSuchMethodSelector, classWorld), |
184 compiler, | 182 compiler, |
185 null); | 183 null); |
186 if (!noSuchMethodQuery.functions.isEmpty) { | 184 if (!noSuchMethodQuery.functions.isEmpty) { |
187 if (functions == null) { | 185 if (functions == null) { |
188 functions = new Setlet<Element>.from(noSuchMethodQuery.functions); | 186 functions = new Setlet<Element>.from(noSuchMethodQuery.functions); |
189 } else { | 187 } else { |
190 functions.addAll(noSuchMethodQuery.functions); | 188 functions.addAll(noSuchMethodQuery.functions); |
191 } | 189 } |
192 } | 190 } |
193 } | 191 } |
194 cacheMap[mask] = result = (functions != null) | 192 cache[selector] = result = (functions != null) |
195 ? newQuery(functions, selector, mask, compiler) | 193 ? newQuery(functions, selector, compiler) |
196 : const FunctionSetQuery(const <Element>[]); | 194 : const FunctionSetQuery(const <Element>[]); |
197 return result; | 195 return result; |
198 } | 196 } |
199 | 197 |
200 FunctionSetQuery newQuery(Iterable<Element> functions, | 198 FunctionSetQuery newQuery(Iterable<Element> functions, |
201 Selector selector, | 199 Selector selector, |
202 TypeMask mask, | |
203 Compiler compiler) { | 200 Compiler compiler) { |
204 return new FullFunctionSetQuery(functions); | 201 return new FullFunctionSetQuery(functions); |
205 } | 202 } |
206 } | 203 } |
207 | 204 |
208 class FunctionSetQuery { | 205 class FunctionSetQuery { |
209 final Iterable<Element> functions; | 206 final Iterable<Element> functions; |
210 TypeMask computeMask(ClassWorld classWorld) => const TypeMask.nonNullEmpty(); | 207 TypeMask computeMask(ClassWorld classWorld) => const TypeMask.nonNullEmpty(); |
211 const FunctionSetQuery(this.functions); | 208 const FunctionSetQuery(this.functions); |
212 } | 209 } |
(...skipping 17 matching lines...) Expand all Loading... |
230 return const TypeMask.empty(); | 227 return const TypeMask.empty(); |
231 } else { | 228 } else { |
232 return new TypeMask.nonNullSubclass(cls.declaration, classWorld); | 229 return new TypeMask.nonNullSubclass(cls.declaration, classWorld); |
233 } | 230 } |
234 }), | 231 }), |
235 classWorld); | 232 classWorld); |
236 } | 233 } |
237 | 234 |
238 FullFunctionSetQuery(functions) : super(functions); | 235 FullFunctionSetQuery(functions) : super(functions); |
239 } | 236 } |
OLD | NEW |