Remove uses of force inlining in horizontal class merger

Change-Id: Ic803be517803ba0b573243ebbd2d068a950c2424
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/ClassMergerSharedData.java b/src/main/java/com/android/tools/r8/classmerging/ClassMergerSharedData.java
similarity index 87%
rename from src/main/java/com/android/tools/r8/verticalclassmerging/ClassMergerSharedData.java
rename to src/main/java/com/android/tools/r8/classmerging/ClassMergerSharedData.java
index 7bc0e12..1948ef7 100644
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/ClassMergerSharedData.java
+++ b/src/main/java/com/android/tools/r8/classmerging/ClassMergerSharedData.java
@@ -1,12 +1,11 @@
 // Copyright (c) 2024, the R8 project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.verticalclassmerging;
+package com.android.tools.r8.classmerging;
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.google.common.base.Suppliers;
 import com.google.common.collect.ImmutableList;
 import java.util.List;
@@ -17,7 +16,7 @@
   // The collection of types that should be used to generate fresh constructor signatures.
   private final List<Supplier<DexType>> extraUnusedArgumentTypes;
 
-  public ClassMergerSharedData(AppView<AppInfoWithLiveness> appView) {
+  public ClassMergerSharedData(AppView<?> appView) {
     DexItemFactory factory = appView.dexItemFactory();
     extraUnusedArgumentTypes =
         ImmutableList.<Supplier<DexType>>builder()
diff --git a/src/main/java/com/android/tools/r8/classmerging/ClassMergerTreeFixer.java b/src/main/java/com/android/tools/r8/classmerging/ClassMergerTreeFixer.java
index 198b611..fce660c 100644
--- a/src/main/java/com/android/tools/r8/classmerging/ClassMergerTreeFixer.java
+++ b/src/main/java/com/android/tools/r8/classmerging/ClassMergerTreeFixer.java
@@ -21,11 +21,9 @@
 import com.android.tools.r8.graph.classmerging.MergedClasses;
 import com.android.tools.r8.graph.fixup.TreeFixerBase;
 import com.android.tools.r8.horizontalclassmerging.SubtypingForrestForClasses;
-import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
 import com.android.tools.r8.shaking.AnnotationFixer;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.ArrayUtils;
-import com.android.tools.r8.utils.Box;
 import com.android.tools.r8.utils.OptionalBool;
 import com.android.tools.r8.utils.Timing;
 import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
@@ -50,8 +48,7 @@
 
   protected final LB lensBuilder;
   protected final MC mergedClasses;
-  private final ProfileCollectionAdditions profileCollectionAdditions;
-  private final SyntheticArgumentClass syntheticArgumentClass;
+  private final ClassMergerSharedData classMergerSharedData;
 
   private final Map<DexProgramClass, DexType> originalSuperTypes = new IdentityHashMap<>();
 
@@ -61,15 +58,13 @@
 
   public ClassMergerTreeFixer(
       AppView<?> appView,
+      ClassMergerSharedData classMergerSharedData,
       LB lensBuilder,
-      MC mergedClasses,
-      ProfileCollectionAdditions profileCollectionAdditions,
-      SyntheticArgumentClass syntheticArgumentClass) {
+      MC mergedClasses) {
     super(appView);
+    this.classMergerSharedData = classMergerSharedData;
     this.lensBuilder = lensBuilder;
     this.mergedClasses = mergedClasses;
-    this.profileCollectionAdditions = profileCollectionAdditions;
-    this.syntheticArgumentClass = syntheticArgumentClass;
   }
 
   public GL run(ExecutorService executorService, Timing timing) throws ExecutionException {
@@ -289,40 +284,18 @@
         if (keptSignatures.contains(newMethodReference)
             || newMethodSignatures.containsValue(newMethodReference.getSignature())) {
           // If the method collides with a direct method on the same class then rename it to a
-          // globally
-          // fresh name and record the signature.
+          // globally fresh name and record the signature.
           if (method.isInstanceInitializer()) {
-            // If the method is an instance initializer, then add extra nulls.
-            Box<Set<DexType>> usedSyntheticArgumentClasses = new Box<>();
+            // If the method is an instance initializer, then add extra unused arguments.
             newMethodReference =
                 dexItemFactory.createInstanceInitializerWithFreshProto(
                     newMethodReference,
-                    syntheticArgumentClass.getArgumentClasses(),
-                    tryMethod -> !newMethodSignatures.containsValue(tryMethod.getSignature()),
-                    usedSyntheticArgumentClasses::set);
+                    classMergerSharedData.getExtraUnusedArgumentTypes(),
+                    tryMethod -> !newMethodSignatures.containsValue(tryMethod.getSignature()));
             lensBuilder.addExtraParameters(
                 originalMethodReference,
                 newMethodReference,
                 computeExtraUnusedParameters(originalMethodReference, newMethodReference));
-
-            // Amend the art profile collection.
-            if (usedSyntheticArgumentClasses.isSet()) {
-              Set<DexMethod> previousMethodReferences =
-                  lensBuilder.getOriginalMethodReferences(originalMethodReference);
-              if (previousMethodReferences.isEmpty()) {
-                profileCollectionAdditions.applyIfContextIsInProfile(
-                    originalMethodReference,
-                    additionsBuilder ->
-                        usedSyntheticArgumentClasses.get().forEach(additionsBuilder::addRule));
-              } else {
-                for (DexMethod previousMethodReference : previousMethodReferences) {
-                  profileCollectionAdditions.applyIfContextIsInProfile(
-                      previousMethodReference,
-                      additionsBuilder ->
-                          usedSyntheticArgumentClasses.get().forEach(additionsBuilder::addRule));
-                }
-              }
-            }
           } else {
             newMethodReference =
                 dexItemFactory.createFreshMethodNameWithoutHolder(
diff --git a/src/main/java/com/android/tools/r8/classmerging/SyntheticArgumentClass.java b/src/main/java/com/android/tools/r8/classmerging/SyntheticArgumentClass.java
deleted file mode 100644
index 54cdd43..0000000
--- a/src/main/java/com/android/tools/r8/classmerging/SyntheticArgumentClass.java
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.classmerging;
-
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.horizontalclassmerging.HorizontalMergeGroup;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.synthesis.SyntheticItems.SyntheticKindSelector;
-import com.google.common.base.Suppliers;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.function.Supplier;
-
-/**
- * Lets assume we are merging a class A that looks like:
- *
- * <pre>
- *   class A {
- *     A() { ... }
- *     A(int) { ... }
- *   }
- * </pre>
- *
- * If {@code A::<init>()} is merged with other constructors, then we need to prevent a conflict with
- * {@code A::<init>(int)}. To do this we introduce a synthetic class so that the new signature for
- * the merged constructor is {@code A::<init>(SyntheticClass, int)}, as this is guaranteed to be
- * unique.
- *
- * <p>This class generates a synthetic class in the package of the first class to be merged.
- */
-public class SyntheticArgumentClass {
-
-  private final List<Supplier<DexType>> syntheticClassTypes;
-
-  private SyntheticArgumentClass(List<Supplier<DexType>> syntheticClassTypes) {
-    this.syntheticClassTypes = syntheticClassTypes;
-  }
-
-  public List<Supplier<DexType>> getArgumentClasses() {
-    return syntheticClassTypes;
-  }
-
-  public static class Builder {
-
-    private final AppView<AppInfoWithLiveness> appView;
-
-    public Builder(AppView<AppInfoWithLiveness> appView) {
-      this.appView = appView;
-    }
-
-    private DexProgramClass synthesizeClass(
-        DexProgramClass context, SyntheticKindSelector syntheticKindSelector) {
-      return appView
-          .getSyntheticItems()
-          .createFixedClass(syntheticKindSelector, context, appView, builder -> {});
-    }
-
-    public SyntheticArgumentClass build(Collection<HorizontalMergeGroup> mergeGroups) {
-      return build(getDeterministicContext(mergeGroups));
-    }
-
-    public SyntheticArgumentClass build(DexProgramClass deterministicContext) {
-      List<Supplier<DexType>> syntheticArgumentTypes = new ArrayList<>();
-      syntheticArgumentTypes.add(
-          Suppliers.memoize(
-              () ->
-                  synthesizeClass(
-                          deterministicContext, kinds -> kinds.HORIZONTAL_INIT_TYPE_ARGUMENT_1)
-                      .getType()));
-      syntheticArgumentTypes.add(
-          Suppliers.memoize(
-              () ->
-                  synthesizeClass(
-                          deterministicContext, kinds -> kinds.HORIZONTAL_INIT_TYPE_ARGUMENT_2)
-                      .getType()));
-      syntheticArgumentTypes.add(
-          Suppliers.memoize(
-              () ->
-                  synthesizeClass(
-                          deterministicContext, kinds -> kinds.HORIZONTAL_INIT_TYPE_ARGUMENT_3)
-                      .getType()));
-      return new SyntheticArgumentClass(syntheticArgumentTypes);
-    }
-
-    private static DexProgramClass getDeterministicContext(
-        Collection<HorizontalMergeGroup> mergeGroups) {
-      // Relies on the determinism of the merge groups.
-      HorizontalMergeGroup mergeGroup = mergeGroups.iterator().next();
-      assert mergeGroup.hasTarget();
-      return mergeGroup.getTarget();
-    }
-  }
-}
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 cb4af41..7139797 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
@@ -8,7 +8,7 @@
 
 import com.android.tools.r8.androidapi.ComputedApiLevel;
 import com.android.tools.r8.classmerging.ClassMergerMode;
-import com.android.tools.r8.classmerging.SyntheticArgumentClass;
+import com.android.tools.r8.classmerging.ClassMergerSharedData;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexDefinition;
@@ -109,11 +109,11 @@
   }
 
   void mergeDirectMethods(
+      ClassMergerSharedData classMergerSharedData,
       ProfileCollectionAdditions profileCollectionAdditions,
-      SyntheticArgumentClass syntheticArgumentClass,
       SyntheticInitializerConverter.Builder syntheticInitializerConverterBuilder) {
     mergeInstanceInitializers(
-        profileCollectionAdditions, syntheticArgumentClass, syntheticInitializerConverterBuilder);
+        classMergerSharedData, profileCollectionAdditions, syntheticInitializerConverterBuilder);
     mergeStaticClassInitializers(syntheticInitializerConverterBuilder);
     group.forEach(this::mergeDirectMethods);
     if (!classInitializerMerger.isEmpty() && classInitializerMerger.isTrivialMerge()) {
@@ -203,26 +203,26 @@
   }
 
   void mergeInstanceInitializers(
+      ClassMergerSharedData classMergerSharedData,
       ProfileCollectionAdditions profileCollectionAdditions,
-      SyntheticArgumentClass syntheticArgumentClass,
       SyntheticInitializerConverter.Builder syntheticInitializerConverterBuilder) {
     instanceInitializerMergers.forEach(
         merger ->
             merger.merge(
+                classMergerSharedData,
                 profileCollectionAdditions,
                 classMethodsBuilder,
-                syntheticArgumentClass,
                 syntheticInitializerConverterBuilder));
   }
 
   void mergeMethods(
+      ClassMergerSharedData classMergerSharedData,
       ProfileCollectionAdditions profileCollectionAdditions,
-      SyntheticArgumentClass syntheticArgumentClass,
       SyntheticInitializerConverter.Builder syntheticInitializerConverterBuilder,
       Consumer<VirtuallyMergedMethodsKeepInfo> virtuallyMergedMethodsKeepInfoConsumer) {
     mergeVirtualMethods(profileCollectionAdditions, virtuallyMergedMethodsKeepInfoConsumer);
     mergeDirectMethods(
-        profileCollectionAdditions, syntheticArgumentClass, syntheticInitializerConverterBuilder);
+        classMergerSharedData, profileCollectionAdditions, syntheticInitializerConverterBuilder);
     classMethodsBuilder.setClassMethods(group.getTarget());
   }
 
@@ -352,9 +352,9 @@
   }
 
   public void mergeGroup(
+      ClassMergerSharedData classMergerSharedData,
       ProfileCollectionAdditions profileCollectionAdditions,
       PrunedItems.Builder prunedItemsBuilder,
-      SyntheticArgumentClass syntheticArgumentClass,
       SyntheticInitializerConverter.Builder syntheticInitializerConverterBuilder,
       Consumer<VirtuallyMergedMethodsKeepInfo> virtuallyMergedMethodsKeepInfoConsumer) {
     fixAccessFlags();
@@ -363,8 +363,8 @@
     mergeInterfaces();
     mergeFields(prunedItemsBuilder);
     mergeMethods(
+        classMergerSharedData,
         profileCollectionAdditions,
-        syntheticArgumentClass,
         syntheticInitializerConverterBuilder,
         virtuallyMergedMethodsKeepInfoConsumer);
     group.getTarget().clearClassSignature();
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorEntryPoint.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorEntryPoint.java
index 49f51d8..49532c6 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorEntryPoint.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorEntryPoint.java
@@ -6,12 +6,14 @@
 
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.ir.code.ConstNumber;
 import com.android.tools.r8.ir.code.InvokeType;
 import com.android.tools.r8.ir.code.Position;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.synthetic.SyntheticSourceCode;
+import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.IntBox;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceMap.Entry;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
@@ -35,17 +37,20 @@
  */
 public class ConstructorEntryPoint extends SyntheticSourceCode {
   private final DexField classIdField;
+  private final int extraNulls;
   private final Int2ReferenceSortedMap<DexMethod> typeConstructors;
 
   public ConstructorEntryPoint(
       Int2ReferenceSortedMap<DexMethod> typeConstructors,
       DexMethod newConstructor,
       DexField classIdField,
+      int extraNulls,
       Position position) {
     super(newConstructor.holder, newConstructor, position);
 
     this.typeConstructors = typeConstructors;
     this.classIdField = classIdField;
+    this.extraNulls = extraNulls;
   }
 
   private boolean hasClassIdField() {
@@ -55,16 +60,37 @@
   void addConstructorInvoke(DexMethod typeConstructor) {
     add(
         builder -> {
-          List<Value> arguments = new ArrayList<>(typeConstructor.getArity() + 1);
+          int originalNumberOfNonReceiverArguments =
+              builder.hasArgumentValues()
+                  ? (builder.getArgumentValues().size()
+                      - BooleanUtils.intValue(typeConstructors.size() > 1)
+                      - extraNulls)
+                  : 0;
+          int newNumberOfNonReceiverArguments = typeConstructor.getArity();
+          List<Value> arguments = new ArrayList<>(newNumberOfNonReceiverArguments + 1);
           arguments.add(builder.getReceiverValue());
-
-          // If there are any arguments add them to the list.
-          for (int i = 0; i < typeConstructor.getArity(); i++) {
-            arguments.add(builder.getArgumentValues().get(i));
+          if (originalNumberOfNonReceiverArguments >= newNumberOfNonReceiverArguments) {
+            for (int i = 0; i < newNumberOfNonReceiverArguments; i++) {
+              arguments.add(builder.getArgumentValues().get(i));
+            }
+          } else {
+            // Exclude the last argument if it is the synthetic class id parameter, since the
+            // original constructor we are calling does not have it.
+            for (int i = 0; i < originalNumberOfNonReceiverArguments; i++) {
+              arguments.add(builder.getArgumentValues().get(i));
+            }
+            int extraRegister = nextRegister(ValueType.INT);
+            ConstNumber constNumber = builder.addIntConst(extraRegister, 0);
+            while (arguments.size() <= newNumberOfNonReceiverArguments) {
+              assert ValueType.fromDexType(
+                      typeConstructor.getArgumentTypeForNonStaticMethod(arguments.size()))
+                  == ValueType.INT;
+              arguments.add(constNumber.outValue());
+            }
           }
-
+          assert arguments.size() == typeConstructor.getNumberOfArgumentsForNonStaticMethod();
           builder.addInvoke(
-              InvokeType.DIRECT, typeConstructor, typeConstructor.proto, arguments, false);
+              InvokeType.DIRECT, typeConstructor, typeConstructor.getProto(), arguments, false);
         });
   }
 
@@ -84,10 +110,8 @@
 
   protected void prepareMultiConstructorInstructions() {
     int typeConstructorCount = typeConstructors.size();
-    DexMethod exampleTargetConstructor = typeConstructors.values().iterator().next();
     // The class id register is always the first synthetic argument.
-    int idRegister = getParamRegister(exampleTargetConstructor.getArity());
-
+    int idRegister = getParamRegister(method.getArity() - 1 - extraNulls);
     if (hasClassIdField()) {
       addRegisterClassIdAssignment(idRegister);
     }
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 03d62ea..91ca758 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
@@ -7,11 +7,12 @@
 import static com.android.tools.r8.graph.DexClassAndMethod.asProgramMethodOrNull;
 
 import com.android.tools.r8.classmerging.ClassMergerMode;
+import com.android.tools.r8.classmerging.ClassMergerSharedData;
 import com.android.tools.r8.classmerging.Policy;
-import com.android.tools.r8.classmerging.SyntheticArgumentClass;
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -130,20 +131,17 @@
 
     // Merge the classes.
     List<ClassMerger> classMergers = initializeClassMergers(codeProvider, lensBuilder, groups);
+    ClassMergerSharedData classMergerSharedData = new ClassMergerSharedData(appView);
     ProfileCollectionAdditions profileCollectionAdditions =
         ProfileCollectionAdditions.create(appView);
-    SyntheticArgumentClass syntheticArgumentClass =
-        mode.isInitial()
-            ? new SyntheticArgumentClass.Builder(appView.withLiveness()).build(groups)
-            : null;
     SyntheticInitializerConverter.Builder syntheticInitializerConverterBuilder =
         SyntheticInitializerConverter.builder(appView, codeProvider, mode);
     List<VirtuallyMergedMethodsKeepInfo> virtuallyMergedMethodsKeepInfos = new ArrayList<>();
     PrunedItems prunedItems =
         applyClassMergers(
             classMergers,
+            classMergerSharedData,
             profileCollectionAdditions,
-            syntheticArgumentClass,
             syntheticInitializerConverterBuilder,
             virtuallyMergedMethodsKeepInfos::add);
 
@@ -159,13 +157,7 @@
 
     HorizontalClassMergerGraphLens horizontalClassMergerGraphLens =
         createLens(
-            mergedClasses,
-            lensBuilder,
-            mode,
-            profileCollectionAdditions,
-            syntheticArgumentClass,
-            executorService,
-            timing);
+            classMergerSharedData, mergedClasses, lensBuilder, mode, executorService, timing);
     profileCollectionAdditions =
         profileCollectionAdditions.rewriteMethodReferences(
             horizontalClassMergerGraphLens::getNextMethodToInvoke);
@@ -298,12 +290,19 @@
                   definition.hasCode()
                       && definition.getCode().isIncompleteHorizontalClassMergerCode(),
               method -> {
+                // Transform the code object to CfCode. This may return null if the code object does
+                // not have support for generating CfCode. In this case, the call to toCfCode() will
+                // lens rewrite the references of the code object using the lens.
+                //
+                // This should be changed to generate non-null LirCode always.
                 IncompleteHorizontalClassMergerCode code =
                     (IncompleteHorizontalClassMergerCode) method.getDefinition().getCode();
-                method.setCode(
+                CfCode cfCode =
                     code.toCfCode(
-                        appView.withClassHierarchy(), method, horizontalClassMergerGraphLens),
-                    appView);
+                        appView.withClassHierarchy(), method, horizontalClassMergerGraphLens);
+                if (cfCode != null) {
+                  method.setCode(cfCode, appView);
+                }
               });
         },
         appView.options().getThreadingModule(),
@@ -387,16 +386,16 @@
   /** Merges all class groups using {@link ClassMerger}. */
   private PrunedItems applyClassMergers(
       Collection<ClassMerger> classMergers,
+      ClassMergerSharedData classMergerSharedData,
       ProfileCollectionAdditions profileCollectionAdditions,
-      SyntheticArgumentClass syntheticArgumentClass,
       SyntheticInitializerConverter.Builder syntheticInitializerConverterBuilder,
       Consumer<VirtuallyMergedMethodsKeepInfo> virtuallyMergedMethodsKeepInfoConsumer) {
     PrunedItems.Builder prunedItemsBuilder = PrunedItems.builder().setPrunedApp(appView.app());
     for (ClassMerger merger : classMergers) {
       merger.mergeGroup(
+          classMergerSharedData,
           profileCollectionAdditions,
           prunedItemsBuilder,
-          syntheticArgumentClass,
           syntheticInitializerConverterBuilder,
           virtuallyMergedMethodsKeepInfoConsumer);
     }
@@ -409,21 +408,15 @@
    */
   @SuppressWarnings("ReferenceEquality")
   private HorizontalClassMergerGraphLens createLens(
+      ClassMergerSharedData classMergerSharedData,
       HorizontallyMergedClasses mergedClasses,
       HorizontalClassMergerGraphLens.Builder lensBuilder,
       ClassMergerMode mode,
-      ProfileCollectionAdditions profileCollectionAdditions,
-      SyntheticArgumentClass syntheticArgumentClass,
       ExecutorService executorService,
       Timing timing)
       throws ExecutionException {
     return new HorizontalClassMergerTreeFixer(
-            appView,
-            mergedClasses,
-            lensBuilder,
-            mode,
-            profileCollectionAdditions,
-            syntheticArgumentClass)
+            appView, classMergerSharedData, mergedClasses, lensBuilder, mode)
         .run(executorService, timing);
   }
 
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerTreeFixer.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerTreeFixer.java
index 5bc07a2..91f25d0 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerTreeFixer.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerTreeFixer.java
@@ -5,10 +5,9 @@
 package com.android.tools.r8.horizontalclassmerging;
 
 import com.android.tools.r8.classmerging.ClassMergerMode;
+import com.android.tools.r8.classmerging.ClassMergerSharedData;
 import com.android.tools.r8.classmerging.ClassMergerTreeFixer;
-import com.android.tools.r8.classmerging.SyntheticArgumentClass;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
 import com.android.tools.r8.utils.Timing;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
@@ -28,12 +27,11 @@
 
   public HorizontalClassMergerTreeFixer(
       AppView<?> appView,
+      ClassMergerSharedData classMergerSharedData,
       HorizontallyMergedClasses mergedClasses,
       HorizontalClassMergerGraphLens.Builder lensBuilder,
-      ClassMergerMode mode,
-      ProfileCollectionAdditions profileCollectionAdditions,
-      SyntheticArgumentClass syntheticArgumentClass) {
-    super(appView, lensBuilder, mergedClasses, profileCollectionAdditions, syntheticArgumentClass);
+      ClassMergerMode mode) {
+    super(appView, classMergerSharedData, lensBuilder, mergedClasses);
     this.mode = mode;
   }
 
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
index 461cbc0..66b8a1e 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
@@ -4,12 +4,11 @@
 
 package com.android.tools.r8.horizontalclassmerging;
 
-import static com.android.tools.r8.dex.Constants.TEMPORARY_INSTANCE_INITIALIZER_PREFIX;
 import static com.android.tools.r8.ir.conversion.ExtraUnusedParameter.computeExtraUnusedParameters;
 
 import com.android.tools.r8.cf.CfVersion;
 import com.android.tools.r8.classmerging.ClassMergerMode;
-import com.android.tools.r8.classmerging.SyntheticArgumentClass;
+import com.android.tools.r8.classmerging.ClassMergerSharedData;
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
@@ -29,7 +28,6 @@
 import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
 import com.android.tools.r8.utils.ArrayUtils;
 import com.android.tools.r8.utils.BooleanUtils;
-import com.android.tools.r8.utils.Box;
 import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.SetUtils;
 import com.android.tools.r8.utils.structural.Ordered;
@@ -160,7 +158,7 @@
     for (ProgramMethod instanceInitializer : instanceInitializers) {
       typeConstructorClassMap.put(
           classIdentifiers.getInt(instanceInitializer.getHolderType()),
-          lensBuilder.getRenamedMethodSignature(instanceInitializer.getReference()));
+          instanceInitializer.getReference());
     }
     return typeConstructorClassMap;
   }
