// Copyright (c) 2018, the R8 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.

package com.android.tools.r8.dex;

import com.android.tools.r8.dex.VirtualFile.VirtualFileCycler;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.utils.ThreadUtils;
import com.google.common.collect.Maps;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

/**
 * Partition classes among dex files to limit LinearAlloc usage during DexOpt.
 *
 * This is achieved by ensuring that each class has all it's hierarchy either in the bootclasspath
 * or in the same secondary dex. This is preventing linking errors for those classes. Then if it's
 * not possible to respect this constraint for some classes, instead ensure that those classes are
 * put in a different secondary dex than all their link dependents (i.e. subclasses,
 * implementations or sub interfaces). Those classes will failed to link during DexOpt but they will
 * be loaded only once, this ensures that DexOpt will not use any extra LinearAlloc space for those
 * classes in linking error.
 */
public class InheritanceClassInDexDistributor {

  private static final Comparator<DexProgramClass> DEX_PROGRAM_CLASS_COMPARATOR =
      (a, b) -> a.type.descriptor.compareTo(b.type.descriptor);

  private static final int DEX_FULL_ENOUGH_THRESHOLD = VirtualFile.MAX_ENTRIES - 100;
  private final ExecutorService executorService;

  /**
   * Group of classes.
   */
  private class ClassGroup implements Comparable<ClassGroup> {

    public final Set<DexProgramClass> members;
    public int numberOfFieldIds = -1;
    public int numberOfMethodIds = -1;
    public boolean dependsOnMainDexClasses = false;

    public ClassGroup() {
      members = new HashSet<>();
    }

    public ClassGroup(Set<DexProgramClass> members) {
      this.members = members;
      updateNumbersOfIds();
    }

    public void updateNumbersOfIds() {
      // Use a temporary VirtualFile to evaluate the number of ids in the group.
      VirtualFile virtualFile = new VirtualFile(0, appView, namingLens);
      // Note: sort not needed.
      for (DexProgramClass clazz : members) {
        virtualFile.addClass(clazz);
      }
      numberOfFieldIds = virtualFile.getNumberOfFields();
      numberOfMethodIds = virtualFile.getNumberOfMethods();
    }

    public boolean canFitInOneDex() {
      return numberOfFieldIds < VirtualFile.MAX_ENTRIES
          && numberOfMethodIds < VirtualFile.MAX_ENTRIES;
    }

    // This is used for sorting. Compared groups must be disjoint.
    @Override
    public int compareTo(ClassGroup other) {
      assert !(
          members.isEmpty()
          || other.members.isEmpty()
          || numberOfFieldIds == -1 || numberOfMethodIds == -1);
      if (this == other) {
        return 0;
      }
      if (numberOfMethodIds != other.numberOfMethodIds) {
        return numberOfMethodIds - other.numberOfMethodIds;
      }
      if (numberOfFieldIds != other.numberOfFieldIds) {
        return numberOfFieldIds - other.numberOfFieldIds;
      }
      if (members.size() != other.members.size()) {
        return members.size() - other.members.size();
      }
      // We can end up here frequently with one element groups, but it seems very unlikely if the
      // groups grow significantly bigger.
      int result = DEX_PROGRAM_CLASS_COMPARATOR.compare(
          getSortedCopy(members).iterator().next(),
          getSortedCopy(other.members).iterator().next());
      assert result != 0;
      return result;
    }
  }

  /**
   * For {@link ClassGroup} with a dependency to the main dex classes. Allow to split the
   * members in 3 categories:
   * - Category 1: members which could go to a secondary dex altogether without facing linking
   *   error.
   * - Category 2: members which could go to the main dex without needing category 1 members to link
   * - Category 3: others members of the group, those which will fail to link unless the whole group
   *   goes into the main dex.
   */
  private class CategorizedInheritanceGroupWithMainDexDependency {

    /** Category 1. */
    final Set<DexProgramClass> mainDexIndependents = new HashSet<>();
    /** Category 2. Main dex dependents independents from mainDexIndependents elements. */
    final Set<DexProgramClass> independentsFromMainDexIndependents = new HashSet<>();
    /** Category 3. Main dex dependents also depending on some mainDexIndependents elements. */
    final Set<DexProgramClass> dependentsOfMainDexIndependents = new HashSet<>();

