Remove unused argument removal phase

Change-Id: I766a217828642057dd0e5357a130e9f5a56e78fb
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 02ef891..65a9a2f 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -57,8 +57,6 @@
 import com.android.tools.r8.ir.optimize.SwitchMapCollector;
 import com.android.tools.r8.ir.optimize.UninstantiatedTypeOptimization;
 import com.android.tools.r8.ir.optimize.UninstantiatedTypeOptimization.UninstantiatedTypeOptimizationGraphLens;
-import com.android.tools.r8.ir.optimize.UnusedArgumentsCollector;
-import com.android.tools.r8.ir.optimize.UnusedArgumentsCollector.UnusedArgumentsGraphLens;
 import com.android.tools.r8.ir.optimize.enums.EnumUnboxingCfMethods;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
 import com.android.tools.r8.ir.optimize.templates.CfUtilityMethodsForCodeOptimizations;
@@ -512,32 +510,15 @@
         }
         assert appView.verticallyMergedClasses() != null;
 
-        if (options.enableArgumentRemoval) {
-          SubtypingInfo subtypingInfo = appViewWithLiveness.appInfo().computeSubtypingInfo();
-          {
-            timing.begin("UnusedArgumentRemoval");
-            UnusedArgumentsGraphLens lens =
-                new UnusedArgumentsCollector(
-                        appViewWithLiveness,
-                        new MethodPoolCollection(appViewWithLiveness, subtypingInfo))
-                    .run(executorService, timing);
-            assert lens == null || getDirectApp(appView).verifyNothingToRewrite(appView, lens);
-            appView.rewriteWithLens(lens);
-            timing.end();
-          }
-          if (options.enableUninstantiatedTypeOptimization) {
-            timing.begin("UninstantiatedTypeOptimization");
-            UninstantiatedTypeOptimizationGraphLens lens =
-                new UninstantiatedTypeOptimization(appViewWithLiveness)
-                    .strenghtenOptimizationInfo()
-                    .run(
-                        new MethodPoolCollection(appViewWithLiveness, subtypingInfo),
-                        executorService,
-                        timing);
-            assert lens == null || getDirectApp(appView).verifyNothingToRewrite(appView, lens);
-            appView.rewriteWithLens(lens);
-            timing.end();
-          }
+        if (options.enableUninstantiatedTypeOptimization) {
+          timing.begin("UninstantiatedTypeOptimization");
+          UninstantiatedTypeOptimizationGraphLens lens =
+              new UninstantiatedTypeOptimization(appViewWithLiveness)
+                  .strenghtenOptimizationInfo()
+                  .run(new MethodPoolCollection(appViewWithLiveness), executorService, timing);
+          assert lens == null || getDirectApp(appView).verifyNothingToRewrite(appView, lens);
+          appView.rewriteWithLens(lens);
+          timing.end();
         }
 
         HorizontalClassMerger.createForInitialClassMerging(appViewWithLiveness)
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MethodPoolCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/MethodPoolCollection.java
index 652c185..2b439a6 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MethodPoolCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MethodPoolCollection.java
@@ -34,6 +34,10 @@
 
   private final Predicate<DexEncodedMethod> methodTester;
 
+  public MethodPoolCollection(AppView<AppInfoWithLiveness> appView) {
+    this(appView, appView.appInfo().computeSubtypingInfo());
+  }
+
   public MethodPoolCollection(AppView<AppInfoWithLiveness> appView, SubtypingInfo subtypingInfo) {
     this(appView, subtypingInfo, Predicates.alwaysTrue());
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java
deleted file mode 100644
index 052e196..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java
+++ /dev/null
@@ -1,333 +0,0 @@
-// Copyright (c) 2018, 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.ir.optimize;
-
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.ArgumentUse;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexProto;
-import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.NestedGraphLens;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
-import com.android.tools.r8.ir.optimize.MemberPoolCollection.MemberPool;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.MethodSignatureEquivalence;
-import com.android.tools.r8.utils.SymbolGenerationUtils;
-import com.android.tools.r8.utils.SymbolGenerationUtils.MixedCasing;
-import com.android.tools.r8.utils.ThreadUtils;
-import com.android.tools.r8.utils.Timing;
-import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
-import com.android.tools.r8.utils.collections.BidirectionalOneToOneMap;
-import com.android.tools.r8.utils.collections.MutableBidirectionalOneToOneMap;
-import com.google.common.base.Equivalence.Wrapper;
-import com.google.common.collect.Streams;
-import java.util.BitSet;
-import java.util.HashSet;
-import java.util.IdentityHashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.stream.Collectors;
-
-public class UnusedArgumentsCollector {
-
-  private static final MethodSignatureEquivalence equivalence = MethodSignatureEquivalence.get();
-
-  private final AppView<AppInfoWithLiveness> appView;
-  private final MethodPoolCollection methodPoolCollection;
-
-  private final MutableBidirectionalOneToOneMap<DexMethod, DexMethod> methodMapping =
-      new BidirectionalOneToOneHashMap<>();
-  private final Map<DexMethod, ArgumentInfoCollection> removedArguments = new IdentityHashMap<>();
-
-  public static class UnusedArgumentsGraphLens extends NestedGraphLens {
-
-    private final Map<DexMethod, ArgumentInfoCollection> removedArguments;
-
-    UnusedArgumentsGraphLens(
-        AppView<?> appView,
-        BidirectionalOneToOneMap<DexMethod, DexMethod> methodMap,
-        Map<DexMethod, ArgumentInfoCollection> removedArguments) {
-      super(appView, EMPTY_FIELD_MAP, methodMap, EMPTY_TYPE_MAP);
-      this.removedArguments = removedArguments;
-    }
-
-    @Override
-    protected RewrittenPrototypeDescription internalDescribePrototypeChanges(
-        RewrittenPrototypeDescription prototypeChanges, DexMethod method) {
-      return prototypeChanges.withRemovedArguments(
-          removedArguments.getOrDefault(method, ArgumentInfoCollection.empty()));
-    }
-  }
-
-  public UnusedArgumentsCollector(
-      AppView<AppInfoWithLiveness> appView, MethodPoolCollection methodPoolCollection) {
-    this.appView = appView;
-    this.methodPoolCollection = methodPoolCollection;
-  }
-
-  public UnusedArgumentsGraphLens run(ExecutorService executorService, Timing timing)
-      throws ExecutionException {
-    ThreadUtils.awaitFutures(
-        Streams.stream(appView.appInfo().classes())
-            .map(this::runnableForClass)
-            .map(executorService::submit)
-            // Materialize list such that all runnables are submitted to the executor service
-            // before calling awaitFutures().
-            .collect(Collectors.toList()));
-
-    // Build method pool collection to enable unused argument removal for virtual methods.
-    methodPoolCollection.buildAll(executorService, timing);
-
-    // Visit classes in deterministic order to ensure deterministic output.
-    appView.appInfo().classesWithDeterministicOrder().forEach(this::processVirtualMethods);
-
-    if (!methodMapping.isEmpty()) {
-      return new UnusedArgumentsGraphLens(appView, methodMapping, removedArguments);
-    }
-
-    return null;
-  }
-
-  private class UsedSignatures {
-
-    private final MethodSignatureEquivalence equivalence = MethodSignatureEquivalence.get();
-    private final Set<Wrapper<DexMethod>> usedSignatures = new HashSet<>();
-
-    private boolean isMethodSignatureAvailable(DexMethod method) {
-      return !usedSignatures.contains(equivalence.wrap(method));
-    }
-
-    private void markSignatureAsUsed(DexMethod method) {
-      usedSignatures.add(equivalence.wrap(method));
-    }
-
-    DexMethod getNewSignature(DexEncodedMethod method, DexProto newProto) {
-      DexMethod newSignature;
-      int count = 0;
-      DexString newName = null;
-      do {
-        if (newName == null) {
-          newName = method.getReference().name;
-        } else if (!appView.dexItemFactory().isConstructor(method.getReference())) {
-          newName =
-              appView
-                  .dexItemFactory()
-                  .createString(
-                      SymbolGenerationUtils.numberToIdentifier(
-                          count,
-                          MixedCasing.USE_MIXED_CASE,
-                          method.getReference().name.toSourceString().toCharArray()));
-        } else {
-          // Constructors must be named `<init>`.
-          return null;
-        }
-        newSignature =
-            appView.dexItemFactory().createMethod(method.getHolderType(), newProto, newName);
-        count++;
-      } while (!isMethodSignatureAvailable(newSignature));
-      return newSignature;
-    }
-
-    DexEncodedMethod removeArguments(
-        DexEncodedMethod method, DexMethod newSignature, ArgumentInfoCollection unused) {
-      boolean removed = usedSignatures.remove(equivalence.wrap(method.getReference()));
-      assert removed;
-
-      markSignatureAsUsed(newSignature);
-
-      return method.toTypeSubstitutedMethod(
-          newSignature, unused.createParameterAnnotationsRemover(method));
-    }
-  }
-
-  private class GloballyUsedSignatures {
-
-    private final MemberPool<DexMethod> methodPool;
-
-    GloballyUsedSignatures(MemberPool<DexMethod> methodPool) {
-      this.methodPool = methodPool;
-    }
-
-    DexMethod getNewSignature(DexEncodedMethod method, DexProto newProto) {
-      DexMethod newSignature;
-      int count = 0;
-      DexString newName = null;
-      do {
-        if (newName == null) {
-          newName = method.getReference().name;
-        } else if (!appView.dexItemFactory().isConstructor(method.getReference())) {
-          newName =
-              appView
-                  .dexItemFactory()
-                  .createString(method.getReference().name.toSourceString() + count);
-        } else {
-          // Constructors must be named `<init>`.
-          return null;
-        }
-        newSignature =
-            appView.dexItemFactory().createMethod(method.getHolderType(), newProto, newName);
-        count++;
-      } while (methodPool.hasSeen(equivalence.wrap(newSignature)));
-      return newSignature;
-    }
-
-    DexEncodedMethod removeArguments(
-        DexEncodedMethod method, DexMethod newSignature, ArgumentInfoCollection unused) {
-      methodPool.seen(equivalence.wrap(newSignature));
-      return method.toTypeSubstitutedMethod(
-          newSignature, unused.createParameterAnnotationsRemover(method));
-    }
-  }
-
-  private Runnable runnableForClass(DexProgramClass clazz) {
-    return () -> this.processDirectMethods(clazz);
-  }
-
-  private void processDirectMethods(DexProgramClass clazz) {
-    UsedSignatures signatures = new UsedSignatures();
-    for (DexEncodedMethod method : clazz.methods()) {
-      signatures.markSignatureAsUsed(method.getReference());
-    }
-
-    clazz
-        .getMethodCollection()
-        .replaceDirectMethods(
-            method -> {
-
-              // If this is a method with known resolution issues, then don't remove any unused
-              // arguments.
-              if (appView.appInfo().isFailedResolutionTarget(method.getReference())) {
-                return method;
-              }
-
-              ArgumentInfoCollection unused = collectUnusedArguments(method);
-              if (unused != null && unused.hasRemovedArguments()) {
-                DexProto newProto = createProtoWithRemovedArguments(method, unused);
-                DexMethod newSignature = signatures.getNewSignature(method, newProto);
-                if (newSignature == null) {
-                  assert appView.dexItemFactory().isConstructor(method.getReference());
-                  return method;
-                }
-                DexEncodedMethod newMethod =
-                    signatures.removeArguments(method, newSignature, unused);
-                synchronized (this) {
-                  methodMapping.put(method.getReference(), newMethod.getReference());
-                  removedArguments.put(newMethod.getReference(), unused);
-                }
-                return newMethod;
-              }
-              return method;
-            });
-  }
-
-  private void processVirtualMethods(DexProgramClass clazz) {
-    MemberPool<DexMethod> methodPool = methodPoolCollection.get(clazz);
-    GloballyUsedSignatures signatures = new GloballyUsedSignatures(methodPool);
-
-    clazz
-        .getMethodCollection()
-        .replaceVirtualMethods(
-            method -> {
-              ArgumentInfoCollection unused = collectUnusedArguments(method, methodPool);
-              if (unused != null && unused.hasRemovedArguments()) {
-                DexProto newProto = createProtoWithRemovedArguments(method, unused);
-                DexMethod newSignature = signatures.getNewSignature(method, newProto);
-
-                // Double-check that the new method signature is in fact available.
-                assert !methodPool.hasSeenStrictlyAbove(equivalence.wrap(newSignature));
-                assert !methodPool.hasSeenStrictlyBelow(equivalence.wrap(newSignature));
-
-                DexEncodedMethod newMethod =
-                    signatures.removeArguments(
-                        method, signatures.getNewSignature(method, newProto), unused);
-
-                methodMapping.put(method.getReference(), newMethod.getReference());
-                removedArguments.put(newMethod.getReference(), unused);
-                return newMethod;
-              }
-              return method;
-            });
-  }
-
-  private ArgumentInfoCollection collectUnusedArguments(DexEncodedMethod method) {
-    return collectUnusedArguments(method, null);
-  }
-
-  private ArgumentInfoCollection collectUnusedArguments(
-      DexEncodedMethod method, MemberPool<DexMethod> methodPool) {
-    if (ArgumentRemovalUtils.isPinned(method, appView)
-        || appView.appInfo().isKeepUnusedArgumentsMethod(method.getReference())) {
-      return null;
-    }
-    // Only process classfile code objects.
-    if (method.getCode() == null || !method.getCode().isCfCode()) {
-      return null;
-    }
-    if (method.isNonPrivateVirtualMethod()) {
-      // Abort if the method overrides another method, or if the method is overridden. In both cases
-      // an unused argument cannot be removed unless it is unused in all of the related methods in
-      // the hierarchy.
-      assert methodPool != null;
-      Wrapper<DexMethod> wrapper = equivalence.wrap(method.getReference());
-      if (methodPool.hasSeenStrictlyAbove(wrapper) || methodPool.hasSeenStrictlyBelow(wrapper)) {
-        return null;
-      }
-    }
-    int offset = method.getFirstNonReceiverArgumentIndex();
-    int argumentCount = method.getReference().proto.parameters.size() + offset;
-    CollectUsedArguments collector = new CollectUsedArguments();
-    if (!method.accessFlags.isStatic()) {
-      // TODO(65810338): The receiver cannot be removed without transforming the method to being
-      // static.
-      collector.register(0);
-    }
-    method.getCode().registerArgumentReferences(method, collector);
-    BitSet used = collector.getUsedArguments();
-    if (used.cardinality() < argumentCount) {
-      ArgumentInfoCollection.Builder argInfosBuilder = ArgumentInfoCollection.builder();
-      for (int argumentIndex = 0; argumentIndex < argumentCount; argumentIndex++) {
-        if (!used.get(argumentIndex)) {
-          RemovedArgumentInfo removedArg =
-              RemovedArgumentInfo.builder()
-                  .setType(method.getReference().proto.parameters.values[argumentIndex - offset])
-                  .build();
-          argInfosBuilder.addArgumentInfo(argumentIndex, removedArg);
-        }
-      }
-      return argInfosBuilder.build();
-    }
-    return null;
-  }
-
-  private DexProto createProtoWithRemovedArguments(
-      DexEncodedMethod encodedMethod, ArgumentInfoCollection unused) {
-    DexType[] parameters = unused.rewriteParameters(encodedMethod);
-    return appView
-        .dexItemFactory()
-        .createProto(encodedMethod.getReference().proto.returnType, parameters);
-  }
-
-  private static class CollectUsedArguments extends ArgumentUse {
-
-    private final BitSet used = new BitSet();
-
-    BitSet getUsedArguments() {
-      return used;
-    }
-
-    @Override
-    public boolean register(int argument) {
-      used.set(argument);
-      return true;
-    }
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java
index 6f97143..ae2a8aa 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java
@@ -18,6 +18,7 @@
 import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteClassTypeParameterState;
 import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteMethodState;
 import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteMonomorphicMethodState;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteMonomorphicMethodStateOrUnknown;
 import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteParameterState;
 import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcretePrimitiveTypeParameterState;
 import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodState;
@@ -159,6 +160,11 @@
       return;
     }
 
+    // Do not optimize @KeepConstantArgument methods.
+    if (appView.appInfo().isKeepConstantArgumentsMethod(method)) {
+      methodState = MethodState.unknown();
+    }
+
     methodState = getMethodStateAfterUnusedParameterRemoval(method, methodState);
 
     if (methodState.isUnknown()) {
@@ -208,12 +214,9 @@
     // before reenqueing.
     MethodReprocessingCriteria reprocessingCriteria =
         reprocessingCriteriaCollection.getReprocessingCriteria(method);
-    if (!reprocessingCriteria.shouldReprocess(appView, method, monomorphicMethodState)) {
-      return;
-    }
-
-    // Do not optimize @KeepConstantArgument methods.
-    if (appView.appInfo().isKeepConstantArgumentsMethod(method)) {
+    ConcreteMonomorphicMethodStateOrUnknown widenedMethodState =
+        reprocessingCriteria.widenMethodState(appView, method, monomorphicMethodState);
+    if (widenedMethodState.isUnknown()) {
       return;
     }
 
@@ -221,7 +224,7 @@
         .getDefinition()
         .setCallSiteOptimizationInfo(
             ConcreteCallSiteOptimizationInfo.fromMethodState(
-                appView, method, monomorphicMethodState));
+                appView, method, widenedMethodState.asMonomorphic()));
   }
 
   private MethodState getMethodStateAfterUnusedParameterRemoval(
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
index 90397d7..8d83dd6 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
@@ -268,6 +268,7 @@
     private boolean isParameterRemovalAllowed(ProgramMethod method) {
       return appView.getKeepInfo(method).isParameterRemovalAllowed(options)
           && !method.getDefinition().isLibraryMethodOverride().isPossiblyTrue()
+          && !appView.appInfo().isBootstrapMethod(method)
           && !appView.appInfo().isMethodTargetedByInvokeDynamic(method);
     }
 
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/MethodReprocessingCriteria.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/MethodReprocessingCriteria.java
index 0afc8ca..658383f 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/MethodReprocessingCriteria.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/MethodReprocessingCriteria.java
@@ -8,8 +8,12 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteMonomorphicMethodState;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteMonomorphicMethodStateOrUnknown;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodState;
 import com.android.tools.r8.optimize.argumentpropagation.codescanner.ParameterState;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.UnknownParameterState;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.google.common.collect.Iterables;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap;
 
@@ -39,7 +43,7 @@
         parameterIndex, ParameterReprocessingCriteria.alwaysReprocess());
   }
 
-  public boolean shouldReprocess(
+  public ConcreteMonomorphicMethodStateOrUnknown widenMethodState(
       AppView<AppInfoWithLiveness> appView,
       ProgramMethod method,
       ConcreteMonomorphicMethodState methodState) {
@@ -50,14 +54,24 @@
         continue;
       }
 
+      if (parameterState.getAbstractValue(appView).isSingleValue()) {
+        // Don't widen when we have information that can be used for parameter removal.
+        continue;
+      }
+
       ParameterReprocessingCriteria parameterReprocessingCriteria =
           getParameterReprocessingCriteria(parameterIndex);
       DexType parameterType = method.getArgumentType(parameterIndex);
       if (parameterReprocessingCriteria.shouldReprocess(
           appView, parameterState.asConcrete(), parameterType)) {
-        return true;
+        continue;
       }
+
+      methodState.setParameterState(parameterIndex, UnknownParameterState.get());
     }
-    return false;
+
+    return Iterables.all(methodState.getParameterStates(), ParameterState::isUnknown)
+        ? MethodState.unknown()
+        : methodState;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index 4887a27..7b5eee3 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -591,6 +591,10 @@
     return bootstrapMethods.contains(method);
   }
 