@@ -245,27 +243,27 @@
   }
 
   private DexMethod moveInstanceInitializer(
-      ClassMethodsBuilder classMethodsBuilder, ProgramMethod instanceInitializer) {
-    DexMethod method =
-        dexItemFactory.createFreshMethodNameWithHolder(
-            TEMPORARY_INSTANCE_INITIALIZER_PREFIX,
-            instanceInitializer.getHolderType(),
-            instanceInitializer.getProto(),
-            group.getTarget().getType(),
-            classMethodsBuilder::isFresh);
-
-    DexEncodedMethod encodedMethod =
+      ClassMergerSharedData classMergerSharedData,
+      ClassMethodsBuilder classMethodsBuilder,
+      ProgramMethod instanceInitializer,
+      DexMethod reservedMethod) {
+    DexMethod newReference =
+        dexItemFactory.createInstanceInitializerWithFreshProto(
+            instanceInitializer.getReference().withHolder(group.getTarget(), dexItemFactory),
+            classMergerSharedData.getExtraUnusedArgumentTypes(),
+            candidate ->
+                classMethodsBuilder.isFresh(candidate)
+                    && candidate.isNotIdenticalTo(reservedMethod));
+    if (newReference.isIdenticalTo(instanceInitializer.getReference())) {
+      classMethodsBuilder.addDirectMethod(instanceInitializer.getDefinition());
+      return newReference;
+    }
+    DexEncodedMethod newMethod =
         instanceInitializer
             .getDefinition()
-            .toTypeSubstitutedMethodAsInlining(method, dexItemFactory);
-    encodedMethod.getMutableOptimizationInfo().markForceInline();
-    encodedMethod.getAccessFlags().unsetConstructor();
-    encodedMethod.getAccessFlags().unsetPublic();
-    encodedMethod.getAccessFlags().unsetProtected();
-    encodedMethod.getAccessFlags().setPrivate();
-    classMethodsBuilder.addDirectMethod(encodedMethod);
-
-    return method;
+            .toTypeSubstitutedMethodAsInlining(newReference, dexItemFactory);
+    classMethodsBuilder.addDirectMethod(newMethod);
+    return newReference;
   }
 
   private MethodAccessFlags getNewAccessFlags() {
@@ -288,7 +286,8 @@
     return new ConstructorEntryPointSynthesizedCode(
         createClassIdToInstanceInitializerMap(),
         newMethodReference,
-        group.hasClassIdField() ? group.getClassIdField() : null);
+        group.hasClassIdField() ? group.getClassIdField() : null,
+        extraNulls);
   }
 
   private boolean isSingleton() {
@@ -298,9 +297,9 @@
   /** Synthesize a new method which selects the constructor based on a parameter type. */
   @SuppressWarnings("ReferenceEquality")
   void merge(
+      ClassMergerSharedData classMergerSharedData,
       ProfileCollectionAdditions profileCollectionAdditions,
       ClassMethodsBuilder classMethodsBuilder,
-      SyntheticArgumentClass syntheticArgumentClass,
       SyntheticInitializerConverter.Builder syntheticInitializerConverterBuilder) {
     ProgramMethod representative = ListUtils.first(instanceInitializers);
 
@@ -313,23 +312,13 @@
     DexMethod newMethodReferenceTemplate = getNewMethodReference(representative, needsClassId);
     assert mode.isInitial() || classMethodsBuilder.isFresh(newMethodReferenceTemplate);
 
-    Box<Set<DexType>> usedSyntheticArgumentClasses = new Box<>();
     DexMethod newMethodReference =
         dexItemFactory.createInstanceInitializerWithFreshProto(
             newMethodReferenceTemplate,
-            mode.isInitial() ? syntheticArgumentClass.getArgumentClasses() : ImmutableList.of(),
-            classMethodsBuilder::isFresh,
-            usedSyntheticArgumentClasses::set);
-
-    // Amend the art profile collection.
-    if (usedSyntheticArgumentClasses.isSet()) {
-      for (ProgramMethod instanceInitializer : instanceInitializers) {
-        profileCollectionAdditions.applyIfContextIsInProfile(
-            instanceInitializer.getReference(),
-            additionsBuilder ->
-                usedSyntheticArgumentClasses.get().forEach(additionsBuilder::addRule));
-      }
-    }
+            mode.isInitial()
+                ? classMergerSharedData.getExtraUnusedArgumentTypes()
+                : ImmutableList.of(),
+            classMethodsBuilder::isFresh);
 
     // Compute the extra unused null parameters.
     List<ExtraUnusedParameter> extraUnusedParameters =
@@ -346,7 +335,11 @@
     } else {
       for (ProgramMethod instanceInitializer : instanceInitializers) {
         DexMethod movedInstanceInitializer =
-            moveInstanceInitializer(classMethodsBuilder, instanceInitializer);
+            moveInstanceInitializer(
+                classMergerSharedData,
+                classMethodsBuilder,
+                instanceInitializer,
+                newMethodReference);
         lensBuilder.mapMethod(movedInstanceInitializer, movedInstanceInitializer);
         lensBuilder.recordNewMethodSignature(
             instanceInitializer.getReference(), movedInstanceInitializer);
@@ -361,7 +354,6 @@
     // Add a mapping from a synthetic name to the synthetic constructor.
     DexMethod syntheticMethodReference =
         getSyntheticMethodReference(classMethodsBuilder, newMethodReference);
-
     if (useSyntheticMethod()) {
       lensBuilder.recordNewMethodSignature(syntheticMethodReference, newMethodReference, true);
     }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
index a9fa5b6..e4df0c7 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
@@ -32,7 +32,6 @@
 import com.android.tools.r8.horizontalclassmerging.policies.NoDirectRuntimeTypeChecks;
 import com.android.tools.r8.horizontalclassmerging.policies.NoEnums;
 import com.android.tools.r8.horizontalclassmerging.policies.NoFailedResolutionTargets;
-import com.android.tools.r8.horizontalclassmerging.policies.NoIllegalInlining;
 import com.android.tools.r8.horizontalclassmerging.policies.NoIndirectRuntimeTypeChecks;
 import com.android.tools.r8.horizontalclassmerging.policies.NoInnerClasses;
 import com.android.tools.r8.horizontalclassmerging.policies.NoInstanceFieldAnnotations;
@@ -125,7 +124,6 @@
       AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
       builder.add(
           new NoDeadEnumLiteMaps(appViewWithLiveness, mode),
-          new NoIllegalInlining(appViewWithLiveness, mode),
           new NoVerticallyMergedClasses(appViewWithLiveness, mode));
     }
 
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ConstructorEntryPointSynthesizedCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ConstructorEntryPointSynthesizedCode.java
index 0c0f059..75b76b6 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ConstructorEntryPointSynthesizedCode.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ConstructorEntryPointSynthesizedCode.java
@@ -5,18 +5,20 @@
 package com.android.tools.r8.horizontalclassmerging.code;
 
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.ClasspathMethod;
-import com.android.tools.r8.graph.Code;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
 import com.android.tools.r8.horizontalclassmerging.ConstructorEntryPoint;
+import com.android.tools.r8.horizontalclassmerging.HorizontalClassMergerGraphLens;
+import com.android.tools.r8.horizontalclassmerging.IncompleteHorizontalClassMergerCode;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.NumberGenerator;
 import com.android.tools.r8.ir.code.Position;
@@ -27,21 +29,25 @@
 import com.android.tools.r8.ir.conversion.SourceCode;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.RetracerForCodePrinting;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
 
-public class ConstructorEntryPointSynthesizedCode extends Code {
+public class ConstructorEntryPointSynthesizedCode extends IncompleteHorizontalClassMergerCode {
 
   private final DexMethod newConstructor;
   private final DexField classIdField;
+  private final int extraNulls;
   private final Int2ReferenceSortedMap<DexMethod> typeConstructors;
 
   public ConstructorEntryPointSynthesizedCode(
       Int2ReferenceSortedMap<DexMethod> typeConstructors,
       DexMethod newConstructor,
-      DexField classIdField) {
+      DexField classIdField,
+      int extraNulls) {
     this.typeConstructors = typeConstructors;
     this.newConstructor = newConstructor;
     this.classIdField = classIdField;
+    this.extraNulls = extraNulls;
   }
 
   private void registerReachableDefinitions(UseRegistry<?> registry) {
@@ -55,11 +61,30 @@
   }
 
   @Override
+  public GraphLens getCodeLens(AppView<?> appView) {
+    return appView
+        .graphLens()
+        .asNonIdentityLens()
+        .find(GraphLens::isHorizontalClassMergerGraphLens);
+  }
+
+  @Override
   public boolean isHorizontalClassMergerCode() {
     return true;
   }
 
   @Override
+  public CfCode toCfCode(
+      AppView<? extends AppInfoWithClassHierarchy> appView,
+      ProgramMethod method,
+      HorizontalClassMergerGraphLens lens) {
+    for (Int2ReferenceMap.Entry<DexMethod> entry : typeConstructors.int2ReferenceEntrySet()) {
+      entry.setValue(lens.getNextMethodSignature(entry.getValue()));
+    }
+    return null;
+  }
+
+  @Override
   public final boolean isEmptyVoidMethod() {
     return false;
   }
@@ -77,7 +102,8 @@
             .setIsD8R8Synthesized(true)
             .build();
     SourceCode sourceCode =
-        new ConstructorEntryPoint(typeConstructors, newConstructor, classIdField, position);
+        new ConstructorEntryPoint(
+            typeConstructors, newConstructor, classIdField, extraNulls, position);
     return IRBuilder.create(method, appView, sourceCode, origin).build(method, conversionOptions);
   }
 
@@ -92,25 +118,14 @@
       Origin origin,
       RewrittenPrototypeDescription protoChanges) {
     SourceCode sourceCode =
-        new ConstructorEntryPoint(typeConstructors, newConstructor, classIdField, callerPosition);
+        new ConstructorEntryPoint(
+            typeConstructors, newConstructor, classIdField, extraNulls, callerPosition);
     return IRBuilder.createForInlining(
             method, appView, codeLens, sourceCode, origin, valueNumberGenerator, protoChanges)
         .build(context, MethodConversionOptions.nonConverting());
   }
 
   @Override
-  public final Code getCodeAsInlining(
-      DexMethod caller,
-      boolean isCallerD8R8Synthesized,
-      DexMethod callee,
-      boolean isCalleeD8R8Synthesized,
-      DexItemFactory factory) {
-    // This code object is synthesized so "inlining" just "strips" the callee position.
-    assert isCalleeD8R8Synthesized;
-    return this;
-  }
-
-  @Override
   public final String toString() {
     return toString(null, RetracerForCodePrinting.empty());
   }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoIllegalInlining.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoIllegalInlining.java
deleted file mode 100644
index 5126df8..0000000
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoIllegalInlining.java
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.horizontalclassmerging.policies;
-
-import com.android.tools.r8.classmerging.ClassMergerMode;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
-import com.android.tools.r8.graph.Code;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.horizontalclassmerging.SingleClassPolicy;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.google.common.collect.Iterables;
-
-public class NoIllegalInlining extends SingleClassPolicy {
-
-  private final AppView<AppInfoWithLiveness> appView;
-
-  public NoIllegalInlining(AppView<AppInfoWithLiveness> appView, ClassMergerMode mode) {
-    // This policy is only relevant for the first round of horizontal class merging, since the final
-    // round of horizontal class merging may not require any inlining.
-    assert mode.isInitial();
-    this.appView = appView;
-  }
-
-  @SuppressWarnings("ReferenceEquality")
-  private boolean disallowInlining(ProgramMethod method) {
-    Code code = method.getDefinition().getCode();
-
-    if (!appView.getKeepInfo(method).isInliningAllowed(appView.options())) {
-      return true;
-    }
-
-    // For non-jar/cf code we currently cannot guarantee that markForceInline() will succeed.
-    if (code == null) {
-      return true;
-    }
-
-    if (code.isCfCode()) {
-      CfCode cfCode = code.asCfCode();
-      ConstraintWithTarget constraint =
-          cfCode.computeInliningConstraint(appView, appView.graphLens(), method);
-      return constraint.isNever();
-    } else if (code.isDefaultInstanceInitializerCode()) {
-      return false;
-    } else {
-      return true;
-    }
-  }
-
-  @Override
-  public boolean canMerge(DexProgramClass program) {
-    return !Iterables.any(
-        program.directProgramMethods(),
-        method -> method.getDefinition().isInstanceInitializer() && disallowInlining(method));
-  }
-
-  @Override
-  public String getName() {
-    return "DontInlinePolicy";
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index a3ca7c5..9cb7612 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -517,6 +517,11 @@
     return targets;
   }
 
+  public boolean hasArgumentValues() {
+    assert argumentValues == null || !argumentValues.isEmpty();
+    return argumentValues != null;
+  }
+
   public List<Value> getArgumentValues() {
     return argumentValues;
   }
@@ -1219,8 +1224,11 @@
     add(new ConstNumber(writeRegister(dest, getDouble(), ThrowingInfo.NO_THROW), value));
   }
 
-  public void addIntConst(int dest, long value) {
-    add(new ConstNumber(writeRegister(dest, getInt(), ThrowingInfo.NO_THROW), value));
+  public ConstNumber addIntConst(int dest, long value) {
+    ConstNumber constNumber =
+        new ConstNumber(writeRegister(dest, getInt(), ThrowingInfo.NO_THROW), value);
+    add(constNumber);
+    return constNumber;
   }
 
   public void addFloatConst(int dest, long value) {
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
index a1795a7..a9f9957 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
@@ -49,12 +49,6 @@
   public final SyntheticKind WRAPPER = generator.forFixedClass("$Wrapper");
   public final SyntheticKind VIVIFIED_WRAPPER = generator.forFixedClass("$VivifiedWrapper");
   public final SyntheticKind INIT_TYPE_ARGUMENT = generator.forFixedClass("-IA");
-  public final SyntheticKind HORIZONTAL_INIT_TYPE_ARGUMENT_1 =
-      generator.forFixedClass(SYNTHETIC_CLASS_SEPARATOR + "IA$1");
-  public final SyntheticKind HORIZONTAL_INIT_TYPE_ARGUMENT_2 =
-      generator.forFixedClass(SYNTHETIC_CLASS_SEPARATOR + "IA$2");
-  public final SyntheticKind HORIZONTAL_INIT_TYPE_ARGUMENT_3 =
-      generator.forFixedClass(SYNTHETIC_CLASS_SEPARATOR + "IA$3");
   public final SyntheticKind ENUM_CONVERSION = generator.forFixedClass("$EnumConversion");
 
   // Locally generated synthetic classes.
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 838558f..009ba19 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -1877,7 +1877,7 @@
         }
       }
       if (mode.isInitial()) {
-        return enableInitial && inlinerOptions.enableInlining;
+        return enableInitial;
       }
       assert mode.isFinal();
       return true;
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/ClassMerger.java b/src/main/java/com/android/tools/r8/verticalclassmerging/ClassMerger.java
index 6f89166..2fdda52 100644
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/ClassMerger.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/ClassMerger.java
@@ -9,6 +9,7 @@
 import static java.util.function.Predicate.not;
 
 import com.android.tools.r8.cf.CfVersion;
+import com.android.tools.r8.classmerging.ClassMergerSharedData;
 import com.android.tools.r8.graph.AccessControl;
 import com.android.tools.r8.graph.AccessFlags;
 import com.android.tools.r8.graph.AppView;
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/ConnectedComponentVerticalClassMerger.java b/src/main/java/com/android/tools/r8/verticalclassmerging/ConnectedComponentVerticalClassMerger.java
index 72547ec..56e619f 100644
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/ConnectedComponentVerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/ConnectedComponentVerticalClassMerger.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.verticalclassmerging;
 
+import com.android.tools.r8.classmerging.ClassMergerSharedData;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.ListUtils;
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMerger.java
index d5e839e..8ef8743 100644
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMerger.java
@@ -6,8 +6,8 @@
 import static com.android.tools.r8.graph.DexClassAndMethod.asProgramMethodOrNull;
 
 import com.android.tools.r8.classmerging.ClassMergerMode;
+import com.android.tools.r8.classmerging.ClassMergerSharedData;
 import com.android.tools.r8.classmerging.Policy;
-import com.android.tools.r8.classmerging.SyntheticArgumentClass;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexItemFactory;
@@ -25,7 +25,6 @@
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.shaking.KeepInfoCollection;
 import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.ThreadUtils;
 import com.android.tools.r8.utils.Timing;
 import com.android.tools.r8.utils.Timing.TimingMerger;
@@ -33,7 +32,6 @@
 import com.google.common.collect.Streams;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Comparator;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
@@ -104,23 +102,26 @@
     timing.end();
 
     // Apply class merging concurrently in disjoint class hierarchies.
+    ClassMergerSharedData classMergerSharedData = new ClassMergerSharedData(appView);
     VerticalClassMergerResult verticalClassMergerResult =
         mergeClassesInConnectedComponents(
-            connectedComponents, immediateSubtypingInfo, executorService, timing);
+            classMergerSharedData,
+            connectedComponents,
+            immediateSubtypingInfo,
+            executorService,
+            timing);
     appView.setVerticallyMergedClasses(
         verticalClassMergerResult.getVerticallyMergedClasses(), mode);
     if (verticalClassMergerResult.isEmpty()) {
       return;
     }
