Add synthetic hashing to DEX instructions.

The more precise hashing avoids large groups of potential
equivalences and reduces the need for computing large
equivalence groups.

Bug: b/237413146
Change-Id: I46796a484de1e9bda7fb4b9c312b328a9b842fa9
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFillArrayDataPayload.java b/src/main/java/com/android/tools/r8/dex/code/DexFillArrayDataPayload.java
index 11b34be..67d796c 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFillArrayDataPayload.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFillArrayDataPayload.java
@@ -11,6 +11,7 @@
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 import java.util.Arrays;
@@ -71,6 +72,11 @@
   }
 
   @Override
+  final void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visit(this, DexFillArrayDataPayload::specify);
+  }
+
+  @Override
   public int hashCode() {
     int result = super.hashCode();
     result = 31 * result + element_width;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat10t.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat10t.java
index 5ccccb9..ba9065a 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat10t.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat10t.java
@@ -11,6 +11,7 @@
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 import java.nio.ShortBuffer;
 
 abstract class DexFormat10t extends DexBase1Format {
@@ -50,6 +51,11 @@
   }
 
   @Override
+  final void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visitInt(AA);
+  }
+
+  @Override
   public String toString(ClassNameMapper naming) {
     return formatString(formatRelativeOffset(AA));
   }
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat11n.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat11n.java
index 20bec92..fe02384 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat11n.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat11n.java
@@ -12,6 +12,7 @@
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
@@ -64,6 +65,11 @@
   }
 
   @Override
+  final void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visit(this, DexFormat11n::specify);
+  }
+
+  @Override
   public String toString(ClassNameMapper naming) {
     return formatString("v" + A + ", #" + B);
   }
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat11x.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat11x.java
index 46d615b..b07478c 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat11x.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat11x.java
@@ -12,6 +12,7 @@
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 import java.nio.ShortBuffer;
 
 abstract class DexFormat11x extends DexBase1Format {
@@ -50,6 +51,11 @@
   }
 
   @Override
+  final void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visitInt(AA);
+  }
+
+  @Override
   public String toString(ClassNameMapper naming) {
     return formatString("v" + AA);
   }
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat12x.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat12x.java
index 29c2224..633837d 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat12x.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat12x.java
@@ -12,6 +12,7 @@
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
@@ -58,6 +59,11 @@
   }
 
   @Override
+  final void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visit(this, DexFormat12x::specify);
+  }
+
+  @Override
   public String toString(ClassNameMapper naming) {
     return formatString("v" + A + ", v" + B);
   }
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat20t.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat20t.java
index c63962f..0c0e15e 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat20t.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat20t.java
@@ -11,6 +11,7 @@
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 import java.nio.ShortBuffer;
 
 abstract class DexFormat20t extends DexBase2Format {
@@ -50,6 +51,11 @@
   }
 
   @Override
+  final void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visitInt(AAAA);
+  }
+
+  @Override
   public String toString(ClassNameMapper naming) {
     return formatString("" + AAAA + " " + formatRelativeOffset(AAAA));
   }
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat21c.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat21c.java
index d942119..b47c6d7 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat21c.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat21c.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.graph.IndexedDexItem;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.util.function.BiPredicate;
 
@@ -42,6 +43,12 @@
         spec -> spec.withInt(i -> i.AA).withSpec(this::internalSubSpecify));
   }
 
+  @Override
+  final void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visitInt(AA);
+    visitor.visit(this, this::internalSubSpecify);
+  }
+
   abstract void internalSubSpecify(StructuralSpecification<DexFormat21c<T>, ?> spec);
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat21h.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat21h.java
index ae07163..246c6cc 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat21h.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat21h.java
@@ -11,6 +11,7 @@
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
@@ -59,6 +60,11 @@
   }
 
   @Override
+  final void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visit(this, DexFormat21h::specify);
+  }
+
+  @Override
   public void collectIndexedItems(
       AppView<?> appView,
       IndexedItemCollection indexedItems,
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat21s.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat21s.java
index 1194963..97e3529 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat21s.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat21s.java
@@ -13,6 +13,7 @@
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
@@ -61,6 +62,11 @@
   }
 
   @Override