+  public boolean isBootstrapMethod(ProgramMethod method) {
+    return isBootstrapMethod(method.getReference());
+  }
+
   public boolean isMethodTargetedByInvokeDynamic(DexMethod method) {
     return methodsTargetedByInvokeDynamic.contains(method);
   }
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 3718fcf..308862a 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -214,7 +214,6 @@
   }
 
   public void disableGlobalOptimizations() {
-    enableArgumentRemoval = false;
     enableInlining = false;
     enableClassInlining = false;
     enableClassStaticizer = false;
@@ -255,7 +254,6 @@
   public boolean enableFieldBitAccessAnalysis =
       System.getProperty("com.android.tools.r8.fieldBitAccessAnalysis") != null;
   public boolean enableVerticalClassMerging = true;
-  public boolean enableArgumentRemoval = true;
   public boolean enableUnusedInterfaceRemoval = true;
   public boolean enableDevirtualization = true;
   public boolean enableInlining =
@@ -1258,6 +1256,15 @@
       return enableDynamicTypePropagation;
     }
 
+    public CallSiteOptimizationOptions setEnabled(boolean enabled) {
+      if (enabled) {
+        assert isEnabled();
+      } else {
+        disableOptimization();
+      }
+      return this;
+    }
+
     public CallSiteOptimizationOptions setEnableLegacyConstantPropagation() {
       assert !enableLegacyConstantPropagation;
       enableLegacyConstantPropagation = true;
diff --git a/src/test/java/com/android/tools/r8/accessrelaxation/NonConstructorRelaxationTest.java b/src/test/java/com/android/tools/r8/accessrelaxation/NonConstructorRelaxationTest.java
index 19c8015..29e44c0 100644
--- a/src/test/java/com/android/tools/r8/accessrelaxation/NonConstructorRelaxationTest.java
+++ b/src/test/java/com/android/tools/r8/accessrelaxation/NonConstructorRelaxationTest.java
@@ -113,7 +113,7 @@
 
     MethodSignature barMethodSignatureAfterArgumentRemoval =
         enableUnusedArgumentRemoval
-            ? new MethodSignature("bara", STRING, ImmutableList.of())
+            ? new MethodSignature("bar$1", STRING, ImmutableList.of())
             : new MethodSignature("bar", STRING, ImmutableList.of("int"));
     assertPublic(inspector, A.class, new MethodSignature("baz", STRING, ImmutableList.of()));
     assertPublic(inspector, A.class, new MethodSignature("bar", STRING, ImmutableList.of()));
diff --git a/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureKeepAttributesTest.java b/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureKeepAttributesTest.java
index fe4a189..48877b9 100644
--- a/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureKeepAttributesTest.java
+++ b/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureKeepAttributesTest.java
@@ -8,6 +8,7 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 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.graph.genericsignature.GenericSignatureKeepAttributesTest.Outer.Middle;
@@ -72,6 +73,7 @@
         .addKeepAttributeInnerClassesAndEnclosingMethod()
         .addKeepMainRule(Main.class)
         .addKeepClassAndMembersRules(Outer.Middle.Inner.class, Supplier.class, Predicate.class)
+        .enableInliningAnnotations()
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines(parameters.isCfRuntime() ? EXPECTED_JVM : EXPECTED_DEX)
         .inspect(this::inspectSignatures);
@@ -146,6 +148,7 @@
       return new Outer<O>.Middle<>();
     }
 
