Merge commit 'a8cb578796218b723389a026531566e3519aba5e' into dev-release
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index 46cc30f..7f17170 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -256,12 +256,9 @@
 
       InspectorImpl.runInspections(options.outputInspections, appView.appInfo().classes());
       NamingLens namingLens = NamingLens.getIdentityLens();
-      if (appView.rewritePrefix.isRewriting()) {
-        namingLens = PrefixRewritingNamingLens.createPrefixRewritingNamingLens(appView, namingLens);
-      }
-      if (appView.options().shouldDesugarRecords()) {
-        namingLens = RecordRewritingNamingLens.createRecordRewritingNamingLens(appView, namingLens);
-      }
+      namingLens = PrefixRewritingNamingLens.createPrefixRewritingNamingLens(appView, namingLens);
+      namingLens = RecordRewritingNamingLens.createRecordRewritingNamingLens(appView, namingLens);
+
       if (options.isGeneratingClassFiles()) {
         ProguardMapSupplier proguardMapSupplier =
             finalizeApplication(inputApp, appView, namingLens);
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index d3c617c..02ef891 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -71,6 +71,7 @@
 import com.android.tools.r8.naming.PrefixRewritingNamingLens;
 import com.android.tools.r8.naming.ProguardMapMinifier;
 import com.android.tools.r8.naming.ProguardMapSupplier;
+import com.android.tools.r8.naming.RecordRewritingNamingLens;
 import com.android.tools.r8.naming.SeedMapper;
 import com.android.tools.r8.naming.SourceFileRewriter;
 import com.android.tools.r8.naming.signature.GenericSignatureRewriter;
@@ -842,15 +843,14 @@
         options.syntheticProguardRulesConsumer.accept(synthesizedProguardRules);
       }
 
-      NamingLens prefixRewritingNamingLens =
-          PrefixRewritingNamingLens.createPrefixRewritingNamingLens(appView, namingLens);
+      namingLens = PrefixRewritingNamingLens.createPrefixRewritingNamingLens(appView, namingLens);
+      namingLens = RecordRewritingNamingLens.createRecordRewritingNamingLens(appView, namingLens);
 
       timing.begin("MinifyKotlinMetadata");
-      new KotlinMetadataRewriter(appView, prefixRewritingNamingLens).runForR8(executorService);
+      new KotlinMetadataRewriter(appView, namingLens).runForR8(executorService);
       timing.end();
 
-      new GenericSignatureRewriter(
-              appView, prefixRewritingNamingLens, genericContextBuilderBeforeFinalMerging)
+      new GenericSignatureRewriter(appView, namingLens, genericContextBuilderBeforeFinalMerging)
           .run(appView.appInfo().classes(), executorService);
 
       assert appView.checkForTesting(
@@ -862,8 +862,7 @@
                           .isValid())
           : "Could not validate generic signatures";
 
-      new DesugaredLibraryKeepRuleGenerator(appView, prefixRewritingNamingLens)
-          .runIfNecessary(timing);
+      new DesugaredLibraryKeepRuleGenerator(appView, namingLens).runIfNecessary(timing);
 
       // Generate the resulting application resources.
       writeApplication(
@@ -871,7 +870,7 @@
           appView,
           appView.graphLens(),
           appView.initClassLens(),
-          prefixRewritingNamingLens,
+          namingLens,
           options,
           ProguardMapSupplier.create(classNameMapper, options));
 
diff --git a/src/main/java/com/android/tools/r8/graph/ApplicationReaderMap.java b/src/main/java/com/android/tools/r8/graph/ApplicationReaderMap.java
index 82b9d7f..5ce8224 100644
--- a/src/main/java/com/android/tools/r8/graph/ApplicationReaderMap.java
+++ b/src/main/java/com/android/tools/r8/graph/ApplicationReaderMap.java
@@ -12,7 +12,7 @@
 
   public static Map<String, String> getDescriptorMap(InternalOptions options) {
     ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
-    if (options.shouldDesugarRecords()) {
+    if (options.shouldDesugarRecords() && !options.testing.disableRecordApplicationReaderMap) {
       builder.put(DexItemFactory.recordTagDescriptorString, DexItemFactory.recordDescriptorString);
     }
     return builder.build();
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/JarClassFileReader.java b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
index b9563fa..4c6c165 100644
--- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -515,10 +515,6 @@
       if (!accessFlags.isRecord()) {
         return;
       }
-      // TODO(b/169645628): Support records in all compilation.
-      if (!application.options.enableExperimentalRecordDesugaring()) {
-        throw new CompilationError("Records are not supported", origin);
-      }
       // TODO(b/169645628): Change this logic if we start stripping the record components.
       // Another approach would be to mark a bit in fields that are record components instead.
       String message = "Records are expected to have one record component per instance field.";
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..1133b65 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 {
 
@@ -201,6 +200,12 @@
       assert newType == rewrittenTypeInfo.oldType;
       return new RewrittenTypeInfo(oldType, rewrittenTypeInfo.newType);
     }
+
+    public boolean verifyIsDueToUnboxing(DexItemFactory dexItemFactory) {
+      assert oldType.toBaseType(dexItemFactory).isClassType();
+      assert newType.toBaseType(dexItemFactory).isIntType();
+      return true;
+    }
   }
 
   public static class ArgumentInfoCollection {
@@ -224,6 +229,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 +258,10 @@
       return removedParameterIndices;
     }
 
+    public boolean isArgumentRemoved(int argumentIndex) {
+      return getArgumentInfo(argumentIndex).isRemovedArgumentInfo();
+    }
+
     public boolean isEmpty() {
       return this == EMPTY;
     }
@@ -274,6 +289,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 +309,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 +412,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 +507,10 @@
     return NONE;
   }
 
