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

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

Issue 2443953002: Introduce isAbstractlyInstantiated to avoid exact masks of abstract classes. (Closed)
Patch Set: Updated cf. comments. 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) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, 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 dart2js.world.class_set; 5 library dart2js.world.class_set;
6 6
7 import 'dart:collection' show IterableBase; 7 import 'dart:collection' show IterableBase;
8 8
9 import '../common.dart';
9 import '../elements/elements.dart' show ClassElement; 10 import '../elements/elements.dart' show ClassElement;
10 import '../util/enumset.dart' show EnumSet; 11 import '../util/enumset.dart' show EnumSet;
11 import '../util/util.dart' show Link; 12 import '../util/util.dart' show Link;
12 13
13 /// Enum for the different kinds of instantiation of a class. 14 /// Enum for the different kinds of instantiation of a class.
14 enum Instantiation { 15 enum Instantiation {
15 UNINSTANTIATED, 16 UNINSTANTIATED,
16 DIRECTLY_INSTANTIATED, 17 DIRECTLY_INSTANTIATED,
17 INDIRECTLY_INSTANTIATED, 18 INDIRECTLY_INSTANTIATED,
19 ABSTRACTLY_INSTANTIATED,
18 } 20 }
19 21
20 /// Node for [cls] in a tree forming the subclass relation of [ClassElement]s. 22 /// Node for [cls] in a tree forming the subclass relation of [ClassElement]s.
21 /// 23 ///
22 /// This is used by the [ClosedWorld] to perform queries on subclass and subtype 24 /// This is used by the [ClosedWorld] to perform queries on subclass and subtype
23 /// relations. 25 /// relations.
24 /// 26 ///
25 /// For this class hierarchy: 27 /// For this class hierarchy:
26 /// 28 ///
27 /// class A {} 29 /// class A {}
(...skipping 14 matching lines...) Expand all
42 /// | 44 /// |
43 /// E 45 /// E
44 /// 46 ///
45 class ClassHierarchyNode { 47 class ClassHierarchyNode {
46 /// Enum set for selecting instantiated classes in 48 /// Enum set for selecting instantiated classes in
47 /// [ClassHierarchyNode.subclassesByMask], 49 /// [ClassHierarchyNode.subclassesByMask],
48 /// [ClassHierarchyNode.subclassesByMask] and [ClassSet.subtypesByMask]. 50 /// [ClassHierarchyNode.subclassesByMask] and [ClassSet.subtypesByMask].
49 static final EnumSet<Instantiation> INSTANTIATED = 51 static final EnumSet<Instantiation> INSTANTIATED =
50 new EnumSet<Instantiation>.fromValues(const <Instantiation>[ 52 new EnumSet<Instantiation>.fromValues(const <Instantiation>[
51 Instantiation.DIRECTLY_INSTANTIATED, 53 Instantiation.DIRECTLY_INSTANTIATED,
52 Instantiation.INDIRECTLY_INSTANTIATED 54 Instantiation.INDIRECTLY_INSTANTIATED,
55 Instantiation.ABSTRACTLY_INSTANTIATED,
53 ], fixed: true); 56 ], fixed: true);
54 57
55 /// Enum set for selecting directly instantiated classes in 58 /// Enum set for selecting directly and abstractly instantiated classes in
56 /// [ClassHierarchyNode.subclassesByMask], 59 /// [ClassHierarchyNode.subclassesByMask],
57 /// [ClassHierarchyNode.subclassesByMask] and [ClassSet.subtypesByMask]. 60 /// [ClassHierarchyNode.subclassesByMask] and [ClassSet.subtypesByMask].
58 static final EnumSet<Instantiation> DIRECTLY_INSTANTIATED = 61 static final EnumSet<Instantiation> EXPLICITLY_INSTANTIATED =
59 new EnumSet<Instantiation>.fromValues( 62 new EnumSet<Instantiation>.fromValues(const <Instantiation>[
60 const <Instantiation>[Instantiation.DIRECTLY_INSTANTIATED], 63 Instantiation.DIRECTLY_INSTANTIATED,
61 fixed: true); 64 Instantiation.ABSTRACTLY_INSTANTIATED
65 ], fixed: true);
62 66
63 /// Enum set for selecting all classes in 67 /// Enum set for selecting all classes in
64 /// [ClassHierarchyNode.subclassesByMask], 68 /// [ClassHierarchyNode.subclassesByMask],
65 /// [ClassHierarchyNode.subclassesByMask] and [ClassSet.subtypesByMask]. 69 /// [ClassHierarchyNode.subclassesByMask] and [ClassSet.subtypesByMask].
66 static final EnumSet<Instantiation> ALL = 70 static final EnumSet<Instantiation> ALL =
67 new EnumSet<Instantiation>.fromValues(Instantiation.values, fixed: true); 71 new EnumSet<Instantiation>.fromValues(Instantiation.values, fixed: true);
68 72
69 /// Creates an enum set for selecting the returned classes in 73 /// Creates an enum set for selecting the returned classes in
70 /// [ClassHierarchyNode.subclassesByMask], 74 /// [ClassHierarchyNode.subclassesByMask],
71 /// [ClassHierarchyNode.subclassesByMask] and [ClassSet.subtypesByMask]. 75 /// [ClassHierarchyNode.subclassesByMask] and [ClassSet.subtypesByMask].
72 static EnumSet<Instantiation> createMask( 76 static EnumSet<Instantiation> createMask(
73 {bool includeDirectlyInstantiated: true, 77 {bool includeDirectlyInstantiated: true,
74 bool includeIndirectlyInstantiated: true, 78 bool includeIndirectlyInstantiated: true,
75 bool includeUninstantiated: true}) { 79 bool includeUninstantiated: true,
80 bool includeAbstractlyInstantiated: true}) {
76 EnumSet<Instantiation> mask = new EnumSet<Instantiation>(); 81 EnumSet<Instantiation> mask = new EnumSet<Instantiation>();
77 if (includeDirectlyInstantiated) { 82 if (includeDirectlyInstantiated) {
78 mask.add(Instantiation.DIRECTLY_INSTANTIATED); 83 mask.add(Instantiation.DIRECTLY_INSTANTIATED);
79 } 84 }
80 if (includeIndirectlyInstantiated) { 85 if (includeIndirectlyInstantiated) {
81 mask.add(Instantiation.INDIRECTLY_INSTANTIATED); 86 mask.add(Instantiation.INDIRECTLY_INSTANTIATED);
82 } 87 }
83 if (includeUninstantiated) { 88 if (includeUninstantiated) {
84 mask.add(Instantiation.UNINSTANTIATED); 89 mask.add(Instantiation.UNINSTANTIATED);
85 } 90 }
91 if (includeAbstractlyInstantiated) {
92 mask.add(Instantiation.ABSTRACTLY_INSTANTIATED);
93 }
86 return mask; 94 return mask;
87 } 95 }
88 96
89 final ClassHierarchyNode parentNode; 97 final ClassHierarchyNode parentNode;
90 final ClassElement cls; 98 final ClassElement cls;
91 final EnumSet<Instantiation> _mask = new EnumSet<Instantiation>.fromValues( 99 final EnumSet<Instantiation> _mask = new EnumSet<Instantiation>.fromValues(
92 const <Instantiation>[Instantiation.UNINSTANTIATED]); 100 const <Instantiation>[Instantiation.UNINSTANTIATED]);
93 101
94 ClassElement _leastUpperInstantiatedSubclass; 102 ClassElement _leastUpperInstantiatedSubclass;
95 int _instantiatedSubclassCount = 0; 103 int _instantiatedSubclassCount = 0;
96 104
97 /// `true` if [cls] has been directly instantiated. 105 /// `true` if [cls] has been directly instantiated.
98 /// 106 ///
99 /// For instance `C` but _not_ `B` in: 107 /// For instance `C` but _not_ `B` in:
100 /// class B {} 108 /// class B {}
101 /// class C extends B {} 109 /// class C extends B {}
102 /// main() => new C(); 110 /// main() => new C();
103 /// 111 ///
104 bool get isDirectlyInstantiated => 112 bool get isDirectlyInstantiated =>
105 _mask.contains(Instantiation.DIRECTLY_INSTANTIATED); 113 _mask.contains(Instantiation.DIRECTLY_INSTANTIATED);
106 114
107 void set isDirectlyInstantiated(bool value) { 115 void set isDirectlyInstantiated(bool value) {
108 if (value != isDirectlyInstantiated) { 116 if (value != isDirectlyInstantiated) {
109 ClassHierarchyNode parent = parentNode; 117 _updateParentInstantiatedSubclassCount(
110 if (value) { 118 Instantiation.DIRECTLY_INSTANTIATED,
111 _mask.remove(Instantiation.UNINSTANTIATED); 119 add: value);
112 _mask.add(Instantiation.DIRECTLY_INSTANTIATED); 120 }
113 while (parent != null) { 121 }
114 parent._updateInstantiatedSubclassCount(1); 122
115 parent = parent.parentNode; 123 /// `true` if [cls] has been abstractly instantiated. This means that at
116 } 124 /// runtime instances of [cls] or unknown subclasses of [cls] are assumed to
117 } else { 125 /// exist.
118 _mask.remove(Instantiation.DIRECTLY_INSTANTIATED); 126 ///
119 if (_mask.isEmpty) { 127 /// This is used to mark native and/or reflectable classes as instantiated.
120 _mask.add(Instantiation.UNINSTANTIATED); 128 /// For native classes we do not know the exact class that instantiates [cls]
121 } 129 /// so [cls] here represents the root of the subclasses. For reflectable
122 while (parent != null) { 130 /// classes we need event abstract classes to be 'live' even though they
123 parent._updateInstantiatedSubclassCount(-1); 131 /// cannot themselves be instantiated.
124 parent = parent.parentNode; 132 bool get isAbstractlyInstantiated =>
125 } 133 _mask.contains(Instantiation.ABSTRACTLY_INSTANTIATED);
134
135 void set isAbstractlyInstantiated(bool value) {
136 if (value != isAbstractlyInstantiated) {
137 _updateParentInstantiatedSubclassCount(
138 Instantiation.ABSTRACTLY_INSTANTIATED,
139 add: value);
140 }
141 }
142
143 /// `true` if [cls] is either directly or abstractly instantiated.
144 bool get isExplicitlyInstantiated =>
145 isDirectlyInstantiated || isAbstractlyInstantiated;
146
147 void _updateParentInstantiatedSubclassCount(Instantiation instantiation,
148 {bool add}) {
149 ClassHierarchyNode parent = parentNode;
150 if (add) {
151 _mask.remove(Instantiation.UNINSTANTIATED);
152 _mask.add(instantiation);
153 while (parent != null) {
154 parent._updateInstantiatedSubclassCount(1);
155 parent = parent.parentNode;
156 }
157 } else {
158 _mask.remove(instantiation);
159 if (_mask.isEmpty) {
160 _mask.add(Instantiation.UNINSTANTIATED);
161 }
162 while (parent != null) {
163 parent._updateInstantiatedSubclassCount(-1);
164 parent = parent.parentNode;
126 } 165 }
127 } 166 }
128 } 167 }
129 168
130 /// `true` if [cls] has been instantiated through subclasses. 169 /// `true` if [cls] has been instantiated through subclasses.
131 /// 170 ///
132 /// For instance `A` and `B` but _not_ `C` in: 171 /// For instance `A` and `B` but _not_ `C` in:
133 /// class A {} 172 /// class A {}
134 /// class B extends A {} 173 /// class B extends A {}
135 /// class C extends B {} 174 /// class C extends B {}
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
181 /// This means that [other] is a subclass of [cls]. 220 /// This means that [other] is a subclass of [cls].
182 bool contains(ClassElement other) { 221 bool contains(ClassElement other) {
183 while (other != null) { 222 while (other != null) {
184 if (cls == other) return true; 223 if (cls == other) return true;
185 if (cls.hierarchyDepth >= other.hierarchyDepth) return false; 224 if (cls.hierarchyDepth >= other.hierarchyDepth) return false;
186 other = other.superclass; 225 other = other.superclass;
187 } 226 }
188 return false; 227 return false;
189 } 228 }
190 229
191 /// `true` if [cls] has been directly or indirectly instantiated. 230 /// `true` if [cls] has been directly, indirectly, or abstractly instantiated.
192 bool get isInstantiated => isDirectlyInstantiated || isIndirectlyInstantiated; 231 bool get isInstantiated =>
232 isExplicitlyInstantiated || isIndirectlyInstantiated;
193 233
194 /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls]. 234 /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls].
195 /// 235 ///
196 /// Subclasses are included if their instantiation properties intersect with 236 /// Subclasses are included if their instantiation properties intersect with
197 /// their corresponding [Instantiation] values in [mask]. If [strict] is 237 /// their corresponding [Instantiation] values in [mask]. If [strict] is
198 /// `true`, [cls] itself is _not_ returned. 238 /// `true`, [cls] itself is _not_ returned.
199 Iterable<ClassElement> subclassesByMask(EnumSet<Instantiation> mask, 239 Iterable<ClassElement> subclassesByMask(EnumSet<Instantiation> mask,
200 {bool strict: false}) { 240 {bool strict: false}) {
201 return new ClassHierarchyNodeIterable(this, mask, includeRoot: !strict); 241 return new ClassHierarchyNodeIterable(this, mask, includeRoot: !strict);
202 } 242 }
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
263 ClassElement getLubOfInstantiatedSubclasses() { 303 ClassElement getLubOfInstantiatedSubclasses() {
264 if (!isInstantiated) return null; 304 if (!isInstantiated) return null;
265 if (_leastUpperInstantiatedSubclass == null) { 305 if (_leastUpperInstantiatedSubclass == null) {
266 _leastUpperInstantiatedSubclass = 306 _leastUpperInstantiatedSubclass =
267 _computeLeastUpperInstantiatedSubclass(); 307 _computeLeastUpperInstantiatedSubclass();
268 } 308 }
269 return _leastUpperInstantiatedSubclass; 309 return _leastUpperInstantiatedSubclass;
270 } 310 }
271 311
272 ClassElement _computeLeastUpperInstantiatedSubclass() { 312 ClassElement _computeLeastUpperInstantiatedSubclass() {
273 if (isDirectlyInstantiated) { 313 if (isExplicitlyInstantiated) {
274 return cls; 314 return cls;
275 } 315 }
316 if (!isInstantiated) {
317 return null;
318 }
276 ClassHierarchyNode subclass; 319 ClassHierarchyNode subclass;
277 for (Link<ClassHierarchyNode> link = _directSubclasses; 320 for (Link<ClassHierarchyNode> link = _directSubclasses;
278 !link.isEmpty; 321 !link.isEmpty;
279 link = link.tail) { 322 link = link.tail) {
280 if (link.head.isInstantiated) { 323 if (link.head.isInstantiated) {
281 if (subclass == null) { 324 if (subclass == null) {
282 subclass = link.head; 325 subclass = link.head;
283 } else { 326 } else {
284 return cls; 327 return cls;
285 } 328 }
(...skipping 18 matching lines...) Expand all
304 if (cls.isAbstract) { 347 if (cls.isAbstract) {
305 sb.write('abstract '); 348 sb.write('abstract ');
306 } 349 }
307 sb.write('class ${cls.name}:'); 350 sb.write('class ${cls.name}:');
308 if (isDirectlyInstantiated) { 351 if (isDirectlyInstantiated) {
309 sb.write(' directly'); 352 sb.write(' directly');
310 } 353 }
311 if (isIndirectlyInstantiated) { 354 if (isIndirectlyInstantiated) {
312 sb.write(' indirectly'); 355 sb.write(' indirectly');
313 } 356 }
357 if (isAbstractlyInstantiated) {
358 sb.write(' abstractly');
359 }
314 sb.write(' ['); 360 sb.write(' [');
315 if (_directSubclasses.isEmpty) { 361 if (_directSubclasses.isEmpty) {
316 sb.write(']'); 362 sb.write(']');
317 } else { 363 } else {
318 var subclasses = _directSubclasses; 364 var subclasses = _directSubclasses;
319 if (sorted) { 365 if (sorted) {
320 subclasses = _directSubclasses.toList() 366 subclasses = _directSubclasses.toList()
321 ..sort((a, b) { 367 ..sort((a, b) {
322 return a.cls.name.compareTo(b.cls.name); 368 return a.cls.name.compareTo(b.cls.name);
323 }); 369 });
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
432 478
433 ClassSet(this.node); 479 ClassSet(this.node);
434 480
435 ClassElement get cls => node.cls; 481 ClassElement get cls => node.cls;
436 482
437 /// Returns the number of directly instantiated subtypes of [cls]. 483 /// Returns the number of directly instantiated subtypes of [cls].
438 int get instantiatedSubtypeCount { 484 int get instantiatedSubtypeCount {
439 int count = node.instantiatedSubclassCount; 485 int count = node.instantiatedSubclassCount;
440 if (_subtypes != null) { 486 if (_subtypes != null) {
441 for (ClassHierarchyNode subtypeNode in _subtypes) { 487 for (ClassHierarchyNode subtypeNode in _subtypes) {
442 if (subtypeNode.isDirectlyInstantiated) { 488 if (subtypeNode.isExplicitlyInstantiated) {
443 count++; 489 count++;
444 } 490 }
445 count += subtypeNode.instantiatedSubclassCount; 491 count += subtypeNode.instantiatedSubclassCount;
446 } 492 }
447 } 493 }
448 return count; 494 return count;
449 } 495 }
450 496
451 /// Returns `true` if all instantiated subtypes of [cls] are subclasses of 497 /// Returns `true` if all instantiated subtypes of [cls] are subclasses of
452 /// [cls]. 498 /// [cls].
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after
640 /// directly instantiated or a superclass of all directly instantiated 686 /// directly instantiated or a superclass of all directly instantiated
641 /// subtypes. If no subtypes of [cls] are instantiated, `null` is returned. 687 /// subtypes. If no subtypes of [cls] are instantiated, `null` is returned.
642 ClassElement getLubOfInstantiatedSubtypes() { 688 ClassElement getLubOfInstantiatedSubtypes() {
643 if (_leastUpperInstantiatedSubtype == null) { 689 if (_leastUpperInstantiatedSubtype == null) {
644 _leastUpperInstantiatedSubtype = _computeLeastUpperInstantiatedSubtype(); 690 _leastUpperInstantiatedSubtype = _computeLeastUpperInstantiatedSubtype();
645 } 691 }
646 return _leastUpperInstantiatedSubtype; 692 return _leastUpperInstantiatedSubtype;
647 } 693 }
648 694
649 ClassElement _computeLeastUpperInstantiatedSubtype() { 695 ClassElement _computeLeastUpperInstantiatedSubtype() {
650 if (node.isDirectlyInstantiated) { 696 if (node.isExplicitlyInstantiated) {
651 return cls; 697 return cls;
652 } 698 }
653 if (_subtypes == null) { 699 if (_subtypes == null) {
654 return node.getLubOfInstantiatedSubclasses(); 700 return node.getLubOfInstantiatedSubclasses();
655 } 701 }
656 ClassHierarchyNode subtype; 702 ClassHierarchyNode subtype;
657 if (node.isInstantiated) { 703 if (node.isInstantiated) {
658 subtype = node; 704 subtype = node;
659 } 705 }
660 for (ClassHierarchyNode subnode in _subtypes) { 706 for (ClassHierarchyNode subnode in _subtypes) {
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after
854 STOP, 900 STOP,
855 901
856 /// Iteration skips the subclasses of the current class. 902 /// Iteration skips the subclasses of the current class.
857 SKIP_SUBCLASSES, 903 SKIP_SUBCLASSES,
858 } 904 }
859 905
860 /// Visiting function used for the `forEachX` functions of [ClassHierarchyNode] 906 /// Visiting function used for the `forEachX` functions of [ClassHierarchyNode]
861 /// and [ClassSet]. The return value controls the continued iteration. If `null` 907 /// and [ClassSet]. The return value controls the continued iteration. If `null`
862 /// is returned, iteration continues to the end. 908 /// is returned, iteration continues to the end.
863 typedef IterationStep ForEachFunction(ClassElement cls); 909 typedef IterationStep ForEachFunction(ClassElement cls);
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/types/union_type_mask.dart ('k') | pkg/compiler/lib/src/universe/world_builder.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698