Unify optimization info fixup in argument propagator, enum unboxer, and staticizer

Change-Id: I0db6ab5751ab22b1279a24a50ed44cf70de4f01e
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 5d05028..b4a382f 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -48,6 +48,8 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DexAnnotation.AnnotatedKind;
 import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
 import com.android.tools.r8.ir.analysis.inlining.SimpleInliningConstraint;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.NumericType;
@@ -57,9 +59,9 @@
 import com.android.tools.r8.ir.optimize.Inliner.Reason;
 import com.android.tools.r8.ir.optimize.NestUtils;
 import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
-import com.android.tools.r8.ir.optimize.info.ConcreteCallSiteOptimizationInfo;
 import com.android.tools.r8.ir.optimize.info.DefaultMethodOptimizationInfo;
 import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo;
+import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfoFixer;
 import com.android.tools.r8.ir.optimize.info.MutableMethodOptimizationInfo;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
 import com.android.tools.r8.ir.optimize.inliner.WhyAreYouNotInliningReporter;
@@ -1287,11 +1289,16 @@
   public DexEncodedMethod toStaticMethodWithoutThis(AppView<AppInfoWithLiveness> appView) {
     checkIfObsolete();
     assert !accessFlags.isStatic();
+
+    ArgumentInfoCollection prototypeChanges =
+        ArgumentInfoCollection.builder()
+            .addArgumentInfo(0, RemovedArgumentInfo.builder().setType(getHolderType()).build())
+            .build();
     Builder builder =
         builder(this)
             .promoteToStatic()
             .withoutThisParameter()
-            .adjustOptimizationInfoAfterRemovingThisParameter(appView)
+            .fixupOptimizationInfo(appView, prototypeChanges.createMethodOptimizationInfoFixer())
             .setGenericSignature(MethodTypeSignature.noSignature());
     DexEncodedMethod method = builder.build();
     method.copyMetadata(this);
@@ -1525,15 +1532,22 @@
       return this;
     }
 
