Merge "Make R8 processing deterministic"
diff --git a/src/main/java/com/android/tools/r8/graph/PresortedComparable.java b/src/main/java/com/android/tools/r8/graph/PresortedComparable.java
index 3caf8f2..eb130d6 100644
--- a/src/main/java/com/android/tools/r8/graph/PresortedComparable.java
+++ b/src/main/java/com/android/tools/r8/graph/PresortedComparable.java
@@ -13,4 +13,8 @@
   // Layered comparison methods that make use of indices for subpart comparisons. These rely
   // on subparts already being sorted and having indices assigned.
   int layeredCompareTo(T other, NamingLens namingLens);
+
+  static <T extends PresortedComparable<T>> int slowCompare(T a, T b) {
+    return a.slowCompareTo(b);
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index d25c4bc..c45a5c1 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -31,7 +31,9 @@
 import com.android.tools.r8.utils.MethodSignatureEquivalence;
 import com.android.tools.r8.utils.Timing;
 import com.google.common.base.Equivalence.Wrapper;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSortedSet;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Queues;
 import com.google.common.collect.Sets;
@@ -39,7 +41,6 @@
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.Deque;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -49,6 +50,7 @@
 import java.util.Map.Entry;
 import java.util.Queue;
 import java.util.Set;
+import java.util.SortedSet;
 import java.util.function.BiFunction;
 import java.util.function.Function;
 import java.util.stream.Collectors;
@@ -886,20 +888,24 @@
         .collect(Collectors.toCollection(Sets::newIdentityHashSet));
   }
 