-    ProfileCollectionAdditions profileCollectionAdditions =
-        ProfileCollectionAdditions.create(appView);
     VerticalClassMergerGraphLens lens =
-        runFixup(profileCollectionAdditions, verticalClassMergerResult, executorService, timing);
+        runFixup(classMergerSharedData, verticalClassMergerResult, executorService, timing);
     assert verifyGraphLens(lens, verticalClassMergerResult);
 
     // Update keep info and art profiles.
     updateKeepInfoForMergedClasses(verticalClassMergerResult, timing);
-    updateArtProfiles(profileCollectionAdditions, lens, verticalClassMergerResult, timing);
+    updateArtProfiles(lens, verticalClassMergerResult, timing);
 
     // Remove merged classes and rewrite AppView with the new lens.
     appView.rewriteWithLens(lens, executorService, timing);
@@ -143,6 +144,7 @@
   }
 
   private VerticalClassMergerResult mergeClassesInConnectedComponents(
+      ClassMergerSharedData classMergerSharedData,
       List<Set<DexProgramClass>> connectedComponents,
       ImmediateProgramSubtypingInfo immediateSubtypingInfo,
       ExecutorService executorService,
@@ -151,7 +153,8 @@
     Collection<ConnectedComponentVerticalClassMerger> connectedComponentMergers =
         getConnectedComponentMergers(
             connectedComponents, immediateSubtypingInfo, executorService, timing);
-    return applyConnectedComponentMergers(connectedComponentMergers, executorService, timing);
+    return applyConnectedComponentMergers(
+        classMergerSharedData, connectedComponentMergers, executorService, timing);
   }
 
   private Collection<ConnectedComponentVerticalClassMerger> getConnectedComponentMergers(
@@ -190,13 +193,13 @@
   }
 
   private VerticalClassMergerResult applyConnectedComponentMergers(
+      ClassMergerSharedData classMergerSharedData,
       Collection<ConnectedComponentVerticalClassMerger> connectedComponentMergers,
       ExecutorService executorService,
       Timing timing)
       throws ExecutionException {
     timing.begin("Merge classes");
     TimingMerger merger = timing.beginMerger("Merge classes", executorService);
-    ClassMergerSharedData sharedData = new ClassMergerSharedData(appView);
     VerticalClassMergerResult.Builder verticalClassMergerResult =
         VerticalClassMergerResult.builder(appView);
     Collection<Timing> timings =
@@ -205,7 +208,7 @@
             connectedComponentMerger -> {
               Timing threadTiming = Timing.create("Merge classes in component", options);
               VerticalClassMergerResult.Builder verticalClassMergerComponentResult =
-                  connectedComponentMerger.run(sharedData);
+                  connectedComponentMerger.run(classMergerSharedData);
               verticalClassMergerResult.merge(verticalClassMergerComponentResult);
               threadTiming.end();
               return threadTiming;
@@ -219,29 +222,14 @@
   }
 
   private VerticalClassMergerGraphLens runFixup(
-      ProfileCollectionAdditions profileCollectionAdditions,
+      ClassMergerSharedData classMergerSharedData,
       VerticalClassMergerResult verticalClassMergerResult,
       ExecutorService executorService,
       Timing timing)
       throws ExecutionException {
-    DexProgramClass deterministicContext =
-        appView
-            .definitionFor(
-                ListUtils.first(
-                    ListUtils.sort(
-                        verticalClassMergerResult.getVerticallyMergedClasses().getTargets(),
-                        Comparator.naturalOrder())))
-            .asProgramClass();
-    SyntheticArgumentClass syntheticArgumentClass =
-        new SyntheticArgumentClass.Builder(appView).build(deterministicContext);
-    VerticalClassMergerGraphLens lens =
-        new VerticalClassMergerTreeFixer(
-                appView,
-                profileCollectionAdditions,
-                syntheticArgumentClass,
-                verticalClassMergerResult)
-            .run(executorService, timing);
-    return lens;
+    return new VerticalClassMergerTreeFixer(
+            appView, classMergerSharedData, verticalClassMergerResult)
+        .run(executorService, timing);
   }
 
   private void rewriteCodeWithLens(ExecutorService executorService, Timing timing)
@@ -253,11 +241,12 @@
   }
 
   private void updateArtProfiles(
-      ProfileCollectionAdditions profileCollectionAdditions,
       VerticalClassMergerGraphLens verticalClassMergerLens,
       VerticalClassMergerResult verticalClassMergerResult,
       Timing timing) {
     // Include bridges in art profiles.
+    ProfileCollectionAdditions profileCollectionAdditions =
+        ProfileCollectionAdditions.create(appView);
     if (profileCollectionAdditions.isNop()) {
       return;
     }
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerTreeFixer.java b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerTreeFixer.java
index c6c1f4d..dc6763b 100644
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerTreeFixer.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerTreeFixer.java
@@ -3,10 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.verticalclassmerging;
 
+import com.android.tools.r8.classmerging.ClassMergerSharedData;
 import com.android.tools.r8.classmerging.ClassMergerTreeFixer;
-import com.android.tools.r8.classmerging.SyntheticArgumentClass;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.Timing;
 import java.util.List;
@@ -23,15 +22,13 @@
 
   VerticalClassMergerTreeFixer(
       AppView<AppInfoWithLiveness> appView,
-      ProfileCollectionAdditions profileCollectionAdditions,
-      SyntheticArgumentClass syntheticArgumentClass,
+      ClassMergerSharedData classMergerSharedData,
       VerticalClassMergerResult verticalClassMergerResult) {
     super(
         appView,
+        classMergerSharedData,
         VerticalClassMergerGraphLens.Builder.createBuilderForFixup(verticalClassMergerResult),
-        verticalClassMergerResult.getVerticallyMergedClasses(),
-        profileCollectionAdditions,
-        syntheticArgumentClass);
+        verticalClassMergerResult.getVerticallyMergedClasses());
     this.synthesizedBridges = verticalClassMergerResult.getSynthesizedBridges();
   }
 
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorCantInlineTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorCantInlineTest.java
index f2db164..3e84ae4 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorCantInlineTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorCantInlineTest.java
@@ -6,6 +6,7 @@
 
 import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentIf;
 import static org.hamcrest.MatcherAssert.assertThat;
 
 import com.android.tools.r8.NeverClassInline;
