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

Unified Diff: pkg/compiler/lib/src/universe/world_builder.dart

Issue 2545413002: Move processing of instantiated classes from ResolutionEnqueuer to ResolutionWorldBuilderImpl (Closed)
Patch Set: Updated cf. comments Created 4 years 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/compiler/lib/src/enqueue.dart ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/universe/world_builder.dart
diff --git a/pkg/compiler/lib/src/universe/world_builder.dart b/pkg/compiler/lib/src/universe/world_builder.dart
index d024fe3348be7be87ecf98effad3d4fdc3257180..33168c59872add128dc759b1aa97001fd262cfde 100644
--- a/pkg/compiler/lib/src/universe/world_builder.dart
+++ b/pkg/compiler/lib/src/universe/world_builder.dart
@@ -372,19 +372,22 @@ class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder {
final Map<String, Map<Selector, SelectorConstraints>> _invokedSetters =
<String, Map<Selector, SelectorConstraints>>{};
+ final Map<ClassElement, _ClassUsage> _processedClasses =
+ <ClassElement, _ClassUsage>{};
+
/// Map of registers usage of instance members of live classes.
- final Map<MemberEntity, MemberUsage> _instanceMemberUsage =
- <MemberEntity, MemberUsage>{};
+ final Map<MemberEntity, _MemberUsage> _instanceMemberUsage =
+ <MemberEntity, _MemberUsage>{};
/// Map containing instance members of live classes that are not yet live
/// themselves.
- final Map<String, Set<MemberUsage>> _instanceMembersByName =
- <String, Set<MemberUsage>>{};
+ final Map<String, Set<_MemberUsage>> _instanceMembersByName =
+ <String, Set<_MemberUsage>>{};
/// Map containing instance methods of live classes that are not yet
/// closurized.
- final Map<String, Set<MemberUsage>> _instanceFunctionsByName =
- <String, Set<MemberUsage>>{};
+ final Map<String, Set<_MemberUsage>> _instanceFunctionsByName =
+ <String, Set<_MemberUsage>>{};
/// Fields set.
final Set<Element> fieldSetters = new Set<Element>();
@@ -440,6 +443,9 @@ class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder {
new WorldImpl(this, backend, resolution.coreClasses, cacheStrategy);
}
+ Iterable<ClassElement> get processedClasses => _processedClasses.keys
+ .where((cls) => _processedClasses[cls].isInstantiated);
+
OpenWorld get openWorld => _openWorld;
/// All directly instantiated classes, that is, classes with a generative
@@ -490,33 +496,32 @@ class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder {
// TODO(johnniwinther): Fully enforce the separation between exact, through
// subclass and through subtype instantiated types/classes.
// TODO(johnniwinther): Support unknown type arguments for generic types.
- void registerTypeInstantiation(InterfaceType type,
+ void registerTypeInstantiation(InterfaceType type, ClassUsed classUsed,
{ConstructorElement constructor,
bool byMirrors: false,
- bool isNative: false,
- bool isRedirection: false,
- void onImplemented(ClassElement cls)}) {
+ bool isRedirection: false}) {
ClassElement cls = type.element;
+ cls.ensureResolved(_resolution);
InstantiationInfo info =
_instantiationInfo.putIfAbsent(cls, () => new InstantiationInfo());
Instantiation kind = Instantiation.UNINSTANTIATED;
- if (!cls.isAbstract
+ bool isNative = _backend.isNative(cls);
+ if (!cls.isAbstract ||
// We can't use the closed-world assumption with native abstract
// classes; a native abstract class may have non-abstract subclasses
// not declared to the program. Instances of these classes are
// indistinguishable from the abstract class.
- ||
- isNative
+ isNative ||
// Likewise, if this registration comes from the mirror system,
// all bets are off.
// TODO(herhut): Track classes required by mirrors seperately.
- ||
byMirrors) {
if (isNative || byMirrors) {
kind = Instantiation.ABSTRACTLY_INSTANTIATED;
} else {
kind = Instantiation.DIRECTLY_INSTANTIATED;
}
+ _processInstantiatedClass(cls, classUsed);
}
info.addInstantiation(constructor, type, kind,
isRedirection: isRedirection);
@@ -524,6 +529,11 @@ class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder {
// TODO(johnniwinther): Use [_instantiationInfo] to compute this information
// instead.
if (_implementedClasses.add(cls)) {
+ void onImplemented(ClassElement cls) {
+ _ClassUsage usage = _getClassUsage(cls);
+ classUsed(usage.cls, usage.implement());
+ }
+
onImplemented(cls);
cls.allSupertypes.forEach((InterfaceType supertype) {
if (_implementedClasses.add(supertype.element)) {
@@ -615,9 +625,9 @@ class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder {
switch (dynamicUse.kind) {
case DynamicUseKind.INVOKE:
if (_registerNewSelector(dynamicUse, _invokedNames)) {
- _processInstanceMembers(methodName, (MemberUsage usage) {
- if (dynamicUse.appliesUnnamed(usage.member, _openWorld)) {
- memberUsed(usage.member, usage.invoke());
+ _processInstanceMembers(methodName, (_MemberUsage usage) {
+ if (dynamicUse.appliesUnnamed(usage.entity, _openWorld)) {
+ memberUsed(usage.entity, usage.invoke());
return true;
}
return false;
@@ -626,16 +636,16 @@ class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder {
break;
case DynamicUseKind.GET:
if (_registerNewSelector(dynamicUse, _invokedGetters)) {
- _processInstanceMembers(methodName, (MemberUsage usage) {
- if (dynamicUse.appliesUnnamed(usage.member, _openWorld)) {
- memberUsed(usage.member, usage.read());
+ _processInstanceMembers(methodName, (_MemberUsage usage) {
+ if (dynamicUse.appliesUnnamed(usage.entity, _openWorld)) {
+ memberUsed(usage.entity, usage.read());
return true;
}
return false;
});
- _processInstanceFunctions(methodName, (MemberUsage usage) {
- if (dynamicUse.appliesUnnamed(usage.member, _openWorld)) {
- memberUsed(usage.member, usage.read());
+ _processInstanceFunctions(methodName, (_MemberUsage usage) {
+ if (dynamicUse.appliesUnnamed(usage.entity, _openWorld)) {
+ memberUsed(usage.entity, usage.read());
return true;
}
return false;
@@ -644,9 +654,9 @@ class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder {
break;
case DynamicUseKind.SET:
if (_registerNewSelector(dynamicUse, _invokedSetters)) {
- _processInstanceMembers(methodName, (MemberUsage usage) {
- if (dynamicUse.appliesUnnamed(usage.member, _openWorld)) {
- memberUsed(usage.member, usage.write());
+ _processInstanceMembers(methodName, (_MemberUsage usage) {
+ if (dynamicUse.appliesUnnamed(usage.entity, _openWorld)) {
+ memberUsed(usage.entity, usage.write());
return true;
}
return false;
@@ -718,12 +728,13 @@ class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder {
fieldSetters.remove(element);
_instantiationInfo.remove(element);
- void removeUsage(Set<MemberUsage> set, Element element) {
+ void removeUsage(Set<_MemberUsage> set, Element element) {
if (set == null) return;
set.removeAll(
- set.where((MemberUsage usage) => usage.member == element).toList());
+ set.where((_MemberUsage usage) => usage.entity == element).toList());
}
+ _processedClasses.remove(element);
removeUsage(_instanceMembersByName[element.name], element);
removeUsage(_instanceFunctionsByName[element.name], element);
}
@@ -738,32 +749,67 @@ class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder {
}));
}
- void _processSet(Map<String, Set<MemberUsage>> map, String memberName,
- bool f(MemberUsage e)) {
- Set<MemberUsage> members = map[memberName];
+ /// Return the canonical [_ClassUsage] for [cls].
+ _ClassUsage _getClassUsage(ClassElement cls) {
+ return _processedClasses.putIfAbsent(cls, () {
+ cls.ensureResolved(_resolution);
+ _ClassUsage usage = new _ClassUsage(cls);
+ _resolution.ensureClassMembers(cls);
+ return usage;
+ });
+ }
+
+ /// Register [cls] and all its superclasses as instantiated.
+ void _processInstantiatedClass(ClassElement cls, ClassUsed classUsed) {
+ // Registers [superclass] as instantiated. Returns `true` if it wasn't
+ // already instantiated and we therefore have to process its superclass as
+ // well.
+ bool processClass(ClassElement superclass) {
+ _ClassUsage usage = _getClassUsage(superclass);
+ if (!usage.isInstantiated) {
+ classUsed(usage.cls, usage.instantiate());
+ return true;
+ }
+ return false;
+ }
+
+ while (cls != null && processClass(cls)) {
+ cls = cls.superclass;
+ }
+ }
+
+ /// Computes usage for all members declared by [cls]. Calls [membersUsed] with
+ /// the usage changes for each member.
+ void processClassMembers(ClassElement cls, MemberUsed memberUsed) {
+ cls.implementation.forEachMember((ClassElement cls, MemberElement member) {
+ _processInstantiatedClassMember(cls, member, memberUsed);
+ });
+ }
+
+ void _processSet(Map<String, Set<_MemberUsage>> map, String memberName,
+ bool f(_MemberUsage e)) {
+ Set<_MemberUsage> members = map[memberName];
if (members == null) return;
// [f] might add elements to [: map[memberName] :] during the loop below
// so we create a new list for [: map[memberName] :] and prepend the
// [remaining] members after the loop.
- map[memberName] = new Set<MemberUsage>();
- Set<MemberUsage> remaining = new Set<MemberUsage>();
- for (MemberUsage usage in members) {
+ map[memberName] = new Set<_MemberUsage>();
+ Set<_MemberUsage> remaining = new Set<_MemberUsage>();
+ for (_MemberUsage usage in members) {
if (!f(usage)) remaining.add(usage);
}
map[memberName].addAll(remaining);
}
- void _processInstanceMembers(String n, bool f(MemberUsage e)) {
- _processSet(_instanceMembersByName, n, f);
+ void _processInstanceMembers(String name, bool f(_MemberUsage e)) {
+ _processSet(_instanceMembersByName, name, f);
}
- void _processInstanceFunctions(String n, bool f(MemberUsage e)) {
+ void _processInstanceFunctions(String n, bool f(_MemberUsage e)) {
_processSet(_instanceFunctionsByName, n, f);
}
- // TODO(johnniwinther): Make this private when
- // [ResolutionEnqueuer._processClass] is move to [ResolutionWorldBuilderImpl].
- void processInstantiatedClassMember(
+ void _processInstantiatedClassMember(
ClassElement cls, MemberElement member, MemberUsed memberUsed) {
assert(invariant(member, member.isDeclaration));
if (!member.isInstanceMember) return;
@@ -778,8 +824,8 @@ class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder {
// Note: this assumes that there are no non-native fields on native
// classes, which may not be the case when a native class is subclassed.
bool isNative = _backend.isNative(cls);
- MemberUsage usage = _instanceMemberUsage.putIfAbsent(member, () {
- MemberUsage usage = new MemberUsage(member, isNative: isNative);
+ _MemberUsage usage = _instanceMemberUsage.putIfAbsent(member, () {
+ _MemberUsage usage = new _MemberUsage(member, isNative: isNative);
useSet.addAll(usage.appliedUse);
if (member.isField && isNative) {
_openWorld.registerUsedElement(member);
@@ -799,18 +845,18 @@ class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder {
// The element is not yet used. Add it to the list of instance
// members to still be processed.
_instanceMembersByName
- .putIfAbsent(memberName, () => new Set<MemberUsage>())
+ .putIfAbsent(memberName, () => new Set<_MemberUsage>())
.add(usage);
}
if (usage.pendingUse.contains(MemberUse.CLOSURIZE)) {
// Store the member in [instanceFunctionsByName] to catch
// getters on the function.
_instanceFunctionsByName
- .putIfAbsent(memberName, () => new Set<MemberUsage>())
+ .putIfAbsent(memberName, () => new Set<_MemberUsage>())
.add(usage);
}
- memberUsed(usage.member, useSet);
+ memberUsed(usage.entity, useSet);
return usage;
});
}
@@ -1080,17 +1126,30 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
}
}
-/// Registry for the observed use of [member] in the open world.
-abstract class MemberUsage {
- // TODO(johnniwinther): Change [Entity] to [MemberEntity].
- final Entity member;
- final EnumSet<MemberUse> _pendingUse = new EnumSet<MemberUse>();
+abstract class _AbstractUsage<T> {
+ final EnumSet<T> _pendingUse = new EnumSet<T>();
- MemberUsage.internal(this.member) {
+ _AbstractUsage() {
_pendingUse.addAll(_originalUse);
}
- factory MemberUsage(MemberEntity member, {bool isNative: false}) {
+ /// Returns the possible uses of [entity] that have not yet been registered.
+ EnumSet<T> get pendingUse => _pendingUse;
+
+ /// Returns the uses of [entity] that have been registered.
+ EnumSet<T> get appliedUse => _originalUse.minus(_pendingUse);
+
+ EnumSet<T> get _originalUse;
+}
+
+/// Registry for the observed use of a member [entity] in the open world.
+abstract class _MemberUsage extends _AbstractUsage<MemberUse> {
+ // TODO(johnniwinther): Change [Entity] to [MemberEntity].
+ final Entity entity;
+
+ _MemberUsage.internal(this.entity);
+
+ factory _MemberUsage(MemberEntity member, {bool isNative: false}) {
if (member.isField) {
if (member.isAssignable) {
return new _FieldUsage(member, isNative: isNative);
@@ -1107,64 +1166,55 @@ abstract class MemberUsage {
}
}
- /// `true` if [member] has be read as a value. For a field this is a normal
+ /// `true` if [entity] has be read as a value. For a field this is a normal
/// read access, for a function this is a closurization.
bool get hasRead => false;
- /// `true` if a value as been written to [member].
+ /// `true` if a value as been written to [entity].
bool get hasWrite => false;
- /// `true` if an invocation has been performed on the value [member]. For a
+ /// `true` if an invocation has been performed on the value [entity]. For a
/// function this is a normal invocation, for a field this is a read access
/// followed by an invocation of the function-like value.
bool get hasInvoke => false;
- /// `true` if [member] has been used in all the ways possible.
+ /// `true` if [entity] has been used in all the ways possible.
bool get fullyUsed;
- /// Registers a read of the value of [member] and returns the new [MemberUse]s
+ /// Registers a read of the value of [entity] and returns the new [MemberUse]s
/// that it caused.
///
/// For a field this is a normal read access, for a function this is a
/// closurization.
EnumSet<MemberUse> read() => MemberUse.NONE;
- /// Registers a write of a value to [member] and returns the new [MemberUse]s
+ /// Registers a write of a value to [entity] and returns the new [MemberUse]s
/// that it caused.
EnumSet<MemberUse> write() => MemberUse.NONE;
- /// Registers an invocation on the value of [member] and returns the new
+ /// Registers an invocation on the value of [entity] and returns the new
/// [MemberUse]s that it caused.
///
/// For a function this is a normal invocation, for a field this is a read
/// access followed by an invocation of the function-like value.
EnumSet<MemberUse> invoke() => MemberUse.NONE;
- /// Registers all possible uses of [member] and returns the new [MemberUse]s
+ /// Registers all possible uses of [entity] and returns the new [MemberUse]s
/// that it caused.
EnumSet<MemberUse> fullyUse() => MemberUse.NONE;
- /// Returns the possible [MemberUse]s of [member] that have not yet been
- /// registered.
- EnumSet<MemberUse> get pendingUse => _pendingUse;
-
- /// Returns the [MemberUse]s of [member] that have been registered.
- EnumSet<MemberUse> get appliedUse => _originalUse.minus(_pendingUse);
-
- EnumSet<MemberUse> get _originalUse;
-
- int get hashCode => member.hashCode;
+ int get hashCode => entity.hashCode;
bool operator ==(other) {
if (identical(this, other)) return true;
- if (other is! MemberUsage) return false;
- return member == other.member;
+ if (other is! _MemberUsage) return false;
+ return entity == other.entity;
}
- String toString() => member.toString();
+ String toString() => entity.toString();
}
-class _FieldUsage extends MemberUsage {
+class _FieldUsage extends _MemberUsage {
bool hasRead = false;
bool hasWrite = false;
@@ -1214,7 +1264,7 @@ class _FieldUsage extends MemberUsage {
}
}
-class _FinalFieldUsage extends MemberUsage {
+class _FinalFieldUsage extends _MemberUsage {
bool hasRead = false;
_FinalFieldUsage(FieldEntity field, {bool isNative: false})
@@ -1248,7 +1298,7 @@ class _FinalFieldUsage extends MemberUsage {
EnumSet<MemberUse> fullyUse() => read();
}
-class _FunctionUsage extends MemberUsage {
+class _FunctionUsage extends _MemberUsage {
bool hasInvoke = false;
bool hasRead = false;
@@ -1290,7 +1340,7 @@ class _FunctionUsage extends MemberUsage {
bool get fullyUsed => hasInvoke && hasRead;
}
-class _GetterUsage extends MemberUsage {
+class _GetterUsage extends _MemberUsage {
bool hasRead = false;
_GetterUsage(FunctionEntity getter) : super.internal(getter);
@@ -1316,7 +1366,7 @@ class _GetterUsage extends MemberUsage {
EnumSet<MemberUse> fullyUse() => read();
}
-class _SetterUsage extends MemberUsage {
+class _SetterUsage extends _MemberUsage {
bool hasWrite = false;
_SetterUsage(FunctionEntity setter) : super.internal(setter);
@@ -1345,6 +1395,8 @@ class MemberUse {
const MemberUse._(this.index);
+ String toString() => 'MemberUse($index)';
+
static const List<MemberUse> values = const <MemberUse>[NORMAL, CLOSURIZE];
static const MemberUse NORMAL = const MemberUse._(0);
@@ -1359,3 +1411,50 @@ class MemberUse {
}
typedef void MemberUsed(MemberEntity member, EnumSet<MemberUse> useSet);
+
+/// Registry for the observed use of a class [entity] in the open world.
+// TODO(johnniwinther): Merge this with [InstantiationInfo].
+class _ClassUsage extends _AbstractUsage<ClassUse> {
+ bool isInstantiated = false;
+ bool isImplemented = false;
+
+ final ClassEntity cls;
+
+ _ClassUsage(this.cls);
+
+ EnumSet<ClassUse> instantiate() {
+ if (isInstantiated) {
+ return ClassUses.NONE;
+ }
+ isInstantiated = true;
+ return _pendingUse.removeAll(ClassUses.INSTANTIATED_ONLY);
+ }
+
+ EnumSet<ClassUse> implement() {
+ if (isImplemented) {
+ return ClassUses.NONE;
+ }
+ isImplemented = true;
+ return _pendingUse.removeAll(ClassUses.IMPLEMENTED_ONLY);
+ }
+
+ @override
+ EnumSet<ClassUse> get _originalUse => ClassUses.ALL;
+
+ String toString() => cls.toString();
+}
+
+/// Enum class for the possible kind of use of [ClassEntity] objects.
+enum ClassUse { INSTANTIATED, IMPLEMENTED }
+
+/// Common [EnumSet]s used for [ClassUse].
+class ClassUses {
+ static const EnumSet<ClassUse> NONE = const EnumSet<ClassUse>.fixed(0);
+ static const EnumSet<ClassUse> INSTANTIATED_ONLY =
+ const EnumSet<ClassUse>.fixed(1);
+ static const EnumSet<ClassUse> IMPLEMENTED_ONLY =
+ const EnumSet<ClassUse>.fixed(2);
+ static const EnumSet<ClassUse> ALL = const EnumSet<ClassUse>.fixed(3);
+}
+
+typedef void ClassUsed(ClassEntity cls, EnumSet<ClassUse> useSet);
« no previous file with comments | « pkg/compiler/lib/src/enqueue.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698