+  final void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visit(this, DexFormat21s::specify);
+  }
+
+  @Override
   public String toString(ClassNameMapper naming) {
     return formatString("v" + AA + ", #" + BBBB);
   }
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat21t.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat21t.java
index 21061c3..1c80b33 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat21t.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat21t.java
@@ -15,6 +15,7 @@
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
@@ -62,6 +63,11 @@
     return visitor.visit(this, (DexFormat21t) other, DexFormat21t::specify);
   }
 
+  @Override
+  final void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visit(this, DexFormat21t::specify);
+  }
+
   public abstract Type getType();
 
   protected abstract ValueTypeConstraint getOperandTypeConstraint();
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat22b.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat22b.java
index 5f3213e..687d7e7 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat22b.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat22b.java
@@ -13,6 +13,7 @@
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
@@ -65,6 +66,11 @@
   }
 
   @Override
+  void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visit(this, DexFormat22b::specify);
+  }
+
+  @Override
   public String toString(ClassNameMapper naming) {
     return formatString("v" + AA + ", v" + BB + ", #" + CC);
   }
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat22c.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat22c.java
index d406aad..2e1246c 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat22c.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat22c.java
@@ -8,6 +8,7 @@
 import com.android.tools.r8.graph.IndexedDexItem;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.util.function.BiPredicate;
 
@@ -49,6 +50,13 @@
   }
 
   @Override
+  void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visit(
+        this,
+        (StructuralSpecification<DexFormat22c<? extends DexReference>, ?> spec) -> specify(spec));
+  }
+
+  @Override
   public String toString(ClassNameMapper naming) {
     return formatString(
         "v" + A + ", v" + B + ", " + (naming == null ? CCCC : naming.originalNameOf(CCCC)));
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat22s.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat22s.java
index 84921eb..e503467 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat22s.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat22s.java
@@ -13,6 +13,7 @@
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
@@ -65,6 +66,11 @@
   }
 
   @Override
+  final void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visit(this, DexFormat22s::specify);
+  }
+
+  @Override
   public String toString(ClassNameMapper naming) {
     return formatString("v" + A + ", v" + B + ", #" + CCCC);
   }
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat22t.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat22t.java
index 395ac6e..17695d7 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat22t.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat22t.java
@@ -15,6 +15,7 @@
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
@@ -66,6 +67,11 @@
     return visitor.visit(this, (DexFormat22t) other, DexFormat22t::specify);
   }
 
+  @Override
+  final void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visit(this, DexFormat22t::specify);
+  }
+
   public abstract Type getType();
 
   public abstract ValueTypeConstraint getOperandTypeConstraint();
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat22x.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat22x.java
index e7d6f0c..3c34540 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat22x.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat22x.java
@@ -12,6 +12,7 @@
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
@@ -60,6 +61,11 @@
   }
 
   @Override
+  final void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visit(this, DexFormat22x::specify);
+  }
+
+  @Override
   public String toString(ClassNameMapper naming) {
     return formatString("v" + AA + ", v" + (int) BBBB);
   }
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat23x.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat23x.java
index ee90cf8..df098d9 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat23x.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat23x.java
@@ -12,6 +12,7 @@
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
@@ -64,6 +65,11 @@
   }
 
   @Override
+  final void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visit(this, DexFormat23x::specify);
+  }
+
+  @Override
   public String toString(ClassNameMapper naming) {
     return formatString("v" + AA + ", v" + BB + ", v" + CC);
   }
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat30t.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat30t.java
index 878cc7b..aa744ad 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat30t.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat30t.java
@@ -11,6 +11,7 @@
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 import java.nio.ShortBuffer;
 
 abstract class DexFormat30t extends DexBase3Format {
@@ -49,6 +50,11 @@
   }
 
   @Override
+  final void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visitInt(AAAAAAAA);
+  }
+
+  @Override
   public String toString(ClassNameMapper naming) {
     return formatString(formatOffset(AAAAAAAA));
   }
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat31c.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat31c.java
index 82e033a..8023664 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat31c.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat31c.java
@@ -15,6 +15,7 @@
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 import java.util.function.BiPredicate;
@@ -63,6 +64,11 @@
   }
 
   @Override
