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; | 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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 } |
OLD | NEW |