Fix recording of synthetic $r8$classId field accesses

Change-Id: I2df11ba6e6c784b457fa337b5c2eb092d31b9556
diff --git a/src/main/java/com/android/tools/r8/graph/Code.java b/src/main/java/com/android/tools/r8/graph/Code.java
index 535c08f..b0d84f9 100644
--- a/src/main/java/com/android/tools/r8/graph/Code.java
+++ b/src/main/java/com/android/tools/r8/graph/Code.java
@@ -57,10 +57,15 @@
     return false;
   }
 
+  public boolean isHorizontalClassMergingCode() {
+    return false;
+  }
+
   public boolean isOutlineCode() {
     return false;
   }
 
+
   /** Estimate the number of IR instructions emitted by buildIR(). */
   public int estimatedSizeForInlining() {
     return Integer.MAX_VALUE;
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index 1547891..2a6ebf5 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -185,6 +185,16 @@
         predicate, method -> consumer.accept(new ProgramMethod(this, method)));
   }
 
+  public void forEachProgramInstanceInitializer(Consumer<ProgramMethod> consumer) {
+    forEachProgramInstanceInitializerMatching(alwaysTrue(), consumer);
+  }
+
+  public void forEachProgramInstanceInitializerMatching(
+      Predicate<DexEncodedMethod> predicate, Consumer<ProgramMethod> consumer) {
+    forEachProgramDirectMethodMatching(
+        method -> method.isInstanceInitializer() && predicate.test(method), consumer);
+  }
+
   public void forEachProgramVirtualMethod(Consumer<ProgramMethod> consumer) {
     forEachProgramVirtualMethodMatching(alwaysTrue(), consumer);
   }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
index b48d8ce..0a6a9b9 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
@@ -27,7 +27,6 @@
 import com.android.tools.r8.graph.ParameterAnnotationsList;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.shaking.FieldAccessInfoCollectionModifier;
 import com.android.tools.r8.utils.IterableUtils;
 import com.android.tools.r8.utils.MethodSignatureEquivalence;
 import com.google.common.base.Equivalence.Wrapper;
@@ -59,7 +58,6 @@
   private final ClassInitializerSynthesizedCode classInitializerSynthesizedCode;
   private final HorizontalClassMergerGraphLens.Builder lensBuilder;
   private final HorizontallyMergedClasses.Builder mergedClassesBuilder;
-  private final FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder;
 
   private final ClassMethodsBuilder classMethodsBuilder = new ClassMethodsBuilder();
   private final Reference2IntMap<DexType> classIdentifiers = new Reference2IntOpenHashMap<>();
@@ -72,7 +70,6 @@
       AppView<AppInfoWithLiveness> appView,
       HorizontalClassMergerGraphLens.Builder lensBuilder,
       HorizontallyMergedClasses.Builder mergedClassesBuilder,
-      FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder,
       MergeGroup group,
       Collection<VirtualMethodMerger> virtualMethodMergers,
       Collection<ConstructorMerger> constructorMergers,
@@ -80,7 +77,6 @@
     this.appView = appView;
     this.lensBuilder = lensBuilder;
     this.mergedClassesBuilder = mergedClassesBuilder;
-    this.fieldAccessChangesBuilder = fieldAccessChangesBuilder;
     this.group = group;
     this.virtualMethodMergers = virtualMethodMergers;
     this.constructorMergers = constructorMergers;
@@ -187,16 +183,13 @@
             merger.merge(
                 classMethodsBuilder,
                 lensBuilder,
-                fieldAccessChangesBuilder,
                 classIdentifiers,
                 syntheticArgumentClass));
   }
 
   void mergeVirtualMethods() {
     virtualMethodMergers.forEach(
-        merger ->
-            merger.merge(
-                classMethodsBuilder, lensBuilder, fieldAccessChangesBuilder, classIdentifiers));
+        merger -> merger.merge(classMethodsBuilder, lensBuilder, classIdentifiers));
     group.forEachSource(clazz -> clazz.getMethodCollection().clearVirtualMethods());
   }
 
@@ -329,8 +322,7 @@
 
     public ClassMerger build(
         HorizontallyMergedClasses.Builder mergedClassesBuilder,
-        HorizontalClassMergerGraphLens.Builder lensBuilder,
-        FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder) {
+        HorizontalClassMergerGraphLens.Builder lensBuilder) {
       setup();
       List<VirtualMethodMerger> virtualMethodMergers =
           new ArrayList<>(virtualMethodMergerBuilders.size());
@@ -356,7 +348,6 @@
           appView,
           lensBuilder,
           mergedClassesBuilder,
-          fieldAccessChangesBuilder,
           group,
           virtualMethodMergers,
           constructorMergers,
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorEntryPointSynthesizedCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorEntryPointSynthesizedCode.java
index 7d250bb..bbce62b 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorEntryPointSynthesizedCode.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorEntryPointSynthesizedCode.java
@@ -45,4 +45,9 @@
       registry.registerInvokeDirect(typeConstructor);
     }
   }
