Fix non determinism of D8 with synthetics

Before we would be generating different hashes for the synthetic methods.

Bug: b/359616078
Change-Id: I0cc31845cf773cdd475810160bcfda1b621a28f1
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java
index 068a1a7..6f20ec4 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java
@@ -25,6 +25,8 @@
 import com.android.tools.r8.graph.RecordComponentInfo;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
+import com.android.tools.r8.utils.structural.HasherWrapper;
+import com.android.tools.r8.utils.structural.StructuralItem;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -185,11 +187,6 @@
         directMethods.add(method);
       }
     }
-    long checksum =
-        7 * (long) directMethods.hashCode()
-            + 11 * (long) virtualMethods.hashCode()
-            + 13 * (long) staticFields.hashCode()
-            + 17 * (long) instanceFields.hashCode();
     C clazz =
         getClassKind()
             .create(
@@ -213,7 +210,7 @@
                 DexEncodedMethod.EMPTY_ARRAY,
                 DexEncodedMethod.EMPTY_ARRAY,
                 factory.getSkipNameValidationForTesting(),
-                c -> checksum,
+                c -> getChecksum(),
                 null);
     if (useSortedMethodBacking) {
       clazz.getMethodCollection().useSortedBacking();
@@ -222,4 +219,17 @@
     clazz.setVirtualMethods(virtualMethods.toArray(DexEncodedMethod.EMPTY_ARRAY));
     return clazz;
   }
+
+  private long getChecksum() {
+    return 7 * hashEntries(virtualMethods, directMethods)
+        + 13 * hashEntries(instanceFields, staticFields);
+  }
+
+  private <S extends StructuralItem<S>> long hashEntries(List<S>... entryLists) {
+    HasherWrapper hasherWrapper = HasherWrapper.murmur3128Hasher();
+    for (List<S> entryList : entryLists) {
+      entryList.stream().sorted().forEach(e -> e.hash(hasherWrapper));
+    }
+    return hasherWrapper.hash().hashCode();
+  }
 }