Index: pkg/compiler/lib/src/universe/universe.dart |
diff --git a/pkg/compiler/lib/src/universe/universe.dart b/pkg/compiler/lib/src/universe/universe.dart |
index cb574bb95bc1e63a40c944025f9d4ea6a90f156a..55a47641507f88b0697f8dec2dba2f0ca45b6612 100644 |
--- a/pkg/compiler/lib/src/universe/universe.dart |
+++ b/pkg/compiler/lib/src/universe/universe.dart |
@@ -106,8 +106,62 @@ abstract class SelectorConstraintsStrategy { |
/// [ClassWorld]. The concepts here and in [ClassWorld] are very similar -- in |
/// the same way that the "universe expands" you can think of this as a mutable |
/// world that is expanding as we visit and discover parts of the program. |
-/// TODO(sigmund): rename to "growing/expanding/mutable world"? |
-class Universe { |
+// TODO(sigmund): rename to "growing/expanding/mutable world"? |
+// TODO(johnniwinther): Move common implementation to a [UniverseBase] when |
+// universes and worlds have been unified. |
+abstract class Universe { |
+ /// All directly instantiated classes, that is, classes with a generative |
+ /// constructor that has been called directly and not only through a |
+ /// super-call. |
+ // TODO(johnniwinther): Improve semantic precision. |
+ Iterable<ClassElement> get directlyInstantiatedClasses; |
+ |
+ /// All types that are checked either through is, as or checked mode checks. |
+ Iterable<DartType> get isChecks; |
+ |
+ /// Registers that [type] is checked in this universe. The unaliased type is |
+ /// returned. |
+ DartType registerIsCheck(DartType type, Compiler compiler); |
+ |
+ /// All directly instantiated types, that is, the types of the directly |
+ /// instantiated classes. |
+ // TODO(johnniwinther): Improve semantic precision. |
+ Iterable<DartType> get instantiatedTypes; |
+ |
+ /// Returns `true` if [member] is invoked as a setter. |
+ bool hasInvokedSetter(Element member, World world); |
+} |
+ |
+abstract class ResolutionUniverse implements Universe { |
+ /// Set of (live) local functions (closures) whose signatures reference type |
+ /// variables. |
+ /// |
+ /// A live function is one whose enclosing member function has been enqueued. |
+ Set<Element> get closuresWithFreeTypeVariables; |
+ |
+ /// Set of (live) `call` methods whose signatures reference type variables. |
+ /// |
+ /// A live `call` method is one whose enclosing class has been instantiated. |
+ Iterable<Element> get callMethodsWithFreeTypeVariables; |
+ |
+ /// Set of all closures in the program. Used by the mirror tracking system |
+ /// to find all live closure instances. |
+ Iterable<LocalFunctionElement> get allClosures; |
+ |
+ /// Set of methods in instantiated classes that are potentially closurized. |
+ Iterable<Element> get closurizedMembers; |
+ |
+ /// Returns `true` if [cls] is considered to be implemented by an |
+ /// instantiated class, either directly, through subclasses or through |
+ /// subtypes. The latter case only contains spurious information from |
+ /// instantiations through factory constructors and mixins. |
+ bool isImplemented(ClassElement cls); |
+ |
+ /// Set of all fields that are statically known to be written to. |
+ Iterable<Element> get fieldSetters; |
+} |
+ |
+class ResolutionUniverseImpl implements ResolutionUniverse { |
/// 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. |
@@ -137,8 +191,6 @@ class Universe { |
* |
* Invariant: Elements are declaration elements. |
*/ |
- final Set<FunctionElement> staticFunctionsNeedingGetter = |
- new Set<FunctionElement>(); |
final Set<FunctionElement> methodsNeedingSuperGetter = |
new Set<FunctionElement>(); |
final Map<String, Map<Selector, SelectorConstraints>> _invokedNames = |
@@ -148,16 +200,7 @@ class Universe { |
final Map<String, Map<Selector, SelectorConstraints>> _invokedSetters = |
<String, Map<Selector, SelectorConstraints>>{}; |
- /** |
- * Fields accessed. Currently only the codegen knows this |
- * information. The resolver is too conservative when seeing a |
- * getter and only registers an invoked getter. |
- */ |
- final Set<Element> fieldGetters = new Set<Element>(); |
- |
- /** |
- * Fields set. See comment in [fieldGetters]. |
- */ |
+ /// Fields set. |
final Set<Element> fieldSetters = new Set<Element>(); |
final Set<DartType> isChecks = new Set<DartType>(); |
@@ -190,7 +233,7 @@ class Universe { |
final SelectorConstraintsStrategy selectorConstraintsStrategy; |
- Universe(this.selectorConstraintsStrategy); |
+ ResolutionUniverseImpl(this.selectorConstraintsStrategy); |
/// All directly instantiated classes, that is, classes with a generative |
/// constructor that has been called directly and not only through a |
@@ -307,6 +350,246 @@ class Universe { |
return constraints.addReceiverConstraint(mask); |
} |
+ DartType registerIsCheck(DartType type, Compiler compiler) { |
+ type.computeUnaliased(compiler.resolution); |
+ type = type.unaliased; |
+ // Even in checked mode, type annotations for return type and argument |
+ // types do not imply type checks, so there should never be a check |
+ // against the type variable of a typedef. |
+ isChecks.add(type); |
+ return type; |
+ } |
+ |
+ void registerStaticUse(StaticUse staticUse) { |
+ Element element = staticUse.element; |
+ if (Elements.isStaticOrTopLevel(element) && element.isField) { |
+ allReferencedStaticFields.add(element); |
+ } |
+ switch (staticUse.kind) { |
+ case StaticUseKind.SUPER_FIELD_SET: |
+ case StaticUseKind.FIELD_SET: |
+ fieldSetters.add(element); |
+ break; |
+ case StaticUseKind.SUPER_TEAR_OFF: |
+ methodsNeedingSuperGetter.add(element); |
+ break; |
+ case StaticUseKind.GENERAL: |
+ case StaticUseKind.STATIC_TEAR_OFF: |
+ case StaticUseKind.FIELD_GET: |
+ break; |
+ case StaticUseKind.CLOSURE: |
+ allClosures.add(element); |
+ break; |
+ } |
+ } |
+ |
+ void forgetElement(Element element, Compiler compiler) { |
+ allClosures.remove(element); |
+ 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); |
+ } |
+ } |
+ |
+ // TODO(ahe): Replace this method with something that is O(1), for example, |
+ // by using a map. |
+ List<LocalFunctionElement> slowDirectlyNestedClosures(Element element) { |
+ // Return new list to guard against concurrent modifications. |
+ return new List<LocalFunctionElement>.from( |
+ allClosures.where((LocalFunctionElement closure) { |
+ return closure.executableContext == element; |
+ })); |
+ } |
+} |
+ |
+/// Universe specific to codegen. |
+/// |
+/// This adds additional access to liveness of selectors and elements. |
+abstract class CodegenUniverse implements Universe { |
+ void forEachInvokedName( |
+ f(String name, Map<Selector, SelectorConstraints> selectors)); |
+ |
+ void forEachInvokedGetter( |
+ f(String name, Map<Selector, SelectorConstraints> selectors)); |
+ |
+ void forEachInvokedSetter( |
+ f(String name, Map<Selector, SelectorConstraints> selectors)); |
+ |
+ bool hasInvokedGetter(Element member, World world); |
+ |
+ Map<Selector, SelectorConstraints> invocationsByName(String name); |
+ |
+ Map<Selector, SelectorConstraints> getterInvocationsByName(String name); |
+ |
+ Map<Selector, SelectorConstraints> setterInvocationsByName(String name); |
+ |
+ Iterable<FunctionElement> get staticFunctionsNeedingGetter; |
+ Iterable<FunctionElement> get methodsNeedingSuperGetter; |
+ |
+ /// The set of all referenced static fields. |
+ /// |
+ /// Invariant: Elements are declaration elements. |
+ Iterable<FieldElement> get allReferencedStaticFields; |
+} |
+ |
+class CodegenUniverseImpl implements CodegenUniverse { |
+ /// 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. |
+ /// |
+ /// Invariant: Elements are declaration elements. |
+ // TODO(johnniwinther): [_directlyInstantiatedClasses] and |
+ // [_instantiatedTypes] sets should be merged. |
+ final Set<ClassElement> _directlyInstantiatedClasses = |
+ new Set<ClassElement>(); |
+ |
+ /// The set of all directly instantiated types, that is, the types of the |
+ /// directly instantiated classes. |
+ /// |
+ /// See [_directlyInstantiatedClasses]. |
+ final Set<DartType> _instantiatedTypes = new Set<DartType>(); |
+ |
+ /// Classes implemented by directly instantiated classes. |
+ final Set<ClassElement> _implementedClasses = new Set<ClassElement>(); |
+ |
+ /// The set of all referenced static fields. |
+ /// |
+ /// Invariant: Elements are declaration elements. |
+ final Set<FieldElement> allReferencedStaticFields = new Set<FieldElement>(); |
+ |
+ /** |
+ * Documentation wanted -- johnniwinther |
+ * |
+ * Invariant: Elements are declaration elements. |
+ */ |
+ final Set<FunctionElement> staticFunctionsNeedingGetter = |
+ new Set<FunctionElement>(); |
+ final Set<FunctionElement> methodsNeedingSuperGetter = |
+ new Set<FunctionElement>(); |
+ final Map<String, Map<Selector, SelectorConstraints>> _invokedNames = |
+ <String, Map<Selector, SelectorConstraints>>{}; |
+ final Map<String, Map<Selector, SelectorConstraints>> _invokedGetters = |
+ <String, Map<Selector, SelectorConstraints>>{}; |
+ final Map<String, Map<Selector, SelectorConstraints>> _invokedSetters = |
+ <String, Map<Selector, SelectorConstraints>>{}; |
+ |
+ final Set<DartType> isChecks = new Set<DartType>(); |
+ |
+ final SelectorConstraintsStrategy selectorConstraintsStrategy; |
+ |
+ CodegenUniverseImpl(this.selectorConstraintsStrategy); |
+ |
+ /// All directly instantiated classes, that is, classes with a generative |
+ /// constructor that has been called directly and not only through a |
+ /// super-call. |
+ // TODO(johnniwinther): Improve semantic precision. |
+ Iterable<ClassElement> get directlyInstantiatedClasses { |
+ return _directlyInstantiatedClasses; |
+ } |
+ |
+ /// All directly instantiated types, that is, the types of the directly |
+ /// instantiated classes. |
+ /// |
+ /// See [directlyInstantiatedClasses]. |
+ // TODO(johnniwinther): Improve semantic precision. |
+ Iterable<DartType> get instantiatedTypes => _instantiatedTypes; |
+ |
+ /// Register [type] as (directly) instantiated. |
+ /// |
+ /// If [byMirrors] is `true`, the instantiation is through mirrors. |
+ // 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, |
+ {bool byMirrors: false, |
+ bool isNative: false, |
+ void onImplemented(ClassElement cls)}) { |
+ _instantiatedTypes.add(type); |
+ ClassElement cls = type.element; |
+ 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 |
+ // Likewise, if this registration comes from the mirror system, |
+ // all bets are off. |
+ // TODO(herhut): Track classes required by mirrors seperately. |
+ || |
+ byMirrors) { |
+ _directlyInstantiatedClasses.add(cls); |
+ } |
+ |
+ // TODO(johnniwinther): Replace this by separate more specific mappings that |
+ // include the type arguments. |
+ if (_implementedClasses.add(cls)) { |
+ onImplemented(cls); |
+ cls.allSupertypes.forEach((InterfaceType supertype) { |
+ if (_implementedClasses.add(supertype.element)) { |
+ onImplemented(supertype.element); |
+ } |
+ }); |
+ } |
+ } |
+ |
+ bool _hasMatchingSelector(Map<Selector, SelectorConstraints> selectors, |
+ Element member, World world) { |
+ if (selectors == null) return false; |
+ for (Selector selector in selectors.keys) { |
+ if (selector.appliesUnnamed(member, world)) { |
+ SelectorConstraints masks = selectors[selector]; |
+ if (masks.applies(member, selector, world)) { |
+ return true; |
+ } |
+ } |
+ } |
+ return false; |
+ } |
+ |
+ bool hasInvocation(Element member, World world) { |
+ return _hasMatchingSelector(_invokedNames[member.name], member, world); |
+ } |
+ |
+ bool hasInvokedGetter(Element member, World world) { |
+ return _hasMatchingSelector(_invokedGetters[member.name], member, world) || |
+ member.isFunction && methodsNeedingSuperGetter.contains(member); |
+ } |
+ |
+ bool hasInvokedSetter(Element member, World world) { |
+ return _hasMatchingSelector(_invokedSetters[member.name], member, world); |
+ } |
+ |
+ bool registerDynamicUse(DynamicUse dynamicUse) { |
+ switch (dynamicUse.kind) { |
+ case DynamicUseKind.INVOKE: |
+ return _registerNewSelector(dynamicUse, _invokedNames); |
+ case DynamicUseKind.GET: |
+ return _registerNewSelector(dynamicUse, _invokedGetters); |
+ case DynamicUseKind.SET: |
+ return _registerNewSelector(dynamicUse, _invokedSetters); |
+ } |
+ } |
+ |
+ bool _registerNewSelector(DynamicUse dynamicUse, |
+ Map<String, Map<Selector, SelectorConstraints>> selectorMap) { |
+ Selector selector = dynamicUse.selector; |
+ String name = selector.name; |
+ ReceiverConstraint mask = dynamicUse.mask; |
+ Map<Selector, SelectorConstraints> selectors = selectorMap.putIfAbsent( |
+ name, () => new Maplet<Selector, SelectorConstraints>()); |
+ UniverseSelectorConstraints constraints = |
+ selectors.putIfAbsent(selector, () { |
+ return selectorConstraintsStrategy.createSelectorConstraints(selector); |
+ }); |
+ return constraints.addReceiverConstraint(mask); |
+ } |
+ |
Map<Selector, SelectorConstraints> _asUnmodifiable( |
Map<Selector, SelectorConstraints> map) { |
if (map == null) return null; |
@@ -359,30 +642,19 @@ class Universe { |
case StaticUseKind.STATIC_TEAR_OFF: |
staticFunctionsNeedingGetter.add(element); |
break; |
- case StaticUseKind.FIELD_GET: |
- fieldGetters.add(element); |
- break; |
- case StaticUseKind.SUPER_FIELD_SET: |
- case StaticUseKind.FIELD_SET: |
- fieldSetters.add(element); |
- break; |
case StaticUseKind.SUPER_TEAR_OFF: |
methodsNeedingSuperGetter.add(element); |
break; |
+ case StaticUseKind.SUPER_FIELD_SET: |
+ case StaticUseKind.FIELD_SET: |
case StaticUseKind.GENERAL: |
- break; |
case StaticUseKind.CLOSURE: |
- allClosures.add(element); |
+ case StaticUseKind.FIELD_GET: |
break; |
} |
} |
void forgetElement(Element element, Compiler compiler) { |
- allClosures.remove(element); |
- slowDirectlyNestedClosures(element).forEach(compiler.forgetElement); |
- closurizedMembers.remove(element); |
- fieldSetters.remove(element); |
- fieldGetters.remove(element); |
_directlyInstantiatedClasses.remove(element); |
if (element is ClassElement) { |
assert(invariant(element, element.thisType.isRaw, |
@@ -390,14 +662,4 @@ class Universe { |
_instantiatedTypes..remove(element.rawType)..remove(element.thisType); |
} |
} |
- |
- // TODO(ahe): Replace this method with something that is O(1), for example, |
- // by using a map. |
- List<LocalFunctionElement> slowDirectlyNestedClosures(Element element) { |
- // Return new list to guard against concurrent modifications. |
- return new List<LocalFunctionElement>.from( |
- allClosures.where((LocalFunctionElement closure) { |
- return closure.executableContext == element; |
- })); |
- } |
} |