    CategorizedInheritanceGroupWithMainDexDependency(ClassGroup group) {

      int totalClassNumber = group.members.size();

      /**
       * Category 2 + category 3 elements. Used during construction only.
       */
      Set<DexProgramClass> mainDexDependents = new HashSet<>();
      // split group members between mainDexIndependents and mainDexDependents
      // Note: sort not needed.
      for (DexProgramClass candidate : group.members) {
        isDependingOnMainDexClass(mainDexDependents, candidate);
      }

      // split mainDexDependents members between independentsFromMainDexIndependents and
      // dependentsOfMainDexIndependents
      for (DexProgramClass candidate : mainDexDependents) {
        isDependingOnMainDexIndependents(candidate);
      }
      assert totalClassNumber ==
          mainDexIndependents.size()
              + dependentsOfMainDexIndependents.size()
              + independentsFromMainDexIndependents.size();

    }

    private boolean isDependingOnMainDexClass(
        Set<DexProgramClass> mainDexDependents, DexProgramClass clazz) {
      if (clazz == null) {
        return false;
      }

      // Think: build on one Map<dexProgramClass, Boolean> and split in a second step.
      if (mainDexIndependents.contains(clazz)) {
        return false;
      }
      if (mainDexDependents.contains(clazz)) {
        return true;
      }
      if (mainDex.classes().contains(clazz)) {
        return true;
      }
      boolean isDependent = false;
      if (isDependingOnMainDexClass(
          mainDexDependents, appView.programDefinitionFor(clazz.superType, clazz))) {
        isDependent = true;
      } else {
        for (DexType interfaze : clazz.interfaces.values) {
          if (isDependingOnMainDexClass(
              mainDexDependents, appView.programDefinitionFor(interfaze, clazz))) {
            isDependent = true;
            break;
          }
        }
      }

      if (isDependent) {
        mainDexDependents.add(clazz);
      } else {
        mainDexIndependents.add(clazz);
      }
      return isDependent;
    }

    private boolean isDependingOnMainDexIndependents(DexProgramClass clazz) {
      if (clazz == null) {
        return false;
      }

      // Think: build on one Map<dexProgramClass, Boolean> and split in a second step.
      if (independentsFromMainDexIndependents.contains(clazz)) {
        return false;
      }
      if (dependentsOfMainDexIndependents.contains(clazz)) {
        return true;
      }
      if (mainDex.classes().contains(clazz)) {
        return false;
      }
      if (mainDexIndependents.contains(clazz)) {
        return true;
      }
      boolean isDependent = false;
      if (isDependingOnMainDexIndependents(appView.programDefinitionFor(clazz.superType, clazz))) {
        isDependent = true;
      } else {
        for (DexType interfaze : clazz.interfaces.values) {
          if (isDependingOnMainDexIndependents(appView.programDefinitionFor(interfaze, clazz))) {
            isDependent = true;
            break;
          }
        }
      }

      if (isDependent) {
        dependentsOfMainDexIndependents.add(clazz);
      } else {
        independentsFromMainDexIndependents.add(clazz);
      }
      return isDependent;
    }
  }

  /**
   * Collect direct inheritance relation between a set of {@link DexProgramClass}.
   * This is not a general purpose tool: it's ignoring any inheritance relation with classes outside
   * of the provided set.
   */
  private static class DirectSubClassesInfo {
    /** Class or interface to direct subclasses or direct sub interfaces and implementing classes */
    private final Map<DexProgramClass, Collection<DexProgramClass>> directSubClasses;
    private final Set<DexProgramClass> classes;

    DirectSubClassesInfo(AppView<?> appView, Set<DexProgramClass> classes) {
      Map<DexProgramClass, Collection<DexProgramClass>> directSubClasses = new HashMap<>();
      for (DexProgramClass clazz : classes) {
        addDirectSubClass(appView, classes, directSubClasses, clazz.superType, clazz);
        for (DexType interfaze : clazz.interfaces.values) {
          addDirectSubClass(appView, classes, directSubClasses, interfaze, clazz);
        }
      }

      this.classes = classes;
      this.directSubClasses = directSubClasses;
    }

    Collection<DexProgramClass> getDirectSubClasses(DexProgramClass clazz) {
      assert classes.contains(clazz);
      return directSubClasses.getOrDefault(clazz, Collections.emptyList());
    }