+  public MethodOptimizationInfoFixer createMethodOptimizationInfoFixer() {
+    return new RewrittenPrototypeDescriptionMethodOptimizationInfoFixer(this);
+  }
+
   public RewrittenPrototypeDescription combine(RewrittenPrototypeDescription other) {
     if (isEmpty()) {
       return other;
@@ -514,6 +542,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..265d050
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescriptionMethodOptimizationInfoFixer.java
@@ -0,0 +1,170 @@
+// 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(
+      AppView<AppInfoWithLiveness> appView,
+      ClassInlinerMethodConstraint classInlinerMethodConstraint) {
+    if (getArgumentInfoCollection().isEmpty()) {
+      return classInlinerMethodConstraint;
+    }
+    return classInlinerMethodConstraint.fixupAfterParametersChanged(
+        appView, 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(
+      AppView<AppInfoWithLiveness> appView,
+      SimpleInliningConstraint constraint,
+      SimpleInliningConstraintFactory factory) {
+    if (getArgumentInfoCollection().isEmpty()) {
+      return constraint;
+    }
+    return constraint.fixupAfterParametersChanged(appView, 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..9180568 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,10 @@
 
 package com.android.tools.r8.ir.analysis.inlining;
 
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.ir.code.InvokeMethod;
-import it.unimi.dsi.fastutil.ints.IntList;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 /** Constraint that is always satisfied. */
 public class AlwaysSimpleInliningConstraint extends SimpleInliningConstraint {
@@ -30,14 +32,10 @@
   }
 
   @Override
-  public SimpleInliningConstraint fixupAfterRemovingThisParameter(
+  public SimpleInliningConstraint fixupAfterParametersChanged(
+      AppView<AppInfoWithLiveness> appView,
+      ArgumentInfoCollection changes,
       SimpleInliningConstraintFactory factory) {
     return this;
   }
-
-  @Override
-  public SimpleInliningConstraint rewrittenWithUnboxedArguments(
-      IntList unboxedArgumentIndices, 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..9a400ae 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,14 @@
 
 package com.android.tools.r8.ir.analysis.inlining;
 
+import com.android.tools.r8.graph.AppView;
+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;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 /** Constraint that is satisfied if a specific argument is always true. */
 public class EqualToBooleanSimpleInliningConstraint extends SimpleInliningArgumentConstraint {
@@ -26,6 +30,30 @@
   }
 
   @Override
+  public SimpleInliningConstraint fixupAfterParametersChanged(
+      AppView<AppInfoWithLiveness> appView,
+      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 +61,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..d786e67 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,10 @@
 
 package com.android.tools.r8.ir.analysis.inlining;
 
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.ir.code.InvokeMethod;
-import it.unimi.dsi.fastutil.ints.IntList;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 /** Constraint that is never satisfied. */
 public class NeverSimpleInliningConstraint extends SimpleInliningConstraint {
@@ -29,14 +31,10 @@
   }
 
   @Override
-  public SimpleInliningConstraint fixupAfterRemovingThisParameter(
+  public SimpleInliningConstraint fixupAfterParametersChanged(
+      AppView<AppInfoWithLiveness> appView,
+      ArgumentInfoCollection changes,
       SimpleInliningConstraintFactory factory) {
     return this;
   }
-
-  @Override
-  public SimpleInliningConstraint rewrittenWithUnboxedArguments(
-      IntList unboxedArgumentIndices, 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..bb4f505 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,17 @@
 
 package com.android.tools.r8.ir.analysis.inlining;
 
+import com.android.tools.r8.graph.AppView;
+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;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 /** Constraint that is satisfied if a specific argument is always null. */
 public class NullSimpleInliningConstraint extends SimpleInliningArgumentConstraint {
@@ -29,6 +34,35 @@
   }
 
   @Override
+  public SimpleInliningConstraint fixupAfterParametersChanged(
+      AppView<AppInfoWithLiveness> appView,
+      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.verifyIsDueToUnboxing(appView.dexItemFactory());
+      // 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 +81,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..23b6233 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,14 @@
 
 package com.android.tools.r8.ir.analysis.inlining;
 
+import com.android.tools.r8.graph.AppView;
+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;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 public abstract class NumberSimpleInliningConstraint extends SimpleInliningArgumentConstraint {
 
@@ -23,6 +27,29 @@
   }
 
   @Override
+  public SimpleInliningConstraint fixupAfterParametersChanged(
+      AppView<AppInfoWithLiveness> appView,
+      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 +57,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..64e6f44 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,11 @@
 
 package com.android.tools.r8.ir.analysis.inlining;
 
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.ir.code.InvokeMethod;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.google.common.collect.ImmutableList;
-import it.unimi.dsi.fastutil.ints.IntList;
 import java.util.function.Supplier;
 
 public abstract class SimpleInliningConstraint {
@@ -90,9 +92,8 @@
     return new SimpleInliningConstraintDisjunction(ImmutableList.of(this, other));
   }
 
-  public abstract SimpleInliningConstraint fixupAfterRemovingThisParameter(
+  public abstract SimpleInliningConstraint fixupAfterParametersChanged(
+      AppView<AppInfoWithLiveness> appView,
+      ArgumentInfoCollection changes,
       SimpleInliningConstraintFactory factory);
-
-  public abstract SimpleInliningConstraint rewrittenWithUnboxedArguments(
-      IntList unboxedArgumentIndices, 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..55da1c0 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,13 @@
 
 package com.android.tools.r8.ir.analysis.inlining;
 
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.ir.code.InvokeMethod;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
 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 +69,40 @@
   }
 
   @Override
-  public SimpleInliningConstraint fixupAfterRemovingThisParameter(
+  public SimpleInliningConstraint fixupAfterParametersChanged(
+      AppView<AppInfoWithLiveness> appView,
+      ArgumentInfoCollection changes,
       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) {
-    List<SimpleInliningConstraint> rewrittenConstraints =
-        ListUtils.mapOrElse(
             constraints,
-            constraint -> constraint.rewrittenWithUnboxedArguments(unboxedArgumentIndices, factory),
+            constraint -> {
+              SimpleInliningConstraint rewrittenConstraint =
+                  constraint.fixupAfterParametersChanged(appView, 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..0ac0ced 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,13 @@
 
 package com.android.tools.r8.ir.analysis.inlining;
 
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
 import com.android.tools.r8.ir.code.InvokeMethod;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
 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 +69,40 @@
   }
 
   @Override
-  public SimpleInliningConstraint fixupAfterRemovingThisParameter(
+  public SimpleInliningConstraint fixupAfterParametersChanged(
+      AppView<AppInfoWithLiveness> appView,
+      ArgumentInfoCollection changes,
       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) {
-    List<SimpleInliningConstraint> rewrittenConstraints =
-        ListUtils.mapOrElse(
             constraints,
-            constraint -> constraint.rewrittenWithUnboxedArguments(unboxedArgumentIndices, factory),
+            constraint -> {
+              SimpleInliningConstraint rewrittenConstraint =
+                  constraint.fixupAfterParametersChanged(appView, 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/code/Value.java b/src/main/java/com/android/tools/r8/ir/code/Value.java
index 0c58032..7b97131 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Value.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Value.java
@@ -832,6 +832,10 @@
       return UnknownValue.getInstance();
     }
 
+    if (getType().nullability().isDefinitelyNull()) {
+      return appView.abstractValueFactory().createNullValue();
+    }
+
     Value root = getAliasedValue();
     if (root.isPhi()) {
       return UnknownValue.getInstance();
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java b/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java
index 1e5a344..2be47ca 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java
@@ -144,10 +144,11 @@
         // We don't care about calls to native methods.
         return;
       }
-      if (appView.appInfo().isPinned(callee.getReference())) {
-        // Since the callee is kept, we cannot inline it into the caller, and we also cannot collect
-        // any optimization info for the method. Therefore, we drop the call edge to reduce the
-        // total number of call graph edges, which should lead to fewer call graph cycles.
+      if (!appView.getKeepInfo(callee).isInliningAllowed(appView.options())) {
+        // Since the callee is kept and optimizations are disallowed, we cannot inline it into the
+        // caller, and we also cannot collect any optimization info for the method. Therefore, we
+        // drop the call edge to reduce the total number of call graph edges, which should lead to
+        // fewer call graph cycles.
         return;
       }
       getOrCreateNode(callee).addCallerConcurrently(currentMethod, likelySpuriousCallEdge);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 0235660..5bde78e 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -1288,6 +1288,7 @@
           .libraryMethodOptimizer()
           .optimize(code, feedback, methodProcessor, methodProcessingContext);
       timing.end();
+      previous = printMethod(code, "IR after class library method optimizer (SSA)", previous);
       assert code.isConsistentSSA();
     }
 
@@ -1298,6 +1299,7 @@
       timing.begin("Devirtualize invoke interface");
       devirtualizer.devirtualizeInvokeInterface(code);
       timing.end();
+      previous = printMethod(code, "IR after devirtualizer (SSA)", previous);
     }
 
     assert code.verifyTypes(appView);
@@ -1374,12 +1376,14 @@
       timing.begin("Rewrite throw NPE");
       codeRewriter.rewriteThrowNullPointerException(code);
       timing.end();
+      previous = printMethod(code, "IR after rewrite throw null (SSA)", previous);
     }
 
     timing.begin("Optimize class initializers");
     ClassInitializerDefaultsResult classInitializerDefaultsResult =
         classInitializerDefaultsOptimization.optimize(code, feedback);
     timing.end();
+    previous = printMethod(code, "IR after class initializer optimisation (SSA)", previous);
 
     if (Log.ENABLED) {
       Log.debug(getClass(), "Intermediate (SSA) flow graph for %s:\n%s",
@@ -1391,7 +1395,7 @@
     deadCodeRemover.run(code, timing);
     assert code.isConsistentSSA();
 
-    previous = printMethod(code, "IR after lambda desugaring (SSA)", previous);
+    previous = printMethod(code, "IR after dead code removal (SSA)", previous);
 
     assert code.verifyTypes(appView);
 
@@ -1572,7 +1576,7 @@
       timing.end();
     }
 
-    if (appView.getKeepInfo().getMethodInfo(code.context()).isPinned(options)) {
+    if (appView.getKeepInfo(code.context()).isPinned(options)) {
       return;
     }
 
@@ -1694,8 +1698,7 @@
         || definition.getOptimizationInfo().isReachabilitySensitive()) {
       return false;
     }
-    if (appView.appInfo().hasLiveness()
-        && appView.appInfo().withLiveness().isPinned(method.getReference())) {
+    if (!appView.getKeepInfo(method).isInliningAllowed(options)) {
       return false;
     }
     return true;
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/desugar/itf/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
index c4c281d..9ee3f54 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
@@ -315,9 +315,11 @@
     // If the target holder does not resolve we may want to issue diagnostics.
     DexClass holder = appView.definitionForHolder(invoke.getMethod(), context);
     if (holder == null) {
-      // NOTE: leave unchanged those calls to undefined targets. This may lead to runtime
-      // exception but we can not report it as error since it can also be the intended
-      // behavior.
+      if (invoke.isInvokeVirtual() || invoke.isInvokeInterface()) {
+        // For virtual targets we should not report anything as any virtual dispatch just remains.
+        return DesugarDescription.nothing();
+      }
+      // For static, private and special invokes, they may require desugaring and should warn.
       return DesugarDescription.builder()
           .addScanEffect(
               () -> {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index 0ddc915..7bf0e38 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -118,7 +118,7 @@
       WhyAreYouNotInliningReporter whyAreYouNotInliningReporter) {
     AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod singleTargetReference = singleTarget.getReference();
-    if (appInfo.isPinned(singleTargetReference)) {
+    if (!appView.getKeepInfo(singleTarget).isInliningAllowed(appView.options())) {
       whyAreYouNotInliningReporter.reportPinned();
       return true;
     }
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..0ceb39e 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,8 @@
   }
 
   @Override
-  public ClassInlinerMethodConstraint fixupAfterRemovingThisParameter() {
+  public ClassInlinerMethodConstraint fixupAfterParametersChanged(
+      AppView<AppInfoWithLiveness> appView, 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..4b8a513 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,8 @@
   }
 
   @Override
-  public ClassInlinerMethodConstraint fixupAfterRemovingThisParameter() {
+  public ClassInlinerMethodConstraint fixupAfterParametersChanged(
+      AppView<AppInfoWithLiveness> appView, 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..ebe34b8 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,15 @@
 
 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(
+      AppView<AppInfoWithLiveness> appView, 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..09a482d 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,8 @@
   }
 
   @Override
-  public ClassInlinerMethodConstraint fixupAfterRemovingThisParameter() {
+  public ClassInlinerMethodConstraint fixupAfterParametersChanged(
+      AppView<AppInfoWithLiveness> appView, ArgumentInfoCollection changes) {
     if (usages.isBottom()) {
       return this;
     }
@@ -40,10 +44,21 @@
     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.verifyIsDueToUnboxing(appView.dexItemFactory());
+                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..58c0f9b
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoFixer.java
@@ -0,0 +1,46 @@
+// 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(
+      AppView<AppInfoWithLiveness> appView,
+      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(
+      AppView<AppInfoWithLiveness> appView,
+      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..c4a08f4 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
@@ -156,6 +156,18 @@
     enumUnboxerMethodClassification = template.enumUnboxerMethodClassification;
   }
 
+  public MutableMethodOptimizationInfo fixup(
+      AppView<AppInfoWithLiveness> appView, MethodOptimizationInfoFixer fixer) {
+    return fixupBridgeInfo(fixer)
+        .fixupClassInlinerMethodConstraint(appView, fixer)
+        .fixupEnumUnboxerMethodClassification(fixer)
+        .fixupInstanceInitializerInfo(appView, fixer)
+        .fixupNonNullParamOnNormalExits(fixer)
+        .fixupNonNullParamOrThrow(fixer)
+        .fixupReturnedArgumentIndex(fixer)
+        .fixupSimpleInliningConstraint(appView, fixer);
+  }
+
   public MutableMethodOptimizationInfo fixupClassTypeReferences(
       AppView<? extends AppInfoWithClassHierarchy> appView, GraphLens lens) {
     return fixupClassTypeReferences(appView, lens, emptySet());
@@ -240,6 +252,13 @@
     return classInlinerConstraint;
   }
 
+  public MutableMethodOptimizationInfo fixupClassInlinerMethodConstraint(
+      AppView<AppInfoWithLiveness> appView, MethodOptimizationInfoFixer fixer) {
+    classInlinerConstraint =
+        fixer.fixupClassInlinerMethodConstraint(appView, 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,14 @@
     this.simpleInliningConstraint = constraint;
   }
 
+  public MutableMethodOptimizationInfo fixupSimpleInliningConstraint(
+      AppView<AppInfoWithLiveness> appView, MethodOptimizationInfoFixer fixer) {
+    simpleInliningConstraint =
+        fixer.fixupSimpleInliningConstraint(
+            appView, simpleInliningConstraint, appView.simpleInliningConstraintFactory());
+    return this;
+  }
+
   void setInstanceInitializerInfoCollection(
       InstanceInitializerInfoCollection instanceInitializerInfoCollection) {
     this.instanceInitializerInfoCollection = instanceInitializerInfoCollection;
@@ -437,10 +493,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 +612,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/ir/optimize/string/StringOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java
index 48f2199..1d0e301 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java
@@ -143,7 +143,10 @@
         continue;
       }
       DexMethod invokedMethod = invoke.getInvokedMethod();
-      if (invokedMethod.name == factory.substringName) {
+      if (invokedMethod.getHolderType() != factory.stringType) {
+        continue;
+      }
+      if (invokedMethod.getName() == factory.substringName) {
         assert invoke.inValues().size() == 2 || invoke.inValues().size() == 3;
         Value rcv = invoke.getReceiver().getAliasedValue();
         if (rcv.definition == null
diff --git a/src/main/java/com/android/tools/r8/kotlin/Kotlin.java b/src/main/java/com/android/tools/r8/kotlin/Kotlin.java
index 2bbd2b3..9470367 100644
--- a/src/main/java/com/android/tools/r8/kotlin/Kotlin.java
+++ b/src/main/java/com/android/tools/r8/kotlin/Kotlin.java
@@ -9,8 +9,10 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
+import com.google.common.collect.ImmutableSet;
 import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;
 import it.unimi.dsi.fastutil.objects.Object2IntMap;
+import java.util.Set;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
@@ -33,8 +35,59 @@
   public static final class ClassClassifiers {
 
     public static final String arrayBinaryName = NAME + "/Array";
+    public static final String arrayDescriptor = PACKAGE_PREFIX + "Array;";
     public static final String anyDescriptor = PACKAGE_PREFIX + "Any;";
+    public static final String unitDescriptor = PACKAGE_PREFIX + "Unit;";
+    public static final String booleanDescriptor = PACKAGE_PREFIX + "Boolean";
+    public static final String charDescriptor = PACKAGE_PREFIX + "Char";
+    public static final String byteDescriptor = PACKAGE_PREFIX + "Byte";
+    public static final String uByteDescriptor = PACKAGE_PREFIX + "UByte";
+    public static final String shortDescriptor = PACKAGE_PREFIX + "Short;";
+    public static final String uShortDescriptor = PACKAGE_PREFIX + "UShort;";
+    public static final String intDescriptor = PACKAGE_PREFIX + "Int;";
+    public static final String uIntDescriptor = PACKAGE_PREFIX + "UInt;";
+    public static final String floatDescriptor = PACKAGE_PREFIX + "Float;";
+    public static final String longDescriptor = PACKAGE_PREFIX + "Long;";
+    public static final String uLongDescriptor = PACKAGE_PREFIX + "ULong;";
+    public static final String doubleDescriptor = PACKAGE_PREFIX + "Double;";
+    public static final String functionDescriptor = PACKAGE_PREFIX + "Function;";
+    public static final String kFunctionDescriptor = PACKAGE_PREFIX + "KFunction;";
     public static final String anyName = NAME + "/Any";
+
+    public static final Set<String> kotlinPrimitivesDescriptors =
+        ImmutableSet.<String>builder()
+            .add(booleanDescriptor)
+            .add(charDescriptor)
+            .add(byteDescriptor)
+            .add(uByteDescriptor)
+            .add(shortDescriptor)
+            .add(uShortDescriptor)
+            .add(intDescriptor)
+            .add(uIntDescriptor)
+            .add(floatDescriptor)
+            .add(longDescriptor)
+            .add(uLongDescriptor)
+            .add(doubleDescriptor)
+            .build();
+
+    // Kotlin static known types is a possible not complete collection of descriptors that kotlinc
+    // and kotlin reflect know and expect the existence of.
+    public static final Set<String> kotlinStaticallyKnownTypes;
+
+    static {
+      ImmutableSet.Builder<String> builder = ImmutableSet.builder();
+      kotlinPrimitivesDescriptors.forEach(
+          primitive -> {
+            builder.add(primitive);
+            builder.add(primitive.substring(0, primitive.length() - 1) + "Array;");
+          });
+      builder.add(unitDescriptor);
+      builder.add(anyDescriptor);
+      builder.add(arrayDescriptor);
+      builder.add(functionDescriptor);
+      builder.add(kFunctionDescriptor);
+      kotlinStaticallyKnownTypes = builder.build();
+    }
   }
 
   public Kotlin(DexItemFactory factory) {
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
index 8cea528..4fd93a0 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
@@ -11,6 +11,7 @@
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.kotlin.Kotlin.ClassClassifiers;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.DescriptorUtils;
@@ -79,8 +80,16 @@
     }
     DexType rewrittenType = toRewrittenTypeOrNull(appView, known);
     if (rewrittenType == null) {
-      rewrittenConsumer.accept(defaultValue);
-      return true;
+      String knownDescriptor = known.toDescriptorString();
+      // Static known kotlin types can be pruned without rewriting to Any since the types are known
+      // by kotlinc and kotlin reflect.
+      if (ClassClassifiers.kotlinStaticallyKnownTypes.contains(knownDescriptor)) {
+        rewrittenConsumer.accept(knownDescriptor);
+        return false;
+      } else {
+        rewrittenConsumer.accept(defaultValue);
+        return true;
+      }
     }
     String renamedString = namingLens.lookupDescriptor(rewrittenType).toString();
     rewrittenConsumer.accept(renamedString);
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java b/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java
index 1dcd902..6dd1fa3 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java
@@ -8,7 +8,6 @@
 import com.android.tools.r8.naming.MemberNaming.FieldSignature;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
 import com.android.tools.r8.naming.MemberNaming.Signature;
-import com.android.tools.r8.naming.ProguardMap.Builder;
 import com.android.tools.r8.naming.mappinginformation.MapVersionMappingInformation;
 import com.android.tools.r8.naming.mappinginformation.MappingInformation;
 import com.android.tools.r8.naming.mappinginformation.MappingInformationDiagnostics;
@@ -231,11 +230,13 @@
       if (isCommentLineWithJsonBrace()) {
         parseMappingInformation(
             info -> {
-              assert info.isMetaInfMappingInformation();
+              assert info.isMapVersionMappingInformation()
+                  || info.isUnknownJsonMappingInformation();
             });
         // Skip reading the rest of the line.
         lineOffset = line.length();
         nextLine();
+        continue;
       }
       String before = parseType(false);
       skipWhitespace();
@@ -257,7 +258,7 @@
           mapBuilder.classNamingBuilder(after, before, getPosition());
       skipWhitespace();
       if (nextLine()) {
-        parseMemberMappings(mapBuilder, currentClassBuilder);
+        parseMemberMappings(currentClassBuilder);
       }
     }
   }
@@ -269,7 +270,7 @@
         diagnosticsHandler,
         lineNo,
         info -> {
-          MapVersionMappingInformation generatorInfo = info.asMetaInfMappingInformation();
+          MapVersionMappingInformation generatorInfo = info.asMapVersionMappingInformation();
           if (generatorInfo != null) {
             if (generatorInfo.getMapVersion().equals(MapVersion.MAP_VERSION_EXPERIMENTAL)) {
               // A mapping file that is marked "experimental" will be treated as an unversioned
@@ -286,8 +287,7 @@
         });
   }
 
-  private void parseMemberMappings(Builder mapBuilder, ClassNaming.Builder classNamingBuilder)
-      throws IOException {
+  private void parseMemberMappings(ClassNaming.Builder classNamingBuilder) throws IOException {
     MemberNaming lastAddedNaming = null;
     MemberNaming activeMemberNaming = null;
     MappedRange activeMappedRange = null;
diff --git a/src/main/java/com/android/tools/r8/naming/RecordRewritingNamingLens.java b/src/main/java/com/android/tools/r8/naming/RecordRewritingNamingLens.java
index e809317..f48cfc7 100644
--- a/src/main/java/com/android/tools/r8/naming/RecordRewritingNamingLens.java
+++ b/src/main/java/com/android/tools/r8/naming/RecordRewritingNamingLens.java
@@ -21,16 +21,16 @@
   final NamingLens namingLens;
   private final DexItemFactory factory;
 
-  public static NamingLens createRecordRewritingNamingLens(AppView<?> appView) {
-    return createRecordRewritingNamingLens(appView, NamingLens.getIdentityLens());
-  }
-
   public static NamingLens createRecordRewritingNamingLens(
       AppView<?> appView, NamingLens namingLens) {
-    if (!appView.options().shouldDesugarRecords()) {
-      return namingLens;
+    if (appView.options().shouldDesugarRecords()
+        && appView
+                .appInfo()
+                .definitionForWithoutExistenceAssert(appView.dexItemFactory().recordType)
+            != null) {
+      return new RecordRewritingNamingLens(namingLens, appView);
     }
-    return new RecordRewritingNamingLens(namingLens, appView);
+    return namingLens;
   }
 
   public RecordRewritingNamingLens(NamingLens namingLens, AppView<?> appView) {
@@ -83,6 +83,16 @@
   }
 
   @Override
+  public boolean hasPrefixRewritingLogic() {
+    return namingLens.hasPrefixRewritingLogic();
+  }
+
+  @Override
+  public DexString prefixRewrittenType(DexType type) {
+    return namingLens.prefixRewrittenType(type);
+  }
+
+  @Override
   public String lookupPackageName(String packageName) {
     return namingLens.lookupPackageName(packageName);
   }
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/CompilerSynthesizedMappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/CompilerSynthesizedMappingInformation.java
index d26d9a8..7f82be1 100644
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/CompilerSynthesizedMappingInformation.java
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/CompilerSynthesizedMappingInformation.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.naming.mappinginformation;
 
-import com.android.tools.r8.DiagnosticsHandler;
 import com.android.tools.r8.naming.MapVersion;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonPrimitive;
@@ -61,9 +60,6 @@
 
   public static void deserialize(
       MapVersion version,
-      JsonObject object,
-      DiagnosticsHandler diagnosticsHandler,
-      int lineNumber,
       Consumer<MappingInformation> onMappingInfo) {
     if (isSupported(version)) {
       onMappingInfo.accept(builder().build());
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/MapVersionMappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/MapVersionMappingInformation.java
index cd72831..357be56 100644
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/MapVersionMappingInformation.java
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/MapVersionMappingInformation.java
@@ -20,7 +20,6 @@
   private final MapVersion mapVersion;
 
   public MapVersionMappingInformation(MapVersion mapVersion) {
-    super();
     this.mapVersion = mapVersion;
   }
 
@@ -30,12 +29,12 @@
   }
 
   @Override
-  public boolean isMetaInfMappingInformation() {
+  public boolean isMapVersionMappingInformation() {
     return true;
   }
 
   @Override
-  public MapVersionMappingInformation asMetaInfMappingInformation() {
+  public MapVersionMappingInformation asMapVersionMappingInformation() {
     return this;
   }
 
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java
index f8f1e53..13bcfe9 100644
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java
@@ -18,30 +18,38 @@
 
   public abstract String serialize();
 
-  public boolean isMetaInfMappingInformation() {
+  public boolean isMapVersionMappingInformation() {
     return false;
   }
 
-  public MapVersionMappingInformation asMetaInfMappingInformation() {
-    return null;
+  public boolean isUnknownJsonMappingInformation() {
+    return false;
   }
 
   public boolean isFileNameInformation() {
     return false;
   }
 
-  public FileNameInformation asFileNameInformation() {
-    return null;
-  }
-
   public boolean isCompilerSynthesizedMappingInformation() {
     return false;
   }
 
+  public MapVersionMappingInformation asMapVersionMappingInformation() {
+    return null;
+  }
+
+  public FileNameInformation asFileNameInformation() {
+    return null;
+  }
+
   public CompilerSynthesizedMappingInformation asCompilerSynthesizedMappingInformation() {
     return null;
   }
 
+  public UnknownJsonMappingInformation asUnknownJsonMappingInformation() {
+    return null;
+  }
+
   public abstract boolean allowOther(MappingInformation information);
 
   public static void fromJsonObject(
@@ -92,11 +100,11 @@
             version, object, diagnosticsHandler, lineNumber, onMappingInfo);
         return;
       case CompilerSynthesizedMappingInformation.ID:
-        CompilerSynthesizedMappingInformation.deserialize(
-            version, object, diagnosticsHandler, lineNumber, onMappingInfo);
+        CompilerSynthesizedMappingInformation.deserialize(version, onMappingInfo);
         return;
       default:
         diagnosticsHandler.info(MappingInformationDiagnostics.noHandlerFor(lineNumber, id));
+        UnknownJsonMappingInformation.deserialize(id, object, onMappingInfo);
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/UnknownJsonMappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/UnknownJsonMappingInformation.java
new file mode 100644
index 0000000..848919b
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/UnknownJsonMappingInformation.java
@@ -0,0 +1,54 @@
+// 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.naming.mappinginformation;
+
+import com.android.tools.r8.errors.Unreachable;
+import com.google.gson.JsonObject;
+import java.util.function.Consumer;
+
+public class UnknownJsonMappingInformation extends MappingInformation {
+
+  private final String id;
+  private final String payload;
+
+  public UnknownJsonMappingInformation(String id, String payload) {
+    this.id = id;
+    this.payload = payload;
+  }
+
+  @Override
+  public String getId() {
+    return id;
+  }
+
+  public String getPayload() {
+    return payload;
+  }
+
+  @Override
+  public String serialize() {
+    throw new Unreachable("We should not at this point serialize unknown information");
+  }
+
+  @Override
+  public boolean allowOther(MappingInformation information) {
+    return true;
+  }
+
+  @Override
+  public boolean isUnknownJsonMappingInformation() {
+    return true;
+  }
+
+  @Override
+  public UnknownJsonMappingInformation asUnknownJsonMappingInformation() {
+    return this;
+  }
+
+  public static void deserialize(
+      String id, JsonObject object, Consumer<MappingInformation> onMappingInfo) {
+    onMappingInfo.accept(new UnknownJsonMappingInformation(id, object.toString()));
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
index 227851f..36719be 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
@@ -128,10 +128,12 @@
     timing.begin("Argument propagator");
 
     // Compute the strongly connected program components for parallel execution.
+    timing.begin("Compute components");
     ImmediateProgramSubtypingInfo immediateSubtypingInfo =
         ImmediateProgramSubtypingInfo.create(appView);
     List<Set<DexProgramClass>> stronglyConnectedProgramComponents =
         computeStronglyConnectedProgramClasses(appView, immediateSubtypingInfo);
+    timing.end();
 
     // Set the optimization info on each method.
     populateParameterOptimizationInfo(
@@ -142,16 +144,17 @@
     Set<DexProgramClass> affectedClasses = Sets.newConcurrentHashSet();
     ArgumentPropagatorGraphLens graphLens =
         new ArgumentPropagatorProgramOptimizer(appView, immediateSubtypingInfo)
-            .run(stronglyConnectedProgramComponents, affectedClasses::add, executorService);
+            .run(stronglyConnectedProgramComponents, affectedClasses::add, executorService, timing);
 
     // Find all the code objects that need reprocessing.
     new ArgumentPropagatorMethodReprocessingEnqueuer(appView)
-        .enqueueMethodForReprocessing(graphLens, postMethodProcessorBuilder, executorService);
+        .enqueueMethodForReprocessing(
+            graphLens, postMethodProcessorBuilder, executorService, timing);
 
     // Finally, apply the graph lens to the program (i.e., remove constant parameters from method
     // definitions).
     new ArgumentPropagatorApplicationFixer(appView, graphLens)
-        .fixupApplication(affectedClasses, executorService);
+        .fixupApplication(affectedClasses, executorService, timing);
 
     timing.end();
   }
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..beb3003 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorApplicationFixer.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorApplicationFixer.java
@@ -8,13 +8,10 @@
 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 com.android.tools.r8.utils.Timing;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
@@ -35,7 +32,7 @@
   }
 
   public void fixupApplication(
-      Set<DexProgramClass> affectedClasses, ExecutorService executorService)
+      Set<DexProgramClass> affectedClasses, ExecutorService executorService, Timing timing)
       throws ExecutionException {
     // If the graph lens is null, argument propagation did not lead to any parameter removals. In
     // this case there is no needed to fixup the program.
@@ -46,8 +43,13 @@
 
     assert !affectedClasses.isEmpty();
 
+    timing.begin("Fixup application");
     ThreadUtils.processItems(affectedClasses, this::fixupClass, executorService);
+    timing.end();
+
+    timing.begin("Rewrite AppView");
     appView.rewriteWithLens(graphLens);
+    timing.end();
   }
 
   private void fixupClass(DexProgramClass clazz) {
@@ -64,30 +66,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());
               });
         });
   }
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java
index 37adcfa..68c7d12 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java
@@ -19,6 +19,7 @@
 import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.ThreadUtils;
+import com.android.tools.r8.utils.Timing;
 import com.android.tools.r8.utils.collections.LongLivedProgramMethodSetBuilder;
 import com.android.tools.r8.utils.collections.ProgramMethodSet;
 import java.util.ArrayList;
@@ -43,18 +44,31 @@
   public void enqueueMethodForReprocessing(
       ArgumentPropagatorGraphLens graphLens,
       PostMethodProcessor.Builder postMethodProcessorBuilder,
-      ExecutorService executorService)
+      ExecutorService executorService,
+      Timing timing)
       throws ExecutionException {
+    timing.begin("Enqueue methods for reprocessing");
+
     // Bring the methods to reprocess set up-to-date with the current graph lens (i.e., the one
     // prior to the argument propagator lens, which has not yet been installed!).
+    timing.begin("Rewrite methods to reprocess");
     LongLivedProgramMethodSetBuilder<ProgramMethodSet> methodsToReprocessBuilder =
         postMethodProcessorBuilder
             .getMethodsToReprocessBuilder()
             .rewrittenWithLens(appView.graphLens());
+    timing.end();
+
+    timing.begin("Enqueue methods with non-trivial info");
     enqueueMethodsWithNonTrivialOptimizationInfo(methodsToReprocessBuilder);
+    timing.end();
+
+    timing.begin("Enqueue affected methods");
     if (graphLens != null) {
       enqueueAffectedCallers(graphLens, methodsToReprocessBuilder, executorService);
     }
+    timing.end();
+
+    timing.end();
   }
 
   private void enqueueMethodsWithNonTrivialOptimizationInfo(
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
index 41e2e9c..76845cc 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
@@ -27,6 +27,7 @@
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.Pair;
 import com.android.tools.r8.utils.ThreadUtils;
+import com.android.tools.r8.utils.Timing;
 import com.android.tools.r8.utils.collections.DexMethodSignatureSet;
 import com.android.tools.r8.utils.collections.ProgramMethodSet;
 import com.google.common.collect.Iterables;
@@ -64,20 +65,27 @@
   public ArgumentPropagatorGraphLens run(
       List<Set<DexProgramClass>> stronglyConnectedProgramComponents,
       Consumer<DexProgramClass> affectedClassConsumer,
-      ExecutorService executorService)
+      ExecutorService executorService,
+      Timing timing)
       throws ExecutionException {
+    timing.begin("Optimize components");
     Collection<Builder> partialGraphLensBuilders =
         ThreadUtils.processItemsWithResults(
             stronglyConnectedProgramComponents,
             classes ->
                 new StronglyConnectedComponentOptimizer().optimize(classes, affectedClassConsumer),
             executorService);
+    timing.end();
 
     // Merge all the partial, disjoint graph lens builders into a single graph lens.
+    timing.begin("Build graph lens");
     ArgumentPropagatorGraphLens.Builder graphLensBuilder =
         ArgumentPropagatorGraphLens.builder(appView);
     partialGraphLensBuilders.forEach(graphLensBuilder::mergeDisjoint);
-    return graphLensBuilder.build();
+    ArgumentPropagatorGraphLens graphLens = graphLensBuilder.build();
+    timing.end();
+
+    return graphLens;
   }
 
   private DexMethodSignatureSet getOrComputeLibraryMethods(DexClass clazz) {
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceClassElement.java b/src/main/java/com/android/tools/r8/retrace/RetraceClassElement.java
index 0615725..35380e4 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceClassElement.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceClassElement.java
@@ -24,4 +24,6 @@
 
   RetraceFrameResult lookupFrame(
       String methodName, int position, List<TypeReference> formalTypes, TypeReference returnType);
+
+  RetraceUnknownJsonMappingInformationResult getUnknownJsonMappingInformation();
 }
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceUnknownJsonMappingInformationResult.java b/src/main/java/com/android/tools/r8/retrace/RetraceUnknownJsonMappingInformationResult.java
new file mode 100644
index 0000000..2afa333
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceUnknownJsonMappingInformationResult.java
@@ -0,0 +1,21 @@
+// 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.retrace;
+
+import com.android.tools.r8.Keep;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+@Keep
+public interface RetraceUnknownJsonMappingInformationResult {
+
+  /** Basic operation over 'elements' which represent a possible non-ambiguous retracing. */
+  Stream<RetraceUnknownMappingInformationElement> stream();
+
+  /** Short-hand for iterating the elements. */
+  default void forEach(Consumer<RetraceUnknownMappingInformationElement> action) {
+    stream().forEach(action);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceUnknownMappingInformationElement.java b/src/main/java/com/android/tools/r8/retrace/RetraceUnknownMappingInformationElement.java
new file mode 100644
index 0000000..3bba032
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceUnknownMappingInformationElement.java
@@ -0,0 +1,17 @@
+// 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.retrace;
+
+import com.android.tools.r8.Keep;
+
+@Keep
+public interface RetraceUnknownMappingInformationElement {
+
+  String getIdentifier();
+
+  String getPayLoad();
+
+  RetraceUnknownJsonMappingInformationResult getRetraceResultContext();
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/StringRetrace.java b/src/main/java/com/android/tools/r8/retrace/StringRetrace.java
index f6636c1..4bdb42c 100644
--- a/src/main/java/com/android/tools/r8/retrace/StringRetrace.java
+++ b/src/main/java/com/android/tools/r8/retrace/StringRetrace.java
@@ -9,6 +9,7 @@
 import com.android.tools.r8.DiagnosticsHandler;
 import com.android.tools.r8.Keep;
 import com.android.tools.r8.retrace.internal.StackTraceElementStringProxy;
+import com.android.tools.r8.utils.ListUtils;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
@@ -97,28 +98,29 @@
       // The result is empty, likely it maps to compiler synthesized items.
       return;
     }
-    List<String> initialResult = retracedResult.get(0);
-    initialResult.forEach(joinedConsumer);
-    if (retracedResult.size() <= 1) {
-      // The result is not ambiguous.
-      return;
-    }
-    Set<String> reportedFrames = new HashSet<>(initialResult);
-    for (int i = 1; i < retracedResult.size(); i++) {
-      List<String> ambiguousResult = retracedResult.get(i);
-      assert !ambiguousResult.isEmpty();
-      String topFrame = ambiguousResult.get(0);
-      if (reportedFrames.add(topFrame)) {
-        ambiguousResult.forEach(
-            retracedString -> {
-              int firstCharIndex = firstNonWhiteSpaceCharacterFromIndex(retracedString, 0);
-              retracedString =
-                  retracedString.substring(0, firstCharIndex)
-                      + "<OR> "
-                      + retracedString.substring(firstCharIndex);
-              joinedConsumer.accept(retracedString);
-            });
-      }
-    }
+    Set<String> reportedFrames = new HashSet<>();
+    ListUtils.forEachWithIndex(
+        retracedResult,
+        (potentialResults, index) -> {
+          assert !potentialResults.isEmpty();
+          // Check if we already reported position.
+          if (reportedFrames.add(potentialResults.get(0))) {
+            boolean isAmbiguous = potentialResults != retracedResult.get(0);
+            potentialResults.forEach(
+                retracedString -> {
+                  if (isAmbiguous) {
+                    int firstCharIndex = firstNonWhiteSpaceCharacterFromIndex(retracedString, 0);
+                    joinedConsumer.accept(
+                        retracedString.substring(0, firstCharIndex)
+                            + "<OR #"
+                            + (index)
+                            + "> "
+                            + retracedString.substring(firstCharIndex));
+                  } else {
+                    joinedConsumer.accept(retracedString);
+                  }
+                });
+          }
+        });
   }
 }
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java
index 5dace5b..55ed4db 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java
@@ -17,6 +17,7 @@
 import com.android.tools.r8.retrace.RetraceClassResult;
 import com.android.tools.r8.retrace.RetraceFrameResult;
 import com.android.tools.r8.retrace.RetraceSourceFileResult;
+import com.android.tools.r8.retrace.RetraceUnknownJsonMappingInformationResult;
 import com.android.tools.r8.retrace.Retracer;
 import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.Pair;
@@ -344,6 +345,12 @@
           position);
     }
 
+    @Override
+    public RetraceUnknownJsonMappingInformationResult getUnknownJsonMappingInformation() {
+      return RetraceUnknownJsonMappingInformationResultImpl.build(
+          mapper.getAdditionalMappingInfo());
+    }
+
     private RetraceFrameResultImpl lookupFrame(MethodDefinition definition, int position) {
       MethodDefinition methodDefinition =
           MethodDefinition.create(classReference.getClassReference(), definition.getName());
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceFrameResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceFrameResultImpl.java
index 82717b1..edde5ab 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetraceFrameResultImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceFrameResultImpl.java
@@ -17,6 +17,7 @@
 import com.android.tools.r8.retrace.Retracer;
 import com.android.tools.r8.retrace.internal.RetraceClassResultImpl.RetraceClassElementImpl;
 import com.android.tools.r8.utils.ListUtils;
+import com.android.tools.r8.utils.OptionalBool;
 import com.android.tools.r8.utils.Pair;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
@@ -34,6 +35,8 @@
   private final List<Pair<RetraceClassElementImpl, List<MappedRange>>> mappedRanges;
   private final Retracer retracer;
 
+  private OptionalBool isAmbiguousCache = OptionalBool.UNKNOWN;
+
   public RetraceFrameResultImpl(
       RetraceClassResultImpl classResult,
       List<Pair<RetraceClassElementImpl, List<MappedRange>>> mappedRanges,
@@ -49,22 +52,27 @@
 
   @Override
   public boolean isAmbiguous() {
-    if (mappedRanges.size() > 1) {
-      return true;
-    }
-    List<MappedRange> methodRanges = mappedRanges.get(0).getSecond();
-    if (methodRanges == null || methodRanges.isEmpty()) {
-      return false;
-    }
-    MappedRange lastRange = methodRanges.get(0);
-    for (MappedRange mappedRange : methodRanges) {
-      if (mappedRange != lastRange
-          && (mappedRange.minifiedRange == null
-              || !mappedRange.minifiedRange.equals(lastRange.minifiedRange))) {
+    if (isAmbiguousCache.isUnknown()) {
+      if (mappedRanges.size() > 1) {
+        isAmbiguousCache = OptionalBool.TRUE;
         return true;
       }
+      List<MappedRange> methodRanges = mappedRanges.get(0).getSecond();
+      if (methodRanges != null && !methodRanges.isEmpty()) {
+        MappedRange lastRange = methodRanges.get(0);
+        for (MappedRange mappedRange : methodRanges) {
+          if (mappedRange != lastRange
+              && (mappedRange.minifiedRange == null
+                  || !mappedRange.minifiedRange.equals(lastRange.minifiedRange))) {
+            isAmbiguousCache = OptionalBool.TRUE;
+            return true;
+          }
+        }
+      }
+      isAmbiguousCache = OptionalBool.FALSE;
     }
-    return false;
+    assert !isAmbiguousCache.isUnknown();
+    return isAmbiguousCache.isTrue();
   }
 
   @Override
@@ -120,12 +128,12 @@
 
   private RetracedMethodReferenceImpl getRetracedMethod(
       MethodReference methodReference, MappedRange mappedRange, int obfuscatedPosition) {
-    if (mappedRange.minifiedRange == null) {
+    if (mappedRange.minifiedRange == null || (obfuscatedPosition == -1 && !isAmbiguous())) {
       int originalLineNumber = mappedRange.getFirstLineNumberOfOriginalRange();
       return RetracedMethodReferenceImpl.create(
           methodReference, originalLineNumber > 0 ? originalLineNumber : obfuscatedPosition);
     }
-    if (obfuscatedPosition == -1 || !mappedRange.minifiedRange.contains(obfuscatedPosition)) {
+    if (!mappedRange.minifiedRange.contains(obfuscatedPosition)) {
       return RetracedMethodReferenceImpl.create(methodReference);
     }
     return RetracedMethodReferenceImpl.create(
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceUnknownJsonMappingInformationResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceUnknownJsonMappingInformationResultImpl.java
new file mode 100644
index 0000000..4a681a3
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceUnknownJsonMappingInformationResultImpl.java
@@ -0,0 +1,45 @@
+// 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.retrace.internal;
+
+import com.android.tools.r8.naming.mappinginformation.MappingInformation;
+import com.android.tools.r8.naming.mappinginformation.UnknownJsonMappingInformation;
+import com.android.tools.r8.retrace.RetraceUnknownJsonMappingInformationResult;
+import com.android.tools.r8.retrace.RetraceUnknownMappingInformationElement;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import java.util.stream.Stream;
+
+public class RetraceUnknownJsonMappingInformationResultImpl
+    implements RetraceUnknownJsonMappingInformationResult {
+
+  private final List<UnknownJsonMappingInformation> elements;
+
+  private RetraceUnknownJsonMappingInformationResultImpl(
+      List<UnknownJsonMappingInformation> elements) {
+    this.elements = elements;
+  }
+
+  @Override
+  public Stream<RetraceUnknownMappingInformationElement> stream() {
+    return elements.stream()
+        .map(
+            unknownJsonMappingInformation ->
+                new RetraceUnknownMappingInformationElementImpl(
+                    this, unknownJsonMappingInformation));
+  }
+
+  static RetraceUnknownJsonMappingInformationResult build(
+      List<MappingInformation> mappingInformations) {
+    ImmutableList.Builder<UnknownJsonMappingInformation> unknownBuilder = ImmutableList.builder();
+    mappingInformations.forEach(
+        info -> {
+          if (info.isUnknownJsonMappingInformation()) {
+            unknownBuilder.add(info.asUnknownJsonMappingInformation());
+          }
+        });
+    return new RetraceUnknownJsonMappingInformationResultImpl(unknownBuilder.build());
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceUnknownMappingInformationElementImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceUnknownMappingInformationElementImpl.java
new file mode 100644
index 0000000..5615408
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceUnknownMappingInformationElementImpl.java
@@ -0,0 +1,38 @@
+// 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.retrace.internal;
+
+import com.android.tools.r8.naming.mappinginformation.UnknownJsonMappingInformation;
+import com.android.tools.r8.retrace.RetraceUnknownJsonMappingInformationResult;
+import com.android.tools.r8.retrace.RetraceUnknownMappingInformationElement;
+
+public class RetraceUnknownMappingInformationElementImpl
+    implements RetraceUnknownMappingInformationElement {
+
+  private final RetraceUnknownJsonMappingInformationResult result;
+  private final UnknownJsonMappingInformation mappingInformation;
+
+  RetraceUnknownMappingInformationElementImpl(
+      RetraceUnknownJsonMappingInformationResult result,
+      UnknownJsonMappingInformation mappingInformation) {
+    this.result = result;
+    this.mappingInformation = mappingInformation;
+  }
+
+  @Override
+  public String getIdentifier() {
+    return mappingInformation.getId();
+  }
+
+  @Override
+  public String getPayLoad() {
+    return mappingInformation.getPayload();
+  }
+
+  @Override
+  public RetraceUnknownJsonMappingInformationResult getRetraceResultContext() {
+    return result;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementStringProxy.java b/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementStringProxy.java
index 33a0ea1..5f512f4 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementStringProxy.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementStringProxy.java
@@ -114,7 +114,11 @@
       return -1;
     }
     try {
-      return Integer.parseInt(getEntryInLine(lineNumber));
+      String lineNumberString = getEntryInLine(lineNumber);
+      if (lineNumberString.isEmpty()) {
+        return -1;
+      }
+      return Integer.parseInt(lineNumberString);
     } catch (NumberFormatException nfe) {
       return -1;
     }
@@ -226,15 +230,16 @@
       return this;
     }
 
-    public StackTraceElementStringProxyBuilder registerLineNumber(int startIndex, int endIndex) {
+    public StackTraceElementStringProxyBuilder registerLineNumber(
+        int startIndex, int endIndex, boolean insertSeparatorForRetraced) {
       lineNumber =
           new StringIndex(
               startIndex,
               endIndex,
               (retraced, original, verbose) ->
-                  retraced.hasLineNumber()
-                      ? retraced.getLineNumber() + ""
-                      : original.lineNumberAsString());
+                  (retraced.hasLineNumber()
+                      ? ((insertSeparatorForRetraced ? ":" : "") + retraced.getLineNumber())
+                      : original.lineNumberAsString()));
       orderedIndices.add(lineNumber);
       return this;
     }
@@ -296,6 +301,9 @@
     }
 
     public StackTraceElementStringProxy build() {
+      if (!lineNumber.hasIndex() && sourceFile.hasIndex()) {
+        registerLineNumber(sourceFile.endIndex, sourceFile.endIndex, true);
+      }
       return new StackTraceElementStringProxy(
           line,
           orderedIndices,
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/StackTraceRegularExpressionParser.java b/src/main/java/com/android/tools/r8/retrace/internal/StackTraceRegularExpressionParser.java
index fc8d5d9..e26e351 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/StackTraceRegularExpressionParser.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/StackTraceRegularExpressionParser.java
@@ -309,7 +309,7 @@
         if (startOfGroup == NO_MATCH) {
           return false;
         }
-        builder.registerLineNumber(startOfGroup, matcher.end(captureGroup));
+        builder.registerLineNumber(startOfGroup, matcher.end(captureGroup), false);
         return true;
       };
     }
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index a46bf38..242a08c 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -937,7 +937,8 @@
     if (!options().enableValuePropagation || neverPropagateValue.contains(method)) {
       return false;
     }
-    if (isPinned(method) && !method.getReturnType().isAlwaysNull(this)) {
+    if (!method.getReturnType().isAlwaysNull(this)
+        && !getKeepInfo().getMethodInfo(method, this).isInliningAllowed(options())) {
       return false;
     }
     return true;
@@ -1319,7 +1320,11 @@
       if (refinedReceiverClass.isProgramClass()) {
         DexClassAndMethod clazzAndMethod =
             resolution.lookupVirtualDispatchTarget(refinedReceiverClass.asProgramClass(), this);
-        if (clazzAndMethod == null || isPinned(clazzAndMethod.getDefinition().getReference())) {
+        if (clazzAndMethod == null
+            || (clazzAndMethod.isProgramMethod()
+                && !getKeepInfo()
+                    .getMethodInfo(clazzAndMethod.asProgramMethod())
+                    .isOptimizationAllowed(options()))) {
           // TODO(b/150640456): We should maybe only consider program methods.
           return DexEncodedMethod.SENTINEL;
         }
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 68fc3dc..c4e0518 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -564,8 +564,10 @@
   }
 
   public void addDeadProtoTypeCandidate(DexType type) {
-    assert type.isProgramType(appView);
-    addDeadProtoTypeCandidate(appView.definitionFor(type).asProgramClass());
+    DexProgramClass clazz = asProgramClassOrNull(appView.definitionFor(type));
+    if (clazz != null) {
+      addDeadProtoTypeCandidate(clazz);
+    }
   }
 
   public void addDeadProtoTypeCandidate(DexProgramClass clazz) {
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java b/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java
index dd4226c..9938bbc 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java
@@ -36,7 +36,7 @@
   }
 
   public boolean isArgumentPropagationAllowed(GlobalKeepInfoConfiguration configuration) {
-    return isOptimizationAllowed(configuration);
+    return isParameterRemovalAllowed(configuration);
   }
 
   public Joiner joiner() {
@@ -54,6 +54,10 @@
     return this.equals(bottom());
   }
 
+  public boolean isInliningAllowed(GlobalKeepInfoConfiguration configuration) {
+    return isOptimizationAllowed(configuration);
+  }
+
   public static class Builder extends KeepInfo.Builder<Builder, KeepMethodInfo> {
 
     private Builder() {
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 9694a13..860860b 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -520,15 +520,7 @@
     return !canUseNestBasedAccess();
   }
 
-  public boolean enableExperimentalRecordDesugaring() {
-    // TODO(b/169645628): Remove when records are supported.
-    return testing.enableExperimentalRecordDesugaring;
-  }
-
   public boolean shouldDesugarRecords() {
-    if (!enableExperimentalRecordDesugaring()) {
-      return false;
-    }
     return desugarState.isOn() && !canUseRecords();
   }
 
@@ -1553,7 +1545,6 @@
     public boolean enableEnumUnboxingDebugLogs = false;
     public boolean forceRedundantConstNumberRemoval = false;
     public boolean enableExperimentalDesugaredLibraryKeepRuleGenerator = false;
-    public boolean enableExperimentalRecordDesugaring = false;
     public boolean invertConditionals = false;
     public boolean placeExceptionalBlocksLast = false;
     public boolean dontCreateMarkerInD8 = false;
@@ -1566,6 +1557,7 @@
     public Consumer<IRCode> inlineeIrModifier = null;
     public int basicBlockMuncherIterationLimit = NO_LIMIT;
     public boolean dontReportFailingCheckDiscarded = false;
+    public boolean disableRecordApplicationReaderMap = false;
     public PrintStream whyAreYouNotInliningConsumer = System.out;
     public boolean trackDesugaredAPIConversions =
         System.getProperty("com.android.tools.r8.trackDesugaredAPIConversions") != null;
diff --git a/src/test/examplesAndroidP/invokecustom/InvokeCustom.java b/src/test/examplesAndroidP/invokecustom/InvokeCustom.java
index c3cb86f..76fed75 100644
--- a/src/test/examplesAndroidP/invokecustom/InvokeCustom.java
+++ b/src/test/examplesAndroidP/invokecustom/InvokeCustom.java
@@ -35,8 +35,6 @@
   }
 }
 
-// TODO(116283747): Add the same test where the interface method is not overriden but inherited
-// from the interface. Currently, that works on the reference implementation but fails on Art.
 class Impl implements I2 {
   @Override
   public ReturnType targetMethodTest5(ArgumentType arg) {
diff --git a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
index 2af9e9a..c81cdfc 100644
--- a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
@@ -1901,6 +1901,7 @@
                   .setDisableTreeShaking(true)
                   .setDisableMinification(true)
                   .setDisableDesugaring(compilationOptions.disableDesugaring)
+                  .addProguardConfiguration(ImmutableList.of("-dontoptimize"), Origin.unknown())
                   .addProguardConfiguration(ImmutableList.of("-keepattributes *"), Origin.unknown())
                   .addProguardConfiguration(compilationOptions.keepRules, Origin.unknown())
                   .setOutput(
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index 2ccb378..1fda6a4 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -1776,6 +1776,10 @@
     return AndroidApiLevel.O;
   }
 
+  public static AndroidApiLevel apiLevelWithConstMethodHandleSupport() {
+    return AndroidApiLevel.P;
+  }
+
   public static AndroidApiLevel apiLevelWithNativeMultiDexSupport() {
     return AndroidApiLevel.L;
   }
diff --git a/src/test/java/com/android/tools/r8/TestCompileResult.java b/src/test/java/com/android/tools/r8/TestCompileResult.java
index b80c482..69bf834 100644
--- a/src/test/java/com/android/tools/r8/TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/TestCompileResult.java
@@ -283,6 +283,14 @@
     return self();
   }
 
+  public CR enableJVMPreview() {
+    assert getBackend() == Backend.CF;
+    if (!vmArguments.contains("--enable-preview")) {
+      vmArguments.add("--enable-preview");
+    }
+    return self();
+  }
+
   public CR enableRuntimeAssertions(boolean enable) {
     if (getBackend() == Backend.CF) {
       if (enable) {
@@ -360,6 +368,13 @@
     return self();
   }
 
+  public <E extends Throwable> CR inspectWithOptions(
+      ThrowingConsumer<CodeInspector, E> consumer, Consumer<InternalOptions> debugOptionsConsumer)
+      throws IOException, E {
+    consumer.accept(inspector(debugOptionsConsumer));
+    return self();
+  }
+
   public CR assertNoMessages() {
     getDiagnosticMessages().assertNoMessages();
     return self();
diff --git a/src/test/java/com/android/tools/r8/desugar/DesugarMissingTypeClassTest.java b/src/test/java/com/android/tools/r8/desugar/DesugarMissingTypeClassTest.java
index a0838e8..1269b34 100644
--- a/src/test/java/com/android/tools/r8/desugar/DesugarMissingTypeClassTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/DesugarMissingTypeClassTest.java
@@ -4,7 +4,6 @@
 package com.android.tools.r8.desugar;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.D8TestBuilder;
@@ -79,10 +78,8 @@
         InterfaceDesugarMissingTypeDiagnostic desugarWarning = (InterfaceDesugarMissingTypeDiagnostic) diagnostic;
         assertEquals(
             Reference.classFromClass(MissingInterface.class), desugarWarning.getMissingType());
-        // The type is both missing from the interface referenced invoke and from the implements.
-        // The diagnostics should likely include all contexts akin to the R8 missing types.
-        assertEquals(Reference.classFromClass(TestClass.class), desugarWarning.getContextType());
-        assertNotEquals(Position.UNKNOWN, desugarWarning.getPosition());
+        assertEquals(Reference.classFromClass(MyClass.class), desugarWarning.getContextType());
+        assertEquals(Position.UNKNOWN, desugarWarning.getPosition());
       }
     }
   }
diff --git a/src/test/java/com/android/tools/r8/desugar/DesugarMissingTypeLambdaTest.java b/src/test/java/com/android/tools/r8/desugar/DesugarMissingTypeLambdaTest.java
index bd50527..875ead2 100644
--- a/src/test/java/com/android/tools/r8/desugar/DesugarMissingTypeLambdaTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/DesugarMissingTypeLambdaTest.java
@@ -3,10 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.desugar;
 
-import static com.android.tools.r8.references.Reference.classFromClass;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.D8TestBuilder;
@@ -19,6 +16,7 @@
 import com.android.tools.r8.errors.DesugarDiagnostic;
 import com.android.tools.r8.errors.InterfaceDesugarMissingTypeDiagnostic;
 import com.android.tools.r8.position.Position;
+import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.StringUtils;
@@ -77,12 +75,12 @@
         assertTrue(diagnostic instanceof DesugarDiagnostic);
         assertTrue(diagnostic instanceof InterfaceDesugarMissingTypeDiagnostic);
         InterfaceDesugarMissingTypeDiagnostic desugarWarning = (InterfaceDesugarMissingTypeDiagnostic) diagnostic;
-        assertEquals(classFromClass(MissingInterface.class), desugarWarning.getMissingType());
-        // TODO(b/132671303): The diagnostics should also contain the lambda context, but it should
-        //  not be the synthesized lambda class.
-        assertFalse(SyntheticItemsTestUtils.isInternalLambda(desugarWarning.getContextType()));
-        assertEquals(classFromClass(TestClass.class), desugarWarning.getContextType());
-        assertNotEquals(Position.UNKNOWN, desugarWarning.getPosition());
+        assertEquals(
+            Reference.classFromClass(MissingInterface.class), desugarWarning.getMissingType());
+        // TODO(b/132671303): The context class should not be the synthesized lambda class.
+        assertTrue(SyntheticItemsTestUtils.isInternalLambda(desugarWarning.getContextType()));
+        // TODO(b/132671303): The position info should be the method context.
+        assertEquals(Position.UNKNOWN, desugarWarning.getPosition());
       }
     }
   }
diff --git a/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaInStacktraceTest.java b/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaInStacktraceTest.java
index 640796d..31f87d9 100644
--- a/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaInStacktraceTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaInStacktraceTest.java
@@ -102,6 +102,7 @@
             .addKeepAttributeSourceFile()
             .addKeepRules("-renamesourcefileattribute SourceFile")
             .noTreeShaking()
+            .addDontOptimize()
             .run(parameters.getRuntime(), TestRunner.class, Boolean.toString(isDalvik))
             .assertSuccess()
             .getStdOut();
diff --git a/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordTest.java b/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordTest.java
index 389744e..817114e 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordTest.java
@@ -11,7 +11,6 @@
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestRuntime.CfRuntime;
 import com.android.tools.r8.utils.StringUtils;
-import java.nio.file.Path;
 import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -55,7 +54,6 @@
         .addProgramClassFileData(PROGRAM_DATA)
         .setMinApi(parameters.getApiLevel())
         .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
-        .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
         .compile()
         .run(parameters.getRuntime(), MAIN_TYPE)
         .assertSuccessWithOutput(EXPECTED_RESULT);
@@ -64,21 +62,16 @@
   @Test
   public void testR8() throws Exception {
     if (parameters.isCfRuntime()) {
-      Path output =
-          testForR8(parameters.getBackend())
-              .addProgramClassFileData(PROGRAM_DATA)
-              .setMinApi(parameters.getApiLevel())
-              .addKeepRules(RECORD_KEEP_RULE)
-              .addKeepMainRule(MAIN_TYPE)
-              .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
-              .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
-              .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
-              .compile()
-              .writeToZip();
-      RecordTestUtils.assertRecordsAreRecords(output);
-      testForJvm()
-          .addRunClasspathFiles(output)
-          .enablePreview()
+      testForR8(parameters.getBackend())
+          .addProgramClassFileData(PROGRAM_DATA)
+          .setMinApi(parameters.getApiLevel())
+          .addKeepRules(RECORD_KEEP_RULE)
+          .addKeepMainRule(MAIN_TYPE)
+          .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
+          .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
+          .compile()
+          .inspect(RecordTestUtils::assertRecordsAreRecords)
+          .enableJVMPreview()
           .run(parameters.getRuntime(), MAIN_TYPE)
           .assertSuccessWithOutput(EXPECTED_RESULT);
       return;
@@ -89,7 +82,6 @@
         .addKeepRules(RECORD_KEEP_RULE)
         .addKeepMainRule(MAIN_TYPE)
         .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
-        .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
         .compile()
         .run(parameters.getRuntime(), MAIN_TYPE)
         .assertSuccessWithOutput(EXPECTED_RESULT);
diff --git a/src/test/java/com/android/tools/r8/desugar/records/InvalidRecordAttributeTest.java b/src/test/java/com/android/tools/r8/desugar/records/InvalidRecordAttributeTest.java
deleted file mode 100644
index 7064af6..0000000
--- a/src/test/java/com/android/tools/r8/desugar/records/InvalidRecordAttributeTest.java
+++ /dev/null
@@ -1,111 +0,0 @@
-// 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.desugar.records;
-
-import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assert.assertThrows;
-
-import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.TestDiagnosticMessages;
-import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestRuntime.CfRuntime;
-import com.android.tools.r8.utils.AndroidApiLevel;
-import java.util.List;
-import org.junit.Assume;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-/** Remove this test when Records are supported by default. */
-@RunWith(Parameterized.class)
-public class InvalidRecordAttributeTest extends TestBase {
-
-  private final TestParameters parameters;
-  private final Backend backend;
-
-  private static final String EMPTY_RECORD = "EmptyRecord";
-  private static final byte[][] EMPTY_RECORD_PROGRAM_DATA =
-      RecordTestUtils.getProgramData(EMPTY_RECORD);
-  private static final String SIMPLE_RECORD = "SimpleRecord";
-  private static final byte[][] SIMPLE_RECORD_PROGRAM_DATA =
-      RecordTestUtils.getProgramData(SIMPLE_RECORD);
-
-  @Parameters(name = "{0} back: {1}")
-  public static List<Object[]> data() {
-    // TODO(b/174431251): This should be replaced with .withCfRuntimes(start = jdk16).
-    return buildParameters(
-        getTestParameters().withCustomRuntime(CfRuntime.getCheckedInJdk16()).build(),
-        Backend.values());
-  }
-
-  public InvalidRecordAttributeTest(TestParameters parameters, Backend backend) {
-    this.parameters = parameters;
-    this.backend = backend;
-  }
-
-  @Test
-  public void testD8EmptyRecord() throws Exception {
-    Assume.assumeTrue(backend.isDex());
-    assertThrows(
-        CompilationFailedException.class,
-        () -> {
-          testForD8(backend)
-              .addProgramClassFileData(EMPTY_RECORD_PROGRAM_DATA)
-              .setMinApi(AndroidApiLevel.B)
-              .compileWithExpectedDiagnostics(
-                  InvalidRecordAttributeTest::assertUnsupportedRecordError);
-        });
-  }
-
-  @Test
-  public void testD8SimpleRecord() throws Exception {
-    Assume.assumeTrue(backend.isDex());
-    assertThrows(
-        CompilationFailedException.class,
-        () -> {
-          testForD8(backend)
-              .addProgramClassFileData(RecordTestUtils.getProgramData(SIMPLE_RECORD))
-              .setMinApi(AndroidApiLevel.B)
-              .compileWithExpectedDiagnostics(
-                  InvalidRecordAttributeTest::assertUnsupportedRecordError);
-        });
-  }
-
-  @Test
-  public void testR8EmptyRecord() throws Exception {
-    assertThrows(
-        CompilationFailedException.class,
-        () -> {
-          testForR8(backend)
-              .addProgramClassFileData(EMPTY_RECORD_PROGRAM_DATA)
-              .setMinApi(AndroidApiLevel.B)
-              .addKeepMainRule(RecordTestUtils.getMainType(EMPTY_RECORD))
-              .compileWithExpectedDiagnostics(
-                  InvalidRecordAttributeTest::assertUnsupportedRecordError);
-        });
-  }
-
-  @Test
-  public void testR8SimpleRecord() throws Exception {
-    assertThrows(
-        CompilationFailedException.class,
-        () -> {
-          testForR8(backend)
-              .addProgramClassFileData(SIMPLE_RECORD_PROGRAM_DATA)
-              .setMinApi(AndroidApiLevel.B)
-              .addKeepMainRule(RecordTestUtils.getMainType(SIMPLE_RECORD))
-              .compileWithExpectedDiagnostics(
-                  InvalidRecordAttributeTest::assertUnsupportedRecordError);
-        });
-  }
-
-  private static void assertUnsupportedRecordError(TestDiagnosticMessages diagnostics) {
-    diagnostics.assertErrorThatMatches(
-        diagnosticMessage(containsString("Records are not supported")));
-  }
-}
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordInstanceOfTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordInstanceOfTest.java
index 08b0e85..6d0f1a3 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordInstanceOfTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordInstanceOfTest.java
@@ -11,7 +11,6 @@
 import com.android.tools.r8.TestRuntime.CfRuntime;
 import com.android.tools.r8.utils.InternalOptions.TestingOptions;
 import com.android.tools.r8.utils.StringUtils;
-import java.nio.file.Path;
 import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -55,7 +54,6 @@
         .addProgramClassFileData(PROGRAM_DATA)
         .setMinApi(parameters.getApiLevel())
         .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
-        .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
         .compile()
         .run(parameters.getRuntime(), MAIN_TYPE)
         .assertSuccessWithOutput(EXPECTED_RESULT);
@@ -64,21 +62,16 @@
   @Test
   public void testR8() throws Exception {
     if (parameters.isCfRuntime()) {
-      Path output =
-          testForR8(parameters.getBackend())
-              .addProgramClassFileData(PROGRAM_DATA)
-              .setMinApi(parameters.getApiLevel())
-              .addKeepRules(RECORD_KEEP_RULE)
-              .addKeepMainRule(MAIN_TYPE)
-              .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
-              .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
-              .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
-              .compile()
-              .writeToZip();
-      RecordTestUtils.assertRecordsAreRecords(output);
-      testForJvm()
-          .addRunClasspathFiles(output)
-          .enablePreview()
+      testForR8(parameters.getBackend())
+          .addProgramClassFileData(PROGRAM_DATA)
+          .setMinApi(parameters.getApiLevel())
+          .addKeepRules(RECORD_KEEP_RULE)
+          .addKeepMainRule(MAIN_TYPE)
+          .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
+          .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
+          .compile()
+          .inspect(RecordTestUtils::assertRecordsAreRecords)
+          .enableJVMPreview()
           .run(parameters.getRuntime(), MAIN_TYPE)
           .assertSuccessWithOutput(EXPECTED_RESULT);
       return;
@@ -89,7 +82,6 @@
         .addKeepRules(RECORD_KEEP_RULE)
         .addKeepMainRule(MAIN_TYPE)
         .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
-        .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
         .compile()
         .run(parameters.getRuntime(), MAIN_TYPE)
         .assertSuccessWithOutput(EXPECTED_RESULT);
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomSplitDesugaringTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomSplitDesugaringTest.java
index 206fc03..0383285 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomSplitDesugaringTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomSplitDesugaringTest.java
@@ -56,14 +56,12 @@
             .addProgramClassFileData(PROGRAM_DATA)
             .setMinApi(parameters.getApiLevel())
             .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
-            .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
             .compile()
             .writeToZip();
     testForD8(parameters.getBackend())
         .addProgramFiles(desugared)
         .setMinApi(parameters.getApiLevel())
         .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
-        .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
         .compile()
         .run(parameters.getRuntime(), MAIN_TYPE)
         .assertSuccessWithOutput(EXPECTED_RESULT);
@@ -76,7 +74,6 @@
             .addProgramClassFileData(PROGRAM_DATA)
             .setMinApi(parameters.getApiLevel())
             .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
-            .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
             .compile()
             .writeToZip();
     testForR8(parameters.getBackend())
@@ -85,7 +82,6 @@
         .addKeepRules(RECORD_KEEP_RULE)
         .addKeepMainRule(MAIN_TYPE)
         .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
-        .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
         .compile()
         .run(parameters.getRuntime(), MAIN_TYPE)
         .assertSuccessWithOutput(EXPECTED_RESULT);
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomTest.java
index 9bf3327..3326483 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomTest.java
@@ -11,7 +11,6 @@
 import com.android.tools.r8.TestRuntime.CfRuntime;
 import com.android.tools.r8.utils.InternalOptions.TestingOptions;
 import com.android.tools.r8.utils.StringUtils;
-import java.nio.file.Path;
 import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -68,7 +67,6 @@
         .addProgramClassFileData(PROGRAM_DATA)
         .setMinApi(parameters.getApiLevel())
         .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
-        .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
         .compile()
         .run(parameters.getRuntime(), MAIN_TYPE)
         .assertSuccessWithOutput(EXPECTED_RESULT);
@@ -77,21 +75,16 @@
   @Test
   public void testR8() throws Exception {
     if (parameters.isCfRuntime()) {
-      Path output =
-          testForR8(parameters.getBackend())
-              .addProgramClassFileData(PROGRAM_DATA)
-              .setMinApi(parameters.getApiLevel())
-              .addKeepRules(RECORD_KEEP_RULE)
-              .addKeepMainRule(MAIN_TYPE)
-              .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
-              .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
-              .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
-              .compile()
-              .writeToZip();
-      RecordTestUtils.assertRecordsAreRecords(output);
-      testForJvm()
-          .addRunClasspathFiles(output)
-          .enablePreview()
+      testForR8(parameters.getBackend())
+          .addProgramClassFileData(PROGRAM_DATA)
+          .setMinApi(parameters.getApiLevel())
+          .addKeepRules(RECORD_KEEP_RULE)
+          .addKeepMainRule(MAIN_TYPE)
+          .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
+          .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
+          .compile()
+          .inspect(RecordTestUtils::assertRecordsAreRecords)
+          .enableJVMPreview()
           .run(parameters.getRuntime(), MAIN_TYPE)
           .assertSuccessWithOutput(EXPECTED_RESULT);
       return;
@@ -102,7 +95,6 @@
         .addKeepRules(RECORD_KEEP_RULE)
         .addKeepMainRule(MAIN_TYPE)
         .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
-        .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
         .compile()
         .run(parameters.getRuntime(), MAIN_TYPE)
         .assertSuccessWithOutput(EXPECTED_RESULT);
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordMergeTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordMergeTest.java
index 240e128..ef11ef4 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordMergeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordMergeTest.java
@@ -56,7 +56,6 @@
             .addProgramClassFileData(PROGRAM_DATA_1)
             .setMinApi(parameters.getApiLevel())
             .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
-            .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
             .compile()
             .writeToZip();
     Path output2 =
@@ -64,7 +63,6 @@
             .addProgramClassFileData(PROGRAM_DATA_2)
             .setMinApi(parameters.getApiLevel())
             .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
-            .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
             .compile()
             .writeToZip();
     D8TestCompileResult result =
@@ -84,7 +82,6 @@
             .addProgramClassFileData(PROGRAM_DATA_1)
             .setMinApi(parameters.getApiLevel())
             .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
-            .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
             .compile()
             .writeToZip();
     D8TestCompileResult result =
@@ -93,7 +90,6 @@
             .addProgramClassFileData(PROGRAM_DATA_2)
             .setMinApi(parameters.getApiLevel())
             .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
-            .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
             .compile();
     result.run(parameters.getRuntime(), MAIN_TYPE_1).assertSuccessWithOutput(EXPECTED_RESULT_1);
     result.run(parameters.getRuntime(), MAIN_TYPE_2).assertSuccessWithOutput(EXPECTED_RESULT_2);
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordReflectionTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordReflectionTest.java
index 9663f43..cad3c5b 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordReflectionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordReflectionTest.java
@@ -11,7 +11,6 @@
 import com.android.tools.r8.TestRuntime.CfRuntime;
 import com.android.tools.r8.utils.InternalOptions.TestingOptions;
 import com.android.tools.r8.utils.StringUtils;
-import java.nio.file.Path;
 import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -59,21 +58,16 @@
 
   @Test
   public void testR8Cf() throws Exception {
-    Path output =
-        testForR8(parameters.getBackend())
-            .addProgramClassFileData(PROGRAM_DATA)
-            .setMinApi(parameters.getApiLevel())
-            .addKeepRules(RECORD_KEEP_RULE)
-            .addKeepMainRule(MAIN_TYPE)
-            .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
-            .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
-            .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
-            .compile()
-            .writeToZip();
-    RecordTestUtils.assertRecordsAreRecords(output);
-    testForJvm()
-        .addRunClasspathFiles(output)
-        .enablePreview()
+    testForR8(parameters.getBackend())
+        .addProgramClassFileData(PROGRAM_DATA)
+        .setMinApi(parameters.getApiLevel())
+        .addKeepRules(RECORD_KEEP_RULE)
+        .addKeepMainRule(MAIN_TYPE)
+        .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
+        .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
+        .compile()
+        .inspect(RecordTestUtils::assertRecordsAreRecords)
+        .enableJVMPreview()
         .run(parameters.getRuntime(), MAIN_TYPE)
         .assertSuccessWithOutput(EXPECTED_RESULT);
   }
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordTestUtils.java b/src/test/java/com/android/tools/r8/desugar/records/RecordTestUtils.java
index 86e30a6..224a873 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordTestUtils.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordTestUtils.java
@@ -5,6 +5,8 @@
 package com.android.tools.r8.desugar.records;
 
 import static com.android.tools.r8.TestRuntime.getCheckedInJdk8;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.JavaCompilerTool;
@@ -98,13 +100,15 @@
     return result.toArray(new byte[0][0]);
   }
 
-  public static void assertRecordsAreRecords(Path output) throws IOException {
-    CodeInspector inspector =
-        new CodeInspector(output, opt -> opt.testing.enableExperimentalRecordDesugaring = true);
+  public static void assertRecordsAreRecords(CodeInspector inspector) {
     for (FoundClassSubject clazz : inspector.allClasses()) {
       if (clazz.getDexProgramClass().superType.toString().equals("java.lang.Record")) {
         assertTrue(clazz.getDexProgramClass().isRecord());
       }
     }
   }
+
+  public static void assertNoJavaLangRecord(CodeInspector inspector) {
+    assertThat(inspector.clazz("java.lang.Record"), isAbsent());
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordWithMembersTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordWithMembersTest.java
index 36b2377..4b2c62a 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordWithMembersTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordWithMembersTest.java
@@ -11,7 +11,6 @@
 import com.android.tools.r8.TestRuntime.CfRuntime;
 import com.android.tools.r8.utils.InternalOptions.TestingOptions;
 import com.android.tools.r8.utils.StringUtils;
-import java.nio.file.Path;
 import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -57,7 +56,6 @@
         .addProgramClassFileData(PROGRAM_DATA)
         .setMinApi(parameters.getApiLevel())
         .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
-        .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
         .compile()
         .run(parameters.getRuntime(), MAIN_TYPE)
         .assertSuccessWithOutput(EXPECTED_RESULT);
@@ -66,21 +64,16 @@
   @Test
   public void testR8() throws Exception {
     if (parameters.isCfRuntime()) {
-      Path output =
-          testForR8(parameters.getBackend())
-              .addProgramClassFileData(PROGRAM_DATA)
-              .setMinApi(parameters.getApiLevel())
-              .addKeepRules(RECORD_KEEP_RULE)
-              .addKeepMainRule(MAIN_TYPE)
-              .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
-              .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
-              .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
-              .compile()
-              .writeToZip();
-      RecordTestUtils.assertRecordsAreRecords(output);
-      testForJvm()
-          .addRunClasspathFiles(output)
-          .enablePreview()
+      testForR8(parameters.getBackend())
+          .addProgramClassFileData(PROGRAM_DATA)
+          .setMinApi(parameters.getApiLevel())
+          .addKeepRules(RECORD_KEEP_RULE)
+          .addKeepMainRule(MAIN_TYPE)
+          .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
+          .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
+          .compile()
+          .inspect(RecordTestUtils::assertRecordsAreRecords)
+          .enableJVMPreview()
           .run(parameters.getRuntime(), MAIN_TYPE)
           .assertSuccessWithOutput(EXPECTED_RESULT);
       return;
@@ -91,7 +84,6 @@
         .addKeepRules(RECORD_KEEP_RULE)
         .addKeepMainRule(MAIN_TYPE)
         .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
-        .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
         .compile()
         .run(parameters.getRuntime(), MAIN_TYPE)
         .assertSuccessWithOutput(EXPECTED_RESULT);
diff --git a/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java b/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java
index 08c9468..ad338ed 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java
@@ -11,7 +11,6 @@
 import com.android.tools.r8.TestRuntime.CfRuntime;
 import com.android.tools.r8.utils.InternalOptions.TestingOptions;
 import com.android.tools.r8.utils.StringUtils;
-import java.nio.file.Path;
 import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -56,8 +55,10 @@
         .addProgramClassFileData(PROGRAM_DATA)
         .setMinApi(parameters.getApiLevel())
         .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
-        .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
         .compile()
+        .inspectWithOptions(
+            RecordTestUtils::assertNoJavaLangRecord,
+            options -> options.testing.disableRecordApplicationReaderMap = true)
         .run(parameters.getRuntime(), MAIN_TYPE)
         .assertSuccessWithOutput(EXPECTED_RESULT);
   }
@@ -65,21 +66,16 @@
   @Test
   public void testR8() throws Exception {
     if (parameters.isCfRuntime()) {
-      Path output =
-          testForR8(parameters.getBackend())
-              .addProgramClassFileData(PROGRAM_DATA)
-              .setMinApi(parameters.getApiLevel())
-              .addKeepRules(RECORD_KEEP_RULE)
-              .addKeepMainRule(MAIN_TYPE)
-              .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
-              .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
-              .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
-              .compile()
-              .writeToZip();
-      RecordTestUtils.assertRecordsAreRecords(output);
-      testForJvm()
-          .addRunClasspathFiles(output)
-          .enablePreview()
+      testForR8(parameters.getBackend())
+          .addProgramClassFileData(PROGRAM_DATA)
+          .setMinApi(parameters.getApiLevel())
+          .addKeepRules(RECORD_KEEP_RULE)
+          .addKeepMainRule(MAIN_TYPE)
+          .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
+          .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
+          .compile()
+          .inspect(RecordTestUtils::assertRecordsAreRecords)
+          .enableJVMPreview()
           .run(parameters.getRuntime(), MAIN_TYPE)
           .assertSuccessWithOutput(EXPECTED_RESULT);
       return;
@@ -90,8 +86,43 @@
         .addKeepRules(RECORD_KEEP_RULE)
         .addKeepMainRule(MAIN_TYPE)
         .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
-        .addOptionsModification(opt -> opt.testing.enableExperimentalRecordDesugaring = true)
         .compile()
+        .inspectWithOptions(
+            RecordTestUtils::assertNoJavaLangRecord,
+            options -> options.testing.disableRecordApplicationReaderMap = true)
+        .run(parameters.getRuntime(), MAIN_TYPE)
+        .assertSuccessWithOutput(EXPECTED_RESULT);
+  }
+
+  @Test
+  public void testR8NoMinification() throws Exception {
+    if (parameters.isCfRuntime()) {
+      testForR8(parameters.getBackend())
+          .addProgramClassFileData(PROGRAM_DATA)
+          .noMinification()
+          .setMinApi(parameters.getApiLevel())
+          .addKeepRules(RECORD_KEEP_RULE)
+          .addKeepMainRule(MAIN_TYPE)
+          .addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
+          .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
+          .compile()
+          .inspect(RecordTestUtils::assertRecordsAreRecords)
+          .enableJVMPreview()
+          .run(parameters.getRuntime(), MAIN_TYPE)
+          .assertSuccessWithOutput(EXPECTED_RESULT);
+      return;
+    }
+    testForR8(parameters.getBackend())
+        .addProgramClassFileData(PROGRAM_DATA)
+        .noMinification()
+        .setMinApi(parameters.getApiLevel())
+        .addKeepRules(RECORD_KEEP_RULE)
+        .addKeepMainRule(MAIN_TYPE)
+        .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
+        .compile()
+        .inspectWithOptions(
+            RecordTestUtils::assertNoJavaLangRecord,
+            options -> options.testing.disableRecordApplicationReaderMap = true)
         .run(parameters.getRuntime(), MAIN_TYPE)
         .assertSuccessWithOutput(EXPECTED_RESULT);
   }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningOptimize.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningOptimize.java
new file mode 100644
index 0000000..0c0bac6
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningOptimize.java
@@ -0,0 +1,47 @@
+// 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.inliner;
+
+import static org.junit.Assert.assertFalse;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import org.junit.Test;
+
+class Foobar {
+  public static void main(String[] args) {
+    System.out.println("Value: " + (new Bar()).returnPlusConstant(42));
+  }
+}
+
+class Bar {
+  public int returnPlusConstant(int value) {
+    return value + 42;
+  }
+}
+
+public class InliningOptimize extends TestBase {
+
+  @Test
+  public void test() throws Exception {
+    testForR8(Backend.DEX)
+        .addProgramClasses(Bar.class, Foobar.class)
+        .addKeepRules("-keep,allowoptimization class ** {\n" + "*;\n" + "}")
+        .compile()
+        .inspect(
+            inspector -> {
+              inspector
+                  .clazz(Foobar.class)
+                  .mainMethod()
+                  .iterateInstructions(InstructionSubject::isInvoke)
+                  .forEachRemaining(
+                      invoke -> {
+                        assertFalse(
+                            invoke.getMethod().name.toString().contains("returnPlusConstant"));
+                      });
+            })
+        .run(Foobar.class)
+        .assertSuccessWithOutputLines("Value: 84");
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrunedFieldsTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrunedFieldsTest.java
index 09c2a9d..505169e 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrunedFieldsTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrunedFieldsTest.java
@@ -54,6 +54,13 @@
         .allowDiagnosticWarningMessages()
         .setMinApi(parameters.getApiLevel())
         .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
+        .addOptionsModification(
+            internalOptions -> {
+              // When checking for metadata being equal if not rewritten, we parse the original data
+              // again. However, for this particular test, a field of the metadata has been removed
+              // and we cannot parse the metadata again.
+              internalOptions.testing.keepMetadataInR8IfNotRewritten = false;
+            })
         .compile()
         .inspect(
             codeInspector -> {
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
index 717bf12..b175132 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
@@ -75,9 +75,6 @@
     testForD8(Backend.DEX)
         .addProgramFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
         .setMinApi(AndroidApiLevel.B)
-        // Enable record desugaring support to force a non-identity naming lens
-        .addOptionsModification(
-            options -> options.testing.enableExperimentalRecordDesugaring = true)
         .compile()
         .inspect(
             inspector ->
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteUnitPrimitiveTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteUnitPrimitiveTest.java
new file mode 100644
index 0000000..fafb083
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteUnitPrimitiveTest.java
@@ -0,0 +1,158 @@
+// 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.kotlin.metadata;
+
+import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.MIN_SUPPORTED_VERSION;
+import static com.android.tools.r8.ToolHelper.KotlinTargetVersion.JAVA_8;
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinReflectJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertNull;
+
+import com.android.tools.r8.KotlinTestParameters;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.kotlin.KotlinMetadataWriter;
+import com.android.tools.r8.shaking.ProguardKeepAttributes;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Collection;
+import junit.framework.TestCase;
+import kotlinx.metadata.jvm.KotlinClassHeader;
+import kotlinx.metadata.jvm.KotlinClassMetadata;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class MetadataRewriteUnitPrimitiveTest extends KotlinMetadataTestBase {
+
+  private static final String PKG_LIB = PKG + ".unit_primitive_lib";
+  private static final String PKG_APP = PKG + ".unit_primitive_app";
+  private final TestParameters parameters;
+
+  private static final String EXPECTED =
+      StringUtils.lines(
+          "fun " + PKG_LIB + ".Lib.testInt(): kotlin.Int",
+          "42",
+          "fun " + PKG_LIB + ".Lib.testIntArray(): kotlin.IntArray",
+          "42",
+          "fun " + PKG_LIB + ".Lib.testUInt(): kotlin.UInt",
+          "42",
+          "fun " + PKG_LIB + ".Lib.testUIntArray(): kotlin.UIntArray",
+          "UIntArray(storage=[42])",
+          "fun " + PKG_LIB + ".Lib.testUnit(): kotlin.Unit",
+          "testUnit",
+          "kotlin.Unit");
+
+  @Parameterized.Parameters(name = "{0}, {1}")
+  public static Collection<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withCfRuntimes().build(),
+        getKotlinTestParameters()
+            .withCompilersStartingFromIncluding(MIN_SUPPORTED_VERSION)
+            .withTargetVersion(JAVA_8)
+            .build());
+  }
+
+  public MetadataRewriteUnitPrimitiveTest(
+      TestParameters parameters, KotlinTestParameters kotlinParameters) {
+    super(kotlinParameters);
+    this.parameters = parameters;
+  }
+
+  private static final KotlinCompileMemoizer kotlincLibJar =
+      getCompileMemoizer(
+          getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib"));
+
+  @Test
+  public void smokeTest() throws Exception {
+    Path output =
+        kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
+            .addClasspathFiles(kotlincLibJar.getForConfiguration(kotlinc, targetVersion))
+            .addSourceFiles(
+                getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
+            .setOutputPath(temp.newFolder().toPath())
+            .compile();
+    testForJvm()
+        .addRunClasspathFiles(
+            getKotlinStdlibJar(kotlinc),
+            getKotlinReflectJar(kotlinc),
+            kotlincLibJar.getForConfiguration(kotlinc, targetVersion))
+        .addClasspath(output)
+        .run(parameters.getRuntime(), PKG_APP + ".MainKt")
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  @Test
+  public void testMetadataForLib() throws Exception {
+    Path libJar =
+        testForR8(parameters.getBackend())
+            .addClasspathFiles(getKotlinAnnotationJar(kotlinc))
+            .addProgramFiles(
+                kotlincLibJar.getForConfiguration(kotlinc, targetVersion),
+                getKotlinStdlibJar(kotlinc))
+            .addKeepClassAndMembersRules(PKG_LIB + ".*")
+            .addKeepAttributes(
+                ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS,
+                ProguardKeepAttributes.SIGNATURE,
+                ProguardKeepAttributes.INNER_CLASSES,
+                ProguardKeepAttributes.ENCLOSING_METHOD)
+            .addKeepKotlinMetadata()
+            .allowDiagnosticWarningMessages()
+            .compile()
+            .assertAllWarningMessagesMatch(
+                equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
+            .inspect(this::inspect)
+            .writeToZip();
+    Path main =
+        kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
+            .addClasspathFiles(libJar)
+            .addSourceFiles(
+                getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
+            .setOutputPath(temp.newFolder().toPath())
+            .compile();
+    testForJvm()
+        .addRunClasspathFiles(
+            getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar)
+        .addClasspath(main)
+        .run(parameters.getRuntime(), PKG_APP + ".MainKt")
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  private void inspect(CodeInspector inspector) throws IOException {
+    CodeInspector stdLibInspector =
+        new CodeInspector(kotlincLibJar.getForConfiguration(kotlinc, targetVersion));
+    for (FoundClassSubject clazzSubject : stdLibInspector.allClasses()) {
+      ClassSubject r8Clazz = inspector.clazz(clazzSubject.getOriginalName());
+      assertThat(r8Clazz, isPresent());
+      KotlinClassMetadata originalMetadata = clazzSubject.getKotlinClassMetadata();
+      KotlinClassMetadata rewrittenMetadata = r8Clazz.getKotlinClassMetadata();
+      if (originalMetadata == null) {
+        assertNull(rewrittenMetadata);
+        continue;
+      }
+      TestCase.assertNotNull(rewrittenMetadata);
+      KotlinClassHeader originalHeader = originalMetadata.getHeader();
+      KotlinClassHeader rewrittenHeader = rewrittenMetadata.getHeader();
+      TestCase.assertEquals(originalHeader.getKind(), rewrittenHeader.getKind());
+      TestCase.assertEquals(originalHeader.getPackageName(), rewrittenHeader.getPackageName());
+      Assert.assertArrayEquals(originalHeader.getData1(), rewrittenHeader.getData1());
+      Assert.assertArrayEquals(originalHeader.getData2(), rewrittenHeader.getData2());
+      String expected = KotlinMetadataWriter.kotlinMetadataToString("", originalMetadata);
+      String actual = KotlinMetadataWriter.kotlinMetadataToString("", rewrittenMetadata);
+      TestCase.assertEquals(expected, actual);
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/unit_primitive_app/main.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/unit_primitive_app/main.kt
new file mode 100644
index 0000000..b3d5d3c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/unit_primitive_app/main.kt
@@ -0,0 +1,21 @@
+// 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.kotlin.metadata.unit_primitive_app
+
+import com.android.tools.r8.kotlin.metadata.unit_primitive_lib.Lib
+import kotlin.reflect.full.declaredFunctions
+
+fun main() {
+  var lib = Lib();
+  lib::class.declaredFunctions.forEach({
+    println(it)
+    var msg = it.call(lib)
+    if (msg is IntArray) {
+      println(msg[0])
+    } else {
+      println(msg)
+    }
+  })
+}
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/unit_primitive_lib/lib.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/unit_primitive_lib/lib.kt
new file mode 100644
index 0000000..65ae861
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/unit_primitive_lib/lib.kt
@@ -0,0 +1,26 @@
+// 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.kotlin.metadata.unit_primitive_lib
+
+class Lib {
+  fun testUnit() : Unit {
+    println("testUnit")
+  }
+
+  fun testInt() : Int {
+    return 42
+  }
+
+  fun testIntArray() : IntArray {
+    return intArrayOf(42)
+  }
+
+  fun testUInt() : UInt {
+    return 42u
+  }
+
+  fun testUIntArray() : UIntArray {
+    return uintArrayOf(42u)
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
index bcea2fe..42cd647 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
@@ -391,6 +391,7 @@
         .setMinApi(minSdk)
         .noMinification()
         .noTreeShaking()
+        .addDontOptimize()
         .setMainDexListConsumer(ToolHelper.consumeString(r8MainDexListOutput::set))
         .allowDiagnosticMessages()
         .compileWithExpectedDiagnostics(
diff --git a/src/test/java/com/android/tools/r8/resolution/InvokeCustomOnNonOverriddenInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/resolution/InvokeCustomOnNonOverriddenInterfaceMethodTest.java
new file mode 100644
index 0000000..eaf6a35
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/resolution/InvokeCustomOnNonOverriddenInterfaceMethodTest.java
@@ -0,0 +1,115 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.resolution;
+
+import static com.android.tools.r8.references.Reference.classFromClass;
+import static com.android.tools.r8.references.Reference.methodFromMethod;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.SingleTestRunResult;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.utils.structural.Ordered;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.WrongMethodTypeException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.objectweb.asm.Handle;
+import org.objectweb.asm.Opcodes;
+
+/** Regression for b/116283747. */
+@RunWith(Parameterized.class)
+public class InvokeCustomOnNonOverriddenInterfaceMethodTest extends TestBase {
+
+  private static final String[] EXPECTED = new String[] {"I.target"};
+
+  private final TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters()
+        .withAllRuntimes()
+        .withApiLevelsStartingAtIncluding(
+            Ordered.max(apiLevelWithInvokeCustomSupport(), apiLevelWithConstMethodHandleSupport()))
+        .build();
+  }
+
+  public InvokeCustomOnNonOverriddenInterfaceMethodTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testRuntime() throws Throwable {
+    testForRuntime(parameters)
+        .addProgramClasses(Main.class, I.class, Super.class)
+        .addProgramClassFileData(getInvokeCustomTransform())
+        .run(parameters.getRuntime(), Main.class)
+        .apply(this::checkRunResult);
+  }
+
+  private void checkRunResult(SingleTestRunResult<?> result) {
+    if (parameters.isCfRuntime()
+        || parameters.asDexRuntime().getVersion().isNewerThanOrEqual(Version.V10_0_0)) {
+      result.assertSuccessWithOutputLines(EXPECTED);
+    } else {
+      // Fails due to b/115964401.
+      assertEquals(Version.V9_0_0, parameters.getDexRuntimeVersion());
+      result.assertFailureWithErrorThatThrows(WrongMethodTypeException.class);
+    }
+  }
+
+  private static byte[] getInvokeCustomTransform() throws Throwable {
+    ClassReference symbolicHolder = classFromClass(InvokeCustom.class);
+    MethodReference method = methodFromMethod(InvokeCustom.class.getMethod("target"));
+    return transformer(InvokeCustom.class)
+        .transformMethodInsnInMethod(
+            "test",
+            (opcode, owner, name, descriptor, isInterface, visitor) -> {
+              // Replace null argument by a const method handle.
+              visitor.visitInsn(Opcodes.POP);
+              visitor.visitLdcInsn(
+                  new Handle(
+                      Opcodes.H_INVOKEVIRTUAL,
+                      symbolicHolder.getBinaryName(),
+                      method.getMethodName(),
+                      method.getMethodDescriptor(),
+                      false));
+              visitor.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+            })
+        .transform();
+  }
+
+  interface I {
+    default void target() {
+      System.out.println("I.target");
+    }
+  }
+
+  static class Super implements I {}
+
+  static class InvokeCustom extends Super {
+
+    public static void doInvokeExact(MethodHandle handle) throws Throwable {
+      handle.invokeExact(new InvokeCustom());
+    }
+
+    public static void test() throws Throwable {
+      doInvokeExact(null /* will be const method handle */);
+    }
+  }
+
+  static class Main {
+
+    public static void main(String[] args) throws Throwable {
+      InvokeCustom.test();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/resolution/InvokePolymorphicResolutionTest.java b/src/test/java/com/android/tools/r8/resolution/InvokePolymorphicResolutionTest.java
new file mode 100644
index 0000000..1b0af62
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/resolution/InvokePolymorphicResolutionTest.java
@@ -0,0 +1,70 @@
+// 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.resolution;
+
+import static com.android.tools.r8.references.Reference.classFromClass;
+import static com.android.tools.r8.references.Reference.methodFromMethod;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import com.android.tools.r8.TestAppViewBuilder;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.MethodResolutionResult;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.references.Reference;
+import java.lang.invoke.MethodHandle;
+import java.util.Collections;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class InvokePolymorphicResolutionTest extends TestBase {
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withNoneRuntime().build();
+  }
+
+  public InvokePolymorphicResolutionTest(TestParameters parameters) {
+    parameters.assertNoneRuntime();
+  }
+
+  @Test
+  public void testResolution() throws Exception {
+    // Note: this could just as well resolve without liveness.
+    AppView<? extends AppInfoWithClassHierarchy> appView =
+        TestAppViewBuilder.builder()
+            .addLibraryFiles(ToolHelper.getJava8RuntimeJar())
+            .buildWithLiveness();
+
+    // An exact resolution will find invokeExact.
+    MethodReference invokeExact =
+        methodFromMethod(MethodHandle.class.getMethod("invokeExact", Object[].class));
+    MethodResolutionResult resolution1 =
+        appView.appInfo().resolveMethod(buildMethod(invokeExact, appView.dexItemFactory()), false);
+    assertFalse(resolution1.isFailedResolution());
+
+    // An inexact signature should also find invokeExact.
+    MethodReference inexactInvokeExact =
+        Reference.method(
+            invokeExact.getHolderClass(),
+            invokeExact.getMethodName(),
+            Collections.singletonList(Reference.array(classFromClass(getClass()), 1)),
+            invokeExact.getReturnType());
+    MethodResolutionResult resolution2 =
+        appView
+            .appInfo()
+            .resolveMethod(buildMethod(inexactInvokeExact, appView.dexItemFactory()), false);
+    assertFalse(resolution2.isFailedResolution());
+
+    // The should both be the same MethodHandle.invokeExact method.
+    assertEquals(resolution1.getSingleTarget(), resolution2.getSingleTarget());
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/MissingInterfaceVirtualTargetsTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/MissingInterfaceVirtualTargetsTest.java
new file mode 100644
index 0000000..afb96e2
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/MissingInterfaceVirtualTargetsTest.java
@@ -0,0 +1,77 @@
+// 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.resolution.interfacetargets;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.StringUtils;
+import java.nio.file.Path;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class MissingInterfaceVirtualTargetsTest extends TestBase {
+
+  static final String EXPECTED = StringUtils.lines("I.foo", "I.foo");
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters()
+        .withAllRuntimes()
+        .withApiLevel(AndroidApiLevel.B)
+        .enableApiLevelsForCf()
+        .build();
+  }
+
+  public MissingInterfaceVirtualTargetsTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void test() throws Exception {
+    Path out =
+        testForD8(parameters.getBackend())
+            .addProgramClasses(TestClass.class)
+            .setMinApi(parameters.getApiLevel())
+            .compile()
+            .assertNoMessages()
+            .writeToZip();
+    testForD8(parameters.getBackend())
+        .addProgramClasses(I.class, A.class)
+        .setMinApi(parameters.getApiLevel())
+        .addRunClasspathFiles(out)
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  interface I {
+    default void foo() {
+      System.out.println("I.foo");
+    }
+  }
+
+  static class A implements I {
+    // No override.
+  }
+
+  static class TestClass {
+
+    static void targetI(I i) {
+      // This invoke-interface target should not cause missing class warnings.
+      i.foo();
+    }
+
+    public static void main(String[] args) {
+      A a = new A();
+      targetI(a);
+      // This invoke-virtual target should not cause missing class warnings.
+      a.foo();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java b/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java
index 252dcc5..d68447d 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java
@@ -105,6 +105,7 @@
         .addKeepMainRule(Main.class)
         .addKeepPackageNamesRule(getClass().getPackage())
         .noTreeShaking()
+        .addDontOptimize()
         .addKeepAttributeSourceFile()
         .addKeepAttributeLineNumberTable()
         .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceTests.java b/src/test/java/com/android/tools/r8/retrace/RetraceTests.java
index 4506755..8cc0883 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceTests.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceTests.java
@@ -35,6 +35,7 @@
 import com.android.tools.r8.retrace.stacktraces.InvalidStackTrace;
 import com.android.tools.r8.retrace.stacktraces.MemberFieldOverlapStackTrace;
 import com.android.tools.r8.retrace.stacktraces.MultipleDotsInFileNameStackTrace;
+import com.android.tools.r8.retrace.stacktraces.MultipleLinesNoLineNumberStackTrace;
 import com.android.tools.r8.retrace.stacktraces.NamedModuleStackTrace;
 import com.android.tools.r8.retrace.stacktraces.NoObfuscatedLineNumberWithOverrideTest;
 import com.android.tools.r8.retrace.stacktraces.NoObfuscationRangeMappingWithStackTrace;
@@ -276,6 +277,11 @@
     runRetraceTest(new SingleLineNoLineNumberStackTrace());
   }
 
+  @Test
+  public void testMultipleLinesNoLineNumberStackTrace() throws Exception {
+    runRetraceTest(new MultipleLinesNoLineNumberStackTrace());
+  }
+
   private void inspectRetraceTest(
       StackTraceForTest stackTraceForTest, Consumer<Retracer> inspection) {
     inspection.accept(
diff --git a/src/test/java/com/android/tools/r8/retrace/StackTraceRegularExpressionParserTests.java b/src/test/java/com/android/tools/r8/retrace/StackTraceRegularExpressionParserTests.java
index 40ec50f..f74fcda 100644
--- a/src/test/java/com/android/tools/r8/retrace/StackTraceRegularExpressionParserTests.java
+++ b/src/test/java/com/android/tools/r8/retrace/StackTraceRegularExpressionParserTests.java
@@ -416,7 +416,7 @@
 
           @Override
           public List<String> retracedStackTrace() {
-            return ImmutableList.of("com.android.tools.r8.R8.foo()");
+            return ImmutableList.of("com.android.tools.r8.R8.foo(7)");
           }
 
           @Override
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestHelper.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestHelper.java
index e73ce25..9c84754 100644
--- a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestHelper.java
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestHelper.java
@@ -43,7 +43,8 @@
           RetraceApiSynthesizedFieldTest.ApiTest.class,
           RetraceApiSynthesizedMethodTest.ApiTest.class,
           RetraceApiSynthesizedFrameTest.ApiTest.class,
-          RetraceApiSynthesizedInnerFrameTest.ApiTest.class);
+          RetraceApiSynthesizedInnerFrameTest.ApiTest.class,
+          RetraceApiUnknownJsonTest.ApiTest.class);
   public static List<Class<? extends RetraceApiBinaryTest>> CLASSES_PENDING_BINARY_COMPATIBILITY =
       ImmutableList.of();
 
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiUnknownJsonTest.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiUnknownJsonTest.java
new file mode 100644
index 0000000..f11a75f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiUnknownJsonTest.java
@@ -0,0 +1,94 @@
+// 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.retrace.api;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.Diagnostic;
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.retrace.ProguardMapProducer;
+import com.android.tools.r8.retrace.RetraceUnknownMappingInformationElement;
+import com.android.tools.r8.retrace.Retracer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class RetraceApiUnknownJsonTest extends RetraceApiTestBase {
+
+  public RetraceApiUnknownJsonTest(TestParameters parameters) {
+    super(parameters);
+  }
+
+  @Override
+  protected Class<? extends RetraceApiBinaryTest> binaryTestClass() {
+    return ApiTest.class;
+  }
+
+  public static class ApiTest implements RetraceApiBinaryTest {
+
+    private final String extraMapping =
+        "{\"id\":\"some.information.with.context\",\"value\":\"Hello World\"}";
+    private final String mapping =
+        "# { 'id': 'com.android.tools.r8.mapping', version: '1.0' }\n"
+            + "# { 'id': 'some.information.without.context' }\n"
+            + "some.Class -> a:\n"
+            + "# "
+            + extraMapping
+            + "\n"
+            + "# {'id': 'sourceFile','fileName':'SomeFileName.kt'}\n"
+            + "  1:3:int strawberry(int):99:101 -> s\n"
+            + "  4:5:int mango(float):121:122 -> s\n";
+
+    @Test
+    public void testRetracingSourceFile() {
+      TestDiagnosticsHandler diagnosticsHandler = new TestDiagnosticsHandler();
+      List<RetraceUnknownMappingInformationElement> mappingInfos =
+          Retracer.createDefault(ProguardMapProducer.fromString(mapping), diagnosticsHandler)
+              .retraceClass(Reference.classFromTypeName("a"))
+              .stream()
+              .flatMap(element -> element.getUnknownJsonMappingInformation().stream())
+              .collect(Collectors.toList());
+      assertEquals(1, mappingInfos.size());
+      RetraceUnknownMappingInformationElement unknownMapping = mappingInfos.get(0);
+      assertEquals("some.information.with.context", unknownMapping.getIdentifier());
+      assertEquals(extraMapping, unknownMapping.getPayLoad());
+
+      assertEquals(2, diagnosticsHandler.infoMessages.size());
+      assertEquals(
+          "Could not find a handler for some.information.without.context",
+          diagnosticsHandler.infoMessages.get(0).getDiagnosticMessage());
+      assertEquals(
+          "Could not find a handler for some.information.with.context",
+          diagnosticsHandler.infoMessages.get(1).getDiagnosticMessage());
+    }
+
+    private static class TestDiagnosticsHandler implements com.android.tools.r8.DiagnosticsHandler {
+
+      private List<Diagnostic> infoMessages = new ArrayList<>();
+
+      @Override
+      public void warning(Diagnostic warning) {
+        throw new RuntimeException("Warning not expected");
+      }
+
+      @Override
+      public void error(Diagnostic error) {
+        throw new RuntimeException("Error not expected");
+      }
+
+      @Override
+      public void info(Diagnostic info) {
+        DiagnosticsHandler.super.info(info);
+        infoMessages.add(info);
+      }
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/AmbiguousMethodVerboseStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/AmbiguousMethodVerboseStackTrace.java
index dcaaa58..3d3a1ee 100644
--- a/src/test/java/com/android/tools/r8/retrace/stacktraces/AmbiguousMethodVerboseStackTrace.java
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/AmbiguousMethodVerboseStackTrace.java
@@ -35,7 +35,7 @@
         "\tat com.android.tools.r8.naming.retrace.Main.c(Main.java)",
         "\tat com.android.tools.r8.naming.retrace.Main.com.android.Foo main("
             + "java.lang.String[])(Main.java)",
-        "\t<OR> at com.android.tools.r8.naming.retrace.Main.void main("
+        "\t<OR #1> at com.android.tools.r8.naming.retrace.Main.void main("
             + "com.android.Bar)(Main.java)",
         "\tat com.android.tools.r8.naming.retrace.Main.com.android.Foo main("
             + "java.lang.String[],com.android.Bar)(Main.java)");
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/AmbiguousMissingLineStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/AmbiguousMissingLineStackTrace.java
index b92190e..310390c 100644
--- a/src/test/java/com/android/tools/r8/retrace/stacktraces/AmbiguousMissingLineStackTrace.java
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/AmbiguousMissingLineStackTrace.java
@@ -27,13 +27,13 @@
     return Arrays.asList(
         "com.android.tools.r8.CompilationException: foo[parens](Source:3)",
         "    at com.android.tools.r8.R8.bar(R8.java:7)",
-        "    <OR> at com.android.tools.r8.R8.foo(R8.java:7)",
+        "    <OR #1> at com.android.tools.r8.R8.foo(R8.java:7)",
         "    at com.android.tools.r8.R8.bar(R8.java:8)",
-        "    <OR> at com.android.tools.r8.R8.foo(R8.java:8)",
+        "    <OR #1> at com.android.tools.r8.R8.foo(R8.java:8)",
         "    at com.android.tools.r8.R8.main(Unknown Source)",
         "Caused by: com.android.tools.r8.CompilationException: foo[parens](Source:3)",
         "    at com.android.tools.r8.R8.bar(R8.java:9)",
-        "    <OR> at com.android.tools.r8.R8.foo(R8.java:9)",
+        "    <OR #1> at com.android.tools.r8.R8.foo(R8.java:9)",
         "    ... 42 more");
   }
 
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/AmbiguousStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/AmbiguousStackTrace.java
index 429ee6b..38fbb08 100644
--- a/src/test/java/com/android/tools/r8/retrace/stacktraces/AmbiguousStackTrace.java
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/AmbiguousStackTrace.java
@@ -54,13 +54,13 @@
     return Arrays.asList(
         "com.android.tools.r8.CompilationException: foo[parens](Source:3)",
         "    at com.android.tools.r8.R8.bar(R8.java)",
-        "    <OR> at com.android.tools.r8.R8.foo(R8.java)",
+        "    <OR #1> at com.android.tools.r8.R8.foo(R8.java)",
         "    at com.android.tools.r8.R8.bar(R8.java)",
-        "    <OR> at com.android.tools.r8.R8.foo(R8.java)",
+        "    <OR #1> at com.android.tools.r8.R8.foo(R8.java)",
         "    at com.android.tools.r8.R8.main(Unknown Source)",
         "Caused by: com.android.tools.r8.CompilationException: foo[parens](Source:3)",
         "    at com.android.tools.r8.R8.bar(R8.java)",
-        "    <OR> at com.android.tools.r8.R8.foo(R8.java)",
+        "    <OR #1> at com.android.tools.r8.R8.foo(R8.java)",
         "    ... 42 more");
   }
 
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/MultipleLinesNoLineNumberStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/MultipleLinesNoLineNumberStackTrace.java
new file mode 100644
index 0000000..54ef0bf
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/MultipleLinesNoLineNumberStackTrace.java
@@ -0,0 +1,42 @@
+// 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.retrace.stacktraces;
+
+import com.android.tools.r8.utils.StringUtils;
+import java.util.Arrays;
+import java.util.List;
+
+public class MultipleLinesNoLineNumberStackTrace implements StackTraceForTest {
+
+  @Override
+  public List<String> obfuscatedStackTrace() {
+    return Arrays.asList(
+        "Exception in thread \"main\" java.lang.NullPointerException",
+        "\tat foo.a.a(Unknown Source)");
+  }
+
+  @Override
+  public String mapping() {
+    return StringUtils.lines(
+        "com.android.tools.r8.naming.retrace.Main -> foo.a:",
+        "    0:0:void method1(java.lang.String):42:42 -> a",
+        "    0:0:void main(java.lang.String[]):28 -> a",
+        "    1:1:void main(java.lang.String[]):153 -> a");
+  }
+
+  @Override
+  public List<String> retracedStackTrace() {
+    return Arrays.asList(
+        "Exception in thread \"main\" java.lang.NullPointerException",
+        "\tat com.android.tools.r8.naming.retrace.Main.main(Main.java)",
+        "\t<OR #1> at com.android.tools.r8.naming.retrace.Main.method1(Main.java)",
+        "\t<OR #1> at com.android.tools.r8.naming.retrace.Main.main(Main.java)");
+  }
+
+  @Override
+  public int expectedWarnings() {
+    return 0;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/NoObfuscatedLineNumberWithOverrideTest.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/NoObfuscatedLineNumberWithOverrideTest.java
index 3f11112..23c5652 100644
--- a/src/test/java/com/android/tools/r8/retrace/stacktraces/NoObfuscatedLineNumberWithOverrideTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/NoObfuscatedLineNumberWithOverrideTest.java
@@ -36,11 +36,11 @@
   public List<String> retracedStackTrace() {
     return Arrays.asList(
         "Exception in thread \"main\" java.lang.NullPointerException",
-        // TODO(b/191513686): Could be retrace to ...Main.main(Main.java:3)
-        "\tat com.android.tools.r8.naming.retrace.Main.main(Main.java)",
-        "\tat com.android.tools.r8.naming.retrace.Main.overload1(Main.java)",
-        "\t<OR> at com.android.tools.r8.naming.retrace.Main.overload2(Main.java)",
-        "\tat com.android.tools.r8.naming.retrace.Main.definedOverload(Main.java)",
+        "\tat com.android.tools.r8.naming.retrace.Main.main(Main.java:3)",
+        "\tat com.android.tools.r8.naming.retrace.Main.overload1(Main.java:7)",
+        "\t<OR #1> at com.android.tools.r8.naming.retrace.Main.overload2(Main.java:11)",
+        "\tat com.android.tools.r8.naming.retrace.Main.definedOverload(Main.java:7)",
+        "\t<OR #1> at com.android.tools.r8.naming.retrace.Main.definedOverload(Main.java:11)",
         "\tat com.android.tools.r8.naming.retrace.Main.mainPC(Main.java:42)");
   }
 
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/OverloadSameLineTest.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/OverloadSameLineTest.java
index d1659cd..f1fbedb 100644
--- a/src/test/java/com/android/tools/r8/retrace/stacktraces/OverloadSameLineTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/OverloadSameLineTest.java
@@ -32,8 +32,8 @@
         "Exception in thread \"main\" java.lang.NullPointerException",
         // TODO(b/199058242): Should be ambiguous and not inline frames
         "\tat com.android.tools.r8.naming.retrace.Main.overload(Main.java:7)",
-        "\t<OR> at com.android.tools.r8.naming.retrace.Main.overload(Main.java:15)",
-        "\t<OR> at com.android.tools.r8.naming.retrace.Main.overload(Main.java:13)");
+        "\t<OR #1> at com.android.tools.r8.naming.retrace.Main.overload(Main.java:15)",
+        "\t<OR #2> at com.android.tools.r8.naming.retrace.Main.overload(Main.java:13)");
   }
 
   @Override
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/SingleLineNoLineNumberStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/SingleLineNoLineNumberStackTrace.java
index 4f6ceb8..0b0c7ef 100644
--- a/src/test/java/com/android/tools/r8/retrace/stacktraces/SingleLineNoLineNumberStackTrace.java
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/SingleLineNoLineNumberStackTrace.java
@@ -16,7 +16,8 @@
         "Exception in thread \"main\" java.lang.NullPointerException",
         "\tat foo.a.a(Unknown Source)",
         "\tat foo.a.b(Unknown Source)",
-        "\tat foo.a.c(Unknown Source)");
+        "\tat foo.a.c(Unknown Source)",
+        "\tat foo.a.d(Unknown Source)");
   }
 
   @Override
@@ -26,20 +27,23 @@
         "    0:0:void method1(java.lang.String):42:42 -> a",
         "    0:0:void main(java.lang.String[]):28 -> a",
         "    0:0:void method2(java.lang.String):42:48 -> b",
-        "    0:0:void main2(java.lang.String[]):28 -> b",
-        "    void main3(java.lang.String[]):153 -> c");
+        "    0:0:void main2(java.lang.String[]):29 -> b",
+        "    void method3(java.lang.String):72:72 -> c",
+        "    void main3(java.lang.String[]):30 -> c",
+        "    void main4(java.lang.String[]):153 -> d");
   }
 
   @Override
   public List<String> retracedStackTrace() {
-    // TODO(b/191513686): Should have line-numbers for main, method1, main2 and main3.
     return Arrays.asList(
         "Exception in thread \"main\" java.lang.NullPointerException",
-        "\tat com.android.tools.r8.naming.retrace.Main.method1(Main.java)",
-        "\tat com.android.tools.r8.naming.retrace.Main.main(Main.java)",
-        "\tat com.android.tools.r8.naming.retrace.Main.method2(Main.java)",
-        "\tat com.android.tools.r8.naming.retrace.Main.main2(Main.java)",
-        "\tat com.android.tools.r8.naming.retrace.Main.main3(Main.java)");
+        "\tat com.android.tools.r8.naming.retrace.Main.method1(Main.java:42)",
+        "\tat com.android.tools.r8.naming.retrace.Main.main(Main.java:28)",
+        "\tat com.android.tools.r8.naming.retrace.Main.method2(Main.java:42)",
+        "\tat com.android.tools.r8.naming.retrace.Main.main2(Main.java:29)",
+        "\tat com.android.tools.r8.naming.retrace.Main.main3(Main.java:30)",
+        "\t<OR #1> at com.android.tools.r8.naming.retrace.Main.method3(Main.java:72)",
+        "\tat com.android.tools.r8.naming.retrace.Main.main4(Main.java:153)");
   }
 
   @Override
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/UnknownSourceStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/UnknownSourceStackTrace.java
index 76b89e4..13b8bdd 100644
--- a/src/test/java/com/android/tools/r8/retrace/stacktraces/UnknownSourceStackTrace.java
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/UnknownSourceStackTrace.java
@@ -27,13 +27,13 @@
     return Arrays.asList(
         "com.android.tools.r8.CompilationException: foo[parens](Source:3)",
         "    at com.android.tools.r8.R8.bar(R8.java)",
-        "    <OR> at com.android.tools.r8.R8.foo(R8.java)",
+        "    <OR #1> at com.android.tools.r8.R8.foo(R8.java)",
         "    at com.android.tools.r8.R8.bar(R8.java)",
-        "    <OR> at com.android.tools.r8.R8.foo(R8.java)",
+        "    <OR #1> at com.android.tools.r8.R8.foo(R8.java)",
         "    at com.android.tools.r8.R8.main(Unknown Source)",
         "Caused by: com.android.tools.r8.CompilationException: foo[parens](Source:3)",
         "    at com.android.tools.r8.R8.bar(R8.java)",
-        "    <OR> at com.android.tools.r8.R8.foo(R8.java)",
+        "    <OR #1> at com.android.tools.r8.R8.foo(R8.java)",
         "    ... 42 more");
   }
 
diff --git a/src/test/java/com/android/tools/r8/smali/OutlineTest.java b/src/test/java/com/android/tools/r8/smali/OutlineTest.java
index 21501d0..c9d30fd 100644
--- a/src/test/java/com/android/tools/r8/smali/OutlineTest.java
+++ b/src/test/java/com/android/tools/r8/smali/OutlineTest.java
@@ -85,6 +85,8 @@
     return options -> {
       // Disable inlining to make sure that code looks as expected.
       options.enableInlining = false;
+      // Disable the devirtulizer to not remove the super calls
+      options.enableDevirtualization = false;
       // Disable string concatenation optimization to not bother outlining of StringBuilder usage.
       options.enableStringConcatenationOptimization = false;
       // Also apply outline options.
diff --git a/third_party/retrace/binary_compatibility.tar.gz.sha1 b/third_party/retrace/binary_compatibility.tar.gz.sha1
index 8bdacb5..0aafcf6 100644
--- a/third_party/retrace/binary_compatibility.tar.gz.sha1
+++ b/third_party/retrace/binary_compatibility.tar.gz.sha1
@@ -1 +1 @@
-2d04d6851b1562286ababb9a4e128bd96a7823ab
\ No newline at end of file
+23a607be2e3644321df25d73e1db663ad06e79cb
\ No newline at end of file