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

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

Issue 2506393002: Enhance precision of recorded instantiation info in ResolutionWorldBuilder (Closed)
Patch Set: Cleanup. Created 4 years, 1 month 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; 5 library universe;
6 6
7 import 'dart:collection'; 7 import 'dart:collection';
8 8
9 import '../cache_strategy.dart'; 9 import '../cache_strategy.dart';
10 import '../common.dart'; 10 import '../common.dart';
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
157 157
158 /// Returns `true` if [cls] is considered to be implemented by an 158 /// Returns `true` if [cls] is considered to be implemented by an
159 /// instantiated class, either directly, through subclasses or through 159 /// instantiated class, either directly, through subclasses or through
160 /// subtypes. The latter case only contains spurious information from 160 /// subtypes. The latter case only contains spurious information from
161 /// instantiations through factory constructors and mixins. 161 /// instantiations through factory constructors and mixins.
162 bool isImplemented(ClassElement cls); 162 bool isImplemented(ClassElement cls);
163 163
164 /// Set of all fields that are statically known to be written to. 164 /// Set of all fields that are statically known to be written to.
165 Iterable<Element> get fieldSetters; 165 Iterable<Element> get fieldSetters;
166 166
167 /// Call [f] for all directly or abstractly instantiated classes. 167 /// Call [f] for all classes with instantiated types. This includes the
168 void forEachInstantiatedClass( 168 /// directly and abstractly instantiated classes but also classes whose type
169 f(ClassElement cls, EnumSet<Instantiation> instantiations)); 169 /// arguments are used in live factory constructors.
170 void forEachInstantiatedClass(f(ClassElement cls, InstantiationInfo info));
170 171
171 /// `true` of `Object.runtimeType` is supported. 172 /// `true` of `Object.runtimeType` is supported.
172 bool get hasRuntimeTypeSupport; 173 bool get hasRuntimeTypeSupport;
173 174
174 /// `true` of use of the `dart:isolate` library is supported. 175 /// `true` of use of the `dart:isolate` library is supported.
175 bool get hasIsolateSupport; 176 bool get hasIsolateSupport;
176 177
177 /// `true` of `Function.apply` is supported. 178 /// `true` of `Function.apply` is supported.
178 bool get hasFunctionApplySupport; 179 bool get hasFunctionApplySupport;
179 180
180 /// The [OpenWorld] being created by this world builder. 181 /// The [OpenWorld] being created by this world builder.
181 // TODO(johnniwinther): Merge this with [ResolutionWorldBuilder]. 182 // TODO(johnniwinther): Merge this with [ResolutionWorldBuilder].
182 OpenWorld get openWorld; 183 OpenWorld get openWorld;
183 } 184 }
184 185
186 /// The type and kind of a register instantiation.
Harry Terkelsen 2016/11/18 00:11:35 what do you mean by "register instantiation"?
Johnni Winther 2016/11/18 09:52:49 register -> registered
187 class Instance {
188 final InterfaceType type;
189 final Instantiation kind;
190 final bool isRedirection;
191
192 Instance(this.type, this.kind, {this.isRedirection: false});
193
194 int get hashCode {
195 return Hashing.objectHash(
196 type, Hashing.objectHash(kind, Hashing.objectHash(isRedirection)));
197 }
198
199 bool operator ==(other) {
200 if (identical(this, other)) return true;
201 if (other is! Instance) return false;
202 return type == other.type &&
203 kind == other.kind &&
204 isRedirection == other.isRedirection;
205 }
206
207 String toString() {
208 StringBuffer sb = new StringBuffer();
209 sb.write(type);
210 if (kind == Instantiation.DIRECTLY_INSTANTIATED) {
211 sb.write(' directly');
212 } else if (kind == Instantiation.ABSTRACTLY_INSTANTIATED) {
213 sb.write(' abstractly');
214 }
215 if (isRedirection) {
216 sb.write(' redirect');
217 }
218 return sb.toString();
219 }
220 }
221
222 /// Information about instantiations of a class.
223 class InstantiationInfo {
224 /// A map from constructor of the class to their instantiated types.
225 ///
226 /// For instance
227 ///
228 /// class Class<T> {
229 /// Class.a();
230 /// Class.b();
231 /// Class.c() = Class.b<T>;
232 /// }
233 ///
234 /// main() {
235 /// new Class.a(),
236 /// new Class<int>.a(),
237 /// new Class<String>.b()
238 /// new Class<num>.c()
239 /// }
240 ///
241 /// will generate the map
242 ///
243 /// {
244 /// Class.a: { Class directly, Class<int> directly },
245 /// Class.b: { Class<String> directly, Class<T> directly redirect },
246 /// Class.c: { Class<num> directly },
247 /// }
Harry Terkelsen 2016/11/18 00:11:35 consider also giving an example of a class that is
Johnni Winther 2016/11/18 09:52:49 Done.
248 ///
249 /// If the constructor is unknown, for instance for native or mirror usage,
250 /// `null` is used as key.
251 Map<ConstructorElement, Set<Instance>> instantiationMap;
252
253 /// Register [type] as the instantiation [kind] using [constructor].
254 void addInstantiation(
255 ConstructorElement constructor, InterfaceType type, Instantiation kind,
256 {bool isRedirection: false}) {
257 instantiationMap ??= new Maplet<ConstructorElement, Set<Instance>>();
Harry Terkelsen 2016/11/18 00:11:35 are maplets still better than maps? I think there
Johnni Winther 2016/11/18 09:52:49 Changed.
258 instantiationMap
259 .putIfAbsent(constructor, () => new Setlet<Instance>())
260 .add(new Instance(type, kind, isRedirection: isRedirection));
261 switch (kind) {
262 case Instantiation.DIRECTLY_INSTANTIATED:
263 isDirectlyInstantiated = true;
264 break;
265 case Instantiation.ABSTRACTLY_INSTANTIATED:
266 isAbstractlyInstantiated = true;
267 break;
268 case Instantiation.UNINSTANTIATED:
269 break;
270 default:
271 throw new StateError("Instantiation $kind is not allowed.");
272 }
273 }
274
275 /// `true` if the class is either directly or abstractly instantiated.
276 bool get hasInstantiation =>
277 isDirectlyInstantiated || isAbstractlyInstantiated;
278
279 /// `true` if the class is directly instantiated.
280 bool isDirectlyInstantiated = false;
281
282 /// `true` if the class is abstractly instantiated.
283 bool isAbstractlyInstantiated = false;
284
285 String toString() {
286 StringBuffer sb = new StringBuffer();
287 sb.write('InstantiationInfo[');
288 if (instantiationMap != null) {
289 bool needsComma = false;
290 instantiationMap
291 .forEach((ConstructorElement constructor, Set<Instance> set) {
292 if (needsComma) {
293 sb.write(', ');
294 }
295 if (constructor != null) {
296 sb.write(constructor);
297 } else {
298 sb.write('<unknown>');
299 }
300 sb.write(': ');
301 sb.write(set);
302 needsComma = true;
303 });
304 }
305 sb.write(']');
306 return sb.toString();
307 }
308 }
309
185 class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder { 310 class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder {
186 /// The set of all directly instantiated classes, that is, classes with a 311 /// Instantiation information for all classes with instantiated types.
187 /// generative constructor that has been called directly and not only through
188 /// a super-call.
189 /// 312 ///
190 /// Invariant: Elements are declaration elements. 313 /// Invariant: Elements are declaration elements.
191 // TODO(johnniwinther): [_directlyInstantiatedClasses] and 314 final Map<ClassElement, InstantiationInfo> _instantiationInfo =
192 // [_instantiatedTypes] sets should be merged. 315 <ClassElement, InstantiationInfo>{};
193 final Map<ClassElement, EnumSet<Instantiation>> _directlyInstantiatedClasses =
194 <ClassElement, EnumSet<Instantiation>>{};
195
196 /// The set of all directly instantiated types, that is, the types of the
197 /// directly instantiated classes.
198 ///
199 /// See [_directlyInstantiatedClasses].
200 final Set<DartType> _instantiatedTypes = new Set<DartType>();
201 316
202 /// Classes implemented by directly instantiated classes. 317 /// Classes implemented by directly instantiated classes.
203 final Set<ClassElement> _implementedClasses = new Set<ClassElement>(); 318 final Set<ClassElement> _implementedClasses = new Set<ClassElement>();
204 319
205 /// The set of all referenced static fields. 320 /// The set of all referenced static fields.
206 /// 321 ///
207 /// Invariant: Elements are declaration elements. 322 /// Invariant: Elements are declaration elements.
208 final Set<FieldElement> allReferencedStaticFields = new Set<FieldElement>(); 323 final Set<FieldElement> allReferencedStaticFields = new Set<FieldElement>();
209 324
210 /** 325 /**
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
265 _openWorld = new WorldImpl(this, backend, coreClasses, cacheStrategy); 380 _openWorld = new WorldImpl(this, backend, coreClasses, cacheStrategy);
266 } 381 }
267 382
268 OpenWorld get openWorld => _openWorld; 383 OpenWorld get openWorld => _openWorld;
269 384
270 /// All directly instantiated classes, that is, classes with a generative 385 /// All directly instantiated classes, that is, classes with a generative
271 /// constructor that has been called directly and not only through a 386 /// constructor that has been called directly and not only through a
272 /// super-call. 387 /// super-call.
273 // TODO(johnniwinther): Improve semantic precision. 388 // TODO(johnniwinther): Improve semantic precision.
274 Iterable<ClassElement> get directlyInstantiatedClasses { 389 Iterable<ClassElement> get directlyInstantiatedClasses {
275 return _directlyInstantiatedClasses.keys; 390 Set<ClassElement> classes = new Set<ClassElement>();
391 _instantiationInfo.forEach((ClassElement cls, InstantiationInfo info) {
392 if (info.hasInstantiation) {
393 classes.add(cls);
394 }
395 });
396 return classes;
276 } 397 }
277 398
278 /// All directly instantiated types, that is, the types of the directly 399 /// All directly instantiated types, that is, the types of the directly
279 /// instantiated classes. 400 /// instantiated classes.
280 /// 401 ///
281 /// See [directlyInstantiatedClasses]. 402 /// See [directlyInstantiatedClasses].
282 // TODO(johnniwinther): Improve semantic precision. 403 // TODO(johnniwinther): Improve semantic precision.
283 Iterable<DartType> get instantiatedTypes => _instantiatedTypes; 404 Iterable<DartType> get instantiatedTypes {
405 Set<InterfaceType> types = new Set<InterfaceType>();
406 _instantiationInfo.forEach((_, InstantiationInfo info) {
407 if (info.instantiationMap != null) {
408 for (Set<Instance> instances in info.instantiationMap.values) {
409 for (Instance instance in instances) {
410 types.add(instance.type);
411 }
412 }
413 }
414 });
415 return types;
416 }
284 417
285 /// Returns `true` if [cls] is considered to be implemented by an 418 /// Returns `true` if [cls] is considered to be implemented by an
286 /// instantiated class, either directly, through subclasses or through 419 /// instantiated class, either directly, through subclasses or through
287 /// subtypes. The latter case only contains spurious information from 420 /// subtypes. The latter case only contains spurious information from
288 /// instantiations through factory constructors and mixins. 421 /// instantiations through factory constructors and mixins.
289 // TODO(johnniwinther): Improve semantic precision. 422 // TODO(johnniwinther): Improve semantic precision.
290 bool isImplemented(ClassElement cls) { 423 bool isImplemented(ClassElement cls) {
291 return _implementedClasses.contains(cls.declaration); 424 return _implementedClasses.contains(cls.declaration);
292 } 425 }
293 426
294 /// Register [type] as (directly) instantiated. 427 /// Register [type] as (directly) instantiated.
295 /// 428 ///
296 /// If [byMirrors] is `true`, the instantiation is through mirrors. 429 /// If [byMirrors] is `true`, the instantiation is through mirrors.
297 // TODO(johnniwinther): Fully enforce the separation between exact, through 430 // TODO(johnniwinther): Fully enforce the separation between exact, through
298 // subclass and through subtype instantiated types/classes. 431 // subclass and through subtype instantiated types/classes.
299 // TODO(johnniwinther): Support unknown type arguments for generic types. 432 // TODO(johnniwinther): Support unknown type arguments for generic types.
300 void registerTypeInstantiation(InterfaceType type, 433 void registerTypeInstantiation(InterfaceType type,
301 {bool byMirrors: false, 434 {ConstructorElement constructor,
435 bool byMirrors: false,
302 bool isNative: false, 436 bool isNative: false,
437 bool isRedirection: false,
303 void onImplemented(ClassElement cls)}) { 438 void onImplemented(ClassElement cls)}) {
304 _instantiatedTypes.add(type);
305 ClassElement cls = type.element; 439 ClassElement cls = type.element;
440 InstantiationInfo info =
441 _instantiationInfo.putIfAbsent(cls, () => new InstantiationInfo());
442 Instantiation kind = Instantiation.UNINSTANTIATED;
306 if (!cls.isAbstract 443 if (!cls.isAbstract
307 // We can't use the closed-world assumption with native abstract 444 // We can't use the closed-world assumption with native abstract
308 // classes; a native abstract class may have non-abstract subclasses 445 // classes; a native abstract class may have non-abstract subclasses
309 // not declared to the program. Instances of these classes are 446 // not declared to the program. Instances of these classes are
310 // indistinguishable from the abstract class. 447 // indistinguishable from the abstract class.
311 || 448 ||
312 isNative 449 isNative
313 // Likewise, if this registration comes from the mirror system, 450 // Likewise, if this registration comes from the mirror system,
314 // all bets are off. 451 // all bets are off.
315 // TODO(herhut): Track classes required by mirrors seperately. 452 // TODO(herhut): Track classes required by mirrors seperately.
316 || 453 ||
317 byMirrors) { 454 byMirrors) {
318 EnumSet<Instantiation> instantiations = _directlyInstantiatedClasses
319 .putIfAbsent(cls, () => new EnumSet<Instantiation>());
320 if (isNative || byMirrors) { 455 if (isNative || byMirrors) {
321 instantiations.add(Instantiation.ABSTRACTLY_INSTANTIATED); 456 kind = Instantiation.ABSTRACTLY_INSTANTIATED;
322 } else { 457 } else {
323 instantiations.add(Instantiation.DIRECTLY_INSTANTIATED); 458 kind = Instantiation.DIRECTLY_INSTANTIATED;
324 } 459 }
325 } 460 }
461 info.addInstantiation(constructor, type, kind,
462 isRedirection: isRedirection);
326 463
327 // TODO(johnniwinther): Replace this by separate more specific mappings that 464 // TODO(johnniwinther): Use [_instantiationInfo] to compute this information
328 // include the type arguments. 465 // instead.
329 if (_implementedClasses.add(cls)) { 466 if (_implementedClasses.add(cls)) {
330 onImplemented(cls); 467 onImplemented(cls);
331 cls.allSupertypes.forEach((InterfaceType supertype) { 468 cls.allSupertypes.forEach((InterfaceType supertype) {
332 if (_implementedClasses.add(supertype.element)) { 469 if (_implementedClasses.add(supertype.element)) {
333 onImplemented(supertype.element); 470 onImplemented(supertype.element);
334 } 471 }
335 }); 472 });
336 } 473 }
337 } 474 }
338 475
339 @override 476 @override
340 void forEachInstantiatedClass( 477 void forEachInstantiatedClass(f(ClassElement cls, InstantiationInfo info)) {
341 f(ClassElement cls, EnumSet<Instantiation> instantiations)) { 478 _instantiationInfo.forEach(f);
342 _directlyInstantiatedClasses.forEach(f);
343 } 479 }
344 480
345 bool _hasMatchingSelector(Map<Selector, SelectorConstraints> selectors, 481 bool _hasMatchingSelector(Map<Selector, SelectorConstraints> selectors,
346 Element member, OpenWorld world) { 482 Element member, OpenWorld world) {
347 if (selectors == null) return false; 483 if (selectors == null) return false;
348 for (Selector selector in selectors.keys) { 484 for (Selector selector in selectors.keys) {
349 if (selector.appliesUnnamed(member)) { 485 if (selector.appliesUnnamed(member)) {
350 SelectorConstraints masks = selectors[selector]; 486 SelectorConstraints masks = selectors[selector];
351 if (masks.applies(member, selector, world)) { 487 if (masks.applies(member, selector, world)) {
352 return true; 488 return true;
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
415 fieldSetters.add(element); 551 fieldSetters.add(element);
416 break; 552 break;
417 case StaticUseKind.SUPER_TEAR_OFF: 553 case StaticUseKind.SUPER_TEAR_OFF:
418 methodsNeedingSuperGetter.add(element); 554 methodsNeedingSuperGetter.add(element);
419 break; 555 break;
420 case StaticUseKind.GENERAL: 556 case StaticUseKind.GENERAL:
421 case StaticUseKind.STATIC_TEAR_OFF: 557 case StaticUseKind.STATIC_TEAR_OFF:
422 case StaticUseKind.FIELD_GET: 558 case StaticUseKind.FIELD_GET:
423 case StaticUseKind.CONSTRUCTOR_INVOKE: 559 case StaticUseKind.CONSTRUCTOR_INVOKE:
424 case StaticUseKind.CONST_CONSTRUCTOR_INVOKE: 560 case StaticUseKind.CONST_CONSTRUCTOR_INVOKE:
561 case StaticUseKind.REDIRECTION:
425 break; 562 break;
426 case StaticUseKind.CLOSURE: 563 case StaticUseKind.CLOSURE:
427 allClosures.add(element); 564 allClosures.add(element);
428 break; 565 break;
429 case StaticUseKind.DIRECT_INVOKE: 566 case StaticUseKind.DIRECT_INVOKE:
430 invariant( 567 invariant(
431 element, 'Direct static use is not supported for resolution.'); 568 element, 'Direct static use is not supported for resolution.');
432 break; 569 break;
433 } 570 }
434 } 571 }
435 572
436 void forgetElement(Element element, Compiler compiler) { 573 void forgetElement(Element element, Compiler compiler) {
437 allClosures.remove(element); 574 allClosures.remove(element);
438 slowDirectlyNestedClosures(element).forEach(compiler.forgetElement); 575 slowDirectlyNestedClosures(element).forEach(compiler.forgetElement);
439 closurizedMembers.remove(element); 576 closurizedMembers.remove(element);
440 fieldSetters.remove(element); 577 fieldSetters.remove(element);
441 _directlyInstantiatedClasses.remove(element); 578 _instantiationInfo.remove(element);
442 if (element is ClassElement) {
443 assert(invariant(element, element.thisType.isRaw,
444 message: 'Generic classes not supported (${element.thisType}).'));
445 _instantiatedTypes..remove(element.rawType)..remove(element.thisType);
446 }
447 } 579 }
448 580
449 // TODO(ahe): Replace this method with something that is O(1), for example, 581 // TODO(ahe): Replace this method with something that is O(1), for example,
450 // by using a map. 582 // by using a map.
451 List<LocalFunctionElement> slowDirectlyNestedClosures(Element element) { 583 List<LocalFunctionElement> slowDirectlyNestedClosures(Element element) {
452 // Return new list to guard against concurrent modifications. 584 // Return new list to guard against concurrent modifications.
453 return new List<LocalFunctionElement>.from( 585 return new List<LocalFunctionElement>.from(
454 allClosures.where((LocalFunctionElement closure) { 586 allClosures.where((LocalFunctionElement closure) {
455 return closure.executableContext == element; 587 return closure.executableContext == element;
456 })); 588 }));
(...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after
694 case StaticUseKind.SUPER_TEAR_OFF: 826 case StaticUseKind.SUPER_TEAR_OFF:
695 methodsNeedingSuperGetter.add(element); 827 methodsNeedingSuperGetter.add(element);
696 break; 828 break;
697 case StaticUseKind.SUPER_FIELD_SET: 829 case StaticUseKind.SUPER_FIELD_SET:
698 case StaticUseKind.FIELD_SET: 830 case StaticUseKind.FIELD_SET:
699 case StaticUseKind.GENERAL: 831 case StaticUseKind.GENERAL:
700 case StaticUseKind.CLOSURE: 832 case StaticUseKind.CLOSURE:
701 case StaticUseKind.FIELD_GET: 833 case StaticUseKind.FIELD_GET:
702 case StaticUseKind.CONSTRUCTOR_INVOKE: 834 case StaticUseKind.CONSTRUCTOR_INVOKE:
703 case StaticUseKind.CONST_CONSTRUCTOR_INVOKE: 835 case StaticUseKind.CONST_CONSTRUCTOR_INVOKE:
836 case StaticUseKind.REDIRECTION:
704 case StaticUseKind.DIRECT_INVOKE: 837 case StaticUseKind.DIRECT_INVOKE:
705 break; 838 break;
706 } 839 }
707 } 840 }
708 841
709 void forgetElement(Element element, Compiler compiler) { 842 void forgetElement(Element element, Compiler compiler) {
710 _directlyInstantiatedClasses.remove(element); 843 _directlyInstantiatedClasses.remove(element);
711 if (element is ClassElement) { 844 if (element is ClassElement) {
712 assert(invariant(element, element.thisType.isRaw, 845 assert(invariant(element, element.thisType.isRaw,
713 message: 'Generic classes not supported (${element.thisType}).')); 846 message: 'Generic classes not supported (${element.thisType}).'));
714 _instantiatedTypes..remove(element.rawType)..remove(element.thisType); 847 _instantiatedTypes..remove(element.rawType)..remove(element.thisType);
715 } 848 }
716 } 849 }
717 } 850 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698