Index: pkg/compiler/lib/src/universe/class_set.dart |
diff --git a/pkg/compiler/lib/src/universe/class_set.dart b/pkg/compiler/lib/src/universe/class_set.dart |
index 637fd168f1c891cd59fa934c21897837dd8384d3..39f507a30305c91a64405129c793c8d6486fdfa6 100644 |
--- a/pkg/compiler/lib/src/universe/class_set.dart |
+++ b/pkg/compiler/lib/src/universe/class_set.dart |
@@ -6,6 +6,7 @@ library dart2js.world.class_set; |
import 'dart:collection' show IterableBase; |
+import '../common.dart'; |
import '../elements/elements.dart' show ClassElement; |
import '../util/enumset.dart' show EnumSet; |
import '../util/util.dart' show Link; |
@@ -15,6 +16,7 @@ enum Instantiation { |
UNINSTANTIATED, |
DIRECTLY_INSTANTIATED, |
INDIRECTLY_INSTANTIATED, |
+ ABSTRACTLY_INSTANTIATED, |
} |
/// Node for [cls] in a tree forming the subclass relation of [ClassElement]s. |
@@ -49,16 +51,18 @@ class ClassHierarchyNode { |
static final EnumSet<Instantiation> INSTANTIATED = |
new EnumSet<Instantiation>.fromValues(const <Instantiation>[ |
Instantiation.DIRECTLY_INSTANTIATED, |
- Instantiation.INDIRECTLY_INSTANTIATED |
+ Instantiation.INDIRECTLY_INSTANTIATED, |
+ Instantiation.ABSTRACTLY_INSTANTIATED, |
], fixed: true); |
- /// Enum set for selecting directly instantiated classes in |
+ /// Enum set for selecting directly and abstractly instantiated classes in |
/// [ClassHierarchyNode.subclassesByMask], |
/// [ClassHierarchyNode.subclassesByMask] and [ClassSet.subtypesByMask]. |
- static final EnumSet<Instantiation> DIRECTLY_INSTANTIATED = |
- new EnumSet<Instantiation>.fromValues( |
- const <Instantiation>[Instantiation.DIRECTLY_INSTANTIATED], |
- fixed: true); |
+ static final EnumSet<Instantiation> EXPLICITLY_INSTANTIATED = |
+ new EnumSet<Instantiation>.fromValues(const <Instantiation>[ |
+ Instantiation.DIRECTLY_INSTANTIATED, |
+ Instantiation.ABSTRACTLY_INSTANTIATED |
+ ], fixed: true); |
/// Enum set for selecting all classes in |
/// [ClassHierarchyNode.subclassesByMask], |
@@ -72,7 +76,8 @@ class ClassHierarchyNode { |
static EnumSet<Instantiation> createMask( |
{bool includeDirectlyInstantiated: true, |
bool includeIndirectlyInstantiated: true, |
- bool includeUninstantiated: true}) { |
+ bool includeUninstantiated: true, |
+ bool includeAbstractlyInstantiated: true}) { |
EnumSet<Instantiation> mask = new EnumSet<Instantiation>(); |
if (includeDirectlyInstantiated) { |
mask.add(Instantiation.DIRECTLY_INSTANTIATED); |
@@ -83,6 +88,9 @@ class ClassHierarchyNode { |
if (includeUninstantiated) { |
mask.add(Instantiation.UNINSTANTIATED); |
} |
+ if (includeAbstractlyInstantiated) { |
+ mask.add(Instantiation.ABSTRACTLY_INSTANTIATED); |
+ } |
return mask; |
} |
@@ -106,23 +114,54 @@ class ClassHierarchyNode { |
void set isDirectlyInstantiated(bool value) { |
if (value != isDirectlyInstantiated) { |
- ClassHierarchyNode parent = parentNode; |
- if (value) { |
- _mask.remove(Instantiation.UNINSTANTIATED); |
- _mask.add(Instantiation.DIRECTLY_INSTANTIATED); |
- while (parent != null) { |
- parent._updateInstantiatedSubclassCount(1); |
- parent = parent.parentNode; |
- } |
- } else { |
- _mask.remove(Instantiation.DIRECTLY_INSTANTIATED); |
- if (_mask.isEmpty) { |
- _mask.add(Instantiation.UNINSTANTIATED); |
- } |
- while (parent != null) { |
- parent._updateInstantiatedSubclassCount(-1); |
- parent = parent.parentNode; |
- } |
+ _updateParentInstantiatedSubclassCount( |
+ Instantiation.DIRECTLY_INSTANTIATED, |
+ add: value); |
+ } |
+ } |
+ |
+ /// `true` if [cls] has been abstractly instantiated. This means that at |
+ /// runtime instances of [cls] or unknown subclasses of [cls] are assumed to |
+ /// exist. |
+ /// |
+ /// This is used to mark native and/or reflectable classes as instantiated. |
+ /// For native classes we do not know the exact class that instantiates [cls] |
+ /// so [cls] here represents the root of the subclasses. For reflectable |
+ /// classes we need event abstract classes to be 'live' even though they |
+ /// cannot themselves be instantiated. |
+ bool get isAbstractlyInstantiated => |
+ _mask.contains(Instantiation.ABSTRACTLY_INSTANTIATED); |
+ |
+ void set isAbstractlyInstantiated(bool value) { |
+ if (value != isAbstractlyInstantiated) { |
+ _updateParentInstantiatedSubclassCount( |
+ Instantiation.ABSTRACTLY_INSTANTIATED, |
+ add: value); |
+ } |
+ } |
+ |
+ /// `true` if [cls] is either directly or abstractly instantiated. |
+ bool get isExplicitlyInstantiated => |
+ isDirectlyInstantiated || isAbstractlyInstantiated; |
+ |
+ void _updateParentInstantiatedSubclassCount(Instantiation instantiation, |
+ {bool add}) { |
+ ClassHierarchyNode parent = parentNode; |
+ if (add) { |
+ _mask.remove(Instantiation.UNINSTANTIATED); |
+ _mask.add(instantiation); |
+ while (parent != null) { |
+ parent._updateInstantiatedSubclassCount(1); |
+ parent = parent.parentNode; |
+ } |
+ } else { |
+ _mask.remove(instantiation); |
+ if (_mask.isEmpty) { |
+ _mask.add(Instantiation.UNINSTANTIATED); |
+ } |
+ while (parent != null) { |
+ parent._updateInstantiatedSubclassCount(-1); |
+ parent = parent.parentNode; |
} |
} |
} |
@@ -188,8 +227,9 @@ class ClassHierarchyNode { |
return false; |
} |
- /// `true` if [cls] has been directly or indirectly instantiated. |
- bool get isInstantiated => isDirectlyInstantiated || isIndirectlyInstantiated; |
+ /// `true` if [cls] has been directly, indirectly, or abstractly instantiated. |
+ bool get isInstantiated => |
+ isExplicitlyInstantiated || isIndirectlyInstantiated; |
/// Returns an [Iterable] of the subclasses of [cls] possibly including [cls]. |
/// |
@@ -270,9 +310,12 @@ class ClassHierarchyNode { |
} |
ClassElement _computeLeastUpperInstantiatedSubclass() { |
- if (isDirectlyInstantiated) { |
+ if (isExplicitlyInstantiated) { |
return cls; |
} |
+ if (!isInstantiated) { |
+ return null; |
+ } |
ClassHierarchyNode subclass; |
for (Link<ClassHierarchyNode> link = _directSubclasses; |
!link.isEmpty; |
@@ -311,6 +354,9 @@ class ClassHierarchyNode { |
if (isIndirectlyInstantiated) { |
sb.write(' indirectly'); |
} |
+ if (isAbstractlyInstantiated) { |
+ sb.write(' abstractly'); |
+ } |
sb.write(' ['); |
if (_directSubclasses.isEmpty) { |
sb.write(']'); |
@@ -439,7 +485,7 @@ class ClassSet { |
int count = node.instantiatedSubclassCount; |
if (_subtypes != null) { |
for (ClassHierarchyNode subtypeNode in _subtypes) { |
- if (subtypeNode.isDirectlyInstantiated) { |
+ if (subtypeNode.isExplicitlyInstantiated) { |
count++; |
} |
count += subtypeNode.instantiatedSubclassCount; |
@@ -647,7 +693,7 @@ class ClassSet { |
} |
ClassElement _computeLeastUpperInstantiatedSubtype() { |
- if (node.isDirectlyInstantiated) { |
+ if (node.isExplicitlyInstantiated) { |
return cls; |
} |
if (_subtypes == null) { |