Revert "Widen dynamic types to unknown when they are not useful"

This reverts commit 47c973e8da359d1773c284f7869b4bc8cfc02952.


Revert "Extend argument propagator to instance initializers"

This reverts commit fc9d62680d377210deb25156c2cfad9d35352d91.


Revert "Remove unused argument removal phase"

This reverts commit 5e80fd4a33ede780636b8df6a48feaaef9fb2000.


Revert "Extend member value propagation to arrays of null"

This reverts commit 5ec70f102fced51ef6c136a8c2053e1a371e5bf7.


Revert "Refactor argument propagation to use RewrittenPrototypeDescription"

This reverts commit 8bfa6adc1641a38c7ec49c45e172c48285229ebf.


Revert "Add equals() to RewrittenPrototypeDescription"

This reverts commit 1c9d9474b9631f23723d0f37cbb0b805fc9578d3.


Revert "Remove override of final method"

This reverts commit a4d4b37a21ee4e3f6a67d40e65f6250c73da5d5b.

Change-Id: I43ed7c493f55dcef803d7243accf5940666782e8
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 65a9a2f..02ef891 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -57,6 +57,8 @@
 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;
@@ -510,15 +512,32 @@
         }
         assert appView.verticallyMergedClasses() != null;
 
-        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();
+        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();
+          }
         }
 
         HorizontalClassMerger.createForInitialClassMerging(appViewWithLiveness)
diff --git a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
index a4a886f..1133b65 100644
--- a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
+++ b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
@@ -18,9 +18,9 @@
 import com.android.tools.r8.utils.IteratorUtils;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Ordering;
-import it.unimi.dsi.fastutil.ints.Int2ObjectMap.Entry;
-import it.unimi.dsi.fastutil.ints.Int2ObjectRBTreeMap;
-import it.unimi.dsi.fastutil.ints.Int2ObjectSortedMap;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceMap.Entry;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceRBTreeMap;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
 import it.unimi.dsi.fastutil.ints.IntArrayList;
 import it.unimi.dsi.fastutil.ints.IntBidirectionalIterator;
 import it.unimi.dsi.fastutil.ints.IntCollection;
