// 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;

class EnqueueTask extends CompilerTask {
  final ResolutionEnqueuer resolution;
  final CodegenEnqueuer codegen;

  /// A reverse map from name to *all* elements with that name, not
  /// just instance members of instantiated classes.
  final Map<String, Link<Element>> allElementsByName
      = new Map<String, Link<Element>>();

  void ensureAllElementsByName() {
    if (!allElementsByName.isEmpty) return;

    void addMemberByName(Element element) {
      element = element.declaration;
      String name = element.name.slowToString();
      Link<Element> members = const Link<Element>();
      if (element.isLibrary()) {
        LibraryElementX library = element;
        // Don't include private implementation libraries.  These
        // libraries contain special classes that cause problems
        // in other parts of the resolver (in particular Null and Void).
        // TODO(ahe): Consider lifting this restriction.
        if (!library.isInternalLibrary) {
          members = library.localMembers;
          // TODO(ahe): Is this right?  Is this necessary?
          name = library.getLibraryOrScriptName();
        }
      } else if (element.isClass() && !element.isMixinApplication) {
        // TODO(ahe): Investigate what makes mixin applications crash
        // this method.
        ClassElementX cls = element;
        cls.ensureResolved(compiler);
        members = cls.localMembers;
        for (var link = cls.computeTypeParameters(compiler);
             !link.isEmpty;
             link = link.tail) {
          addMemberByName(link.head.element);
        }
      } else if (element.isConstructor()) {
        SourceString source = Elements.deconstructConstructorName(
            element.name, element.getEnclosingClass());
        if (source == null) {
          // source is null for unnamed constructors.
          name = '';
        } else {
          name = source.slowToString();
        }
      }
      allElementsByName[name] = allElementsByName.putIfAbsent(
          name, () => const Link<Element>()).prepend(element);
      for (var link = members; !link.isEmpty; link = link.tail) {
        addMemberByName(link.head);
      }
    }

    compiler.libraries.values.forEach(addMemberByName);
  }


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

abstract class Enqueuer {
  final String name;
  final Compiler compiler; // TODO(ahe): Remove this dependency.
  final Function itemCompilationContextCreator;
  final Map<String, Link<Element>> instanceMembersByName
      = new Map<String, Link<Element>>();
  final Map<String, Link<Element>> instanceFunctionsByName
      = new Map<String, Link<Element>>();
  final Set<ClassElement> seenClasses = new Set<ClassElement>();
  final Universe universe = new Universe();

  bool queueIsClosed = false;
  EnqueueTask task;
  native.NativeEnqueuer nativeEnqueuer;  // Set by EnqueueTask

  Enqueuer(this.name, this.compiler,
           ItemCompilationContext itemCompilationContextCreator())
    : this.itemCompilationContextCreator = itemCompilationContextCreator;

  /// Returns [:true:] if this enqueuer is the resolution enqueuer.
  bool get isResolutionQueue => false;

  /// 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));
    if (element.isForeign(compiler)) return;

    if (element.isForwardingConstructor) {
      addToWorkList(element.targetConstructor);
      return;
    }

    internalAddToWorkList(element);
  }

  /**
   * Adds [element] to the work list if it has not already been processed.
   */
  void internalAddToWorkList(Element element);

  void registerInstantiatedType(InterfaceType type, TreeElements elements) {
    ClassElement cls = type.element;
    elements.registerDependency(cls);
    cls.ensureResolved(compiler);
    universe.instantiatedTypes.add(type);
    if (universe.instantiatedClasses.contains(cls)) return;
    if (!cls.isAbstract(compiler)) {
      universe.instantiatedClasses.add(cls);
    }
    onRegisterInstantiatedClass(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);
  }

  void registerInstantiatedClass(ClassElement cls, TreeElements elements) {
    cls.ensureResolved(compiler);
    registerInstantiatedType(cls.rawType, elements);
  }