@@ -33,7 +34,7 @@
         .inspect(
             codeInspector -> {
               assertThat(codeInspector.clazz(A.class), isAbsent());
-              assertThat(codeInspector.clazz(B.class), isAbsent());
+              assertThat(codeInspector.clazz(B.class), isPresentIf(parameters.isCfRuntime()));
               assertThat(codeInspector.clazz(C.class), isPresent());
               assertThat(codeInspector.clazz(D.class), isAbsent());
             });
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingOverlapTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingOverlapTest.java
index 7dee4de..e6e1d11 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingOverlapTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingOverlapTest.java
@@ -45,7 +45,8 @@
               assertThat(firstInitSubject, isPresent());
               assertThat(firstInitSubject, writesInstanceField(classIdFieldSubject.getDexField()));
 
-              MethodSubject otherInitSubject = aClassSubject.init("int", "int");
+              MethodSubject otherInitSubject =
+                  aClassSubject.init("int", parameters.isCfRuntime() ? "java.lang.Object" : "int");
               assertThat(otherInitSubject, isPresent());
               assertThat(otherInitSubject, writesInstanceField(classIdFieldSubject.getDexField()));
 
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingTrivialOverlapTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingTrivialOverlapTest.java
index 2be25d3..ecb49d6 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingTrivialOverlapTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingTrivialOverlapTest.java
@@ -45,7 +45,8 @@
               assertThat(firstInitSubject, isPresent());
               assertThat(firstInitSubject, writesInstanceField(classIdFieldSubject.getDexField()));
 