-    public Builder fixupCallSiteOptimizationInfo(
-        Function<ConcreteCallSiteOptimizationInfo, ? extends CallSiteOptimizationInfo> fn) {
+    public Builder fixupCallSiteOptimizationInfo(MethodOptimizationInfoFixer fixer) {
       if (callSiteOptimizationInfo.isConcreteCallSiteOptimizationInfo()) {
         callSiteOptimizationInfo =
-            fn.apply(callSiteOptimizationInfo.asConcreteCallSiteOptimizationInfo());
+            fixer.fixupCallSiteOptimizationInfo(
+                callSiteOptimizationInfo.asConcreteCallSiteOptimizationInfo());
       }
       return this;
     }
 
+    public Builder fixupOptimizationInfo(
+        AppView<AppInfoWithLiveness> appView, MethodOptimizationInfoFixer fixer) {
+      return fixupCallSiteOptimizationInfo(fixer)
+          .modifyOptimizationInfo(
+              (newMethod, optimizationInfo) -> optimizationInfo.fixup(appView, fixer));
+    }
+
     public Builder setSimpleInliningConstraint(
         DexProgramClass holder, SimpleInliningConstraint simpleInliningConstraint) {
       return addBuildConsumer(
@@ -1661,15 +1675,6 @@
       return this;
     }
 
-    public Builder adjustOptimizationInfoAfterRemovingThisParameter(
-        AppView<AppInfoWithLiveness> appView) {
-      return fixupCallSiteOptimizationInfo(
-              callSiteOptimizationInfo -> callSiteOptimizationInfo.fixupAfterParameterRemoval(0))
-          .modifyOptimizationInfo(
-              (newMethod, optimizationInfo) ->
-                  optimizationInfo.adjustOptimizationInfoAfterRemovingThisParameter(appView));
-    }
-
     public Builder modifyOptimizationInfo(
         BiConsumer<DexEncodedMethod, MutableMethodOptimizationInfo> consumer) {
       return addBuildConsumer(
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 dffe2a3..448d440 100644
--- a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
+++ b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
@@ -11,10 +11,10 @@
 import com.android.tools.r8.ir.code.Position;
 import com.android.tools.r8.ir.conversion.ExtraParameter;
 import com.android.tools.r8.ir.conversion.ExtraUnusedNullParameter;
-import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
-import com.android.tools.r8.ir.optimize.info.ConcreteCallSiteOptimizationInfo;
+import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfoFixer;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.ConsumerUtils;
+import com.android.tools.r8.utils.IntObjConsumer;
 import com.android.tools.r8.utils.IteratorUtils;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Ordering;
@@ -32,7 +32,6 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.function.Consumer;
-import java.util.function.Function;
 
 public class RewrittenPrototypeDescription {
 
@@ -224,6 +223,12 @@
       return EMPTY;
     }
 
+    public void forEach(IntObjConsumer<ArgumentInfo> consumer) {
+      for (Entry<ArgumentInfo> entry : argumentInfos.int2ReferenceEntrySet()) {
+        consumer.accept(entry.getIntKey(), entry.getValue());
+      }
+    }
+
     public IntSortedSet getKeys() {
       return argumentInfos.keySet();
     }
@@ -247,6 +252,10 @@
       return removedParameterIndices;
     }
 
+    public boolean isArgumentRemoved(int argumentIndex) {
+      return getArgumentInfo(argumentIndex).isRemovedArgumentInfo();
+    }
+
     public boolean isEmpty() {
       return this == EMPTY;
     }
@@ -274,6 +283,10 @@
       return removed;
     }
 
+    public boolean hasArgumentInfo(int argumentIndex) {
+      return argumentInfos.containsKey(argumentIndex);
+    }
+
     public ArgumentInfo getArgumentInfo(int argumentIndex) {
       return argumentInfos.getOrDefault(argumentIndex, ArgumentInfo.NO_INFO);
     }
@@ -290,12 +303,13 @@
 
       private Int2ReferenceSortedMap<ArgumentInfo> argumentInfos;
 
-      public void addArgumentInfo(int argIndex, ArgumentInfo argInfo) {
+      public Builder addArgumentInfo(int argIndex, ArgumentInfo argInfo) {
         if (argumentInfos == null) {
           argumentInfos = new Int2ReferenceRBTreeMap<>();
         }
         assert !argumentInfos.containsKey(argIndex);
         argumentInfos.put(argIndex, argInfo);
+        return this;
       }
 
       public ArgumentInfoCollection build() {
@@ -392,12 +406,16 @@
       return Integer.MAX_VALUE;
     }
 
-    public Function<ConcreteCallSiteOptimizationInfo, ? extends CallSiteOptimizationInfo>
-        createCallSiteOptimizationInfoFixer() {
-      return callSiteOptimizationInfo ->
-          callSiteOptimizationInfo.fixupAfterParameterRemoval(getRemovedParameterIndices());
+    public MethodOptimizationInfoFixer createMethodOptimizationInfoFixer() {
+      RewrittenPrototypeDescription prototypeChanges =
+          RewrittenPrototypeDescription.create(Collections.emptyList(), null, this);
+      return prototypeChanges.createMethodOptimizationInfoFixer();
     }
 
+    /**
+     * Returns a function for rewriting the parameter annotations on a method info after prototype
+     * changes were made.
+     */
     public Consumer<DexEncodedMethod.Builder> createParameterAnnotationsRemover(
         DexEncodedMethod method) {
       if (numberOfRemovedArguments() > 0 && !method.parameterAnnotationsList.isEmpty()) {
@@ -483,6 +501,10 @@
     return NONE;
   }
 
+  public MethodOptimizationInfoFixer createMethodOptimizationInfoFixer() {
+    return new RewrittenPrototypeDescriptionMethodOptimizationInfoFixer(this);
+  }
+
   public RewrittenPrototypeDescription combine(RewrittenPrototypeDescription other) {
     if (isEmpty()) {
       return other;
@@ -514,6 +536,10 @@
         && argumentInfoCollection.isEmpty();
   }
 
+  public boolean hasExtraParameters() {
+    return !extraParameters.isEmpty();
+  }
+
   public List<ExtraParameter> getExtraParameters() {
     return extraParameters;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescriptionMethodOptimizationInfoFixer.java b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescriptionMethodOptimizationInfoFixer.java
new file mode 100644
index 0000000..1ef6ffc
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescriptionMethodOptimizationInfoFixer.java
@@ -0,0 +1,166 @@
+// Copyright (c) 2021, 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.graph;
+
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfo;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.ir.analysis.inlining.SimpleInliningConstraint;
+import com.android.tools.r8.ir.analysis.inlining.SimpleInliningConstraintFactory;
+import com.android.tools.r8.ir.optimize.classinliner.constraint.ClassInlinerMethodConstraint;
+import com.android.tools.r8.ir.optimize.enums.classification.EnumUnboxerMethodClassification;
+import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
+import com.android.tools.r8.ir.optimize.info.ConcreteCallSiteOptimizationInfo;
+import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfoFixer;
+import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
+import com.android.tools.r8.ir.optimize.info.bridge.VirtualBridgeInfo;
+import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfoCollection;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import java.util.BitSet;
+
+public class RewrittenPrototypeDescriptionMethodOptimizationInfoFixer
+    extends MethodOptimizationInfoFixer {
+
+  private final RewrittenPrototypeDescription prototypeChanges;
+
+  public RewrittenPrototypeDescriptionMethodOptimizationInfoFixer(
+      RewrittenPrototypeDescription prototypeChanges) {
+    this.prototypeChanges = prototypeChanges;
+  }
+
+  private ArgumentInfoCollection getArgumentInfoCollection() {
+    return prototypeChanges.getArgumentInfoCollection();
+  }
+
+  /**
+   * Function for rewriting the bridge info on a piece of method optimization info after prototype
+   * changes were made.
+   */
+  @Override
+  public BridgeInfo fixupBridgeInfo(VirtualBridgeInfo bridgeInfo) {
+    if (getArgumentInfoCollection().isEmpty()) {
+      return bridgeInfo;
+    }
+    return null;
+  }
+
+  /**
+   * Function for rewriting the call site optimization info on a method after prototype changes were
+   * made.
+   */
+  @Override
+  public CallSiteOptimizationInfo fixupCallSiteOptimizationInfo(
+      ConcreteCallSiteOptimizationInfo callSiteOptimizationInfo) {
+    if (prototypeChanges.isEmpty()) {
+      return callSiteOptimizationInfo;
+    }
+    return callSiteOptimizationInfo.fixupAfterParametersChanged(prototypeChanges);
+  }
+
+  /**
+   * Function for rewriting the class inliner method constraint on a piece of method optimization
+   * info after prototype changes were made.
+   */
+  @Override
+  public ClassInlinerMethodConstraint fixupClassInlinerMethodConstraint(
+      ClassInlinerMethodConstraint classInlinerMethodConstraint) {
+    if (getArgumentInfoCollection().isEmpty()) {
+      return classInlinerMethodConstraint;
+    }
+    return classInlinerMethodConstraint.fixupAfterParametersChanged(getArgumentInfoCollection());
+  }
+
+  /**
+   * Function for rewriting the enum unboxer method classification on a piece of method optimization
+   * info after prototype changes were made.
+   */
+  @Override
+  public EnumUnboxerMethodClassification fixupEnumUnboxerMethodClassification(
+      EnumUnboxerMethodClassification classification) {
+    if (getArgumentInfoCollection().isEmpty()) {
+      return classification;
+    }
+    return classification.fixupAfterParametersChanged(getArgumentInfoCollection());
+  }
+
+  /**
+   * Function for rewriting the instance initializer information on a piece of method optimization
+   * info after prototype changes were made.
+   */
+  @Override
+  public InstanceInitializerInfoCollection fixupInstanceInitializerInfo(
+      AppView<AppInfoWithLiveness> appView,
+      InstanceInitializerInfoCollection instanceInitializerInfo) {
+    if (getArgumentInfoCollection().isEmpty()) {
+      return instanceInitializerInfo;
+    }
+    return instanceInitializerInfo.fixupAfterParametersChanged(
+        appView, getArgumentInfoCollection());
+  }
+
+  /**
+   * Function for rewriting the non-null-param-on-normal-exits information on a piece of method
+   * optimization info after prototype changes were made.
+   */
+  @Override
+  public BitSet fixupNonNullParamOnNormalExits(BitSet nonNullParamOnNormalExits) {
+    return fixupNonNullParamInfo(nonNullParamOnNormalExits);
+  }
+
+  /**
+   * Function for rewriting the non-null-param-or-throw information on a piece of method
+   * optimization info after prototype changes were made.
+   */
+  @Override
+  public BitSet fixupNonNullParamOrThrow(BitSet nonNullParamOrThrow) {
+    return fixupNonNullParamInfo(nonNullParamOrThrow);
+  }
+
+  private BitSet fixupNonNullParamInfo(BitSet nonNullParamInfo) {
+    if (getArgumentInfoCollection().isEmpty() || nonNullParamInfo == null) {
+      return nonNullParamInfo;
+    }
+    int n = nonNullParamInfo.length();
+    BitSet rewrittenNonNullParamOnNormalExits = new BitSet(n);
+    for (int argumentIndex = 0; argumentIndex < n; argumentIndex++) {
+      if (!nonNullParamInfo.get(argumentIndex)) {
+        continue;
+      }
+      ArgumentInfo argumentInfo = getArgumentInfoCollection().getArgumentInfo(argumentIndex);
+      if (argumentInfo.isRemovedArgumentInfo() || argumentInfo.isRewrittenTypeInfo()) {
+        continue;
+      }
+      rewrittenNonNullParamOnNormalExits.set(
+          getArgumentInfoCollection().getNewArgumentIndex(argumentIndex));
+    }
+    return rewrittenNonNullParamOnNormalExits.isEmpty() ? null : rewrittenNonNullParamOnNormalExits;
+  }
+
+  /**
+   * Function for rewriting the returned argument information on a piece of method optimization info
+   * after prototype changes were made.
+   */
+  @Override
+  public int fixupReturnedArgumentIndex(int returnedArgumentIndex) {
+    if (getArgumentInfoCollection().isEmpty() || returnedArgumentIndex < 0) {
+      return returnedArgumentIndex;
+    }
+    return getArgumentInfoCollection().isArgumentRemoved(returnedArgumentIndex)
+        ? -1
+        : getArgumentInfoCollection().getNewArgumentIndex(returnedArgumentIndex);
+  }
+
+  /**
+   * Function for rewriting the simple inlining constraint on a piece of method optimization info
+   * after prototype changes were made.
+   */
+  @Override
+  public SimpleInliningConstraint fixupSimpleInliningConstraint(
+      SimpleInliningConstraint constraint, SimpleInliningConstraintFactory factory) {
+    if (getArgumentInfoCollection().isEmpty()) {
+      return constraint;
+    }
+    return constraint.fixupAfterParametersChanged(getArgumentInfoCollection(), factory);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/AbstractFieldSet.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/AbstractFieldSet.java
index a5977df..b6ac534 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/AbstractFieldSet.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/AbstractFieldSet.java
@@ -8,6 +8,8 @@
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 /**
  * Implements a lifted subset lattice for fields.
@@ -71,6 +73,9 @@
     return lessThanOrEqual(other) && !equals(other);
   }
 
+  public abstract AbstractFieldSet fixupReadSetAfterParametersChanged(
+      AppView<AppInfoWithLiveness> appView, ArgumentInfoCollection argumentInfoCollection);
+
   public abstract AbstractFieldSet rewrittenWithLens(
       AppView<?> appView, GraphLens lens, PrunedItems prunedItems);
 }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/ConcreteMutableFieldSet.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/ConcreteMutableFieldSet.java
index cdb9eb9..757e426 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/ConcreteMutableFieldSet.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/ConcreteMutableFieldSet.java
@@ -10,6 +10,8 @@
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.SetUtils;
 import com.google.common.collect.Sets;
@@ -70,6 +72,22 @@
   }
 
   @Override
+  public AbstractFieldSet fixupReadSetAfterParametersChanged(
+      AppView<AppInfoWithLiveness> appView, ArgumentInfoCollection argumentInfoCollection) {
+    assert !isEmpty();
+
+    if (argumentInfoCollection.isEmpty()) {
+      return this;
+    }
+
+    // Find the new field gets that are introduced as a result of constant parameter removal.
+    AbstractFieldSet newReadSet =
+        EmptyFieldSet.getInstance()
+            .fixupReadSetAfterParametersChanged(appView, argumentInfoCollection);
+    return newReadSet.isEmpty() ? this : newReadSet.asConcreteFieldSet().addAll(this);
+  }
+
+  @Override
   public AbstractFieldSet rewrittenWithLens(
       AppView<?> appView, GraphLens lens, PrunedItems prunedItems) {
     assert !isEmpty();
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/EmptyFieldSet.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/EmptyFieldSet.java
index d5d694f..78fa9c0 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/EmptyFieldSet.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/EmptyFieldSet.java
@@ -8,6 +8,9 @@
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 public class EmptyFieldSet extends AbstractFieldSet implements KnownFieldSet {
 
@@ -40,6 +43,35 @@
   }
 
   @Override
+  public AbstractFieldSet fixupReadSetAfterParametersChanged(
+      AppView<AppInfoWithLiveness> appView, ArgumentInfoCollection argumentInfoCollection) {
+    if (argumentInfoCollection.isEmpty()) {
+      return this;
+    }
+
+    // Find the new field gets that are introduced as a result of constant parameter removal.
+    ConcreteMutableFieldSet newReadSet = new ConcreteMutableFieldSet();
+    argumentInfoCollection.forEach(
+        (argumentIndex, argumentInfo) -> {
+          if (argumentInfo.isRemovedArgumentInfo()) {
+            RemovedArgumentInfo removedArgumentInfo = argumentInfo.asRemovedArgumentInfo();
+            if (removedArgumentInfo.hasSingleValue()
+                && removedArgumentInfo.getSingleValue().isSingleFieldValue()) {
+              DexEncodedField definition =
+                  removedArgumentInfo.getSingleValue().asSingleFieldValue().getField(appView);
+              if (definition != null) {
+                newReadSet.add(definition);
+              } else {
+                assert false;
+              }
+            }
+          }
+        });
+
+    return newReadSet.isEmpty() ? this : newReadSet;
+  }
+
+  @Override
   public AbstractFieldSet rewrittenWithLens(
       AppView<?> appView, GraphLens lens, PrunedItems prunedItems) {
     return this;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/UnknownFieldSet.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/UnknownFieldSet.java
index 32ddba9..5de960d 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/UnknownFieldSet.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/UnknownFieldSet.java
@@ -8,6 +8,8 @@
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 public class UnknownFieldSet extends AbstractFieldSet {
 
@@ -35,6 +37,12 @@
   }
 
   @Override
+  public AbstractFieldSet fixupReadSetAfterParametersChanged(
+      AppView<AppInfoWithLiveness> appView, ArgumentInfoCollection argumentInfoCollection) {
+    return this;
+  }
+
+  @Override
   public AbstractFieldSet rewrittenWithLens(
       AppView<?> appView, GraphLens lens, PrunedItems prunedItems) {
     return this;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/AlwaysSimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/AlwaysSimpleInliningConstraint.java
index 93cdb16..9d4f3cf 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/AlwaysSimpleInliningConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/AlwaysSimpleInliningConstraint.java
@@ -4,8 +4,8 @@
 
 package com.android.tools.r8.ir.analysis.inlining;
 
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.ir.code.InvokeMethod;
-import it.unimi.dsi.fastutil.ints.IntList;
 
 /** Constraint that is always satisfied. */
 public class AlwaysSimpleInliningConstraint extends SimpleInliningConstraint {
@@ -30,14 +30,8 @@
   }
 
   @Override
-  public SimpleInliningConstraint fixupAfterRemovingThisParameter(
-      SimpleInliningConstraintFactory factory) {
-    return this;
-  }
-
-  @Override
-  public SimpleInliningConstraint rewrittenWithUnboxedArguments(
-      IntList unboxedArgumentIndices, SimpleInliningConstraintFactory factory) {
+  public SimpleInliningConstraint fixupAfterParametersChanged(
+      ArgumentInfoCollection changes, SimpleInliningConstraintFactory factory) {
     return this;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/EqualToBooleanSimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/EqualToBooleanSimpleInliningConstraint.java
index dae3231..eb663af 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/EqualToBooleanSimpleInliningConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/EqualToBooleanSimpleInliningConstraint.java
@@ -4,10 +4,12 @@
 
 package com.android.tools.r8.ir.analysis.inlining;
 
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
+import com.android.tools.r8.ir.analysis.value.SingleValue;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InvokeMethod;
 import com.android.tools.r8.ir.code.Value;
-import it.unimi.dsi.fastutil.ints.IntList;
 
 /** Constraint that is satisfied if a specific argument is always true. */
 public class EqualToBooleanSimpleInliningConstraint extends SimpleInliningArgumentConstraint {
@@ -26,6 +28,28 @@
   }
 
   @Override
+  public SimpleInliningConstraint fixupAfterParametersChanged(
+      ArgumentInfoCollection changes, SimpleInliningConstraintFactory factory) {
+    if (changes.isArgumentRemoved(getArgumentIndex())) {
+      RemovedArgumentInfo removedArgumentInfo =
+          changes.getArgumentInfo(getArgumentIndex()).asRemovedArgumentInfo();
+      if (!removedArgumentInfo.hasSingleValue()) {
+        // We should never have constraints for unused arguments.
+        assert false;
+        return NeverSimpleInliningConstraint.getInstance();
+      }
+      SingleValue singleValue = removedArgumentInfo.getSingleValue();
+      return singleValue.isSingleNumberValue()
+              && singleValue.asSingleNumberValue().getBooleanValue() == value
+          ? AlwaysSimpleInliningConstraint.getInstance()
+          : NeverSimpleInliningConstraint.getInstance();
+    } else {
+      assert !changes.hasArgumentInfo(getArgumentIndex());
+    }
+    return withArgumentIndex(changes.getNewArgumentIndex(getArgumentIndex()), factory);
+  }
+
+  @Override
   public boolean isSatisfied(InvokeMethod invoke) {
     Value argumentRoot = getArgument(invoke).getAliasedValue();
     return argumentRoot.isDefinedByInstructionSatisfying(Instruction::isConstNumber)
@@ -33,12 +57,6 @@
   }
 
   @Override
-  public SimpleInliningConstraint rewrittenWithUnboxedArguments(
-      IntList unboxedArgumentIndices, SimpleInliningConstraintFactory factory) {
-    return this;
-  }
-
-  @Override
   SimpleInliningArgumentConstraint withArgumentIndex(
       int argumentIndex, SimpleInliningConstraintFactory factory) {
     return factory.createEqualToBooleanConstraint(argumentIndex, value);
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/NeverSimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NeverSimpleInliningConstraint.java
index 809dbb9..3d35fa9 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/NeverSimpleInliningConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NeverSimpleInliningConstraint.java
@@ -4,8 +4,8 @@
 
 package com.android.tools.r8.ir.analysis.inlining;
 
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.ir.code.InvokeMethod;
-import it.unimi.dsi.fastutil.ints.IntList;
 
 /** Constraint that is never satisfied. */
 public class NeverSimpleInliningConstraint extends SimpleInliningConstraint {
@@ -29,14 +29,8 @@
   }
 
   @Override
-  public SimpleInliningConstraint fixupAfterRemovingThisParameter(
-      SimpleInliningConstraintFactory factory) {
-    return this;
-  }
-
-  @Override
-  public SimpleInliningConstraint rewrittenWithUnboxedArguments(
-      IntList unboxedArgumentIndices, SimpleInliningConstraintFactory factory) {
+  public SimpleInliningConstraint fixupAfterParametersChanged(
+      ArgumentInfoCollection changes, SimpleInliningConstraintFactory factory) {
     return this;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/NullSimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NullSimpleInliningConstraint.java
index 13cc5b9..750ca4d 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/NullSimpleInliningConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NullSimpleInliningConstraint.java
@@ -4,12 +4,15 @@
 
 package com.android.tools.r8.ir.analysis.inlining;
 
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfo;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.RewrittenTypeInfo;
 import com.android.tools.r8.ir.analysis.type.Nullability;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InvokeMethod;
 import com.android.tools.r8.ir.code.Value;
-import it.unimi.dsi.fastutil.ints.IntList;
 
 /** Constraint that is satisfied if a specific argument is always null. */
 public class NullSimpleInliningConstraint extends SimpleInliningArgumentConstraint {
@@ -29,6 +32,34 @@
   }
 
   @Override
+  public SimpleInliningConstraint fixupAfterParametersChanged(
+      ArgumentInfoCollection changes, SimpleInliningConstraintFactory factory) {
+    ArgumentInfo argumentInfo = changes.getArgumentInfo(getArgumentIndex());
+    if (argumentInfo.isRemovedArgumentInfo()) {
+      RemovedArgumentInfo removedArgumentInfo =
+          changes.getArgumentInfo(getArgumentIndex()).asRemovedArgumentInfo();
+      if (!removedArgumentInfo.hasSingleValue()) {
+        // We should never have constraints for unused arguments.
+        assert false;
+        return NeverSimpleInliningConstraint.getInstance();
+      }
+      return removedArgumentInfo.getSingleValue().isNull() && nullability.isDefinitelyNull()
+          ? AlwaysSimpleInliningConstraint.getInstance()
+          : NeverSimpleInliningConstraint.getInstance();
+    } else if (argumentInfo.isRewrittenTypeInfo()) {
+      RewrittenTypeInfo rewrittenTypeInfo = argumentInfo.asRewrittenTypeInfo();
+      // We should only get here as a result of enum unboxing.
+      assert rewrittenTypeInfo.getOldType().isClassType();
+      assert rewrittenTypeInfo.getNewType().isIntType();
+      // Rewrite definitely-null constraints to definitely-zero constraints.
+      return nullability.isDefinitelyNull()
+          ? factory.createEqualToNumberConstraint(getArgumentIndex(), 0)
+          : factory.createNotEqualToNumberConstraint(getArgumentIndex(), 0);
+    }
+    return withArgumentIndex(changes.getNewArgumentIndex(getArgumentIndex()), factory);
+  }
+
+  @Override
   public final boolean isSatisfied(InvokeMethod invoke) {
     Value argument = getArgument(invoke);
     TypeElement argumentType = argument.getType();
@@ -47,17 +78,6 @@
   }
 
   @Override
-  public SimpleInliningConstraint rewrittenWithUnboxedArguments(
-      IntList unboxedArgumentIndices, SimpleInliningConstraintFactory factory) {
-    if (unboxedArgumentIndices.contains(getArgumentIndex())) {
-      return nullability.isDefinitelyNull()
-          ? factory.createEqualToNumberConstraint(getArgumentIndex(), 0)
-          : factory.createNotEqualToNumberConstraint(getArgumentIndex(), 0);
-    }
-    return this;
-  }
-
-  @Override
   SimpleInliningArgumentConstraint withArgumentIndex(
       int argumentIndex, SimpleInliningConstraintFactory factory) {
     return factory.createNullConstraint(argumentIndex, nullability);
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/NumberSimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NumberSimpleInliningConstraint.java
index 4f6ee2c..50e9844 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/NumberSimpleInliningConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NumberSimpleInliningConstraint.java
@@ -4,10 +4,12 @@
 
 package com.android.tools.r8.ir.analysis.inlining;
 
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
+import com.android.tools.r8.ir.analysis.value.SingleValue;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InvokeMethod;
 import com.android.tools.r8.ir.code.Value;
-import it.unimi.dsi.fastutil.ints.IntList;
 
 public abstract class NumberSimpleInliningConstraint extends SimpleInliningArgumentConstraint {
 
@@ -23,6 +25,27 @@
   }
 
   @Override
+  public SimpleInliningConstraint fixupAfterParametersChanged(
+      ArgumentInfoCollection changes, SimpleInliningConstraintFactory factory) {
+    if (changes.isArgumentRemoved(getArgumentIndex())) {
+      RemovedArgumentInfo removedArgumentInfo =
+          changes.getArgumentInfo(getArgumentIndex()).asRemovedArgumentInfo();
+      if (!removedArgumentInfo.hasSingleValue()) {
+        // We should never have constraints for unused arguments.
+        assert false;
+        return NeverSimpleInliningConstraint.getInstance();
+      }
+      SingleValue singleValue = removedArgumentInfo.getSingleValue();
+      return singleValue.isSingleNumberValue() && test(singleValue.asSingleNumberValue().getValue())
+          ? AlwaysSimpleInliningConstraint.getInstance()
+          : NeverSimpleInliningConstraint.getInstance();
+    } else {
+      assert !changes.hasArgumentInfo(getArgumentIndex());
+    }
+    return withArgumentIndex(changes.getNewArgumentIndex(getArgumentIndex()), factory);
+  }
+
+  @Override
   public final boolean isSatisfied(InvokeMethod invoke) {
     Value argumentRoot = getArgument(invoke).getAliasedValue();
     return argumentRoot.isDefinedByInstructionSatisfying(Instruction::isConstNumber)
@@ -30,10 +53,4 @@
   }
 
   abstract boolean test(long argumentValue);
-
-  @Override
-  public final SimpleInliningConstraint rewrittenWithUnboxedArguments(
-      IntList unboxedArgumentIndices, SimpleInliningConstraintFactory factory) {
-    return this;
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningArgumentConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningArgumentConstraint.java
index 78bf329..8583b96 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningArgumentConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningArgumentConstraint.java
@@ -15,13 +15,6 @@
     this.argumentIndex = argumentIndex;
   }
 
-  @Override
-  public final SimpleInliningConstraint fixupAfterRemovingThisParameter(
-      SimpleInliningConstraintFactory factory) {
-    assert getArgumentIndex() > 0;
-    return withArgumentIndex(getArgumentIndex() - 1, factory);
-  }
-
   Value getArgument(InvokeMethod invoke) {
     return invoke.getArgument(argumentIndex);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraint.java
index c9978cb..b7d88f7 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraint.java
@@ -4,9 +4,9 @@
 
 package com.android.tools.r8.ir.analysis.inlining;
 
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.ir.code.InvokeMethod;
 import com.google.common.collect.ImmutableList;
-import it.unimi.dsi.fastutil.ints.IntList;
 import java.util.function.Supplier;
 
 public abstract class SimpleInliningConstraint {
@@ -90,9 +90,6 @@
     return new SimpleInliningConstraintDisjunction(ImmutableList.of(this, other));
   }
 
-  public abstract SimpleInliningConstraint fixupAfterRemovingThisParameter(
-      SimpleInliningConstraintFactory factory);
-
-  public abstract SimpleInliningConstraint rewrittenWithUnboxedArguments(
-      IntList unboxedArgumentIndices, SimpleInliningConstraintFactory factory);
+  public abstract SimpleInliningConstraint fixupAfterParametersChanged(
+      ArgumentInfoCollection changes, SimpleInliningConstraintFactory factory);
 }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintConjunction.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintConjunction.java
index ae2e07b..3814e2e 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintConjunction.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintConjunction.java
@@ -4,10 +4,11 @@
 
 package com.android.tools.r8.ir.analysis.inlining;
 
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.ir.code.InvokeMethod;
 import com.android.tools.r8.utils.ListUtils;
 import com.google.common.collect.ImmutableList;
-import it.unimi.dsi.fastutil.ints.IntList;
+import com.google.common.collect.Iterables;
 import java.util.List;
 
 public class SimpleInliningConstraintConjunction extends SimpleInliningConstraint {
@@ -66,26 +67,38 @@
   }
 
   @Override
-  public SimpleInliningConstraint fixupAfterRemovingThisParameter(
-      SimpleInliningConstraintFactory factory) {
-    List<SimpleInliningConstraint> rewrittenConstraints =
-        ListUtils.mapOrElse(
-            constraints, constraint -> constraint.fixupAfterRemovingThisParameter(factory), null);
-    return rewrittenConstraints != null
-        ? new SimpleInliningConstraintConjunction(rewrittenConstraints)
-        : this;
-  }
-
-  @Override
-  public SimpleInliningConstraint rewrittenWithUnboxedArguments(
-      IntList unboxedArgumentIndices, SimpleInliningConstraintFactory factory) {
+  public SimpleInliningConstraint fixupAfterParametersChanged(
+      ArgumentInfoCollection changes, SimpleInliningConstraintFactory factory) {
     List<SimpleInliningConstraint> rewrittenConstraints =
         ListUtils.mapOrElse(
             constraints,
-            constraint -> constraint.rewrittenWithUnboxedArguments(unboxedArgumentIndices, factory),
+            constraint -> {
+              SimpleInliningConstraint rewrittenConstraint =
+                  constraint.fixupAfterParametersChanged(changes, factory);
+              if (rewrittenConstraint.isAlways()) {
+                // Remove 'always' from conjunctions.
+                return null;
+              }
+              return rewrittenConstraint;
+            },
             null);
-    return rewrittenConstraints != null
-        ? new SimpleInliningConstraintConjunction(rewrittenConstraints)
-        : this;
+
+    if (rewrittenConstraints == null) {
+      return this;
+    }
+
+    if (rewrittenConstraints.isEmpty()) {
+      return AlwaysSimpleInliningConstraint.getInstance();
+    }
+
+    if (rewrittenConstraints.size() == 1) {
+      return ListUtils.first(rewrittenConstraints);
+    }
+
+    if (Iterables.any(rewrittenConstraints, SimpleInliningConstraint::isNever)) {
+      return NeverSimpleInliningConstraint.getInstance();
+    }
+
+    return new SimpleInliningConstraintConjunction(rewrittenConstraints);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintDisjunction.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintDisjunction.java
index 42bcaf6..de6bddb 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintDisjunction.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintDisjunction.java
@@ -4,10 +4,11 @@
 
 package com.android.tools.r8.ir.analysis.inlining;
 
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.ir.code.InvokeMethod;
 import com.android.tools.r8.utils.ListUtils;
 import com.google.common.collect.ImmutableList;
-import it.unimi.dsi.fastutil.ints.IntList;
+import com.google.common.collect.Iterables;
 import java.util.List;
 
 public class SimpleInliningConstraintDisjunction extends SimpleInliningConstraint {
@@ -66,26 +67,38 @@
   }
 
   @Override
-  public SimpleInliningConstraint fixupAfterRemovingThisParameter(
-      SimpleInliningConstraintFactory factory) {
-    List<SimpleInliningConstraint> rewrittenConstraints =
-        ListUtils.mapOrElse(
-            constraints, constraint -> constraint.fixupAfterRemovingThisParameter(factory), null);
-    return rewrittenConstraints != null
-        ? new SimpleInliningConstraintDisjunction(rewrittenConstraints)
-        : this;
-  }
-
-  @Override
-  public SimpleInliningConstraint rewrittenWithUnboxedArguments(
-      IntList unboxedArgumentIndices, SimpleInliningConstraintFactory factory) {
+  public SimpleInliningConstraint fixupAfterParametersChanged(
+      ArgumentInfoCollection changes, SimpleInliningConstraintFactory factory) {
     List<SimpleInliningConstraint> rewrittenConstraints =
         ListUtils.mapOrElse(
             constraints,
-            constraint -> constraint.rewrittenWithUnboxedArguments(unboxedArgumentIndices, factory),
+            constraint -> {
+              SimpleInliningConstraint rewrittenConstraint =
+                  constraint.fixupAfterParametersChanged(changes, factory);
+              if (rewrittenConstraint.isNever()) {
+                // Remove 'never' from disjunctions.
+                return null;
+              }
+              return rewrittenConstraint;
+            },
             null);
-    return rewrittenConstraints != null
-        ? new SimpleInliningConstraintDisjunction(rewrittenConstraints)
-        : this;
+
+    if (rewrittenConstraints == null) {
+      return this;
+    }
+
+    if (rewrittenConstraints.isEmpty()) {
+      return NeverSimpleInliningConstraint.getInstance();
+    }
+
+    if (rewrittenConstraints.size() == 1) {
+      return ListUtils.first(rewrittenConstraints);
+    }
+
+    if (Iterables.any(rewrittenConstraints, SimpleInliningConstraint::isAlways)) {
+      return AlwaysSimpleInliningConstraint.getInstance();
+    }
+
+    return new SimpleInliningConstraintDisjunction(rewrittenConstraints);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java
index 3352cf7..c9bcee0 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java
@@ -15,12 +15,14 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.code.ConstClass;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.NumberGenerator;
 import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
 import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfo;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 public class SingleConstClassValue extends SingleConstValue {
@@ -109,6 +111,12 @@
   }
 
   @Override
+  public InstanceFieldInitializationInfo fixupAfterParametersChanged(
+      ArgumentInfoCollection argumentInfoCollection) {
+    return this;
+  }
+
+  @Override
   public SingleValue rewrittenWithLens(AppView<AppInfoWithLiveness> appView, GraphLens lens) {
     assert lens.lookupType(type) == type;
     return this;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleDexItemBasedStringValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleDexItemBasedStringValue.java
index a537863..f1fac36 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleDexItemBasedStringValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleDexItemBasedStringValue.java
@@ -13,12 +13,14 @@
 import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.code.DexItemBasedConstString;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.NumberGenerator;
 import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
 import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfo;
 import com.android.tools.r8.naming.dexitembasedstring.NameComputationInfo;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import java.util.Objects;
@@ -106,6 +108,12 @@
   }
 
   @Override
+  public InstanceFieldInitializationInfo fixupAfterParametersChanged(
+      ArgumentInfoCollection argumentInfoCollection) {
+    return this;
+  }
+
+  @Override
   public SingleValue rewrittenWithLens(AppView<AppInfoWithLiveness> appView, GraphLens lens) {
     return appView
         .abstractValueFactory()
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
index de0be6d..530bfc4 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
@@ -9,12 +9,14 @@
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.code.Instruction;
@@ -23,6 +25,7 @@
 import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.ir.optimize.enums.EnumDataMap;
+import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfo;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 public abstract class SingleFieldValue extends SingleValue {
@@ -37,6 +40,11 @@
     return field;
   }
 
+  public DexEncodedField getField(DexDefinitionSupplier definitions) {
+    DexClass holder = definitions.definitionFor(field.getHolderType());
+    return field.lookupOnClass(holder);
+  }
+
   public abstract ObjectState getState();
 
   public boolean mayHaveFinalizeMethodDirectlyOrIndirectly(AppView<AppInfoWithLiveness> appView) {
@@ -105,6 +113,12 @@
   }
 
   @Override
+  public InstanceFieldInitializationInfo fixupAfterParametersChanged(
+      ArgumentInfoCollection argumentInfoCollection) {
+    return this;
+  }
+
+  @Override
   public SingleValue rewrittenWithLens(AppView<AppInfoWithLiveness> appView, GraphLens lens) {
     AbstractValueFactory factory = appView.abstractValueFactory();
     if (field.holder == field.type) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java
index c01133e..264bec5 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java
@@ -9,12 +9,14 @@
 import com.android.tools.r8.graph.DebugLocalInfo;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.code.ConstNumber;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.NumberGenerator;
 import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
 import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfo;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.ArrayUtils;
 import com.android.tools.r8.utils.OptionalBool;
@@ -152,6 +154,12 @@
   }
 
   @Override
+  public InstanceFieldInitializationInfo fixupAfterParametersChanged(
+      ArgumentInfoCollection argumentInfoCollection) {
+    return this;
+  }
+
+  @Override
   public SingleValue rewrittenWithLens(AppView<AppInfoWithLiveness> appView, GraphLens lens) {
     return this;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java
index 35acae4..f346b24 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java
@@ -13,12 +13,14 @@
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.code.ConstString;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.NumberGenerator;
 import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
 import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfo;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 public class SingleStringValue extends SingleConstValue {
@@ -93,6 +95,12 @@
   }
 
   @Override
+  public InstanceFieldInitializationInfo fixupAfterParametersChanged(
+      ArgumentInfoCollection argumentInfoCollection) {
+    return this;
+  }
+
+  @Override
   public SingleValue rewrittenWithLens(AppView<AppInfoWithLiveness> appView, GraphLens lens) {
     return this;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java b/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
index 53bb277..13b7140 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
@@ -66,8 +66,6 @@
   void setEnumUnboxerMethodClassification(
       ProgramMethod method, EnumUnboxerMethodClassification enumUnboxerMethodClassification);
 
-  void unsetEnumUnboxerMethodClassification(ProgramMethod method);
-
   void setInstanceInitializerInfoCollection(
       DexEncodedMethod method, InstanceInitializerInfoCollection instanceInitializerInfoCollection);
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysFalseClassInlinerMethodConstraint.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysFalseClassInlinerMethodConstraint.java
index 6ddae8d..0a2ffa1 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysFalseClassInlinerMethodConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysFalseClassInlinerMethodConstraint.java
@@ -6,6 +6,7 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.ir.analysis.value.ObjectState;
 import com.android.tools.r8.ir.optimize.classinliner.analysis.ParameterUsage;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -22,7 +23,7 @@
   }
 
   @Override
-  public ClassInlinerMethodConstraint fixupAfterRemovingThisParameter() {
+  public ClassInlinerMethodConstraint fixupAfterParametersChanged(ArgumentInfoCollection changes) {
     return this;
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysTrueClassInlinerMethodConstraint.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysTrueClassInlinerMethodConstraint.java
index dc89cf4..ebc8ad1 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysTrueClassInlinerMethodConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysTrueClassInlinerMethodConstraint.java
@@ -6,6 +6,7 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.ir.analysis.value.ObjectState;
 import com.android.tools.r8.ir.optimize.classinliner.analysis.ParameterUsage;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -22,7 +23,7 @@
   }
 
   @Override
-  public ClassInlinerMethodConstraint fixupAfterRemovingThisParameter() {
+  public ClassInlinerMethodConstraint fixupAfterParametersChanged(ArgumentInfoCollection changes) {
     return this;
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ClassInlinerMethodConstraint.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ClassInlinerMethodConstraint.java
index 22079fe..3e2e706 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ClassInlinerMethodConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ClassInlinerMethodConstraint.java
@@ -6,13 +6,14 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.ir.analysis.value.ObjectState;
 import com.android.tools.r8.ir.optimize.classinliner.analysis.ParameterUsage;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 public interface ClassInlinerMethodConstraint {
 
-  ClassInlinerMethodConstraint fixupAfterRemovingThisParameter();
+  ClassInlinerMethodConstraint fixupAfterParametersChanged(ArgumentInfoCollection changes);
 
   ParameterUsage getParameterUsage(int parameter);
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ConditionalClassInlinerMethodConstraint.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ConditionalClassInlinerMethodConstraint.java
index eb743cb..c559462 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ConditionalClassInlinerMethodConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ConditionalClassInlinerMethodConstraint.java
@@ -9,6 +9,9 @@
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfo;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.RewrittenTypeInfo;
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
 import com.android.tools.r8.ir.analysis.value.ObjectState;
 import com.android.tools.r8.ir.analysis.value.SingleConstValue;
@@ -32,7 +35,7 @@
   }
 
   @Override
-  public ClassInlinerMethodConstraint fixupAfterRemovingThisParameter() {
+  public ClassInlinerMethodConstraint fixupAfterParametersChanged(ArgumentInfoCollection changes) {
     if (usages.isBottom()) {
       return this;
     }
@@ -40,10 +43,22 @@
     usages
         .asNonEmpty()
         .forEach(
-            (parameter, usagePerContext) -> {
-              if (parameter > 0) {
-                backing.put(parameter - 1, usagePerContext);
+            (argumentIndex, usagePerContext) -> {
+              ArgumentInfo argumentInfo = changes.getArgumentInfo(argumentIndex);
+              if (argumentInfo.isRemovedArgumentInfo()) {
+                // When removing a parameter from a method, we no longer need information about the
+                // usages of that parameter for class inlining.
+                return;
               }
+              if (argumentInfo.isRewrittenTypeInfo()) {
+                // This is due to enum unboxing. After enum unboxing, we no longer need information
+                // about the usages of this parameter for class inlining.
+                RewrittenTypeInfo rewrittenTypeInfo = argumentInfo.asRewrittenTypeInfo();
+                assert rewrittenTypeInfo.getOldType().isClassType();
+                assert rewrittenTypeInfo.getNewType().isIntType();
+                return;
+              }
+              backing.put(changes.getNewArgumentIndex(argumentIndex), usagePerContext);
             });
     return new ConditionalClassInlinerMethodConstraint(NonEmptyParameterUsages.create(backing));
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java
index c9c7c40..da704c1 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java
@@ -100,7 +100,7 @@
       move(from, to, fromStatic, toStatic, 0);
     }
 
-    public void move(
+    public RewrittenPrototypeDescription move(
         DexMethod from,
         DexMethod to,
         boolean fromStatic,
@@ -134,10 +134,11 @@
               ? null
               : new RewrittenPrototypeDescription.RewrittenTypeInfo(
                   from.proto.returnType, to.proto.returnType);
-      prototypeChangesPerMethod.put(
-          to,
+      RewrittenPrototypeDescription prototypeChanges =
           RewrittenPrototypeDescription.createForRewrittenTypes(returnInfo, builder.build())
-              .withExtraUnusedNullParameters(numberOfExtraNullParameters));
+              .withExtraUnusedNullParameters(numberOfExtraNullParameters);
+      prototypeChangesPerMethod.put(to, prototypeChanges);
+      return prototypeChanges;
     }
 
     void recordCheckNotZeroMethod(
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 09dc715..c7bcc37 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
@@ -24,7 +24,7 @@
 import com.android.tools.r8.graph.ProgramField;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.PrunedItems;
-import com.android.tools.r8.ir.analysis.inlining.SimpleInliningConstraint;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription;
 import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.code.BasicBlock;
@@ -48,7 +48,6 @@
 import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfo;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.ImmutableArrayUtils;
 import com.android.tools.r8.utils.OptionalBool;
 import com.android.tools.r8.utils.SetUtils;
@@ -56,8 +55,6 @@
 import com.android.tools.r8.utils.Timing;
 import com.android.tools.r8.utils.collections.ProgramMethodMap;
 import com.google.common.collect.Sets;
-import it.unimi.dsi.fastutil.ints.IntArrayList;
-import it.unimi.dsi.fastutil.ints.IntList;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.IdentityHashMap;
@@ -516,38 +513,18 @@
     newMethod = ensureUniqueMethod(method, newMethod);
     int numberOfExtraNullParameters = newMethod.getArity() - method.getReference().getArity();
     boolean isStatic = method.isStatic();
-    lensBuilder.move(
-        method.getReference(), newMethod, isStatic, isStatic, numberOfExtraNullParameters);
+    RewrittenPrototypeDescription prototypeChanges =
+        lensBuilder.move(
+            method.getReference(), newMethod, isStatic, isStatic, numberOfExtraNullParameters);
     return method.toTypeSubstitutedMethod(
         newMethod,
         builder ->
             builder
-                .fixupCallSiteOptimizationInfo(
-                    callSiteOptimizationInfo ->
-                        callSiteOptimizationInfo.fixupAfterExtraNullParameters(
-                            numberOfExtraNullParameters))
+                .fixupOptimizationInfo(
+                    appView, prototypeChanges.createMethodOptimizationInfoFixer())
                 .setCompilationState(method.getCompilationState())
                 .setIsLibraryMethodOverrideIf(
-                    method.isNonPrivateVirtualMethod(), OptionalBool.FALSE)
-                .setSimpleInliningConstraint(
-                    holder, getRewrittenSimpleInliningConstraint(method, oldProto, newProto)));
-  }
-
-  private SimpleInliningConstraint getRewrittenSimpleInliningConstraint(
-      DexEncodedMethod method, DexProto oldProto, DexProto newProto) {
-    IntList unboxedArgumentIndices = new IntArrayList();
-    int offset = BooleanUtils.intValue(method.isInstance());
-    for (int i = 0; i < method.getReference().getArity(); i++) {
-      if (oldProto.getParameter(i).isReferenceType()
-          && newProto.getParameter(i).isPrimitiveType()) {
-        unboxedArgumentIndices.add(i + offset);
-      }
-    }
-    return method
-        .getOptimizationInfo()
-        .getSimpleInliningConstraint()
-        .rewrittenWithUnboxedArguments(
-            unboxedArgumentIndices, appView.simpleInliningConstraintFactory());
+                    method.isNonPrivateVirtualMethod(), OptionalBool.FALSE));
   }
 
   private DexMethod ensureUniqueMethod(DexEncodedMethod encodedMethod, DexMethod newMethod) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/CheckNotNullEnumUnboxerMethodClassification.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/CheckNotNullEnumUnboxerMethodClassification.java
index 1a466ed..e9f1bdb 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/CheckNotNullEnumUnboxerMethodClassification.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/CheckNotNullEnumUnboxerMethodClassification.java
@@ -32,7 +32,7 @@
   }
 
   @Override
-  public EnumUnboxerMethodClassification fixupAfterParameterRemoval(
+  public EnumUnboxerMethodClassification fixupAfterParametersChanged(
       ArgumentInfoCollection removedParameters) {
     if (removedParameters.getArgumentInfo(argumentIndex).isRemovedArgumentInfo()) {
       // If the null-checked argument is removed from the parameters of the method, then we can no
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/EnumUnboxerMethodClassification.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/EnumUnboxerMethodClassification.java
index 5c93c36..f9192b9 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/EnumUnboxerMethodClassification.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/EnumUnboxerMethodClassification.java
@@ -12,15 +12,9 @@
     return UnknownEnumUnboxerMethodClassification.getInstance();
   }
 
-  public abstract EnumUnboxerMethodClassification fixupAfterParameterRemoval(
+  public abstract EnumUnboxerMethodClassification fixupAfterParametersChanged(
       ArgumentInfoCollection removedParameters);
 
-  public EnumUnboxerMethodClassification fixupAfterRemovingThisParameter() {
-    // Only static methods are currently classified by the enum unboxer.
-    assert isUnknownClassification();
-    return unknown();
-  }
-
   public boolean isCheckNotNullClassification() {
     return false;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/UnknownEnumUnboxerMethodClassification.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/UnknownEnumUnboxerMethodClassification.java
index e88239b..04529b4 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/UnknownEnumUnboxerMethodClassification.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/UnknownEnumUnboxerMethodClassification.java
@@ -18,7 +18,7 @@
   }
 
   @Override
-  public EnumUnboxerMethodClassification fixupAfterParameterRemoval(
+  public EnumUnboxerMethodClassification fixupAfterParametersChanged(
       ArgumentInfoCollection removedParameters) {
     return this;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/ConcreteCallSiteOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/ConcreteCallSiteOptimizationInfo.java
index a82770c..d598935 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/ConcreteCallSiteOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/ConcreteCallSiteOptimizationInfo.java
@@ -13,6 +13,8 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
 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.ir.analysis.type.DynamicType;
 import com.android.tools.r8.ir.analysis.type.Nullability;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
@@ -26,9 +28,6 @@
 import it.unimi.dsi.fastutil.ints.Int2ReferenceArrayMap;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceMaps;
-import it.unimi.dsi.fastutil.ints.IntArrayList;
-import it.unimi.dsi.fastutil.ints.IntCollection;
-import it.unimi.dsi.fastutil.ints.IntList;
 import java.util.List;
 
 // Accumulated optimization info from call sites.
@@ -76,33 +75,37 @@
         : this;
   }
 
-  public CallSiteOptimizationInfo fixupAfterParameterRemoval(int removedParameterIndex) {
-    IntList removedParameterIndices = new IntArrayList(1);
-    removedParameterIndices.add(removedParameterIndex);
-    return fixupAfterParameterRemoval(removedParameterIndices);
-  }
-
-  public CallSiteOptimizationInfo fixupAfterParameterRemoval(
-      IntCollection removedParameterIndices) {
-    if (removedParameterIndices.isEmpty()) {
+  public CallSiteOptimizationInfo fixupAfterParametersChanged(
+      RewrittenPrototypeDescription prototypeChanges) {
+    if (prototypeChanges.isEmpty()) {
       return this;
     }
 
-    assert removedParameterIndices.stream()
+    ArgumentInfoCollection parameterChanges = prototypeChanges.getArgumentInfoCollection();
+    if (parameterChanges.isEmpty()) {
+      if (prototypeChanges.hasExtraParameters()) {
+        return new ConcreteCallSiteOptimizationInfo(
+            size + prototypeChanges.numberOfExtraParameters(), dynamicUpperBoundTypes, constants);
+      }
+      return this;
+    }
+
+    assert parameterChanges.getRemovedParameterIndices().stream()
         .allMatch(removedParameterIndex -> removedParameterIndex < size);
 
-    int newSize = size - removedParameterIndices.size();
-    if (newSize == 0) {
+    int newSizeAfterParameterRemoval = size - parameterChanges.numberOfRemovedArguments();
+    if (newSizeAfterParameterRemoval == 0) {
       return top();
     }
 
-    Int2ReferenceMap<AbstractValue> rewrittenConstants = new Int2ReferenceArrayMap<>(newSize);
+    Int2ReferenceMap<AbstractValue> rewrittenConstants =
+        new Int2ReferenceArrayMap<>(newSizeAfterParameterRemoval);
     Int2ReferenceMap<TypeElement> rewrittenDynamicUpperBoundTypes =
-        new Int2ReferenceArrayMap<>(newSize);
+        new Int2ReferenceArrayMap<>(newSizeAfterParameterRemoval);
     for (int parameterIndex = 0, rewrittenParameterIndex = 0;
         parameterIndex < size;
         parameterIndex++) {
-      if (!removedParameterIndices.contains(parameterIndex)) {
+      if (!parameterChanges.isArgumentRemoved(parameterIndex)) {
         AbstractValue abstractValue =
             constants.getOrDefault(parameterIndex, AbstractValue.unknown());
         if (!abstractValue.isUnknown()) {
@@ -116,7 +119,9 @@
       }
     }
     return ConcreteCallSiteOptimizationInfo.create(
-        newSize, rewrittenDynamicUpperBoundTypes, rewrittenConstants);
+        newSizeAfterParameterRemoval + prototypeChanges.numberOfExtraParameters(),
+        rewrittenDynamicUpperBoundTypes,
+        rewrittenConstants);
   }
 
   CallSiteOptimizationInfo join(
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoFixer.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoFixer.java
new file mode 100644
index 0000000..4b2476e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoFixer.java
@@ -0,0 +1,43 @@
+// Copyright (c) 2021, 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.info;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.ir.analysis.inlining.SimpleInliningConstraint;
+import com.android.tools.r8.ir.analysis.inlining.SimpleInliningConstraintFactory;
+import com.android.tools.r8.ir.optimize.classinliner.constraint.ClassInlinerMethodConstraint;
+import com.android.tools.r8.ir.optimize.enums.classification.EnumUnboxerMethodClassification;
+import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
+import com.android.tools.r8.ir.optimize.info.bridge.VirtualBridgeInfo;
+import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfoCollection;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import java.util.BitSet;
+
+public abstract class MethodOptimizationInfoFixer {
+
+  public abstract BridgeInfo fixupBridgeInfo(VirtualBridgeInfo bridgeInfo);
+
+  public abstract CallSiteOptimizationInfo fixupCallSiteOptimizationInfo(
+      ConcreteCallSiteOptimizationInfo callSiteOptimizationInfo);
+
+  public abstract ClassInlinerMethodConstraint fixupClassInlinerMethodConstraint(
+      ClassInlinerMethodConstraint classInlinerMethodConstraint);
+
+  public abstract EnumUnboxerMethodClassification fixupEnumUnboxerMethodClassification(
+      EnumUnboxerMethodClassification classification);
+
+  public abstract InstanceInitializerInfoCollection fixupInstanceInitializerInfo(
+      AppView<AppInfoWithLiveness> appView,
+      InstanceInitializerInfoCollection instanceInitializerInfo);
+
+  public abstract BitSet fixupNonNullParamOnNormalExits(BitSet nonNullParamOnNormalExits);
+
+  public abstract BitSet fixupNonNullParamOrThrow(BitSet nonNullParamOrThrow);
+
+  public abstract int fixupReturnedArgumentIndex(int returnedArgumentIndex);
+
+  public abstract SimpleInliningConstraint fixupSimpleInliningConstraint(
+      SimpleInliningConstraint constraint, SimpleInliningConstraintFactory factory);
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
index 4263b35..c5f8fbe 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
@@ -13,6 +13,7 @@
 import com.android.tools.r8.graph.PrunedItems;
 import com.android.tools.r8.ir.analysis.inlining.NeverSimpleInliningConstraint;
 import com.android.tools.r8.ir.analysis.inlining.SimpleInliningConstraint;
+import com.android.tools.r8.ir.analysis.inlining.SimpleInliningConstraintFactory;
 import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
@@ -156,6 +157,18 @@
     enumUnboxerMethodClassification = template.enumUnboxerMethodClassification;
   }
 
+  public MutableMethodOptimizationInfo fixup(
+      AppView<AppInfoWithLiveness> appView, MethodOptimizationInfoFixer fixer) {
+    return fixupBridgeInfo(fixer)
+        .fixupClassInlinerMethodConstraint(fixer)
+        .fixupEnumUnboxerMethodClassification(fixer)
+        .fixupInstanceInitializerInfo(appView, fixer)
+        .fixupNonNullParamOnNormalExits(fixer)
+        .fixupNonNullParamOrThrow(fixer)
+        .fixupReturnedArgumentIndex(fixer)
+        .fixupSimpleInliningConstraint(fixer, appView.simpleInliningConstraintFactory());
+  }
+
   public MutableMethodOptimizationInfo fixupClassTypeReferences(
       AppView<? extends AppInfoWithClassHierarchy> appView, GraphLens lens) {
     return fixupClassTypeReferences(appView, lens, emptySet());
@@ -240,6 +253,12 @@
     return classInlinerConstraint;
   }
 
+  public MutableMethodOptimizationInfo fixupClassInlinerMethodConstraint(
+      MethodOptimizationInfoFixer fixer) {
+    classInlinerConstraint = fixer.fixupClassInlinerMethodConstraint(classInlinerConstraint);
+    return this;
+  }
+
   void setClassInlinerMethodConstraint(ClassInlinerMethodConstraint classInlinerConstraint) {
     this.classInlinerConstraint = classInlinerConstraint;
   }
@@ -261,8 +280,11 @@
     this.enumUnboxerMethodClassification = enumUnboxerMethodClassification;
   }
 
-  void unsetEnumUnboxerMethodClassification() {
-    this.enumUnboxerMethodClassification = EnumUnboxerMethodClassification.unknown();
+  public MutableMethodOptimizationInfo fixupEnumUnboxerMethodClassification(
+      MethodOptimizationInfoFixer fixer) {
+    enumUnboxerMethodClassification =
+        fixer.fixupEnumUnboxerMethodClassification(enumUnboxerMethodClassification);
+    return this;
   }
 
   @Override
@@ -290,16 +312,42 @@
     return instanceInitializerInfoCollection.get(invoke);
   }
 
+  public MutableMethodOptimizationInfo fixupInstanceInitializerInfo(
+      AppView<AppInfoWithLiveness> appView, MethodOptimizationInfoFixer fixer) {
+    instanceInitializerInfoCollection =
+        fixer.fixupInstanceInitializerInfo(appView, instanceInitializerInfoCollection);
+    return this;
+  }
+
   @Override
   public BitSet getNonNullParamOrThrow() {
     return nonNullParamOrThrow;
   }
 
+  public MutableMethodOptimizationInfo fixupNonNullParamOrThrow(MethodOptimizationInfoFixer fixer) {
+    nonNullParamOrThrow = fixer.fixupNonNullParamOrThrow(nonNullParamOrThrow);
+    return this;
+  }
+
+  void setNonNullParamOrThrow(BitSet facts) {
+    this.nonNullParamOrThrow = facts;
+  }
+
   @Override
   public BitSet getNonNullParamOnNormalExits() {
     return nonNullParamOnNormalExits;
   }
 
+  public MutableMethodOptimizationInfo fixupNonNullParamOnNormalExits(
+      MethodOptimizationInfoFixer fixer) {
+    nonNullParamOnNormalExits = fixer.fixupNonNullParamOnNormalExits(nonNullParamOnNormalExits);
+    return this;
+  }
+
+  void setNonNullParamOnNormalExits(BitSet facts) {
+    this.nonNullParamOnNormalExits = facts;
+  }
+
   @Override
   public boolean hasBeenInlinedIntoSingleCallSite() {
     return isFlagSet(HAS_BEEN_INLINED_INTO_SINGLE_CALL_SITE_FLAG);
@@ -335,6 +383,14 @@
     return bridgeInfo;
   }
 
+  public MutableMethodOptimizationInfo fixupBridgeInfo(MethodOptimizationInfoFixer fixer) {
+    if (bridgeInfo != null) {
+      assert bridgeInfo.isVirtualBridgeInfo();
+      bridgeInfo = fixer.fixupBridgeInfo(bridgeInfo.asVirtualBridgeInfo());
+    }
+    return this;
+  }
+
   void setBridgeInfo(BridgeInfo bridgeInfo) {
     this.bridgeInfo = bridgeInfo;
   }
@@ -408,14 +464,6 @@
     return isFlagSet(RETURN_VALUE_ONLY_DEPENDS_ON_ARGUMENTS_FLAG);
   }
 
-  void setNonNullParamOrThrow(BitSet facts) {
-    this.nonNullParamOrThrow = facts;
-  }
-
-  void setNonNullParamOnNormalExits(BitSet facts) {
-    this.nonNullParamOnNormalExits = facts;
-  }
-
   public void setReachabilitySensitive(boolean reachabilitySensitive) {
     setFlag(REACHABILITY_SENSITIVE_FLAG, reachabilitySensitive);
   }
@@ -424,6 +472,13 @@
     this.simpleInliningConstraint = constraint;
   }
 
+  public MutableMethodOptimizationInfo fixupSimpleInliningConstraint(
+      MethodOptimizationInfoFixer fixer, SimpleInliningConstraintFactory factory) {
+    simpleInliningConstraint =
+        fixer.fixupSimpleInliningConstraint(simpleInliningConstraint, factory);
+    return this;
+  }
+
   void setInstanceInitializerInfoCollection(
       InstanceInitializerInfoCollection instanceInitializerInfoCollection) {
     this.instanceInitializerInfoCollection = instanceInitializerInfoCollection;
@@ -437,10 +492,16 @@
     this.initializedClassesOnNormalExit = initializedClassesOnNormalExit;
   }
 
-  void markReturnsArgument(int argument) {
-    assert argument >= 0;
-    assert returnedArgument == -1 || returnedArgument == argument;
-    returnedArgument = argument;
+  void markReturnsArgument(int returnedArgumentIndex) {
+    assert returnedArgumentIndex >= 0;
+    assert returnedArgument == -1 || returnedArgument == returnedArgumentIndex;
+    returnedArgument = returnedArgumentIndex;
+  }
+
+  public MutableMethodOptimizationInfo fixupReturnedArgumentIndex(
+      MethodOptimizationInfoFixer fixer) {
+    returnedArgument = fixer.fixupReturnedArgumentIndex(returnedArgument);
+    return this;
   }
 
   void markMayNotHaveSideEffects() {
@@ -550,64 +611,4 @@
   public MutableMethodOptimizationInfo mutableCopy() {
     return new MutableMethodOptimizationInfo(this);
   }
-
-  public void adjustOptimizationInfoAfterRemovingThisParameter(
-      AppView<AppInfoWithLiveness> appView) {
-    classInlinerConstraint = classInlinerConstraint.fixupAfterRemovingThisParameter();
-    enumUnboxerMethodClassification =
-        enumUnboxerMethodClassification.fixupAfterRemovingThisParameter();
-    simpleInliningConstraint =
-        simpleInliningConstraint.fixupAfterRemovingThisParameter(
-            appView.simpleInliningConstraintFactory());
-    // cannotBeKept: doesn't depend on `this`
-    // classInitializerMayBePostponed: `this` could trigger <clinit> of the previous holder.
-    clearFlag(CLASS_INITIALIZER_MAY_BE_POSTPONED_FLAG);
-    // hasBeenInlinedIntoSingleCallSite: then it should not be staticized.
-    clearFlag(HAS_BEEN_INLINED_INTO_SINGLE_CALL_SITE_FLAG);
-    // initializedClassesOnNormalExit: `this` could trigger <clinit> of the previous holder.
-    initializedClassesOnNormalExit =
-        DefaultMethodOptimizationInfo.UNKNOWN_INITIALIZED_CLASSES_ON_NORMAL_EXIT;
-    // At least, `this` pointer is not used in `returnedArgument`.
-    assert returnedArgument == DefaultMethodOptimizationInfo.UNKNOWN_RETURNED_ARGUMENT
-        || returnedArgument > 0;
-    returnedArgument =
-        returnedArgument == DefaultMethodOptimizationInfo.UNKNOWN_RETURNED_ARGUMENT
-            ? DefaultMethodOptimizationInfo.UNKNOWN_RETURNED_ARGUMENT
-            : returnedArgument - 1;
-    // mayHaveSideEffects: `this` Argument didn't have side effects, so removing it doesn't affect
-    //   whether or not the method may have side effects.
-    // returnValueOnlyDependsOnArguments:
-    //   if the method did before, so it does even after removing `this` Argument
-    // code is not changed, and thus the following *return* info is not changed either.
-    //   * neverReturnsNull
-    //   * neverReturnsNormally
-    //   * constantValue
-    //   * returnsObjectWithUpperBoundType
-    //   * returnsObjectWithLowerBoundType
-    // inlining: it is not inlined, and thus staticized. No more chance of inlining, though.
-    inlining = InlinePreference.Default;
-    // checksNullReceiverBeforeAnySideEffect: no more receiver.
-    markCheckNullReceiverBeforeAnySideEffect(
-        DefaultMethodOptimizationInfo.UNKNOWN_CHECKS_NULL_RECEIVER_BEFORE_ANY_SIDE_EFFECT);
-    // triggersClassInitBeforeAnySideEffect: code is not changed.
-    markTriggerClassInitBeforeAnySideEffect(
-        DefaultMethodOptimizationInfo.UNKNOWN_TRIGGERS_CLASS_INIT_BEFORE_ANY_SIDE_EFFECT);
-    // initializerInfo: the computed initializer info may become invalid.
-    instanceInitializerInfoCollection = InstanceInitializerInfoCollection.empty();
-    // initializerEnablingJavaAssertions: `this` could trigger <clinit> of the previous holder.
-    setFlag(
-        INITIALIZER_ENABLING_JAVA_ASSERTIONS_FLAG,
-        DefaultMethodOptimizationInfo.UNKNOWN_INITIALIZER_ENABLING_JAVA_ASSERTIONS);
-    nonNullParamOrThrow =
-        nonNullParamOrThrow == DefaultMethodOptimizationInfo.NO_NULL_PARAMETER_OR_THROW_FACTS
-            ? DefaultMethodOptimizationInfo.NO_NULL_PARAMETER_OR_THROW_FACTS
-            : nonNullParamOrThrow.get(1, nonNullParamOrThrow.length());
-    nonNullParamOnNormalExits =
-        nonNullParamOnNormalExits
-                == DefaultMethodOptimizationInfo.NO_NULL_PARAMETER_ON_NORMAL_EXITS_FACTS
-            ? DefaultMethodOptimizationInfo.NO_NULL_PARAMETER_ON_NORMAL_EXITS_FACTS
-            : nonNullParamOnNormalExits.get(1, nonNullParamOnNormalExits.length());
-    // reachabilitySensitive: doesn't depend on `this`
-    // returnValueHasBeenPropagated: doesn't depend on `this`
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
index bd275db..c9390d7 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
@@ -272,11 +272,6 @@
   }
 
   @Override
-  public synchronized void unsetEnumUnboxerMethodClassification(ProgramMethod method) {
-    getMethodOptimizationInfoForUpdating(method).unsetEnumUnboxerMethodClassification();
-  }
-
-  @Override
   public synchronized void setInstanceInitializerInfoCollection(
       DexEncodedMethod method,
       InstanceInitializerInfoCollection instanceInitializerInfoCollection) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
index 1894532..623d8d2 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
@@ -122,9 +122,6 @@
       ProgramMethod method, EnumUnboxerMethodClassification enumUnboxerMethodClassification) {}
 
   @Override
-  public void unsetEnumUnboxerMethodClassification(ProgramMethod method) {}
-
-  @Override
   public void setInstanceInitializerInfoCollection(
       DexEncodedMethod method,
       InstanceInitializerInfoCollection instanceInitializerInfoCollection) {}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
index 10649fb..47f1b8e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
@@ -194,11 +194,6 @@
   }
 
   @Override
-  public void unsetEnumUnboxerMethodClassification(ProgramMethod method) {
-    method.getDefinition().getMutableOptimizationInfo().unsetEnumUnboxerMethodClassification();
-  }
-
-  @Override
   public void setInstanceInitializerInfoCollection(
       DexEncodedMethod method,
       InstanceInitializerInfoCollection instanceInitializerInfoCollection) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/EmptyInstanceFieldInitializationInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/EmptyInstanceFieldInitializationInfoCollection.java
index 9c7d07c..16a86a4 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/field/EmptyInstanceFieldInitializationInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/EmptyInstanceFieldInitializationInfoCollection.java
@@ -8,6 +8,7 @@
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import java.util.function.BiConsumer;
 
@@ -52,6 +53,12 @@
   }
 
   @Override
+  public InstanceFieldInitializationInfoCollection fixupAfterParametersChanged(
+      ArgumentInfoCollection argumentInfoCollection) {
+    return this;
+  }
+
+  @Override
   public InstanceFieldInitializationInfoCollection rewrittenWithLens(
       AppView<AppInfoWithLiveness> appView, GraphLens lens) {
     return this;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldArgumentInitializationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldArgumentInitializationInfo.java
index 0447d5d..46255f1 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldArgumentInitializationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldArgumentInitializationInfo.java
@@ -6,6 +6,9 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfo;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 /**
@@ -36,6 +39,28 @@
   }
 
   @Override
+  public InstanceFieldInitializationInfo fixupAfterParametersChanged(
+      ArgumentInfoCollection argumentInfoCollection) {
+    ArgumentInfo argumentInfo = argumentInfoCollection.getArgumentInfo(argumentIndex);
+    if (argumentInfo.isRemovedArgumentInfo()) {
+      RemovedArgumentInfo removedArgumentInfo = argumentInfo.asRemovedArgumentInfo();
+      if (!removedArgumentInfo.hasSingleValue()) {
+        // This should only happen if the argument is unused, but here the argument is used to
+        // initialize an instance field on the enclosing class.
+        assert false;
+        return UnknownInstanceFieldInitializationInfo.getInstance();
+      }
+      // Now the constant is used to initialize the field instead of the argument.
+      return removedArgumentInfo.getSingleValue();
+    }
+
+    int newArgumentIndex = argumentInfoCollection.getNewArgumentIndex(argumentIndex);
+    return newArgumentIndex != argumentIndex
+        ? new InstanceFieldArgumentInitializationInfo(newArgumentIndex)
+        : this;
+  }
+
+  @Override
   public InstanceFieldInitializationInfo rewrittenWithLens(
       AppView<AppInfoWithLiveness> appView, GraphLens lens) {
     // We don't have the context here to determine what should happen. It is the responsibility of
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfo.java
index aa3ab9b..94e5ea5 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfo.java
@@ -6,6 +6,7 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.ir.analysis.value.SingleValue;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
@@ -46,6 +47,9 @@
     return false;
   }
 
+  InstanceFieldInitializationInfo fixupAfterParametersChanged(
+      ArgumentInfoCollection argumentInfoCollection);
+
   InstanceFieldInitializationInfo rewrittenWithLens(
       AppView<AppInfoWithLiveness> appView, GraphLens lens);
 }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfoCollection.java
index aca1f76..ef40285 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfoCollection.java
@@ -9,6 +9,7 @@
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import java.util.TreeMap;
 import java.util.function.BiConsumer;
@@ -38,6 +39,9 @@
 
   public abstract boolean isEmpty();
 
+  public abstract InstanceFieldInitializationInfoCollection fixupAfterParametersChanged(
+      ArgumentInfoCollection argumentInfoCollection);
+
   public abstract InstanceFieldInitializationInfoCollection rewrittenWithLens(
       AppView<AppInfoWithLiveness> appView, GraphLens lens);
 
@@ -52,7 +56,9 @@
 
     public Builder recordInitializationInfo(DexField field, InstanceFieldInitializationInfo info) {
       assert !infos.containsKey(field);
-      infos.put(field, info);
+      if (!info.isUnknown()) {
+        infos.put(field, info);
+      }
       return this;
     }
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldTypeInitializationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldTypeInitializationInfo.java
index 708c84a..39a72ba 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldTypeInitializationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldTypeInitializationInfo.java
@@ -6,6 +6,7 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.optimize.enums.EnumDataMap;
@@ -47,6 +48,12 @@
   }
 
   @Override
+  public InstanceFieldInitializationInfo fixupAfterParametersChanged(
+      ArgumentInfoCollection argumentInfoCollection) {
+    return this;
+  }
+
+  @Override
   public InstanceFieldInitializationInfo rewrittenWithLens(
       AppView<AppInfoWithLiveness> appView, GraphLens lens) {
     EnumDataMap enumDataMap = appView.unboxedEnums();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/NonTrivialInstanceFieldInitializationInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/NonTrivialInstanceFieldInitializationInfoCollection.java
index 2081721..2e34bcd 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/field/NonTrivialInstanceFieldInitializationInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/NonTrivialInstanceFieldInitializationInfoCollection.java
@@ -11,6 +11,7 @@
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.StringUtils;
 import java.util.ArrayList;
@@ -67,17 +68,24 @@
   }
 
   @Override
+  public InstanceFieldInitializationInfoCollection fixupAfterParametersChanged(
+      ArgumentInfoCollection argumentInfoCollection) {
+    Builder builder = InstanceFieldInitializationInfoCollection.builder();
+    infos.forEach(
+        (field, info) ->
+            builder.recordInitializationInfo(
+                field, info.fixupAfterParametersChanged(argumentInfoCollection)));
+    return builder.build();
+  }
+
+  @Override
   public InstanceFieldInitializationInfoCollection rewrittenWithLens(
       AppView<AppInfoWithLiveness> appView, GraphLens lens) {
     Builder builder = InstanceFieldInitializationInfoCollection.builder();
     infos.forEach(
-        (field, info) -> {
-          DexField rewrittenField = lens.lookupField(field);
-          InstanceFieldInitializationInfo rewrittenInfo = info.rewrittenWithLens(appView, lens);
-          if (!rewrittenInfo.isUnknown()) {
-            builder.recordInitializationInfo(rewrittenField, rewrittenInfo);
-          }
-        });
+        (field, info) ->
+            builder.recordInitializationInfo(
+                lens.lookupField(field), info.rewrittenWithLens(appView, lens)));
     return builder.build();
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/UnknownInstanceFieldInitializationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/UnknownInstanceFieldInitializationInfo.java
index 13d4944..f0353a4 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/field/UnknownInstanceFieldInitializationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/UnknownInstanceFieldInitializationInfo.java
@@ -6,6 +6,7 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 /**
@@ -29,6 +30,12 @@
   }
 
   @Override
+  public InstanceFieldInitializationInfo fixupAfterParametersChanged(
+      ArgumentInfoCollection argumentInfoCollection) {
+    return this;
+  }
+
+  @Override
   public InstanceFieldInitializationInfo rewrittenWithLens(
       AppView<AppInfoWithLiveness> appView, GraphLens lens) {
     return this;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/ContextInsensitiveInstanceInitializerInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/ContextInsensitiveInstanceInitializerInfoCollection.java
index 537bda3..1feccf6 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/ContextInsensitiveInstanceInitializerInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/ContextInsensitiveInstanceInitializerInfoCollection.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.ir.code.InvokeDirect;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
@@ -35,6 +36,17 @@
   }
 
   @Override
+  public InstanceInitializerInfoCollection fixupAfterParametersChanged(
+      AppView<AppInfoWithLiveness> appView, ArgumentInfoCollection argumentInfoCollection) {
+    NonTrivialInstanceInitializerInfo rewrittenInfo =
+        info.fixupAfterParametersChanged(appView, argumentInfoCollection);
+    if (rewrittenInfo != info) {
+      return new ContextInsensitiveInstanceInitializerInfoCollection(rewrittenInfo);
+    }
+    return this;
+  }
+
+  @Override
   public ContextInsensitiveInstanceInitializerInfoCollection rewrittenWithLens(
       AppView<AppInfoWithLiveness> appView, GraphLens lens, PrunedItems prunedItems) {
     NonTrivialInstanceInitializerInfo rewrittenInfo =
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/ContextSensitiveInstanceInitializerInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/ContextSensitiveInstanceInitializerInfoCollection.java
index acaeef9..f281892 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/ContextSensitiveInstanceInitializerInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/ContextSensitiveInstanceInitializerInfoCollection.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.ir.code.InvokeDirect;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.google.common.collect.ImmutableMap;
@@ -49,6 +50,17 @@
   }
 
   @Override
+  public InstanceInitializerInfoCollection fixupAfterParametersChanged(
+      AppView<AppInfoWithLiveness> appView, ArgumentInfoCollection argumentInfoCollection) {
+    Builder builder = builder();
+    infos.forEach(
+        (context, info) ->
+            builder.put(
+                context, info.fixupAfterParametersChanged(appView, argumentInfoCollection)));
+    return builder.build();
+  }
+
+  @Override
   public InstanceInitializerInfoCollection rewrittenWithLens(
       AppView<AppInfoWithLiveness> appView, GraphLens lens, PrunedItems prunedItems) {
     Builder builder = builder();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/DefaultInstanceInitializerInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/DefaultInstanceInitializerInfo.java
index 8391de8..678489b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/DefaultInstanceInitializerInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/DefaultInstanceInitializerInfo.java
@@ -8,6 +8,7 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.ir.analysis.fieldvalueanalysis.AbstractFieldSet;
 import com.android.tools.r8.ir.analysis.fieldvalueanalysis.UnknownFieldSet;
 import com.android.tools.r8.ir.optimize.info.field.EmptyInstanceFieldInitializationInfoCollection;
@@ -66,6 +67,12 @@
   }
 
   @Override
+  public InstanceInitializerInfo fixupAfterParametersChanged(
+      AppView<AppInfoWithLiveness> appView, ArgumentInfoCollection argumentInfoCollection) {
+    return this;
+  }
+
+  @Override
   public InstanceInitializerInfo rewrittenWithLens(
       AppView<AppInfoWithLiveness> appView, GraphLens lens, PrunedItems prunedItems) {
     return this;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/EmptyInstanceInitializerInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/EmptyInstanceInitializerInfoCollection.java
index 7100e35..c3742a5 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/EmptyInstanceInitializerInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/EmptyInstanceInitializerInfoCollection.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.ir.code.InvokeDirect;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
@@ -37,6 +38,12 @@
   }
 
   @Override
+  public InstanceInitializerInfoCollection fixupAfterParametersChanged(
+      AppView<AppInfoWithLiveness> appView, ArgumentInfoCollection argumentInfoCollection) {
+    return this;
+  }
+
+  @Override
   public EmptyInstanceInitializerInfoCollection rewrittenWithLens(
       AppView<AppInfoWithLiveness> appView, GraphLens lens, PrunedItems prunedItems) {
     return this;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/InstanceInitializerInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/InstanceInitializerInfo.java
index edd78e5..e89b738 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/InstanceInitializerInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/InstanceInitializerInfo.java
@@ -8,6 +8,7 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.ir.analysis.fieldvalueanalysis.AbstractFieldSet;
 import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoCollection;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -71,6 +72,9 @@
     return !receiverNeverEscapesOutsideConstructorChain();
   }
 
+  public abstract InstanceInitializerInfo fixupAfterParametersChanged(
+      AppView<AppInfoWithLiveness> appView, ArgumentInfoCollection argumentInfoCollection);
+
   public abstract InstanceInitializerInfo rewrittenWithLens(
       AppView<AppInfoWithLiveness> appView, GraphLens lens, PrunedItems prunedItems);
 }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/InstanceInitializerInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/InstanceInitializerInfoCollection.java
index 0139cf0..f228922 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/InstanceInitializerInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/InstanceInitializerInfoCollection.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.ir.code.InvokeDirect;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.MapUtils;
@@ -36,6 +37,9 @@
 
   public abstract boolean isEmpty();
 
+  public abstract InstanceInitializerInfoCollection fixupAfterParametersChanged(
+      AppView<AppInfoWithLiveness> appView, ArgumentInfoCollection argumentInfoCollection);
+
   public abstract InstanceInitializerInfoCollection rewrittenWithLens(
       AppView<AppInfoWithLiveness> appView, GraphLens lens, PrunedItems prunedItems);
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/NonTrivialInstanceInitializerInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/NonTrivialInstanceInitializerInfo.java
index 7066531..99cb83b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/NonTrivialInstanceInitializerInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/NonTrivialInstanceInitializerInfo.java
@@ -9,6 +9,7 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.ir.analysis.fieldvalueanalysis.AbstractFieldSet;
 import com.android.tools.r8.ir.analysis.fieldvalueanalysis.ConcreteMutableFieldSet;
 import com.android.tools.r8.ir.analysis.fieldvalueanalysis.EmptyFieldSet;
@@ -99,6 +100,16 @@
   }
 
   @Override
+  public NonTrivialInstanceInitializerInfo fixupAfterParametersChanged(
+      AppView<AppInfoWithLiveness> appView, ArgumentInfoCollection argumentInfoCollection) {
+    return new NonTrivialInstanceInitializerInfo(
+        data,
+        fieldInitializationInfos.fixupAfterParametersChanged(argumentInfoCollection),
+        readSet.fixupReadSetAfterParametersChanged(appView, argumentInfoCollection),
+        parent);
+  }
+
+  @Override
   public NonTrivialInstanceInitializerInfo rewrittenWithLens(
       AppView<AppInfoWithLiveness> appView, GraphLens lens, PrunedItems prunedItems) {
     return new NonTrivialInstanceInitializerInfo(
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 b3e2027..ff551ca 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,11 +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.ProgramMethod;
 import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
-import com.android.tools.r8.ir.optimize.enums.classification.EnumUnboxerMethodClassification;
-import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
-import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.ThreadUtils;
 import java.util.Set;
@@ -64,30 +60,12 @@
           return method.toTypeSubstitutedMethod(
               methodReferenceAfterParameterRemoval,
               builder -> {
-                // TODO(b/190154391): fixup parameter annotations, if any.
                 ArgumentInfoCollection removedParameters =
                     graphLens.getRemovedParameters(methodReferenceAfterParameterRemoval);
                 builder
-                    .fixupCallSiteOptimizationInfo(
-                        removedParameters.createCallSiteOptimizationInfoFixer())
-                    .modifyOptimizationInfo(
-                        (newMethod, optimizationInfo) -> {
-                          OptimizationFeedback feedback = OptimizationFeedbackSimple.getInstance();
-                          ProgramMethod programMethod = new ProgramMethod(clazz, newMethod);
-                          // TODO(b/190154391): test this.
-                          EnumUnboxerMethodClassification rewrittenEnumUnboxerMethodClassification =
-                              optimizationInfo
-                                  .getEnumUnboxerMethodClassification()
-                                  .fixupAfterParameterRemoval(removedParameters);
-                          if (rewrittenEnumUnboxerMethodClassification
-                              .isCheckNotNullClassification()) {
-                            feedback.setEnumUnboxerMethodClassification(
-                                programMethod, rewrittenEnumUnboxerMethodClassification);
-                          } else {
-                            // Bypass monotonicity check.
-                            feedback.unsetEnumUnboxerMethodClassification(programMethod);
-                          }
-                        });
+                    .apply(removedParameters.createParameterAnnotationsRemover(method))
+                    .fixupOptimizationInfo(
+                        appView, removedParameters.createMethodOptimizationInfoFixer());
               });
         });
   }