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

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

Issue 2506393002: Enhance precision of recorded instantiation info in ResolutionWorldBuilder (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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/compiler/lib/src/universe/use.dart ('k') | pkg/compiler/lib/src/world.dart » ('j') | 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 fa4108aa282ab8ce8ca2fcb149cb9862be2891a1..caa50e60b4ad1869a91fb71d176f8dc31e24f2bb 100644
--- a/pkg/compiler/lib/src/universe/world_builder.dart
+++ b/pkg/compiler/lib/src/universe/world_builder.dart
@@ -14,9 +14,7 @@ import '../compiler.dart' show Compiler;
import '../core_types.dart' show CoreClasses;
import '../dart_types.dart';
import '../elements/elements.dart';
-import '../types/masks.dart' show CommonMasks;
import '../universe/class_set.dart' show Instantiation;
-import '../util/enumset.dart';
import '../util/util.dart';
import '../world.dart' show World, ClosedWorld, OpenWorld, WorldImpl;
import 'selector.dart' show Selector;
@@ -164,9 +162,10 @@ abstract class ResolutionWorldBuilder implements WorldBuilder {
/// Set of all fields that are statically known to be written to.
Iterable<Element> get fieldSetters;
- /// Call [f] for all directly or abstractly instantiated classes.
- void forEachInstantiatedClass(
- f(ClassElement cls, EnumSet<Instantiation> instantiations));
+ /// Call [f] for all classes with instantiated types. This includes the
+ /// directly and abstractly instantiated classes but also classes whose type
+ /// arguments are used in live factory constructors.
+ void forEachInstantiatedClass(f(ClassElement cls, InstantiationInfo info));
/// `true` of `Object.runtimeType` is supported.
bool get hasRuntimeTypeSupport;
@@ -182,22 +181,172 @@ abstract class ResolutionWorldBuilder implements WorldBuilder {
OpenWorld get openWorld;
}
-class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder {
- /// The set of all directly instantiated classes, that is, classes with a
- /// generative constructor that has been called directly and not only through
- /// a super-call.
+/// The type and kind of an instantiation registered through
+/// `ResolutionWorldBuilder.registerTypeInstantiation`.
+class Instance {
+ final InterfaceType type;
+ final Instantiation kind;
+ final bool isRedirection;
+
+ Instance(this.type, this.kind, {this.isRedirection: false});
+
+ int get hashCode {
+ return Hashing.objectHash(
+ type, Hashing.objectHash(kind, Hashing.objectHash(isRedirection)));
+ }
+
+ bool operator ==(other) {
+ if (identical(this, other)) return true;
+ if (other is! Instance) return false;
+ return type == other.type &&
+ kind == other.kind &&
+ isRedirection == other.isRedirection;
+ }
+
+ String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.write(type);
+ if (kind == Instantiation.DIRECTLY_INSTANTIATED) {
+ sb.write(' directly');
+ } else if (kind == Instantiation.ABSTRACTLY_INSTANTIATED) {
+ sb.write(' abstractly');
+ } else if (kind == Instantiation.UNINSTANTIATED) {
+ sb.write(' none');
+ }
+ if (isRedirection) {
+ sb.write(' redirect');
+ }
+ return sb.toString();
+ }
+}
+
+/// Information about instantiations of a class.
+class InstantiationInfo {
+ /// A map from constructor of the class to their instantiated types.
///
- /// Invariant: Elements are declaration elements.
- // TODO(johnniwinther): [_directlyInstantiatedClasses] and
- // [_instantiatedTypes] sets should be merged.
- final Map<ClassElement, EnumSet<Instantiation>> _directlyInstantiatedClasses =
- <ClassElement, EnumSet<Instantiation>>{};
+ /// For instance
+ ///
+ /// import 'dart:html';
+ ///
+ /// abstract class AbstractClass<S> {
+ /// factory AbstractClass.a() = Class<S>.a;
+ /// factory AbstractClass.b() => new Class<S>.b();
+ /// }
+ /// class Class<T> implements AbstractClass<T> {
+ /// Class.a();
+ /// Class.b();
+ /// factory Class.c() = Class.b<T>;
+ /// }
+ ///
+ ///
+ /// main() {
+ /// new Class.a();
+ /// new Class<int>.a();
+ /// new Class<String>.b();
+ /// new Class<num>.c();
+ /// new AbstractClass<double>.a();
+ /// new AbstractClass<bool>.b();
+ /// new DivElement(); // native instantiation
+ /// }
+ ///
+ /// will generate the mappings
+ ///
+ /// AbstractClass: {
+ /// AbstractClass.a: {
+ /// AbstractClass<double> none, // from `new AbstractClass<double>.a()`
+ /// },
+ /// AbstractClass.b: {
+ /// AbstractClass<bool> none, // from `new AbstractClass<bool>.b()`
+ /// },
+ /// },
+ /// Class: {
+ /// Class.a: {
+ /// Class directly, // from `new Class.a()`
+ /// Class<int> directly, // from `new Class<int>.a()`
+ /// Class<S> directly redirect, // from `factory AbstractClass.a`
+ /// },
+ /// Class.b: {
+ /// Class<String> directly, // from `new Class<String>.b()`
+ /// Class<T> directly redirect, // from `factory Class.c`
+ /// Class<S> directly, // from `factory AbstractClass.b`
+ /// },
+ /// Class.c: {
+ /// Class<num> directly, // from `new Class<num>.c()`
+ /// },
+ /// },
+ /// DivElement: {
+ /// DivElement: {
+ /// DivElement abstractly, // from `new DivElement()`
+ /// },
+ /// }
+ ///
+ /// If the constructor is unknown, for instance for native or mirror usage,
+ /// `null` is used as key.
+ Map<ConstructorElement, Set<Instance>> instantiationMap;
+
+ /// Register [type] as the instantiation [kind] using [constructor].
+ void addInstantiation(
+ ConstructorElement constructor, InterfaceType type, Instantiation kind,
+ {bool isRedirection: false}) {
+ instantiationMap ??= <ConstructorElement, Set<Instance>>{};
+ instantiationMap
+ .putIfAbsent(constructor, () => new Set<Instance>())
+ .add(new Instance(type, kind, isRedirection: isRedirection));
+ switch (kind) {
+ case Instantiation.DIRECTLY_INSTANTIATED:
+ isDirectlyInstantiated = true;
+ break;
+ case Instantiation.ABSTRACTLY_INSTANTIATED:
+ isAbstractlyInstantiated = true;
+ break;
+ case Instantiation.UNINSTANTIATED:
+ break;
+ default:
+ throw new StateError("Instantiation $kind is not allowed.");
+ }
+ }
- /// The set of all directly instantiated types, that is, the types of the
- /// directly instantiated classes.
+ /// `true` if the class is either directly or abstractly instantiated.
+ bool get hasInstantiation =>
+ isDirectlyInstantiated || isAbstractlyInstantiated;
+
+ /// `true` if the class is directly instantiated.
+ bool isDirectlyInstantiated = false;
+
+ /// `true` if the class is abstractly instantiated.
+ bool isAbstractlyInstantiated = false;
+
+ String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.write('InstantiationInfo[');
+ if (instantiationMap != null) {
+ bool needsComma = false;
+ instantiationMap
+ .forEach((ConstructorElement constructor, Set<Instance> set) {
+ if (needsComma) {
+ sb.write(', ');
+ }
+ if (constructor != null) {
+ sb.write(constructor);
+ } else {
+ sb.write('<unknown>');
+ }
+ sb.write(': ');
+ sb.write(set);
+ needsComma = true;
+ });
+ }
+ sb.write(']');
+ return sb.toString();
+ }
+}
+
+class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder {
+ /// Instantiation information for all classes with instantiated types.
///
- /// See [_directlyInstantiatedClasses].
- final Set<DartType> _instantiatedTypes = new Set<DartType>();
+ /// Invariant: Elements are declaration elements.
+ final Map<ClassElement, InstantiationInfo> _instantiationInfo =
+ <ClassElement, InstantiationInfo>{};
/// Classes implemented by directly instantiated classes.
final Set<ClassElement> _implementedClasses = new Set<ClassElement>();
@@ -272,7 +421,13 @@ class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder {
/// super-call.
// TODO(johnniwinther): Improve semantic precision.
Iterable<ClassElement> get directlyInstantiatedClasses {
- return _directlyInstantiatedClasses.keys;
+ Set<ClassElement> classes = new Set<ClassElement>();
+ _instantiationInfo.forEach((ClassElement cls, InstantiationInfo info) {
+ if (info.hasInstantiation) {
+ classes.add(cls);
+ }
+ });
+ return classes;
}
/// All directly instantiated types, that is, the types of the directly
@@ -280,7 +435,19 @@ class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder {
///
/// See [directlyInstantiatedClasses].
// TODO(johnniwinther): Improve semantic precision.
- Iterable<DartType> get instantiatedTypes => _instantiatedTypes;
+ Iterable<DartType> get instantiatedTypes {
+ Set<InterfaceType> types = new Set<InterfaceType>();
+ _instantiationInfo.forEach((_, InstantiationInfo info) {
+ if (info.instantiationMap != null) {
+ for (Set<Instance> instances in info.instantiationMap.values) {
+ for (Instance instance in instances) {
+ types.add(instance.type);
+ }
+ }
+ }
+ });
+ return types;
+ }
/// Returns `true` if [cls] is considered to be implemented by an
/// instantiated class, either directly, through subclasses or through
@@ -298,11 +465,15 @@ class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder {
// subclass and through subtype instantiated types/classes.
// TODO(johnniwinther): Support unknown type arguments for generic types.
void registerTypeInstantiation(InterfaceType type,
- {bool byMirrors: false,
+ {ConstructorElement constructor,
+ bool byMirrors: false,
bool isNative: false,
+ bool isRedirection: false,
void onImplemented(ClassElement cls)}) {
- _instantiatedTypes.add(type);
ClassElement cls = type.element;
+ InstantiationInfo info =
+ _instantiationInfo.putIfAbsent(cls, () => new InstantiationInfo());
+ Instantiation kind = Instantiation.UNINSTANTIATED;
if (!cls.isAbstract
// We can't use the closed-world assumption with native abstract
// classes; a native abstract class may have non-abstract subclasses
@@ -315,17 +486,17 @@ class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder {
// TODO(herhut): Track classes required by mirrors seperately.
||
byMirrors) {
- EnumSet<Instantiation> instantiations = _directlyInstantiatedClasses
- .putIfAbsent(cls, () => new EnumSet<Instantiation>());
if (isNative || byMirrors) {
- instantiations.add(Instantiation.ABSTRACTLY_INSTANTIATED);
+ kind = Instantiation.ABSTRACTLY_INSTANTIATED;
} else {
- instantiations.add(Instantiation.DIRECTLY_INSTANTIATED);
+ kind = Instantiation.DIRECTLY_INSTANTIATED;
}
}
+ info.addInstantiation(constructor, type, kind,
+ isRedirection: isRedirection);
- // TODO(johnniwinther): Replace this by separate more specific mappings that
- // include the type arguments.
+ // TODO(johnniwinther): Use [_instantiationInfo] to compute this information
+ // instead.
if (_implementedClasses.add(cls)) {
onImplemented(cls);
cls.allSupertypes.forEach((InterfaceType supertype) {
@@ -337,9 +508,8 @@ class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder {
}
@override
- void forEachInstantiatedClass(
- f(ClassElement cls, EnumSet<Instantiation> instantiations)) {
- _directlyInstantiatedClasses.forEach(f);
+ void forEachInstantiatedClass(f(ClassElement cls, InstantiationInfo info)) {
+ _instantiationInfo.forEach(f);
}
bool _hasMatchingSelector(Map<Selector, SelectorConstraints> selectors,
@@ -422,6 +592,7 @@ class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder {
case StaticUseKind.FIELD_GET:
case StaticUseKind.CONSTRUCTOR_INVOKE:
case StaticUseKind.CONST_CONSTRUCTOR_INVOKE:
+ case StaticUseKind.REDIRECTION:
break;
case StaticUseKind.CLOSURE:
allClosures.add(element);
@@ -438,12 +609,7 @@ class ResolutionWorldBuilderImpl implements ResolutionWorldBuilder {
slowDirectlyNestedClosures(element).forEach(compiler.forgetElement);
closurizedMembers.remove(element);
fieldSetters.remove(element);
- _directlyInstantiatedClasses.remove(element);
- if (element is ClassElement) {
- assert(invariant(element, element.thisType.isRaw,
- message: 'Generic classes not supported (${element.thisType}).'));
- _instantiatedTypes..remove(element.rawType)..remove(element.thisType);
- }
+ _instantiationInfo.remove(element);
}
// TODO(ahe): Replace this method with something that is O(1), for example,
@@ -701,6 +867,7 @@ class CodegenWorldBuilderImpl implements CodegenWorldBuilder {
case StaticUseKind.FIELD_GET:
case StaticUseKind.CONSTRUCTOR_INVOKE:
case StaticUseKind.CONST_CONSTRUCTOR_INVOKE:
+ case StaticUseKind.REDIRECTION:
case StaticUseKind.DIRECT_INVOKE:
break;
}
« no previous file with comments | « pkg/compiler/lib/src/universe/use.dart ('k') | pkg/compiler/lib/src/world.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698