-              MethodSubject otherInitSubject = aClassSubject.init("int", "int");
+              MethodSubject otherInitSubject =
+                  aClassSubject.init("int", parameters.isCfRuntime() ? "java.lang.Object" : "int");
               assertThat(otherInitSubject, isPresent());
               assertThat(otherInitSubject, writesInstanceField(classIdFieldSubject.getDexField()));
 
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/EquivalentConstructorsWithClassIdAndDifferentArgumentAndAssignmentOrderMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/EquivalentConstructorsWithClassIdAndDifferentArgumentAndAssignmentOrderMergingTest.java
index f319d54..c8b807f 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/EquivalentConstructorsWithClassIdAndDifferentArgumentAndAssignmentOrderMergingTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/EquivalentConstructorsWithClassIdAndDifferentArgumentAndAssignmentOrderMergingTest.java
@@ -53,9 +53,10 @@
               ClassSubject aClassSubject = inspector.clazz(A.class);
               assertThat(aClassSubject, isPresent());
               // TODO(b/189296638): Enable constructor merging by changing the constructor
-              // arguments.
+              //  arguments.
               assertEquals(
-                  2, aClassSubject.allMethods(FoundMethodSubject::isInstanceInitializer).size());
+                  parameters.isCfRuntime() ? 4 : 2,
+                  aClassSubject.allMethods(FoundMethodSubject::isInstanceInitializer).size());
             })
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines("CD", "CD");
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/EquivalentConstructorsWithClassIdAndDifferentArgumentOrderMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/EquivalentConstructorsWithClassIdAndDifferentArgumentOrderMergingTest.java
index ba0b57d..19ed979 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/EquivalentConstructorsWithClassIdAndDifferentArgumentOrderMergingTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/EquivalentConstructorsWithClassIdAndDifferentArgumentOrderMergingTest.java
@@ -54,9 +54,10 @@
               assertThat(aClassSubject, isPresent());
 
               // TODO(b/189296638): Enable constructor merging by changing the constructor
