Fix conversion to dex when instance initializers need lens rewriting

Bug: 230430794
Change-Id: I872b29b465eced07d6e5c772815279504aa20c08
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 6671b6a..3608975 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
@@ -127,7 +127,7 @@
             ? new SyntheticArgumentClass.Builder(appView.withLiveness()).build(groups)
             : null;
     SyntheticInitializerConverter.Builder syntheticInitializerConverterBuilder =
-        SyntheticInitializerConverter.builder(appView, codeProvider);
+        SyntheticInitializerConverter.builder(appView, codeProvider, mode);
     List<VirtuallyMergedMethodsKeepInfo> virtuallyMergedMethodsKeepInfos = new ArrayList<>();
     PrunedItems prunedItems =
         applyClassMergers(
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/SyntheticInitializerConverter.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/SyntheticInitializerConverter.java
index 7912f4c..a31760b 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/SyntheticInitializerConverter.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/SyntheticInitializerConverter.java
@@ -6,15 +6,19 @@
 
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.horizontalclassmerging.HorizontalClassMerger.Mode;
 import com.android.tools.r8.horizontalclassmerging.IRCodeProvider;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.conversion.IRConverter;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackIgnore;
 import com.android.tools.r8.utils.ThreadUtils;
 import com.android.tools.r8.utils.Timing;
+import com.google.common.collect.Sets;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 
@@ -26,22 +30,28 @@
 
   private final AppView<?> appView;
   private final IRCodeProvider codeProvider;
+  private final Mode mode;
+
   private final List<ProgramMethod> classInitializers;
-  private final List<ProgramMethod> instanceInitializers;
+
+  // Classes with one or more instance initializers that need to have their code processed into dex.
+  private final Set<DexProgramClass> instanceInitializers;
 
   private SyntheticInitializerConverter(
       AppView<?> appView,
       IRCodeProvider codeProvider,
+      Mode mode,
       List<ProgramMethod> classInitializers,
-      List<ProgramMethod> instanceInitializers) {
+      Set<DexProgramClass> instanceInitializers) {
     this.appView = appView;
     this.codeProvider = codeProvider;
+    this.mode = mode;
     this.classInitializers = classInitializers;
     this.instanceInitializers = instanceInitializers;
   }
 
-  public static Builder builder(AppView<?> appView, IRCodeProvider codeProvider) {
-    return new Builder(appView, codeProvider);
+  public static Builder builder(AppView<?> appView, IRCodeProvider codeProvider, Mode mode) {
+    return new Builder(appView, codeProvider, mode);
   }
 
   public void convertClassInitializers(ExecutorService executorService) throws ExecutionException {
@@ -57,10 +67,23 @@
     if (!instanceInitializers.isEmpty()) {
       IRConverter converter = new IRConverter(createAppViewForConversion(), Timing.empty());
       ThreadUtils.processItems(
-          instanceInitializers, method -> processMethod(method, converter), executorService);
+          instanceInitializers,
+          clazz -> processInstanceInitializers(clazz, converter),
+          executorService);
     }
   }
 
+  private void processInstanceInitializers(DexProgramClass clazz, IRConverter converter) {
+    assert appView.options().isGeneratingDex();
+    assert mode.isFinal();
+    clazz.forEachProgramInstanceInitializerMatching(
+        method -> !method.getCode().isDexCode(),
+        method -> {
+          processMethod(method, converter);
+          assert method.getDefinition().getCode().isDexCode();
+        });
+  }
+
   private AppView<AppInfo> createAppViewForConversion() {
     // At this point the code rewritings described by repackaging and synthetic finalization have
     // not been applied to the code objects. These code rewritings will be applied in the
@@ -88,12 +111,15 @@
 
     private final AppView<?> appView;
     private final IRCodeProvider codeProvider;
-    private final List<ProgramMethod> classInitializers = new ArrayList<>();
-    private final List<ProgramMethod> instanceInitializers = new ArrayList<>();
+    private final Mode mode;
 
-    private Builder(AppView<?> appView, IRCodeProvider codeProvider) {
+    private final List<ProgramMethod> classInitializers = new ArrayList<>();
+    private final Set<DexProgramClass> instanceInitializers = Sets.newIdentityHashSet();
+
+    private Builder(AppView<?> appView, IRCodeProvider codeProvider, Mode mode) {
       this.appView = appView;
       this.codeProvider = codeProvider;
+      this.mode = mode;
     }
 
     public Builder addClassInitializer(ProgramMethod method) {
@@ -102,13 +128,16 @@
     }
 
     public Builder addInstanceInitializer(ProgramMethod method) {
-      this.instanceInitializers.add(method);
+      // Record that the holder has an instance initializer that needs processing to dex. We avoid
+      // storing the collection of exact initializers that need processing, since that requires lens
+      // code rewriting after the fixup has been made.
+      this.instanceInitializers.add(method.getHolder());
       return this;
     }
 
     public SyntheticInitializerConverter build() {
       return new SyntheticInitializerConverter(
-          appView, codeProvider, classInitializers, instanceInitializers);
+          appView, codeProvider, mode, classInitializers, instanceInitializers);
     }
   }
 }