Merge "Revert "Revert "Canonicalize constants"""
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfo.java b/src/main/java/com/android/tools/r8/graph/AppInfo.java
index 9dcd701..612d280 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfo.java
@@ -54,6 +54,10 @@
return app.classes();
}
+ public Iterable<DexProgramClass> classesWithDeterministicOrder() {
+ return app.classesWithDeterministicOrder();
+ }
+
public DexClass definitionFor(DexType type) {
return app.definitionFor(type);
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexApplication.java b/src/main/java/com/android/tools/r8/graph/DexApplication.java
index 8b2fee9..20949c3 100644
--- a/src/main/java/com/android/tools/r8/graph/DexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DexApplication.java
@@ -77,6 +77,14 @@
return classes;
}
+ public Iterable<DexProgramClass> classesWithDeterministicOrder() {
+ programClasses.forceLoad(type -> true);
+ List<DexProgramClass> classes = programClasses.getAllClasses();
+ // To keep the order deterministic, we sort the classes by their type, which is a unique key.
+ classes.sort((a, b) -> a.type.slowCompareTo(b.type));
+ return classes;
+ }
+
public abstract DexClass definitionFor(DexType type);
public DexProgramClass programDefinitionFor(DexType type) {
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java
index 9983f29..6544ea9 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -14,6 +14,7 @@
import java.util.Arrays;
import java.util.Deque;
import java.util.Set;
+import java.util.TreeSet;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -30,6 +31,10 @@
public final DexString descriptor;
private String toStringCache = null;
private int hierarchyLevel = UNKNOWN_LEVEL;
+ /**
+ * Set of direct subtypes. This set has to remain sorted to ensure determinism. The actual sorting
+ * is not important but {@link #slowCompareTo(DexType)} works well.
+ */
private Set<DexType> directSubtypes = NO_DIRECT_SUBTYPE;
DexType(DexString descriptor) {
@@ -52,7 +57,7 @@
private void ensureDirectSubTypeSet() {
if (directSubtypes == NO_DIRECT_SUBTYPE) {
- directSubtypes = Sets.newIdentityHashSet();
+ directSubtypes = new TreeSet<>(DexType::slowCompareTo);
}
}
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
index 5a743b5..ff50c3e 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
@@ -80,7 +80,8 @@
}
Map<DexType, DexString> computeRenaming(Timing timing) {
- Iterable<DexProgramClass> classes = appInfo.classes();
+ // Use deterministic class order to make sure renaming is deterministic.
+ Iterable<DexProgramClass> classes = appInfo.classesWithDeterministicOrder();
// Collect names we have to keep.
timing.begin("reserve");
for (DexClass clazz : classes) {
diff --git a/src/test/java/com/android/tools/r8/internal/R8GMSCoreV10TreeShakeJarVerificationTest.java b/src/test/java/com/android/tools/r8/internal/R8GMSCoreV10TreeShakeJarVerificationTest.java
index 766de9d..ae470c6 100644
--- a/src/test/java/com/android/tools/r8/internal/R8GMSCoreV10TreeShakeJarVerificationTest.java
+++ b/src/test/java/com/android/tools/r8/internal/R8GMSCoreV10TreeShakeJarVerificationTest.java
@@ -5,7 +5,6 @@
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.InternalOptions;
import org.junit.Test;
public class R8GMSCoreV10TreeShakeJarVerificationTest
@@ -14,24 +13,10 @@
@Test
public void buildAndTreeShakeFromDeployJar() throws Exception {
// TODO(tamaskenez): set hasReference = true when we have the noshrink file for V10
- buildAndTreeShakeFromDeployJar(
- CompilationMode.RELEASE, GMSCORE_V10_DIR, false, GMSCORE_V10_MAX_SIZE, null);
- }
-
- private void configureDeterministic(InternalOptions options) {
- options.skipMinification = true;
- }
-
- @Test
- public void deterministic() throws Exception {
- // TODO(sgjesse): When minification is deterministic remove this test and make the one above
- // check for deterministic output.
AndroidApp app1 = buildAndTreeShakeFromDeployJar(
- CompilationMode.RELEASE, GMSCORE_V10_DIR, false, GMSCORE_V10_MAX_SIZE + 2000000,
- this::configureDeterministic);
+ CompilationMode.RELEASE, GMSCORE_V10_DIR, false, GMSCORE_V10_MAX_SIZE, null);
AndroidApp app2 = buildAndTreeShakeFromDeployJar(
- CompilationMode.RELEASE, GMSCORE_V10_DIR, false, GMSCORE_V10_MAX_SIZE + 2000000,
- this::configureDeterministic);
+ CompilationMode.RELEASE, GMSCORE_V10_DIR, false, GMSCORE_V10_MAX_SIZE, null);
// Verify that the result of the two compilations was the same.
assertIdenticalApplications(app1, app2);