+
+  @Override
+  public boolean isHorizontalClassMergingCode() {
+    return true;
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorMerger.java
index 01d5771..b4e9887 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorMerger.java
@@ -21,7 +21,6 @@
 import com.android.tools.r8.ir.conversion.ExtraParameter;
 import com.android.tools.r8.ir.conversion.ExtraUnusedNullParameter;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.shaking.FieldAccessInfoCollectionModifier;
 import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.structural.Ordered;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceAVLTreeMap;
@@ -139,7 +138,6 @@
   void merge(
       ClassMethodsBuilder classMethodsBuilder,
       HorizontalClassMergerGraphLens.Builder lensBuilder,
-      FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder,
       Reference2IntMap<DexType> classIdentifiers,
       SyntheticArgumentClass syntheticArgumentClass) {
     // Tree map as must be sorted.
@@ -216,8 +214,5 @@
     lensBuilder.recordNewMethodSignature(bridgeConstructorReference, newConstructorReference);
 
     classMethodsBuilder.addDirectMethod(newConstructor);
-
-    fieldAccessChangesBuilder.fieldWrittenByMethod(
-        group.getClassIdField(), newConstructorReference);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
index 09b975b..fd9fa86 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
@@ -80,15 +80,12 @@
         new HorizontallyMergedClasses.Builder();
     HorizontalClassMergerGraphLens.Builder lensBuilder =
         new HorizontalClassMergerGraphLens.Builder();
-    FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder =
-        new FieldAccessInfoCollectionModifier.Builder();
     MainDexTracingResult.Builder mainDexTracingResultBuilder =
         mainDexTracingResult.extensionBuilder(appView.appInfo());
 
     // Set up a class merger for each group.
     List<ClassMerger> classMergers =
-        initializeClassMergers(
-            mergedClassesBuilder, lensBuilder, fieldAccessChangesBuilder, groups);
+        initializeClassMergers(mergedClassesBuilder, lensBuilder, groups);
     Iterable<DexProgramClass> allMergeClasses =
         Iterables.concat(
             Iterables.transform(classMergers, classMerger -> classMerger.getGroup().getClasses()));
@@ -104,14 +101,30 @@
     HorizontallyMergedClasses mergedClasses = mergedClassesBuilder.build();
     appView.setHorizontallyMergedClasses(mergedClasses);
     HorizontalClassMergerGraphLens lens =
-        createLens(mergedClasses, lensBuilder, fieldAccessChangesBuilder, syntheticArgumentClass);
+        createLens(mergedClasses, lensBuilder, syntheticArgumentClass);
 
     // Prune keep info.
     KeepInfoCollection keepInfo = appView.appInfo().getKeepInfo();
     keepInfo.mutate(mutator -> mutator.removeKeepInfoForPrunedItems(mergedClasses.getSources()));
 
     return new HorizontalClassMergerResult(
-        fieldAccessChangesBuilder.build(), lens, mainDexTracingResultBuilder.build());
+        createFieldAccessInfoCollectionModifier(groups), lens, mainDexTracingResultBuilder.build());
+  }
+
+  private FieldAccessInfoCollectionModifier createFieldAccessInfoCollectionModifier(
+      Collection<MergeGroup> groups) {
+    FieldAccessInfoCollectionModifier.Builder builder =
+        new FieldAccessInfoCollectionModifier.Builder();
+    for (MergeGroup group : groups) {
+      DexProgramClass target = group.getTarget();
+      target.forEachProgramInstanceInitializerMatching(
+          definition -> definition.getCode().isHorizontalClassMergingCode(),
+          method -> builder.recordFieldWrittenInContext(group.getClassIdField(), method));
+      target.forEachProgramVirtualMethodMatching(
+          definition -> definition.getCode().isHorizontalClassMergingCode(),
+          method -> builder.recordFieldReadInContext(group.getClassIdField(), method));
+    }
+    return builder.build();
   }
 
   private List<Policy> getPolicies(
@@ -157,7 +170,6 @@
   private List<ClassMerger> initializeClassMergers(
       HorizontallyMergedClasses.Builder mergedClassesBuilder,
       HorizontalClassMergerGraphLens.Builder lensBuilder,
-      FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder,
       Collection<MergeGroup> groups) {
     List<ClassMerger> classMergers = new ArrayList<>();
 
@@ -165,8 +177,7 @@
     for (MergeGroup group : groups) {
       assert !group.isEmpty();
       ClassMerger merger =
-          new ClassMerger.Builder(appView, group)
-              .build(mergedClassesBuilder, lensBuilder, fieldAccessChangesBuilder);
+          new ClassMerger.Builder(appView, group).build(mergedClassesBuilder, lensBuilder);
       classMergers.add(merger);
     }
 
@@ -188,10 +199,8 @@
   private HorizontalClassMergerGraphLens createLens(
       HorizontallyMergedClasses mergedClasses,
       HorizontalClassMergerGraphLens.Builder lensBuilder,
-      FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder,
       SyntheticArgumentClass syntheticArgumentClass) {
-    return new TreeFixer(
-            appView, mergedClasses, lensBuilder, fieldAccessChangesBuilder, syntheticArgumentClass)
+    return new TreeFixer(appView, mergedClasses, lensBuilder, syntheticArgumentClass)
         .fixupTypeReferences();
   }
 }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java
index 551d229..c66d5de 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java
@@ -20,7 +20,6 @@
 import com.android.tools.r8.ir.conversion.ExtraUnusedNullParameter;
 import com.android.tools.r8.shaking.AnnotationFixer;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.shaking.FieldAccessInfoCollectionModifier;
 import com.android.tools.r8.utils.OptionalBool;
 import com.google.common.collect.BiMap;
 import com.google.common.collect.HashBiMap;
@@ -40,7 +39,6 @@
 class TreeFixer extends TreeFixerBase {
   private final HorizontallyMergedClasses mergedClasses;
   private final HorizontalClassMergerGraphLens.Builder lensBuilder;
-  private final FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder;
   private final AppView<AppInfoWithLiveness> appView;
   private final DexItemFactory dexItemFactory;
   private final SyntheticArgumentClass syntheticArgumentClass;
@@ -51,13 +49,11 @@
       AppView<AppInfoWithLiveness> appView,
       HorizontallyMergedClasses mergedClasses,
       HorizontalClassMergerGraphLens.Builder lensBuilder,
-      FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder,
       SyntheticArgumentClass syntheticArgumentClass) {
     super(appView);
     this.appView = appView;
     this.mergedClasses = mergedClasses;
     this.lensBuilder = lensBuilder;
-    this.fieldAccessChangesBuilder = fieldAccessChangesBuilder;
     this.syntheticArgumentClass = syntheticArgumentClass;
     this.dexItemFactory = appView.dexItemFactory();
   }
@@ -126,7 +122,6 @@
       subtypingForrest.traverseNodeDepthFirst(root, HashBiMap.create(), this::fixupProgramClass);
     }
     HorizontalClassMergerGraphLens lens = lensBuilder.build(appView, mergedClasses);