@@ -31,35 +31,14 @@
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Objects;
 import java.util.function.Consumer;
 
 public class RewrittenPrototypeDescription {
 
-  public abstract static class ArgumentInfo {
-
-    static final ArgumentInfo NO_INFO =
-        new ArgumentInfo() {
-
-          @Override
-          public ArgumentInfo combine(ArgumentInfo info) {
-            assert false : "ArgumentInfo NO_INFO should not be combined";
-            return info;
-          }
-
-          @Override
-          public boolean equals(Object obj) {
-            return obj == this;
-          }
-
-          @Override
-          public int hashCode() {
-            return System.identityHashCode(this);
-          }
-        };
+  public interface ArgumentInfo {
 
     @SuppressWarnings("ConstantConditions")
-    public static ArgumentInfo combine(ArgumentInfo arg1, ArgumentInfo arg2) {
+    static ArgumentInfo combine(ArgumentInfo arg1, ArgumentInfo arg2) {
       if (arg1 == null) {
         assert arg2 != null;
         return arg2;
@@ -71,33 +50,33 @@
       return arg1.combine(arg2);
     }
 
-    public boolean isRemovedArgumentInfo() {
+    ArgumentInfo NO_INFO =
+        info -> {
+          assert false : "ArgumentInfo NO_INFO should not be combined";
+          return info;
+        };
+
+    default boolean isRemovedArgumentInfo() {
       return false;
     }
 
-    public RemovedArgumentInfo asRemovedArgumentInfo() {
+    default RemovedArgumentInfo asRemovedArgumentInfo() {
       return null;
     }
 
-    public boolean isRewrittenTypeInfo() {
+    default boolean isRewrittenTypeInfo() {
       return false;
     }
 
-    public RewrittenTypeInfo asRewrittenTypeInfo() {
+    default RewrittenTypeInfo asRewrittenTypeInfo() {
       return null;
     }
 
     // ArgumentInfo are combined with `this` first, and the `info` argument second.
-    public abstract ArgumentInfo combine(ArgumentInfo info);
-
-    @Override
-    public abstract boolean equals(Object obj);
-
-    @Override
-    public abstract int hashCode();
+    ArgumentInfo combine(ArgumentInfo info);
   }
 
-  public static class RemovedArgumentInfo extends ArgumentInfo {
+  public static class RemovedArgumentInfo implements ArgumentInfo {
 
     public static class Builder {
 
@@ -163,23 +142,9 @@
       assert false : "Once the argument is removed one cannot modify it any further.";
       return this;
     }
-
-    @Override
-    public boolean equals(Object obj) {
-      if (obj == null || getClass() != obj.getClass()) {
-        return false;
-      }
-      RemovedArgumentInfo other = (RemovedArgumentInfo) obj;
-      return type == other.type && Objects.equals(singleValue, other.singleValue);
-    }
-
-    @Override
-    public int hashCode() {
-      return Objects.hash(singleValue, type);
-    }
   }
 
-  public static class RewrittenTypeInfo extends ArgumentInfo {
+  public static class RewrittenTypeInfo implements ArgumentInfo {
 
     private final DexType oldType;
     private final DexType newType;
@@ -236,20 +201,6 @@
       return new RewrittenTypeInfo(oldType, rewrittenTypeInfo.newType);
     }
 
-    @Override
-    public boolean equals(Object obj) {
-      if (obj == null || getClass() != obj.getClass()) {
-        return false;
-      }
-      RewrittenTypeInfo other = (RewrittenTypeInfo) obj;
-      return oldType == other.oldType && newType == other.newType;
-    }
-
-    @Override
-    public int hashCode() {
-      return Objects.hash(oldType, newType);
-    }
-
     public boolean verifyIsDueToUnboxing(DexItemFactory dexItemFactory) {
       assert oldType.toBaseType(dexItemFactory).isClassType();
       assert newType.toBaseType(dexItemFactory).isIntType();
@@ -261,14 +212,14 @@
 
     private static final ArgumentInfoCollection EMPTY = new ArgumentInfoCollection();
 
-    private final Int2ObjectSortedMap<ArgumentInfo> argumentInfos;
+    private final Int2ReferenceSortedMap<ArgumentInfo> argumentInfos;
 
     // Specific constructor for empty.
     private ArgumentInfoCollection() {
-      this.argumentInfos = new Int2ObjectRBTreeMap<>();
+      this.argumentInfos = new Int2ReferenceRBTreeMap<>();
     }
 
-    private ArgumentInfoCollection(Int2ObjectSortedMap<ArgumentInfo> argumentInfos) {
+    private ArgumentInfoCollection(Int2ReferenceSortedMap<ArgumentInfo> argumentInfos) {
       assert argumentInfos != null : "should use empty.";
       assert !argumentInfos.isEmpty() : "should use empty.";
       this.argumentInfos = argumentInfos;
@@ -279,7 +230,7 @@
     }
 
     public void forEach(IntObjConsumer<ArgumentInfo> consumer) {
-      for (Entry<ArgumentInfo> entry : argumentInfos.int2ObjectEntrySet()) {
+      for (Entry<ArgumentInfo> entry : argumentInfos.int2ReferenceEntrySet()) {
         consumer.accept(entry.getIntKey(), entry.getValue());
       }
     }
@@ -316,7 +267,7 @@
     }
 
     public Iterator<Entry<ArgumentInfo>> iterator() {
-      return argumentInfos.int2ObjectEntrySet().iterator();
+      return argumentInfos.int2ReferenceEntrySet().iterator();
     }
 
     public boolean hasRemovedArguments() {
@@ -350,31 +301,17 @@
       return argumentInfos.size();
     }
 
-    @Override
-    public boolean equals(Object obj) {
-      if (obj == null || getClass() != obj.getClass()) {
-        return false;
-      }
-      ArgumentInfoCollection other = (ArgumentInfoCollection) obj;
-      return argumentInfos.equals(other.argumentInfos);
-    }
-
-    @Override
-    public int hashCode() {
-      return argumentInfos.hashCode();
-    }
-
     public static Builder builder() {
       return new Builder();
     }
 
     public static class Builder {
 
-      private Int2ObjectSortedMap<ArgumentInfo> argumentInfos;
+      private Int2ReferenceSortedMap<ArgumentInfo> argumentInfos;
 
       public Builder addArgumentInfo(int argIndex, ArgumentInfo argInfo) {
         if (argumentInfos == null) {
-          argumentInfos = new Int2ObjectRBTreeMap<>();
+          argumentInfos = new Int2ReferenceRBTreeMap<>();
         }
         assert !argumentInfos.containsKey(argIndex);
         argumentInfos.put(argIndex, argInfo);
@@ -440,7 +377,7 @@
         }
       }
 
-      Int2ObjectSortedMap<ArgumentInfo> newArgInfos = new Int2ObjectRBTreeMap<>();
+      Int2ReferenceSortedMap<ArgumentInfo> newArgInfos = new Int2ReferenceRBTreeMap<>();
       newArgInfos.putAll(argumentInfos);
       IntBidirectionalIterator iterator = argumentInfos.keySet().iterator();
       int offset = 0;
@@ -540,7 +477,7 @@
     assert !isEmpty();
   }
 
-  public static RewrittenPrototypeDescription create(
+  private static RewrittenPrototypeDescription create(
       List<ExtraParameter> extraParameters,
       RewrittenTypeInfo rewrittenReturnInfo,
       ArgumentInfoCollection argumentsInfo) {
@@ -570,11 +507,6 @@
     return NONE;
   }
 
-  public Consumer<DexEncodedMethod.Builder> createParameterAnnotationsRemover(
-      DexEncodedMethod method) {
-    return getArgumentInfoCollection().createParameterAnnotationsRemover(method);
-  }
-
   public MethodOptimizationInfoFixer createMethodOptimizationInfoFixer() {
     return new RewrittenPrototypeDescriptionMethodOptimizationInfoFixer(this);
   }
@@ -729,20 +661,4 @@
     return new RewrittenPrototypeDescription(
         newExtraParameters, rewrittenReturnInfo, argumentInfoCollection);
   }
-
-  @Override
-  public boolean equals(Object obj) {
-    if (obj == null || getClass() != obj.getClass()) {
-      return false;
-    }
-    RewrittenPrototypeDescription other = (RewrittenPrototypeDescription) obj;
-    return extraParameters.equals(other.extraParameters)
-        && Objects.equals(rewrittenReturnInfo, other.rewrittenReturnInfo)
-        && argumentInfoCollection.equals(other.argumentInfoCollection);
-  }
-
-  @Override
-  public int hashCode() {
-    return Objects.hash(extraParameters, rewrittenReturnInfo, argumentInfoCollection);
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java b/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
index 0f2e98a..83dfa77 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
@@ -46,10 +46,6 @@
         || result == null;
   }
 
-  public static Builder builder() {
-    return new Builder();
-  }
-
   @Override
   public int opcode() {
     return Opcodes.INVOKE_DIRECT;
@@ -214,17 +210,4 @@
 
     return LibraryMethodReadSetModeling.getModeledReadSetOrUnknown(appView, this);
   }
-
-  public static class Builder extends InvokeMethod.Builder<Builder, InvokeDirect> {
-
-    @Override
-    public InvokeDirect build() {
-      return amend(new InvokeDirect(method, outValue, arguments));
-    }
-
-    @Override
-    public Builder self() {
-      return this;
-    }
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/ExtraConstantIntParameter.java b/src/main/java/com/android/tools/r8/ir/conversion/ExtraConstantIntParameter.java
index b0544d9..d698e7a 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/ExtraConstantIntParameter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/ExtraConstantIntParameter.java
@@ -10,8 +10,7 @@
 import com.android.tools.r8.ir.analysis.value.SingleNumberValue;
 
 public class ExtraConstantIntParameter extends ExtraParameter {
-
-  private final long value;
+  long value;
 
   public ExtraConstantIntParameter(long value) {
     this.value = value;
@@ -27,18 +26,4 @@
   public SingleNumberValue getValue(AppView<?> appView) {
     return appView.abstractValueFactory().createSingleNumberValue(value);
   }
-
-  @Override
-  public boolean equals(Object obj) {
-    if (obj == null || getClass() != obj.getClass()) {
-      return false;
-    }
-    ExtraConstantIntParameter other = (ExtraConstantIntParameter) obj;
-    return value == other.value;
-  }
-
-  @Override
-  public int hashCode() {
-    return Long.hashCode(value);
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/ExtraParameter.java b/src/main/java/com/android/tools/r8/ir/conversion/ExtraParameter.java
index 6211fa3..93f52df 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/ExtraParameter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/ExtraParameter.java
@@ -10,14 +10,7 @@
 import com.android.tools.r8.ir.analysis.value.SingleNumberValue;
 
 public abstract class ExtraParameter {
-
   public abstract TypeElement getTypeElement(AppView<?> appView, DexType argType);
 
   public abstract SingleNumberValue getValue(AppView<?> appView);
-
-  @Override
-  public abstract boolean equals(Object obj);
-
-  @Override
-  public abstract int hashCode();
 }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/ExtraUnusedNullParameter.java b/src/main/java/com/android/tools/r8/ir/conversion/ExtraUnusedNullParameter.java
index a543a0c..f478661 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/ExtraUnusedNullParameter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/ExtraUnusedNullParameter.java
@@ -21,14 +21,4 @@
   public SingleNumberValue getValue(AppView<?> appView) {
     return appView.abstractValueFactory().createNullValue();
   }
-
-  @Override
-  public boolean equals(Object obj) {
-    return obj != null && getClass() == obj.getClass();
-  }
-
-  @Override
-  public int hashCode() {
-    return 0;
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 77c7af7..a165209 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -94,7 +94,6 @@
 import com.android.tools.r8.ir.regalloc.RegisterAllocator;
 import com.android.tools.r8.logging.Log;
 import com.android.tools.r8.naming.IdentifierNameStringMarker;
-import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagator;
 import com.android.tools.r8.position.MethodPosition;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.shaking.LibraryMethodOverrideAnalysis;
@@ -836,7 +835,6 @@
     if (options.enableFieldAssignmentTracker) {
       fieldAccessAnalysis.fieldAssignmentTracker().waveDone(wave, delayedOptimizationFeedback);
     }
-    appView.withArgumentPropagator(ArgumentPropagator::publishDelayedReprocessingCriteria);
     if (appView.options().protoShrinking().enableRemoveProtoEnumSwitchMap()) {
       appView.protoShrinker().protoEnumSwitchMapRemover.updateVisibleStaticFieldValues();
     }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
index 9e8d052..9608eed 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
@@ -17,13 +17,11 @@
 import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
 import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
 import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
 import com.android.tools.r8.ir.analysis.value.SingleValue;
 import com.android.tools.r8.ir.analysis.value.UnknownValue;
-import com.android.tools.r8.ir.code.ArrayGet;
 import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.FieldInstruction;
 import com.android.tools.r8.ir.code.IRCode;
@@ -65,63 +63,6 @@
     this.reporter = appView.options().reporter;
   }
 
-  private void rewriteArrayGet(
-      IRCode code,
-      ProgramMethod context,
-      Set<Value> affectedValues,
-      ListIterator<BasicBlock> blocks,
-      InstructionListIterator iterator,
-      ArrayGet arrayGet) {
-    TypeElement arrayType = arrayGet.array().getType();
-    if (!arrayType.isArrayType()) {
-      // Does not type check.
-      return;
-    }
-
-    TypeElement memberType = arrayType.asArrayType().getMemberType();
-    if (!memberType.isClassType()) {
-      // We don't know what the value of the element is.
-      return;
-    }
-
-    boolean isAlwaysNull = false;
-    ClassTypeElement memberClassType = memberType.asClassType();
-    if (memberClassType.getClassType().isAlwaysNull(appView)) {
-      isAlwaysNull = true;
-    } else if (memberClassType.getInterfaces().hasSingleKnownInterface()) {
-      isAlwaysNull =
-          memberClassType.getInterfaces().getSingleKnownInterface().isAlwaysNull(appView);
-    }
-
-    if (!isAlwaysNull) {
-      // We don't know what the value of the element is.
-      return;
-    }
-
-    BasicBlock block = arrayGet.getBlock();
-    Position position = arrayGet.getPosition();
-
-    // All usages are replaced by the replacement value.
-    Instruction replacement =
-        appView
-            .abstractValueFactory()
-            .createNullValue()
-            .createMaterializingInstruction(appView, code, arrayGet);
-    affectedValues.addAll(arrayGet.outValue().affectedValues());
-    arrayGet.outValue().replaceUsers(replacement.outValue());
-
-    // Insert the definition of the replacement.
-    replacement.setPosition(position);
-    if (block.hasCatchHandlers()) {
-      iterator
-          .splitCopyCatchHandlers(code, blocks, appView.options())
-          .listIterator(code)
-          .add(replacement);
-    } else {
-      iterator.add(replacement);
-    }
-  }
-
   private boolean mayPropagateValueFor(DexClassAndField field) {
     if (field.isProgramField()) {
       return appView.appInfo().mayPropagateValueFor(field.getReference());
@@ -531,10 +472,7 @@
       InstructionListIterator iterator = block.listIterator(code);
       while (iterator.hasNext()) {
         Instruction current = iterator.next();
-        if (current.isArrayGet()) {
-          rewriteArrayGet(
-              code, context, affectedValues, blockIterator, iterator, current.asArrayGet());
-        } else if (current.isInvokeMethod()) {
+        if (current.isInvokeMethod()) {
           rewriteInvokeMethodWithConstantValues(
               code, context, affectedValues, blockIterator, iterator, current.asInvokeMethod());
         } else if (current.isFieldGet()) {
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 2b439a6..652c185 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,10 +34,6 @@
 
   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
new file mode 100644
index 0000000..052e196
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java
@@ -0,0 +1,333 @@
+// 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/ir/optimize/enums/EnumUnboxingTreeFixer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
index d2a73ed..8a97aef 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
@@ -20,7 +20,6 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.DexValue;
 import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
-import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.ProgramField;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -57,14 +56,13 @@
 import com.android.tools.r8.utils.collections.ProgramMethodMap;
 import com.google.common.collect.BiMap;
 import com.google.common.collect.HashBiMap;
+import com.google.common.collect.Sets;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.IdentityHashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.ListIterator;
 import java.util.Map;
-import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
@@ -243,22 +241,13 @@
     // Rewrite enum instantiations + remove static-puts to pruned fields.
     IRCode code = classInitializer.buildIR(appView);
     ListIterator<BasicBlock> blockIterator = code.listIterator();
-
-    // A mapping from instructions-to-be-removed from the IR to their lens-rewritten
-    // instruction (if any). If an instruction-to-be-removed has a lens-rewritten instruction, the
-    // lens-rewritten instruction must also be detached from the IR.
-    Map<Instruction, Optional<Instruction>> instructionsToRemove = new IdentityHashMap<>();
+    Set<Instruction> instructionsToRemove = Sets.newIdentityHashSet();
     while (blockIterator.hasNext()) {
       BasicBlock block = blockIterator.next();
       InstructionListIterator instructionIterator = block.listIterator(code);
       while (instructionIterator.hasNext()) {
         Instruction instruction = instructionIterator.next();
-        if (instructionsToRemove.containsKey(instruction)) {
-          Optional<Instruction> rewrittenInstruction = instructionsToRemove.remove(instruction);
-          if (rewrittenInstruction.isPresent()) {
-            instructionIterator.replaceCurrentInstruction(rewrittenInstruction.get());
-            instructionIterator.previous();
-          }
+        if (instructionsToRemove.remove(instruction)) {
           instructionIterator.removeOrReplaceByDebugLocalRead();
           continue;
         }
@@ -305,47 +294,8 @@
                 newInstance.getUniqueConstructorInvoke(appView.dexItemFactory());
             assert constructorInvoke != null;
 
-            DexMethod invokedMethod = constructorInvoke.getInvokedMethod();
-
-            // Rewrite the constructor invoke in case there are any removed arguments. This is
-            // required since we find the argument index of the ordinal value below, and use this to
-            // find the ordinal of the current enum instance.
-            MethodLookupResult lookupResult =
-                appView.graphLens().lookupInvokeDirect(invokedMethod, classInitializer);
-            if (lookupResult.getReference() != invokedMethod) {
-              List<Value> rewrittenArguments =
-                  new ArrayList<>(constructorInvoke.arguments().size());
-              for (int i = 0; i < constructorInvoke.arguments().size(); i++) {
-                Value argument = constructorInvoke.getArgument(i);
-                if (!lookupResult
-                    .getPrototypeChanges()
-                    .getArgumentInfoCollection()
-                    .isArgumentRemoved(i)) {
-                  rewrittenArguments.add(argument);
-                }
-              }
-              InvokeDirect originalConstructorInvoke = constructorInvoke;
-              constructorInvoke =
-                  InvokeDirect.builder()
-                      .setArguments(rewrittenArguments)
-                      .setMethod(lookupResult.getReference())
-                      .build();
-
-              // Record that the original constructor invoke has been rewritten into the new
-              // constructor invoke, and that these instructions need to be removed from the IR.
-              // Note that although the rewritten constructor invoke has not been inserted into the
-              // IR, the creation of it has added it as a user of each of the operands. To undo this
-              // we replace the original constructor invoke by the rewritten constructor invoke and
-              // then remove the rewritten constructor invoke from the IR.
-              instructionsToRemove.put(originalConstructorInvoke, Optional.of(constructorInvoke));
-            } else {
-              assert lookupResult.getPrototypeChanges().isEmpty();
-              // Record that the constructor invoke needs to be removed.
-              instructionsToRemove.put(constructorInvoke, Optional.empty());
-            }
-
             ProgramMethod constructor =
-                unboxedEnum.lookupProgramMethod(lookupResult.getReference());
+                unboxedEnum.lookupProgramMethod(constructorInvoke.getInvokedMethod());
             assert constructor != null;
 
             InstanceFieldInitializationInfo ordinalInitializationInfo =
@@ -384,6 +334,8 @@
                     code.createValue(
                         ClassTypeElement.create(
                             unboxedEnum.getType(), definitelyNotNull(), appView))));
+
+            instructionsToRemove.add(constructorInvoke);
           }
         } else if (instruction.isStaticPut()) {
           StaticPut staticPut = instruction.asStaticPut();
@@ -406,13 +358,7 @@
     if (!instructionsToRemove.isEmpty()) {
       InstructionListIterator instructionIterator = code.instructionListIterator();
       while (instructionIterator.hasNext()) {
-        Instruction instruction = instructionIterator.next();
-        if (instructionsToRemove.containsKey(instruction)) {
-          Optional<Instruction> rewrittenInstruction = instructionsToRemove.get(instruction);
-          if (rewrittenInstruction.isPresent()) {
-            instructionIterator.replaceCurrentInstruction(rewrittenInstruction.get());
-            instructionIterator.previous();
-          }
+        if (instructionsToRemove.remove(instructionIterator.next())) {
           instructionIterator.removeOrReplaceByDebugLocalRead();
         }
       }
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
index 645bac0..cabc28f 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
@@ -67,8 +67,8 @@
     timing.begin("Argument propagator");
     timing.begin("Initialize code scanner");
 
+    codeScanner = new ArgumentPropagatorCodeScanner(appView);
     reprocessingCriteriaCollection = new ArgumentPropagatorReprocessingCriteriaCollection(appView);
-    codeScanner = new ArgumentPropagatorCodeScanner(appView, reprocessingCriteriaCollection);
 
     ImmediateProgramSubtypingInfo immediateSubtypingInfo =
         ImmediateProgramSubtypingInfo.create(appView);
@@ -110,11 +110,6 @@
     }
   }
 
-  public void publishDelayedReprocessingCriteria() {
-    assert reprocessingCriteriaCollection != null;
-    reprocessingCriteriaCollection.publishDelayedReprocessingCriteria();
-  }
-
   public void transferArgumentInformation(ProgramMethod from, ProgramMethod to) {
     assert codeScanner != null;
     MethodStateCollectionByReference methodStates = codeScanner.getMethodStates();
@@ -130,8 +125,6 @@
       Timing timing)
       throws ExecutionException {
     assert !appView.getSyntheticItems().hasPendingSyntheticClasses();
-    assert reprocessingCriteriaCollection.verifyNoDelayedReprocessingCriteria();
-
     timing.begin("Argument propagator");
 
     // Compute the strongly connected program components for parallel execution.
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorApplicationFixer.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorApplicationFixer.java
index 890cb48..beb3003 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorApplicationFixer.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorApplicationFixer.java
@@ -8,7 +8,7 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.MethodCollection;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.ThreadUtils;
 import com.android.tools.r8.utils.Timing;
@@ -66,12 +66,12 @@
           return method.toTypeSubstitutedMethod(
               methodReferenceAfterParameterRemoval,
               builder -> {
-                RewrittenPrototypeDescription prototypeChanges =
-                    graphLens.getPrototypeChanges(methodReferenceAfterParameterRemoval);
+                ArgumentInfoCollection removedParameters =
+                    graphLens.getRemovedParameters(methodReferenceAfterParameterRemoval);
                 builder
-                    .apply(prototypeChanges.createParameterAnnotationsRemover(method))
+                    .apply(removedParameters.createParameterAnnotationsRemover(method))
                     .fixupOptimizationInfo(
-                        appView, prototypeChanges.createMethodOptimizationInfoFixer());
+                        appView, removedParameters.createMethodOptimizationInfoFixer());
               });
         });
   }
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 4d19a71..a61d0b4 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
@@ -40,9 +40,6 @@
 import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodStateCollectionByReference;
 import com.android.tools.r8.optimize.argumentpropagation.codescanner.ParameterState;
 import com.android.tools.r8.optimize.argumentpropagation.codescanner.UnknownMethodState;
-import com.android.tools.r8.optimize.argumentpropagation.reprocessingcriteria.ArgumentPropagatorReprocessingCriteriaCollection;
-import com.android.tools.r8.optimize.argumentpropagation.reprocessingcriteria.MethodReprocessingCriteria;
-import com.android.tools.r8.optimize.argumentpropagation.reprocessingcriteria.ParameterReprocessingCriteria;
 import com.android.tools.r8.optimize.argumentpropagation.utils.WideningUtils;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.Timing;
@@ -71,8 +68,6 @@
 
   private final Set<DexMethod> monomorphicVirtualMethods = Sets.newIdentityHashSet();
 
-  private final ArgumentPropagatorReprocessingCriteriaCollection reprocessingCriteriaCollection;
-
   /**
    * Maps each non-private virtual method to the upper most method in the class hierarchy with the
    * same method signature. Virtual methods that do not override other virtual methods are mapped to
@@ -87,11 +82,8 @@
   private final MethodStateCollectionByReference methodStates =
       MethodStateCollectionByReference.createConcurrent();
 
-  ArgumentPropagatorCodeScanner(
-      AppView<AppInfoWithLiveness> appView,
-      ArgumentPropagatorReprocessingCriteriaCollection reprocessingCriteriaCollection) {
+  ArgumentPropagatorCodeScanner(AppView<AppInfoWithLiveness> appView) {
     this.appView = appView;
-    this.reprocessingCriteriaCollection = reprocessingCriteriaCollection;
   }
 
   public synchronized void addMonomorphicVirtualMethods(Set<DexMethod> extension) {
@@ -267,11 +259,7 @@
       assert existingMethodState.isBottom() || existingMethodState.isMonomorphic();
       result =
           computeMonomorphicMethodState(
-              invoke,
-              resolvedMethod,
-              invoke.lookupSingleProgramTarget(appView, context),
-              context,
-              existingMethodState.asMonomorphicOrBottom());
+              invoke, resolvedMethod, context, existingMethodState.asMonomorphicOrBottom());
     }
     timing.end();
     return result;
@@ -288,10 +276,9 @@
     DynamicType dynamicReceiverType = invoke.getReceiver().getDynamicType(appView);
     assert !dynamicReceiverType.getDynamicUpperBoundType().nullability().isDefinitelyNull();
 
-    ProgramMethod singleTarget = invoke.lookupSingleProgramTarget(appView, context);
     DynamicType bounds =
         computeBoundsForPolymorphicMethodState(
-            invoke, resolvedMethod, singleTarget, context, dynamicReceiverType);
+            invoke, resolvedMethod, context, dynamicReceiverType);
     MethodState existingMethodStateForBounds =
         existingMethodState.isPolymorphic()
             ? existingMethodState.asPolymorphic().getMethodStateForBounds(bounds)
@@ -312,7 +299,6 @@
         computeMonomorphicMethodState(
             invoke,
             resolvedMethod,
-            singleTarget,
             context,
             existingMethodStateForBounds.asMonomorphicOrBottom(),
             dynamicReceiverType);
@@ -322,9 +308,9 @@
   private DynamicType computeBoundsForPolymorphicMethodState(
       InvokeMethodWithReceiver invoke,
       ProgramMethod resolvedMethod,
-      ProgramMethod singleTarget,
       ProgramMethod context,
       DynamicType dynamicReceiverType) {
+    ProgramMethod singleTarget = invoke.lookupSingleProgramTarget(appView, context);
     DynamicType bounds =
         singleTarget != null
             ? DynamicType.createExact(
@@ -357,13 +343,11 @@
   private ConcreteMonomorphicMethodStateOrUnknown computeMonomorphicMethodState(
       InvokeMethod invoke,
       ProgramMethod resolvedMethod,
-      ProgramMethod singleTarget,
       ProgramMethod context,
       ConcreteMonomorphicMethodStateOrBottom existingMethodState) {
     return computeMonomorphicMethodState(
         invoke,
         resolvedMethod,
-        singleTarget,
         context,
         existingMethodState,
         invoke.isInvokeMethodWithReceiver()
@@ -374,17 +358,11 @@
   private ConcreteMonomorphicMethodStateOrUnknown computeMonomorphicMethodState(
       InvokeMethod invoke,
       ProgramMethod resolvedMethod,
-      ProgramMethod singleTarget,
       ProgramMethod context,
       ConcreteMonomorphicMethodStateOrBottom existingMethodState,
       DynamicType dynamicReceiverType) {
     List<ParameterState> parameterStates = new ArrayList<>(invoke.arguments().size());
 
-    MethodReprocessingCriteria methodReprocessingCriteria =
-        singleTarget != null
-            ? reprocessingCriteriaCollection.getReprocessingCriteria(singleTarget)
-            : MethodReprocessingCriteria.alwaysReprocess();
-
     int argumentIndex = 0;
     if (invoke.isInvokeMethodWithReceiver()) {
       assert dynamicReceiverType != null;
@@ -393,8 +371,7 @@
               invoke.asInvokeMethodWithReceiver(),
               resolvedMethod,
               dynamicReceiverType,
-              existingMethodState,
-              methodReprocessingCriteria.getParameterReprocessingCriteria(0)));
+              existingMethodState));
       argumentIndex++;
     }
 
@@ -405,8 +382,7 @@
               argumentIndex,
               invoke.getArgument(argumentIndex),
               context,
-              existingMethodState,
-              methodReprocessingCriteria.getParameterReprocessingCriteria(argumentIndex)));
+              existingMethodState));
     }
 
     // If all parameter states are unknown, then return a canonicalized unknown method state that
@@ -426,20 +402,13 @@
       InvokeMethodWithReceiver invoke,
       ProgramMethod resolvedMethod,
       DynamicType dynamicReceiverType,
-      ConcreteMonomorphicMethodStateOrBottom existingMethodState,
-      ParameterReprocessingCriteria parameterReprocessingCriteria) {
+      ConcreteMonomorphicMethodStateOrBottom existingMethodState) {
     // Don't compute a state for this parameter if the stored state is already unknown.
     if (existingMethodState.isMonomorphic()
         && existingMethodState.asMonomorphic().getParameterState(0).isUnknown()) {
       return ParameterState.unknown();
     }
 
-    // For receivers we only track the dynamic type. Therefore, if there is no need to track the
-    // dynamic type of the receiver of the targeted method, then just return unknown.
-    if (!parameterReprocessingCriteria.shouldReprocessDueToDynamicType()) {
-      return ParameterState.unknown();
-    }
-
     DynamicType widenedDynamicReceiverType =
         WideningUtils.widenDynamicReceiverType(appView, resolvedMethod, dynamicReceiverType);
     return widenedDynamicReceiverType.isUnknown()
@@ -452,8 +421,7 @@
       int argumentIndex,
       Value argument,
       ProgramMethod context,
-      ConcreteMonomorphicMethodStateOrBottom existingMethodState,
-      ParameterReprocessingCriteria parameterReprocessingCriteria) {
+      ConcreteMonomorphicMethodStateOrBottom existingMethodState) {
     // Don't compute a state for this parameter if the stored state is already unknown.
     if (existingMethodState.isMonomorphic()
         && existingMethodState.asMonomorphic().getParameterState(argumentIndex).isUnknown()) {
@@ -501,12 +469,6 @@
     // then use UnknownParameterState.
     if (parameterTypeElement.isClassType()) {
       DynamicType dynamicType = argument.getDynamicType(appView);
-      if (!parameterReprocessingCriteria.shouldReprocessDueToDynamicType()) {
-        dynamicType =
-            parameterReprocessingCriteria.widenDynamicClassType(
-                appView, dynamicType, parameterTypeElement.asClassType());
-      }
-
       DynamicType widenedDynamicType =
           WideningUtils.widenDynamicNonReceiverType(appView, dynamicType, parameterType);
       return abstractValue.isUnknown() && widenedDynamicType.isUnknown()
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorGraphLens.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorGraphLens.java
index c3fe41b..a00c016 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorGraphLens.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorGraphLens.java
@@ -8,6 +8,7 @@
 import com.android.tools.r8.graph.DexMethod;
 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.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
 import com.android.tools.r8.utils.collections.BidirectionalOneToOneMap;
@@ -17,23 +18,23 @@
 
 public class ArgumentPropagatorGraphLens extends NestedGraphLens {
 
-  private final Map<DexMethod, RewrittenPrototypeDescription> prototypeChanges;
+  private final Map<DexMethod, ArgumentInfoCollection> removedParameters;
 
   ArgumentPropagatorGraphLens(
       AppView<AppInfoWithLiveness> appView,
       BidirectionalOneToOneMap<DexMethod, DexMethod> methodMap,
-      Map<DexMethod, RewrittenPrototypeDescription> prototypeChanges) {
+      Map<DexMethod, ArgumentInfoCollection> removedParameters) {
     super(appView, EMPTY_FIELD_MAP, methodMap, EMPTY_TYPE_MAP);
-    this.prototypeChanges = prototypeChanges;
+    this.removedParameters = removedParameters;
   }
 
   public static Builder builder(AppView<AppInfoWithLiveness> appView) {
     return new Builder(appView);
   }
 
-  public RewrittenPrototypeDescription getPrototypeChanges(DexMethod method) {
+  public ArgumentInfoCollection getRemovedParameters(DexMethod method) {
     assert method != internalGetPreviousMethodSignature(method);
-    return prototypeChanges.getOrDefault(method, RewrittenPrototypeDescription.none());
+    return removedParameters.getOrDefault(method, ArgumentInfoCollection.empty());
   }
 
   @Override
@@ -41,10 +42,10 @@
       RewrittenPrototypeDescription prototypeChanges, DexMethod method) {
     DexMethod previous = internalGetPreviousMethodSignature(method);
     if (previous == method) {
-      assert !this.prototypeChanges.containsKey(method);
+      assert !removedParameters.containsKey(method);
       return prototypeChanges;
     }
-    return prototypeChanges.combine(getPrototypeChanges(method));
+    return prototypeChanges.withRemovedArguments(getRemovedParameters(method));
   }
 
   @Override
@@ -62,7 +63,7 @@
     private final AppView<AppInfoWithLiveness> appView;
     private final MutableBidirectionalOneToOneMap<DexMethod, DexMethod> newMethodSignatures =
         new BidirectionalOneToOneHashMap<>();
-    private final Map<DexMethod, RewrittenPrototypeDescription> prototypeChanges =
+    private final Map<DexMethod, ArgumentInfoCollection> removedParameters =
         new IdentityHashMap<>();
 
     Builder(AppView<AppInfoWithLiveness> appView) {
@@ -76,16 +77,16 @@
     public ArgumentPropagatorGraphLens.Builder mergeDisjoint(
         ArgumentPropagatorGraphLens.Builder partialGraphLensBuilder) {
       newMethodSignatures.putAll(partialGraphLensBuilder.newMethodSignatures);
-      prototypeChanges.putAll(partialGraphLensBuilder.prototypeChanges);
+      removedParameters.putAll(partialGraphLensBuilder.removedParameters);
       return this;
     }
 
     public Builder recordMove(
-        DexMethod from, DexMethod to, RewrittenPrototypeDescription prototypeChangesForMethod) {
+        DexMethod from, DexMethod to, ArgumentInfoCollection removedParametersForMethod) {
       assert from != to;
       newMethodSignatures.put(from, to);
-      if (!prototypeChangesForMethod.isEmpty()) {
-        prototypeChanges.put(to, prototypeChangesForMethod);
+      if (!removedParametersForMethod.isEmpty()) {
+        removedParameters.put(to, removedParametersForMethod);
       }
       return this;
     }
@@ -93,7 +94,7 @@
     public ArgumentPropagatorGraphLens build() {
       return isEmpty()
           ? null
-          : new ArgumentPropagatorGraphLens(appView, newMethodSignatures, prototypeChanges);
+          : new ArgumentPropagatorGraphLens(appView, newMethodSignatures, removedParameters);
     }
   }
 }
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 ae2a8aa..6f97143 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,7 +18,6 @@
 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;
@@ -160,11 +159,6 @@
       return;
     }
 
-    // Do not optimize @KeepConstantArgument methods.
-    if (appView.appInfo().isKeepConstantArgumentsMethod(method)) {
-      methodState = MethodState.unknown();
-    }
-
     methodState = getMethodStateAfterUnusedParameterRemoval(method, methodState);
 
     if (methodState.isUnknown()) {
@@ -214,9 +208,12 @@
     // before reenqueing.
     MethodReprocessingCriteria reprocessingCriteria =
         reprocessingCriteriaCollection.getReprocessingCriteria(method);
-    ConcreteMonomorphicMethodStateOrUnknown widenedMethodState =
-        reprocessingCriteria.widenMethodState(appView, method, monomorphicMethodState);
-    if (widenedMethodState.isUnknown()) {
+    if (!reprocessingCriteria.shouldReprocess(appView, method, monomorphicMethodState)) {
+      return;
+    }
+
+    // Do not optimize @KeepConstantArgument methods.
+    if (appView.appInfo().isKeepConstantArgumentsMethod(method)) {
       return;
     }
 
@@ -224,7 +221,7 @@
         .getDefinition()
         .setCallSiteOptimizationInfo(
             ConcreteCallSiteOptimizationInfo.fromMethodState(
-                appView, method, widenedMethodState.asMonomorphic()));
+                appView, method, monomorphicMethodState));
   }
 
   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 055013f..5f14c9d 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
@@ -16,7 +16,6 @@
 import com.android.tools.r8.graph.ImmediateProgramSubtypingInfo;
 import com.android.tools.r8.graph.ObjectAllocationInfoCollection;
 import com.android.tools.r8.graph.ProgramMethod;
-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.analysis.value.AbstractValue;
@@ -55,8 +54,7 @@
   private final AppView<AppInfoWithLiveness> appView;
   private final ImmediateProgramSubtypingInfo immediateSubtypingInfo;
 
-  private final Map<DexClass, DexMethodSignatureSet> libraryVirtualMethods =
-      new ConcurrentHashMap<>();
+  private final Map<DexClass, DexMethodSignatureSet> libraryMethods = new ConcurrentHashMap<>();
 
   public ArgumentPropagatorProgramOptimizer(
       AppView<AppInfoWithLiveness> appView, ImmediateProgramSubtypingInfo immediateSubtypingInfo) {
@@ -90,25 +88,25 @@
     return graphLens;
   }
 
-  private DexMethodSignatureSet getOrComputeLibraryVirtualMethods(DexClass clazz) {
-    DexMethodSignatureSet libraryMethodsOnClass = libraryVirtualMethods.get(clazz);
+  private DexMethodSignatureSet getOrComputeLibraryMethods(DexClass clazz) {
+    DexMethodSignatureSet libraryMethodsOnClass = libraryMethods.get(clazz);
     if (libraryMethodsOnClass != null) {
       return libraryMethodsOnClass;
     }
-    return computeLibraryVirtualMethods(clazz);
+    return computeLibraryMethods(clazz);
   }
 
-  private DexMethodSignatureSet computeLibraryVirtualMethods(DexClass clazz) {
+  private DexMethodSignatureSet computeLibraryMethods(DexClass clazz) {
     DexMethodSignatureSet libraryMethodsOnClass = DexMethodSignatureSet.create();
     immediateSubtypingInfo.forEachImmediateSuperClassMatching(
         clazz,
         (supertype, superclass) -> superclass != null,
         (supertype, superclass) ->
-            libraryMethodsOnClass.addAll(getOrComputeLibraryVirtualMethods(superclass)));
+            libraryMethodsOnClass.addAll(getOrComputeLibraryMethods(superclass)));
     clazz.forEachClassMethodMatching(
         DexEncodedMethod::belongsToVirtualPool,
         method -> libraryMethodsOnClass.add(method.getMethodSignature()));
-    libraryVirtualMethods.put(clazz, libraryMethodsOnClass);
+    libraryMethods.put(clazz, libraryMethodsOnClass);
     return libraryMethodsOnClass;
   }
 
@@ -184,8 +182,7 @@
       DexMethodSignatureSet pinnedMethodSignatures = DexMethodSignatureSet.create();
       Set<DexClass> seenLibraryClasses = Sets.newIdentityHashSet();
       for (DexProgramClass clazz : stronglyConnectedProgramClasses) {
-        clazz.forEachProgramMethodMatching(
-            method -> !method.isInstanceInitializer(),
+        clazz.forEachProgramMethod(
             method -> {
               if (!appView.getKeepInfo(method).isShrinkingAllowed(options)) {
                 pinnedMethodSignatures.add(method.getMethodSignature());
@@ -198,7 +195,7 @@
                     && !superclass.isProgramClass()
                     && seenLibraryClasses.add(superclass),
             (supertype, superclass) ->
-                pinnedMethodSignatures.addAll(getOrComputeLibraryVirtualMethods(superclass)));
+                pinnedMethodSignatures.addAll(getOrComputeLibraryMethods(superclass)));
       }
       pinnedMethodSignatures.forEach(
           signature -> reserveMethodSignature(signature, signature, IntSets.EMPTY_SET));
@@ -269,7 +266,6 @@
     private boolean isParameterRemovalAllowed(ProgramMethod method) {
       return appView.getKeepInfo(method).isParameterRemovalAllowed(options)
           && !method.getDefinition().isLibraryMethodOverride().isPossiblyTrue()
-          && !appView.appInfo().isBootstrapMethod(method)
           && !appView.appInfo().isMethodTargetedByInvokeDynamic(method);
     }
 
@@ -310,19 +306,16 @@
     private boolean visitClass(
         DexProgramClass clazz, ArgumentPropagatorGraphLens.Builder partialGraphLensBuilder) {
       BooleanBox affected = new BooleanBox();
-      DexMethodSignatureSet instanceInitializerSignatures = DexMethodSignatureSet.create();
-      clazz.forEachProgramInstanceInitializer(instanceInitializerSignatures::add);
       clazz.forEachProgramMethod(
           method -> {
-            RewrittenPrototypeDescription prototypeChanges =
+            ArgumentInfoCollection removableParameters =
                 method.getDefinition().belongsToDirectPool()
-                    ? computeRemovableParametersFromDirectMethod(
-                        method, instanceInitializerSignatures)
+                    ? computeRemovableParametersFromDirectMethod(method)
                     : computeRemovableParametersFromVirtualMethod(method);
-            DexMethod newMethodSignature = getNewMethodSignature(method, prototypeChanges);
+            DexMethod newMethodSignature = getNewMethodSignature(method, removableParameters);
             if (newMethodSignature != method.getReference()) {
               partialGraphLensBuilder.recordMove(
-                  method.getReference(), newMethodSignature, prototypeChanges);
+                  method.getReference(), newMethodSignature, removableParameters);
               affected.set();
             }
           });
@@ -330,32 +323,30 @@
     }
 
     private DexMethod getNewMethodSignature(
-        ProgramMethod method, RewrittenPrototypeDescription prototypeChanges) {
-      DexMethodSignature methodSignatureWithoutPrototypeChanges = method.getMethodSignature();
-      IntSet removableParameterIndices = prototypeChanges.getArgumentInfoCollection().getKeys();
+        ProgramMethod method, ArgumentInfoCollection removableParameters) {
+      DexMethodSignature methodSignatureWithoutParametersRemoved = method.getMethodSignature();
+      IntSet removableParameterIndices = removableParameters.getKeys();
 
       // Check if there is a reserved signature for this already.
       DexMethodSignature reservedSignature =
           newMethodSignatures
-              .getOrDefault(methodSignatureWithoutPrototypeChanges, Collections.emptyMap())
+              .getOrDefault(methodSignatureWithoutParametersRemoved, Collections.emptyMap())
               .get(removableParameterIndices);
       if (reservedSignature != null) {
         return reservedSignature.withHolder(method.getHolderType(), dexItemFactory);
       }
 
       DexMethod methodReferenceWithParametersRemoved =
-          prototypeChanges.getArgumentInfoCollection().rewriteMethod(method, dexItemFactory);
+          removableParameters.rewriteMethod(method, dexItemFactory);
       DexMethodSignature methodSignatureWithParametersRemoved =
           methodReferenceWithParametersRemoved.getSignature();
 
       // Find a method signature. First check if the current signature is available.
       if (!occupiedMethodSignatures.containsKey(methodSignatureWithParametersRemoved)) {
-        if (!method.getDefinition().isInstanceInitializer()) {
-          reserveMethodSignature(
-              methodSignatureWithParametersRemoved,
-              methodSignatureWithoutPrototypeChanges,
-              removableParameterIndices);
-        }
+        reserveMethodSignature(
+            methodSignatureWithParametersRemoved,
+            methodSignatureWithoutParametersRemoved,
+            removableParameterIndices);
         return methodReferenceWithParametersRemoved;
       }
 
@@ -363,7 +354,7 @@
           occupiedMethodSignatures.get(methodSignatureWithParametersRemoved);
       // In this case we should have found a reserved method signature above.
       assert !(occupant.getFirst().equals(removableParameterIndices)
-          && occupant.getSecond().equals(methodSignatureWithoutPrototypeChanges));
+          && occupant.getSecond().equals(methodSignatureWithoutParametersRemoved));
 
       // We need to find a new name for this method, since the signature is already occupied.
       // TODO(b/190154391): Instead of generating a new name, we could also try permuting the order
@@ -380,55 +371,45 @@
                   return true;
                 }
                 return candidateOccupant.getFirst().equals(removableParameterIndices)
-                    && candidateOccupant.getSecond().equals(methodSignatureWithoutPrototypeChanges);
+                    && candidateOccupant
+                        .getSecond()
+                        .equals(methodSignatureWithoutParametersRemoved);
               });
 
       // Reserve the newly generated method signature.
-      if (!method.getDefinition().isInstanceInitializer()) {
-        reserveMethodSignature(
-            newMethod.getSignature(),
-            methodSignatureWithoutPrototypeChanges,
-            removableParameterIndices);
-      }
+      reserveMethodSignature(
+          newMethod.getSignature(),
+          methodSignatureWithoutParametersRemoved,
+          removableParameterIndices);
 
       return newMethod;
     }
 
-    private RewrittenPrototypeDescription computeRemovableParametersFromDirectMethod(
-        ProgramMethod method, DexMethodSignatureSet instanceInitializerSignatures) {
+    private ArgumentInfoCollection computeRemovableParametersFromDirectMethod(
+        ProgramMethod method) {
       assert method.getDefinition().belongsToDirectPool();
-      if (!isParameterRemovalAllowed(method)) {
-        return RewrittenPrototypeDescription.none();
+      // TODO(b/190154391): Allow parameter removal from initializers. We need to guarantee absence
+      //  of collisions since initializers can't be renamed.
+      if (!isParameterRemovalAllowed(method) || method.getDefinition().isInstanceInitializer()) {
+        return ArgumentInfoCollection.empty();
       }
       // TODO(b/199864962): Allow parameter removal from check-not-null classified methods.
       if (method
           .getOptimizationInfo()
           .getEnumUnboxerMethodClassification()
           .isCheckNotNullClassification()) {
-        return RewrittenPrototypeDescription.none();
+        return ArgumentInfoCollection.empty();
       }
-      RewrittenPrototypeDescription prototypeChanges = computePrototypeChangesForMethod(method);
-      if (prototypeChanges.isEmpty()) {
-        return prototypeChanges;
-      }
-      if (method.getDefinition().isInstanceInitializer()) {
-        DexMethod rewrittenMethod =
-            prototypeChanges.getArgumentInfoCollection().rewriteMethod(method, dexItemFactory);
-        assert rewrittenMethod != method.getReference();
-        if (!instanceInitializerSignatures.add(rewrittenMethod)) {
-          return RewrittenPrototypeDescription.none();
-        }
-      }
-      return prototypeChanges;
+      return computeRemovableParametersFromMethod(method);
     }
 
-    private RewrittenPrototypeDescription computeRemovableParametersFromVirtualMethod(
+    private ArgumentInfoCollection computeRemovableParametersFromVirtualMethod(
         ProgramMethod method) {
       IntSet removableParameterIndices =
           removableVirtualMethodParameters.getOrDefault(
               method.getMethodSignature(), IntSets.EMPTY_SET);
       if (removableParameterIndices.isEmpty()) {
-        return RewrittenPrototypeDescription.none();
+        return ArgumentInfoCollection.empty();
       }
 
       if (method.getAccessFlags().isAbstract()) {
@@ -442,27 +423,25 @@
                   .setType(method.getArgumentType(removableParameterIndex))
                   .build());
         }
-        return RewrittenPrototypeDescription.create(
-            Collections.emptyList(), null, removableParametersBuilder.build());
+        return removableParametersBuilder.build();
       }
 
-      RewrittenPrototypeDescription prototypeChanges =
-          computePrototypeChangesForMethod(method, removableParameterIndices::contains);
-      assert prototypeChanges.getArgumentInfoCollection().size()
-          == removableParameterIndices.size();
-      return prototypeChanges;
+      ArgumentInfoCollection removableParameters =
+          computeRemovableParametersFromMethod(method, removableParameterIndices::contains);
+      assert removableParameters.size() == removableParameterIndices.size();
+      return removableParameters;
     }
 
-    private RewrittenPrototypeDescription computePrototypeChangesForMethod(ProgramMethod method) {
-      return computePrototypeChangesForMethod(method, parameterIndex -> true);
+    private ArgumentInfoCollection computeRemovableParametersFromMethod(ProgramMethod method) {
+      return computeRemovableParametersFromMethod(method, parameterIndex -> true);
     }
 
-    private RewrittenPrototypeDescription computePrototypeChangesForMethod(
+    private ArgumentInfoCollection computeRemovableParametersFromMethod(
         ProgramMethod method, IntPredicate removableParameterIndices) {
       ConcreteCallSiteOptimizationInfo optimizationInfo =
           method.getDefinition().getCallSiteOptimizationInfo().asConcreteCallSiteOptimizationInfo();
       if (optimizationInfo == null) {
-        return RewrittenPrototypeDescription.none();
+        return ArgumentInfoCollection.empty();
       }
 
       ArgumentInfoCollection.Builder removableParametersBuilder = ArgumentInfoCollection.builder();
@@ -483,8 +462,7 @@
                   .build());
         }
       }
-      return RewrittenPrototypeDescription.create(
-          Collections.emptyList(), null, removableParametersBuilder.build());
+      return removableParametersBuilder.build();
     }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/ArgumentPropagatorReprocessingCriteriaCollection.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/ArgumentPropagatorReprocessingCriteriaCollection.java
index 90e9ead..68191f9 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/ArgumentPropagatorReprocessingCriteriaCollection.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/ArgumentPropagatorReprocessingCriteriaCollection.java
@@ -27,7 +27,6 @@
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap;
-import java.util.IdentityHashMap;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
@@ -36,9 +35,6 @@
   private final AppView<AppInfoWithLiveness> appView;
 
   private final Map<DexMethod, MethodReprocessingCriteria> reproccessingCriteria =
-      new IdentityHashMap<>();
-
-  private final Map<DexMethod, MethodReprocessingCriteria> delayedReproccessingCriteria =
       new ConcurrentHashMap<>();
 
   public ArgumentPropagatorReprocessingCriteriaCollection(AppView<AppInfoWithLiveness> appView) {
@@ -47,12 +43,7 @@
 
   public MethodReprocessingCriteria getReprocessingCriteria(ProgramMethod method) {
     return reproccessingCriteria.getOrDefault(
-        method.getReference(), MethodReprocessingCriteria.alwaysReprocess());
-  }
-
-  public void publishDelayedReprocessingCriteria() {
-    reproccessingCriteria.putAll(delayedReproccessingCriteria);
-    delayedReproccessingCriteria.clear();
+        method.getReference(), MethodReprocessingCriteria.empty());
   }
 
   /**
@@ -78,7 +69,7 @@
     // optimization info, then record this information. If the map is empty, then the method should
     // always be reprocessed if we find non-trivial optimization info for some of the parameters.
     if (!methodReprocessingCriteria.isEmpty()) {
-      delayedReproccessingCriteria.put(
+      reproccessingCriteria.put(
           method.getReference(), new MethodReprocessingCriteria(methodReprocessingCriteria));
     }
   }
@@ -151,9 +142,4 @@
 
     return builder.build();
   }
-
-  public boolean verifyNoDelayedReprocessingCriteria() {
-    assert delayedReproccessingCriteria.isEmpty();
-    return true;
-  }
 }
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 658383f..527ee9e 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,19 +8,14 @@
 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;
 
 public class MethodReprocessingCriteria {
 
-  public static final MethodReprocessingCriteria ALWAYS_REPROCESS =
-      new MethodReprocessingCriteria();
+  public static final MethodReprocessingCriteria EMPTY = new MethodReprocessingCriteria();
 
   private final Int2ReferenceMap<ParameterReprocessingCriteria> reproccesingCriteria;
 
@@ -34,8 +29,8 @@
     this.reproccesingCriteria = reproccesingCriteria;
   }
 
-  public static MethodReprocessingCriteria alwaysReprocess() {
-    return ALWAYS_REPROCESS;
+  public static MethodReprocessingCriteria empty() {
+    return EMPTY;
   }
 
   public ParameterReprocessingCriteria getParameterReprocessingCriteria(int parameterIndex) {
@@ -43,7 +38,7 @@
         parameterIndex, ParameterReprocessingCriteria.alwaysReprocess());
   }
 
-  public ConcreteMonomorphicMethodStateOrUnknown widenMethodState(
+  public boolean shouldReprocess(
       AppView<AppInfoWithLiveness> appView,
       ProgramMethod method,
       ConcreteMonomorphicMethodState methodState) {
@@ -54,24 +49,14 @@
         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)) {
-        continue;
+        return true;
       }
-
-      methodState.setParameterState(parameterIndex, UnknownParameterState.get());
     }
-
-    return Iterables.all(methodState.getParameterStates(), ParameterState::isUnknown)
-        ? MethodState.unknown()
-        : methodState;
+    return false;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/ParameterReprocessingCriteria.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/ParameterReprocessingCriteria.java
index d7c8890..9022f81 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/ParameterReprocessingCriteria.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/ParameterReprocessingCriteria.java
@@ -6,8 +6,6 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
-import com.android.tools.r8.ir.analysis.type.DynamicType;
 import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteParameterState;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
@@ -44,14 +42,6 @@
 
   public abstract boolean shouldReprocessDueToNullability();
 
-  public final DynamicType widenDynamicClassType(
-      AppView<AppInfoWithLiveness> appView, DynamicType dynamicType, ClassTypeElement staticType) {
-    if (dynamicType.getNullability().isMaybeNull()) {
-      return DynamicType.unknown();
-    }
-    return DynamicType.create(appView, staticType.getOrCreateVariant(dynamicType.getNullability()));
-  }
-
   public static class Builder {
 
     private boolean reprocessDueToAbstractValue;
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 7b5eee3..4887a27 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -591,10 +591,6 @@
     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 308862a..3718fcf 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -214,6 +214,7 @@
   }
 
   public void disableGlobalOptimizations() {
+    enableArgumentRemoval = false;
     enableInlining = false;
     enableClassInlining = false;
     enableClassStaticizer = false;
@@ -254,6 +255,7 @@
   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 =
@@ -1256,15 +1258,6 @@
       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/main/java/com/android/tools/r8/utils/collections/DexMethodSignatureSet.java b/src/main/java/com/android/tools/r8/utils/collections/DexMethodSignatureSet.java
index 8ef1277..b6f7c52 100644
--- a/src/main/java/com/android/tools/r8/utils/collections/DexMethodSignatureSet.java
+++ b/src/main/java/com/android/tools/r8/utils/collections/DexMethodSignatureSet.java
@@ -94,10 +94,6 @@
     return backing.contains(signature);
   }
 
-  public boolean contains(DexMethod method) {
-    return contains(method.getSignature());
-  }
-
   public boolean contains(DexEncodedMethod method) {
     return contains(method.getSignature());
   }
diff --git a/src/test/examples/classmerging/CallGraphCycleTest.java b/src/test/examples/classmerging/CallGraphCycleTest.java
index ea958d2..40347d6 100644
--- a/src/test/examples/classmerging/CallGraphCycleTest.java
+++ b/src/test/examples/classmerging/CallGraphCycleTest.java
@@ -7,14 +7,14 @@
 public class CallGraphCycleTest {
 
   public static void main(String[] args) {
-    new B(args.length == 0, args.length == 1);
+    new B(true);
   }
 
   public static class A {
 
-    public A(boolean instantiateB, boolean alwaysFalse) {
+    public A(boolean instantiateB) {
       if (instantiateB) {
-        new B(alwaysFalse, alwaysFalse);
+        new B(false);
       }
       System.out.println("A(" + instantiateB + ")");
     }
@@ -22,8 +22,8 @@
 
   public static class B extends A {
 
-    public B(boolean instantiateBinA, boolean alwaysFalse) {
-      super(instantiateBinA, alwaysFalse);
+    public B(boolean instantiateBinA) {
+      super(instantiateBinA);
       System.out.println("B(" + instantiateBinA + ")");
     }
   }
diff --git a/src/test/examples/shaking1/Shaking.java b/src/test/examples/shaking1/Shaking.java
index 924ae93..8c39ab8 100644
--- a/src/test/examples/shaking1/Shaking.java
+++ b/src/test/examples/shaking1/Shaking.java
@@ -5,7 +5,6 @@
 
 public class Shaking {
   public static void main(String[] args) {
-    String world = args.length == 0 ? "world" : null;
-    System.out.println(new Used(world).method());
+    System.out.println(new Used("world").method());
   }
 }
diff --git a/src/test/examples/shaking1/print-mapping-cf.ref b/src/test/examples/shaking1/print-mapping-cf.ref
index 8b38084..a7e0b8e 100644
--- a/src/test/examples/shaking1/print-mapping-cf.ref
+++ b/src/test/examples/shaking1/print-mapping-cf.ref
@@ -1,7 +1,6 @@
 shaking1.Shaking -> shaking1.Shaking:
 shaking1.Used -> a.a:
-    1:2:void <init>(java.lang.String):12:13 -> <init>
-    1:1:java.lang.String aMethodThatIsNotUsedButKept():21:21 -> aMethodThatIsNotUsedButKept
-    1:2:void main(java.lang.String[]):8:9 -> main
     1:1:java.lang.String method():17:17 -> a
-    java.lang.String name -> a
\ No newline at end of file
+    1:1:void main(java.lang.String[]):8:8 -> main
+    1:1:void <init>(java.lang.String):12:12 -> <init>
+    1:1:java.lang.String aMethodThatIsNotUsedButKept():21:21 -> aMethodThatIsNotUsedButKept
\ No newline at end of file
diff --git a/src/test/examples/shaking1/print-mapping-dex.ref b/src/test/examples/shaking1/print-mapping-dex.ref
index 5a9504a..7ba8ee8 100644
--- a/src/test/examples/shaking1/print-mapping-dex.ref
+++ b/src/test/examples/shaking1/print-mapping-dex.ref
@@ -1,8 +1,5 @@
 shaking1.Shaking -> shaking1.Shaking:
 shaking1.Used -> a.a:
-    0:2:void <init>(java.lang.String):12:12 -> <init>
-    3:5:void <init>(java.lang.String):13:13 -> <init>
-    0:6:void main(java.lang.String[]):8:8 -> main
-    7:21:void main(java.lang.String[]):9:9 -> main
-    0:19:java.lang.String method():17:17 -> a
-    java.lang.String name -> a
+    java.lang.String method() -> a
+    0:16:void main(java.lang.String[]):8:8 -> main
+    0:3:void <init>(java.lang.String):12:12 -> <init>
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 29e44c0..19c8015 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("bar$1", STRING, ImmutableList.of())
+            ? new MethodSignature("bara", 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/classmerging/horizontal/ConstructorMergingPreoptimizedTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingPreoptimizedTest.java
index 06bfb5b..e0c6c9e 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingPreoptimizedTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingPreoptimizedTest.java
@@ -38,7 +38,8 @@
         .enableNoHorizontalClassMergingAnnotations()
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), Main.class)
-        .assertSuccessWithOutputLines("changed", "0", "42", "foo", "7", "foo", "print a", "print b")
+        .assertSuccessWithOutputLines(
+            "changed", "13", "42", "foo", "7", "foo", "print a", "print b")
         .inspect(
             codeInspector -> {
               ClassSubject changedClassSubject = codeInspector.clazz(Changed.class);
@@ -117,7 +118,7 @@
   public static class Main {
     public static void main(String[] args) {
       Parent p = new Changed();
-      A a = new A(args.length);
+      A a = new A(13);
       a = new A(p);
       B b = new B(p);
       a.print();
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/EquivalentConstructorsWithClassIdAndExtraNullsMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/EquivalentConstructorsWithClassIdAndExtraNullsMergingTest.java
index 6094157..3917d56 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/EquivalentConstructorsWithClassIdAndExtraNullsMergingTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/EquivalentConstructorsWithClassIdAndExtraNullsMergingTest.java
@@ -75,14 +75,14 @@
                   isPresent());
             })
         .run(parameters.getRuntime(), Main.class)
-        .assertSuccessWithOutputLines("C", "0", "C", "D");
+        .assertSuccessWithOutputLines("C", "42", "C", "D");
   }
 
   static class Main {
 
     public static void main(String[] args) {
       System.out.println(new A(new C()));
-      System.out.println(new A(new C(), args.length));
+      System.out.println(new A(new C(), 42));
       System.out.println(new B(new D()));
     }
   }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMemberAccessTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMemberAccessTest.java
index 9b45774..dd9ab2a 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMemberAccessTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMemberAccessTest.java
@@ -30,7 +30,7 @@
         .enableNeverClassInliningAnnotations()
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), Main.class)
-        .assertSuccessWithOutputLines("foo", "B", "bar", "0", "foobar")
+        .assertSuccessWithOutputLines("foo", "B", "bar", "5", "foobar")
         .inspect(
             codeInspector -> {
               assertThat(codeInspector.clazz(A.class), isAbsent());
@@ -56,7 +56,7 @@
       a.foo();
       B b = a.get("B");
       b.bar();
-      C c = new C(args.length);
+      C c = new C(5);
       c.foobar();
     }
   }
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 48877b9..fe4a189 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,7 +8,6 @@
 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;
@@ -73,7 +72,6 @@
         .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);
@@ -148,7 +146,6 @@
       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 3c32c7b..e34a36c 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,7 +7,6 @@
 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;
@@ -49,7 +48,6 @@
         .addKeepAttributeInnerClassesAndEnclosingMethod()
         .addKeepAttributeSignature()
         .addKeepClassRules(Foo.Bar.class)
-        .enableInliningAnnotations()
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines(EXPECTED)
@@ -73,7 +71,6 @@
       }
     }
 
-    @NeverInline
     public Bar<String> foo() {
       return new Bar<>();
     }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineLibraryInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineLibraryInterfaceMethodTest.java
index 3c76052..48d3203 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineLibraryInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineLibraryInterfaceMethodTest.java
@@ -58,9 +58,11 @@
               counts.println = countInvokesWithName(methodSubject, "println");
             });
 
-    // TODO(b/126323172) Add test here to check the same with desugared lambdas.
-    assertEquals(0, counts.run);
-    assertEquals(2, counts.println);
+    // TODO(b/129044633) We expect 0 x run and 2 x println after we can inline those methods.
+    assertEquals(2, counts.run);
+    assertEquals(0, counts.println);
+    // TODO(b/126323172) After this issue has been fixed, add test here to check the same with
+    // desugared lambdas.
   }
 
   private static long countInvokesWithName(MethodSubject methodSubject, String name) {
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 59e5118..f9081c2 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,7 +10,6 @@
 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;
@@ -225,7 +224,6 @@
         .addOptionsModification(
             options -> options.enableInliningOfInvokesWithClassInitializationSideEffects = false)
         .enableConstantArgumentAnnotations()
-        .enableUnusedArgumentAnnotations()
         .enableInliningAnnotations()
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), mainClass)
@@ -324,7 +322,6 @@
     }
 
     @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 c3f71e3..a1b6f08 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,19 +164,16 @@
     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 TrivialTestClass.next()",
-            "SimpleWithParams SimpleWithParams.INSTANCE",
-            "VIRTUAL: String SimpleWithParams.bar(String)",
-            "VIRTUAL: String SimpleWithParams.foo()"),
+            "STATIC: String SimpleWithParams.bar(String)",
+            "STATIC: String SimpleWithParams.foo()",
+            "STATIC: String TrivialTestClass.next()"),
         references(clazz, "testSimpleWithParams", "void"));
 
     ClassSubject simpleWithParams = inspector.clazz(SimpleWithParams.class);
-    assertFalse(instanceMethods(simpleWithParams).isEmpty());
-    assertThat(simpleWithParams.clinit(), isPresent());
+    assertTrue(instanceMethods(simpleWithParams).isEmpty());
+    assertThat(simpleWithParams.clinit(), not(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 06aae25..e7e09dd 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.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -33,19 +33,17 @@
 @RunWith(Parameterized.class)
 public class InvokeMethodWithReceiverOptimizationTest extends TestBase {
 
-  private final TestParameters parameters;
-  private final boolean enableArgumentPropagation;
+  private final Backend backend;
+  private final boolean enableArgumentRemoval;
 
-  @Parameters(name = "{0}, argument propagation: {1}")
+  @Parameters(name = "Backend: {0}, enable argument removal: {1}")
   public static List<Object[]> data() {
-    return buildParameters(
-        getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values());
+    return buildParameters(ToolHelper.getBackends(), BooleanUtils.values());
   }
 
-  public InvokeMethodWithReceiverOptimizationTest(
-      TestParameters parameters, boolean enableArgumentPropagation) {
-    this.parameters = parameters;
-    this.enableArgumentPropagation = enableArgumentPropagation;
+  public InvokeMethodWithReceiverOptimizationTest(Backend backend, boolean enableArgumentRemoval) {
+    this.backend = backend;
+    this.enableArgumentRemoval = enableArgumentRemoval;
   }
 
   @Test
@@ -59,20 +57,15 @@
     testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expected);
 
     CodeInspector inspector =
-        testForR8(parameters.getBackend())
+        testForR8(backend)
             .addInnerClasses(InvokeMethodWithReceiverOptimizationTest.class)
             .addKeepMainRule(TestClass.class)
             .enableInliningAnnotations()
-            .addOptionsModification(
-                options -> {
-                  options.enableUninstantiatedTypeOptimization = enableArgumentPropagation;
-                  options.callSiteOptimizationOptions().setEnabled(enableArgumentPropagation);
-                })
+            .addOptionsModification(o -> o.enableArgumentRemoval = enableArgumentRemoval)
             // TODO(b/120764902): The calls to getOriginalName() below does not work in presence of
-            //  argument removal.
-            .noMinification()
-            .setMinApi(parameters.getApiLevel())
-            .run(parameters.getRuntime(), TestClass.class)
+            // argument removal.
+            .addKeepRules("-dontobfuscate")
+            .run(TestClass.class)
             .assertSuccessWithOutput(expected)
             .inspector();
 
@@ -80,7 +73,7 @@
     assertThat(testClassSubject, isPresent());
 
     ClassSubject otherClassSubject = inspector.clazz(A.class);
-    assertNotEquals(enableArgumentPropagation, otherClassSubject.isPresent());
+    assertNotEquals(enableArgumentRemoval, 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 58dc4e5..8dc29fb 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().withAllRuntimesAndApiLevels().build(),
+        getTestParameters().withAllRuntimes().build(),
         BooleanUtils.values(),
         BooleanUtils.values());
   }
@@ -66,7 +66,7 @@
         .enableNoHorizontalClassMergingAnnotations()
         .minification(minification)
         .allowAccessModification(allowAccessModification)
-        .setMinApi(parameters.getApiLevel())
+        .setMinApi(parameters.getRuntime())
         .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 0e4a3a2..663bcf6 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,7 +100,10 @@
     for (MethodSubject methodSubject : methodSubjects) {
       assertThat(methodSubject, isPresent());
 
-      if (keepUninstantiatedArguments) {
+      // TODO(b/131735725): Should also remove arguments from the virtual methods.
+      boolean shouldHaveArgumentRemoval =
+          keepUninstantiatedArguments || methodSubject.getOriginalName().contains("Virtual");
+      if (shouldHaveArgumentRemoval) {
         assertEquals(3, methodSubject.getMethod().getParameters().size());
 
         // In non-compat mode, R8 removes annotations from non-pinned items.
@@ -119,7 +122,7 @@
         assertEquals(1, annotationSet.size());
 
         DexAnnotation annotation = annotationSet.getFirst();
-        if (keepUninstantiatedArguments && i == getPositionOfUnusedArgument(methodSubject)) {
+        if (shouldHaveArgumentRemoval && 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 612a0b5..14efc77 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("toString$1", methodSubject.getFinalName());
+      assertEquals("toString1", 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 7ca05fb..138f0a9 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,7 +6,6 @@
 
 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;
@@ -40,7 +39,6 @@
         .addKeepMainRule(Main.class)
         .noMinification()
         .enableInliningAnnotations()
-        .enableNeverClassInliningAnnotations()
         .setMinApi(parameters.getApiLevel())
         .compile()
         .inspect(this::assertMethodsAreThere)
@@ -170,6 +168,5 @@
 
   private static class UnInstantiated {}
 
-  @NeverClassInline
   private static class Unused {}
 }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAnnotatedArgumentsWithMissingAnnotationsTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAnnotatedArgumentsWithMissingAnnotationsTest.java
index c074ee1..c008972 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAnnotatedArgumentsWithMissingAnnotationsTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAnnotatedArgumentsWithMissingAnnotationsTest.java
@@ -82,9 +82,7 @@
         .addKeepRules(
             "-keep @interface Annotation?",
             "-neverclassinline class *",
-            "-nohorizontalclassmerging class Test$Inner?",
-            "-keepclassmembers class Test$Inner? { synthetic <fields>; }",
-            "-keepconstantarguments class Test$Inner? { void <init>(...); }")
+            "-nohorizontalclassmerging class Test$Inner?")
         .addKeepRuntimeVisibleParameterAnnotations()
         .enableProguardTestOptions()
         .setMinApi(parameters.getApiLevel())
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 58b052c..281db3e 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,8 +32,7 @@
 
   @Parameters(name = "{1}, minification: {0}")
   public static List<Object[]> params() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+    return buildParameters(BooleanUtils.values(), getTestParameters().withAllRuntimes().build());
   }
 
   public UnusedArgumentRemovalWithOverridingTest(boolean minification, TestParameters parameters) {
@@ -51,7 +50,7 @@
         .enableInliningAnnotations()
         .enableNoVerticalClassMergingAnnotations()
         .minification(minification)
-        .setMinApi(parameters.getApiLevel())
+        .setMinApi(parameters.getRuntime())
         .compile()
         .inspect(this::verify)
         .run(parameters.getRuntime(), TestClass.class)
@@ -71,9 +70,8 @@
   static class TestClass {
 
     public static void main(String[] args) {
-      String greeting = System.currentTimeMillis() > 0 ? "Hello world!" : null;
-      System.out.println(new A().greeting(greeting));
-      System.out.println(new B().greeting(greeting));
+      System.out.println(new A().greeting("Hello world!"));
+      System.out.println(new B().greeting("Hello world!"));
     }
   }
 
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 8ccee13..7d9a941 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,20 +29,25 @@
 public class UnusedArgumentsCollisionMappingTest extends TestBase {
 
   private final TestParameters parameters;
+  private final CompilationMode compilationMode;
 
-  @Parameters(name = "{0}")
-  public static TestParametersCollection data() {
-    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  @Parameters(name = "{0}, compilation mode: {1}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withAllRuntimesAndApiLevels().build(), CompilationMode.values());
   }
 
-  public UnusedArgumentsCollisionMappingTest(TestParameters parameters) {
+  public UnusedArgumentsCollisionMappingTest(
+      TestParameters parameters, CompilationMode compilationMode) {
     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 c59eb85..1137a01 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,8 +34,7 @@
 
   @Parameters(name = "{1}, minification: {0}")
   public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+    return buildParameters(BooleanUtils.values(), getTestParameters().withAllRuntimes().build());
   }
 
   public UnusedArgumentsCollisionTest(boolean minification, TestParameters parameters) {
@@ -61,7 +60,7 @@
         .enableNeverClassInliningAnnotations()
         .enableNoVerticalClassMergingAnnotations()
         .minification(minification)
-        .setMinApi(parameters.getApiLevel())
+        .setMinApi(parameters.getRuntime())
         .compile()
         .inspect(this::verifyUnusedArgumentsRemovedAndNoCollisions)
         .run(parameters.getRuntime(), TestClass.class)
@@ -86,10 +85,11 @@
     MethodSubject methodB1Subject =
         bClassSubject.allMethods().stream().filter(FoundMethodSubject::isStatic).findFirst().get();
     assertThat(methodB1Subject, isPresent());
-    assertEquals(0, methodB1Subject.getMethod().getParameters().size());
+    assertEquals(0, methodB1Subject.getMethod().getReference().proto.parameters.size());
 
-    // Verify that the static method B.method1() does not collide with a method in A.
-    assertNotEquals(methodB1Subject.getFinalName(), methodA1Subject.getFinalName());
+    // 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());
     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().getParameters().size());
+    assertEquals(0, methodB2Subject.getMethod().getReference().proto.parameters.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 a4622bc..c890e97 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,14 +11,11 @@
 
 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.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
 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;
@@ -28,39 +25,32 @@
 @RunWith(Parameterized.class)
 public class UnusedArgumentsInstanceConstructorTest extends TestBase {
 
-  private final TestParameters parameters;
+  private final Backend backend;
 
-  @Parameters(name = "{0}")
-  public static TestParametersCollection data() {
-    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  @Parameters(name = "Backend: {0}")
+  public static Backend[] data() {
+    return ToolHelper.getBackends();
   }
 
-  public UnusedArgumentsInstanceConstructorTest(TestParameters parameters) {
-    this.parameters = parameters;
+  public UnusedArgumentsInstanceConstructorTest(Backend backend) {
+    this.backend = backend;
   }
 
   @Test
   public void test() throws Exception {
     String expectedOutput = StringUtils.lines("Hello world");
 
-    if (parameters.isCfRuntime()) {
-      testForJvm()
-          .addTestClasspath()
-          .run(parameters.getRuntime(), TestClass.class)
-          .assertSuccessWithOutput(expectedOutput);
+    if (backend == Backend.CF) {
+      testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expectedOutput);
     }
 
     CodeInspector inspector =
-        testForR8(parameters.getBackend())
+        testForR8(backend)
             .addInnerClasses(UnusedArgumentsInstanceConstructorTest.class)
             .addKeepMainRule(TestClass.class)
-            .addHorizontallyMergedClassesInspector(
-                HorizontallyMergedClassesInspector::assertNoClassesMerged)
             .enableInliningAnnotations()
             .enableNeverClassInliningAnnotations()
-            .enableNoHorizontalClassMergingAnnotations()
-            .setMinApi(parameters.getApiLevel())
-            .run(parameters.getRuntime(), TestClass.class)
+            .run(TestClass.class)
             .assertSuccessWithOutput(expectedOutput)
             .inspector();
 
@@ -83,7 +73,6 @@
   }
 
   @NeverClassInline
-  @NoHorizontalClassMerging
   static class A {
 
     public A(B uninstantiated, C unused) {
@@ -101,9 +90,7 @@
     }
   }
 
-  @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 3a4eeda..794d588 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,7 +29,6 @@
     return UnusedArgumentsTestBase.data();
   }
 
-  @NeverClassInline
   static class TestObject {
 
     public final String s;
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java
index 2cb21d4..aebbbb2 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java
@@ -6,8 +6,10 @@
 
 import static org.junit.Assume.assumeTrue;
 
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion;
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.kotlin.TestKotlinClass.Visibility;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
@@ -76,7 +78,9 @@
                     .addOptionsModification(disableClassInliner))
         .inspect(
             inspector -> {
-              if (allowAccessModification) {
+              if (allowAccessModification
+                  && kotlinParameters.is(
+                      KotlinCompilerVersion.KOTLINC_1_5_0, KotlinTargetVersion.JAVA_8)) {
                 checkClassIsRemoved(inspector, TEST_DATA_CLASS.getClassName());
               } else {
                 ClassSubject dataClass =
@@ -125,7 +129,9 @@
                     .addOptionsModification(disableClassInliner))
         .inspect(
             inspector -> {
-              if (allowAccessModification) {
+              if (allowAccessModification
+                  && kotlinParameters.is(
+                      KotlinCompilerVersion.KOTLINC_1_5_0, KotlinTargetVersion.JAVA_8)) {
                 checkClassIsRemoved(inspector, TEST_DATA_CLASS.getClassName());
               } else {
                 ClassSubject dataClass =
@@ -175,26 +181,21 @@
                     .addOptionsModification(disableClassInliner))
         .inspect(
             inspector -> {
-              if (allowAccessModification) {
-                checkClassIsRemoved(inspector, TEST_DATA_CLASS.getClassName());
-              } else {
-                ClassSubject dataClass =
-                    checkClassIsKept(inspector, TEST_DATA_CLASS.getClassName());
+              ClassSubject dataClass = checkClassIsKept(inspector, TEST_DATA_CLASS.getClassName());
 
-                boolean component2IsPresent = !allowAccessModification;
-                checkMethodIsKeptOrRemoved(dataClass, COMPONENT2_METHOD, component2IsPresent);
+              boolean component2IsPresent = !allowAccessModification;
+              checkMethodIsKeptOrRemoved(dataClass, COMPONENT2_METHOD, component2IsPresent);
 
-                // Function component1 is not used.
-                checkMethodIsRemoved(dataClass, COMPONENT1_METHOD);
+              // Function component1 is not used.
+              checkMethodIsRemoved(dataClass, COMPONENT1_METHOD);
 
-                // No use of getter.
-                checkMethodIsRemoved(dataClass, NAME_GETTER_METHOD);
-                checkMethodIsRemoved(dataClass, AGE_GETTER_METHOD);
+              // No use of getter.
+              checkMethodIsRemoved(dataClass, NAME_GETTER_METHOD);
+              checkMethodIsRemoved(dataClass, AGE_GETTER_METHOD);
 
-                // No use of copy functions.
-                checkMethodIsRemoved(dataClass, COPY_METHOD);
-                checkMethodIsRemoved(dataClass, COPY_DEFAULT_METHOD);
-              }
+              // No use of copy functions.
+              checkMethodIsRemoved(dataClass, COPY_METHOD);
+              checkMethodIsRemoved(dataClass, COPY_DEFAULT_METHOD);
 
               ClassSubject classSubject = checkClassIsKept(inspector, mainClassName);
               MethodSubject testMethod = checkMethodIsKept(classSubject, testMethodSignature);
@@ -221,7 +222,9 @@
                     .addOptionsModification(disableClassInliner))
         .inspect(
             inspector -> {
-              if (allowAccessModification) {
+              if (testParameters.isDexRuntime()
+                  && allowAccessModification
+                  && kotlinParameters.is(KotlinCompilerVersion.KOTLINC_1_3_72)) {
                 checkClassIsRemoved(inspector, TEST_DATA_CLASS.getClassName());
               } else {
                 ClassSubject dataClass =
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 d251e28..d0cb2bf 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().withAllRuntimesAndApiLevels().build();
+    return getTestParameters().withAllRuntimes().build();
   }
 
   public Regress69825683Test(TestParameters parameters) {
@@ -48,13 +48,10 @@
             .addKeepRules(
                 "-assumemayhavesideeffects class " + inner.getName() + " {",
                 "  synthetic void <init>(...);",
-                "}",
-                "-keepunusedarguments class " + inner.getName() + " {",
-                "  synthetic void <init>(...);",
                 "}")
             .addOptionsModification(options -> options.enableClassInlining = false)
             .noMinification()
-            .setMinApi(parameters.getApiLevel())
+            .setMinApi(parameters.getRuntime())
             .run(parameters.getRuntime(), outer)
             // Run code to check that the constructor with synthetic class as argument is present.
             .assertSuccessWithOutputThatMatches(startsWith(innerName))
@@ -85,7 +82,7 @@
                 "}")
             .noMinification()
             .addOptionsModification(o -> o.enableClassInlining = false)
-            .setMinApi(parameters.getApiLevel())
+            .setMinApi(parameters.getRuntime())
             // 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 b99494e..7f6323a 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 enableArgumentPropagation;
+  private final boolean enableArgumentRemoval;
   private final TestParameters parameters;
 
-  @Parameters(name = "{1}, argument propagation: {0}")
+  @Parameters(name = "{1}, argument removal: {0}")
   public static List<Object[]> data() {
     return buildParameters(
         BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
   }
 
-  public ParameterTypeTest(boolean enableArgumentPropagation, TestParameters parameters) {
-    this.enableArgumentPropagation = enableArgumentPropagation;
+  public ParameterTypeTest(boolean enableArgumentRemoval, TestParameters parameters) {
+    this.enableArgumentRemoval = enableArgumentRemoval;
     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.callSiteOptimizationOptions().setEnabled(enableArgumentPropagation);
+              options.enableArgumentRemoval = enableArgumentRemoval;
             });
 
     // Run processed (output) program on ART
@@ -239,7 +239,7 @@
 
     CodeInspector inspector = new CodeInspector(processedApp);
     ClassSubject subSubject = inspector.clazz(sub.name);
-    assertNotEquals(enableArgumentPropagation, subSubject.isPresent());
+    assertNotEquals(enableArgumentRemoval, 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.callSiteOptimizationOptions().setEnabled(enableArgumentPropagation);
+              options.enableArgumentRemoval = enableArgumentRemoval;
             })
         .noMinification()
         .setMinApi(parameters.getApiLevel())
@@ -315,11 +315,11 @@
         .inspect(
             inspector -> {
               ClassSubject subSubject = inspector.clazz(sub.name);
-              assertNotEquals(enableArgumentPropagation, subSubject.isPresent());
+              assertNotEquals(enableArgumentRemoval, subSubject.isPresent());
             })
         .run(parameters.getRuntime(), mainClassName)
         .applyIf(
-            enableArgumentPropagation || parameters.isCfRuntime(),
+            enableArgumentRemoval || 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.callSiteOptimizationOptions().setEnabled(enableArgumentPropagation);
+              options.enableArgumentRemoval = enableArgumentRemoval;
             });
 
     // Run processed (output) program on ART
@@ -422,6 +422,6 @@
 
     CodeInspector inspector = new CodeInspector(processedApp);
     ClassSubject subSubject = inspector.clazz(sub.name);
-    assertNotEquals(enableArgumentPropagation, subSubject.isPresent());
+    assertNotEquals(enableArgumentRemoval, subSubject.isPresent());
   }
 }