  void registerTypeLiteral(Element element, TreeElements elements) {
    registerInstantiatedClass(compiler.typeClass, elements);
    compiler.backend.registerTypeLiteral(elements);
    if (compiler.mirrorsEnabled) {
      // In order to use reflectClass, we need to find the constructor.
      registerInstantiatedClass(element, elements);
    }
  }

  bool checkNoEnqueuedInvokedInstanceMethods() {
    task.measure(() {
      // Run through the classes and see if we need to compile methods.
      for (ClassElement classElement in universe.instantiatedClasses) {
        for (ClassElement currentClass = classElement;
             currentClass != null;
             currentClass = currentClass.superclass) {
          processInstantiatedClass(currentClass);
        }
      }
    });
    return true;
  }

  void processInstantiatedClass(ClassElement cls) {
    cls.implementation.forEachMember(processInstantiatedClassMember);
  }

  /**
   * Documentation wanted -- johnniwinther
   */
  void processInstantiatedClassMember(ClassElement cls, Element member) {
    assert(invariant(member, member.isDeclaration));
    if (isProcessed(member)) return;
    if (!member.isInstanceMember()) return;

    String memberName = member.name.slowToString();

    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) ||
            universe.hasInvocation(member, compiler)) {
          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)) {
          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) {
      if (member.name == Compiler.NO_SUCH_METHOD) {
        enableNoSuchMethod(member);
      }
      // If there is a property access with the same name as a method we
      // need to emit the method.
      if (universe.hasInvokedGetter(member, compiler)) {
        // We will emit a closure, so make sure the bound closure class is
        // generated.
        registerInstantiatedClass(compiler.boundClosureClass,
                                  // Precise dependency is not important here.
                                  compiler.globalDependencies);
        return addToWorkList(member);
      }
      // Store the member in [instanceFunctionsByName] to catch
      // getters on the function.
      Link<Element> members = instanceFunctionsByName.putIfAbsent(
          memberName, () => const Link<Element>());
      instanceFunctionsByName[memberName] = members.prepend(member);
      if (universe.hasInvocation(member, compiler)) {
        return addToWorkList(member);
      }
    } else if (member.kind == ElementKind.GETTER) {
      if (universe.hasInvokedGetter(member, compiler)) {
        return addToWorkList(member);
      }
      // 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(member, compiler)) {
        return addToWorkList(member);
      }
    } else if (member.kind == ElementKind.SETTER) {
      if (universe.hasInvokedSetter(member, compiler)) {
        return addToWorkList(member);
      }
    }

    // The element is not yet used. Add it to the list of instance
    // members to still be processed.
    Link<Element> members = instanceMembersByName.putIfAbsent(
        memberName, () => const Link<Element>());
    instanceMembersByName[memberName] = members.prepend(member);
  }

  void enableNoSuchMethod(Element element) {}

  void onRegisterInstantiatedClass(ClassElement cls) {
    task.measure(() {
      // The class must be resolved to compute the set of all
      // supertypes.
      cls.ensureResolved(compiler);

      void processClass(ClassElement cls) {
        if (seenClasses.contains(cls)) return;

        seenClasses.add(cls);
        cls.ensureResolved(compiler);
        cls.implementation.forEachMember(processInstantiatedClassMember);
        if (isResolutionQueue) {
          compiler.resolver.checkClass(cls);
        }
      }
      processClass(cls);
      for (Link<DartType> supertypes = cls.allSupertypes;
           !supertypes.isEmpty; supertypes = supertypes.tail) {
        processClass(supertypes.head.element);
      }
    });
  }

  void registerNewSelector(SourceString name,
                           Selector selector,
                           Map<SourceString, Set<Selector>> selectorsMap) {
    if (name != selector.name) {
      String message = "$name != ${selector.name} (${selector.kind})";
      compiler.internalError("Wrong selector name: $message.");
    }
    Set<Selector> selectors =
        selectorsMap.putIfAbsent(name, () => new Set<Selector>());
    if (!selectors.contains(selector)) {
      selectors.add(selector);
      handleUnseenSelector(name, selector);
    }
  }

  void registerInvocation(SourceString methodName, Selector selector) {
    task.measure(() {
      registerNewSelector(methodName, selector, universe.invokedNames);
    });
  }

  void registerInvokedGetter(SourceString getterName, Selector selector) {
    task.measure(() {
      registerNewSelector(getterName, selector, universe.invokedGetters);
    });
  }

  void registerInvokedSetter(SourceString setterName, Selector selector) {
    task.measure(() {
      registerNewSelector(setterName, selector, universe.invokedSetters);
    });
  }

  /// Called when [:const Symbol(name):] is seen.
  void registerConstSymbol(String name, TreeElements elements) {
    // If dart:mirrors is loaded, a const symbol may be used to call a
    // static/top-level method or accessor, instantiate a class, call
    // an instance method or accessor with the given name.
    if (!compiler.mirrorsEnabled) return;

    task.ensureAllElementsByName();

    for (var link = task.allElementsByName[name];
         link != null && !link.isEmpty;
         link = link.tail) {
      Element element = link.head;
      if (Elements.isUnresolved(element)) {
        // Ignore.
      } else if (element.isConstructor()) {
        ClassElement cls = element.declaration.getEnclosingClass();
        registerInstantiatedType(cls.rawType, elements);
        registerStaticUse(element.declaration);
      } else if (element.impliesType()) {
        // Don't enqueue classes, typedefs, and type variables.
      } else if (Elements.isStaticOrTopLevel(element)) {
        registerStaticUse(element.declaration);
      } else if (element.isInstanceMember()) {
        if (element.isFunction()) {
          int arity =
              element.asFunctionElement().requiredParameterCount(compiler);
          Selector selector =
              new Selector.call(element.name, element.getLibrary(), arity);
          registerInvocation(element.name, selector);
        } else if (element.isSetter()) {
          Selector selector =
              new Selector.setter(element.name, element.getLibrary());
          registerInvokedSetter(element.name, selector);
        } else if (element.isGetter()) {
          Selector selector =
              new Selector.getter(element.name, element.getLibrary());
          registerInvokedGetter(element.name, selector);
        } else if (element.isField()) {
          Selector selector =
              new Selector.setter(element.name, element.getLibrary());
          registerInvokedSetter(element.name, selector);
          selector =
              new Selector.getter(element.name, element.getLibrary());
          registerInvokedGetter(element.name, selector);
        }
      }
    }
  }

  /// Called when [:new Symbol(...):] is seen.
  void registerNewSymbol(TreeElements elements) {
  }

  processLink(Map<String, Link<Element>> map,
              SourceString n,
              bool f(Element e)) {
    String memberName = n.slowToString();
    Link<Element> members = map[memberName];
    if (members != null) {
      LinkBuilder<Element> remaining = new LinkBuilder<Element>();
      for (; !members.isEmpty; members = members.tail) {
        if (!f(members.head)) remaining.addLast(members.head);
      }
      map[memberName] = remaining.toLink();
    }
  }

  processInstanceMembers(SourceString n, bool f(Element e)) {
    processLink(instanceMembersByName, n, f);
  }

  processInstanceFunctions(SourceString n, bool f(Element e)) {
    processLink(instanceFunctionsByName, n, f);
  }

  void handleUnseenSelector(SourceString methodName, Selector selector) {
    processInstanceMembers(methodName, (Element member) {
      if (selector.appliesUnnamed(member, compiler)) {
        if (member.isField() && member.getEnclosingClass().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)) {
          // We will emit a closure, so make sure the bound closure class is
          // generated.
          registerInstantiatedClass(compiler.boundClosureClass,
                                    // Precise dependency is not important here.
                                    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);
  }

  void registerGetOfStaticFunction(FunctionElement element) {
    registerStaticUse(element);
    registerInstantiatedClass(compiler.closureClass,
                              compiler.globalDependencies);
    universe.staticFunctionsNeedingGetter.add(element);
  }

  void registerDynamicInvocation(SourceString methodName, Selector selector) {
    assert(selector != null);
    registerInvocation(methodName, selector);
  }

  void registerDynamicInvocationOf(Element element, Selector selector) {
    assert(selector.isCall()
           || selector.isOperator()
           || selector.isIndex()
           || selector.isIndexSet());
    if (element.isFunction() || element.isGetter()) {
      addToWorkList(element);
    } else if (element.isAbstractField()) {
      AbstractFieldElement field = element;
      // Since the invocation is a dynamic call on a getter, we only
      // need to schedule the getter on the work list.
      addToWorkList(field.getter);
    } else {
      assert(element.isField());
    }
    // We also need to add the selector to the invoked names map,
    // because the emitter uses that map to generate parameter stubs.
    Set<Selector> selectors = universe.invokedNames.putIfAbsent(
        element.name, () => new Set<Selector>());
    selectors.add(selector);
  }

  void registerSelectorUse(Selector selector) {
    if (selector.isGetter()) {
      registerInvokedGetter(selector.name, selector);
    } else if (selector.isSetter()) {
      registerInvokedSetter(selector.name, selector);
    } else {
      registerInvocation(selector.name, selector);
    }
  }

  void registerDynamicGetter(SourceString methodName, Selector selector) {
    registerInvokedGetter(methodName, selector);
  }

  void registerDynamicSetter(SourceString methodName, Selector selector) {
    registerInvokedSetter(methodName, selector);
  }

  void registerFieldGetter(Element element) {
    universe.fieldGetters.add(element);
  }

  void registerFieldSetter(Element element) {
    universe.fieldSetters.add(element);
  }

  void registerIsCheck(DartType type, TreeElements elements) {
    // 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());
    universe.isChecks.add(type);
    compiler.backend.registerIsCheck(type, this, elements);
  }

  /**
   * 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(TreeElements elements) {
    universe.usingFactoryWithTypeArguments = true;
  }

  void registerAsCheck(DartType type, TreeElements elements) {
    registerIsCheck(type, elements);
    compiler.backend.registerAsCheck(type, elements);
  }

  void forEach(f(WorkItem work));

  void forEachPostProcessTask(f(PostProcessTask work)) {}

  void logSummary(log(message)) {
    _logSpecificSummary(log);
    nativeEnqueuer.logSummary(log);
  }

  /// Log summary specific to the concrete enqueuer.
  void _logSpecificSummary(log(message));

  String toString() => 'Enqueuer($name)';
}

/// [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 Map<Element, TreeElements> resolvedElements;

  final Queue<ResolutionWorkItem> queue;

  /**
   * A post-processing queue for the resolution phase which is processed
   * immediately after the resolution queue has been closed.
   */
  final Queue<PostProcessTask> postQueue;

  ResolutionEnqueuer(Compiler compiler,
                     ItemCompilationContext itemCompilationContextCreator())
      : super('resolution enqueuer', compiler, itemCompilationContextCreator),
        resolvedElements = new Map<Element, TreeElements>(),
        queue = new Queue<ResolutionWorkItem>(),
        postQueue = new Queue<PostProcessTask>();

  bool get isResolutionQueue => true;

  bool isProcessed(Element member) => resolvedElements.containsKey(member);

  TreeElements getCachedElements(Element element) {
    // TODO(ngeoffray): Get rid of this check.
    if (element.enclosingElement.isClosure()) {
      closureMapping.ClosureClassElement cls = element.enclosingElement;
      element = cls.methodElement;
    } else if (element.isGenerativeConstructorBody()) {
      ConstructorBodyElement body = element;
      element = body.constructor;
    }
    Element owner = element.getOutermostEnclosingMemberOrTopLevel();
    if (owner == null) {
      owner = element;
    }
    return resolvedElements[owner.declaration];
  }

  void internalAddToWorkList(Element element) {
    if (getCachedElements(element) != null) return;
    if (queueIsClosed) {
      throw new SpannableAssertionFailure(element,
                                          "Resolution work list is closed.");
    }
    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.
    LibraryElement library = element.getLibrary();
    if (!compiler.hasIsolateSupport()) {
      String uri = library.canonicalUri.toString();
      if (uri == 'dart:isolate') {
        enableIsolateSupport(library);
      } else if (uri == 'dart:async') {
        ClassElement cls = element.getEnclosingClass();
        if (cls != null && cls.name == const SourceString('Timer')) {
          // The [:Timer:] class uses the event queue of the isolate
          // library, so we make sure that event queue is generated.
          enableIsolateSupport(library);
        }
      }
    }

    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(compiler.globalDependencies);
    } else if (element == compiler.functionApplyMethod) {
      compiler.enabledFunctionApply = true;
    } else if (element == compiler.invokeOnMethod) {
      compiler.enabledInvokeOn = true;
    }

    nativeEnqueuer.registerElement(element);
  }

  void enableIsolateSupport(LibraryElement element) {
    compiler.isolateLibrary = element.patch;
    var startRootIsolate =
        compiler.isolateHelperLibrary.find(Compiler.START_ROOT_ISOLATE);
    addToWorkList(startRootIsolate);
    compiler.globalDependencies.registerDependency(startRootIsolate);
    addToWorkList(compiler.isolateHelperLibrary.find(
        const SourceString('_currentIsolate')));
    addToWorkList(compiler.isolateHelperLibrary.find(
        const SourceString('_callInIsolate')));
  }

  void enableNoSuchMethod(Element element) {
    if (compiler.enabledNoSuchMethod) return;
    if (compiler.backend.isDefaultNoSuchMethodImplementation(element)) return;

    Selector selector = compiler.noSuchMethodSelector;
    compiler.enabledNoSuchMethod = true;
    registerInvocation(Compiler.NO_SUCH_METHOD, selector);

    compiler.createInvocationMirrorElement =
        compiler.findHelper(Compiler.CREATE_INVOCATION_MIRROR);
    addToWorkList(compiler.createInvocationMirrorElement);
  }

  void forEach(f(WorkItem work)) {
    while (!queue.isEmpty) {
      // TODO(johnniwinther): Find an optimal process order for resolution.
      f(queue.removeLast());
    }
  }

  /**
   * Adds an action to the post-processing queue.
   *
   * The action is performed as part of the post-processing immediately after
   * the resolution queue has been closed. As a consequence, [action] must not
   * add elements to the resolution queue.
   */
  void addPostProcessAction(Element element, PostProcessAction action) {
    if (queueIsClosed) {
      throw new SpannableAssertionFailure(element,
                                          "Resolution work list is closed.");
    }
    postQueue.add(new PostProcessTask(element, action));
  }

  void forEachPostProcessTask(f(PostProcessTask work)) {
    while (!postQueue.isEmpty) {
      f(postQueue.removeFirst());
    }
  }

  void registerJsCall(Send node, ResolverVisitor resolver) {
    nativeEnqueuer.registerJsCall(node, resolver);
  }

  void _logSpecificSummary(log(message)) {
    log('Resolved ${resolvedElements.length} elements.');
  }
}

/// [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>();

  CodegenEnqueuer(Compiler compiler,
                  ItemCompilationContext itemCompilationContextCreator())
      : super('codegen enqueuer', compiler, itemCompilationContextCreator),
        queue = new Queue<CodegenWorkItem>();

  bool isProcessed(Element member) =>
      member.isAbstract(compiler) || generatedCode.containsKey(member);

  void internalAddToWorkList(Element element) {
    // Codegen inlines field initializers, so it does not need to add
    // individual fields in the work list.
    if (element.isField() && element.isInstanceMember()) return;

    if (queueIsClosed) {
      throw new SpannableAssertionFailure(element,
                                          "Codegen work list is closed.");
    }
    CodegenWorkItem workItem = new CodegenWorkItem(
        element, itemCompilationContextCreator());
    queue.add(workItem);
  }

  void forEach(f(WorkItem work)) {
    while(!queue.isEmpty) {
      // TODO(johnniwinther): Find an optimal process order for codegen.
      f(queue.removeLast());
    }
  }

  void _logSpecificSummary(log(message)) {
    log('Compiled ${generatedCode.length} methods.');
  }
}