+  final void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visit(this, DexFormat31c::specify);
+  }
+
+  @Override
   public String toString(ClassNameMapper naming) {
     return formatString(
         "v" + AA + ", " + (naming == null ? BBBBBBBB : naming.originalNameOf(BBBBBBBB)));
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat31i.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat31i.java
index 04e57f1..0795a92 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat31i.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat31i.java
@@ -12,6 +12,7 @@
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
@@ -59,6 +60,11 @@
   }
 
   @Override
+  void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visit(this, DexFormat31i::specify);
+  }
+
+  @Override
   public String toString(ClassNameMapper naming) {
     return formatString("v" + AA + ", #" + BBBBBBBB);
   }
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat31t.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat31t.java
index cc57a14..320514d 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat31t.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat31t.java
@@ -12,6 +12,7 @@
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
@@ -74,6 +75,11 @@
   }
 
   @Override
+  void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visit(this, DexFormat31t::specify);
+  }
+
+  @Override
   public String toString(ClassNameMapper naming) {
     return formatString("v" + AA + ", " + formatRelativeOffset(BBBBBBBB));
   }
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat32x.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat32x.java
index f9a7792..00cf1f4 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat32x.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat32x.java
@@ -13,6 +13,7 @@
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
@@ -62,6 +63,11 @@
   }
 
   @Override
+  final void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visit(this, DexFormat32x::specify);
+  }
+
+  @Override
   public String toString(ClassNameMapper naming) {
     return formatString("v" + AAAA + ", v" + BBBB);
   }
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat35c.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat35c.java
index 78a5323..6e40c73 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat35c.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat35c.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.graph.IndexedDexItem;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 import com.android.tools.r8.utils.structural.StructuralItem;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.util.function.BiPredicate;
@@ -75,6 +76,11 @@
     return visitor.visit(this, (DexFormat35c<T>) other, DexFormat35c::specify);
   }
 
+  @Override
+  void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visit(this, DexFormat35c::specify);
+  }
+
   private void appendRegisterArguments(StringBuilder builder, String separator) {
     builder.append("{ ");
     int[] values = new int[] {C, D, E, F, G};
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat3rc.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat3rc.java
index 01fff36b..b0c0204 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat3rc.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat3rc.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.graph.IndexedDexItem;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 import com.android.tools.r8.utils.structural.StructuralItem;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.util.function.BiPredicate;
@@ -54,6 +55,11 @@
     return visitor.visit(this, (DexFormat3rc<T>) other, DexFormat3rc::specify);
   }
 
+  @Override
+  final void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visit(this, DexFormat3rc::specify);
+  }
+
   private void appendRegisterRange(StringBuilder builder) {
     int firstRegister = CCCC;
     builder.append("{ ");
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat45cc.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat45cc.java
index bdc0a15..e658265 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat45cc.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat45cc.java
@@ -18,6 +18,7 @@
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
@@ -95,6 +96,11 @@
   }
 
   @Override
+  final void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visit(this, DexFormat45cc::specify);
+  }
+
+  @Override
   public void collectIndexedItems(
       AppView<?> appView,
       IndexedItemCollection indexedItems,
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat4rcc.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat4rcc.java
index a96b70b..ace2725 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat4rcc.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat4rcc.java
@@ -17,6 +17,7 @@
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 import java.util.function.BiPredicate;
@@ -81,6 +82,11 @@
   }
 
   @Override
+  final void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visit(this, DexFormat4rcc::specify);
+  }
+
+  @Override
   public String toString(ClassNameMapper naming) {
     StringBuilder builder = new StringBuilder();
     appendRegisterRange(builder);
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat51l.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat51l.java
index fa88721..30ddee5 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat51l.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat51l.java
@@ -12,6 +12,7 @@
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
@@ -59,6 +60,11 @@
   }
 
   @Override
+  final void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visit(this, DexFormat51l::specify);
+  }
+
+  @Override
   public String toString(ClassNameMapper naming) {
     return formatString("v" + AA + ", #" + BBBBBBBBBBBBBBBB);
   }
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexInitClass.java b/src/main/java/com/android/tools/r8/dex/code/DexInitClass.java
index b1e5025..c600656 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexInitClass.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInitClass.java
@@ -18,6 +18,7 @@
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
@@ -138,6 +139,11 @@
   }
 
   @Override
