Writing dex classdefs: sort classdefs to match the dx tool's ordering.
Bug:
Change-Id: I0bfb0ff1751ca0f44083225719ca2dcadf6fb080
diff --git a/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java b/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java
index c7fc65d..09d6696 100644
--- a/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java
+++ b/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java
@@ -5,14 +5,13 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.CompilationError;
-import com.google.common.collect.Sets;
+import it.unimi.dsi.fastutil.objects.Reference2IntArrayMap;
import it.unimi.dsi.fastutil.objects.Reference2IntLinkedOpenHashMap;
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
import java.util.Collection;
import java.util.Collections;
-import java.util.Comparator;
+import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@@ -91,14 +90,59 @@
return map;
}
+ /**
+ * Here, 'depth' of a program class is an integer one bigger then the maximum depth of its
+ * superclass and implemented interfaces. The depth of classes without any or without known
+ * superclasses and interfaces is 1.
+ */
+ private static class ProgramClassDepthsMemoized {
+ private final DexApplication application;
+ private final Reference2IntMap<DexProgramClass> depthOfClasses = new Reference2IntArrayMap<>();
+
+ ProgramClassDepthsMemoized(DexApplication application) {
+ this.application = application;
+ }
+
+ int getDepth(DexProgramClass programClass) {
+ return depthOfClasses.computeIfAbsent(
+ programClass,
+ programClassToCompute -> {
+ // Emulating the algorithm of com.android.dx.merge.SortableType.tryAssignDepth().
+ DexType superType = programClassToCompute.superType;
+ int maxDepth;
+ if (superType == null) {
+ maxDepth = 0;
+ } else {
+ maxDepth = 1;
+ DexProgramClass superClass = application.programDefinitionFor(superType);
+ if (superClass != null) {
+ maxDepth = getDepth(superClass);
+ }
+ }
+ for (DexType inf : programClassToCompute.interfaces.values) {
+ DexProgramClass infClass = application.programDefinitionFor(inf);
+ maxDepth = Math.max(maxDepth, infClass == null ? 1 : getDepth(infClass));
+ }
+ return maxDepth + 1;
+ });
+ }
+ }
+
private static DexProgramClass[] sortClasses(DexApplication application,
Collection<DexProgramClass> classes) {
- SortingProgramClassVisitor classVisitor = new SortingProgramClassVisitor(application, classes);
// Collect classes in subtyping order, based on a sorted list of classes to start with.
- classVisitor.run(
- classes.stream().sorted(Comparator.comparing(DexClass::getType))
- .collect(Collectors.toList()));
- return classVisitor.getSortedClasses();
+ ProgramClassDepthsMemoized classDepths = new ProgramClassDepthsMemoized(application);
+ List<DexProgramClass> sortedClasses =
+ classes
+ .stream()
+ .sorted(
+ (x, y) -> {
+ int dx = classDepths.getDepth(x);
+ int dy = classDepths.getDepth(y);
+ return dx != dy ? dx - dy : x.type.compareTo(y.type);
+ })
+ .collect(Collectors.toList());
+ return sortedClasses.toArray(new DexProgramClass[sortedClasses.size()]);
}
private static <T> Collection<T> keysOrEmpty(Map<T, ?> map) {
@@ -179,34 +223,4 @@
public int getOffsetFor(DexMethodHandle methodHandle) {
return getOffsetFor(methodHandle, methodHandles);
}
-
- private static class SortingProgramClassVisitor extends ProgramClassVisitor {
- private final Set<DexClass> classSet = Sets.newIdentityHashSet();
- private final DexProgramClass[] sortedClasses;
-
- private int index = 0;
-
- SortingProgramClassVisitor(DexApplication application,
- Collection<DexProgramClass> classes) {
- super(application);
- this.sortedClasses = new DexProgramClass[classes.size()];
- classSet.addAll(classes);
- }
-
- @Override
- public void visit(DexType type) {}
-
- @Override
- public void visit(DexClass clazz) {
- if (classSet.contains(clazz)) {
- assert index < sortedClasses.length;
- sortedClasses[index++] = (DexProgramClass) clazz;
- }
- }
-
- DexProgramClass[] getSortedClasses() {
- assert index == sortedClasses.length;
- return sortedClasses;
- }
- }
}