| Index: pkg/compiler/lib/src/enqueue.dart
|
| diff --git a/pkg/compiler/lib/src/enqueue.dart b/pkg/compiler/lib/src/enqueue.dart
|
| deleted file mode 100644
|
| index a00c365e2d766fdf465c8ef3533ce6bba95218ff..0000000000000000000000000000000000000000
|
| --- a/pkg/compiler/lib/src/enqueue.dart
|
| +++ /dev/null
|
| @@ -1,905 +0,0 @@
|
| -// Copyright (c) 2012, 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 dart2js;
|
| -
|
| -typedef ItemCompilationContext ItemCompilationContextCreator();
|
| -
|
| -class EnqueueTask extends CompilerTask {
|
| - final ResolutionEnqueuer resolution;
|
| - final CodegenEnqueuer codegen;
|
| -
|
| - String get name => 'Enqueue';
|
| -
|
| - EnqueueTask(Compiler compiler)
|
| - : resolution = new ResolutionEnqueuer(
|
| - compiler, compiler.backend.createItemCompilationContext),
|
| - codegen = new CodegenEnqueuer(
|
| - compiler, compiler.backend.createItemCompilationContext),
|
| - super(compiler) {
|
| - codegen.task = this;
|
| - resolution.task = this;
|
| -
|
| - codegen.nativeEnqueuer = compiler.backend.nativeCodegenEnqueuer(codegen);
|
| - resolution.nativeEnqueuer =
|
| - compiler.backend.nativeResolutionEnqueuer(resolution);
|
| - }
|
| -
|
| - void forgetElement(Element element) {
|
| - resolution.forgetElement(element);
|
| - codegen.forgetElement(element);
|
| - }
|
| -}
|
| -
|
| -abstract class Enqueuer {
|
| - final String name;
|
| - final Compiler compiler; // TODO(ahe): Remove this dependency.
|
| - final ItemCompilationContextCreator itemCompilationContextCreator;
|
| - final Map<String, Set<Element>> instanceMembersByName
|
| - = new Map<String, Set<Element>>();
|
| - final Map<String, Set<Element>> instanceFunctionsByName
|
| - = new Map<String, Set<Element>>();
|
| - final Set<ClassElement> _processedClasses = new Set<ClassElement>();
|
| - Set<ClassElement> recentClasses = new Setlet<ClassElement>();
|
| - final Universe universe = new Universe();
|
| -
|
| - static final TRACE_MIRROR_ENQUEUING =
|
| - const bool.fromEnvironment("TRACE_MIRROR_ENQUEUING");
|
| -
|
| - bool queueIsClosed = false;
|
| - EnqueueTask task;
|
| - native.NativeEnqueuer nativeEnqueuer; // Set by EnqueueTask
|
| -
|
| - bool hasEnqueuedReflectiveElements = false;
|
| - bool hasEnqueuedReflectiveStaticFields = false;
|
| -
|
| - Enqueuer(this.name, this.compiler, this.itemCompilationContextCreator);
|
| -
|
| - Queue<WorkItem> get queue;
|
| - bool get queueIsEmpty => queue.isEmpty;
|
| -
|
| - /// Returns [:true:] if this enqueuer is the resolution enqueuer.
|
| - bool get isResolutionQueue => false;
|
| -
|
| - QueueFilter get filter => compiler.enqueuerFilter;
|
| -
|
| - /// Returns [:true:] if [member] has been processed by this enqueuer.
|
| - bool isProcessed(Element member);
|
| -
|
| - /**
|
| - * Documentation wanted -- johnniwinther
|
| - *
|
| - * Invariant: [element] must be a declaration element.
|
| - */
|
| - void addToWorkList(Element element) {
|
| - assert(invariant(element, element.isDeclaration));
|
| - internalAddToWorkList(element);
|
| - }
|
| -
|
| - /**
|
| - * Adds [element] to the work list if it has not already been processed.
|
| - *
|
| - * Returns [true] if the element was actually added to the queue.
|
| - */
|
| - bool internalAddToWorkList(Element element);
|
| -
|
| - void registerInstantiatedType(InterfaceType type, Registry registry,
|
| - {bool mirrorUsage: false}) {
|
| - task.measure(() {
|
| - ClassElement cls = type.element;
|
| - registry.registerDependency(cls);
|
| - cls.ensureResolved(compiler);
|
| - universe.registerTypeInstantiation(type, byMirrors: mirrorUsage);
|
| - processInstantiatedClass(cls);
|
| - });
|
| - }
|
| -
|
| - void registerInstantiatedClass(ClassElement cls, Registry registry,
|
| - {bool mirrorUsage: false}) {
|
| - cls.ensureResolved(compiler);
|
| - registerInstantiatedType(cls.rawType, registry, mirrorUsage: mirrorUsage);
|
| - }
|
| -
|
| - bool checkNoEnqueuedInvokedInstanceMethods() {
|
| - return filter.checkNoEnqueuedInvokedInstanceMethods(this);
|
| - }
|
| -
|
| - void processInstantiatedClassMembers(ClassElement cls) {
|
| - cls.implementation.forEachMember(processInstantiatedClassMember);
|
| - }
|
| -
|
| - void processInstantiatedClassMember(ClassElement cls, Element member) {
|
| - assert(invariant(member, member.isDeclaration));
|
| - if (isProcessed(member)) return;
|
| - if (!member.isInstanceMember) return;
|
| -
|
| - String memberName = member.name;
|
| -
|
| - if (member.kind == ElementKind.FIELD) {
|
| - // The obvious thing to test here would be "member.isNative",
|
| - // however, that only works after metadata has been parsed/analyzed,
|
| - // and that may not have happened yet.
|
| - // So instead we use the enclosing class, which we know have had
|
| - // its metadata parsed and analyzed.
|
| - // Note: this assumes that there are no non-native fields on native
|
| - // classes, which may not be the case when a native class is subclassed.
|
| - if (cls.isNative) {
|
| - compiler.world.registerUsedElement(member);
|
| - nativeEnqueuer.handleFieldAnnotations(member);
|
| - if (universe.hasInvokedGetter(member, compiler.world) ||
|
| - universe.hasInvocation(member, compiler.world)) {
|
| - nativeEnqueuer.registerFieldLoad(member);
|
| - // In handleUnseenSelector we can't tell if the field is loaded or
|
| - // stored. We need the basic algorithm to be Church-Rosser, since the
|
| - // resolution 'reduction' order is different to the codegen order. So
|
| - // register that the field is also stored. In other words: if we
|
| - // don't register the store here during resolution, the store could be
|
| - // registered during codegen on the handleUnseenSelector path, and
|
| - // cause the set of codegen elements to include unresolved elements.
|
| - nativeEnqueuer.registerFieldStore(member);
|
| - addToWorkList(member);
|
| - return;
|
| - }
|
| - if (universe.hasInvokedSetter(member, compiler.world)) {
|
| - nativeEnqueuer.registerFieldStore(member);
|
| - // See comment after registerFieldLoad above.
|
| - nativeEnqueuer.registerFieldLoad(member);
|
| - addToWorkList(member);
|
| - return;
|
| - }
|
| - // Native fields need to go into instanceMembersByName as they
|
| - // are virtual instantiation points and escape points.
|
| - } else {
|
| - // All field initializers must be resolved as they could
|
| - // have an observable side-effect (and cannot be tree-shaken
|
| - // away).
|
| - addToWorkList(member);
|
| - return;
|
| - }
|
| - } else if (member.kind == ElementKind.FUNCTION) {
|
| - FunctionElement function = member;
|
| - function.computeSignature(compiler);
|
| - if (function.name == Compiler.NO_SUCH_METHOD) {
|
| - enableNoSuchMethod(function);
|
| - }
|
| - if (function.name == Compiler.CALL_OPERATOR_NAME &&
|
| - !cls.typeVariables.isEmpty) {
|
| - registerCallMethodWithFreeTypeVariables(
|
| - function, compiler.globalDependencies);
|
| - }
|
| - // If there is a property access with the same name as a method we
|
| - // need to emit the method.
|
| - if (universe.hasInvokedGetter(function, compiler.world)) {
|
| - registerClosurizedMember(function, compiler.globalDependencies);
|
| - addToWorkList(function);
|
| - return;
|
| - }
|
| - // Store the member in [instanceFunctionsByName] to catch
|
| - // getters on the function.
|
| - instanceFunctionsByName.putIfAbsent(memberName, () => new Set<Element>())
|
| - .add(member);
|
| - if (universe.hasInvocation(function, compiler.world)) {
|
| - addToWorkList(function);
|
| - return;
|
| - }
|
| - } else if (member.kind == ElementKind.GETTER) {
|
| - FunctionElement getter = member;
|
| - getter.computeSignature(compiler);
|
| - if (universe.hasInvokedGetter(getter, compiler.world)) {
|
| - addToWorkList(getter);
|
| - return;
|
| - }
|
| - // We don't know what selectors the returned closure accepts. If
|
| - // the set contains any selector we have to assume that it matches.
|
| - if (universe.hasInvocation(getter, compiler.world)) {
|
| - addToWorkList(getter);
|
| - return;
|
| - }
|
| - } else if (member.kind == ElementKind.SETTER) {
|
| - FunctionElement setter = member;
|
| - setter.computeSignature(compiler);
|
| - if (universe.hasInvokedSetter(setter, compiler.world)) {
|
| - addToWorkList(setter);
|
| - return;
|
| - }
|
| - }
|
| -
|
| - // The element is not yet used. Add it to the list of instance
|
| - // members to still be processed.
|
| - instanceMembersByName.putIfAbsent(memberName, () => new Set<Element>())
|
| - .add(member);
|
| - }
|
| -
|
| - void enableNoSuchMethod(Element element) {}
|
| - void enableIsolateSupport() {}
|
| -
|
| - void processInstantiatedClass(ClassElement cls) {
|
| - task.measure(() {
|
| - if (_processedClasses.contains(cls)) return;
|
| - // The class must be resolved to compute the set of all
|
| - // supertypes.
|
| - cls.ensureResolved(compiler);
|
| -
|
| - void processClass(ClassElement cls) {
|
| - if (_processedClasses.contains(cls)) return;
|
| -
|
| - _processedClasses.add(cls);
|
| - recentClasses.add(cls);
|
| - cls.ensureResolved(compiler);
|
| - cls.implementation.forEachMember(processInstantiatedClassMember);
|
| - if (isResolutionQueue) {
|
| - compiler.resolver.checkClass(cls);
|
| - }
|
| - // We only tell the backend once that [cls] was instantiated, so
|
| - // any additional dependencies must be treated as global
|
| - // dependencies.
|
| - compiler.backend.registerInstantiatedClass(
|
| - cls, this, compiler.globalDependencies);
|
| - }
|
| - processClass(cls);
|
| - for (Link<DartType> supertypes = cls.allSupertypes;
|
| - !supertypes.isEmpty; supertypes = supertypes.tail) {
|
| - processClass(supertypes.head.element);
|
| - }
|
| - });
|
| - }
|
| -
|
| - void registerNewSelector(Selector selector,
|
| - Map<String, Set<Selector>> selectorsMap) {
|
| - String name = selector.name;
|
| - Set<Selector> selectors =
|
| - selectorsMap.putIfAbsent(name, () => new Setlet<Selector>());
|
| - if (!selectors.contains(selector)) {
|
| - selectors.add(selector);
|
| - handleUnseenSelector(name, selector);
|
| - }
|
| - }
|
| -
|
| - void registerInvocation(Selector selector) {
|
| - task.measure(() {
|
| - registerNewSelector(selector, universe.invokedNames);
|
| - });
|
| - }
|
| -
|
| - void registerInvokedGetter(Selector selector) {
|
| - task.measure(() {
|
| - registerNewSelector(selector, universe.invokedGetters);
|
| - });
|
| - }
|
| -
|
| - void registerInvokedSetter(Selector selector) {
|
| - task.measure(() {
|
| - registerNewSelector(selector, universe.invokedSetters);
|
| - });
|
| - }
|
| -
|
| - /**
|
| - * Decides whether an element should be included to satisfy requirements
|
| - * of the mirror system. [includedEnclosing] provides a hint whether the
|
| - * enclosing element was included.
|
| - *
|
| - * The actual implementation depends on the current compiler phase.
|
| - */
|
| - bool shouldIncludeElementDueToMirrors(Element element,
|
| - {bool includedEnclosing});
|
| -
|
| - void logEnqueueReflectiveAction(action, [msg = ""]) {
|
| - if (TRACE_MIRROR_ENQUEUING) {
|
| - print("MIRROR_ENQUEUE (${isResolutionQueue ? "R" : "C"}): $action $msg");
|
| - }
|
| - }
|
| -
|
| - /// Enqeue the constructor [ctor] if it is required for reflection.
|
| - ///
|
| - /// [enclosingWasIncluded] provides a hint whether the enclosing element was
|
| - /// needed for reflection.
|
| - void enqueueReflectiveConstructor(ConstructorElement ctor,
|
| - bool enclosingWasIncluded) {
|
| - if (shouldIncludeElementDueToMirrors(ctor,
|
| - includedEnclosing: enclosingWasIncluded)) {
|
| - logEnqueueReflectiveAction(ctor);
|
| - ClassElement cls = ctor.declaration.enclosingClass;
|
| - registerInstantiatedType(cls.rawType, compiler.mirrorDependencies,
|
| - mirrorUsage: true);
|
| - registerStaticUse(ctor.declaration);
|
| - }
|
| - }
|
| -
|
| - /// Enqeue the member [element] if it is required for reflection.
|
| - ///
|
| - /// [enclosingWasIncluded] provides a hint whether the enclosing element was
|
| - /// needed for reflection.
|
| - void enqueueReflectiveMember(Element element, bool enclosingWasIncluded) {
|
| - if (shouldIncludeElementDueToMirrors(element,
|
| - includedEnclosing: enclosingWasIncluded)) {
|
| - logEnqueueReflectiveAction(element);
|
| - if (element.isTypedef) {
|
| - TypedefElement typedef = element;
|
| - typedef.ensureResolved(compiler);
|
| - compiler.world.allTypedefs.add(element);
|
| - } else if (Elements.isStaticOrTopLevel(element)) {
|
| - registerStaticUse(element.declaration);
|
| - } else if (element.isInstanceMember) {
|
| - // We need to enqueue all members matching this one in subclasses, as
|
| - // well.
|
| - // TODO(herhut): Use TypedSelector.subtype for enqueueing
|
| - Selector selector = new Selector.fromElement(element);
|
| - registerSelectorUse(selector);
|
| - if (element.isField) {
|
| - Selector selector =
|
| - new Selector.setter(element.name, element.library);
|
| - registerInvokedSetter(selector);
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - /// Enqeue the member [element] if it is required for reflection.
|
| - ///
|
| - /// [enclosingWasIncluded] provides a hint whether the enclosing element was
|
| - /// needed for reflection.
|
| - void enqueueReflectiveElementsInClass(ClassElement cls,
|
| - Iterable<ClassElement> recents,
|
| - bool enclosingWasIncluded) {
|
| - if (cls.library.isInternalLibrary || cls.isInjected) return;
|
| - bool includeClass = shouldIncludeElementDueToMirrors(cls,
|
| - includedEnclosing: enclosingWasIncluded);
|
| - if (includeClass) {
|
| - logEnqueueReflectiveAction(cls, "register");
|
| - ClassElement decl = cls.declaration;
|
| - registerInstantiatedClass(decl, compiler.mirrorDependencies,
|
| - mirrorUsage: true);
|
| - }
|
| - // If the class is never instantiated, we know nothing of it can possibly
|
| - // be reflected upon.
|
| - // TODO(herhut): Add a warning if a mirrors annotation cannot hit.
|
| - if (recents.contains(cls.declaration)) {
|
| - logEnqueueReflectiveAction(cls, "members");
|
| - cls.constructors.forEach((Element element) {
|
| - enqueueReflectiveConstructor(element, includeClass);
|
| - });
|
| - cls.forEachClassMember((Member member) {
|
| - enqueueReflectiveMember(member.element, includeClass);
|
| - });
|
| - }
|
| - }
|
| -
|
| - /// Enqeue special classes that might not be visible by normal means or that
|
| - /// would not normally be enqueued:
|
| - ///
|
| - /// [Closure] is treated specially as it is the superclass of all closures.
|
| - /// Although it is in an internal library, we mark it as reflectable. Note
|
| - /// that none of its methods are reflectable, unless reflectable by
|
| - /// inheritance.
|
| - void enqueueReflectiveSpecialClasses() {
|
| - Iterable<ClassElement> classes =
|
| - compiler.backend.classesRequiredForReflection;
|
| - for (ClassElement cls in classes) {
|
| - if (compiler.backend.referencedFromMirrorSystem(cls)) {
|
| - logEnqueueReflectiveAction(cls);
|
| - registerInstantiatedClass(cls, compiler.mirrorDependencies,
|
| - mirrorUsage: true);
|
| - }
|
| - }
|
| - }
|
| -
|
| - /// Enqeue all local members of the library [lib] if they are required for
|
| - /// reflection.
|
| - void enqueueReflectiveElementsInLibrary(LibraryElement lib,
|
| - Iterable<ClassElement> recents) {
|
| - bool includeLibrary = shouldIncludeElementDueToMirrors(lib,
|
| - includedEnclosing: false);
|
| - lib.forEachLocalMember((Element member) {
|
| - if (member.isClass) {
|
| - enqueueReflectiveElementsInClass(member, recents, includeLibrary);
|
| - } else {
|
| - enqueueReflectiveMember(member, includeLibrary);
|
| - }
|
| - });
|
| - }
|
| -
|
| - /// Enqueue all elements that are matched by the mirrors used
|
| - /// annotation or, in lack thereof, all elements.
|
| - void enqueueReflectiveElements(Iterable<ClassElement> recents) {
|
| - if (!hasEnqueuedReflectiveElements) {
|
| - logEnqueueReflectiveAction("!START enqueueAll");
|
| - // First round of enqueuing, visit everything that is visible to
|
| - // also pick up static top levels, etc.
|
| - // Also, during the first round, consider all classes that have been seen
|
| - // as recently seen, as we do not know how many rounds of resolution might
|
| - // have run before tree shaking is disabled and thus everything is
|
| - // enqueued.
|
| - recents = _processedClasses.toSet();
|
| - compiler.log('Enqueuing everything');
|
| - for (LibraryElement lib in compiler.libraryLoader.libraries) {
|
| - enqueueReflectiveElementsInLibrary(lib, recents);
|
| - }
|
| - enqueueReflectiveSpecialClasses();
|
| - hasEnqueuedReflectiveElements = true;
|
| - hasEnqueuedReflectiveStaticFields = true;
|
| - logEnqueueReflectiveAction("!DONE enqueueAll");
|
| - } else if (recents.isNotEmpty) {
|
| - // Keep looking at new classes until fixpoint is reached.
|
| - logEnqueueReflectiveAction("!START enqueueRecents");
|
| - recents.forEach((ClassElement cls) {
|
| - enqueueReflectiveElementsInClass(cls, recents,
|
| - shouldIncludeElementDueToMirrors(cls.library,
|
| - includedEnclosing: false));
|
| - });
|
| - logEnqueueReflectiveAction("!DONE enqueueRecents");
|
| - }
|
| - }
|
| -
|
| - /// Enqueue the static fields that have been marked as used by reflective
|
| - /// usage through `MirrorsUsed`.
|
| - void enqueueReflectiveStaticFields(Iterable<Element> elements) {
|
| - if (hasEnqueuedReflectiveStaticFields) return;
|
| - hasEnqueuedReflectiveStaticFields = true;
|
| - for (Element element in elements) {
|
| - enqueueReflectiveMember(element, true);
|
| - }
|
| - }
|
| -
|
| - void processSet(
|
| - Map<String, Set<Element>> map,
|
| - String memberName,
|
| - bool f(Element e)) {
|
| - Set<Element> members = map[memberName];
|
| - if (members == null) return;
|
| - // [f] might add elements to [: map[memberName] :] during the loop below
|
| - // so we create a new list for [: map[memberName] :] and prepend the
|
| - // [remaining] members after the loop.
|
| - map[memberName] = new Set<Element>();
|
| - Set<Element> remaining = new Set<Element>();
|
| - for (Element member in members) {
|
| - if (!f(member)) remaining.add(member);
|
| - }
|
| - map[memberName].addAll(remaining);
|
| - }
|
| -
|
| - processInstanceMembers(String n, bool f(Element e)) {
|
| - processSet(instanceMembersByName, n, f);
|
| - }
|
| -
|
| - processInstanceFunctions(String n, bool f(Element e)) {
|
| - processSet(instanceFunctionsByName, n, f);
|
| - }
|
| -
|
| - void handleUnseenSelector(String methodName, Selector selector) {
|
| - processInstanceMembers(methodName, (Element member) {
|
| - if (selector.appliesUnnamed(member, compiler.world)) {
|
| - if (member.isFunction && selector.isGetter) {
|
| - registerClosurizedMember(member, compiler.globalDependencies);
|
| - }
|
| - if (member.isField && member.enclosingClass.isNative) {
|
| - if (selector.isGetter || selector.isCall) {
|
| - nativeEnqueuer.registerFieldLoad(member);
|
| - // We have to also handle storing to the field because we only get
|
| - // one look at each member and there might be a store we have not
|
| - // seen yet.
|
| - // TODO(sra): Process fields for storing separately.
|
| - nativeEnqueuer.registerFieldStore(member);
|
| - } else {
|
| - assert(selector.isSetter);
|
| - nativeEnqueuer.registerFieldStore(member);
|
| - // We have to also handle loading from the field because we only get
|
| - // one look at each member and there might be a load we have not
|
| - // seen yet.
|
| - // TODO(sra): Process fields for storing separately.
|
| - nativeEnqueuer.registerFieldLoad(member);
|
| - }
|
| - }
|
| - addToWorkList(member);
|
| - return true;
|
| - }
|
| - return false;
|
| - });
|
| - if (selector.isGetter) {
|
| - processInstanceFunctions(methodName, (Element member) {
|
| - if (selector.appliesUnnamed(member, compiler.world)) {
|
| - registerClosurizedMember(member, compiler.globalDependencies);
|
| - return true;
|
| - }
|
| - return false;
|
| - });
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Documentation wanted -- johnniwinther
|
| - *
|
| - * Invariant: [element] must be a declaration element.
|
| - */
|
| - void registerStaticUse(Element element) {
|
| - if (element == null) return;
|
| - assert(invariant(element, element.isDeclaration));
|
| - addToWorkList(element);
|
| - compiler.backend.registerStaticUse(element, this);
|
| - }
|
| -
|
| - void registerGetOfStaticFunction(FunctionElement element) {
|
| - registerStaticUse(element);
|
| - compiler.backend.registerGetOfStaticFunction(this);
|
| - universe.staticFunctionsNeedingGetter.add(element);
|
| - }
|
| -
|
| - void registerDynamicInvocation(Selector selector) {
|
| - assert(selector != null);
|
| - registerInvocation(selector);
|
| - }
|
| -
|
| - void registerSelectorUse(Selector selector) {
|
| - if (selector.isGetter) {
|
| - registerInvokedGetter(selector);
|
| - } else if (selector.isSetter) {
|
| - registerInvokedSetter(selector);
|
| - } else {
|
| - registerInvocation(selector);
|
| - }
|
| - }
|
| -
|
| - void registerDynamicGetter(Selector selector) {
|
| - registerInvokedGetter(selector);
|
| - }
|
| -
|
| - void registerDynamicSetter(Selector selector) {
|
| - registerInvokedSetter(selector);
|
| - }
|
| -
|
| - void registerGetterForSuperMethod(Element element) {
|
| - universe.methodsNeedingSuperGetter.add(element);
|
| - }
|
| -
|
| - void registerFieldGetter(Element element) {
|
| - universe.fieldGetters.add(element);
|
| - }
|
| -
|
| - void registerFieldSetter(Element element) {
|
| - universe.fieldSetters.add(element);
|
| - }
|
| -
|
| - void registerIsCheck(DartType type, Registry registry) {
|
| - type = universe.registerIsCheck(type, compiler);
|
| - // 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.kind != TypeKind.TYPE_VARIABLE ||
|
| - !type.element.enclosingElement.isTypedef);
|
| - }
|
| -
|
| - /**
|
| - * If a factory constructor is used with type arguments, we lose track
|
| - * which arguments could be used to create instances of classes that use their
|
| - * type variables as expressions, so we have to remember if we saw such a use.
|
| - */
|
| - void registerFactoryWithTypeArguments(Registry registry) {
|
| - universe.usingFactoryWithTypeArguments = true;
|
| - }
|
| -
|
| - void registerCallMethodWithFreeTypeVariables(
|
| - Element element,
|
| - Registry registry) {
|
| - compiler.backend.registerCallMethodWithFreeTypeVariables(
|
| - element, this, registry);
|
| - universe.callMethodsWithFreeTypeVariables.add(element);
|
| - }
|
| -
|
| - void registerClosurizedMember(Element element, Registry registry) {
|
| - assert(element.isInstanceMember);
|
| - registerClosureIfFreeTypeVariables(element, registry);
|
| - compiler.backend.registerBoundClosure(this);
|
| - universe.closurizedMembers.add(element);
|
| - }
|
| -
|
| - void registerClosureIfFreeTypeVariables(Element element, Registry registry) {
|
| - if (element.computeType(compiler).containsTypeVariables) {
|
| - compiler.backend.registerClosureWithFreeTypeVariables(
|
| - element, this, registry);
|
| - universe.closuresWithFreeTypeVariables.add(element);
|
| - }
|
| - }
|
| -
|
| - void registerClosure(LocalFunctionElement element, Registry registry) {
|
| - universe.allClosures.add(element);
|
| - registerClosureIfFreeTypeVariables(element, registry);
|
| - }
|
| -
|
| - void forEach(void f(WorkItem work)) {
|
| - do {
|
| - while (queue.isNotEmpty) {
|
| - // TODO(johnniwinther): Find an optimal process order.
|
| - filter.processWorkItem(f, queue.removeLast());
|
| - }
|
| - List recents = recentClasses.toList(growable: false);
|
| - recentClasses.clear();
|
| - if (!onQueueEmpty(recents)) recentClasses.addAll(recents);
|
| - } while (queue.isNotEmpty || recentClasses.isNotEmpty);
|
| - }
|
| -
|
| - /// [onQueueEmpty] is called whenever the queue is drained. [recentClasses]
|
| - /// contains the set of all classes seen for the first time since
|
| - /// [onQueueEmpty] was called last. A return value of [true] indicates that
|
| - /// the [recentClasses] have been processed and may be cleared. If [false] is
|
| - /// returned, [onQueueEmpty] will be called once the queue is empty again (or
|
| - /// still empty) and [recentClasses] will be a superset of the current value.
|
| - bool onQueueEmpty(Iterable<ClassElement> recentClasses) {
|
| - return compiler.backend.onQueueEmpty(this, recentClasses);
|
| - }
|
| -
|
| - void logSummary(log(message)) {
|
| - _logSpecificSummary(log);
|
| - nativeEnqueuer.logSummary(log);
|
| - }
|
| -
|
| - /// Log summary specific to the concrete enqueuer.
|
| - void _logSpecificSummary(log(message));
|
| -
|
| - String toString() => 'Enqueuer($name)';
|
| -
|
| - void forgetElement(Element element) {
|
| - universe.forgetElement(element, compiler);
|
| - _processedClasses.remove(element);
|
| - }
|
| -}
|
| -
|
| -/// [Enqueuer] which is specific to resolution.
|
| -class ResolutionEnqueuer extends Enqueuer {
|
| - /**
|
| - * Map from declaration elements to the [TreeElements] object holding the
|
| - * resolution mapping for the element implementation.
|
| - *
|
| - * Invariant: Key elements are declaration elements.
|
| - */
|
| - final Set<AstElement> resolvedElements;
|
| -
|
| - final Queue<ResolutionWorkItem> queue;
|
| -
|
| - /**
|
| - * A deferred task queue for the resolution phase which is processed
|
| - * when the resolution queue has been emptied.
|
| - */
|
| - final Queue<DeferredTask> deferredTaskQueue;
|
| -
|
| - ResolutionEnqueuer(Compiler compiler,
|
| - ItemCompilationContext itemCompilationContextCreator())
|
| - : super('resolution enqueuer', compiler, itemCompilationContextCreator),
|
| - resolvedElements = new Set<AstElement>(),
|
| - queue = new Queue<ResolutionWorkItem>(),
|
| - deferredTaskQueue = new Queue<DeferredTask>();
|
| -
|
| - bool get isResolutionQueue => true;
|
| -
|
| - bool isProcessed(Element member) => resolvedElements.contains(member);
|
| -
|
| - /// Returns `true` if [element] has been processed by the resolution enqueuer.
|
| - bool hasBeenResolved(Element element) {
|
| - return resolvedElements.contains(element.analyzableElement.declaration);
|
| - }
|
| -
|
| - /// Registers [element] as resolved for the resolution enqueuer.
|
| - void registerResolvedElement(AstElement element) {
|
| - resolvedElements.add(element);
|
| - }
|
| -
|
| - /**
|
| - * Decides whether an element should be included to satisfy requirements
|
| - * of the mirror system.
|
| - *
|
| - * During resolution, we have to resort to matching elements against the
|
| - * [MirrorsUsed] pattern, as we do not have a complete picture of the world,
|
| - * yet.
|
| - */
|
| - bool shouldIncludeElementDueToMirrors(Element element,
|
| - {bool includedEnclosing}) {
|
| - return includedEnclosing || compiler.backend.requiredByMirrorSystem(element);
|
| - }
|
| -
|
| - bool internalAddToWorkList(Element element) {
|
| - assert(invariant(element, element is AnalyzableElement,
|
| - message: 'Element $element is not analyzable.'));
|
| - if (hasBeenResolved(element)) return false;
|
| - if (queueIsClosed) {
|
| - throw new SpannableAssertionFailure(element,
|
| - "Resolution work list is closed. Trying to add $element.");
|
| - }
|
| -
|
| - compiler.world.registerUsedElement(element);
|
| -
|
| - queue.add(new ResolutionWorkItem(element, itemCompilationContextCreator()));
|
| -
|
| - // Enable isolate support if we start using something from the isolate
|
| - // library, or timers for the async library. We exclude constant fields,
|
| - // which are ending here because their initializing expression is compiled.
|
| - LibraryElement library = element.library;
|
| - if (!compiler.hasIsolateSupport &&
|
| - (!element.isField || !element.isConst)) {
|
| - String uri = library.canonicalUri.toString();
|
| - if (uri == 'dart:isolate') {
|
| - enableIsolateSupport();
|
| - } else if (uri == 'dart:async') {
|
| - if (element.name == '_createTimer' ||
|
| - element.name == '_createPeriodicTimer') {
|
| - // The [:Timer:] class uses the event queue of the isolate
|
| - // library, so we make sure that event queue is generated.
|
| - enableIsolateSupport();
|
| - }
|
| - }
|
| - }
|
| -
|
| - if (element.isGetter && element.name == Compiler.RUNTIME_TYPE) {
|
| - // Enable runtime type support if we discover a getter called runtimeType.
|
| - // We have to enable runtime type before hitting the codegen, so
|
| - // that constructors know whether they need to generate code for
|
| - // runtime type.
|
| - compiler.enabledRuntimeType = true;
|
| - // TODO(ahe): Record precise dependency here.
|
| - compiler.backend.registerRuntimeType(this, compiler.globalDependencies);
|
| - } else if (element == compiler.functionApplyMethod) {
|
| - compiler.enabledFunctionApply = true;
|
| - }
|
| -
|
| - nativeEnqueuer.registerElement(element);
|
| - return true;
|
| - }
|
| -
|
| - void enableIsolateSupport() {
|
| - compiler.hasIsolateSupport = true;
|
| - compiler.backend.enableIsolateSupport(this);
|
| - }
|
| -
|
| - void enableNoSuchMethod(Element element) {
|
| - if (compiler.enabledNoSuchMethod) return;
|
| - if (compiler.backend.isDefaultNoSuchMethodImplementation(element)) return;
|
| -
|
| - compiler.enabledNoSuchMethod = true;
|
| - compiler.backend.enableNoSuchMethod(element, this);
|
| - }
|
| -
|
| - /**
|
| - * Adds an action to the deferred task queue.
|
| - *
|
| - * The action is performed the next time the resolution queue has been
|
| - * emptied.
|
| - *
|
| - * The queue is processed in FIFO order.
|
| - */
|
| - void addDeferredAction(Element element, DeferredAction action) {
|
| - if (queueIsClosed) {
|
| - throw new SpannableAssertionFailure(element,
|
| - "Resolution work list is closed. "
|
| - "Trying to add deferred action for $element");
|
| - }
|
| - deferredTaskQueue.add(new DeferredTask(element, action));
|
| - }
|
| -
|
| - bool onQueueEmpty(Iterable<ClassElement> recentClasses) {
|
| - emptyDeferredTaskQueue();
|
| - return super.onQueueEmpty(recentClasses);
|
| - }
|
| -
|
| - void emptyDeferredTaskQueue() {
|
| - while (!deferredTaskQueue.isEmpty) {
|
| - DeferredTask task = deferredTaskQueue.removeFirst();
|
| - compiler.withCurrentElement(task.element, task.action);
|
| - }
|
| - }
|
| -
|
| - void registerJsCall(Send node, ResolverVisitor resolver) {
|
| - nativeEnqueuer.registerJsCall(node, resolver);
|
| - }
|
| -
|
| - void registerJsEmbeddedGlobalCall(Send node, ResolverVisitor resolver) {
|
| - nativeEnqueuer.registerJsEmbeddedGlobalCall(node, resolver);
|
| - }
|
| -
|
| - void _logSpecificSummary(log(message)) {
|
| - log('Resolved ${resolvedElements.length} elements.');
|
| - }
|
| -
|
| - void forgetElement(Element element) {
|
| - super.forgetElement(element);
|
| - resolvedElements.remove(element);
|
| - }
|
| -}
|
| -
|
| -/// [Enqueuer] which is specific to code generation.
|
| -class CodegenEnqueuer extends Enqueuer {
|
| - final Queue<CodegenWorkItem> queue;
|
| - final Map<Element, js.Expression> generatedCode =
|
| - new Map<Element, js.Expression>();
|
| -
|
| - final Set<Element> newlyEnqueuedElements;
|
| -
|
| - CodegenEnqueuer(Compiler compiler,
|
| - ItemCompilationContext itemCompilationContextCreator())
|
| - : queue = new Queue<CodegenWorkItem>(),
|
| - newlyEnqueuedElements = compiler.cacheStrategy.newSet(),
|
| - super('codegen enqueuer', compiler, itemCompilationContextCreator);
|
| -
|
| - bool isProcessed(Element member) =>
|
| - member.isAbstract || generatedCode.containsKey(member);
|
| -
|
| - /**
|
| - * Decides whether an element should be included to satisfy requirements
|
| - * of the mirror system.
|
| - *
|
| - * For code generation, we rely on the precomputed set of elements that takes
|
| - * subtyping constraints into account.
|
| - */
|
| - bool shouldIncludeElementDueToMirrors(Element element,
|
| - {bool includedEnclosing}) {
|
| - return compiler.backend.isAccessibleByReflection(element);
|
| - }
|
| -
|
| - bool internalAddToWorkList(Element element) {
|
| - // Don't generate code for foreign elements.
|
| - if (element.isForeign(compiler.backend)) return false;
|
| -
|
| - // Codegen inlines field initializers. It only needs to generate
|
| - // code for checked setters.
|
| - if (element.isField && element.isInstanceMember) {
|
| - if (!compiler.enableTypeAssertions
|
| - || element.enclosingElement.isClosure) {
|
| - return false;
|
| - }
|
| - }
|
| -
|
| - if (compiler.hasIncrementalSupport && !isProcessed(element)) {
|
| - newlyEnqueuedElements.add(element);
|
| - }
|
| -
|
| - if (queueIsClosed) {
|
| - throw new SpannableAssertionFailure(element,
|
| - "Codegen work list is closed. Trying to add $element");
|
| - }
|
| - CodegenWorkItem workItem = new CodegenWorkItem(
|
| - element, itemCompilationContextCreator());
|
| - queue.add(workItem);
|
| - return true;
|
| - }
|
| -
|
| - void _logSpecificSummary(log(message)) {
|
| - log('Compiled ${generatedCode.length} methods.');
|
| - }
|
| -
|
| - void forgetElement(Element element) {
|
| - super.forgetElement(element);
|
| - generatedCode.remove(element);
|
| - if (element is MemberElement) {
|
| - for (Element closure in element.nestedClosures) {
|
| - generatedCode.remove(closure);
|
| - removeFromSet(instanceMembersByName, closure);
|
| - removeFromSet(instanceFunctionsByName, closure);
|
| - }
|
| - }
|
| - }
|
| -}
|
| -
|
| -/// Parameterizes filtering of which work items are enqueued.
|
| -class QueueFilter {
|
| - bool checkNoEnqueuedInvokedInstanceMethods(Enqueuer enqueuer) {
|
| - enqueuer.task.measure(() {
|
| - // Run through the classes and see if we need to compile methods.
|
| - for (ClassElement classElement in
|
| - enqueuer.universe.directlyInstantiatedClasses) {
|
| - for (ClassElement currentClass = classElement;
|
| - currentClass != null;
|
| - currentClass = currentClass.superclass) {
|
| - enqueuer.processInstantiatedClassMembers(currentClass);
|
| - }
|
| - }
|
| - });
|
| - return true;
|
| - }
|
| -
|
| - 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);
|
| -}
|
|
|