-    fieldAccessChangesBuilder.fixup(this::fixupMethodReference);
     new AnnotationFixer(lens).run(appView.appInfo().classes());
     return lens;
   }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodEntryPointSynthesizedCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodEntryPointSynthesizedCode.java
index 7428b92..a1aaa6b 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodEntryPointSynthesizedCode.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodEntryPointSynthesizedCode.java
@@ -38,4 +38,9 @@
       registry.registerInvokeDirect(mappedMethod);
     }
   }
+
+  @Override
+  public boolean isHorizontalClassMergingCode() {
+    return true;
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
index e4060fe..24a1b84 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
@@ -19,7 +19,6 @@
 import com.android.tools.r8.graph.ResolutionResult.SingleResolutionResult;
 import com.android.tools.r8.ir.synthetic.AbstractSynthesizedCode;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.shaking.FieldAccessInfoCollectionModifier;
 import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.OptionalBool;
 import com.android.tools.r8.utils.structural.Ordered;
@@ -200,7 +199,6 @@
   public void merge(
       ClassMethodsBuilder classMethodsBuilder,
       HorizontalClassMergerGraphLens.Builder lensBuilder,
-      FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder,
       Reference2IntMap<DexType> classIdentifiers) {
     assert !methods.isEmpty();
 
@@ -275,7 +273,5 @@
     lensBuilder.recordNewMethodSignature(bridgeMethodReference, newMethodReference);
 
     classMethodsBuilder.addVirtualMethod(newMethod);
-
-    fieldAccessChangesBuilder.fieldReadByMethod(group.getClassIdField(), newMethodReference);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/shaking/FieldAccessInfoCollectionModifier.java b/src/main/java/com/android/tools/r8/shaking/FieldAccessInfoCollectionModifier.java
index 591ef6d..f656a56 100644
--- a/src/main/java/com/android/tools/r8/shaking/FieldAccessInfoCollectionModifier.java
+++ b/src/main/java/com/android/tools/r8/shaking/FieldAccessInfoCollectionModifier.java
@@ -6,94 +6,57 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.FieldAccessInfoCollectionImpl;
 import com.android.tools.r8.graph.FieldAccessInfoImpl;
 import com.android.tools.r8.graph.ProgramMethod;
-import java.util.ArrayList;
-import java.util.Collection;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
 import java.util.IdentityHashMap;
-import java.util.List;
 import java.util.Map;
-import java.util.function.BiConsumer;
-import java.util.function.Function;
 
 public class FieldAccessInfoCollectionModifier {
 
   static class FieldReferences {
-    final List<DexMethod> writeContexts = new ArrayList<>();
-    final List<DexMethod> readContexts = new ArrayList<>();
-
-    void fixUpMethods(List<DexMethod> methods, Function<DexMethod, DexMethod> fixUpMethod) {
-      for (int i = 0; i < methods.size(); i++) {
-        DexMethod method = methods.get(i);
-        DexMethod newMethod = fixUpMethod.apply(method);
-        if (method != newMethod) {
-          methods.set(i, newMethod);
-        }
-      }
-    }
-
-    void fixup(Function<DexMethod, DexMethod> fixUpMethod) {
-      fixUpMethods(writeContexts, fixUpMethod);
-      fixUpMethods(readContexts, fixUpMethod);
-    }
+    private final ProgramMethodSet writeContexts = ProgramMethodSet.create();
+    private final ProgramMethodSet readContexts = ProgramMethodSet.create();
   }
 
-  final Map<DexField, FieldReferences> newFieldAccesses;
+  private final Map<DexField, FieldReferences> newFieldAccesses;
 
   FieldAccessInfoCollectionModifier(Map<DexField, FieldReferences> newFieldAccesses) {
     this.newFieldAccesses = newFieldAccesses;
   }
 
-  void forEachFieldAccess(
-      AppView<?> appView,
-      Collection<DexMethod> methods,
-      DexField field,
-      BiConsumer<DexField, ProgramMethod> record) {
-    for (DexMethod method : methods) {
-      ProgramMethod programMethod =
-          appView.definitionFor(method.holder).asProgramClass().lookupProgramMethod(method);
-      record.accept(field, programMethod);
-    }
-  }
-
   public void modify(AppView<AppInfoWithLiveness> appView) {
     FieldAccessInfoCollectionImpl impl = appView.appInfo().getMutableFieldAccessInfoCollection();
     newFieldAccesses.forEach(
         (field, info) -> {
           FieldAccessInfoImpl fieldAccessInfo = new FieldAccessInfoImpl(field);
-          forEachFieldAccess(appView, info.readContexts, field, fieldAccessInfo::recordRead);
-          forEachFieldAccess(appView, info.writeContexts, field, fieldAccessInfo::recordWrite);
+          info.readContexts.forEach(context -> fieldAccessInfo.recordRead(field, context));
+          info.writeContexts.forEach(context -> fieldAccessInfo.recordWrite(field, context));
           impl.extend(field, fieldAccessInfo);
         });
   }
 
   public static class Builder {
-    final Map<DexField, FieldReferences> newFieldAccesses = new IdentityHashMap<>();
+
+    private final Map<DexField, FieldReferences> newFieldAccesses = new IdentityHashMap<>();
 
     public Builder() {}
 
-    public void fixup(Function<DexMethod, DexMethod> fixupMethod) {
-      for (FieldReferences fieldReferences : newFieldAccesses.values()) {
-        fieldReferences.fixup(fixupMethod);
-      }
+    private FieldReferences getFieldReferences(DexField field) {
+      return newFieldAccesses.computeIfAbsent(field, ignore -> new FieldReferences());
+    }
+
+    public void recordFieldReadInContext(DexField field, ProgramMethod context) {
+      getFieldReferences(field).readContexts.add(context);
+    }
+
+    public void recordFieldWrittenInContext(DexField field, ProgramMethod context) {
+      getFieldReferences(field).writeContexts.add(context);
     }
 
     public FieldAccessInfoCollectionModifier build() {
       return new FieldAccessInfoCollectionModifier(newFieldAccesses);
     }
-
-    FieldReferences getFieldReferences(DexField field) {
-      return newFieldAccesses.computeIfAbsent(field, ignore -> new FieldReferences());
-    }
-
-    public void fieldReadByMethod(DexField field, DexMethod method) {
-      getFieldReferences(field).readContexts.add(method);
-    }
-
-    public void fieldWrittenByMethod(DexField field, DexMethod method) {
-      getFieldReferences(field).writeContexts.add(method);
-    }
   }
 }