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