Chromium Code Reviews| 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 '../common/names.dart' show | 9 import '../common/names.dart' show |
| 10 Identifiers, | 10 Identifiers, |
| 11 Names, | 11 Names, |
| 12 Selectors; | 12 Selectors; |
| 13 import '../compiler.dart' show | 13 import '../compiler.dart' show |
| 14 Compiler; | 14 Compiler; |
| 15 import '../diagnostics/invariant.dart' show | 15 import '../diagnostics/invariant.dart' show |
| 16 invariant; | 16 invariant; |
| 17 import '../diagnostics/spannable.dart' show | 17 import '../diagnostics/spannable.dart' show |
| 18 SpannableAssertionFailure; | 18 SpannableAssertionFailure; |
| 19 import '../elements/elements.dart'; | 19 import '../elements/elements.dart'; |
| 20 import '../dart_types.dart'; | 20 import '../dart_types.dart'; |
| 21 import '../tree/tree.dart'; | |
| 21 import '../types/types.dart'; | 22 import '../types/types.dart'; |
| 22 import '../tree/tree.dart'; | |
| 23 import '../util/util.dart'; | 23 import '../util/util.dart'; |
| 24 import '../world.dart' show | 24 import '../world.dart' show |
| 25 ClassWorld, | 25 ClassWorld, |
| 26 World; | 26 World; |
| 27 | 27 |
| 28 part 'function_set.dart'; | 28 part 'function_set.dart'; |
| 29 part 'side_effects.dart'; | 29 part 'side_effects.dart'; |
| 30 | 30 |
| 31 class UniverseSelector { | 31 class UniverseSelector { |
| 32 final Selector selector; | 32 final Selector selector; |
| 33 final TypeMask mask; | 33 final ReceiverMask mask; |
| 34 | 34 |
| 35 UniverseSelector(this.selector, this.mask); | 35 UniverseSelector(this.selector, this.mask); |
| 36 | 36 |
| 37 bool appliesUnnamed(Element element, ClassWorld world) { | 37 bool appliesUnnamed(Element element, ClassWorld world) { |
| 38 return selector.appliesUnnamed(element, world) && | 38 return selector.appliesUnnamed(element, world) && |
| 39 (mask == null || mask.canHit(element, selector, world)); | 39 (mask == null || mask.canHit(element, selector, world)); |
| 40 } | 40 } |
| 41 | 41 |
| 42 String toString() => '$selector,$mask'; | 42 String toString() => '$selector,$mask'; |
| 43 } | 43 } |
| 44 | 44 |
| 45 abstract class TypeMaskSet { | 45 /// A potential receiver for a dynamic call site. |
| 46 bool applies(Element element, Selector selector, ClassWorld world); | 46 abstract class ReceiverMask { |
| 47 Iterable<TypeMask> get masks; | 47 /// Returns whether [element] is a potential target when being |
| 48 /// invoked on this type mask. [selector] is used to ensure library | |
|
Siggi Cherem (dart-lang)
2015/09/01 02:12:59
type => receiver?
Johnni Winther
2015/09/01 08:15:51
Done.
| |
| 49 /// privacy is taken into account. | |
| 50 bool canHit(Element element, Selector selector, ClassWorld classWorld); | |
| 48 } | 51 } |
| 49 | 52 |
| 50 /// An implementation of a [TypeMaskSet] that is only increasing, that is, once | 53 /// A set of potential receivers for the dynamic call sites of the same |
| 51 /// a mask is added it cannot be removed. | 54 /// selector. |
| 52 class IncreasingTypeMaskSet extends TypeMaskSet { | 55 /// |
| 53 bool isAll = false; | 56 /// For instance for these calls |
| 54 Set<TypeMask> _masks; | 57 /// |
| 58 /// new A().foo(a, b); | |
| 59 /// new B().foo(0, 42); | |
| 60 /// | |
| 61 /// the receiver mask set for dynamic calls to 'foo' with to positional | |
| 62 /// arguments will contain receiver masks abstracting `new A()` and `new B()`. | |
| 63 abstract class ReceiverMaskSet { | |
|
Siggi Cherem (dart-lang)
2015/09/01 02:12:59
let's keep the term for now, but I wonder if "mask
Johnni Winther
2015/09/01 08:15:51
Acknowledged.
| |
| 64 /// Returns `true` if [selector] applies to any of the potential receivers | |
| 65 /// in this set given the closed [world]. | |
| 66 bool applies(Element element, Selector selector, ClassWorld world); | |
| 55 | 67 |
| 56 bool applies(Element element, Selector selector, ClassWorld world) { | 68 /// Returns `true` if any potential receivers in this set given the closed |
| 57 if (isAll) return true; | 69 /// [world] have no implementation matching [selector]. |
| 58 if (_masks == null) return false; | 70 /// |
| 59 for (TypeMask mask in _masks) { | 71 /// For instance for this code snippet |
| 60 if (mask.canHit(element, selector, world)) return true; | 72 /// |
| 61 } | 73 /// class A {} |
| 62 return false; | 74 /// class B { foo() {} } |
| 63 } | 75 /// m(b) => (b ? new A() : new B()).foo(); |
| 64 | 76 /// |
| 65 bool add(TypeMask mask) { | 77 /// the potential receiver `new A()` have no implementation of `foo` and thus |
| 66 if (isAll) return false; | 78 /// needs to handle the call though its `noSuchMethod` handler. |
| 67 if (mask == null) { | 79 bool needsNoSuchMethodHandling(Selector selector, ClassWorld world); |
| 68 isAll = true; | |
| 69 _masks = null; | |
| 70 return true; | |
| 71 } | |
| 72 if (_masks == null) { | |
| 73 _masks = new Setlet<TypeMask>(); | |
| 74 } | |
| 75 return _masks.add(mask); | |
| 76 } | |
| 77 | |
| 78 Iterable<TypeMask> get masks { | |
| 79 if (isAll) return const [null]; | |
| 80 if (_masks == null) return const []; | |
| 81 return _masks; | |
| 82 } | |
| 83 | |
| 84 String toString() { | |
| 85 if (isAll) { | |
| 86 return '<all>'; | |
| 87 } else if (_masks != null) { | |
| 88 return '$_masks'; | |
| 89 } else { | |
| 90 return '<none>'; | |
| 91 } | |
| 92 } | |
| 93 } | 80 } |
| 94 | 81 |
| 82 /// A mutable [ReceiverMaskSet] used in [Universe]. | |
| 83 abstract class UniverseReceiverMaskSet extends ReceiverMaskSet { | |
| 84 /// Adds [mask] to this set of potential receivers. Return `true` if the | |
| 85 /// set expanded due to the new mask. | |
| 86 bool addReceiverMask(ReceiverMask mask); | |
|
Siggi Cherem (dart-lang)
2015/09/01 02:12:59
if this is the main API to add a possible receiver
Johnni Winther
2015/09/01 08:15:51
Acknowledged.
| |
| 87 } | |
| 95 | 88 |
| 89 /// Strategy for computing potential receivers of dynamic call sites. | |
| 90 abstract class ReceiverMaskStrategy { | |
| 91 /// Create a [UniverseReceiverMaskSet] to represent the potential receiver for | |
| 92 /// a dynamic call site with [selector]. | |
| 93 UniverseReceiverMaskSet createReceiverMaskSet(Selector selector); | |
| 94 } | |
| 96 | 95 |
| 97 class Universe { | 96 class Universe { |
| 98 /// The set of all directly instantiated classes, that is, classes with a | 97 /// The set of all directly instantiated classes, that is, classes with a |
| 99 /// generative constructor that has been called directly and not only through | 98 /// generative constructor that has been called directly and not only through |
| 100 /// a super-call. | 99 /// a super-call. |
| 101 /// | 100 /// |
| 102 /// Invariant: Elements are declaration elements. | 101 /// Invariant: Elements are declaration elements. |
| 103 // TODO(johnniwinther): [_directlyInstantiatedClasses] and | 102 // TODO(johnniwinther): [_directlyInstantiatedClasses] and |
| 104 // [_instantiatedTypes] sets should be merged. | 103 // [_instantiatedTypes] sets should be merged. |
| 105 final Set<ClassElement> _directlyInstantiatedClasses = | 104 final Set<ClassElement> _directlyInstantiatedClasses = |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 124 | 123 |
| 125 /** | 124 /** |
| 126 * Documentation wanted -- johnniwinther | 125 * Documentation wanted -- johnniwinther |
| 127 * | 126 * |
| 128 * Invariant: Elements are declaration elements. | 127 * Invariant: Elements are declaration elements. |
| 129 */ | 128 */ |
| 130 final Set<FunctionElement> staticFunctionsNeedingGetter = | 129 final Set<FunctionElement> staticFunctionsNeedingGetter = |
| 131 new Set<FunctionElement>(); | 130 new Set<FunctionElement>(); |
| 132 final Set<FunctionElement> methodsNeedingSuperGetter = | 131 final Set<FunctionElement> methodsNeedingSuperGetter = |
| 133 new Set<FunctionElement>(); | 132 new Set<FunctionElement>(); |
| 134 final Map<String, Map<Selector, TypeMaskSet>> _invokedNames = | 133 final Map<String, Map<Selector, ReceiverMaskSet>> _invokedNames = |
| 135 <String, Map<Selector, TypeMaskSet>>{}; | 134 <String, Map<Selector, ReceiverMaskSet>>{}; |
| 136 final Map<String, Map<Selector, TypeMaskSet>> _invokedGetters = | 135 final Map<String, Map<Selector, ReceiverMaskSet>> _invokedGetters = |
| 137 <String, Map<Selector, TypeMaskSet>>{}; | 136 <String, Map<Selector, ReceiverMaskSet>>{}; |
| 138 final Map<String, Map<Selector, TypeMaskSet>> _invokedSetters = | 137 final Map<String, Map<Selector, ReceiverMaskSet>> _invokedSetters = |
| 139 <String, Map<Selector, TypeMaskSet>>{}; | 138 <String, Map<Selector, ReceiverMaskSet>>{}; |
| 140 | 139 |
| 141 /** | 140 /** |
| 142 * Fields accessed. Currently only the codegen knows this | 141 * Fields accessed. Currently only the codegen knows this |
| 143 * information. The resolver is too conservative when seeing a | 142 * information. The resolver is too conservative when seeing a |
| 144 * getter and only registers an invoked getter. | 143 * getter and only registers an invoked getter. |
| 145 */ | 144 */ |
| 146 final Set<Element> fieldGetters = new Set<Element>(); | 145 final Set<Element> fieldGetters = new Set<Element>(); |
| 147 | 146 |
| 148 /** | 147 /** |
| 149 * Fields set. See comment in [fieldGetters]. | 148 * Fields set. See comment in [fieldGetters]. |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 171 * to find all live closure instances. | 170 * to find all live closure instances. |
| 172 */ | 171 */ |
| 173 final Set<LocalFunctionElement> allClosures = new Set<LocalFunctionElement>(); | 172 final Set<LocalFunctionElement> allClosures = new Set<LocalFunctionElement>(); |
| 174 | 173 |
| 175 /** | 174 /** |
| 176 * Set of methods in instantiated classes that are potentially | 175 * Set of methods in instantiated classes that are potentially |
| 177 * closurized. | 176 * closurized. |
| 178 */ | 177 */ |
| 179 final Set<Element> closurizedMembers = new Set<Element>(); | 178 final Set<Element> closurizedMembers = new Set<Element>(); |
| 180 | 179 |
| 180 final ReceiverMaskStrategy receiverMaskStrategy; | |
| 181 | |
| 182 Universe(this.receiverMaskStrategy); | |
| 183 | |
| 181 /// All directly instantiated classes, that is, classes with a generative | 184 /// All directly instantiated classes, that is, classes with a generative |
| 182 /// constructor that has been called directly and not only through a | 185 /// constructor that has been called directly and not only through a |
| 183 /// super-call. | 186 /// super-call. |
| 184 // TODO(johnniwinther): Improve semantic precision. | 187 // TODO(johnniwinther): Improve semantic precision. |
| 185 Iterable<ClassElement> get directlyInstantiatedClasses { | 188 Iterable<ClassElement> get directlyInstantiatedClasses { |
| 186 return _directlyInstantiatedClasses; | 189 return _directlyInstantiatedClasses; |
| 187 } | 190 } |
| 188 | 191 |
| 189 /// All instantiated classes, either directly, as superclasses or as | 192 /// All instantiated classes, either directly, as superclasses or as |
| 190 /// supertypes. | 193 /// supertypes. |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 232 _directlyInstantiatedClasses.add(cls); | 235 _directlyInstantiatedClasses.add(cls); |
| 233 } | 236 } |
| 234 | 237 |
| 235 // TODO(johnniwinther): Replace this by separate more specific mappings. | 238 // TODO(johnniwinther): Replace this by separate more specific mappings. |
| 236 if (!_allInstantiatedClasses.add(cls)) return; | 239 if (!_allInstantiatedClasses.add(cls)) return; |
| 237 cls.allSupertypes.forEach((InterfaceType supertype) { | 240 cls.allSupertypes.forEach((InterfaceType supertype) { |
| 238 _allInstantiatedClasses.add(supertype.element); | 241 _allInstantiatedClasses.add(supertype.element); |
| 239 }); | 242 }); |
| 240 } | 243 } |
| 241 | 244 |
| 242 bool _hasMatchingSelector(Map<Selector, TypeMaskSet> selectors, | 245 bool _hasMatchingSelector(Map<Selector, ReceiverMaskSet> selectors, |
| 243 Element member, | 246 Element member, |
| 244 World world) { | 247 World world) { |
| 245 if (selectors == null) return false; | 248 if (selectors == null) return false; |
| 246 for (Selector selector in selectors.keys) { | 249 for (Selector selector in selectors.keys) { |
| 247 if (selector.appliesUnnamed(member, world)) { | 250 if (selector.appliesUnnamed(member, world)) { |
| 248 TypeMaskSet masks = selectors[selector]; | 251 ReceiverMaskSet masks = selectors[selector]; |
| 249 if (masks.applies(member, selector, world)) { | 252 if (masks.applies(member, selector, world)) { |
| 250 return true; | 253 return true; |
| 251 } | 254 } |
| 252 } | 255 } |
| 253 } | 256 } |
| 254 return false; | 257 return false; |
| 255 } | 258 } |
| 256 | 259 |
| 257 bool hasInvocation(Element member, World world) { | 260 bool hasInvocation(Element member, World world) { |
| 258 return _hasMatchingSelector(_invokedNames[member.name], member, world); | 261 return _hasMatchingSelector(_invokedNames[member.name], member, world); |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 273 bool registerInvokedGetter(UniverseSelector selector) { | 276 bool registerInvokedGetter(UniverseSelector selector) { |
| 274 return _registerNewSelector(selector, _invokedGetters); | 277 return _registerNewSelector(selector, _invokedGetters); |
| 275 } | 278 } |
| 276 | 279 |
| 277 bool registerInvokedSetter(UniverseSelector selector) { | 280 bool registerInvokedSetter(UniverseSelector selector) { |
| 278 return _registerNewSelector(selector, _invokedSetters); | 281 return _registerNewSelector(selector, _invokedSetters); |
| 279 } | 282 } |
| 280 | 283 |
| 281 bool _registerNewSelector( | 284 bool _registerNewSelector( |
| 282 UniverseSelector universeSelector, | 285 UniverseSelector universeSelector, |
| 283 Map<String, Map<Selector, TypeMaskSet>> selectorMap) { | 286 Map<String, Map<Selector, ReceiverMaskSet>> selectorMap) { |
| 284 Selector selector = universeSelector.selector; | 287 Selector selector = universeSelector.selector; |
| 285 String name = selector.name; | 288 String name = selector.name; |
| 286 TypeMask mask = universeSelector.mask; | 289 ReceiverMask mask = universeSelector.mask; |
| 287 Map<Selector, TypeMaskSet> selectors = selectorMap.putIfAbsent( | 290 Map<Selector, ReceiverMaskSet> selectors = selectorMap.putIfAbsent( |
| 288 name, () => new Maplet<Selector, TypeMaskSet>()); | 291 name, () => new Maplet<Selector, ReceiverMaskSet>()); |
| 289 IncreasingTypeMaskSet masks = selectors.putIfAbsent( | 292 UniverseReceiverMaskSet masks = selectors.putIfAbsent( |
| 290 selector, () => new IncreasingTypeMaskSet()); | 293 selector, () => receiverMaskStrategy.createReceiverMaskSet(selector)); |
| 291 return masks.add(mask); | 294 return masks.addReceiverMask(mask); |
| 292 } | 295 } |
| 293 | 296 |
| 294 Map<Selector, TypeMaskSet> _asUnmodifiable(Map<Selector, TypeMaskSet> map) { | 297 Map<Selector, ReceiverMaskSet> _asUnmodifiable( |
| 298 Map<Selector, ReceiverMaskSet> map) { | |
| 295 if (map == null) return null; | 299 if (map == null) return null; |
| 296 return new UnmodifiableMapView(map); | 300 return new UnmodifiableMapView(map); |
| 297 } | 301 } |
| 298 | 302 |
| 299 Map<Selector, TypeMaskSet> invocationsByName(String name) { | 303 Map<Selector, ReceiverMaskSet> invocationsByName(String name) { |
| 300 return _asUnmodifiable(_invokedNames[name]); | 304 return _asUnmodifiable(_invokedNames[name]); |
| 301 } | 305 } |
| 302 | 306 |
| 303 Map<Selector, TypeMaskSet> getterInvocationsByName(String name) { | 307 Map<Selector, ReceiverMaskSet> getterInvocationsByName(String name) { |
| 304 return _asUnmodifiable(_invokedGetters[name]); | 308 return _asUnmodifiable(_invokedGetters[name]); |
| 305 } | 309 } |
| 306 | 310 |
| 307 Map<Selector, TypeMaskSet> setterInvocationsByName(String name) { | 311 Map<Selector, ReceiverMaskSet> setterInvocationsByName(String name) { |
| 308 return _asUnmodifiable(_invokedSetters[name]); | 312 return _asUnmodifiable(_invokedSetters[name]); |
| 309 } | 313 } |
| 310 | 314 |
| 311 void forEachInvokedName( | 315 void forEachInvokedName( |
| 312 f(String name, Map<Selector, TypeMaskSet> selectors)) { | 316 f(String name, Map<Selector, ReceiverMaskSet> selectors)) { |
| 313 _invokedNames.forEach(f); | 317 _invokedNames.forEach(f); |
| 314 } | 318 } |
| 315 | 319 |
| 316 void forEachInvokedGetter( | 320 void forEachInvokedGetter( |
| 317 f(String name, Map<Selector, TypeMaskSet> selectors)) { | 321 f(String name, Map<Selector, ReceiverMaskSet> selectors)) { |
| 318 _invokedGetters.forEach(f); | 322 _invokedGetters.forEach(f); |
| 319 } | 323 } |
| 320 | 324 |
| 321 void forEachInvokedSetter( | 325 void forEachInvokedSetter( |
| 322 f(String name, Map<Selector, TypeMaskSet> selectors)) { | 326 f(String name, Map<Selector, ReceiverMaskSet> selectors)) { |
| 323 _invokedSetters.forEach(f); | 327 _invokedSetters.forEach(f); |
| 324 } | 328 } |
| 325 | 329 |
| 326 DartType registerIsCheck(DartType type, Compiler compiler) { | 330 DartType registerIsCheck(DartType type, Compiler compiler) { |
| 327 type = type.unalias(compiler); | 331 type = type.unalias(compiler); |
| 328 // Even in checked mode, type annotations for return type and argument | 332 // Even in checked mode, type annotations for return type and argument |
| 329 // types do not imply type checks, so there should never be a check | 333 // types do not imply type checks, so there should never be a check |
| 330 // against the type variable of a typedef. | 334 // against the type variable of a typedef. |
| 331 isChecks.add(type); | 335 isChecks.add(type); |
| 332 return type; | 336 return type; |
| (...skipping 570 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 903 // Add bits from the call structure. | 907 // Add bits from the call structure. |
| 904 return Hashing.mixHashCodeBits(hash, callStructure.hashCode); | 908 return Hashing.mixHashCodeBits(hash, callStructure.hashCode); |
| 905 } | 909 } |
| 906 | 910 |
| 907 String toString() { | 911 String toString() { |
| 908 return 'Selector($kind, $name, ${callStructure.structureToString()})'; | 912 return 'Selector($kind, $name, ${callStructure.structureToString()})'; |
| 909 } | 913 } |
| 910 | 914 |
| 911 Selector toCallSelector() => new Selector.callClosureFrom(this); | 915 Selector toCallSelector() => new Selector.callClosureFrom(this); |
| 912 } | 916 } |
| OLD | NEW |