-              // arguments.
+              //  arguments.
               assertEquals(
-                  2, aClassSubject.allMethods(FoundMethodSubject::isInstanceInitializer).size());
+                  parameters.isCfRuntime() ? 4 : 2,
+                  aClassSubject.allMethods(FoundMethodSubject::isInstanceInitializer).size());
             })
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines("C0", "D1");
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/EquivalentConstructorsWithClassIdAndExtraNullsMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/EquivalentConstructorsWithClassIdAndExtraNullsMergingTest.java
index 5e15d11..fa03ace 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/EquivalentConstructorsWithClassIdAndExtraNullsMergingTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/EquivalentConstructorsWithClassIdAndExtraNullsMergingTest.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.classmerging.horizontal;
 
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentIf;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 
@@ -53,12 +54,13 @@
               ClassSubject aClassSubject = inspector.clazz(A.class);
               assertThat(aClassSubject, isPresent());
               assertEquals(
-                  2, aClassSubject.allMethods(FoundMethodSubject::isInstanceInitializer).size());
+                  parameters.isCfRuntime() ? 3 : 2,
+                  aClassSubject.allMethods(FoundMethodSubject::isInstanceInitializer).size());
+              assertThat(aClassSubject.init("java.lang.Object", "int"), isPresent());
+              assertThat(aClassSubject.init("java.lang.Object", "int", "int"), isPresent());
               assertThat(
-                  aClassSubject.method("void", "<init>", "java.lang.Object", "int"), isPresent());
-              assertThat(
-                  aClassSubject.method("void", "<init>", "java.lang.Object", "int", "int"),
-                  isPresent());
+                  aClassSubject.init("java.lang.Object", "int", "java.lang.Object"),
+                  isPresentIf(parameters.isCfRuntime()));
             })
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines("C", "0", "C", "D");
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMembersAccessedTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMembersAccessedTest.java
index 0d09fd4..0d912b3 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMembersAccessedTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMembersAccessedTest.java
@@ -26,9 +26,9 @@
         .addProgramClasses(C.class)
         .addProgramClasses(D.class)
         .addKeepMainRule(Main.class)