    private static void addDirectSubClass(
        AppView<?> appView,
        Set<DexProgramClass> classes,
        Map<DexProgramClass, Collection<DexProgramClass>> directSubClasses,
        DexType superType,
        DexProgramClass clazz) {
      DexProgramClass zuper = appView.programDefinitionFor(superType, clazz);
      // Don't bother collecting subclasses info that we won't use.
      if (zuper != null && classes.contains(zuper)) {
        Collection<DexProgramClass> subClasses =
            directSubClasses.computeIfAbsent(zuper, unused -> new ArrayList<>());
        subClasses.add(clazz);
      }
    }

  }

  private final VirtualFile mainDex;
  private final List<VirtualFile> dexes;
  private final BitSet fullDex = new BitSet();
  private final Set<DexProgramClass> classes;
  private final AppView<?> appView;
  private final int dexIndexOffset;
  private final NamingLens namingLens;
  private final DirectSubClassesInfo directSubClasses;

  public InheritanceClassInDexDistributor(
      VirtualFile mainDex,
      List<VirtualFile> dexes,
      Set<DexProgramClass> classes,
      int dexIndexOffset,
      NamingLens namingLens,
      AppView<?> appView,
      ExecutorService executorService) {
    this.mainDex = mainDex;
    this.dexes = dexes;
    this.classes = classes;
    this.dexIndexOffset = dexIndexOffset;
    this.namingLens = namingLens;
    this.appView = appView;
    this.executorService = executorService;

    directSubClasses = new DirectSubClassesInfo(appView, classes);
  }

  public void distribute() {
    List<ClassGroup> remainingInheritanceGroups = collectInheritanceGroups();
    // Sort to ensure reproducible allocation
    remainingInheritanceGroups.sort(null);
    // Starts with big groups since they are more likely to cause problem.
    Collections.reverse(remainingInheritanceGroups);

    // Allocate member of groups depending on
    // the main dex members
    for (Iterator<ClassGroup> iter = remainingInheritanceGroups.iterator(); iter.hasNext();) {
      ClassGroup group = iter.next();
      if (group.dependsOnMainDexClasses) {

        iter.remove();

        // Try to assign the whole group to the main dex
        if (group.canFitInOneDex()
            && !isDexFull(mainDex)
            && assignAll(mainDex, group.members)) {
          // It fitted, so work done
          continue;
        }

        // We can't put the whole group in the main dex, let's split the group to try to make the
        // best of it.
        CategorizedInheritanceGroupWithMainDexDependency groupSplit =
            new CategorizedInheritanceGroupWithMainDexDependency(group);

        // Attempt to assign the "main dex dependent classes independents from mainDexIndependents"
        // to the main dex where they can link.
        Collection<DexProgramClass> classesMissingMainDex =
            assignFromRoot(mainDex, groupSplit.independentsFromMainDexIndependents);

        // Assign mainDexIndependents classes, those can link as long as the group fit into one dex
        ClassGroup mainDexIndependentGroup =
            new ClassGroup(groupSplit.mainDexIndependents);

        Collection<VirtualFile> mainDexInpendentsDexes =
            assignGroup(mainDexIndependentGroup, Collections.singletonList(mainDex));

        Set<DexProgramClass> classesWithLinkingError =
            new HashSet<>(groupSplit.dependentsOfMainDexIndependents);
        classesWithLinkingError.addAll(classesMissingMainDex);
        assignClassesWithLinkingError(classesWithLinkingError, mainDexInpendentsDexes);
      }
    }

    // Allocate member of groups independents from the main dex members
    for (ClassGroup group : remainingInheritanceGroups) {
      if (!group.dependsOnMainDexClasses) {
        assignGroup(group, Collections.emptyList());
      }
    }
  }

  private static int getTotalClassNumber(List<ClassGroup> groups) {
    int groupClassNumber = 0;
    for (ClassGroup group : groups) {
      groupClassNumber += group.members.size();
    }
    return groupClassNumber;
  }

