| Index: pkg/compiler/lib/src/enqueue.dart
|
| diff --git a/pkg/compiler/lib/src/enqueue.dart b/pkg/compiler/lib/src/enqueue.dart
|
| index 6c7de3fbbe2961ada4e97ad40f7847b95f20f24e..9277ee41052496707f857e3dfe7c8690946d2b17 100644
|
| --- a/pkg/compiler/lib/src/enqueue.dart
|
| +++ b/pkg/compiler/lib/src/enqueue.dart
|
| @@ -54,9 +54,8 @@ class EnqueueTask extends CompilerTask {
|
| this,
|
| compiler.options,
|
| compiler.resolution,
|
| - compiler.enqueuerFilter,
|
| compiler.options.analyzeOnly && compiler.options.analyzeMain
|
| - ? const EnqueuerStrategy()
|
| + ? const DirectEnqueuerStrategy()
|
| : const TreeShakingEnqueuerStrategy(),
|
| compiler.globalDependencies,
|
| compiler.backend,
|
| @@ -75,16 +74,24 @@ class EnqueueTask extends CompilerTask {
|
| }
|
|
|
| abstract class Enqueuer {
|
| - CompilerTask get task;
|
| WorldBuilder get universe;
|
| native.NativeEnqueuer get nativeEnqueuer;
|
| void forgetElement(Element element, Compiler compiler);
|
| - void processInstantiatedClassMembers(ClassElement cls);
|
| - void processInstantiatedClassMember(ClassElement cls, Element member);
|
| - void handleUnseenSelectorInternal(DynamicUse dynamicUse);
|
| - void registerStaticUse(StaticUse staticUse);
|
| - void registerStaticUseInternal(StaticUse staticUse);
|
| - void registerDynamicUse(DynamicUse dynamicUse);
|
| +
|
| + // TODO(johnniwinther): Initialize [_impactStrategy] to `null`.
|
| + ImpactStrategy _impactStrategy = const ImpactStrategy();
|
| +
|
| + ImpactStrategy get impactStrategy => _impactStrategy;
|
| +
|
| + void open(ImpactStrategy impactStrategy) {
|
| + _impactStrategy = impactStrategy;
|
| + }
|
| +
|
| + void close() {
|
| + // TODO(johnniwinther): Set [_impactStrategy] to `null` and [queueIsClosed]
|
| + // to `false` here.
|
| + _impactStrategy = const ImpactStrategy();
|
| + }
|
|
|
| /// Returns [:true:] if this enqueuer is the resolution enqueuer.
|
| bool get isResolutionQueue;
|
| @@ -95,23 +102,12 @@ abstract class Enqueuer {
|
|
|
| ImpactUseCase get impactUse;
|
|
|
| - /**
|
| - * Documentation wanted -- johnniwinther
|
| - *
|
| - * Invariant: [element] must be a declaration element.
|
| - */
|
| - void addToWorkList(Element element);
|
| -
|
| - void enableIsolateSupport();
|
| -
|
| - void registerInstantiatedType(InterfaceType type);
|
| void forEach(void f(WorkItem work));
|
|
|
| - /// Apply the [worldImpact] to this enqueuer. If the [impactSource] is provided
|
| - /// the impact strategy will remove it from the element impact cache, if it is
|
| - /// no longer needed.
|
| - void applyImpact(ImpactStrategy impactStrategy, WorldImpact worldImpact,
|
| - {Element impactSource});
|
| + /// Apply the [worldImpact] to this enqueuer. If the [impactSource] is
|
| + /// provided the impact strategy will remove it from the element impact cache,
|
| + /// if it is no longer needed.
|
| + void applyImpact(WorldImpact worldImpact, {Element impactSource});
|
| bool checkNoEnqueuedInvokedInstanceMethods();
|
| void logSummary(log(message));
|
|
|
| @@ -123,12 +119,23 @@ abstract class Enqueuer {
|
| Iterable<ClassElement> get processedClasses;
|
| }
|
|
|
| +abstract class EnqueuerImpl extends Enqueuer {
|
| + CompilerTask get task;
|
| + void processInstantiatedClassMembers(ClassElement cls);
|
| + void processInstantiatedClassMember(ClassElement cls, Element member);
|
| + void registerStaticUse(StaticUse staticUse);
|
| + void registerStaticUseInternal(StaticUse staticUse);
|
| + void registerTypeUse(TypeUse typeUse);
|
| + void registerTypeUseInternal(TypeUse typeUse);
|
| + void registerDynamicUse(DynamicUse dynamicUse);
|
| + void handleUnseenSelectorInternal(DynamicUse dynamicUse);
|
| +}
|
| +
|
| /// [Enqueuer] which is specific to resolution.
|
| -class ResolutionEnqueuer extends Enqueuer {
|
| +class ResolutionEnqueuer extends EnqueuerImpl {
|
| final CompilerTask task;
|
| final String name;
|
| final Resolution resolution;
|
| - final QueueFilter filter;
|
| final CompilerOptions options;
|
| final Backend backend;
|
| final GlobalDependencyRegistry globalDependencies;
|
| @@ -148,13 +155,10 @@ class ResolutionEnqueuer extends Enqueuer {
|
|
|
| WorldImpactVisitor impactVisitor;
|
|
|
| - ImpactStrategy impactStrategy;
|
| -
|
| ResolutionEnqueuer(
|
| this.task,
|
| this.options,
|
| this.resolution,
|
| - this.filter,
|
| this.strategy,
|
| this.globalDependencies,
|
| Backend backend,
|
| @@ -169,7 +173,7 @@ class ResolutionEnqueuer extends Enqueuer {
|
| deferredQueue = new Queue<_DeferredAction>(),
|
| _universe = new ResolutionWorldBuilderImpl(
|
| backend, commonElements, cacheStrategy, const TypeMaskStrategy()) {
|
| - impactVisitor = new _EnqueuerImpactVisitor(this);
|
| + impactVisitor = new EnqueuerImplImpactVisitor(this);
|
| }
|
|
|
| ResolutionWorldBuilder get universe => _universe;
|
| @@ -194,8 +198,8 @@ class ResolutionEnqueuer extends Enqueuer {
|
| internalAddToWorkList(element);
|
| }
|
|
|
| - void applyImpact(ImpactStrategy impactStrategy, WorldImpact worldImpact,
|
| - {Element impactSource}) {
|
| + void applyImpact(WorldImpact worldImpact, {Element impactSource}) {
|
| + if (worldImpact.isEmpty) return;
|
| impactStrategy.visitImpact(
|
| impactSource, worldImpact, impactVisitor, impactUse);
|
| }
|
| @@ -219,7 +223,7 @@ class ResolutionEnqueuer extends Enqueuer {
|
| isNative: isNative,
|
| byMirrors: mirrorUsage,
|
| isRedirection: isRedirection, onImplemented: (ClassElement cls) {
|
| - backend.registerImplementedClass(cls, this);
|
| + applyImpact(backend.registerImplementedClass(cls, forResolution: true));
|
| });
|
| if (globalDependency && !mirrorUsage) {
|
| globalDependencies.registerDependency(type.element);
|
| @@ -236,7 +240,7 @@ class ResolutionEnqueuer extends Enqueuer {
|
| }
|
|
|
| bool checkNoEnqueuedInvokedInstanceMethods() {
|
| - return filter.checkNoEnqueuedInvokedInstanceMethods(this);
|
| + return strategy.checkEnqueuerConsistency(this);
|
| }
|
|
|
| void processInstantiatedClassMembers(ClassElement cls) {
|
| @@ -284,7 +288,7 @@ class ResolutionEnqueuer extends Enqueuer {
|
| registerNoSuchMethod(function);
|
| }
|
| if (function.name == Identifiers.call && !cls.typeVariables.isEmpty) {
|
| - registerCallMethodWithFreeTypeVariables(function);
|
| + _registerCallMethodWithFreeTypeVariables(function);
|
| }
|
| // If there is a property access with the same name as a method we
|
| // need to emit the method.
|
| @@ -349,7 +353,8 @@ class ResolutionEnqueuer extends Enqueuer {
|
| // We only tell the backend once that [superclass] was instantiated, so
|
| // any additional dependencies must be treated as global
|
| // dependencies.
|
| - backend.registerInstantiatedClass(superclass, this);
|
| + applyImpact(
|
| + backend.registerInstantiatedClass(superclass, forResolution: true));
|
| }
|
|
|
| ClassElement superclass = cls;
|
| @@ -433,11 +438,11 @@ class ResolutionEnqueuer extends Enqueuer {
|
| assert(invariant(element, element.isDeclaration,
|
| message: "Element ${element} is not the declaration."));
|
| _universe.registerStaticUse(staticUse);
|
| - backend.registerStaticUse(this, element);
|
| + applyImpact(backend.registerStaticUse(element, forResolution: true));
|
| bool addElement = true;
|
| switch (staticUse.kind) {
|
| case StaticUseKind.STATIC_TEAR_OFF:
|
| - backend.registerGetOfStaticFunction(this);
|
| + applyImpact(backend.registerGetOfStaticFunction());
|
| break;
|
| case StaticUseKind.FIELD_GET:
|
| case StaticUseKind.FIELD_SET:
|
| @@ -455,6 +460,7 @@ class ResolutionEnqueuer extends Enqueuer {
|
| case StaticUseKind.SUPER_FIELD_SET:
|
| case StaticUseKind.SUPER_TEAR_OFF:
|
| case StaticUseKind.GENERAL:
|
| + case StaticUseKind.DIRECT_USE:
|
| break;
|
| case StaticUseKind.CONSTRUCTOR_INVOKE:
|
| case StaticUseKind.CONST_CONSTRUCTOR_INVOKE:
|
| @@ -477,7 +483,11 @@ class ResolutionEnqueuer extends Enqueuer {
|
| }
|
| }
|
|
|
| - void _registerTypeUse(TypeUse typeUse) {
|
| + void registerTypeUse(TypeUse typeUse) {
|
| + strategy.processTypeUse(this, typeUse);
|
| + }
|
| +
|
| + void registerTypeUseInternal(TypeUse typeUse) {
|
| DartType type = typeUse.type;
|
| switch (typeUse.kind) {
|
| case TypeUseKind.INSTANTIATION:
|
| @@ -514,18 +524,20 @@ class ResolutionEnqueuer extends Enqueuer {
|
| assert(!type.isTypeVariable || !type.element.enclosingElement.isTypedef);
|
| }
|
|
|
| - void registerCallMethodWithFreeTypeVariables(Element element) {
|
| - backend.registerCallMethodWithFreeTypeVariables(element, this);
|
| + void _registerCallMethodWithFreeTypeVariables(Element element) {
|
| + applyImpact(backend.registerCallMethodWithFreeTypeVariables(element,
|
| + forResolution: true));
|
| _universe.callMethodsWithFreeTypeVariables.add(element);
|
| }
|
|
|
| void registerClosurizedMember(TypedElement element) {
|
| assert(element.isInstanceMember);
|
| if (element.computeType(resolution).containsTypeVariables) {
|
| - backend.registerClosureWithFreeTypeVariables(element, this);
|
| + applyImpact(backend.registerClosureWithFreeTypeVariables(element,
|
| + forResolution: true));
|
| _universe.closuresWithFreeTypeVariables.add(element);
|
| }
|
| - backend.registerBoundClosure(this);
|
| + applyImpact(backend.registerBoundClosure());
|
| _universe.closurizedMembers.add(element);
|
| }
|
|
|
| @@ -533,7 +545,11 @@ class ResolutionEnqueuer extends Enqueuer {
|
| do {
|
| while (queue.isNotEmpty) {
|
| // TODO(johnniwinther): Find an optimal process order.
|
| - filter.processWorkItem(f, queue.removeLast());
|
| + WorkItem work = queue.removeLast();
|
| + if (!isProcessed(work.element)) {
|
| + strategy.processWorkItem(f, work);
|
| + registerProcessedElement(work.element);
|
| + }
|
| }
|
| List recents = recentClasses.toList(growable: false);
|
| recentClasses.clear();
|
| @@ -625,7 +641,7 @@ class ResolutionEnqueuer extends Enqueuer {
|
| // runtime type.
|
| _universe.hasRuntimeTypeSupport = true;
|
| // TODO(ahe): Record precise dependency here.
|
| - backend.registerRuntimeType(this);
|
| + applyImpact(backend.registerRuntimeType());
|
| } else if (commonElements.isFunctionApplyMethod(element)) {
|
| _universe.hasFunctionApplySupport = true;
|
| }
|
| @@ -639,7 +655,7 @@ class ResolutionEnqueuer extends Enqueuer {
|
|
|
| void enableIsolateSupport() {
|
| _universe.hasIsolateSupport = true;
|
| - backend.enableIsolateSupport(this);
|
| + applyImpact(backend.enableIsolateSupport(forResolution: true));
|
| }
|
|
|
| /**
|
| @@ -690,11 +706,32 @@ class ResolutionEnqueuer extends Enqueuer {
|
| }
|
| }
|
|
|
| -/// Parameterizes filtering of which work items are enqueued.
|
| -class QueueFilter {
|
| - bool checkNoEnqueuedInvokedInstanceMethods(Enqueuer enqueuer) {
|
| +void removeFromSet(Map<String, Set<Element>> map, Element element) {
|
| + Set<Element> set = map[element.name];
|
| + if (set == null) return;
|
| + set.remove(element);
|
| +}
|
| +
|
| +/// Strategy used by the enqueuer to populate the world.
|
| +class EnqueuerStrategy {
|
| + const EnqueuerStrategy();
|
| +
|
| + /// Process a class instantiated in live code.
|
| + void processInstantiatedClass(EnqueuerImpl enqueuer, ClassElement cls) {}
|
| +
|
| + /// Process a static use of and element in live code.
|
| + void processStaticUse(EnqueuerImpl enqueuer, StaticUse staticUse) {}
|
| +
|
| + /// Process a type use in live code.
|
| + void processTypeUse(EnqueuerImpl enqueuer, TypeUse typeUse) {}
|
| +
|
| + /// Process a dynamic use for a call site in live code.
|
| + void processDynamicUse(EnqueuerImpl enqueuer, DynamicUse dynamicUse) {}
|
| +
|
| + /// Check enqueuer consistency after the queue has been closed.
|
| + bool checkEnqueuerConsistency(EnqueuerImpl enqueuer) {
|
| enqueuer.task.measure(() {
|
| - // Run through the classes and see if we need to compile methods.
|
| + // Run through the classes and see if we need to enqueue more methods.
|
| for (ClassElement classElement
|
| in enqueuer.universe.directlyInstantiatedClasses) {
|
| for (ClassElement currentClass = classElement;
|
| @@ -707,55 +744,51 @@ class QueueFilter {
|
| return true;
|
| }
|
|
|
| + /// Process [work] using [f].
|
| void processWorkItem(void f(WorkItem work), WorkItem work) {
|
| f(work);
|
| }
|
| }
|
|
|
| -void removeFromSet(Map<String, Set<Element>> map, Element element) {
|
| - Set<Element> set = map[element.name];
|
| - if (set == null) return;
|
| - set.remove(element);
|
| -}
|
| -
|
| -/// Strategy used by the enqueuer to populate the world.
|
| -// TODO(johnniwinther): Merge this interface with [QueueFilter].
|
| -class EnqueuerStrategy {
|
| - const EnqueuerStrategy();
|
| -
|
| - /// Process a class instantiated in live code.
|
| - void processInstantiatedClass(Enqueuer enqueuer, ClassElement cls) {}
|
| -
|
| - /// Process a static use of and element in live code.
|
| - void processStaticUse(Enqueuer enqueuer, StaticUse staticUse) {}
|
| -
|
| - /// Process a dynamic use for a call site in live code.
|
| - void processDynamicUse(Enqueuer enqueuer, DynamicUse dynamicUse) {}
|
| +/// Strategy that only enqueues directly used elements.
|
| +class DirectEnqueuerStrategy extends EnqueuerStrategy {
|
| + const DirectEnqueuerStrategy();
|
| + void processStaticUse(EnqueuerImpl enqueuer, StaticUse staticUse) {
|
| + if (staticUse.kind == StaticUseKind.DIRECT_USE) {
|
| + enqueuer.registerStaticUseInternal(staticUse);
|
| + }
|
| + }
|
| }
|
|
|
| -class TreeShakingEnqueuerStrategy implements EnqueuerStrategy {
|
| +/// Strategy used for tree-shaking.
|
| +class TreeShakingEnqueuerStrategy extends EnqueuerStrategy {
|
| const TreeShakingEnqueuerStrategy();
|
|
|
| @override
|
| - void processInstantiatedClass(Enqueuer enqueuer, ClassElement cls) {
|
| + void processInstantiatedClass(EnqueuerImpl enqueuer, ClassElement cls) {
|
| cls.implementation.forEachMember(enqueuer.processInstantiatedClassMember);
|
| }
|
|
|
| @override
|
| - void processStaticUse(Enqueuer enqueuer, StaticUse staticUse) {
|
| + void processStaticUse(EnqueuerImpl enqueuer, StaticUse staticUse) {
|
| enqueuer.registerStaticUseInternal(staticUse);
|
| }
|
|
|
| @override
|
| - void processDynamicUse(Enqueuer enqueuer, DynamicUse dynamicUse) {
|
| + void processTypeUse(EnqueuerImpl enqueuer, TypeUse typeUse) {
|
| + enqueuer.registerTypeUseInternal(typeUse);
|
| + }
|
| +
|
| + @override
|
| + void processDynamicUse(EnqueuerImpl enqueuer, DynamicUse dynamicUse) {
|
| enqueuer.handleUnseenSelectorInternal(dynamicUse);
|
| }
|
| }
|
|
|
| -class _EnqueuerImpactVisitor implements WorldImpactVisitor {
|
| - final ResolutionEnqueuer enqueuer;
|
| +class EnqueuerImplImpactVisitor implements WorldImpactVisitor {
|
| + final EnqueuerImpl enqueuer;
|
|
|
| - _EnqueuerImpactVisitor(this.enqueuer);
|
| + EnqueuerImplImpactVisitor(this.enqueuer);
|
|
|
| @override
|
| void visitDynamicUse(DynamicUse dynamicUse) {
|
| @@ -769,7 +802,7 @@ class _EnqueuerImpactVisitor implements WorldImpactVisitor {
|
|
|
| @override
|
| void visitTypeUse(TypeUse typeUse) {
|
| - enqueuer._registerTypeUse(typeUse);
|
| + enqueuer.registerTypeUse(typeUse);
|
| }
|
| }
|
|
|
|
|