-        .allowAccessModification(false)
         .enableInliningAnnotations()
         .enableNeverClassInliningAnnotations()
+        .enableNoAccessModificationAnnotationsForMembers()
         .setMinApi(parameters)
         .compile()
         .run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/testclasses/C.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/testclasses/C.java
index f2220c0..003bc93 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/testclasses/C.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/testclasses/C.java
@@ -6,11 +6,14 @@
 
 import com.android.tools.r8.NeverClassInline;
 import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoAccessModification;
 
 @NeverClassInline
 public class C {
-  String field;
 
+  @NoAccessModification String field;
+
+  @NoAccessModification
   protected C(String field) {
     this.field = field;
   }
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexShrinkingFieldsTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexShrinkingFieldsTest.java
index 4a1e82c..121a0f3 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexShrinkingFieldsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexShrinkingFieldsTest.java
@@ -89,7 +89,11 @@
         .setMinApi(parameters)
         .addOptionsModification(options -> options.emitNestAnnotationsInDex = true)
         .compile()
-        .inspect(inspector -> assertEquals(1, inspector.allClasses().size()))
+        // TODO(b/136250031, b/136458109): Allow inlining of constructors into constructors when
+        //  compiling to CF.
+        .inspect(
+            inspector ->
+                assertEquals(parameters.isCfRuntime() ? 2 : 1, inspector.allClasses().size()))
         .run(parameters.getRuntime(), "Host")
         .assertSuccessWithOutput(EXPECTED_OUTPUT);
   }
diff --git a/src/test/java/com/android/tools/r8/gson/GsonDefaultConstructorTest.java b/src/test/java/com/android/tools/r8/gson/GsonDefaultConstructorTest.java
index 9d0b65d..fd6deea 100644
--- a/src/test/java/com/android/tools/r8/gson/GsonDefaultConstructorTest.java
+++ b/src/test/java/com/android/tools/r8/gson/GsonDefaultConstructorTest.java
@@ -11,7 +11,6 @@
 import com.android.tools.r8.ProguardVersion;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.ToolHelper.DexVm.Version;
-import com.android.tools.r8.gson.GsonNoDefaultConstructorTest.Data;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/sync/InlineWithMonitorInConstructorInline.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/sync/InlineWithMonitorInConstructorInline.java
index de3375c..b80dc58 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/sync/InlineWithMonitorInConstructorInline.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/sync/InlineWithMonitorInConstructorInline.java
@@ -4,14 +4,13 @@
 
 package com.android.tools.r8.ir.optimize.inliner.sync;
 
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import org.junit.Test;
@@ -38,6 +37,11 @@
     testForR8(parameters.getBackend())
         .addInnerClasses(InlineWithMonitorInConstructorInline.class)
         .addKeepMainRule(TestClass.class)
+        .addHorizontallyMergedClassesInspector(
+            inspector ->
+                inspector
+                    .assertIsCompleteMergeGroup(Foo.class, Bar.class)
+                    .assertNoOtherClassesMerged())
         .setMinApi(parameters)
         .run(parameters.getRuntime(), TestClass.class)
         .inspect(this::inspect)
@@ -48,13 +52,12 @@
     ClassSubject classSubject = inspector.clazz(TestClass.class);
     assertThat(classSubject, isPresent());
     ClassSubject utilClassSubject = inspector.clazz(Util.class);