  private Collection<VirtualFile> assignGroup(ClassGroup group, List<VirtualFile> exclude) {
    VirtualFileCycler cycler = new VirtualFileCycler(dexes, appView, namingLens, dexIndexOffset);
    if (group.members.isEmpty()) {
      return Collections.emptyList();
    } else if (group.canFitInOneDex()) {
      VirtualFile currentDex;
      while (true) {
        currentDex = cycler.nextOrCreate(dex -> !exclude.contains(dex) && !isDexFull(dex));
        if (assignAll(currentDex, group.members)) {
          break;
        }
      }
      return Collections.singletonList(currentDex);
    } else {
      // put as much as possible of the group in an empty dex.
      // About the existing dexes: only case when there can be an empty one is when this.dexes
      // contains only one empty dex created as initial dex of a minimal main dex run. So no need to
      // run through all the existing dexes to find for a possible empty candidate, if the next one
      // is not empty, no other existing dex is. This means the exclude check is redundant but
      // its cost is negligible so no need to go wild on optimization and let's be safe.
      VirtualFile dexForLinkingClasses =
          cycler.nextOrCreate(dex -> dex.isEmpty() && !exclude.contains(dex) && !isDexFull(dex));
      Set<DexProgramClass> remaining = assignFromRoot(dexForLinkingClasses, group.members);

      // Assign remainingclasses so that they are never in the same dex as their subclasses.
      // They will fail to link during DexOpt but they will be loaded only once.
      // For now use a "leaf layer by dex" algorithm to ensure the constrainst.
      Collection<VirtualFile> newExclude = new HashSet<>(exclude);
      newExclude.add(dexForLinkingClasses);

      Collection<VirtualFile> usedDex = assignClassesWithLinkingError(remaining, newExclude);
      usedDex.add(dexForLinkingClasses);
      return usedDex;
    }
  }

  /**
   * Assign classes so that they are never in the same dex as their subclasses. They will fail to
   * link during DexOpt but they will be loaded only once.
   *
   * @param classes set of classes to assign, the set will be destroyed during assignment.
   */
  private Collection<VirtualFile> assignClassesWithLinkingError(
      Set<DexProgramClass> classes, Collection<VirtualFile> exclude) {

    List<ClassGroup> layers = collectNoDirectInheritanceGroups(classes);

    Collections.sort(layers);

    Collection<VirtualFile> usedDex = new ArrayList<>();
    VirtualFileCycler cycler = new VirtualFileCycler(dexes, appView, namingLens, dexIndexOffset);
    // Don't modify exclude. Think about modifying the input collection considering this
    // is private API.
    Set<VirtualFile> currentExclude = new HashSet<>(exclude);
    // Don't put class expected to fail linking in the main dex, save main dex space for classes
    // that may benefit to be in the main dex.
    currentExclude.add(mainDex);

    for (ClassGroup group : layers) {
      cycler.reset();
      VirtualFile dexForLayer =
          cycler.nextOrCreate(dex -> !currentExclude.contains(dex) && !isDexFull(dex));
      currentExclude.add(dexForLayer);
      usedDex.add(dexForLayer);
      for (DexProgramClass dexProgramClass : getSortedCopy(group.members)) {
        while (true) {
          dexForLayer.addClass(dexProgramClass);
          if (dexForLayer.isFull()) {
            dexForLayer.abortTransaction();
            if (dexForLayer.isEmpty()) {
              // The class is too big to fit in one dex
              throw new CompilationError("Class '" + dexProgramClass.toSourceString()
                  + "' from " + dexProgramClass.getOrigin().toString()
                  + " is too big to fit in a dex.");
            }
            if (dexForLayer.isFull(DEX_FULL_ENOUGH_THRESHOLD)) {
              markDexFull(dexForLayer);
            }
            // Current dex is too full, continue to next dex.
            dexForLayer =
                cycler.nextOrCreate(dex -> !currentExclude.contains(dex) && !isDexFull(dex));
            currentExclude.add(dexForLayer);
            usedDex.add(dexForLayer);
          } else {
            dexForLayer.commitTransaction();
            break;
          }

        }
      }

    }

    return usedDex;
  }

