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 '../elements/elements.dart'; | 7 import '../elements/elements.dart'; |
8 import '../dart2jslib.dart'; | 8 import '../dart2jslib.dart'; |
9 import '../dart_types.dart'; | 9 import '../dart_types.dart'; |
10 import '../types/types.dart'; | 10 import '../types/types.dart'; |
11 import '../tree/tree.dart'; | 11 import '../tree/tree.dart'; |
12 import '../util/util.dart'; | 12 import '../util/util.dart'; |
13 | 13 |
14 part 'function_set.dart'; | 14 part 'function_set.dart'; |
15 part 'side_effects.dart'; | 15 part 'side_effects.dart'; |
16 | 16 |
17 class UniverseSelector { | |
18 final Selector selector; | |
19 final TypeMask mask; | |
20 | |
21 UniverseSelector(this.selector, this.mask); | |
22 | |
23 bool appliesUnnamed(Element element, ClassWorld world) { | |
24 return selector.appliesUnnamed(element, world) && | |
25 (mask == null || mask.canHit(element, selector, world)); | |
26 } | |
27 | |
28 String toString() => '$selector,$mask'; | |
29 } | |
30 | |
31 abstract class TypeMaskSet { | |
32 bool applies(Element element, Selector selector, ClassWorld world); | |
33 Iterable<TypeMask> get masks; | |
34 } | |
35 | |
36 /// An implementation of a [TypeMaskSet] that is only increasing, that is, once | |
37 /// a mask is added it cannot be removed. | |
38 class IncreasingTypeMaskSet extends TypeMaskSet { | |
39 bool isAll = false; | |
40 Set<TypeMask> _masks; | |
41 | |
42 bool applies(Element element, Selector selector, ClassWorld world) { | |
43 if (isAll) return true; | |
44 if (_masks == null) return false; | |
45 for (TypeMask mask in _masks) { | |
46 if (mask.canHit(element, selector, world)) return true; | |
47 } | |
48 return false; | |
49 } | |
50 | |
51 bool add(TypeMask mask) { | |
52 if (isAll) return false; | |
53 if (mask == null) { | |
54 isAll = true; | |
55 _masks = null; | |
56 return true; | |
57 } | |
58 if (_masks == null) { | |
59 _masks = new Setlet<TypeMask>(); | |
60 } | |
61 return _masks.add(mask); | |
62 } | |
63 | |
64 Iterable<TypeMask> get masks { | |
65 if (isAll) return const [null]; | |
66 if (_masks == null) return const []; | |
67 return _masks; | |
68 } | |
69 | |
70 String toString() { | |
71 if (isAll) { | |
72 return '<all>'; | |
73 } else if (_masks != null) { | |
74 return '$_masks'; | |
75 } else { | |
76 return '<none>'; | |
77 } | |
78 } | |
79 } | |
80 | |
81 | |
82 | |
83 class Universe { | 17 class Universe { |
84 /// The set of all directly instantiated classes, that is, classes with a | 18 /// The set of all directly instantiated classes, that is, classes with a |
85 /// generative constructor that has been called directly and not only through | 19 /// generative constructor that has been called directly and not only through |
86 /// a super-call. | 20 /// a super-call. |
87 /// | 21 /// |
88 /// Invariant: Elements are declaration elements. | 22 /// Invariant: Elements are declaration elements. |
89 // TODO(johnniwinther): [_directlyInstantiatedClasses] and | 23 // TODO(johnniwinther): [_directlyInstantiatedClasses] and |
90 // [_instantiatedTypes] sets should be merged. | 24 // [_instantiatedTypes] sets should be merged. |
91 final Set<ClassElement> _directlyInstantiatedClasses = | 25 final Set<ClassElement> _directlyInstantiatedClasses = |
92 new Set<ClassElement>(); | 26 new Set<ClassElement>(); |
(...skipping 17 matching lines...) Expand all Loading... |
110 | 44 |
111 /** | 45 /** |
112 * Documentation wanted -- johnniwinther | 46 * Documentation wanted -- johnniwinther |
113 * | 47 * |
114 * Invariant: Elements are declaration elements. | 48 * Invariant: Elements are declaration elements. |
115 */ | 49 */ |
116 final Set<FunctionElement> staticFunctionsNeedingGetter = | 50 final Set<FunctionElement> staticFunctionsNeedingGetter = |
117 new Set<FunctionElement>(); | 51 new Set<FunctionElement>(); |
118 final Set<FunctionElement> methodsNeedingSuperGetter = | 52 final Set<FunctionElement> methodsNeedingSuperGetter = |
119 new Set<FunctionElement>(); | 53 new Set<FunctionElement>(); |
120 final Map<String, Map<Selector, TypeMaskSet>> _invokedNames = | 54 final Map<String, Set<Selector>> invokedNames = |
121 <String, Map<Selector, TypeMaskSet>>{}; | 55 new Map<String, Set<Selector>>(); |
122 final Map<String, Map<Selector, TypeMaskSet>> _invokedGetters = | 56 final Map<String, Set<Selector>> invokedGetters = |
123 <String, Map<Selector, TypeMaskSet>>{}; | 57 new Map<String, Set<Selector>>(); |
124 final Map<String, Map<Selector, TypeMaskSet>> _invokedSetters = | 58 final Map<String, Set<Selector>> invokedSetters = |
125 <String, Map<Selector, TypeMaskSet>>{}; | 59 new Map<String, Set<Selector>>(); |
126 | 60 |
127 /** | 61 /** |
128 * Fields accessed. Currently only the codegen knows this | 62 * Fields accessed. Currently only the codegen knows this |
129 * information. The resolver is too conservative when seeing a | 63 * information. The resolver is too conservative when seeing a |
130 * getter and only registers an invoked getter. | 64 * getter and only registers an invoked getter. |
131 */ | 65 */ |
132 final Set<Element> fieldGetters = new Set<Element>(); | 66 final Set<Element> fieldGetters = new Set<Element>(); |
133 | 67 |
134 /** | 68 /** |
135 * Fields set. See comment in [fieldGetters]. | 69 * Fields set. See comment in [fieldGetters]. |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
218 _directlyInstantiatedClasses.add(cls); | 152 _directlyInstantiatedClasses.add(cls); |
219 } | 153 } |
220 | 154 |
221 // TODO(johnniwinther): Replace this by separate more specific mappings. | 155 // TODO(johnniwinther): Replace this by separate more specific mappings. |
222 if (!_allInstantiatedClasses.add(cls)) return; | 156 if (!_allInstantiatedClasses.add(cls)) return; |
223 cls.allSupertypes.forEach((InterfaceType supertype) { | 157 cls.allSupertypes.forEach((InterfaceType supertype) { |
224 _allInstantiatedClasses.add(supertype.element); | 158 _allInstantiatedClasses.add(supertype.element); |
225 }); | 159 }); |
226 } | 160 } |
227 | 161 |
228 bool _hasMatchingSelector(Map<Selector, TypeMaskSet> selectors, | 162 bool hasMatchingSelector(Set<Selector> selectors, |
229 Element member, | 163 Element member, |
230 World world) { | 164 World world) { |
231 if (selectors == null) return false; | 165 if (selectors == null) return false; |
232 for (Selector selector in selectors.keys) { | 166 for (Selector selector in selectors) { |
233 if (selector.appliesUnnamed(member, world)) { | 167 if (selector.appliesUnnamed(member, world)) return true; |
234 TypeMaskSet masks = selectors[selector]; | |
235 if (masks.applies(member, selector, world)) { | |
236 return true; | |
237 } | |
238 } | |
239 } | 168 } |
240 return false; | 169 return false; |
241 } | 170 } |
242 | 171 |
243 bool hasInvocation(Element member, World world) { | 172 bool hasInvocation(Element member, World world) { |
244 return _hasMatchingSelector(_invokedNames[member.name], member, world); | 173 return hasMatchingSelector(invokedNames[member.name], member, world); |
245 } | 174 } |
246 | 175 |
247 bool hasInvokedGetter(Element member, World world) { | 176 bool hasInvokedGetter(Element member, World world) { |
248 return _hasMatchingSelector(_invokedGetters[member.name], member, world); | 177 return hasMatchingSelector(invokedGetters[member.name], member, world); |
249 } | 178 } |
250 | 179 |
251 bool hasInvokedSetter(Element member, World world) { | 180 bool hasInvokedSetter(Element member, World world) { |
252 return _hasMatchingSelector(_invokedSetters[member.name], member, world); | 181 return hasMatchingSelector(invokedSetters[member.name], member, world); |
253 } | |
254 | |
255 bool registerInvocation(UniverseSelector selector) { | |
256 return _registerNewSelector(selector, _invokedNames); | |
257 } | |
258 | |
259 bool registerInvokedGetter(UniverseSelector selector) { | |
260 return _registerNewSelector(selector, _invokedGetters); | |
261 } | |
262 | |
263 bool registerInvokedSetter(UniverseSelector selector) { | |
264 return _registerNewSelector(selector, _invokedSetters); | |
265 } | |
266 | |
267 bool _registerNewSelector( | |
268 UniverseSelector universeSelector, | |
269 Map<String, Map<Selector, TypeMaskSet>> selectorMap) { | |
270 Selector selector = universeSelector.selector; | |
271 String name = selector.name; | |
272 TypeMask mask = universeSelector.mask; | |
273 Map<Selector, TypeMaskSet> selectors = selectorMap.putIfAbsent( | |
274 name, () => new Maplet<Selector, TypeMaskSet>()); | |
275 IncreasingTypeMaskSet masks = selectors.putIfAbsent( | |
276 selector, () => new IncreasingTypeMaskSet()); | |
277 return masks.add(mask); | |
278 } | |
279 | |
280 Map<Selector, TypeMaskSet> invocationsByName(String name) { | |
281 return _invokedNames[name]; | |
282 } | |
283 | |
284 void forEachInvokedName( | |
285 f(String name, Map<Selector, TypeMaskSet> selectors)) { | |
286 _invokedNames.forEach(f); | |
287 } | |
288 | |
289 void forEachInvokedGetter( | |
290 f(String name, Map<Selector, TypeMaskSet> selectors)) { | |
291 _invokedGetters.forEach(f); | |
292 } | |
293 | |
294 void forEachInvokedSetter( | |
295 f(String name, Map<Selector, TypeMaskSet> selectors)) { | |
296 _invokedSetters.forEach(f); | |
297 } | 182 } |
298 | 183 |
299 DartType registerIsCheck(DartType type, Compiler compiler) { | 184 DartType registerIsCheck(DartType type, Compiler compiler) { |
300 type = type.unalias(compiler); | 185 type = type.unalias(compiler); |
301 // Even in checked mode, type annotations for return type and argument | 186 // Even in checked mode, type annotations for return type and argument |
302 // types do not imply type checks, so there should never be a check | 187 // types do not imply type checks, so there should never be a check |
303 // against the type variable of a typedef. | 188 // against the type variable of a typedef. |
304 isChecks.add(type); | 189 isChecks.add(type); |
305 return type; | 190 return type; |
306 } | 191 } |
(...skipping 369 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
676 Name name, | 561 Name name, |
677 CallStructure callStructure) { | 562 CallStructure callStructure) { |
678 // TODO(johnniwinther): Maybe use equality instead of implicit hashing. | 563 // TODO(johnniwinther): Maybe use equality instead of implicit hashing. |
679 int hashCode = computeHashCode(kind, name, callStructure); | 564 int hashCode = computeHashCode(kind, name, callStructure); |
680 List<Selector> list = canonicalizedValues.putIfAbsent(hashCode, | 565 List<Selector> list = canonicalizedValues.putIfAbsent(hashCode, |
681 () => <Selector>[]); | 566 () => <Selector>[]); |
682 for (int i = 0; i < list.length; i++) { | 567 for (int i = 0; i < list.length; i++) { |
683 Selector existing = list[i]; | 568 Selector existing = list[i]; |
684 if (existing.match(kind, name, callStructure)) { | 569 if (existing.match(kind, name, callStructure)) { |
685 assert(existing.hashCode == hashCode); | 570 assert(existing.hashCode == hashCode); |
| 571 assert(existing.mask == null); |
686 return existing; | 572 return existing; |
687 } | 573 } |
688 } | 574 } |
689 Selector result = new Selector.internal( | 575 Selector result = new Selector.internal( |
690 kind, name, callStructure, hashCode); | 576 kind, name, callStructure, hashCode); |
691 list.add(result); | 577 list.add(result); |
692 return result; | 578 return result; |
693 } | 579 } |
694 | 580 |
695 factory Selector.fromElement(Element element) { | 581 factory Selector.fromElement(Element element) { |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
800 | 686 |
801 bool get isIndex => kind == SelectorKind.INDEX && argumentCount == 1; | 687 bool get isIndex => kind == SelectorKind.INDEX && argumentCount == 1; |
802 bool get isIndexSet => kind == SelectorKind.INDEX && argumentCount == 2; | 688 bool get isIndexSet => kind == SelectorKind.INDEX && argumentCount == 2; |
803 | 689 |
804 bool get isOperator => kind == SelectorKind.OPERATOR; | 690 bool get isOperator => kind == SelectorKind.OPERATOR; |
805 bool get isUnaryOperator => isOperator && argumentCount == 0; | 691 bool get isUnaryOperator => isOperator && argumentCount == 0; |
806 | 692 |
807 /** Check whether this is a call to 'assert'. */ | 693 /** Check whether this is a call to 'assert'. */ |
808 bool get isAssert => isCall && identical(name, "assert"); | 694 bool get isAssert => isCall && identical(name, "assert"); |
809 | 695 |
| 696 bool get hasExactMask => false; |
| 697 TypeMask get mask => null; |
| 698 Selector get asUntyped => this; |
| 699 |
810 /** | 700 /** |
811 * The member name for invocation mirrors created from this selector. | 701 * The member name for invocation mirrors created from this selector. |
812 */ | 702 */ |
813 String get invocationMirrorMemberName => | 703 String get invocationMirrorMemberName => |
814 isSetter ? '$name=' : name; | 704 isSetter ? '$name=' : name; |
815 | 705 |
816 int get invocationMirrorKind { | 706 int get invocationMirrorKind { |
817 const int METHOD = 0; | 707 const int METHOD = 0; |
818 const int GETTER = 1; | 708 const int GETTER = 1; |
819 const int SETTER = 2; | 709 const int SETTER = 2; |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
879 static int computeHashCode(SelectorKind kind, | 769 static int computeHashCode(SelectorKind kind, |
880 Name name, | 770 Name name, |
881 CallStructure callStructure) { | 771 CallStructure callStructure) { |
882 // Add bits from name and kind. | 772 // Add bits from name and kind. |
883 int hash = Hashing.mixHashCodeBits(name.hashCode, kind.hashCode); | 773 int hash = Hashing.mixHashCodeBits(name.hashCode, kind.hashCode); |
884 // Add bits from the call structure. | 774 // Add bits from the call structure. |
885 return Hashing.mixHashCodeBits(hash, callStructure.hashCode); | 775 return Hashing.mixHashCodeBits(hash, callStructure.hashCode); |
886 } | 776 } |
887 | 777 |
888 String toString() { | 778 String toString() { |
889 return 'Selector($kind, $name, ${callStructure.structureToString()})'; | 779 String type = ''; |
| 780 if (mask != null) type = ', mask=$mask'; |
| 781 return 'Selector($kind, $name, ${callStructure.structureToString()}$type)'; |
| 782 } |
| 783 |
| 784 Selector extendIfReachesAll(Compiler compiler) { |
| 785 return new TypedSelector( |
| 786 compiler.typesTask.dynamicType, this, compiler.world); |
890 } | 787 } |
891 | 788 |
892 Selector toCallSelector() => new Selector.callClosureFrom(this); | 789 Selector toCallSelector() => new Selector.callClosureFrom(this); |
893 } | 790 } |
| 791 |
| 792 class TypedSelector extends Selector { |
| 793 final Selector asUntyped; |
| 794 final TypeMask mask; |
| 795 |
| 796 TypedSelector.internal(this.mask, Selector selector, int hashCode) |
| 797 : asUntyped = selector, |
| 798 super.internal(selector.kind, |
| 799 selector.memberName, |
| 800 selector.callStructure, |
| 801 hashCode) { |
| 802 assert(mask != null); |
| 803 assert(asUntyped.mask == null); |
| 804 } |
| 805 |
| 806 |
| 807 factory TypedSelector(TypeMask mask, Selector selector, World world) { |
| 808 if (!world.hasClosedWorldAssumption) { |
| 809 // TODO(johnniwinther): Improve use of TypedSelector in an open world. |
| 810 bool isNullable = mask.isNullable; |
| 811 mask = world.compiler.typesTask.dynamicType; |
| 812 if (isNullable) { |
| 813 mask = mask.nullable(); |
| 814 } |
| 815 } |
| 816 // TODO(johnniwinther): Allow more TypeSelector kinds during resoluton. |
| 817 assert(world.isClosed || mask.isExact); |
| 818 if (selector.mask == mask) return selector; |
| 819 Selector untyped = selector.asUntyped; |
| 820 Map<TypeMask, TypedSelector> map = world.canonicalizedValues |
| 821 .putIfAbsent(untyped, () => new Map<TypeMask, TypedSelector>()); |
| 822 TypedSelector result = map[mask]; |
| 823 if (result == null) { |
| 824 int hashCode = Hashing.mixHashCodeBits(untyped.hashCode, mask.hashCode); |
| 825 result = map[mask] = new TypedSelector.internal(mask, untyped, hashCode); |
| 826 } |
| 827 return result; |
| 828 } |
| 829 |
| 830 factory TypedSelector.exact( |
| 831 ClassElement base, Selector selector, World world) |
| 832 => new TypedSelector(new TypeMask.exact(base, world), selector, |
| 833 world); |
| 834 |
| 835 factory TypedSelector.subclass( |
| 836 ClassElement base, Selector selector, World world) |
| 837 => new TypedSelector(new TypeMask.subclass(base, world), |
| 838 selector, world); |
| 839 |
| 840 factory TypedSelector.subtype( |
| 841 ClassElement base, Selector selector, World world) |
| 842 => new TypedSelector(new TypeMask.subtype(base, world), |
| 843 selector, world); |
| 844 |
| 845 bool appliesUnnamed(Element element, World world) { |
| 846 assert(sameNameHack(element, world)); |
| 847 if (!mask.canHit(element, this, world)) return false; |
| 848 return appliesUntyped(element, world); |
| 849 } |
| 850 |
| 851 Selector extendIfReachesAll(Compiler compiler) { |
| 852 bool canReachAll = compiler.enabledInvokeOn |
| 853 && mask.needsNoSuchMethodHandling(this, compiler.world); |
| 854 return canReachAll |
| 855 ? new TypedSelector( |
| 856 compiler.typesTask.dynamicType, this, compiler.world) |
| 857 : this; |
| 858 } |
| 859 } |
OLD | NEW |