+    @NeverInline
     public static Outer<?>.Middle<?>.Inner<Object> create() {
       return new Outer<>().createMiddle().createInner();
     }
diff --git a/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureReflectiveInnerTest.java b/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureReflectiveInnerTest.java
index e34a36c..3c32c7b 100644
--- a/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureReflectiveInnerTest.java
+++ b/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureReflectiveInnerTest.java
@@ -7,6 +7,7 @@
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
 
+import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -48,6 +49,7 @@
         .addKeepAttributeInnerClassesAndEnclosingMethod()
         .addKeepAttributeSignature()
         .addKeepClassRules(Foo.Bar.class)
+        .enableInliningAnnotations()
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines(EXPECTED)
@@ -71,6 +73,7 @@
       }
     }
 
+    @NeverInline
     public Bar<String> foo() {
       return new Bar<>();
     }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningAfterClassInitializationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningAfterClassInitializationTest.java
index f9081c2..59e5118 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningAfterClassInitializationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningAfterClassInitializationTest.java
@@ -10,6 +10,7 @@
 import static org.hamcrest.core.IsNot.not;
 
 import com.android.tools.r8.KeepConstantArguments;
+import com.android.tools.r8.KeepUnusedArguments;
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -224,6 +225,7 @@
         .addOptionsModification(
             options -> options.enableInliningOfInvokesWithClassInitializationSideEffects = false)
         .enableConstantArgumentAnnotations()
