Revert "Extend single caller inliner to all invoke types"
This reverts commit 9d03af113168282da5454691f9605944f8f30529.
Reason for revert: Test failures
Change-Id: I0d6204a7b72fff7039a770a599038b26ae9cb646
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 7cabfb6..261c4e6 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -33,6 +33,7 @@
 import com.android.tools.r8.graph.PrunedItems;
 import com.android.tools.r8.graph.SubtypingInfo;
 import com.android.tools.r8.graph.analysis.ClassInitializerAssertionEnablingAnalysis;
+import com.android.tools.r8.graph.analysis.InitializedClassesInInstanceMethodsAnalysis;
 import com.android.tools.r8.horizontalclassmerging.HorizontalClassMerger;
 import com.android.tools.r8.inspector.internal.InspectorImpl;
 import com.android.tools.r8.ir.conversion.IRConverter;
@@ -1140,6 +1141,9 @@
             appView, profileCollectionAdditions, executorService, subtypingInfo);
     enqueuer.setKeepDeclarations(keepDeclarations);
     enqueuer.setAnnotationRemoverBuilder(annotationRemoverBuilder);
+    if (appView.options().enableInitializedClassesInInstanceMethodsAnalysis) {
+      enqueuer.registerAnalysis(new InitializedClassesInInstanceMethodsAnalysis(appView));
+    }
     if (AssertionsRewriter.isEnabled(appView.options())) {
       ClassInitializerAssertionEnablingAnalysis analysis =
           new ClassInitializerAssertionEnablingAnalysis(
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/InitializedClassesInInstanceMethodsAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/InitializedClassesInInstanceMethodsAnalysis.java
index 42ca59e..d849002 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/InitializedClassesInInstanceMethodsAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/InitializedClassesInInstanceMethodsAnalysis.java
@@ -63,16 +63,6 @@
     this.appView = appView;
   }
 
-  public static void register(
-      AppView<? extends AppInfoWithClassHierarchy> appView, Enqueuer enqueuer) {
-    if (appView.options().enableInitializedClassesInInstanceMethodsAnalysis
-        && enqueuer.getMode().isInitialTreeShaking()) {
-      enqueuer.registerAnalysis(new InitializedClassesInInstanceMethodsAnalysis(appView));
-    } else {
-      appView.setInitializedClassesInInstanceMethods(null);
-    }
-  }
-
   @Override
   public void processNewlyInstantiatedClass(
       DexProgramClass clazz, ProgramMethod context, EnqueuerWorklist worklist) {
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorCodeScanner.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorCodeScanner.java
index 1f95169..aa82269 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorCodeScanner.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorCodeScanner.java
@@ -66,7 +66,6 @@
 import com.android.tools.r8.utils.Timing;
 import com.google.common.collect.Sets;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.IdentityHashMap;
 import java.util.List;
 import java.util.Map;
@@ -129,7 +128,7 @@
     this.reprocessingCriteriaCollection = reprocessingCriteriaCollection;
   }
 
-  public synchronized void addMonomorphicVirtualMethods(Collection<DexMethod> extension) {
+  public synchronized void addMonomorphicVirtualMethods(Set<DexMethod> extension) {
     monomorphicVirtualMethods.addAll(extension);
   }
 
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/VirtualRootMethodsAnalysis.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/VirtualRootMethodsAnalysis.java
index 3a9e9c6..dd7eac12 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/VirtualRootMethodsAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/VirtualRootMethodsAnalysis.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.optimize.argumentpropagation.codescanner;
 
+import static com.android.tools.r8.utils.MapUtils.ignoreKey;
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethod;
@@ -11,11 +12,16 @@
 import com.android.tools.r8.graph.ImmediateProgramSubtypingInfo;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagatorCodeScanner;
+import com.android.tools.r8.optimize.argumentpropagation.utils.DepthFirstTopDownClassHierarchyTraversal;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.google.common.collect.Iterables;
-import java.util.ArrayList;
+import com.android.tools.r8.utils.collections.DexMethodSignatureMap;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
+import com.google.common.collect.Sets;
 import java.util.Collection;
+import java.util.IdentityHashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.function.Consumer;
 
 /**
@@ -25,7 +31,83 @@
  * <p>The analysis can be used to easily mark effectively final classes and methods as final, and
  * therefore does this as a side effect.
  */
-public class VirtualRootMethodsAnalysis extends VirtualRootMethodsAnalysisBase {
+public class VirtualRootMethodsAnalysis extends DepthFirstTopDownClassHierarchyTraversal {
+
+  static class VirtualRootMethod {
+
+    private final VirtualRootMethod parent;
+    private final ProgramMethod root;
+    private final ProgramMethodSet overrides = ProgramMethodSet.create();
+
+    VirtualRootMethod(ProgramMethod root) {
+      this(root, null);
+    }
+
+    VirtualRootMethod(ProgramMethod root, VirtualRootMethod parent) {
+      assert root != null;
+      this.parent = parent;
+      this.root = root;
+    }
+
+    void addOverride(ProgramMethod override) {
+      assert override.getDefinition() != root.getDefinition();
+      assert override.getMethodSignature().equals(root.getMethodSignature());
+      overrides.add(override);
+      if (hasParent()) {
+        getParent().addOverride(override);
+      }
+    }
+
+    boolean hasParent() {
+      return parent != null;
+    }
+
+    VirtualRootMethod getParent() {
+      return parent;
+    }
+
+    ProgramMethod getRoot() {
+      return root;
+    }
+
+    ProgramMethod getSingleNonAbstractMethod() {
+      ProgramMethod singleNonAbstractMethod = root.getAccessFlags().isAbstract() ? null : root;
+      for (ProgramMethod override : overrides) {
+        if (!override.getAccessFlags().isAbstract()) {
+          if (singleNonAbstractMethod != null) {
+            // Not a single non-abstract method.
+            return null;
+          }
+          singleNonAbstractMethod = override;
+        }
+      }
+      assert singleNonAbstractMethod == null
+          || !singleNonAbstractMethod.getAccessFlags().isAbstract();
+      return singleNonAbstractMethod;
+    }
+
+    void forEach(Consumer<ProgramMethod> consumer) {
+      consumer.accept(root);
+      overrides.forEach(consumer);
+    }
+
+    boolean hasOverrides() {
+      return !overrides.isEmpty();
+    }
+
+    boolean isInterfaceMethodWithSiblings() {
+      // TODO(b/190154391): Conservatively returns true for all interface methods, but should only
+      //  return true for those with siblings.
+      return root.getHolder().isInterface();
+    }
+  }
+
+  private final Map<DexProgramClass, DexMethodSignatureMap<VirtualRootMethod>>
+      virtualRootMethodsPerClass = new IdentityHashMap<>();
+
+  private final Set<DexMethod> monomorphicVirtualMethods = Sets.newIdentityHashSet();
+
+  private final Map<DexMethod, DexMethod> virtualRootMethods = new IdentityHashMap<>();
 
   public VirtualRootMethodsAnalysis(
       AppView<AppInfoWithLiveness> appView, ImmediateProgramSubtypingInfo immediateSubtypingInfo) {
@@ -39,23 +121,11 @@
     run(stronglyConnectedComponent);
 
     // Commit the result to the code scanner.
-    List<DexMethod> monomorphicVirtualMethodReferences =
-        new ArrayList<>(
-            monomorphicVirtualRootMethods.size() + monomorphicVirtualNonRootMethods.size());
-    for (ProgramMethod method :
-        Iterables.concat(monomorphicVirtualRootMethods, monomorphicVirtualNonRootMethods)) {
-      monomorphicVirtualMethodReferences.add(method.getReference());
-    }
-    codeScanner.addMonomorphicVirtualMethods(monomorphicVirtualMethodReferences);
+    codeScanner.addMonomorphicVirtualMethods(monomorphicVirtualMethods);
     codeScanner.addVirtualRootMethods(virtualRootMethods);
   }
 
   @Override
-  protected void acceptVirtualMethod(ProgramMethod method, VirtualRootMethod virtualRootMethod) {
-    promoteToFinalIfPossible(method, virtualRootMethod);
-  }
-
-  @Override
   public void forEachSubClass(DexProgramClass clazz, Consumer<DexProgramClass> consumer) {
     List<DexProgramClass> subclasses = immediateSubtypingInfo.getSubclasses(clazz);
     if (subclasses.isEmpty()) {
@@ -65,6 +135,78 @@
     }
   }
 
+  @Override
+  public void visit(DexProgramClass clazz) {
+    DexMethodSignatureMap<VirtualRootMethod> state = computeVirtualRootMethodsState(clazz);
+    virtualRootMethodsPerClass.put(clazz, state);
+  }
+
+  private DexMethodSignatureMap<VirtualRootMethod> computeVirtualRootMethodsState(
+      DexProgramClass clazz) {
+    DexMethodSignatureMap<VirtualRootMethod> virtualRootMethodsForClass =
+        DexMethodSignatureMap.create();
+    immediateSubtypingInfo.forEachImmediateProgramSuperClass(
+        clazz,
+        superclass -> {
+          DexMethodSignatureMap<VirtualRootMethod> virtualRootMethodsForSuperclass =
+              virtualRootMethodsPerClass.get(superclass);
+          virtualRootMethodsForSuperclass.forEach(
+              (signature, info) ->
+                  virtualRootMethodsForClass.computeIfAbsent(
+                      signature, ignoreKey(() -> new VirtualRootMethod(info.getRoot(), info))));
+        });
+    clazz.forEachProgramVirtualMethod(
+        method -> {
+          if (virtualRootMethodsForClass.containsKey(method)) {
+            virtualRootMethodsForClass.get(method).getParent().addOverride(method);
+          } else {
+            virtualRootMethodsForClass.put(method, new VirtualRootMethod(method));
+          }
+        });
+    return virtualRootMethodsForClass;
+  }
+
+  @Override
+  public void prune(DexProgramClass clazz) {
+    // Record the overrides for each virtual method that is rooted at this class.
+    DexMethodSignatureMap<VirtualRootMethod> virtualRootMethodsForClass =
+        virtualRootMethodsPerClass.remove(clazz);
+    clazz.forEachProgramVirtualMethod(
+        rootCandidate -> {
+          VirtualRootMethod virtualRootMethod =
+              virtualRootMethodsForClass.remove(rootCandidate.getMethodSignature());
+          promoteToFinalIfPossible(rootCandidate, virtualRootMethod);
+          if (!rootCandidate.isStructurallyEqualTo(virtualRootMethod.getRoot())) {
+            return;
+          }
+          boolean isMonomorphicVirtualMethod =
+              !clazz.isInterface() && !virtualRootMethod.hasOverrides();
+          if (isMonomorphicVirtualMethod) {
+            monomorphicVirtualMethods.add(rootCandidate.getReference());
+          } else {
+            ProgramMethod singleNonAbstractMethod = virtualRootMethod.getSingleNonAbstractMethod();
+            if (singleNonAbstractMethod != null
+                && !virtualRootMethod.isInterfaceMethodWithSiblings()) {
+              virtualRootMethod.forEach(
+                  method -> {
+                    // Interface methods can have siblings and can therefore not be mapped to their
+                    // unique non-abstract implementation, unless the interface method does not have
+                    // any siblings.
+                    virtualRootMethods.put(
+                        method.getReference(), singleNonAbstractMethod.getReference());
+                  });
+              if (!singleNonAbstractMethod.getHolder().isInterface()) {
+                monomorphicVirtualMethods.add(singleNonAbstractMethod.getReference());
+              }
+            } else {
+              virtualRootMethod.forEach(
+                  method ->
+                      virtualRootMethods.put(method.getReference(), rootCandidate.getReference()));
+            }
+          }
+        });
+  }
+
   private void promoteToFinalIfPossible(DexProgramClass clazz) {
     if (!appView.testing().disableMarkingClassesFinal
         && !clazz.isAbstract()
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/VirtualRootMethodsAnalysisBase.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/VirtualRootMethodsAnalysisBase.java
deleted file mode 100644
index b5f1374..0000000
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/VirtualRootMethodsAnalysisBase.java
+++ /dev/null
@@ -1,184 +0,0 @@
-// 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.optimize.argumentpropagation.codescanner;
-
-import static com.android.tools.r8.utils.MapUtils.ignoreKey;
-
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.ImmediateProgramSubtypingInfo;
-import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.optimize.argumentpropagation.utils.DepthFirstTopDownClassHierarchyTraversal;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.collections.DexMethodSignatureMap;
-import com.android.tools.r8.utils.collections.ProgramMethodSet;
-import java.util.IdentityHashMap;
-import java.util.Map;
-import java.util.function.Consumer;
-
-/**
- * Computes the set of virtual methods for which we can use a monomorphic method state as well as
- * the mapping from virtual methods to their representative root methods.
- */
-public class VirtualRootMethodsAnalysisBase extends DepthFirstTopDownClassHierarchyTraversal {
-
-  protected static class VirtualRootMethod {
-
-    private final VirtualRootMethod parent;
-    private final ProgramMethod root;
-    private final ProgramMethodSet overrides = ProgramMethodSet.create();
-
-    VirtualRootMethod(ProgramMethod root) {
-      this(root, null);
-    }
-
-    VirtualRootMethod(ProgramMethod root, VirtualRootMethod parent) {
-      assert root != null;
-      this.parent = parent;
-      this.root = root;
-    }
-
-    void addOverride(ProgramMethod override) {
-      assert override.getDefinition() != root.getDefinition();
-      assert override.getMethodSignature().equals(root.getMethodSignature());
-      overrides.add(override);
-      if (hasParent()) {
-        getParent().addOverride(override);
-      }
-    }
-
-    boolean hasParent() {
-      return parent != null;
-    }
-
-    VirtualRootMethod getParent() {
-      return parent;
-    }
-
-    ProgramMethod getRoot() {
-      return root;
-    }
-
-    ProgramMethod getSingleNonAbstractMethod() {
-      ProgramMethod singleNonAbstractMethod = root.getAccessFlags().isAbstract() ? null : root;
-      for (ProgramMethod override : overrides) {
-        if (!override.getAccessFlags().isAbstract()) {
-          if (singleNonAbstractMethod != null) {
-            // Not a single non-abstract method.
-            return null;
-          }
-          singleNonAbstractMethod = override;
-        }
-      }
-      assert singleNonAbstractMethod == null
-          || !singleNonAbstractMethod.getAccessFlags().isAbstract();
-      return singleNonAbstractMethod;
-    }
-
-    void forEach(Consumer<ProgramMethod> consumer) {
-      consumer.accept(root);
-      overrides.forEach(consumer);
-    }
-
-    boolean hasOverrides() {
-      return !overrides.isEmpty();
-    }
-
-    boolean isInterfaceMethodWithSiblings() {
-      // TODO(b/190154391): Conservatively returns true for all interface methods, but should only
-      //  return true for those with siblings.
-      return root.getHolder().isInterface();
-    }
-  }
-
-  private final Map<DexProgramClass, DexMethodSignatureMap<VirtualRootMethod>>
-      virtualRootMethodsPerClass = new IdentityHashMap<>();
-
-  protected final ProgramMethodSet monomorphicVirtualRootMethods = ProgramMethodSet.create();
-  protected final ProgramMethodSet monomorphicVirtualNonRootMethods = ProgramMethodSet.create();
-
-  protected final Map<DexMethod, DexMethod> virtualRootMethods = new IdentityHashMap<>();
-
-  protected VirtualRootMethodsAnalysisBase(
-      AppView<AppInfoWithLiveness> appView, ImmediateProgramSubtypingInfo immediateSubtypingInfo) {
-    super(appView, immediateSubtypingInfo);
-  }
-
-  @Override
-  public void visit(DexProgramClass clazz) {
-    DexMethodSignatureMap<VirtualRootMethod> state = computeVirtualRootMethodsState(clazz);
-    virtualRootMethodsPerClass.put(clazz, state);
-  }
-
-  private DexMethodSignatureMap<VirtualRootMethod> computeVirtualRootMethodsState(
-      DexProgramClass clazz) {
-    DexMethodSignatureMap<VirtualRootMethod> virtualRootMethodsForClass =
-        DexMethodSignatureMap.create();
-    immediateSubtypingInfo.forEachImmediateProgramSuperClass(
-        clazz,
-        superclass -> {
-          DexMethodSignatureMap<VirtualRootMethod> virtualRootMethodsForSuperclass =
-              virtualRootMethodsPerClass.get(superclass);
-          virtualRootMethodsForSuperclass.forEach(
-              (signature, info) ->
-                  virtualRootMethodsForClass.computeIfAbsent(
-                      signature, ignoreKey(() -> new VirtualRootMethod(info.getRoot(), info))));
-        });
-    clazz.forEachProgramVirtualMethod(
-        method -> {
-          if (virtualRootMethodsForClass.containsKey(method)) {
-            virtualRootMethodsForClass.get(method).getParent().addOverride(method);
-          } else {
-            virtualRootMethodsForClass.put(method, new VirtualRootMethod(method));
-          }
-        });
-    return virtualRootMethodsForClass;
-  }
-
-  @Override
-  public void prune(DexProgramClass clazz) {
-    // Record the overrides for each virtual method that is rooted at this class.
-    DexMethodSignatureMap<VirtualRootMethod> virtualRootMethodsForClass =
-        virtualRootMethodsPerClass.remove(clazz);
-    clazz.forEachProgramVirtualMethod(
-        rootCandidate -> {
-          VirtualRootMethod virtualRootMethod =
-              virtualRootMethodsForClass.remove(rootCandidate.getMethodSignature());
-          acceptVirtualMethod(rootCandidate, virtualRootMethod);
-          if (!rootCandidate.isStructurallyEqualTo(virtualRootMethod.getRoot())) {
-            return;
-          }
-          boolean isMonomorphicVirtualMethod =
-              !clazz.isInterface() && !virtualRootMethod.hasOverrides();
-          if (isMonomorphicVirtualMethod) {
-            monomorphicVirtualRootMethods.add(rootCandidate);
-          } else {
-            ProgramMethod singleNonAbstractMethod = virtualRootMethod.getSingleNonAbstractMethod();
-            if (singleNonAbstractMethod != null
-                && !virtualRootMethod.isInterfaceMethodWithSiblings()) {
-              virtualRootMethod.forEach(
-                  method -> {
-                    // Interface methods can have siblings and can therefore not be mapped to their
-                    // unique non-abstract implementation, unless the interface method does not have
-                    // any siblings.
-                    virtualRootMethods.put(
-                        method.getReference(), singleNonAbstractMethod.getReference());
-                  });
-              if (!singleNonAbstractMethod.getHolder().isInterface()) {
-                monomorphicVirtualNonRootMethods.add(singleNonAbstractMethod);
-              }
-            } else {
-              virtualRootMethod.forEach(
-                  method ->
-                      virtualRootMethods.put(method.getReference(), rootCandidate.getReference()));
-            }
-          }
-        });
-  }
-
-  protected void acceptVirtualMethod(ProgramMethod method, VirtualRootMethod virtualRootMethod) {
-    // Intentionally empty.
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/optimize/singlecaller/MonomorphicVirtualMethodsAnalysis.java b/src/main/java/com/android/tools/r8/optimize/singlecaller/MonomorphicVirtualMethodsAnalysis.java
deleted file mode 100644
index 8d589a8..0000000
--- a/src/main/java/com/android/tools/r8/optimize/singlecaller/MonomorphicVirtualMethodsAnalysis.java
+++ /dev/null
@@ -1,54 +0,0 @@
-// 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.optimize.singlecaller;
-
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.ImmediateProgramSubtypingInfo;
-import com.android.tools.r8.optimize.argumentpropagation.codescanner.VirtualRootMethodsAnalysisBase;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.ThreadUtils;
-import com.android.tools.r8.utils.collections.ProgramMethodSet;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-
-public class MonomorphicVirtualMethodsAnalysis extends VirtualRootMethodsAnalysisBase {
-
-  public MonomorphicVirtualMethodsAnalysis(
-      AppView<AppInfoWithLiveness> appView, ImmediateProgramSubtypingInfo immediateSubtypingInfo) {
-    super(appView, immediateSubtypingInfo);
-  }
-
-  public static ProgramMethodSet computeMonomorphicVirtualRootMethods(
-      AppView<AppInfoWithLiveness> appView,
-      ImmediateProgramSubtypingInfo immediateSubtypingInfo,
-      List<Set<DexProgramClass>> stronglyConnectedComponents,
-      ExecutorService executorService)
-      throws ExecutionException {
-    ProgramMethodSet monomorphicVirtualMethods = ProgramMethodSet.createConcurrent();
-    ThreadUtils.processItems(
-        stronglyConnectedComponents,
-        stronglyConnectedComponent -> {
-          ProgramMethodSet monomorphicVirtualMethodsInComponent =
-              computeMonomorphicVirtualRootMethodsInComponent(
-                  appView, immediateSubtypingInfo, stronglyConnectedComponent);
-          monomorphicVirtualMethods.addAll(monomorphicVirtualMethodsInComponent);
-        },
-        appView.options().getThreadingModule(),
-        executorService);
-    return monomorphicVirtualMethods;
-  }
-
-  private static ProgramMethodSet computeMonomorphicVirtualRootMethodsInComponent(
-      AppView<AppInfoWithLiveness> appView,
-      ImmediateProgramSubtypingInfo immediateSubtypingInfo,
-      Set<DexProgramClass> stronglyConnectedComponent) {
-    MonomorphicVirtualMethodsAnalysis analysis =
-        new MonomorphicVirtualMethodsAnalysis(appView, immediateSubtypingInfo);
-    analysis.run(stronglyConnectedComponent);
-    return analysis.monomorphicVirtualRootMethods;
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/optimize/singlecaller/SingleCallerInliner.java b/src/main/java/com/android/tools/r8/optimize/singlecaller/SingleCallerInliner.java
index 5ec48d5..10731fb 100644
--- a/src/main/java/com/android/tools/r8/optimize/singlecaller/SingleCallerInliner.java
+++ b/src/main/java/com/android/tools/r8/optimize/singlecaller/SingleCallerInliner.java
@@ -7,8 +7,6 @@
 
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.ImmediateProgramSubtypingInfo;
 import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.PrunedItems;
@@ -30,15 +28,13 @@
 import com.android.tools.r8.ir.optimize.inliner.NopWhyAreYouNotInliningReporter;
 import com.android.tools.r8.ir.optimize.inliner.WhyAreYouNotInliningReporter;
 import com.android.tools.r8.lightir.LirCode;
-import com.android.tools.r8.optimize.argumentpropagation.utils.ProgramClassesBidirectedGraph;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.ThreadUtils;
 import com.android.tools.r8.utils.Timing;
 import com.android.tools.r8.utils.collections.ProgramMethodMap;
 import com.android.tools.r8.utils.collections.ProgramMethodSet;
 import java.util.Deque;
-import java.util.List;
-import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 
@@ -60,36 +56,22 @@
   }
 
   private boolean shouldRun() {
-    return appView.options().getSingleCallerInlinerOptions().isEnabled();
+    InternalOptions options = appView.options();
+    return !options.debug
+        && !options.intermediate
+        && options.isOptimizing()
+        && options.isShrinking();
   }
 
   public void run(ExecutorService executorService) throws ExecutionException {
-    ProgramMethodSet monomorphicVirtualMethods =
-        computeMonomorphicVirtualRootMethods(executorService);
     ProgramMethodMap<ProgramMethod> singleCallerMethods =
-        new SingleCallerScanner(appView, monomorphicVirtualMethods)
-            .getSingleCallerMethods(executorService);
+        new SingleCallerScanner(appView).getSingleCallerMethods(executorService);
     Inliner inliner = new SingleCallerInlinerImpl(appView, singleCallerMethods);
     processCallees(inliner, singleCallerMethods, executorService);
     performInlining(inliner, singleCallerMethods, executorService);
     pruneItems(singleCallerMethods, executorService);
   }
 
-  // We only allow single caller inlining of "direct dispatch virtual methods". We currently only
-  // deal with (rooted) virtual methods that do not override abstract/interface methods. In order to
-  // also deal with virtual methods that override abstract/interface methods we would need to record
-  // calls to the abstract/interface methods as calls to the non-abstract virtual method.
-  private ProgramMethodSet computeMonomorphicVirtualRootMethods(ExecutorService executorService)
-      throws ExecutionException {
-    ImmediateProgramSubtypingInfo immediateSubtypingInfo =
-        ImmediateProgramSubtypingInfo.create(appView);
-    List<Set<DexProgramClass>> stronglyConnectedComponents =
-        new ProgramClassesBidirectedGraph(appView, immediateSubtypingInfo)
-            .computeStronglyConnectedComponents();
-    return MonomorphicVirtualMethodsAnalysis.computeMonomorphicVirtualRootMethods(
-        appView, immediateSubtypingInfo, stronglyConnectedComponents, executorService);
-  }
-
   private void processCallees(
       Inliner inliner,
       ProgramMethodMap<ProgramMethod> singleCallerMethods,
diff --git a/src/main/java/com/android/tools/r8/optimize/singlecaller/SingleCallerInlinerOptions.java b/src/main/java/com/android/tools/r8/optimize/singlecaller/SingleCallerInlinerOptions.java
deleted file mode 100644
index fa8d1f0..0000000
--- a/src/main/java/com/android/tools/r8/optimize/singlecaller/SingleCallerInlinerOptions.java
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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.optimize.singlecaller;
-
-import com.android.tools.r8.utils.InternalOptions;
-
-public class SingleCallerInlinerOptions {
-
-  private final InternalOptions options;
-
-  private boolean enable = true;
-
-  public SingleCallerInlinerOptions(InternalOptions options) {
-    this.options = options;
-  }
-
-  public boolean isEnabled() {
-    return enable
-        && !options.debug
-        && !options.intermediate
-        && options.isOptimizing()
-        && options.isShrinking();
-  }
-
-  public void setEnable(boolean enable) {
-    this.enable = enable;
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/optimize/singlecaller/SingleCallerScanner.java b/src/main/java/com/android/tools/r8/optimize/singlecaller/SingleCallerScanner.java
index 3cbfd70..f71e82f 100644
--- a/src/main/java/com/android/tools/r8/optimize/singlecaller/SingleCallerScanner.java
+++ b/src/main/java/com/android/tools/r8/optimize/singlecaller/SingleCallerScanner.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.optimize.singlecaller;
 
+import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
 import static com.android.tools.r8.utils.MapUtils.ignoreKey;
 
 import com.android.tools.r8.graph.AppView;
@@ -16,7 +17,7 @@
 import com.android.tools.r8.lightir.LirCode;
 import com.android.tools.r8.lightir.LirConstant;
 import com.android.tools.r8.lightir.LirInstructionView;
-import com.android.tools.r8.lightir.LirOpcodeUtils;
+import com.android.tools.r8.lightir.LirOpcodes;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.ObjectUtils;
 import com.android.tools.r8.utils.ThreadUtils;
@@ -30,22 +31,15 @@
   private static final ProgramMethod MULTIPLE_CALLERS = ProgramMethod.createSentinel();
 
   private final AppView<AppInfoWithLiveness> appView;
-  private final ProgramMethodSet monomorphicVirtualMethods;
 
-  SingleCallerScanner(
-      AppView<AppInfoWithLiveness> appView, ProgramMethodSet monomorphicVirtualMethods) {
+  SingleCallerScanner(AppView<AppInfoWithLiveness> appView) {
     this.appView = appView;
-    this.monomorphicVirtualMethods = monomorphicVirtualMethods;
   }
 
   public ProgramMethodMap<ProgramMethod> getSingleCallerMethods(ExecutorService executorService)
       throws ExecutionException {
     ProgramMethodMap<ProgramMethod> singleCallerMethodCandidates =
         traceConstantPools(executorService);
-    singleCallerMethodCandidates.removeIf(
-        (callee, caller) ->
-            callee.getDefinition().isLibraryMethodOverride().isPossiblyTrue()
-                || appView.appInfo().isNeverInlineDueToSingleCallerMethod(callee));
     return traceInstructions(singleCallerMethodCandidates, executorService);
   }
 
@@ -139,13 +133,28 @@
     if (referencedMethod.getHolderType().isArrayType()) {
       return;
     }
-    ProgramMethod resolvedMethod =
-        appView
-            .appInfo()
-            .unsafeResolveMethodDueToDexFormat(referencedMethod)
-            .getResolvedProgramMethod();
-    if (resolvedMethod != null) {
-      recordCallEdge(method, resolvedMethod, threadLocalSingleCallerMethods);
+    if (referencedMethod.isInstanceInitializer(appView.dexItemFactory())) {
+      ProgramMethod referencedProgramMethod =
+          appView
+              .appInfo()
+              .unsafeResolveMethodDueToDexFormat(referencedMethod)
+              .getResolvedProgramMethod();
+      if (referencedProgramMethod != null) {
+        recordCallEdge(method, referencedProgramMethod, threadLocalSingleCallerMethods);
+      }
+    } else {
+      DexProgramClass referencedProgramMethodHolder =
+          asProgramClassOrNull(
+              appView
+                  .appInfo()
+                  .definitionForWithoutExistenceAssert(referencedMethod.getHolderType()));
+      ProgramMethod referencedProgramMethod =
+          referencedMethod.lookupOnProgramClass(referencedProgramMethodHolder);
+      if (referencedProgramMethod != null
+          && referencedProgramMethod.getAccessFlags().isPrivate()
+          && !referencedProgramMethod.getAccessFlags().isStatic()) {
+        recordCallEdge(method, referencedProgramMethod, threadLocalSingleCallerMethods);
+      }
     }
   }
 
@@ -172,7 +181,10 @@
           ProgramMethodMap<Integer> counters = ProgramMethodMap.create();
           for (LirInstructionView view : code) {
             int opcode = view.getOpcode();
-            if (!LirOpcodeUtils.isInvokeMethod(opcode)) {
+            if (opcode != LirOpcodes.INVOKEDIRECT
+                && opcode != LirOpcodes.INVOKEDIRECT_ITF
+                // JDK 17 generates invokevirtual to private methods.
+                && opcode != LirOpcodes.INVOKEVIRTUAL) {
               continue;
             }
             DexMethod invokedMethod =
@@ -180,17 +192,11 @@
             ProgramMethod resolvedMethod =
                 appView
                     .appInfo()
-                    .resolveMethod(
-                        invokedMethod, LirOpcodeUtils.getInterfaceBitFromInvokeOpcode(opcode))
+                    .resolveMethod(invokedMethod, opcode == LirOpcodes.INVOKEDIRECT_ITF)
                     .getResolvedProgramMethod();
-            if (resolvedMethod == null || !callees.contains(resolvedMethod)) {
-              continue;
+            if (resolvedMethod != null && callees.contains(resolvedMethod)) {
+              counters.put(resolvedMethod, counters.getOrDefault(resolvedMethod, 0) + 1);
             }
-            if (resolvedMethod.getAccessFlags().belongsToVirtualPool()
-                && !monomorphicVirtualMethods.contains(resolvedMethod)) {
-              continue;
-            }
-            counters.put(resolvedMethod, counters.getOrDefault(resolvedMethod, 0) + 1);
           }
           callees.forEach(
               (callee) -> {
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 2acfff2..7cc38a2 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -98,7 +98,6 @@
 import com.android.tools.r8.graph.analysis.EnqueuerNewInstanceAnalysis;
 import com.android.tools.r8.graph.analysis.EnqueuerTypeAccessAnalysis;
 import com.android.tools.r8.graph.analysis.GetArrayOfMissingTypeVerifyErrorWorkaround;
-import com.android.tools.r8.graph.analysis.InitializedClassesInInstanceMethodsAnalysis;
 import com.android.tools.r8.graph.analysis.InvokeVirtualToInterfaceVerifyErrorWorkaround;
 import com.android.tools.r8.graph.analysis.ResourceAccessAnalysis;
 import com.android.tools.r8.ir.analysis.proto.ProtoEnqueuerUseRegistry;
@@ -519,7 +518,6 @@
       appView.getResourceShrinkerState().setEnqueuerCallback(this::recordReferenceFromResources);
     }
     if (mode.isTreeShaking()) {
-      InitializedClassesInInstanceMethodsAnalysis.register(appView, this);
       GetArrayOfMissingTypeVerifyErrorWorkaround.register(appView, this);
       InvokeVirtualToInterfaceVerifyErrorWorkaround.register(appView, this);
       if (options.protoShrinking().enableGeneratedMessageLiteShrinking) {
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 1ed80f2..27b7af9 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -84,7 +84,6 @@
 import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagatorEventConsumer;
 import com.android.tools.r8.optimize.compose.JetpackComposeOptions;
 import com.android.tools.r8.optimize.redundantbridgeremoval.RedundantBridgeRemovalOptions;
-import com.android.tools.r8.optimize.singlecaller.SingleCallerInlinerOptions;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.position.Position;
 import com.android.tools.r8.profile.art.ArtProfileOptions;
@@ -933,8 +932,6 @@
   private final CfCodeAnalysisOptions cfCodeAnalysisOptions = new CfCodeAnalysisOptions();
   private final ClassInlinerOptions classInlinerOptions = new ClassInlinerOptions();
   private final InlinerOptions inlinerOptions = new InlinerOptions(this);
-  private final SingleCallerInlinerOptions singleCallerInlinerOptions =
-      new SingleCallerInlinerOptions(this);
   private final JetpackComposeOptions jetpackComposeOptions = new JetpackComposeOptions(this);
   private final HorizontalClassMergerOptions horizontalClassMergerOptions =
       new HorizontalClassMergerOptions();
@@ -993,10 +990,6 @@
     return jetpackComposeOptions;
   }
 
-  public SingleCallerInlinerOptions getSingleCallerInlinerOptions() {
-    return singleCallerInlinerOptions;
-  }
-
   public VerticalClassMergerOptions getVerticalClassMergerOptions() {
     return verticalClassMergerOptions;
   }
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergingWithMissingTypeArgsSubstitutionTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergingWithMissingTypeArgsSubstitutionTest.java
index cac41ff..966addb 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergingWithMissingTypeArgsSubstitutionTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergingWithMissingTypeArgsSubstitutionTest.java
@@ -48,10 +48,10 @@
         .addKeepClassRules(A.class)
         .addKeepAttributeSignature()
         .addOptionsModification(
-            options -> {
-              options.getSingleCallerInlinerOptions().setEnable(false);
-              options.getVerticalClassMergerOptions().setEnableBridgeAnalysis(enableBridgeAnalysis);
-            })
+            options ->
+                options
+                    .getVerticalClassMergerOptions()
+                    .setEnableBridgeAnalysis(enableBridgeAnalysis))
         .addVerticallyMergedClassesInspector(
             inspector -> inspector.assertMergedIntoSubtype(B.class).assertNoOtherClassesMerged())
         .enableInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/internal/proto/Proto2ShrinkingTest.java b/src/test/java/com/android/tools/r8/internal/proto/Proto2ShrinkingTest.java
index 64e4c42..55a961e 100644
--- a/src/test/java/com/android/tools/r8/internal/proto/Proto2ShrinkingTest.java
+++ b/src/test/java/com/android/tools/r8/internal/proto/Proto2ShrinkingTest.java
@@ -4,8 +4,8 @@
 
 package com.android.tools.r8.internal.proto;
 
-import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsentIf;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.notIf;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -249,8 +249,9 @@
 
     // Verify that the registry methods are still present in the output.
     //
-    // We expect findLiteExtensionByNumber2() to be inlined into findLiteExtensionByNumber1() and
-    // findLiteExtensionByNumber1() to be inlined into findLiteExtensionByNumber().
+    // We expect findLiteExtensionByNumber2() to be inlined into findLiteExtensionByNumber1(). The
+    // method findLiteExtensionByNumber1() has two call sites from findLiteExtensionByNumber(),
+    // which prevents it from being single-caller inlined.
     {
       ClassSubject generatedExtensionRegistryLoader = outputInspector.clazz(extensionRegistryName);
       assertThat(generatedExtensionRegistryLoader, isPresent());
@@ -261,11 +262,11 @@
       assertThat(
           generatedExtensionRegistryLoader.uniqueMethodWithOriginalName(
               "findLiteExtensionByNumber1"),
-          isAbsentIf(enableMinification));
+          isPresent());
       assertThat(
           generatedExtensionRegistryLoader.uniqueMethodWithOriginalName(
               "findLiteExtensionByNumber2"),
-          isAbsentIf(enableMinification));
+          notIf(isPresent(), enableMinification));
     }
 
     // Verify that unused extensions have been removed with -allowaccessmodification.
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/BridgeWithCastsInliningTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/BridgeWithCastsInliningTest.java
index f5e7361..cf1b311 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/BridgeWithCastsInliningTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/BridgeWithCastsInliningTest.java
@@ -10,7 +10,6 @@
 
 import com.android.tools.r8.NeverClassInline;
 import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverSingleCallerInline;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.utils.BooleanUtils;
@@ -56,7 +55,6 @@
             })
         .enableInliningAnnotations()
         .enableNeverClassInliningAnnotations()
-        .enableNeverSingleCallerInlineAnnotations()
         .setMinApi(parameters)
         .compile()
         .inspect(this::inspect)
@@ -108,7 +106,6 @@
       foo(o, o, o, o, o);
     }
 
-    @NeverSingleCallerInline
     static void foo(Object o1, Object o2, Object o3, Object o4, Object o5) {
       A a1 = (A) o1;
       A a2 = (A) o2;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/BridgeWithUnboxingInliningTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/BridgeWithUnboxingInliningTest.java
index 2dea095..2623bc0 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/BridgeWithUnboxingInliningTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/BridgeWithUnboxingInliningTest.java
@@ -10,7 +10,6 @@
 
 import com.android.tools.r8.NeverClassInline;
 import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverSingleCallerInline;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.utils.BooleanUtils;
@@ -56,7 +55,6 @@
             })
         .enableInliningAnnotations()
         .enableNeverClassInliningAnnotations()
-        .enableNeverSingleCallerInlineAnnotations()
         .setMinApi(parameters)
         .compile()
         .inspect(this::inspect)
@@ -116,7 +114,6 @@
       foo(o1, o2, o3, o4, o5);
     }
 
-    @NeverSingleCallerInline
     static void foo(Integer o1, Integer o2, Integer o3, Integer o4, Integer o5) {
       int i1 = o1;
       int i2 = o2;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningOfVirtualMethodOnKeptClassTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningOfVirtualMethodOnKeptClassTest.java
index 946d711..2b4c4bb 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningOfVirtualMethodOnKeptClassTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningOfVirtualMethodOnKeptClassTest.java
@@ -4,8 +4,8 @@
 
 package com.android.tools.r8.ir.optimize.inliner;
 
-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.NeverClassInline;
@@ -50,7 +50,7 @@
   private void verifyOutput(CodeInspector inspector) {
     ClassSubject classSubject = inspector.clazz(TestClass.class);
     assertThat(classSubject, isPresent());
-    assertThat(classSubject.uniqueMethodWithOriginalName("foo"), isAbsent());
+    assertThat(classSubject.uniqueMethodWithOriginalName("foo"), not(isPresent()));
     assertThat(classSubject.uniqueMethodWithOriginalName("bar"), isPresent());
     assertThat(classSubject.uniqueMethodWithOriginalName("baz"), isPresent());
   }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/SingleTargetAfterInliningTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/SingleTargetAfterInliningTest.java
index 59e609d..95cf23e 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/SingleTargetAfterInliningTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/SingleTargetAfterInliningTest.java
@@ -50,11 +50,9 @@
         .addInnerClasses(SingleTargetAfterInliningTest.class)
         .addKeepMainRule(TestClass.class)
         .addOptionsModification(
-            options -> {
-              options.inlinerOptions().applyInliningToInlineePredicateForTesting =
-                  (appView, inlinee, inliningDepth) -> inliningDepth <= maxInliningDepth;
-              options.getSingleCallerInlinerOptions().setEnable(false);
-            })
+            options ->
+                options.inlinerOptions().applyInliningToInlineePredicateForTesting =
+                    (appView, inlinee, inliningDepth) -> inliningDepth <= maxInliningDepth)
         .enableAlwaysInliningAnnotations()
         .enableInliningAnnotations()
         .enableNeverClassInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/keepanno/KeepEmptyClassTest.java b/src/test/java/com/android/tools/r8/keepanno/KeepEmptyClassTest.java
index 3e9b7ee..a80be3c 100644
--- a/src/test/java/com/android/tools/r8/keepanno/KeepEmptyClassTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/KeepEmptyClassTest.java
@@ -64,14 +64,10 @@
       assertTrue(parameters.isExtractRules());
       // PG and R8 with keep rules will keep the residual class.
       assertThat(classA, isPresentAndRenamed());
-      // R8 using keep rules will soft-pin the precondition method too. The soft pinning is only
-      // applied in the first round of tree shaking, however, so R8 can still single caller inline
-      // the method after the final round of tree shaking.
+      // R8 using keep rules will soft-pin the precondition method too.
       assertThat(
           classA.uniqueMethodWithOriginalName("foo"),
-          parameters.isPG() || (parameters.isCurrentR8() && parameters.isExtractRules())
-              ? isAbsent()
-              : isPresentAndRenamed());
+          parameters.isPG() ? isAbsent() : isPresentAndRenamed());
     }
   }
 
diff --git a/src/test/java/com/android/tools/r8/keepanno/compatissues/BackReferenceIssuesTest.java b/src/test/java/com/android/tools/r8/keepanno/compatissues/BackReferenceIssuesTest.java
index 85464e5..63692c5 100644
--- a/src/test/java/com/android/tools/r8/keepanno/compatissues/BackReferenceIssuesTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/compatissues/BackReferenceIssuesTest.java
@@ -8,6 +8,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.isPresentAndNotRenamed;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assume.assumeTrue;
 
@@ -81,7 +82,7 @@
                 assertThat(
                     inspector.clazz(A.class).uniqueMethodWithOriginalName("foo"),
                     // The rule is not valid and does not keep the method in R8.
-                    shrinker.isPG() ? isPresentAndNotRenamed() : isAbsent()));
+                    shrinker.isPG() ? isPresentAndNotRenamed() : isPresentAndRenamed()));
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/VerticalClassMergingRetraceTest.java b/src/test/java/com/android/tools/r8/naming/retrace/VerticalClassMergingRetraceTest.java
index 34b7502..cb94b5d 100644
--- a/src/test/java/com/android/tools/r8/naming/retrace/VerticalClassMergingRetraceTest.java
+++ b/src/test/java/com/android/tools/r8/naming/retrace/VerticalClassMergingRetraceTest.java
@@ -73,8 +73,7 @@
   private int expectedActualStackTraceHeight() {
     // In RELEASE mode a synthetic bridge is added by the vertical class merger if the method is
     // targeted by the invoke-super (which is modeled by setting enableBridgeAnalysis to false).
-    // Due to single caller inlining we still end up with a stack trace height of 2.
-    return 2;
+    return mode == CompilationMode.DEBUG || enableBridgeAnalysis ? 2 : 3;
   }
 
   private boolean filterSynthesizedMethodWhenLineNumberAvailable(
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/IfMemberRuleWithUnusedParameterTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/IfMemberRuleWithUnusedParameterTest.java
index 4490fff..2d871fc 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/IfMemberRuleWithUnusedParameterTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/IfMemberRuleWithUnusedParameterTest.java
@@ -7,7 +7,6 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -39,7 +38,6 @@
             "  public static void print(" + Object.class.getTypeName() + ");",
             "}",
             "-keep class " + KeptByIf.class.getTypeName())
-        .enableInliningAnnotations()
         .setMinApi(parameters)
         .compile()
         .inspect(
@@ -63,7 +61,6 @@
       print(args);
     }
 
-    @NeverInline
     public static void print(Object unused) {
       System.out.println("Hello, world!");
     }
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/inlining/IfRuleWithInlining.java b/src/test/java/com/android/tools/r8/shaking/ifrule/inlining/IfRuleWithInlining.java
index 4f0a320..07eb940 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/inlining/IfRuleWithInlining.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/inlining/IfRuleWithInlining.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.shaking.ifrule.inlining;
 
-import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsentIf;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
@@ -71,10 +70,8 @@
     CodeInspector inspector = new CodeInspector(app);
     ClassSubject clazzA = inspector.clazz(A.class);
     assertThat(clazzA, isPresent());
-    // A.a may be inlined when neverInlineMethod is false.
-    assertThat(
-        clazzA.uniqueMethodWithOriginalName("a"),
-        isAbsentIf(shrinker.isR8() && !neverInlineMethod));
+    // A.a should not be inlined.
+    assertThat(clazzA.method("int", "a", ImmutableList.of()), isPresent());
     assertThat(inspector.clazz(D.class), isPresent());
     ProcessResult result;
     if (shrinker == Shrinker.R8) {
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedParameterTypeTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedParameterTypeTest.java
index 3100e4c..aa46e96 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedParameterTypeTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedParameterTypeTest.java
@@ -4,12 +4,12 @@
 
 package com.android.tools.r8.shaking.ifrule.verticalclassmerging;
 
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 
-import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.NoAccessModification;
 import com.android.tools.r8.NoHorizontalClassMerging;
 import com.android.tools.r8.R8FullTestBuilder;
@@ -59,7 +59,6 @@
     @NoHorizontalClassMerging
     static class SuperTestClass {
 
-      @NeverInline
       public static void method(A obj) {
         System.out.print(obj.getClass().getName());
       }
@@ -88,16 +87,7 @@
     @Override
     public void configure(R8FullTestBuilder builder) {
       super.configure(builder);
-      builder
-          .addVerticallyMergedClassesInspector(
-              inspector ->
-                  inspector
-                      .applyIf(
-                          enableVerticalClassMerging,
-                          i -> i.assertMergedIntoSubtype(A.class, SuperTestClass.class))
-                      .assertNoOtherClassesMerged())
-          .enableInliningAnnotations()
-          .enableNoHorizontalClassMergingAnnotations();
+      builder.enableNoHorizontalClassMergingAnnotations();
     }
 
     @Override
@@ -123,6 +113,11 @@
       assertThat(testClassSubject, isPresent());
 
       if (enableVerticalClassMerging) {
+        // Verify that SuperTestClass has been merged into TestClass.
+        assertThat(inspector.clazz(SuperTestClass.class), isAbsent());
+        assertEquals(
+            "java.lang.Object", testClassSubject.getDexProgramClass().superType.toSourceString());
+
         // Verify that TestClass.method has been removed.
         List<FoundMethodSubject> methods =
             testClassSubject.allMethods().stream()
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedReturnTypeTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedReturnTypeTest.java
index 77c2a2e..9e98e16 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedReturnTypeTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedReturnTypeTest.java
@@ -6,16 +6,15 @@
 
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.IsNot.not;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 
 import com.android.tools.r8.AssumeMayHaveSideEffects;
-import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.NoAccessModification;
 import com.android.tools.r8.NoHorizontalClassMerging;
 import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.shaking.ifrule.verticalclassmerging.MergedParameterTypeTest.MergedParameterTypeWithCollisionTest.SuperTestClass;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
@@ -69,7 +68,6 @@
     static class SuperTestClass {
 
       @AssumeMayHaveSideEffects
-      @NeverInline
       public static A method() {
         return new B();
       }
@@ -98,17 +96,7 @@
     @Override
     public void configure(R8FullTestBuilder builder) {
       super.configure(builder);
-      builder
-          .addVerticallyMergedClassesInspector(
-              inspector ->
-                  inspector
-                      .applyIf(
-                          enableVerticalClassMerging,
-                          i -> i.assertMergedIntoSubtype(A.class, SuperTestClass.class))
-                      .assertNoOtherClassesMerged())
-          .enableInliningAnnotations()
-          .enableNoHorizontalClassMergingAnnotations()
-          .enableSideEffectAnnotations();
+      builder.enableNoHorizontalClassMergingAnnotations().enableSideEffectAnnotations();
     }
 
     @Override
@@ -134,6 +122,11 @@
       assertThat(testClassSubject, isPresent());
 
       if (enableVerticalClassMerging) {
+        // Verify that SuperTestClass has been merged into TestClass.
+        assertThat(inspector.clazz(SuperTestClass.class), not(isPresent()));
+        assertEquals(
+            "java.lang.Object", testClassSubject.getDexProgramClass().superType.toSourceString());
+
         // Verify that TestClass.method has been removed.
         List<FoundMethodSubject> methods =
             testClassSubject.allMethods().stream()
diff --git a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByConditionalOnMethodTest.java b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByConditionalOnMethodTest.java
index 235de24..6a9341c 100644
--- a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByConditionalOnMethodTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByConditionalOnMethodTest.java
@@ -7,7 +7,6 @@
 import static com.android.tools.r8.references.Reference.methodFromMethod;
 import static org.junit.Assert.assertEquals;
 
-import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -25,7 +24,6 @@
 public class KeptByConditionalOnMethodTest extends TestBase {
 
   public static class IfClass {
-    @NeverInline
     public void foo(String name) throws Exception {
       Class<?> clazz = Class.forName(name);
       Object object = clazz.getDeclaredConstructor().newInstance();
@@ -79,7 +77,6 @@
             .addProgramClasses(Main.class, IfClass.class, ThenClass.class)
             .addKeepMainRule(Main.class)
             .addKeepRules(ifRuleContent)
-            .enableInliningAnnotations()
             .setMinApi(parameters)
             .run(parameters.getRuntime(), Main.class, ThenClass.class.getTypeName())
             .assertSuccessWithOutput(EXPECTED)
diff --git a/src/test/java/com/android/tools/r8/startup/StartupSyntheticPlacementTest.java b/src/test/java/com/android/tools/r8/startup/StartupSyntheticPlacementTest.java
index f391aff..2f41828 100644
--- a/src/test/java/com/android/tools/r8/startup/StartupSyntheticPlacementTest.java
+++ b/src/test/java/com/android/tools/r8/startup/StartupSyntheticPlacementTest.java
@@ -162,7 +162,6 @@
             testBuilder ->
                 configureStartupOptions(
                     testBuilder, instrumentationCompileResult.inspector(), startupList))
-        .noInliningOfSynthetics()
         .setMinApi(parameters)
         .compile()
         .inspectDiagnosticMessages(