Index: pkg/compiler/lib/src/universe/element_world_builder.dart |
diff --git a/pkg/compiler/lib/src/universe/element_world_builder.dart b/pkg/compiler/lib/src/universe/element_world_builder.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..39ed5e5bf63d25f59e2c5270c666852cd9c676c9 |
--- /dev/null |
+++ b/pkg/compiler/lib/src/universe/element_world_builder.dart |
@@ -0,0 +1,260 @@ |
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+part of world_builder; |
+ |
+/// [ResolutionEnqueuerWorldBuilder] based on the [Element] model. |
+class ElementResolutionWorldBuilder extends ResolutionWorldBuilderBase { |
+ /// Used for testing the new more precise computation of instantiated types |
+ /// and classes. |
+ static bool useInstantiationMap = false; |
+ |
+ final JavaScriptBackend _backend; |
+ final Resolution _resolution; |
+ |
+ ElementResolutionWorldBuilder(this._backend, this._resolution, |
+ SelectorConstraintsStrategy selectorConstraintsStrategy) |
+ : super(_backend.compiler.elementEnvironment, _resolution.commonElements, |
+ _backend.nativeBasicData, selectorConstraintsStrategy); |
+ |
+ bool isImplemented(ClassElement cls) { |
+ return super.isImplemented(cls.declaration); |
+ } |
+ |
+ void registerTypeInstantiation( |
+ InterfaceType type, ClassUsedCallback classUsed, |
+ {ConstructorEntity constructor, |
+ bool byMirrors: false, |
+ bool isRedirection: false}) { |
+ ClassElement cls = type.element; |
+ cls.ensureResolved(_resolution); |
+ super.registerTypeInstantiation(type, classUsed, |
+ constructor: constructor, |
+ byMirrors: byMirrors, |
+ isRedirection: isRedirection); |
+ } |
+ |
+ /// Returns the instantiation map used for computing the closed world. |
+ /// |
+ /// If [useInstantiationMap] is `true`, redirections are removed and |
+ /// redirecting factories are converted to their effective target and type. |
+ Map<ClassEntity, InstantiationInfo> getInstantiationMap() { |
+ if (!useInstantiationMap) return _instantiationInfo; |
+ |
+ Map<ClassEntity, InstantiationInfo> instantiationMap = |
+ <ClassEntity, InstantiationInfo>{}; |
+ |
+ InstantiationInfo infoFor(ClassEntity cls) { |
+ return instantiationMap.putIfAbsent(cls, () => new InstantiationInfo()); |
+ } |
+ |
+ _instantiationInfo.forEach((cls, info) { |
+ if (info.instantiationMap != null) { |
+ info.instantiationMap |
+ .forEach((ConstructorElement constructor, Set<Instance> set) { |
+ for (Instance instance in set) { |
+ if (instance.isRedirection) { |
+ continue; |
+ } |
+ if (constructor == null || !constructor.isRedirectingFactory) { |
+ infoFor(cls) |
+ .addInstantiation(constructor, instance.type, instance.kind); |
+ } else { |
+ ConstructorElement target = constructor.effectiveTarget; |
+ ResolutionInterfaceType targetType = |
+ constructor.computeEffectiveTargetType(instance.type); |
+ Instantiation kind = Instantiation.DIRECTLY_INSTANTIATED; |
+ if (target.enclosingClass.isAbstract) { |
+ // If target is a factory constructor on an abstract class. |
+ kind = Instantiation.UNINSTANTIATED; |
+ } |
+ infoFor(targetType.element) |
+ .addInstantiation(target, targetType, kind); |
+ } |
+ } |
+ }); |
+ } |
+ }); |
+ return instantiationMap; |
+ } |
+ |
+ void registerIsCheck(ResolutionDartType type) { |
+ type.computeUnaliased(_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. |
+ assert(!type.isTypeVariable || !type.element.enclosingElement.isTypedef); |
+ super.registerIsCheck(type); |
+ } |
+ |
+ void registerStaticUse(StaticUse staticUse, MemberUsedCallback memberUsed) { |
+ if (staticUse.kind == StaticUseKind.CLOSURE) { |
+ LocalFunctionElement localFunction = staticUse.element; |
+ if (localFunction.type.containsTypeVariables) { |
+ localFunctionsWithFreeTypeVariables.add(localFunction); |
+ } |
+ localFunctions.add(staticUse.element); |
+ return; |
+ } |
+ MemberElement element = staticUse.element; |
+ assert(invariant(element, element.isDeclaration, |
+ message: "Element ${element} is not the declaration.")); |
+ super.registerStaticUse(staticUse, memberUsed); |
+ } |
+ |
+ _ClassUsage _createClassUsage(ClassElement cls) { |
+ cls.ensureResolved(_resolution); |
+ _resolution.ensureClassMembers(cls); |
+ return super._createClassUsage(cls); |
+ } |
+ |
+ /// Called to add [cls] to the set of known classes. |
+ /// |
+ /// This ensures that class hierarchy queries can be performed on [cls] and |
+ /// classes that extend or implement it. |
+ void registerClass(ClassEntity cls) => _registerClass(cls); |
+ |
+ void _registerClass(ClassEntity cls, {bool isDirectlyInstantiated: false}) { |
+ _ensureClassSet(cls); |
+ if (isDirectlyInstantiated) { |
+ _updateClassHierarchyNodeForClass(cls, directlyInstantiated: true); |
+ } |
+ } |
+ |
+ void _processInstantiatedClassMember( |
+ ClassEntity cls, MemberElement member, MemberUsedCallback memberUsed) { |
+ assert(invariant(member, member.isDeclaration)); |
+ member.computeType(_resolution); |
+ super._processInstantiatedClassMember(cls, member, memberUsed); |
+ } |
+ |
+ ClassHierarchyNode _ensureClassHierarchyNode(ClassElement cls) { |
+ cls = cls.declaration; |
+ return _classHierarchyNodes.putIfAbsent(cls, () { |
+ ClassHierarchyNode parentNode; |
+ if (cls.superclass != null) { |
+ parentNode = _ensureClassHierarchyNode(cls.superclass); |
+ } |
+ return new ClassHierarchyNode(parentNode, cls); |
+ }); |
+ } |
+ |
+ ClassSet _ensureClassSet(ClassElement cls) { |
+ cls = cls.declaration; |
+ return _classSets.putIfAbsent(cls, () { |
+ ClassHierarchyNode node = _ensureClassHierarchyNode(cls); |
+ ClassSet classSet = new ClassSet(node); |
+ |
+ for (ResolutionInterfaceType type in cls.allSupertypes) { |
+ // TODO(johnniwinther): Optimization: Avoid adding [cls] to |
+ // superclasses. |
+ ClassSet subtypeSet = _ensureClassSet(type.element); |
+ subtypeSet.addSubtype(node); |
+ } |
+ if (cls.isMixinApplication) { |
+ // TODO(johnniwinther): Store this in the [ClassSet]. |
+ MixinApplicationElement mixinApplication = cls; |
+ if (mixinApplication.mixin != null) { |
+ // If [mixinApplication] is malformed [mixin] is `null`. |
+ registerMixinUse(mixinApplication, mixinApplication.mixin); |
+ } |
+ } |
+ |
+ return classSet; |
+ }); |
+ } |
+ |
+ void _updateSuperClassHierarchyNodeForClass(ClassHierarchyNode node) { |
+ // Ensure that classes implicitly implementing `Function` are in its |
+ // subtype set. |
+ ClassElement cls = node.cls; |
+ if (cls != _commonElements.functionClass && |
+ cls.implementsFunction(_commonElements)) { |
+ ClassSet subtypeSet = _ensureClassSet(_commonElements.functionClass); |
+ subtypeSet.addSubtype(node); |
+ } |
+ if (!node.isInstantiated && node.parentNode != null) { |
+ _updateSuperClassHierarchyNodeForClass(node.parentNode); |
+ } |
+ } |
+ |
+ void _updateClassHierarchyNodeForClass(ClassElement cls, |
+ {bool directlyInstantiated: false, bool abstractlyInstantiated: false}) { |
+ ClassHierarchyNode node = _ensureClassHierarchyNode(cls); |
+ _updateSuperClassHierarchyNodeForClass(node); |
+ if (directlyInstantiated) { |
+ node.isDirectlyInstantiated = true; |
+ } |
+ if (abstractlyInstantiated) { |
+ node.isAbstractlyInstantiated = true; |
+ } |
+ } |
+ |
+ ClosedWorld closeWorld(DiagnosticReporter reporter) { |
+ Map<ClassEntity, Set<ClassEntity>> typesImplementedBySubclasses = |
+ new Map<ClassEntity, Set<ClassEntity>>(); |
+ |
+ /// Updates the `isDirectlyInstantiated` and `isIndirectlyInstantiated` |
+ /// properties of the [ClassHierarchyNode] for [cls]. |
+ |
+ void addSubtypes(ClassElement cls, InstantiationInfo info) { |
+ if (!info.hasInstantiation) { |
+ return; |
+ } |
+ assert(cls.isDeclaration); |
+ if (!cls.isResolved) { |
+ reporter.internalError(cls, 'Class "${cls.name}" is not resolved.'); |
+ } |
+ |
+ _updateClassHierarchyNodeForClass(cls, |
+ directlyInstantiated: info.isDirectlyInstantiated, |
+ abstractlyInstantiated: info.isAbstractlyInstantiated); |
+ |
+ // Walk through the superclasses, and record the types |
+ // implemented by that type on the superclasses. |
+ ClassElement superclass = cls.superclass; |
+ while (superclass != null) { |
+ Set<ClassEntity> typesImplementedBySubclassesOfCls = |
+ typesImplementedBySubclasses.putIfAbsent( |
+ superclass, () => new Set<ClassEntity>()); |
+ for (ResolutionInterfaceType current in cls.allSupertypes) { |
+ typesImplementedBySubclassesOfCls.add(current.element); |
+ } |
+ superclass = superclass.superclass; |
+ } |
+ } |
+ |
+ // Use the [:seenClasses:] set to include non-instantiated |
+ // classes: if the superclass of these classes require RTI, then |
+ // they also need RTI, so that a constructor passes the type |
+ // variables to the super constructor. |
+ forEachInstantiatedClass(addSubtypes); |
+ |
+ _closed = true; |
+ return _closedWorldCache = new ClosedWorldImpl( |
+ backend: _backend, |
+ commonElements: _commonElements, |
+ resolutionWorldBuilder: this, |
+ functionSetBuilder: _allFunctions, |
+ allTypedefs: _allTypedefs, |
+ mixinUses: _mixinUses, |
+ typesImplementedBySubclasses: typesImplementedBySubclasses, |
+ classHierarchyNodes: _classHierarchyNodes, |
+ classSets: _classSets); |
+ } |
+ |
+ void registerUsedElement(MemberElement element) { |
+ if (element.isInstanceMember && !element.isAbstract) { |
+ _allFunctions.add(element); |
+ } |
+ } |
+ |
+ @override |
+ void registerMixinUse( |
+ MixinApplicationElement mixinApplication, ClassElement mixin) { |
+ assert(mixin.isDeclaration); |
+ super.registerMixinUse(mixinApplication, mixin); |
+ } |
+} |