  /**
   * Distribute given classes in groups where each group never contains 2 classes with a direct
   * inheritance relation. For example:<br>
   * I3 --> I1<br>
   * I4 --> I2<br>
   * I5 --> I1, I2<br>
   * One valid result can be {I3, I4, I5} and {I1,I2}. This method attempts to return a small number
   * of groups but does not guaranty to produce the minimal possible solution.
   */
  private List<ClassGroup> collectNoDirectInheritanceGroups(Set<DexProgramClass> classes) {

    int totalClassNumber = classes.size();
    List<DexProgramClass> sortedClasses = getTopologicalOrder(classes);
    assert sortedClasses.size() == totalClassNumber;
    // make a graph colorization starting by the end of the topological order (leafs)
    ArrayList<ClassGroup> layers = new ArrayList<>();
    Map<DexProgramClass, Integer> assignedLayer = Maps.newHashMapWithExpectedSize(classes.size());
    for (int i = sortedClasses.size() - 1; i >= 0; i--) {
      DexProgramClass toAssign = sortedClasses.get(i);

      Collection<DexProgramClass> subClasses = directSubClasses.getDirectSubClasses(toAssign);
      BitSet used = new BitSet();
      for (DexProgramClass subclass : subClasses) {
        used.set(assignedLayer.get(subclass).intValue());
      }

      // Assign the lowest available color (layer)
      int layer = used.nextClearBit(0);
      assignedLayer.put(toAssign, Integer.valueOf(layer));
      if (layers.size() == layer) {
        layers.add(new ClassGroup());
      }
      layers.get(layer).members.add(toAssign);
    }

    updateGroupsNumberOfIds(layers);

    assert totalClassNumber == getTotalClassNumber(layers);

    return layers;
  }

  /**
   * Collect groups of classes with an inheritance relation. This relation can be indirect:<br>
   * I3 --> I1<br>
   * I4 --> I2<br>
   * I5 --> I1, I2<br>
   * I3 and I4 will be in the same group even if they have no relation with each other.
   */
  private List<ClassGroup> collectInheritanceGroups() {
    // Considering classes are the nodes of a graph which edges are the inheritance relation between
    // classes. We just want to isolate every connected sub-graphs.
    // To do that we just pick one node, walk through the connected sub-graph, then repeat until we
    // have collected all nodes.

    Collection<DexProgramClass> remainingClasses = new HashSet<>(classes);
    List<ClassGroup> groups = new LinkedList<>();
    while (!remainingClasses.isEmpty()) {
      DexProgramClass clazz = remainingClasses.iterator().next();
      ClassGroup group = new ClassGroup();
      groups.add(group);
      collectGroup(remainingClasses, group, clazz);
      assert !group.members.isEmpty();
    }

    updateGroupsNumberOfIds(groups);
    assert classes.size() == getTotalClassNumber(groups);
    return groups;
  }

  private void updateGroupsNumberOfIds(List<ClassGroup> groups) {
    Collection<Future<?>> updateIdsTasks = new ArrayList<>(groups.size());
    for (ClassGroup group : groups) {
      updateIdsTasks.add(executorService.submit(group::updateNumbersOfIds));
    }
    try {
      ThreadUtils.awaitFutures(updateIdsTasks);
    } catch (ExecutionException e) {
      Throwable cause = e.getCause();
      if (cause instanceof RuntimeException) {
        throw (RuntimeException) cause;
      } else if (cause instanceof Error) {
        throw (Error) cause;
      } else {
        // no checked exception thrown in task.
        throw new AssertionError(e);
      }
    }
  }

  private void collectGroup(Collection<DexProgramClass> classes, ClassGroup group,
      DexProgramClass clazz) {
    if (clazz == null) {
      return;
    }
    if (!classes.remove(clazz)) {
      if (!group.dependsOnMainDexClasses) {
        group.dependsOnMainDexClasses = mainDex.classes().contains(clazz);
      }
      // If the class is not in the classes list it's either that it's a non program class, part of
      // the main dex or it was already added to this group: so either we're not interested in the
      // class or it's dependencies and dependants are already being taken care of.
      return;
    }

    group.members.add(clazz);

    // Check dependencies are added to the group.
    collectGroup(classes, group, appView.programDefinitionFor(clazz.superType, clazz));
    for (DexType interfaze : clazz.interfaces.values) {
      collectGroup(classes, group, appView.programDefinitionFor(interfaze, clazz));
    }

    // Check that dependants are added to the group.
    for (DexProgramClass directSubClass : directSubClasses.getDirectSubClasses(clazz)) {
      collectGroup(classes, group, directSubClass);
    }
  }

  /**
   * Assign all given classes or none.
   * @return true if it managed to assign all the classes, false otherwise.
   */
  private boolean assignAll(VirtualFile dex, Collection<DexProgramClass> classes) {
    int totalClasses = classes.size();
    int assignedClasses = 0;
    int dexInitialSize = dex.classes().size();
    for (DexProgramClass clazz : classes) {
      dex.addClass(clazz);
      assignedClasses++;
      if (dex.isFull()) {
        dex.abortTransaction();
        if (dex.isFull(DEX_FULL_ENOUGH_THRESHOLD)) {
          markDexFull(dex);
        }
        assert dexInitialSize == dex.classes().size();
        return false;
      }
    }
    dex.commitTransaction();
    assert totalClasses == assignedClasses
      && dexInitialSize + assignedClasses == dex.classes().size();
    return true;
  }

