Chromium Code Reviews| 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..f2805a5c2891a57746ea8cc04f06f67501b365a2 100644 |
| --- a/pkg/compiler/lib/src/universe/universe.dart |
| +++ b/pkg/compiler/lib/src/universe/universe.dart |
| @@ -107,7 +107,60 @@ abstract class SelectorConstraintsStrategy { |
| /// 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 { |
| +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; |
|
Harry Terkelsen
2016/09/19 18:07:10
how come some of these collections are sets and so
Johnni Winther
2016/09/21 09:13:04
This is added to from the outside. Will be changed
|
| + |
| + /// 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. |
| + // TODO(johnniwinther): Improve semantic precision. |
|
Siggi Cherem (dart-lang)
2016/09/06 17:57:43
remove TODO (it's already in the impl class below)
Johnni Winther
2016/09/21 09:13:04
Done.
|
| + 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 +190,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 +199,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 +232,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 +349,243 @@ 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; |
| + })); |
| + } |
| +} |
| + |
| +abstract class CodegenUniverse implements Universe { |
|
Harry Terkelsen
2016/09/19 18:07:10
add dartdoc for this class
Johnni Winther
2016/09/21 09:13:04
Done.
|
| + 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, |
|
Siggi Cherem (dart-lang)
2016/09/06 17:57:43
should some of this shared code be in a shared sup
Harry Terkelsen
2016/09/19 18:07:10
I would suggest 'UniverseBase'
Johnni Winther
2016/09/21 09:13:04
I'll wait with that until the unification of world
|
| + {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 +638,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 +658,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; |
| - })); |
| - } |
| } |