Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(655)

Side by Side Diff: pkg/compiler/lib/src/universe/function_set.dart

Issue 2615223003: Use MemberElement instead of Element in function sets and selectors. (Closed)
Patch Set: Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 '../elements/elements.dart' show MemberElement;
9 import '../elements/elements.dart'; 9 import '../elements/entities.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 ClosedWorld; 12 import '../world.dart' show ClosedWorld;
13 import 'selector.dart' show Selector; 13 import 'selector.dart' show Selector;
14 import 'world_builder.dart' show ReceiverConstraint; 14 import 'world_builder.dart' show ReceiverConstraint;
15 15
16 class FunctionSetBuilder { 16 class FunctionSetBuilder {
17 final Map<String, FunctionSetNode> nodes = new Map<String, FunctionSetNode>(); 17 final Map<String, FunctionSetNode> nodes = new Map<String, FunctionSetNode>();
18 18
19 FunctionSetNode newNode(String name) => new FunctionSetNode(name); 19 FunctionSetNode newNode(String name) => new FunctionSetNode(name);
20 20
21 void add(Element element) { 21 void add(MemberElement element) {
22 assert(element.isInstanceMember); 22 assert(element.isInstanceMember);
23 assert(!element.isAbstract); 23 assert(!element.isAbstract);
24 String name = element.name; 24 String name = element.name;
25 FunctionSetNode node = nodes.putIfAbsent(name, () => newNode(name)); 25 FunctionSetNode node = nodes.putIfAbsent(name, () => newNode(name));
26 node.add(element); 26 node.add(element);
27 } 27 }
28 28
29 void remove(Element element) { 29 void remove(MemberElement element) {
30 assert(element.isInstanceMember); 30 assert(element.isInstanceMember);
31 assert(!element.isAbstract); 31 assert(!element.isAbstract);
32 String name = element.name; 32 String name = element.name;
33 FunctionSetNode node = nodes[name]; 33 FunctionSetNode node = nodes[name];
34 if (node != null) { 34 if (node != null) {
35 node.remove(element); 35 node.remove(element);
36 } 36 }
37 } 37 }
38 38
39 FunctionSet close(ClosedWorld closedWorld) { 39 FunctionSet close(ClosedWorld closedWorld) {
40 return new FunctionSet(closedWorld, nodes); 40 return new FunctionSet(closedWorld, nodes);
41 } 41 }
42 } 42 }
43 43
44 // TODO(kasperl): This actually holds getters and setters just fine 44 // TODO(kasperl): This actually holds getters and setters just fine
45 // too and stricly they aren't functions. Maybe this needs a better 45 // too and stricly they aren't functions. Maybe this needs a better
46 // name -- something like ElementSet seems a bit too generic. 46 // name -- something like ElementSet seems a bit too generic.
47 class FunctionSet { 47 class FunctionSet {
48 final ClosedWorld closedWorld; 48 final ClosedWorld closedWorld;
49 final Map<String, FunctionSetNode> nodes; 49 final Map<String, FunctionSetNode> nodes;
50 50
51 FunctionSet(this.closedWorld, this.nodes); 51 FunctionSet(this.closedWorld, this.nodes);
52 52
53 bool contains(Element element) { 53 bool contains(MemberElement element) {
54 assert(element.isInstanceMember); 54 assert(element.isInstanceMember);
55 assert(!element.isAbstract); 55 assert(!element.isAbstract);
56 String name = element.name; 56 String name = element.name;
57 FunctionSetNode node = nodes[name]; 57 FunctionSetNode node = nodes[name];
58 return (node != null) ? node.contains(element) : false; 58 return (node != null) ? node.contains(element) : false;
59 } 59 }
60 60
61 /// Returns all the functions that may be invoked with the [selector] on a 61 /// Returns all the functions that may be invoked with the [selector] on a
62 /// receiver with the given [constraint]. The returned elements may include 62 /// receiver with the given [constraint]. The returned elements may include
63 /// noSuchMethod handlers that are potential targets indirectly through the 63 /// noSuchMethod handlers that are potential targets indirectly through the
64 /// noSuchMethod mechanism. 64 /// noSuchMethod mechanism.
65 Iterable<Element> filter(Selector selector, ReceiverConstraint constraint) { 65 Iterable<MemberElement> filter(
66 Selector selector, ReceiverConstraint constraint) {
66 return query(selector, constraint).functions; 67 return query(selector, constraint).functions;
67 } 68 }
68 69
69 /// Returns the mask for the potential receivers of a dynamic call to 70 /// Returns the mask for the potential receivers of a dynamic call to
70 /// [selector] on [constraint]. 71 /// [selector] on [constraint].
71 /// 72 ///
72 /// This will narrow the constraints of [constraint] to a [TypeMask] of the 73 /// This will narrow the constraints of [constraint] to a [TypeMask] of the
73 /// set of classes that actually implement the selected member or implement 74 /// set of classes that actually implement the selected member or implement
74 /// the handling 'noSuchMethod' where the selected member is unimplemented. 75 /// the handling 'noSuchMethod' where the selected member is unimplemented.
75 TypeMask receiverType(Selector selector, ReceiverConstraint constraint) { 76 TypeMask receiverType(Selector selector, ReceiverConstraint constraint) {
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
126 SelectorMask(Selector selector, ReceiverConstraint constraint) 127 SelectorMask(Selector selector, ReceiverConstraint constraint)
127 : this.selector = selector, 128 : this.selector = selector,
128 this.constraint = constraint, 129 this.constraint = constraint,
129 this.hashCode = 130 this.hashCode =
130 Hashing.mixHashCodeBits(selector.hashCode, constraint.hashCode) { 131 Hashing.mixHashCodeBits(selector.hashCode, constraint.hashCode) {
131 assert(constraint != null); 132 assert(constraint != null);
132 } 133 }
133 134
134 String get name => selector.name; 135 String get name => selector.name;
135 136
136 bool applies(Element element, ClosedWorld closedWorld) { 137 bool applies(MemberEntity element, ClosedWorld closedWorld) {
137 if (!selector.appliesUnnamed(element)) return false; 138 if (!selector.appliesUnnamed(element)) return false;
138 return constraint.canHit(element, selector, closedWorld); 139 return constraint.canHit(element, selector, closedWorld);
139 } 140 }
140 141
141 bool needsNoSuchMethodHandling(ClosedWorld closedWorld) { 142 bool needsNoSuchMethodHandling(ClosedWorld closedWorld) {
142 return constraint.needsNoSuchMethodHandling(selector, closedWorld); 143 return constraint.needsNoSuchMethodHandling(selector, closedWorld);
143 } 144 }
144 145
145 bool operator ==(other) { 146 bool operator ==(other) {
146 if (identical(this, other)) return true; 147 if (identical(this, other)) return true;
147 return selector == other.selector && constraint == other.constraint; 148 return selector == other.selector && constraint == other.constraint;
148 } 149 }
149 150
150 String toString() => '($selector,$constraint)'; 151 String toString() => '($selector,$constraint)';
151 } 152 }
152 153
153 /// A node in the [FunctionSet] caching all [FunctionSetQuery] object for 154 /// A node in the [FunctionSet] caching all [FunctionSetQuery] object for
154 /// selectors with the same [name]. 155 /// selectors with the same [name].
155 class FunctionSetNode { 156 class FunctionSetNode {
156 final String name; 157 final String name;
157 final Map<SelectorMask, FunctionSetQuery> cache = 158 final Map<SelectorMask, FunctionSetQuery> cache =
158 <SelectorMask, FunctionSetQuery>{}; 159 <SelectorMask, FunctionSetQuery>{};
159 160
160 // Initially, we keep the elements in a list because it is more 161 // Initially, we keep the elements in a list because it is more
161 // compact than a hash set. Once we get enough elements, we change 162 // compact than a hash set. Once we get enough elements, we change
162 // the representation to be a set to get faster contains checks. 163 // the representation to be a set to get faster contains checks.
163 static const int MAX_ELEMENTS_IN_LIST = 8; 164 static const int MAX_ELEMENTS_IN_LIST = 8;
164 var elements = <Element>[]; 165 var elements = <MemberElement>[];
165 bool isList = true; 166 bool isList = true;
166 167
167 FunctionSetNode(this.name); 168 FunctionSetNode(this.name);
168 169
169 void add(Element element) { 170 void add(MemberElement element) {
170 assert(element.name == name); 171 assert(element.name == name);
171 // We try to avoid clearing the cache unless we have to. For that 172 // We try to avoid clearing the cache unless we have to. For that
172 // reason we keep the explicit contains check even though the add 173 // reason we keep the explicit contains check even though the add
173 // method ends up doing the work again (for sets). 174 // method ends up doing the work again (for sets).
174 if (!elements.contains(element)) { 175 if (!elements.contains(element)) {
175 if (isList && elements.length >= MAX_ELEMENTS_IN_LIST) { 176 if (isList && elements.length >= MAX_ELEMENTS_IN_LIST) {
176 elements = elements.toSet(); 177 elements = elements.toSet();
177 isList = false; 178 isList = false;
178 } 179 }
179 elements.add(element); 180 elements.add(element);
180 if (!cache.isEmpty) cache.clear(); 181 if (!cache.isEmpty) cache.clear();
181 } 182 }
182 } 183 }
183 184
184 void remove(Element element) { 185 void remove(MemberElement element) {
185 assert(element.name == name); 186 assert(element.name == name);
186 if (isList) { 187 if (isList) {
187 List list = elements; 188 List list = elements;
188 int index = list.indexOf(element); 189 int index = list.indexOf(element);
189 if (index < 0) return; 190 if (index < 0) return;
190 Element last = list.removeLast(); 191 MemberElement last = list.removeLast();
191 if (index != list.length) { 192 if (index != list.length) {
192 list[index] = last; 193 list[index] = last;
193 } 194 }
194 if (!cache.isEmpty) cache.clear(); 195 if (!cache.isEmpty) cache.clear();
195 } else { 196 } else {
196 Set set = elements; 197 Set set = elements;
197 if (set.remove(element)) { 198 if (set.remove(element)) {
198 // To avoid wobbling between the two representations, we do 199 // To avoid wobbling between the two representations, we do
199 // not transition back to the list representation even if we 200 // not transition back to the list representation even if we
200 // end up with few enough elements at this point. 201 // end up with few enough elements at this point.
201 if (!cache.isEmpty) cache.clear(); 202 if (!cache.isEmpty) cache.clear();
202 } 203 }
203 } 204 }
204 } 205 }
205 206
206 bool contains(Element element) { 207 bool contains(MemberElement element) {
207 assert(element.name == name); 208 assert(element.name == name);
208 return elements.contains(element); 209 return elements.contains(element);
209 } 210 }
210 211
211 void forEach(Function action) { 212 void forEach(Function action) {
212 elements.forEach(action); 213 elements.forEach(action);
213 } 214 }
214 215
215 /// Returns the set of functions that can be the target of [selectorMask] 216 /// Returns the set of functions that can be the target of [selectorMask]
216 /// including no such method handling where applicable. 217 /// including no such method handling where applicable.
217 FunctionSetQuery query(SelectorMask selectorMask, ClosedWorld closedWorld, 218 FunctionSetQuery query(SelectorMask selectorMask, ClosedWorld closedWorld,
218 [FunctionSetNode noSuchMethods, SelectorMask noSuchMethodMask]) { 219 [FunctionSetNode noSuchMethods, SelectorMask noSuchMethodMask]) {
219 assert(selectorMask.name == name); 220 assert(selectorMask.name == name);
220 FunctionSetQuery result = cache[selectorMask]; 221 FunctionSetQuery result = cache[selectorMask];
221 if (result != null) return result; 222 if (result != null) return result;
222 223
223 Setlet<Element> functions; 224 Setlet<MemberElement> functions;
224 for (Element element in elements) { 225 for (MemberElement element in elements) {
225 if (selectorMask.applies(element, closedWorld)) { 226 if (selectorMask.applies(element, closedWorld)) {
226 if (functions == null) { 227 if (functions == null) {
227 // Defer the allocation of the functions set until we are 228 // Defer the allocation of the functions set until we are
228 // sure we need it. This allows us to return immutable empty 229 // sure we need it. This allows us to return immutable empty
229 // lists when the filtering produced no results. 230 // lists when the filtering produced no results.
230 functions = new Setlet<Element>(); 231 functions = new Setlet<MemberElement>();
231 } 232 }
232 functions.add(element); 233 functions.add(element);
233 } 234 }
234 } 235 }
235 236
236 // If we cannot ensure a method will be found at runtime, we also 237 // If we cannot ensure a method will be found at runtime, we also
237 // add [noSuchMethod] implementations that apply to [mask] as 238 // add [noSuchMethod] implementations that apply to [mask] as
238 // potential targets. 239 // potential targets.
239 if (noSuchMethods != null && 240 if (noSuchMethods != null &&
240 selectorMask.needsNoSuchMethodHandling(closedWorld)) { 241 selectorMask.needsNoSuchMethodHandling(closedWorld)) {
241 FunctionSetQuery noSuchMethodQuery = 242 FunctionSetQuery noSuchMethodQuery =
242 noSuchMethods.query(noSuchMethodMask, closedWorld); 243 noSuchMethods.query(noSuchMethodMask, closedWorld);
243 if (!noSuchMethodQuery.functions.isEmpty) { 244 if (!noSuchMethodQuery.functions.isEmpty) {
244 if (functions == null) { 245 if (functions == null) {
245 functions = new Setlet<Element>.from(noSuchMethodQuery.functions); 246 functions =
247 new Setlet<MemberElement>.from(noSuchMethodQuery.functions);
246 } else { 248 } else {
247 functions.addAll(noSuchMethodQuery.functions); 249 functions.addAll(noSuchMethodQuery.functions);
248 } 250 }
249 } 251 }
250 } 252 }
251 cache[selectorMask] = result = (functions != null) 253 cache[selectorMask] = result = (functions != null)
252 ? new FullFunctionSetQuery(functions) 254 ? new FullFunctionSetQuery(functions)
253 : const EmptyFunctionSetQuery(); 255 : const EmptyFunctionSetQuery();
254 return result; 256 return result;
255 } 257 }
256 } 258 }
257 259
258 /// A set of functions that are the potential targets of all call sites sharing 260 /// A set of functions that are the potential targets of all call sites sharing
259 /// the same receiver mask and selector. 261 /// the same receiver mask and selector.
260 abstract class FunctionSetQuery { 262 abstract class FunctionSetQuery {
261 const FunctionSetQuery(); 263 const FunctionSetQuery();
262 264
263 /// Compute the type of all potential receivers of this function set. 265 /// Compute the type of all potential receivers of this function set.
264 TypeMask computeMask(ClosedWorld closedWorld); 266 TypeMask computeMask(ClosedWorld closedWorld);
265 267
266 /// Returns all potential targets of this function set. 268 /// Returns all potential targets of this function set.
267 Iterable<Element> get functions; 269 Iterable<MemberElement> get functions;
268 } 270 }
269 271
270 class EmptyFunctionSetQuery implements FunctionSetQuery { 272 class EmptyFunctionSetQuery implements FunctionSetQuery {
271 const EmptyFunctionSetQuery(); 273 const EmptyFunctionSetQuery();
272 274
273 @override 275 @override
274 TypeMask computeMask(ClosedWorld closedWorld) => 276 TypeMask computeMask(ClosedWorld closedWorld) =>
275 const TypeMask.nonNullEmpty(); 277 const TypeMask.nonNullEmpty();
276 278
277 @override 279 @override
278 Iterable<Element> get functions => const <Element>[]; 280 Iterable<MemberElement> get functions => const <MemberElement>[];
279 } 281 }
280 282
281 class FullFunctionSetQuery implements FunctionSetQuery { 283 class FullFunctionSetQuery implements FunctionSetQuery {
282 @override 284 @override
283 final Iterable<Element> functions; 285 final Iterable<MemberElement> functions;
284 286
285 TypeMask _mask; 287 TypeMask _mask;
286 288
287 FullFunctionSetQuery(this.functions); 289 FullFunctionSetQuery(this.functions);
288 290
289 @override 291 @override
290 TypeMask computeMask(ClosedWorld closedWorld) { 292 TypeMask computeMask(ClosedWorld closedWorld) {
291 assert(closedWorld 293 assert(closedWorld
292 .hasAnyStrictSubclass(closedWorld.commonElements.objectClass)); 294 .hasAnyStrictSubclass(closedWorld.commonElements.objectClass));
293 if (_mask != null) return _mask; 295 if (_mask != null) return _mask;
294 return _mask = new TypeMask.unionOf( 296 return _mask = new TypeMask.unionOf(
295 functions.expand((element) { 297 functions.expand((MemberElement element) {
296 ClassElement cls = element.enclosingClass; 298 ClassEntity cls = element.enclosingClass.declaration;
297 return [cls]..addAll(closedWorld.mixinUsesOf(cls)); 299 return [cls]..addAll(closedWorld.mixinUsesOf(cls));
298 }).map((cls) { 300 }).map((cls) {
299 if (closedWorld.backendClasses.nullImplementation == cls) { 301 if (closedWorld.backendClasses.nullImplementation == cls) {
300 return const TypeMask.empty(); 302 return const TypeMask.empty();
301 } else if (closedWorld.isInstantiated(cls.declaration)) { 303 } else if (closedWorld.isInstantiated(cls)) {
302 return new TypeMask.nonNullSubclass(cls.declaration, closedWorld); 304 return new TypeMask.nonNullSubclass(cls, closedWorld);
303 } else { 305 } else {
304 // TODO(johnniwinther): Avoid the need for this case. 306 // TODO(johnniwinther): Avoid the need for this case.
305 return const TypeMask.empty(); 307 return const TypeMask.empty();
306 } 308 }
307 }), 309 }),
308 closedWorld); 310 closedWorld);
309 } 311 }
310 } 312 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698