-    if (parameters.isCfRuntime()
-        || parameters.getApiLevel().isLessThanOrEqualTo(AndroidApiLevel.M)) {
+    if (parameters.isCfRuntime()) {
       // We disallow merging methods with monitors into constructors which will be class merged
       // on pre M devices, see b/238399429
       assertThat(utilClassSubject, isPresent());
     } else {
-      assertThat(utilClassSubject, not(isPresent()));
+      assertThat(utilClassSubject, isAbsent());
     }
   }
 
diff --git a/src/test/java/com/android/tools/r8/profile/art/completeness/HorizontallyMergedConstructorMethodProfileRewritingTest.java b/src/test/java/com/android/tools/r8/profile/art/completeness/HorizontallyMergedConstructorMethodProfileRewritingTest.java
index 1c3a805..faea413 100644
--- a/src/test/java/com/android/tools/r8/profile/art/completeness/HorizontallyMergedConstructorMethodProfileRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/profile/art/completeness/HorizontallyMergedConstructorMethodProfileRewritingTest.java
@@ -51,14 +51,36 @@
       ClassSubject aClassSubject = inspector.clazz(A.class);
       assertThat(aClassSubject, isPresent());
 
-      MethodSubject syntheticConstructorSubject = aClassSubject.uniqueMethod();
+      MethodSubject syntheticConstructorSubject =
+          aClassSubject.uniqueMethodThatMatches(
+              method -> method.isInstanceInitializer() && method.isSynthetic());
       assertThat(syntheticConstructorSubject, isPresent());
       assertEquals(2, syntheticConstructorSubject.getParameters().size());
       assertEquals(aClassSubject.asTypeSubject(), syntheticConstructorSubject.getParameter(0));
       assertEquals("int", syntheticConstructorSubject.getParameter(1).getTypeName());
 
+      MethodSubject aConstructorSubject =
+          aClassSubject.uniqueMethodThatMatches(
+              method ->
+                  method.isInstanceInitializer()
+                      && !method.isSynthetic()
+                      && method.getProgramMethod().getReference().getArity() == 1);
+      assertThat(syntheticConstructorSubject, isPresent());
+
+      MethodSubject bConstructorSubject =
+          aClassSubject.uniqueMethodThatMatches(
+              method ->
+                  method.isInstanceInitializer()
+                      && !method.isSynthetic()
+                      && method.getProgramMethod().getReference().getArity() == 2);
+      assertThat(syntheticConstructorSubject, isPresent());
+
       profileInspector
-          .assertContainsMethodRule(syntheticConstructorSubject)
+          .assertContainsMethodRules(syntheticConstructorSubject)
+          .applyIf(
+              this == A_CONSTRUCTOR,
+              i -> i.assertContainsMethodRule(aConstructorSubject),
+              i -> i.assertContainsMethodRule(bConstructorSubject))
           .assertContainsNoOtherRules();
     }
   }
@@ -83,7 +105,7 @@
         .addArtProfileForRewriting(artProfileInputOutput.getArtProfile())
         .addHorizontallyMergedClassesInspector(
             inspector -> inspector.assertMergedInto(B.class, A.class).assertNoOtherClassesMerged())
-        .addOptionsModification(InlinerOptions::setOnlyForceInlining)
+        .addOptionsModification(InlinerOptions::disableInlining)
         .addOptionsModification(
             options -> options.callSiteOptimizationOptions().disableOptimization())
         .enableNeverClassInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/profile/art/utils/ArtProfileInspector.java b/src/test/java/com/android/tools/r8/profile/art/utils/ArtProfileInspector.java
index 3b75886..e6f9092 100644
--- a/src/test/java/com/android/tools/r8/profile/art/utils/ArtProfileInspector.java
+++ b/src/test/java/com/android/tools/r8/profile/art/utils/ArtProfileInspector.java
@@ -30,9 +30,22 @@
     this.artProfile = artProfile;
   }
 
-  public ArtProfileInspector applyIf(boolean condition, Consumer<ArtProfileInspector> fn) {
+  public ArtProfileInspector applyIf(
+      boolean condition, Consumer<ArtProfileInspector> thenConsumer) {
     if (condition) {
-      fn.accept(this);
+      thenConsumer.accept(this);
+    }
+    return this;
+  }
+
+  public ArtProfileInspector applyIf(
+      boolean condition,
+      Consumer<ArtProfileInspector> thenConsumer,
+      Consumer<ArtProfileInspector> elseConsumer) {
+    if (condition) {
+      thenConsumer.accept(this);
+    } else {
+      elseConsumer.accept(this);
     }
     return this;
   }
diff --git a/src/test/java/com/android/tools/r8/shaking/KeepAnnotatedMemberTest.java b/src/test/java/com/android/tools/r8/shaking/KeepAnnotatedMemberTest.java
index c0211ef..86f4fd6 100644
--- a/src/test/java/com/android/tools/r8/shaking/KeepAnnotatedMemberTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/KeepAnnotatedMemberTest.java
@@ -252,7 +252,8 @@
             .apply(this::suppressZipFileAssignmentsToJavaLangAutoCloseable)
             .compile()
             .graphInspector();
-    assertRetainedClassesEqual(referenceInspector, ifThenKeepClassesWithMembersInspector);
+    assertRetainedClassesEqual(
+        referenceInspector, ifThenKeepClassesWithMembersInspector, true, true);
 
     GraphInspector ifHasMemberThenKeepClassInspector =
         testForR8(Backend.CF)
@@ -273,7 +274,7 @@
             .apply(this::suppressZipFileAssignmentsToJavaLangAutoCloseable)
             .compile()
             .graphInspector();
-    assertRetainedClassesEqual(referenceInspector, ifHasMemberThenKeepClassInspector);
+    assertRetainedClassesEqual(referenceInspector, ifHasMemberThenKeepClassInspector, true, true);
   }
 
   private void configureHorizontalClassMerging(R8FullTestBuilder testBuilder) {
diff --git a/src/test/java/com/android/tools/r8/shaking/ParameterTypeTest.java b/src/test/java/com/android/tools/r8/shaking/ParameterTypeTest.java
index da8944c..dd7d5da 100644
--- a/src/test/java/com/android/tools/r8/shaking/ParameterTypeTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ParameterTypeTest.java
@@ -141,8 +141,7 @@
             .inspector();
 
     ClassSubject superInterface1 = inspector.clazz(B112452064SuperInterface1.class);
-    assertThat(
-        superInterface1, isAbsentIf(enableUnusedInterfaceRemoval && enableVerticalClassMerging));
+    assertThat(superInterface1, isAbsentIf(enableVerticalClassMerging));
 
     MethodSubject foo = superInterface1.uniqueMethodWithOriginalName("foo");
     assertThat(foo, isAbsent());
diff --git a/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java b/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
index e69bb0f..47d969c 100644
--- a/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
+++ b/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
@@ -139,10 +139,6 @@
     return syntheticClass(reference, naming.RECORD_HELPER, id);
   }
 
-  public static ClassReference syntheticTwrCloseResourceClass(Class<?> clazz, int id) {
-    return syntheticClass(clazz, naming.TWR_CLOSE_RESOURCE, id);
-  }
-
   public static ClassReference syntheticTwrCloseResourceClass(ClassReference reference, int id) {
     return syntheticClass(reference, naming.TWR_CLOSE_RESOURCE, id);
   }
@@ -302,12 +298,6 @@
         reference, Phase.EXTERNAL, naming.NON_FIXED_INIT_TYPE_ARGUMENT);
   }
 
-  public static boolean isHorizontalInitializerTypeArgument(ClassReference reference) {
-    return SyntheticNaming.isSynthetic(reference, null, naming.HORIZONTAL_INIT_TYPE_ARGUMENT_1)
-        || SyntheticNaming.isSynthetic(reference, null, naming.HORIZONTAL_INIT_TYPE_ARGUMENT_2)
-        || SyntheticNaming.isSynthetic(reference, null, naming.HORIZONTAL_INIT_TYPE_ARGUMENT_3);
-  }
-
   public static boolean isWrapper(ClassReference reference) {
     return SyntheticNaming.isSynthetic(reference, null, naming.WRAPPER)
         || SyntheticNaming.isSynthetic(reference, null, naming.VIVIFIED_WRAPPER);