-  Set<DexField> collectInstanceFieldsRead() {
-    return Collections.unmodifiableSet(collectFields(instanceFieldsRead));
+  SortedSet<DexField> collectInstanceFieldsRead() {
+    return ImmutableSortedSet.copyOf(
+        PresortedComparable::slowCompareTo, collectFields(instanceFieldsRead));
   }
 
-  Set<DexField> collectInstanceFieldsWritten() {
-    return Collections.unmodifiableSet(collectFields(instanceFieldsWritten));
+  SortedSet<DexField> collectInstanceFieldsWritten() {
+    return ImmutableSortedSet.copyOf(
+        PresortedComparable::slowCompareTo, collectFields(instanceFieldsWritten));
   }
 
-  Set<DexField> collectStaticFieldsRead() {
-    return Collections.unmodifiableSet(collectFields(staticFieldsRead));
+  SortedSet<DexField> collectStaticFieldsRead() {
+    return ImmutableSortedSet.copyOf(
+        PresortedComparable::slowCompareTo, collectFields(staticFieldsRead));
   }
 
-  Set<DexField> collectStaticFieldsWritten() {
-    return Collections.unmodifiableSet(collectFields(staticFieldsWritten));
+  SortedSet<DexField> collectStaticFieldsWritten() {
+    return ImmutableSortedSet.copyOf(
+        PresortedComparable::slowCompareTo, collectFields(staticFieldsWritten));
   }
 
   private Set<DexField> collectReachedFields(Map<DexType, Set<DexField>> map,
@@ -918,14 +924,16 @@
     return target == null ? field : target.field;
   }
 
-  Set<DexField> collectFieldsRead() {
-    return Sets.union(collectReachedFields(instanceFieldsRead, this::tryLookupInstanceField),
-        collectReachedFields(staticFieldsRead, this::tryLookupStaticField));
+  SortedSet<DexField> collectFieldsRead() {
+    return ImmutableSortedSet.copyOf(PresortedComparable::slowCompareTo,
+        Sets.union(collectReachedFields(instanceFieldsRead, this::tryLookupInstanceField),
+        collectReachedFields(staticFieldsRead, this::tryLookupStaticField)));
   }
 
-  Set<DexField> collectFieldsWritten() {
-    return Sets.union(collectReachedFields(instanceFieldsWritten, this::tryLookupInstanceField),
-        collectReachedFields(staticFieldsWritten, this::tryLookupStaticField));
+  SortedSet<DexField> collectFieldsWritten() {
+    return ImmutableSortedSet.copyOf(PresortedComparable::slowCompareTo,
+        Sets.union(collectReachedFields(instanceFieldsWritten, this::tryLookupInstanceField),
+        collectReachedFields(staticFieldsWritten, this::tryLookupStaticField)));
   }
 
   private static class Action {
@@ -1009,68 +1017,68 @@
      * Set of types that are mentioned in the program. We at least need an empty abstract classitem
      * for these.
      */
-    public final Set<DexType> liveTypes;
+    public final SortedSet<DexType> liveTypes;
     /**
      * Set of types that are actually instantiated. These cannot be abstract.
      */
-    final Set<DexType> instantiatedTypes;
+    final SortedSet<DexType> instantiatedTypes;
     /**
      * Set of methods that are the immediate target of an invoke. They might not actually be live
      * but are required so that invokes can find the method. If such a method is not live (i.e. not
      * contained in {@link #liveMethods}, it may be marked as abstract and its implementation may be
      * removed.
      */
-    final Set<DexMethod> targetedMethods;
+    final SortedSet<DexMethod> targetedMethods;
     /**
      * Set of methods that belong to live classes and can be reached by invokes. These need to be
      * kept.
      */
-    final Set<DexMethod> liveMethods;
+    final SortedSet<DexMethod> liveMethods;
     /**
      * Set of fields that belong to live classes and can be reached by invokes. These need to be
      * kept.
      */
-    public final Set<DexField> liveFields;
+    public final SortedSet<DexField> liveFields;
     /**
      * Set of all fields which may be touched by a get operation. This is actual field definitions.
      */
-    public final Set<DexField> fieldsRead;
+    public final SortedSet<DexField> fieldsRead;
     /**
      * Set of all fields which may be touched by a put operation. This is actual field definitions.
      */
-    public final Set<DexField> fieldsWritten;
+    public final SortedSet<DexField> fieldsWritten;
     /**
      * Set of all field ids used in instance field reads.
      */
-    public final Set<DexField> instanceFieldReads;
+    public final SortedSet<DexField> instanceFieldReads;
     /**
      * Set of all field ids used in instance field writes.
      */
-    public final Set<DexField> instanceFieldWrites;
+    public final SortedSet<DexField> instanceFieldWrites;
     /**
      * Set of all field ids used in static static field reads.
      */
-    public final Set<DexField> staticFieldReads;
+    public final SortedSet<DexField> staticFieldReads;
     /**
      * Set of all field ids used in static field writes.
      */
-    public final Set<DexField> staticFieldWrites;
+    public final SortedSet<DexField> staticFieldWrites;
     /**
      * Set of all methods referenced in virtual invokes;
      */
-    public final Set<DexMethod> virtualInvokes;
+    public final SortedSet<DexMethod> virtualInvokes;
     /**
      * Set of all methods referenced in super invokes;
      */
-    public final Set<DexMethod> superInvokes;
+    public final SortedSet<DexMethod> superInvokes;
     /**
      * Set of all methods referenced in direct invokes;
      */
-    public final Set<DexMethod> directInvokes;
+    public final SortedSet<DexMethod> directInvokes;
     /**
      * Set of all methods referenced in static invokes;
      */
-    public final Set<DexMethod> staticInvokes;
+    public final SortedSet<DexMethod> staticInvokes;
     /**
      * Set of all items that have to be kept independent of whether they are used.
      */
@@ -1090,8 +1098,10 @@
 
     private AppInfoWithLiveness(AppInfoWithSubtyping appInfo, Enqueuer enqueuer) {
       super(appInfo);
-      this.liveTypes = Collections.unmodifiableSet(enqueuer.liveTypes);
-      this.instantiatedTypes = enqueuer.instantiatedTypes.getItems();
+      this.liveTypes =
+          ImmutableSortedSet.copyOf(PresortedComparable::slowCompareTo, enqueuer.liveTypes);
+      this.instantiatedTypes = ImmutableSortedSet.copyOf(
+          PresortedComparable::slowCompareTo, enqueuer.instantiatedTypes.getItems());
       this.targetedMethods = toDescriptorSet(enqueuer.targetedMethods.getItems());
       this.liveMethods = toDescriptorSet(enqueuer.liveMethods.getItems());
       this.liveFields = toDescriptorSet(enqueuer.liveFields.getItems());
@@ -1101,7 +1111,7 @@
       this.staticFieldWrites = enqueuer.collectStaticFieldsWritten();
       this.fieldsRead = enqueuer.collectFieldsRead();
       this.fieldsWritten = enqueuer.collectFieldsWritten();
-      this.pinnedItems = Collections.unmodifiableSet(enqueuer.pinnedItems);
+      this.pinnedItems = ImmutableSet.copyOf(enqueuer.pinnedItems);
       this.virtualInvokes = joinInvokedMethods(enqueuer.virtualInvokes);
       this.superInvokes = joinInvokedMethods(enqueuer.superInvokes);
       this.directInvokes = joinInvokedMethods(enqueuer.directInvokes);
@@ -1165,24 +1175,27 @@
       assert Sets.intersection(instanceFieldWrites, staticFieldWrites).size() == 0;
     }
 
-    private Set<DexMethod> joinInvokedMethods(Map<DexType, Set<DexMethod>> invokes) {
-      ImmutableSet.Builder<DexMethod> builder = ImmutableSet.builder();
+    private SortedSet<DexMethod> joinInvokedMethods(Map<DexType, Set<DexMethod>> invokes) {
+      ImmutableSortedSet.Builder<DexMethod> builder =
+          new ImmutableSortedSet.Builder<>(PresortedComparable::slowCompare);
       invokes.values().forEach(builder::addAll);
       return builder.build();
     }
 
-    private <T extends PresortedComparable<T>> Set<T> toDescriptorSet(
+    private <T extends PresortedComparable<T>> SortedSet<T> toDescriptorSet(
         Set<? extends KeyedDexItem<T>> set) {
-      ImmutableSet.Builder<T> builder = ImmutableSet.builder();
+      ImmutableSortedSet.Builder<T> builder =
+          new ImmutableSortedSet.Builder<>(PresortedComparable::slowCompareTo);
       for (KeyedDexItem<T> item : set) {
         builder.add(item.getKey());
       }
       return builder.build();
     }
 
-    private static <T> ImmutableSet<T> rewriteItems(Set<T> original,
-        BiFunction<T, DexEncodedMethod, T> rewrite) {
-      ImmutableSet.Builder<T> builder = ImmutableSet.builder();
+    private static <T extends PresortedComparable<T>> ImmutableSortedSet<T> rewriteItems(
+        Set<T> original, BiFunction<T, DexEncodedMethod, T> rewrite) {
+      ImmutableSortedSet.Builder<T> builder =
+          new ImmutableSortedSet.Builder<>(PresortedComparable::slowCompare);
       for (T item : original) {
         builder.add(rewrite.apply(item, null));
       }
@@ -1245,11 +1258,11 @@
     }
 
     Set<T> getItems() {
-      return Collections.unmodifiableSet(items);
+      return ImmutableSet.copyOf(items);
     }
 
     Map<T, KeepReason> getReasons() {
-      return Collections.unmodifiableMap(reasons);
+      return ImmutableMap.copyOf(reasons);
     }
   }
 
diff --git a/src/test/java/com/android/tools/r8/internal/R8GMSCoreV10DeployJarVerificationTest.java b/src/test/java/com/android/tools/r8/internal/R8GMSCoreV10DeployJarVerificationTest.java
index dc2acae..ca713fd 100644
--- a/src/test/java/com/android/tools/r8/internal/R8GMSCoreV10DeployJarVerificationTest.java
+++ b/src/test/java/com/android/tools/r8/internal/R8GMSCoreV10DeployJarVerificationTest.java
@@ -22,14 +22,11 @@
     AndroidApp app1 = buildFromDeployJar(
         CompilerUnderTest.R8, CompilationMode.RELEASE,
         GMSCoreCompilationTestBase.GMSCORE_V10_DIR, false);
-    // TODO(sgjesse): Re-enable the deterministic test part when output is stable.
-    if (false) {
-      AndroidApp app2 = buildFromDeployJar(
-          CompilerUnderTest.R8, CompilationMode.RELEASE,
-          GMSCoreCompilationTestBase.GMSCORE_V10_DIR, false);
+    AndroidApp app2 = buildFromDeployJar(
+        CompilerUnderTest.R8, CompilationMode.RELEASE,
+        GMSCoreCompilationTestBase.GMSCORE_V10_DIR, false);
 
-      // Verify that the result of the two compilations was the same.
-      assertIdenticalApplications(app1, app2);
-    }
+    // Verify that the result of the two compilations was the same.
+    assertIdenticalApplications(app1, app2);
   }
 }