| 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;
|
| - }));
|
| - }
|
| }
|
|
|