+        .enableUnusedArgumentAnnotations()
         .enableInliningAnnotations()
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), mainClass)
@@ -322,6 +324,7 @@
     }
 
     @KeepConstantArguments
+    @KeepUnusedArguments
     @NeverInline
     private static void test(A obj) {
       try {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java
index a1b6f08..c3f71e3 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java
@@ -164,16 +164,19 @@
     assertTrue(instanceMethods(simpleWithPhi).isEmpty());
     assertThat(simpleWithPhi.clinit(), not(isPresent()));
 
+    // TODO(b/200498092): SimpleWithParams should be staticized, but due to reprocessing the
+    //  instantiation of SimpleWithParams, it is marked as ineligible for staticizing.
     assertEquals(
         Lists.newArrayList(
-            "STATIC: String SimpleWithParams.bar(String)",
-            "STATIC: String SimpleWithParams.foo()",
-            "STATIC: String TrivialTestClass.next()"),
+            "STATIC: String TrivialTestClass.next()",
+            "SimpleWithParams SimpleWithParams.INSTANCE",
+            "VIRTUAL: String SimpleWithParams.bar(String)",
+            "VIRTUAL: String SimpleWithParams.foo()"),
         references(clazz, "testSimpleWithParams", "void"));
 
     ClassSubject simpleWithParams = inspector.clazz(SimpleWithParams.class);
-    assertTrue(instanceMethods(simpleWithParams).isEmpty());
-    assertThat(simpleWithParams.clinit(), not(isPresent()));
+    assertFalse(instanceMethods(simpleWithParams).isEmpty());
+    assertThat(simpleWithParams.clinit(), isPresent());
 
     assertEquals(
         Lists.newArrayList(
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithReceiverOptimizationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithReceiverOptimizationTest.java
index e7e09dd..06aae25 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithReceiverOptimizationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithReceiverOptimizationTest.java
@@ -12,7 +12,7 @@
 
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -33,17 +33,19 @@
 @RunWith(Parameterized.class)
 public class InvokeMethodWithReceiverOptimizationTest extends TestBase {
 
-  private final Backend backend;
-  private final boolean enableArgumentRemoval;
+  private final TestParameters parameters;
+  private final boolean enableArgumentPropagation;
 
-  @Parameters(name = "Backend: {0}, enable argument removal: {1}")
+  @Parameters(name = "{0}, argument propagation: {1}")
   public static List<Object[]> data() {
-    return buildParameters(ToolHelper.getBackends(), BooleanUtils.values());
+    return buildParameters(
+        getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values());
   }
 
-  public InvokeMethodWithReceiverOptimizationTest(Backend backend, boolean enableArgumentRemoval) {
-    this.backend = backend;
-    this.enableArgumentRemoval = enableArgumentRemoval;
+  public InvokeMethodWithReceiverOptimizationTest(
+      TestParameters parameters, boolean enableArgumentPropagation) {
+    this.parameters = parameters;
+    this.enableArgumentPropagation = enableArgumentPropagation;
   }
 
   @Test
@@ -57,15 +59,20 @@
     testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expected);
 
     CodeInspector inspector =
-        testForR8(backend)
+        testForR8(parameters.getBackend())
             .addInnerClasses(InvokeMethodWithReceiverOptimizationTest.class)
             .addKeepMainRule(TestClass.class)
             .enableInliningAnnotations()
-            .addOptionsModification(o -> o.enableArgumentRemoval = enableArgumentRemoval)
+            .addOptionsModification(
+                options -> {
+                  options.enableUninstantiatedTypeOptimization = enableArgumentPropagation;
+                  options.callSiteOptimizationOptions().setEnabled(enableArgumentPropagation);
+                })
             // TODO(b/120764902): The calls to getOriginalName() below does not work in presence of
-            // argument removal.
-            .addKeepRules("-dontobfuscate")
-            .run(TestClass.class)
+            //  argument removal.
+            .noMinification()
+            .setMinApi(parameters.getApiLevel())
+            .run(parameters.getRuntime(), TestClass.class)
             .assertSuccessWithOutput(expected)
             .inspector();
 
@@ -73,7 +80,7 @@
     assertThat(testClassSubject, isPresent());
 
     ClassSubject otherClassSubject = inspector.clazz(A.class);
-    assertNotEquals(enableArgumentRemoval, otherClassSubject.isPresent());
+    assertNotEquals(enableArgumentPropagation, otherClassSubject.isPresent());
 
     // Check that A.method() has been removed.
     assertThat(otherClassSubject.uniqueMethodWithName("method"), not(isPresent()));
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/PrivateInstanceMethodCollisionTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/PrivateInstanceMethodCollisionTest.java
index 8dc29fb..58dc4e5 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/PrivateInstanceMethodCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/PrivateInstanceMethodCollisionTest.java
@@ -35,7 +35,7 @@
   @Parameters(name = "{0}, minification: {1}, allowaccessmodification: {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        getTestParameters().withAllRuntimes().build(),
+        getTestParameters().withAllRuntimesAndApiLevels().build(),
         BooleanUtils.values(),
         BooleanUtils.values());
   }
@@ -66,7 +66,7 @@
         .enableNoHorizontalClassMergingAnnotations()
         .minification(minification)
         .allowAccessModification(allowAccessModification)
-        .setMinApi(parameters.getRuntime())
+        .setMinApi(parameters.getApiLevel())
         .compile()
         .inspect(this::verifyUninstantiatedArgumentsRemovedAndNoCollisions)
         .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/UninstantiatedAnnotatedArgumentsTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/UninstantiatedAnnotatedArgumentsTest.java
index 663bcf6..0e4a3a2 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/UninstantiatedAnnotatedArgumentsTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/UninstantiatedAnnotatedArgumentsTest.java
@@ -100,10 +100,7 @@
     for (MethodSubject methodSubject : methodSubjects) {
       assertThat(methodSubject, isPresent());
 
-      // TODO(b/131735725): Should also remove arguments from the virtual methods.
-      boolean shouldHaveArgumentRemoval =
-          keepUninstantiatedArguments || methodSubject.getOriginalName().contains("Virtual");
-      if (shouldHaveArgumentRemoval) {
+      if (keepUninstantiatedArguments) {
         assertEquals(3, methodSubject.getMethod().getParameters().size());
 
         // In non-compat mode, R8 removes annotations from non-pinned items.
@@ -122,7 +119,7 @@
         assertEquals(1, annotationSet.size());
 
         DexAnnotation annotation = annotationSet.getFirst();
-        if (shouldHaveArgumentRemoval && i == getPositionOfUnusedArgument(methodSubject)) {
+        if (keepUninstantiatedArguments && i == getPositionOfUnusedArgument(methodSubject)) {
           assertEquals(
               uninstantiatedClassSubject.getFinalName(),
               annotation.getAnnotationType().getTypeName());
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/CollisionWithLibraryMethodsTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/CollisionWithLibraryMethodsTest.java
index 14efc77..612a0b5 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/CollisionWithLibraryMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/CollisionWithLibraryMethodsTest.java
@@ -67,7 +67,7 @@
       assertEquals("a", methodSubject.getFinalName());
       assertEquals(0, methodSubject.getMethod().getReference().proto.parameters.size());
     } else {
-      assertEquals("toString1", methodSubject.getFinalName());
+      assertEquals("toString$1", methodSubject.getFinalName());
       assertEquals(0, methodSubject.getMethod().getReference().proto.parameters.size());
     }
   }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAndUninstantiatedTypesTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAndUninstantiatedTypesTest.java
index 138f0a9..7ca05fb 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAndUninstantiatedTypesTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAndUninstantiatedTypesTest.java
@@ -6,6 +6,7 @@
 
 import static org.junit.Assert.assertEquals;
 
+import com.android.tools.r8.NeverClassInline;
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -39,6 +40,7 @@
         .addKeepMainRule(Main.class)
         .noMinification()
         .enableInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .setMinApi(parameters.getApiLevel())
         .compile()
         .inspect(this::assertMethodsAreThere)
@@ -168,5 +170,6 @@
 
   private static class UnInstantiated {}
 
+  @NeverClassInline
   private static class Unused {}
 }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentRemovalWithOverridingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentRemovalWithOverridingTest.java
index 281db3e..58b052c 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentRemovalWithOverridingTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentRemovalWithOverridingTest.java
@@ -32,7 +32,8 @@
 
   @Parameters(name = "{1}, minification: {0}")
   public static List<Object[]> params() {
-    return buildParameters(BooleanUtils.values(), getTestParameters().withAllRuntimes().build());
+    return buildParameters(
+        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
   }
 
   public UnusedArgumentRemovalWithOverridingTest(boolean minification, TestParameters parameters) {
@@ -50,7 +51,7 @@
         .enableInliningAnnotations()
         .enableNoVerticalClassMergingAnnotations()
         .minification(minification)
-        .setMinApi(parameters.getRuntime())
+        .setMinApi(parameters.getApiLevel())
         .compile()
         .inspect(this::verify)
         .run(parameters.getRuntime(), TestClass.class)
@@ -70,8 +71,9 @@
   static class TestClass {
 
     public static void main(String[] args) {
-      System.out.println(new A().greeting("Hello world!"));
-      System.out.println(new B().greeting("Hello world!"));
+      String greeting = System.currentTimeMillis() > 0 ? "Hello world!" : null;
+      System.out.println(new A().greeting(greeting));
+      System.out.println(new B().greeting(greeting));
     }
   }
 
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionMappingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionMappingTest.java
index 7d9a941..8ccee13 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionMappingTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionMappingTest.java
@@ -9,12 +9,12 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.CompilationMode;
 import com.android.tools.r8.KeepConstantArguments;
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -29,25 +29,20 @@
 public class UnusedArgumentsCollisionMappingTest extends TestBase {
 
   private final TestParameters parameters;
-  private final CompilationMode compilationMode;
 
-  @Parameters(name = "{0}, compilation mode: {1}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        getTestParameters().withAllRuntimesAndApiLevels().build(), CompilationMode.values());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  public UnusedArgumentsCollisionMappingTest(
-      TestParameters parameters, CompilationMode compilationMode) {
+  public UnusedArgumentsCollisionMappingTest(TestParameters parameters) {
     this.parameters = parameters;
-    this.compilationMode = compilationMode;
   }
 
   @Test
   public void testR8() throws Exception {
     R8TestRunResult runResult =
         testForR8(parameters.getBackend())
-            .setMode(compilationMode)
             .addProgramClasses(Main.class)
             .setMinApi(parameters.getApiLevel())
             .addKeepMainRule(Main.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionTest.java
index 1137a01..c59eb85 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionTest.java
@@ -34,7 +34,8 @@
 
   @Parameters(name = "{1}, minification: {0}")
   public static List<Object[]> data() {
-    return buildParameters(BooleanUtils.values(), getTestParameters().withAllRuntimes().build());
+    return buildParameters(
+        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
   }
 
   public UnusedArgumentsCollisionTest(boolean minification, TestParameters parameters) {
@@ -60,7 +61,7 @@
         .enableNeverClassInliningAnnotations()
         .enableNoVerticalClassMergingAnnotations()
         .minification(minification)
-        .setMinApi(parameters.getRuntime())
+        .setMinApi(parameters.getApiLevel())
         .compile()
         .inspect(this::verifyUnusedArgumentsRemovedAndNoCollisions)
         .run(parameters.getRuntime(), TestClass.class)
@@ -85,11 +86,10 @@
     MethodSubject methodB1Subject =
         bClassSubject.allMethods().stream().filter(FoundMethodSubject::isStatic).findFirst().get();
     assertThat(methodB1Subject, isPresent());
-    assertEquals(0, methodB1Subject.getMethod().getReference().proto.parameters.size());
+    assertEquals(0, methodB1Subject.getMethod().getParameters().size());
 
-    // TODO(b/129933280): Determine if we should use member pool collection for unused argument
-    //  removal for private and static methods.
-    assertEquals(methodB1Subject.getFinalName(), methodA1Subject.getFinalName());
+    // Verify that the static method B.method1() does not collide with a method in A.
+    assertNotEquals(methodB1Subject.getFinalName(), methodA1Subject.getFinalName());
     assertNotEquals(methodB1Subject.getFinalName(), methodA2Subject.getFinalName());
 
     // Verify that the unused argument has been removed from B.method2().
@@ -97,7 +97,7 @@
     MethodSubject methodB2Subject =
         bClassSubject.allMethods().stream().filter(FoundMethodSubject::isVirtual).findFirst().get();
     assertThat(methodB2Subject, isPresent());
-    assertEquals(0, methodB2Subject.getMethod().getReference().proto.parameters.size());
+    assertEquals(0, methodB2Subject.getMethod().getParameters().size());
 
     // Verify that the virtual method B.method2() does not collide with a method in A.
     assertNotEquals(methodB2Subject.getFinalName(), methodA1Subject.getFinalName());
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsInstanceConstructorTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsInstanceConstructorTest.java
index c890e97..a4622bc 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsInstanceConstructorTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsInstanceConstructorTest.java
@@ -11,11 +11,14 @@
 
 import com.android.tools.r8.NeverClassInline;
 import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoHorizontalClassMerging;
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.HorizontallyMergedClassesInspector;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -25,32 +28,39 @@
 @RunWith(Parameterized.class)
 public class UnusedArgumentsInstanceConstructorTest extends TestBase {
 
-  private final Backend backend;
+  private final TestParameters parameters;
 
-  @Parameters(name = "Backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  public UnusedArgumentsInstanceConstructorTest(Backend backend) {
-    this.backend = backend;
+  public UnusedArgumentsInstanceConstructorTest(TestParameters parameters) {
+    this.parameters = parameters;
   }
 
   @Test
   public void test() throws Exception {
     String expectedOutput = StringUtils.lines("Hello world");
 
-    if (backend == Backend.CF) {
-      testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expectedOutput);
+    if (parameters.isCfRuntime()) {
+      testForJvm()
+          .addTestClasspath()
+          .run(parameters.getRuntime(), TestClass.class)
+          .assertSuccessWithOutput(expectedOutput);
     }
 
     CodeInspector inspector =
-        testForR8(backend)
+        testForR8(parameters.getBackend())
             .addInnerClasses(UnusedArgumentsInstanceConstructorTest.class)
             .addKeepMainRule(TestClass.class)
+            .addHorizontallyMergedClassesInspector(
+                HorizontallyMergedClassesInspector::assertNoClassesMerged)
             .enableInliningAnnotations()
             .enableNeverClassInliningAnnotations()
-            .run(TestClass.class)
+            .enableNoHorizontalClassMergingAnnotations()
+            .setMinApi(parameters.getApiLevel())
+            .run(parameters.getRuntime(), TestClass.class)
             .assertSuccessWithOutput(expectedOutput)
             .inspector();
 
@@ -73,6 +83,7 @@
   }
 
   @NeverClassInline
+  @NoHorizontalClassMerging
   static class A {
 
     public A(B uninstantiated, C unused) {
@@ -90,7 +101,9 @@
     }
   }
 
+  @NoHorizontalClassMerging
   static class B {}
 
+  @NoHorizontalClassMerging
   static class C {}
 }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsObjectTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsObjectTest.java
index 794d588..3a4eeda 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsObjectTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsObjectTest.java
@@ -29,6 +29,7 @@
     return UnusedArgumentsTestBase.data();
   }
 
+  @NeverClassInline
   static class TestObject {
 
     public final String s;
diff --git a/src/test/java/com/android/tools/r8/regress/b69825683/Regress69825683Test.java b/src/test/java/com/android/tools/r8/regress/b69825683/Regress69825683Test.java
index d0cb2bf..d251e28 100644
--- a/src/test/java/com/android/tools/r8/regress/b69825683/Regress69825683Test.java
+++ b/src/test/java/com/android/tools/r8/regress/b69825683/Regress69825683Test.java
@@ -24,7 +24,7 @@
 
   @Parameterized.Parameters(name = "{0}")
   public static TestParametersCollection data() {
-    return getTestParameters().withAllRuntimes().build();
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   public Regress69825683Test(TestParameters parameters) {
@@ -48,10 +48,13 @@
             .addKeepRules(
                 "-assumemayhavesideeffects class " + inner.getName() + " {",
                 "  synthetic void <init>(...);",
+                "}",
+                "-keepunusedarguments class " + inner.getName() + " {",
+                "  synthetic void <init>(...);",
                 "}")
             .addOptionsModification(options -> options.enableClassInlining = false)
             .noMinification()
-            .setMinApi(parameters.getRuntime())
+            .setMinApi(parameters.getApiLevel())
             .run(parameters.getRuntime(), outer)
             // Run code to check that the constructor with synthetic class as argument is present.
             .assertSuccessWithOutputThatMatches(startsWith(innerName))
@@ -82,7 +85,7 @@
                 "}")
             .noMinification()
             .addOptionsModification(o -> o.enableClassInlining = false)
-            .setMinApi(parameters.getRuntime())
+            .setMinApi(parameters.getApiLevel())
             // Run code to check that the constructor with synthetic class as argument is present.
             .run(parameters.getRuntime(), clazz)
             .assertSuccessWithOutputThatMatches(startsWith(clazz.getName()))
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 7f6323a..b99494e 100644
--- a/src/test/java/com/android/tools/r8/shaking/ParameterTypeTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ParameterTypeTest.java
@@ -80,17 +80,17 @@
 @RunWith(Parameterized.class)
 public class ParameterTypeTest extends TestBase {
 
-  private final boolean enableArgumentRemoval;
+  private final boolean enableArgumentPropagation;
   private final TestParameters parameters;
 
-  @Parameters(name = "{1}, argument removal: {0}")
+  @Parameters(name = "{1}, argument propagation: {0}")
   public static List<Object[]> data() {
     return buildParameters(
         BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
   }
 
-  public ParameterTypeTest(boolean enableArgumentRemoval, TestParameters parameters) {
-    this.enableArgumentRemoval = enableArgumentRemoval;
+  public ParameterTypeTest(boolean enableArgumentPropagation, TestParameters parameters) {
+    this.enableArgumentPropagation = enableArgumentPropagation;
     this.parameters = parameters;
   }
 
@@ -228,7 +228,7 @@
             options -> {
               // Disable inlining to avoid the (short) tested method from being inlined and removed.
               options.enableInlining = false;
-              options.enableArgumentRemoval = enableArgumentRemoval;
+              options.callSiteOptimizationOptions().setEnabled(enableArgumentPropagation);
             });
 
     // Run processed (output) program on ART
@@ -239,7 +239,7 @@
 
     CodeInspector inspector = new CodeInspector(processedApp);
     ClassSubject subSubject = inspector.clazz(sub.name);
-    assertNotEquals(enableArgumentRemoval, subSubject.isPresent());
+    assertNotEquals(enableArgumentPropagation, subSubject.isPresent());
   }
 
   @Test
@@ -307,7 +307,7 @@
             options -> {
               // Disable inlining to avoid the (short) tested method from being inlined and removed.
               options.enableInlining = false;
-              options.enableArgumentRemoval = enableArgumentRemoval;
+              options.callSiteOptimizationOptions().setEnabled(enableArgumentPropagation);
             })
         .noMinification()
         .setMinApi(parameters.getApiLevel())
@@ -315,11 +315,11 @@
         .inspect(
             inspector -> {
               ClassSubject subSubject = inspector.clazz(sub.name);
-              assertNotEquals(enableArgumentRemoval, subSubject.isPresent());
+              assertNotEquals(enableArgumentPropagation, subSubject.isPresent());
             })
         .run(parameters.getRuntime(), mainClassName)
         .applyIf(
-            enableArgumentRemoval || parameters.isCfRuntime(),
+            enableArgumentPropagation || parameters.isCfRuntime(),
             SingleTestRunResult::assertSuccess,
             result ->
                 result.assertFailureWithErrorThatMatches(
@@ -410,7 +410,7 @@
             options -> {
               // Disable inlining to avoid the (short) tested method from being inlined and removed.
               options.enableInlining = false;
-              options.enableArgumentRemoval = enableArgumentRemoval;
+              options.callSiteOptimizationOptions().setEnabled(enableArgumentPropagation);
             });
 
     // Run processed (output) program on ART
@@ -422,6 +422,6 @@
 
     CodeInspector inspector = new CodeInspector(processedApp);
     ClassSubject subSubject = inspector.clazz(sub.name);
-    assertNotEquals(enableArgumentRemoval, subSubject.isPresent());
+    assertNotEquals(enableArgumentPropagation, subSubject.isPresent());
   }
 }