  /**
   * Assign as many classes as possible by layer starting by roots.
   * @return the list of classes that were not assigned.
   */
  private Set<DexProgramClass> assignFromRoot(
      VirtualFile dex, Collection<DexProgramClass> classes) {

    int totalClasses = classes.size();
    int assignedClasses = 0;
    int dexInitialSize = dex.classes().size();
    boolean isLayerFullyAssigned = true;
    Set<DexProgramClass> remaining = new HashSet<>(classes);
    while (isLayerFullyAssigned && !remaining.isEmpty()) {
      Set<DexProgramClass> toProcess = remaining;
      remaining = new HashSet<>();
      boolean currentDexIsTooFull = false;
      for (DexProgramClass clazz : getSortedCopy(toProcess)) {
        if (currentDexIsTooFull || hasDirectInheritanceInCollection(clazz, toProcess)) {
          remaining.add(clazz);
        } else {
          dex.addClass(clazz);
          if (dex.isFull()) {
            dex.abortTransaction();
            if (dex.isEmpty()) {
              // The class is too big to fit in one dex
              throw new CompilationError("Class '" + clazz.toSourceString() + "' from "
                  + clazz.getOrigin().toString() + " is too big to fit in a dex.");
            }
            isLayerFullyAssigned = false;
            remaining.add(clazz);
            if (dex.isFull(DEX_FULL_ENOUGH_THRESHOLD)) {
              markDexFull(dex);
              currentDexIsTooFull = true;
            }
          } else {
            assignedClasses++;
            dex.commitTransaction();
          }
        }
      }
    }
    assert totalClasses == assignedClasses + remaining.size()
        && dexInitialSize + assignedClasses == dex.classes().size();
    return remaining;
  }

  private boolean hasDirectInheritanceInCollection(DexProgramClass clazz,
      Set<DexProgramClass> collection) {
    if (collection.contains(appView.programDefinitionFor(clazz.superType, clazz))) {
      return true;
    }
    for (DexType interfaze : clazz.interfaces.values) {
      if (collection.contains(appView.programDefinitionFor(interfaze, clazz))) {
        return true;
      }
    }
    return false;
  }

  private boolean hasDirectSubclassInCollection(DexProgramClass clazz,
      Set<DexProgramClass> collection) {
    for (DexProgramClass subClass : directSubClasses.getDirectSubClasses(clazz)) {
      if (collection.contains(subClass)) {
        return true;
      }
    }
    return false;
  }

  private static List<DexProgramClass> getSortedCopy(Collection<DexProgramClass> collection) {
    List<DexProgramClass> sorted = new ArrayList<>(collection);
    Collections.sort(sorted, DEX_PROGRAM_CLASS_COMPARATOR);
    return sorted;
  }

  /**
   * @param classes set of classes to sort, the set will be destroyed by sorting.
   */
  private List<DexProgramClass> getTopologicalOrder(Set<DexProgramClass> classes) {
    List<DexProgramClass> result = new ArrayList<>();
    while (!classes.isEmpty()) {
      DexProgramClass root = findOneRootInSetFrom(classes.iterator().next(), classes);
      classes.remove(root);
      result.add(root);
    }
    return result;
  }

  private DexProgramClass findOneRootInSetFrom(DexProgramClass searchFrom,
      Set<DexProgramClass> classSet) {
    DexProgramClass zuper = appView.programDefinitionFor(searchFrom.superType, searchFrom);
    if (classSet.contains(zuper)) {
      return findOneRootInSetFrom(zuper, classSet);
    }
    for (DexType interfaceType : searchFrom.interfaces.values) {
      DexClass interfaceClass = appView.definitionFor(interfaceType);
      if (interfaceClass.isProgramClass() && classSet.contains(interfaceClass.asProgramClass())) {
        return findOneRootInSetFrom((DexProgramClass) interfaceClass, classSet);
      }
    }
    return searchFrom;
  }

  private void markDexFull(VirtualFile dex) {
    fullDex.set(dex.getId());
  }

  private boolean isDexFull(VirtualFile dex) {
    return fullDex.get(dex.getId());
  }
}