+  void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visit(this, DexInitClass::specify);
+  }
+
+  @Override
   public String toSmaliString(ClassNameMapper naming) {
     return formatSmaliString("v" + dest + ", " + clazz.toSmaliString());
   }
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexInstruction.java b/src/main/java/com/android/tools/r8/dex/code/DexInstruction.java
index 5efe526..d5f8183 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexInstruction.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInstruction.java
@@ -351,13 +351,13 @@
     return opcodeDiff != 0 ? opcodeDiff : internalAcceptCompareTo(other, visitor);
   }
 
+  abstract void internalAcceptHashing(HashingVisitor visitor);
+
   @Override
   public final void acceptHashing(HashingVisitor visitor) {
-    // Rather than traverse the full instruction, the compare ID will likely give a reasonable hash.
-    // TODO(b/158159959): This will likely lead to a lot of distinct synthetics hashing to the same
-    //  hash as many have the same instruction pattern such as an invoke of the impl method or a
-    //  field access.
     visitor.visitInt(getCompareToId());
+    visitor.visitInt(getOffset());
+    internalAcceptHashing(visitor);
   }
 
   public abstract String getName();
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexNop.java b/src/main/java/com/android/tools/r8/dex/code/DexNop.java
index f25e0ec..71cd7b5 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexNop.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexNop.java
@@ -5,6 +5,7 @@
 
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 
 public class DexNop extends DexFormat10x {
 
@@ -39,6 +40,12 @@
 
   // Notice that this must be overridden by the "Nop" subtypes!
   @Override
+  void internalAcceptHashing(HashingVisitor visitor) {
+    // Nothing to hash besides the compare-id.
+  }
+
+  // Notice that this must be overridden by the "Nop" subtypes!
+  @Override
   public int hashCode() {
     return NAME.hashCode() * 7;
   }
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexPackedSwitchPayload.java b/src/main/java/com/android/tools/r8/dex/code/DexPackedSwitchPayload.java
index 2b0a21f..d06f619 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexPackedSwitchPayload.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexPackedSwitchPayload.java
@@ -10,6 +10,7 @@
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 import java.util.Arrays;
@@ -67,6 +68,11 @@
   }
 
   @Override
+  final void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visit(this, DexPackedSwitchPayload::specify);
+  }
+
+  @Override
   public int hashCode() {
     int result = super.hashCode();
     result = 31 * result + size;
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexRecordFieldValues.java b/src/main/java/com/android/tools/r8/dex/code/DexRecordFieldValues.java
index 0c03729..955f67e 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexRecordFieldValues.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexRecordFieldValues.java
@@ -15,6 +15,7 @@
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import it.unimi.dsi.fastutil.ints.IntArrayList;
 import it.unimi.dsi.fastutil.ints.IntList;
@@ -74,10 +75,15 @@
   }
 
   @Override
-  int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
     return visitor.visit(this, (DexRecordFieldValues) other, DexRecordFieldValues::specify);
   }
 
+  @Override
+  final void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visit(this, DexRecordFieldValues::specify);
+  }
+
   private static void specify(StructuralSpecification<DexRecordFieldValues, ?> spec) {
     spec.withItemArray(i -> i.fields);
   }
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexReturnVoid.java b/src/main/java/com/android/tools/r8/dex/code/DexReturnVoid.java
index fae79fc..9195241 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexReturnVoid.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexReturnVoid.java
@@ -5,6 +5,7 @@
 
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 
 public class DexReturnVoid extends DexFormat10x {
 
@@ -39,6 +40,11 @@
   }
 
   @Override
+  final void internalAcceptHashing(HashingVisitor visitor) {
+    // Nothing to hash except the compare-id.
+  }
+
+  @Override
   public int hashCode() {
     return NAME.hashCode();
   }
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexSparseSwitchPayload.java b/src/main/java/com/android/tools/r8/dex/code/DexSparseSwitchPayload.java
index f9ed49e..97d369a 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexSparseSwitchPayload.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSparseSwitchPayload.java
@@ -10,6 +10,7 @@
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 import java.util.Arrays;
@@ -73,6 +74,11 @@
   }
 
   @Override
+  final void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visit(this, DexSparseSwitchPayload::specify);
+  }
+
+  @Override
   public int hashCode() {
     int result = super.hashCode();
     result = 31 * result + size;