Merge commit '4d7a9ae72060d1931d1117a79afd94f372d349e4' into dev-release
diff --git a/doc/retrace.md b/doc/retrace.md
index aaea59b..ea6a151 100644
--- a/doc/retrace.md
+++ b/doc/retrace.md
@@ -39,6 +39,8 @@
 Retracing tools supporting this versioning scheme should issue a warning when
 given mapping files with versions higher than the version supported by the tool.
 
+- Version 1.0 was introduced by R8 in version 3.1.21
+
 ### Source File
 
 The source file information states what source file a class originated from.
@@ -131,3 +133,144 @@
 since that method was not part of the input program it should not be in the
 output mapping information at all.
 
+### RewriteFrame (Introduced at version 2.0)
+
+The RewriteFrame information informs the retrace tool that when retracing a
+frame it should rewrite it. The mapping information has the form:
+
+```
+  # { id: 'com.android.tools.r8.rewriteFrame', "
+      conditions: ['throws(<exceptionDescriptor>)'],
+      actions: ['removeInnerFrames(<count>)'] }
+```
+
+The format is to specify conditions for when the rule should be applied and then
+describe the actions to take. The following conditions exist:
+
+- `throws(<exceptionDescriptor>)`: Will be true if the thrown exception above is
+`<exceptionDescriptor>`
+
+Conditions can be combined by adding more items to the list. The semantics of
+having more elements in the list is that the conditions are AND'ed together. To
+achieve OR one should duplicate the information.
+
+Actions describe what should happen to the retraced frames if the condition
+holds. Multiple specified actions will be applied from left to right. The
+following actions exist:
+
+- `removeInnerFrames(<count>)`: Will remove the number of frames starting with
+inner most frame. It is an error to specify a count higher than all frames.
+
+An example could be to remove an inlined frame if a null-pointer-exception is
+thrown:
+
+```
+some.Class -> a:
+  4:4:void other.Class.inlinee():23:23 -> a
+  4:4:void caller(other.Class):7 -> a\n"
+  # { id: 'com.android.tools.r8.rewriteFrame', "
+      conditions: ['throws(Ljava/lang/NullPointerException;)'],
+      actions: ['removeInnerFrames(1)'] }
+```
+
+When retracing:
+```
+Exception in thread "main" java.lang.NullPointerException: ...
+  at a.a(:4)
+```
+
+It will normally retrace to:
+```
+Exception in thread "main" java.lang.NullPointerException: ...
+  at other.Class.inlinee(Class.java:23)
+  at some.Class.caller(Class.java:7)
+```
+
+Amending the last mapping with the above inline information instructs the
+retracer to discard frames above, resulting in the retrace result:
+```
+Exception in thread "main" java.lang.NullPointerException: ...
+  at some.Class.caller(Class.java:7)
+```
+
+The `rewriteFrame` information will only be applied if the line that is being
+retraced is directly under the exception line.
+
+### Outline (Introduced at version 2.0)
+
+The outline information can be used by compilers to specify that a method is an
+outline. It has the following format:
+
+```
+# { 'id':'com.android.tools.r8.outline' }
+```
+
+When a retracer retraces a frame that has the outline mapping information it
+should carry the reported position to the next frame and use the
+`outlineCallsite` to obtain the correct position.
+
+### Outline Call Site (Introduced at version 2.0)
+
+A position in an outline can correspond to multiple different positions
+depending on the context. The information can be stored in the mapping file with
+the following format:
+
+```
+# { 'id':'com.android.tools.r8.outlineCallsite',
+    'positions': {
+        'outline_pos_1': callsite_pos_1,
+        'outline_pos_2': callsite_pos_2,
+         ...
+     }
+  }
+```
+
+The retracer should when seeing the `outline` information carry the line number
+to the next frame. The position should be rewritten by using the positions map
+before using the resulting position for further retracing. Here is an example:
+
+```
+# { id: 'com.android.tools.r8.mapping', version: '2.0' }
+outline.Class -> a:
+  1:2:int outline() -> a
+# { 'id':'com.android.tools.r8.outline' }
+some.Class -> b:
+  1:1:void foo.bar.Baz.qux():42:42 -> s
+  4:4:int outlineCaller(int):98:98 -> s
+  5:5:int outlineCaller(int):100:100 -> s
+  27:27:int outlineCaller(int):0:0 -> s
+# { 'id':'com.android.tools.r8.outlineCallsite',
+    'positions': { '1': 4, '2': 5 } }
+```
+
+Retracing the following stack trace lines:
+
+```
+  at a.a(:1)
+  at b.s(:27)
+```
+
+Should first retrace the first line and see it is an `outline` and then use
+the `outlineCallsite` for `b.s` at position `27` to map the read position `1` to
+position `4` and then use that to find the actual mapping, resulting in the
+retraced stack:
+
+```
+  at some.Class.outlineCaller(Class.java:98)
+```
+
+It should be such that for all stack traces, if a retracer ever see an outline
+the next obfuscated line should contain `outlineCallSite` information.
+
+### Catch all range for methods with a single unique position
+
+If only a single position is needed for retracing a method correctly one can
+skip emitting the position and rely on retrace to retrace correctly. To ensure
+compatibility R8 emits a catch-all range `0:65535` as such:
+
+```
+0:65535:void foo():33:33 -> a
+```
+
+It does not matter if the mapping is an inline frame. Catch all ranges should
+never be used for overloads.
\ No newline at end of file
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index cfb13ae..32e1f64 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -23,7 +23,6 @@
 import com.android.tools.r8.ir.analysis.proto.ProtoShrinker;
 import com.android.tools.r8.ir.analysis.value.AbstractValueFactory;
 import com.android.tools.r8.ir.desugar.PrefixRewritingMapper;
-import com.android.tools.r8.ir.optimize.CallSiteOptimizationInfoPropagator;
 import com.android.tools.r8.ir.optimize.enums.EnumDataMap;
 import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoFactory;
 import com.android.tools.r8.ir.optimize.library.LibraryMemberOptimizer;
@@ -93,7 +92,6 @@
 
   // Optimizations.
   private final ArgumentPropagator argumentPropagator;
-  private final CallSiteOptimizationInfoPropagator callSiteOptimizationInfoPropagator;
   private final LibraryMemberOptimizer libraryMemberOptimizer;
   private final ProtoShrinker protoShrinker;
 
@@ -131,17 +129,9 @@
     this.rewritePrefix = mapper;
 
     if (enableWholeProgramOptimizations() && options().callSiteOptimizationOptions().isEnabled()) {
-      if (options().callSiteOptimizationOptions().isExperimentalArgumentPropagationEnabled()) {
-        this.argumentPropagator = new ArgumentPropagator(withLiveness());
-        this.callSiteOptimizationInfoPropagator = null;
-      } else {
-        this.argumentPropagator = null;
-        this.callSiteOptimizationInfoPropagator =
-            new CallSiteOptimizationInfoPropagator(withLiveness());
-      }
+      this.argumentPropagator = new ArgumentPropagator(withLiveness());
     } else {
       this.argumentPropagator = null;
-      this.callSiteOptimizationInfoPropagator = null;
     }
 
     this.libraryMethodSideEffectModelCollection = new LibraryMethodSideEffectModelCollection(this);
@@ -344,10 +334,6 @@
     return appInfo.getSyntheticItems();
   }
 
-  public CallSiteOptimizationInfoPropagator callSiteOptimizationInfoPropagator() {
-    return callSiteOptimizationInfoPropagator;
-  }
-
   public <E extends Throwable> void withArgumentPropagator(
       ThrowingConsumer<ArgumentPropagator, E> consumer) throws E {
     if (argumentPropagator != null) {
@@ -355,13 +341,6 @@
     }
   }
 
-  public <E extends Throwable> void withCallSiteOptimizationInfoPropagator(
-      ThrowingConsumer<CallSiteOptimizationInfoPropagator, E> consumer) throws E {
-    if (callSiteOptimizationInfoPropagator != null) {
-      consumer.accept(callSiteOptimizationInfoPropagator);
-    }
-  }
-
   public LibraryMemberOptimizer libraryMethodOptimizer() {
     return libraryMemberOptimizer;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java b/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java
index f8bfbeb..8091db7 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java
@@ -256,7 +256,7 @@
     if (nextPosition.isOutline()) {
       events.add(factory.createSetOutlineFrame());
     }
-    if (nextPosition.getOutlineCallee() != null) {
+    if (nextPosition.getOutlineCallee() != null && !nextPosition.getOutlinePositions().isEmpty()) {
       events.add(
           factory.createSetOutlineCallerFrame(
               nextPosition.getOutlineCallee(), nextPosition.getOutlinePositions()));
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 d3be3c2..ccf7d83 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -16,7 +16,6 @@
 import static java.util.Objects.requireNonNull;
 
 import com.android.tools.r8.cf.CfVersion;
-import com.android.tools.r8.cf.code.CfConstNull;
 import com.android.tools.r8.cf.code.CfConstNumber;
 import com.android.tools.r8.cf.code.CfConstString;
 import com.android.tools.r8.cf.code.CfInstanceOf;
@@ -30,7 +29,6 @@
 import com.android.tools.r8.cf.code.CfStackInstruction.Opcode;
 import com.android.tools.r8.cf.code.CfStore;
 import com.android.tools.r8.cf.code.CfThrow;
-import com.android.tools.r8.code.Const4;
 import com.android.tools.r8.code.ConstString;
 import com.android.tools.r8.code.InstanceOf;
 import com.android.tools.r8.code.Instruction;
@@ -941,64 +939,6 @@
         null);
   }
 
-  public DexEncodedMethod toEmptyThrowingMethod(InternalOptions options) {
-    return options.isGeneratingClassFiles()
-        ? toEmptyThrowingMethodCf()
-        : toEmptyThrowingMethodDex(true);
-  }
-
-  public DexEncodedMethod toEmptyThrowingMethodDex(boolean setIsLibraryOverride) {
-    checkIfObsolete();
-    assert !shouldNotHaveCode();
-    Builder builder = builder(this);
-    builder.setCode(buildEmptyThrowingDexCode());
-    if (setIsLibraryOverride && isNonPrivateVirtualMethod()) {
-      builder.setIsLibraryMethodOverride(isLibraryMethodOverride());
-    }
-    DexEncodedMethod result = builder.build();
-    setObsolete();
-    return result;
-  }
-
-  private DexEncodedMethod toEmptyThrowingMethodCf() {
-    checkIfObsolete();
-    assert !shouldNotHaveCode();
-    Builder builder = builder(this);
-    builder.setCode(buildEmptyThrowingCfCode());
-    if (isNonPrivateVirtualMethod()) {
-      builder.setIsLibraryMethodOverride(isLibraryMethodOverride());
-    }
-    DexEncodedMethod result = builder.build();
-    setObsolete();
-    return result;
-  }
-
-  public Code buildEmptyThrowingCode(InternalOptions options) {
-    return options.isGeneratingClassFiles()
-        ? buildEmptyThrowingCfCode()
-        : buildEmptyThrowingDexCode();
-  }
-
-  public CfCode buildEmptyThrowingCfCode() {
-    return buildEmptyThrowingCfCode(getReference());
-  }
-
-  public static CfCode buildEmptyThrowingCfCode(DexMethod method) {
-    CfInstruction insn[] = {new CfConstNull(), new CfThrow()};
-    return new CfCode(
-        method.holder,
-        1,
-        method.proto.parameters.size() + 1,
-        Arrays.asList(insn),
-        Collections.emptyList(),
-        Collections.emptyList());
-  }
-
-  public DexCode buildEmptyThrowingDexCode() {
-    Instruction[] insn = {new Const4(0, 0), new Throw(0)};
-    return generateCodeFromTemplate(1, 0, insn);
-  }
-
   public Code buildInstanceOfCode(DexType type, boolean negate, InternalOptions options) {
     return options.isGeneratingClassFiles()
         ? buildInstanceOfCfCode(type, negate)
diff --git a/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java b/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java
index 287ef0f..1f845ed 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java
@@ -182,6 +182,12 @@
           || initialResolutionHolder.type == resolvedMethod.getHolderType();
     }
 
+    public SingleResolutionResult withInitialResolutionHolder(DexClass newInitialResolutionHolder) {
+      return newInitialResolutionHolder != initialResolutionHolder
+          ? new SingleResolutionResult(newInitialResolutionHolder, resolvedHolder, resolvedMethod)
+          : this;
+    }
+
     @Override
     public DexClass getInitialResolutionHolder() {
       return initialResolutionHolder;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/equivalence/BasicBlockBehavioralSubsumption.java b/src/main/java/com/android/tools/r8/ir/analysis/equivalence/BasicBlockBehavioralSubsumption.java
index 2fb3ef7..e901e23 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/equivalence/BasicBlockBehavioralSubsumption.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/equivalence/BasicBlockBehavioralSubsumption.java
@@ -18,6 +18,7 @@
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionIterator;
+import com.android.tools.r8.ir.code.InvokeDirect;
 import com.android.tools.r8.ir.code.Phi;
 import com.android.tools.r8.ir.code.Return;
 import com.android.tools.r8.ir.code.Value;
@@ -134,6 +135,26 @@
       }
     }
 
+    if (instruction.isInvokeConstructor(appView.dexItemFactory())) {
+      InvokeDirect invoke = instruction.asInvokeDirect();
+      if (otherInstruction.isInvokeConstructor(appView.dexItemFactory())) {
+        InvokeDirect otherInvoke = otherInstruction.asInvokeDirect();
+        // If neither has side effects, then continue.
+        DexClassAndMethod singleTarget = invoke.lookupSingleTarget(appView, context);
+        if (singleTarget == null
+            || singleTarget.getDefinition().getOptimizationInfo().mayHaveSideEffects()) {
+          return false;
+        }
+        DexClassAndMethod otherSingleTarget = otherInvoke.lookupSingleTarget(appView, context);
+        if (otherSingleTarget == null
+            || otherSingleTarget.getDefinition().getOptimizationInfo().mayHaveSideEffects()) {
+          return false;
+        }
+        return isSubsumedBy(iterator, otherIterator, visited);
+      }
+      return false;
+    }
+
     if (instruction.isReturn()) {
       Return returnInstruction = instruction.asReturn();
       if (otherInstruction.isReturn()) {
@@ -152,20 +173,7 @@
   }
 
   private boolean isBlockLocalInstructionWithoutSideEffects(Instruction instruction) {
-    if (!definesBlockLocalValue(instruction)) {
-      return false;
-    }
-    if (instruction.instructionMayHaveSideEffects(appView, context)) {
-      return false;
-    }
-    // For constructor calls include field initialization side effects.
-    if (instruction.isInvokeConstructor(appView.dexItemFactory())) {
-      DexClassAndMethod singleTarget =
-          instruction.asInvokeDirect().lookupSingleTarget(appView, context);
-      return singleTarget != null
-          && !singleTarget.getDefinition().getOptimizationInfo().mayHaveSideEffects();
-    }
-    return true;
+    return definesBlockLocalValue(instruction) && !instructionMayHaveSideEffects(instruction);
   }
 
   private boolean definesBlockLocalValue(Instruction instruction) {
@@ -188,7 +196,8 @@
   }
 
   private boolean instructionMayHaveSideEffects(Instruction instruction) {
-    return instruction.instructionMayHaveSideEffects(appView, context);
+    return instruction.isInvokeConstructor(appView.dexItemFactory())
+        || instruction.instructionMayHaveSideEffects(appView, context);
   }
 
   private boolean valuesAreIdentical(Value value, Value other) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java
index 30060d9..0303ba7 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java
@@ -11,7 +11,6 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexValue;
 import com.android.tools.r8.graph.DexValue.DexValueNull;
@@ -25,6 +24,7 @@
 import com.android.tools.r8.ir.analysis.value.UnknownValue;
 import com.android.tools.r8.ir.analysis.value.objectstate.EnumValuesObjectState;
 import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
+import com.android.tools.r8.ir.analysis.value.objectstate.ObjectStateAnalysis;
 import com.android.tools.r8.ir.code.ArrayPut;
 import com.android.tools.r8.ir.code.FieldInstruction;
 import com.android.tools.r8.ir.code.IRCode;
@@ -35,8 +35,6 @@
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.ir.optimize.ClassInitializerDefaultsOptimization.ClassInitializerDefaultsResult;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
-import com.android.tools.r8.ir.optimize.info.field.InstanceFieldArgumentInitializationInfo;
-import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoCollection;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.Timing;
 import java.util.IdentityHashMap;
@@ -240,7 +238,7 @@
       // This implicitely answers null if the value could not get computed.
       if (valuesValue.isSingleFieldValue()) {
         SingleFieldValue fieldValue = valuesValue.asSingleFieldValue();
-        if (fieldValue.getState().isEnumValuesObjectState()) {
+        if (fieldValue.getObjectState().isEnumValuesObjectState()) {
           return fieldValue;
         }
       }
@@ -439,62 +437,12 @@
   }
 
   private ObjectState computeObjectState(Value value) {
-    assert !value.hasAliasedValue();
-    if (!value.isDefinedByInstructionSatisfying(Instruction::isNewInstance)) {
-      return ObjectState.empty();
-    }
-
-    NewInstance newInstance = value.definition.asNewInstance();
-    InvokeDirect uniqueConstructorInvoke =
-        newInstance.getUniqueConstructorInvoke(appView.dexItemFactory());
-    if (uniqueConstructorInvoke == null) {
-      return ObjectState.empty();
-    }
-
-    DexClassAndMethod singleTarget = uniqueConstructorInvoke.lookupSingleTarget(appView, context);
-    if (singleTarget == null) {
-      return ObjectState.empty();
-    }
-
-    InstanceFieldInitializationInfoCollection initializationInfos =
-        singleTarget
-            .getDefinition()
-            .getOptimizationInfo()
-            .getInstanceInitializerInfo(uniqueConstructorInvoke)
-            .fieldInitializationInfos();
-    if (initializationInfos.isEmpty()) {
-      return ObjectState.empty();
-    }
-
-    ObjectState.Builder builder = ObjectState.builder();
-    initializationInfos.forEach(
-        appView,
-        (field, initializationInfo) -> {
-          // If the instance field is not written only in the instance initializer, then we can't
-          // conclude that this field will have a constant value.
-          //
-          // We have special handling for library fields that satisfy the property that they are
-          // only written in their corresponding instance initializers. This is needed since we
-          // don't analyze these instance initializers in the Enqueuer, as they are in the library.
-          if (!appView.appInfo().isInstanceFieldWrittenOnlyInInstanceInitializers(field)
-              && !appView.dexItemFactory().enumMembers.isNameOrOrdinalField(field.getReference())) {
-            return;
-          }
-          if (initializationInfo.isArgumentInitializationInfo()) {
-            InstanceFieldArgumentInitializationInfo argumentInitializationInfo =
-                initializationInfo.asArgumentInitializationInfo();
-            Value argument =
-                uniqueConstructorInvoke.getArgument(argumentInitializationInfo.getArgumentIndex());
-            builder.recordFieldHasValue(field, argument.getAbstractValue(appView, context));
-          } else if (initializationInfo.isSingleValue()) {
-            builder.recordFieldHasValue(field, initializationInfo.asSingleValue());
-          }
-        });
-    return builder.build();
+    // TODO(b/204159267): Move this logic into Instruction#getAbstractValue in NewInstance.
+    return ObjectStateAnalysis.computeObjectState(value, appView, context);
   }
 
   private boolean isEnumValuesArray(Value value) {
     SingleFieldValue singleFieldValue = computeSingleEnumFieldValueForValuesArray(value);
-    return singleFieldValue != null && singleFieldValue.getState().isEnumValuesObjectState();
+    return singleFieldValue != null && singleFieldValue.getObjectState().isEnumValuesObjectState();
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValues.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValues.java
index 0b9a6cd..e57052f 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValues.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValues.java
@@ -59,17 +59,18 @@
           DexEncodedField staticField, AbstractValue value, DexItemFactory factory) {
         if (factory.enumMembers.isValuesFieldCandidate(staticField, staticField.getHolderType())) {
           if (value.isSingleFieldValue()
-              && value.asSingleFieldValue().getState().isEnumValuesObjectState()) {
+              && value.asSingleFieldValue().getObjectState().isEnumValuesObjectState()) {
             assert valuesCandidateAbstractValue == null
                 || valuesCandidateAbstractValue.equals(value);
             valuesCandidateAbstractValue = value;
             enumObjectStateBuilder.put(
-                staticField.getReference(), value.asSingleFieldValue().getState());
+                staticField.getReference(), value.asSingleFieldValue().getObjectState());
           }
         } else if (factory.enumMembers.isEnumField(staticField, staticField.getHolderType())) {
-          if (value.isSingleFieldValue() && !value.asSingleFieldValue().getState().isEmpty()) {
+          if (value.isSingleFieldValue()
+              && !value.asSingleFieldValue().getObjectState().isEmpty()) {
             enumObjectStateBuilder.put(
-                staticField.getReference(), value.asSingleFieldValue().getState());
+                staticField.getReference(), value.asSingleFieldValue().getObjectState());
           }
         }
       }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java
index d69ca26..854ea6d 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 public abstract class AbstractValue {
@@ -57,14 +58,32 @@
     return null;
   }
 
-  public boolean isKnownLengthArrayValue() {
+  public boolean hasObjectState() {
     return false;
   }
 
-  public KnownLengthArrayValue asKnownLengthArrayValue() {
+  public ObjectState getObjectState() {
+    throw new UnsupportedOperationException(
+        "Abstract value " + this + " does not have any object state.");
+  }
+
+  public boolean isStatefulObjectValue() {
+    return false;
+  }
+
+  public StatefulObjectValue asStatefulObjectValue() {
     return null;
   }
 
+  public boolean hasKnownArrayLength() {
+    return false;
+  }
+
+  public int getKnownArrayLength() {
+    throw new UnsupportedOperationException(
+        "Abstract value " + this + " does not have a known array length.");
+  }
+
   public boolean isSingleConstValue() {
     return false;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueFactory.java b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueFactory.java
index e1cdb6c..bc1a554 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueFactory.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueFactory.java
@@ -8,6 +8,7 @@
 import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.analysis.value.objectstate.KnownLengthArrayState;
 import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
 import com.android.tools.r8.naming.dexitembasedstring.NameComputationInfo;
 import java.util.concurrent.ConcurrentHashMap;
@@ -19,15 +20,15 @@
   private ConcurrentHashMap<Long, SingleNumberValue> singleNumberValues = new ConcurrentHashMap<>();
   private ConcurrentHashMap<DexString, SingleStringValue> singleStringValues =
       new ConcurrentHashMap<>();
-  private ConcurrentHashMap<Integer, KnownLengthArrayValue> knownArrayLengthValues =
+  private ConcurrentHashMap<Integer, KnownLengthArrayState> knownArrayLengthStates =
       new ConcurrentHashMap<>();
 
   public SingleConstClassValue createSingleConstClassValue(DexType type) {
     return singleConstClassValues.computeIfAbsent(type, SingleConstClassValue::new);
   }
 
-  public AbstractValue createKnownLengthArrayValue(int length) {
-    return knownArrayLengthValues.computeIfAbsent(length, KnownLengthArrayValue::new);
+  public KnownLengthArrayState createKnownLengthArrayState(int length) {
+    return knownArrayLengthStates.computeIfAbsent(length, KnownLengthArrayState::new);
   }
 
   public SingleFieldValue createSingleFieldValue(DexField field, ObjectState state) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/KnownLengthArrayValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/KnownLengthArrayValue.java
deleted file mode 100644
index 9721031..0000000
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/KnownLengthArrayValue.java
+++ /dev/null
@@ -1,57 +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.ir.analysis.value;
-
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-
-/** A KnownLengthArrayValue implicitly implies the value is non null. */
-public class KnownLengthArrayValue extends AbstractValue {
-
-  private final int length;
-
-  public KnownLengthArrayValue(int length) {
-    this.length = length;
-  }
-
-  public int getLength() {
-    return length;
-  }
-
-  @Override
-  public boolean isKnownLengthArrayValue() {
-    return true;
-  }
-
-  @Override
-  public KnownLengthArrayValue asKnownLengthArrayValue() {
-    return this;
-  }
-
-  @Override
-  public boolean isNonTrivial() {
-    return true;
-  }
-
-  @Override
-  public AbstractValue rewrittenWithLens(AppView<AppInfoWithLiveness> appView, GraphLens lens) {
-    return this;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    return this == o;
-  }
-
-  @Override
-  public int hashCode() {
-    return System.identityHashCode(this);
-  }
-
-  @Override
-  public String toString() {
-    return "KnownLengthArrayValue(len=" + length + ")";
-  }
-}
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 71a6dbf..b499b81 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
@@ -48,7 +48,11 @@
     return field.lookupOnClass(holder);
   }
 
-  public abstract ObjectState getState();
+  @Override
+  public abstract ObjectState getObjectState();
+
+  @Override
+  public abstract boolean hasObjectState();
 
   public boolean mayHaveFinalizeMethodDirectlyOrIndirectly(AppView<AppInfoWithLiveness> appView) {
     DexType fieldType = field.type;
@@ -140,6 +144,6 @@
       }
     }
     return factory.createSingleFieldValue(
-        lens.lookupField(field), getState().rewrittenWithLens(appView, lens));
+        lens.lookupField(field), getObjectState().rewrittenWithLens(appView, lens));
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStatefulFieldValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStatefulFieldValue.java
index d14f5a9..4191a9c 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStatefulFieldValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStatefulFieldValue.java
@@ -20,7 +20,22 @@
   }
 
   @Override
-  public ObjectState getState() {
+  public boolean hasKnownArrayLength() {
+    return getObjectState().hasKnownArrayLength();
+  }
+
+  @Override
+  public int getKnownArrayLength() {
+    return getObjectState().getKnownArrayLength();
+  }
+
+  @Override
+  public boolean hasObjectState() {
+    return true;
+  }
+
+  @Override
+  public ObjectState getObjectState() {
     return state;
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStatelessFieldValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStatelessFieldValue.java
index 809b365..8a58dfe 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStatelessFieldValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStatelessFieldValue.java
@@ -15,18 +15,23 @@
   }
 
   @Override
-  public ObjectState getState() {
+  public ObjectState getObjectState() {
     return ObjectState.empty();
   }
 
   @Override
+  public boolean hasObjectState() {
+    return false;
+  }
+
+  @Override
   public String toString() {
     return "SingleStatelessFieldValue(" + field.toSourceString() + ")";
   }
 
   @Override
   public boolean equals(Object o) {
-    if (getClass() != o.getClass()) {
+    if (o == null || getClass() != o.getClass()) {
       return false;
     }
     SingleStatelessFieldValue singleFieldValue = (SingleStatelessFieldValue) o;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/StatefulObjectValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/StatefulObjectValue.java
new file mode 100644
index 0000000..39174da
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/StatefulObjectValue.java
@@ -0,0 +1,85 @@
+// 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.analysis.value;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+
+/** A KnownLengthArrayValue implicitly implies the value is non null. */
+public class StatefulObjectValue extends AbstractValue {
+
+  private final ObjectState state;
+
+  StatefulObjectValue(ObjectState state) {
+    assert !state.isEmpty();
+    this.state = state;
+  }
+
+  public static AbstractValue create(ObjectState objectState) {
+    return objectState.isEmpty()
+        ? UnknownValue.getInstance()
+        : new StatefulObjectValue(objectState);
+  }
+
+  @Override
+  public boolean isNonTrivial() {
+    return true;
+  }
+
+  @Override
+  public boolean isStatefulObjectValue() {
+    return true;
+  }
+
+  @Override
+  public StatefulObjectValue asStatefulObjectValue() {
+    return this;
+  }
+
+  @Override
+  public boolean hasKnownArrayLength() {
+    return getObjectState().hasKnownArrayLength();
+  }
+
+  @Override
+  public int getKnownArrayLength() {
+    return getObjectState().getKnownArrayLength();
+  }
+
+  @Override
+  public AbstractValue rewrittenWithLens(AppView<AppInfoWithLiveness> appView, GraphLens lens) {
+    return create(getObjectState().rewrittenWithLens(appView, lens));
+  }
+
+  @Override
+  public boolean hasObjectState() {
+    return true;
+  }
+
+  @Override
+  public ObjectState getObjectState() {
+    return state;
+  }
+
+  @Override
+  public String toString() {
+    return "StatefulValue";
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (getClass() != o.getClass()) {
+      return false;
+    }
+    StatefulObjectValue statefulObjectValue = (StatefulObjectValue) o;
+    return state.equals(statefulObjectValue.state);
+  }
+
+  @Override
+  public int hashCode() {
+    return state.hashCode();
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/EnumValuesObjectState.java b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/EnumValuesObjectState.java
index 397e79f..817b166 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/EnumValuesObjectState.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/EnumValuesObjectState.java
@@ -45,6 +45,16 @@
   }
 
   @Override
+  public boolean hasKnownArrayLength() {
+    return true;
+  }
+
+  @Override
+  public int getKnownArrayLength() {
+    return state.length;
+  }
+
+  @Override
   public boolean isEnumValuesObjectState() {
     return true;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/KnownLengthArrayState.java b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/KnownLengthArrayState.java
new file mode 100644
index 0000000..a379776
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/KnownLengthArrayState.java
@@ -0,0 +1,63 @@
+// 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.analysis.value.objectstate;
+
+import com.android.tools.r8.graph.AppView;
+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.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.analysis.value.UnknownValue;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import java.util.function.BiConsumer;
+
+public class KnownLengthArrayState extends ObjectState {
+
+  private final int length;
+
+  public KnownLengthArrayState(int length) {
+    this.length = length;
+  }
+
+  @Override
+  public void forEachAbstractFieldValue(BiConsumer<DexField, AbstractValue> consumer) {
+    // Intentionally empty.
+  }
+
+  @Override
+  public AbstractValue getAbstractFieldValue(DexEncodedField field) {
+    return UnknownValue.getInstance();
+  }
+
+  @Override
+  public boolean isEmpty() {
+    return false;
+  }
+
+  @Override
+  public boolean hasKnownArrayLength() {
+    return true;
+  }
+
+  @Override
+  public int getKnownArrayLength() {
+    return length;
+  }
+
+  @Override
+  public ObjectState rewrittenWithLens(AppView<AppInfoWithLiveness> appView, GraphLens lens) {
+    return this;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    return this == o;
+  }
+
+  @Override
+  public int hashCode() {
+    return System.identityHashCode(this);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/ObjectState.java b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/ObjectState.java
index f709c59..b81fb32 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/ObjectState.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/ObjectState.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.ir.analysis.value.objectstate;
 
+import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexField;
@@ -58,6 +59,15 @@
   @Override
   public abstract int hashCode();
 
+  public boolean hasKnownArrayLength() {
+    return false;
+  }
+
+  public int getKnownArrayLength() {
+    // Override this method if hasKnownArrayLength answers true.
+    throw new Unreachable();
+  }
+
   public boolean isEnumValuesObjectState() {
     return false;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/ObjectStateAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/ObjectStateAnalysis.java
new file mode 100644
index 0000000..125acfa
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/ObjectStateAnalysis.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.ir.analysis.value.objectstate;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.InvokeDirect;
+import com.android.tools.r8.ir.code.NewInstance;
+import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.optimize.info.field.InstanceFieldArgumentInitializationInfo;
+import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoCollection;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+
+public class ObjectStateAnalysis {
+
+  public static ObjectState computeObjectState(
+      Value value, AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
+    assert !value.hasAliasedValue();
+    if (value.isDefinedByInstructionSatisfying(
+        i -> i.isNewArrayEmpty() || i.isNewArrayFilledData() || i.isInvokeNewArray())) {
+      return computeNewArrayObjectState(value, appView, context);
+    }
+    if (value.isDefinedByInstructionSatisfying(Instruction::isNewInstance)) {
+      return computeNewInstanceObjectState(value, appView, context);
+    }
+    return ObjectState.empty();
+  }
+
+  private static ObjectState computeNewArrayObjectState(
+      Value value, AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
+    AbstractValue abstractValue = value.definition.getAbstractValue(appView, context);
+    if (abstractValue.isStatefulObjectValue()) {
+      // TODO(b/204272377): Avoid wrapping and unwrapping the object state.
+      return abstractValue.asStatefulObjectValue().getObjectState();
+    }
+    return ObjectState.empty();
+  }
+
+  private static ObjectState computeNewInstanceObjectState(
+      Value value, AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
+    NewInstance newInstance = value.definition.asNewInstance();
+    InvokeDirect uniqueConstructorInvoke =
+        newInstance.getUniqueConstructorInvoke(appView.dexItemFactory());
+    if (uniqueConstructorInvoke == null) {
+      return ObjectState.empty();
+    }
+
+    DexClassAndMethod singleTarget = uniqueConstructorInvoke.lookupSingleTarget(appView, context);
+    if (singleTarget == null) {
+      return ObjectState.empty();
+    }
+
+    InstanceFieldInitializationInfoCollection initializationInfos =
+        singleTarget
+            .getDefinition()
+            .getOptimizationInfo()
+            .getInstanceInitializerInfo(uniqueConstructorInvoke)
+            .fieldInitializationInfos();
+    if (initializationInfos.isEmpty()) {
+      return ObjectState.empty();
+    }
+
+    ObjectState.Builder builder = ObjectState.builder();
+    initializationInfos.forEach(
+        appView,
+        (field, initializationInfo) -> {
+          // If the instance field is not written only in the instance initializer, then we can't
+          // conclude that this field will have a constant value.
+          //
+          // We have special handling for library fields that satisfy the property that they are
+          // only written in their corresponding instance initializers. This is needed since we
+          // don't analyze these instance initializers in the Enqueuer, as they are in the library.
+          if (!appView.appInfo().isInstanceFieldWrittenOnlyInInstanceInitializers(field)
+              && !appView.dexItemFactory().enumMembers.isNameOrOrdinalField(field.getReference())) {
+            return;
+          }
+          if (initializationInfo.isArgumentInitializationInfo()) {
+            InstanceFieldArgumentInitializationInfo argumentInitializationInfo =
+                initializationInfo.asArgumentInitializationInfo();
+            Value argument =
+                uniqueConstructorInvoke.getArgument(argumentInitializationInfo.getArgumentIndex());
+            builder.recordFieldHasValue(field, argument.getAbstractValue(appView, context));
+          } else if (initializationInfo.isSingleValue()) {
+            builder.recordFieldHasValue(field, initializationInfo.asSingleValue());
+          }
+        });
+    return builder.build();
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java b/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java
index 9aff428..e1bb5bf 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java
@@ -276,10 +276,10 @@
       return true;
     }
     AbstractValue abstractValue = array().getAliasedValue().getAbstractValue(appView, context);
-    if (!abstractValue.isKnownLengthArrayValue()) {
+    if (!abstractValue.hasKnownArrayLength()) {
       return true;
     }
-    int newArraySize = abstractValue.asKnownLengthArrayValue().getLength();
+    int newArraySize = abstractValue.getKnownArrayLength();
     int index = index().getConstInstruction().asConstNumber().getIntValue();
     return newArraySize <= 0 || index < 0 || newArraySize <= index;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java b/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
index cad5e1d..636468c 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
@@ -15,6 +15,9 @@
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.type.Nullability;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.analysis.value.StatefulObjectValue;
+import com.android.tools.r8.ir.analysis.value.UnknownValue;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
@@ -140,6 +143,17 @@
   }
 
   @Override
+  public AbstractValue getAbstractValue(
+      AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
+    if (!instructionMayHaveSideEffects(appView, context)) {
+      int size = inValues.size();
+      return StatefulObjectValue.create(
+          appView.abstractValueFactory().createKnownLengthArrayState(size));
+    }
+    return UnknownValue.getInstance();
+  }
+
+  @Override
   public boolean instructionInstanceCanThrow(AppView<?> appView, ProgramMethod context) {
     DexType baseType = type.isArrayType() ? type.toBaseType(appView.dexItemFactory()) : type;
     if (baseType.isPrimitiveType()) {
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java b/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
index 3ddbcbd..3be3d3d 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
@@ -14,6 +14,7 @@
 import com.android.tools.r8.ir.analysis.type.Nullability;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.analysis.value.StatefulObjectValue;
 import com.android.tools.r8.ir.analysis.value.UnknownValue;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
@@ -90,9 +91,10 @@
       AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
     if (!instructionMayHaveSideEffects(appView, context) && size().getType().isInt()) {
       assert !instructionInstanceCanThrow();
-      return appView
-          .abstractValueFactory()
-          .createKnownLengthArrayValue(size().definition.asConstNumber().getIntValue());
+      return StatefulObjectValue.create(
+          appView
+              .abstractValueFactory()
+              .createKnownLengthArrayState(size().definition.asConstNumber().getIntValue()));
     }
     return UnknownValue.getInstance();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java b/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java
index ce235d4..fb04f03 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java
@@ -11,6 +11,7 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.analysis.value.StatefulObjectValue;
 import com.android.tools.r8.ir.analysis.value.UnknownValue;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
@@ -127,7 +128,8 @@
       AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
     if (!instructionMayHaveSideEffects(appView, context) && size <= Integer.MAX_VALUE) {
       assert !instructionInstanceCanThrow();
-      return appView.abstractValueFactory().createKnownLengthArrayValue((int) size);
+      return StatefulObjectValue.create(
+          appView.abstractValueFactory().createKnownLengthArrayState((int) size));
     }
     return UnknownValue.getInstance();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Position.java b/src/main/java/com/android/tools/r8/ir/code/Position.java
index cf718aa..47549e9 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Position.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Position.java
@@ -544,6 +544,10 @@
         return this;
       }
 
+      public boolean hasOutlinePositions() {
+        return !outlinePositionsBuilder.isEmpty();
+      }
+
       @Override
       public OutlineCallerPosition build() {
         assert noCheckOfPosition || line >= 0;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index b6fcd8c..40cb9e9 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -760,16 +760,10 @@
       //  !appView.hasLiveness() (which currently may happen due to the reflective behavior
       //  handling in the final round of tree shaking).
       if (appView.hasLiveness()) {
-        if (appView
-                .options()
-                .callSiteOptimizationOptions()
-                .isExperimentalArgumentPropagationEnabled()
-            || appView.callSiteOptimizationInfoPropagator().getMode().isRevisit()) {
-          ArgumentPropagatorIROptimizer.optimize(
-              appView.withLiveness(),
-              ir,
-              callSiteOptimizationInfo.asConcreteCallSiteOptimizationInfo());
-        }
+        ArgumentPropagatorIROptimizer.optimize(
+            appView.withLiveness(),
+            ir,
+            callSiteOptimizationInfo.asConcreteCallSiteOptimizationInfo());
       }
     }
 
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 316fdb9..ce9faef 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
@@ -64,7 +64,6 @@
 import com.android.tools.r8.ir.desugar.nest.D8NestBasedAccessDesugaring;
 import com.android.tools.r8.ir.optimize.AssertionsRewriter;
 import com.android.tools.r8.ir.optimize.AssumeInserter;
-import com.android.tools.r8.ir.optimize.CallSiteOptimizationInfoPropagator;
 import com.android.tools.r8.ir.optimize.ClassInitializerDefaultsOptimization;
 import com.android.tools.r8.ir.optimize.ClassInitializerDefaultsOptimization.ClassInitializerDefaultsResult;
 import com.android.tools.r8.ir.optimize.CodeRewriter;
@@ -132,7 +131,7 @@
   public final AppView<?> appView;
 
   private final Timing timing;
-  private final Outliner outliner;
+  public final Outliner outliner;
   private final ClassInitializerDefaultsOptimization classInitializerDefaultsOptimization;
   private final CfInstructionDesugaringCollection instructionDesugaring;
   private final FieldAccessAnalysis fieldAccessAnalysis;
@@ -146,7 +145,7 @@
   private final CfgPrinter printer;
   public final CodeRewriter codeRewriter;
   private final ConstantCanonicalizer constantCanonicalizer;
-  private final MemberValuePropagation memberValuePropagation;
+  public final MemberValuePropagation memberValuePropagation;
   private final LensCodeRewriter lensCodeRewriter;
   private final Inliner inliner;
   private final IdentifierNameStringMarker identifierNameStringMarker;
@@ -652,13 +651,6 @@
     // Setup optimizations for the primary optimization pass.
     appView.withArgumentPropagator(
         argumentPropagator -> argumentPropagator.initializeCodeScanner(executorService, timing));
-    appView.withCallSiteOptimizationInfoPropagator(
-        optimization -> {
-          optimization.abandonCallSitePropagationForLambdaImplementationMethods(
-              executorService, timing);
-          optimization.abandonCallSitePropagationForPinnedMethodsAndOverrides(
-              executorService, timing);
-        });
     enumUnboxer.prepareForPrimaryOptimizationPass(graphLensForPrimaryOptimizationPass);
     ConsumerUtils.acceptIfNotNull(
         classStaticizer,
@@ -719,10 +711,6 @@
         argumentPropagator ->
             argumentPropagator.tearDownCodeScanner(
                 this, postMethodProcessorBuilder, executorService, timing));
-    appView.withCallSiteOptimizationInfoPropagator(
-        callSiteOptimizationInfoPropagator ->
-            callSiteOptimizationInfoPropagator.enqueueMethodsForReprocessing(
-                postMethodProcessorBuilder));
 
     if (libraryMethodOverrideAnalysis != null) {
       libraryMethodOverrideAnalysis.finish();
@@ -815,8 +803,6 @@
     }
 
     if (Log.ENABLED) {
-      appView.withCallSiteOptimizationInfoPropagator(
-          CallSiteOptimizationInfoPropagator::logResults);
       constantCanonicalizer.logResults();
       if (idempotentFunctionCallCanonicalizer != null) {
         idempotentFunctionCallCanonicalizer.logResults();
@@ -1576,15 +1562,6 @@
       timing.end();
     }
 
-    // Arguments can be changed during the debug mode.
-    boolean isDebugMode =
-        options.debug || method.getDefinition().getOptimizationInfo().isReachabilitySensitive();
-    if (!isDebugMode && appView.callSiteOptimizationInfoPropagator() != null) {
-      timing.begin("Collect call-site info");
-      appView.callSiteOptimizationInfoPropagator().collectCallSiteOptimizationInfo(code, timing);
-      timing.end();
-    }
-
     if (appView.getKeepInfo(code.context()).isPinned(options)) {
       return;
     }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
index 7226037..0dc7375 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
@@ -32,6 +32,7 @@
 import com.android.tools.r8.graph.InvalidCode;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.ThrowNullCode;
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.itf.EmulatedInterfaceSynthesizerEventConsumer.ClasspathEmulatedInterfaceSynthesizerEventConsumer;
 import com.android.tools.r8.synthesis.SyntheticClassBuilder;
@@ -223,7 +224,7 @@
             methodBuilder ->
                 methodBuilder
                     .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic())
-                    .setCode(DexEncodedMethod::buildEmptyThrowingCfCode));
+                    .setCode(ignore -> ThrowNullCode.get()));
   }
 
   DexClassAndMethod ensureDefaultAsMethodOfCompanionClassStub(DexClassAndMethod method) {
@@ -357,7 +358,7 @@
             methodBuilder ->
                 methodBuilder
                     .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic())
-                    .setCode(DexEncodedMethod::buildEmptyThrowingCfCode));
+                    .setCode(ignore -> ThrowNullCode.get()));
   }
 
   ProgramMethod ensureStaticAsMethodOfProgramCompanionClassStub(
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index bcd27e6..dae6f04 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -3451,7 +3451,7 @@
       }
 
       AbstractValue abstractValue = array.getAbstractValue(appView, code.context());
-      if (!abstractValue.isKnownLengthArrayValue() && !array.isNeverNull()) {
+      if (!abstractValue.hasKnownArrayLength() && !array.isNeverNull()) {
         continue;
       }
       Instruction arrayDefinition = array.getDefinition();
@@ -3468,15 +3468,13 @@
           continue;
         }
         iterator.replaceCurrentInstructionWithConstInt(code, (int) size);
-      } else if (abstractValue.isKnownLengthArrayValue()) {
-        iterator.replaceCurrentInstructionWithConstInt(
-            code, abstractValue.asKnownLengthArrayValue().getLength());
+      } else if (abstractValue.hasKnownArrayLength()) {
+        iterator.replaceCurrentInstructionWithConstInt(code, abstractValue.getKnownArrayLength());
       } else {
         continue;
       }
 
       phiUsers.forEach(Phi::removeTrivialPhi);
-      // TODO(139489070): static-get of constant array
     }
     assert code.isConsistentSSA();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
index 9e8d052..206c455 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
@@ -401,12 +401,8 @@
       if (abstractValue.isUnknown() && !definition.isStatic()) {
         AbstractValue abstractReceiverValue =
             current.asInstanceGet().object().getAbstractValue(appView, code.context());
-        if (abstractReceiverValue.isSingleFieldValue()) {
-          abstractValue =
-              abstractReceiverValue
-                  .asSingleFieldValue()
-                  .getState()
-                  .getAbstractFieldValue(definition);
+        if (abstractReceiverValue.hasObjectState()) {
+          abstractValue = abstractReceiverValue.getObjectState().getAbstractFieldValue(definition);
         }
       }
     } else if (definition.isStatic()) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/OutlinerImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/OutlinerImpl.java
index 921bc7f..d73ac60 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/OutlinerImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/OutlinerImpl.java
@@ -1243,7 +1243,6 @@
                 // set a new disjoint line.
                 .setLine(0);
         Instruction lastInstruction = null;
-        Position position = Position.none();
         { // Scope for 'instructions'.
           int outlinePositionIndex = 0;
           for (int i = start; i < end; i++) {
@@ -1252,8 +1251,9 @@
               // Leave any const instructions.
               continue;
             }
-            if (current.getPosition() != null) {
-              positionBuilder.addOutlinePosition(outlinePositionIndex++, current.getPosition());
+            int currentPositionIndex = outlinePositionIndex++;
+            if (current.getPosition() != null && current.instructionInstanceCanThrow()) {
+              positionBuilder.addOutlinePosition(currentPositionIndex, current.getPosition());
             }
 
             // Prepare to remove the instruction.
@@ -1284,7 +1284,10 @@
         }
         Invoke outlineInvoke = new InvokeStatic(outlineMethod, returnValue, in);
         outlineInvoke.setBlock(lastInstruction.getBlock());
-        outlineInvoke.setPosition(positionBuilder.build());
+        outlineInvoke.setPosition(
+            positionBuilder.hasOutlinePositions()
+                ? positionBuilder.build()
+                : Position.syntheticNone());
         InstructionListIterator endIterator =
             lastInstruction.getBlock().listIterator(code, lastInstruction);
         Instruction instructionBeforeEnd = endIterator.previous();
@@ -1336,6 +1339,7 @@
       ExecutorService executorService,
       Timing timing)
       throws ExecutionException {
+    assert feedback.noUpdatesLeft();
     converter.printPhase("Outlining");
     timing.begin("IR conversion phase 3");
     ProgramMethodSet methodsSelectedForOutlining = selectMethodsForOutlining();
@@ -1350,12 +1354,15 @@
           executorService);
       List<ProgramMethod> outlineMethods = buildOutlineMethods();
       converter.optimizeSynthesizedMethods(outlineMethods, executorService);
+      feedback.updateVisibleOptimizationInfo();
       forEachSelectedOutliningMethod(
           converter,
           methodsSelectedForOutlining,
           code -> {
             applyOutliningCandidate(code);
             converter.printMethod(code, "IR after outlining (SSA)", null);
+            converter.memberValuePropagation.run(code);
+            converter.codeRewriter.rewriteMoveResult(code);
             converter.removeDeadCodeAndFinalizeIR(
                 code, OptimizationFeedbackIgnore.getInstance(), Timing.empty());
           },
@@ -1728,6 +1735,8 @@
 
     @Override
     public Position getCurrentPosition() {
+      // Always build positions for outlinee - each callsite will only build a position map for
+      // instructions that are actually throwing.
       return OutlinePosition.builder().setLine(position).setMethod(method).build();
     }
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
index e42266b..290f25b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
@@ -421,7 +421,7 @@
       SingleFieldValue singleFieldValue =
           field.getDefinition().getOptimizationInfo().getAbstractValue().asSingleFieldValue();
       if (singleFieldValue != null) {
-        applyObjectState(staticGet.outValue(), singleFieldValue.getState());
+        applyObjectState(staticGet.outValue(), singleFieldValue.getObjectState());
       }
     }
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
index 487d677..82322c7 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
@@ -191,7 +191,7 @@
     AbstractValue abstractValue = optimizationInfo.getAbstractValue();
     objectState =
         abstractValue.isSingleFieldValue()
-            ? abstractValue.asSingleFieldValue().getState()
+            ? abstractValue.asSingleFieldValue().getObjectState()
             : ObjectState.empty();
     return EligibilityStatus.ELIGIBLE;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java
index f51dc69..ff79200 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java
@@ -356,7 +356,7 @@
     if (encodedField == null) {
       return null;
     }
-    return abstractValue.asSingleFieldValue().getState().getAbstractFieldValue(encodedField);
+    return abstractValue.asSingleFieldValue().getObjectState().getAbstractFieldValue(encodedField);
   }
 
   private static final class EnumSwitchInfo {
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 d598935..230b15b 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
@@ -27,7 +27,6 @@
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceArrayMap;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
-import it.unimi.dsi.fastutil.ints.Int2ReferenceMaps;
 import java.util.List;
 
 // Accumulated optimization info from call sites.
@@ -39,13 +38,8 @@
   private final Int2ReferenceMap<TypeElement> dynamicUpperBoundTypes;
   private final Int2ReferenceMap<AbstractValue> constants;
 
-  private ConcreteCallSiteOptimizationInfo(int size, boolean allowConstantPropagation) {
-    this(
-        size,
-        new Int2ReferenceArrayMap<>(size),
-        allowConstantPropagation
-            ? new Int2ReferenceArrayMap<>(size)
-            : Int2ReferenceMaps.emptyMap());
+  private ConcreteCallSiteOptimizationInfo(int size) {
+    this(size, new Int2ReferenceArrayMap<>(size), new Int2ReferenceArrayMap<>(size));
   }
 
   private ConcreteCallSiteOptimizationInfo(
@@ -128,21 +122,16 @@
       ConcreteCallSiteOptimizationInfo other, AppView<?> appView, DexEncodedMethod method) {
     assert size == other.size;
     assert size == method.getNumberOfArguments();
-    boolean allowConstantPropagation =
-        appView.options().callSiteOptimizationOptions().isConstantPropagationEnabled();
-    ConcreteCallSiteOptimizationInfo result =
-        new ConcreteCallSiteOptimizationInfo(size, allowConstantPropagation);
+    ConcreteCallSiteOptimizationInfo result = new ConcreteCallSiteOptimizationInfo(size);
     for (int i = 0; i < result.size; i++) {
-      if (allowConstantPropagation) {
-        AbstractValue abstractValue =
-            getAbstractArgumentValue(i)
-                .join(
-                    other.getAbstractArgumentValue(i),
-                    appView.abstractValueFactory(),
-                    method.getArgumentType(i));
-        if (abstractValue.isNonTrivial()) {
-          result.constants.put(i, abstractValue);
-        }
+      AbstractValue abstractValue =
+          getAbstractArgumentValue(i)
+              .join(
+                  other.getAbstractArgumentValue(i),
+                  appView.abstractValueFactory(),
+                  method.getArgumentType(i));
+      if (abstractValue.isNonTrivial()) {
+        result.constants.put(i, abstractValue);
       }
 
       TypeElement thisUpperBoundType = getDynamicUpperBoundType(i);
@@ -186,7 +175,6 @@
     for (int i = 0; i < size; i++) {
       AbstractValue abstractValue = getAbstractArgumentValue(i);
       if (abstractValue.isNonTrivial()) {
-        assert appView.options().callSiteOptimizationOptions().isConstantPropagationEnabled();
         return true;
       }
 
@@ -197,7 +185,6 @@
       if (dynamicUpperBoundType == null) {
         continue;
       }
-      assert appView.options().callSiteOptimizationOptions().isDynamicTypePropagationEnabled();
       // To avoid the full join of type lattices below, separately check if the nullability of
       // arguments is improved, and if so, we can eagerly conclude that we've collected useful
       // call site information for this method.
@@ -232,17 +219,14 @@
       DexMethod invokedMethod,
       List<Value> arguments,
       ProgramMethod context) {
-    boolean allowConstantPropagation =
-        appView.options().callSiteOptimizationOptions().isConstantPropagationEnabled();
     ConcreteCallSiteOptimizationInfo newCallSiteInfo =
-        new ConcreteCallSiteOptimizationInfo(arguments.size(), allowConstantPropagation);
+        new ConcreteCallSiteOptimizationInfo(arguments.size());
     boolean hasReceiver = arguments.size() > invokedMethod.getArity();
     boolean isTop = true;
     for (int i = 0; i < newCallSiteInfo.size; i++) {
       Value arg = arguments.get(i);
 
       // Constant propagation.
-      if (allowConstantPropagation) {
         Value aliasedValue = arg.getAliasedValue();
         if (!aliasedValue.isPhi()) {
           AbstractValue abstractValue = aliasedValue.definition.getAbstractValue(appView, context);
@@ -250,7 +234,6 @@
             newCallSiteInfo.constants.put(i, abstractValue);
             isTop = false;
           }
-        }
       }
 
       // Type propagation.
@@ -276,10 +259,8 @@
       AppView<AppInfoWithLiveness> appView,
       ProgramMethod method,
       ConcreteMonomorphicMethodState methodState) {
-    boolean allowConstantPropagation =
-        appView.options().callSiteOptimizationOptions().isConstantPropagationEnabled();
     ConcreteCallSiteOptimizationInfo newCallSiteInfo =
-        new ConcreteCallSiteOptimizationInfo(methodState.size(), allowConstantPropagation);
+        new ConcreteCallSiteOptimizationInfo(methodState.size());
     boolean isTop = true;
     for (int argumentIndex = 0; argumentIndex < methodState.size(); argumentIndex++) {
       ParameterState parameterState = methodState.getParameterState(argumentIndex);
@@ -290,13 +271,11 @@
       ConcreteParameterState concreteParameterState = parameterState.asConcrete();
 
       // Constant propagation.
-      if (allowConstantPropagation) {
         AbstractValue abstractValue = concreteParameterState.getAbstractValue(appView);
         if (abstractValue.isNonTrivial()) {
           newCallSiteInfo.constants.put(argumentIndex, abstractValue);
           isTop = false;
         }
-      }
 
       // Type propagation.
       DexType staticType = method.getDefinition().getArgumentType(argumentIndex);
@@ -305,13 +284,8 @@
         if (staticType.isArrayType()) {
           Nullability nullability = concreteParameterState.asArrayParameter().getNullability();
           if (nullability.isDefinitelyNull()) {
-            if (allowConstantPropagation) {
               newCallSiteInfo.constants.put(
                   argumentIndex, appView.abstractValueFactory().createNullValue());
-            } else {
-              newCallSiteInfo.dynamicUpperBoundTypes.put(
-                  argumentIndex, staticTypeElement.asArrayType().asDefinitelyNull());
-            }
             isTop = false;
           } else if (nullability.isDefinitelyNotNull()) {
             newCallSiteInfo.dynamicUpperBoundTypes.put(
@@ -364,6 +338,6 @@
   @Override
   public String toString() {
     return dynamicUpperBoundTypes.toString()
-        + (constants == null ? "" : (System.lineSeparator() + constants.toString()));
+        + (constants == null ? "" : (System.lineSeparator() + constants));
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
index 15819c7..b5ced8c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
@@ -65,6 +65,9 @@
 import com.android.tools.r8.ir.analysis.type.Nullability;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.analysis.value.StatefulObjectValue;
+import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
+import com.android.tools.r8.ir.analysis.value.objectstate.ObjectStateAnalysis;
 import com.android.tools.r8.ir.code.AliasedValueConfiguration;
 import com.android.tools.r8.ir.code.Argument;
 import com.android.tools.r8.ir.code.AssumeAndCheckCastAliasedValueConfiguration;
@@ -209,6 +212,13 @@
             checkCastAndInstanceOfMethodSpecialization.addCandidateForOptimization(
                 context, abstractReturnValue, methodProcessor);
           }
+        } else if (returnValue.getType().isReferenceType()) {
+          // TODO(b/204159267): Move this logic into Instruction#getAbstractValue in NewInstance.
+          ObjectState objectState =
+              ObjectStateAnalysis.computeObjectState(aliasedValue, appView, context);
+          // TODO(b/204272377): Avoid wrapping and unwrapping the object state.
+          feedback.methodReturnsAbstractValue(
+              method, appView, StatefulObjectValue.create(objectState));
         }
       }
     }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
index 8ab0859..9397cc6 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
@@ -126,6 +126,9 @@
     enqueueMethodsWithCodeOptimizations(
         methodsToBeStaticized, optimizations -> optimizations.add(this::removeReferencesToThis));
 
+    // Rewrite outliner with lens.
+    converter.outliner.rewriteWithLens();
+
     // Process queued methods with associated optimizations
     processMethodsConcurrently(feedback, executorService);
 
@@ -146,6 +149,9 @@
                 .add(this::insertAssumeInstructions)
                 .add(collectOptimizationInfo(feedback)));
 
+    // Rewrite outliner with lens.
+    converter.outliner.rewriteWithLens();
+
     // Process queued methods with associated optimizations
     processMethodsConcurrently(feedback, executorService);
 
diff --git a/src/main/java/com/android/tools/r8/naming/MapVersion.java b/src/main/java/com/android/tools/r8/naming/MapVersion.java
index 87412e8..a23196c 100644
--- a/src/main/java/com/android/tools/r8/naming/MapVersion.java
+++ b/src/main/java/com/android/tools/r8/naming/MapVersion.java
@@ -8,10 +8,11 @@
 public enum MapVersion implements Ordered<MapVersion> {
   MAP_VERSION_NONE("none"),
   MAP_VERSION_1_0("1.0"),
+  MAP_VERSION_2_0("2.0"),
   MAP_VERSION_EXPERIMENTAL("experimental"),
   MAP_VERSION_UNKNOWN("unknown");
 
-  public static final MapVersion STABLE = MAP_VERSION_1_0;
+  public static final MapVersion STABLE = MAP_VERSION_2_0;
 
   private final String name;
 
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/OutlineCallsiteMappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/OutlineCallsiteMappingInformation.java
index 7f0beee..6cb093d 100644
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/OutlineCallsiteMappingInformation.java
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/OutlineCallsiteMappingInformation.java
@@ -14,7 +14,7 @@
 
 public class OutlineCallsiteMappingInformation extends MappingInformation {
 
-  public static final MapVersion SUPPORTED_VERSION = MapVersion.MAP_VERSION_EXPERIMENTAL;
+  public static final MapVersion SUPPORTED_VERSION = MapVersion.MAP_VERSION_2_0;
   public static final String ID = "com.android.tools.r8.outlineCallsite";
 
   private static final String POSITIONS_KEY = "positions";
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/OutlineMappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/OutlineMappingInformation.java
index 20df16d..1914431 100644
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/OutlineMappingInformation.java
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/OutlineMappingInformation.java
@@ -11,7 +11,7 @@
 
 public class OutlineMappingInformation extends MappingInformation {
 
-  public static final MapVersion SUPPORTED_VERSION = MapVersion.MAP_VERSION_EXPERIMENTAL;
+  public static final MapVersion SUPPORTED_VERSION = MapVersion.MAP_VERSION_2_0;
   public static final String ID = "com.android.tools.r8.outline";
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/RewriteFrameMappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/RewriteFrameMappingInformation.java
index b27fe19..82b2a0b 100644
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/RewriteFrameMappingInformation.java
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/RewriteFrameMappingInformation.java
@@ -26,7 +26,7 @@
 
 public class RewriteFrameMappingInformation extends MappingInformation {
 
-  public static final MapVersion SUPPORTED_VERSION = MapVersion.MAP_VERSION_EXPERIMENTAL;
+  public static final MapVersion SUPPORTED_VERSION = MapVersion.MAP_VERSION_2_0;
   public static final String ID = "com.android.tools.r8.rewriteFrame";
   private static final String CONDITIONS_KEY = "conditions";
   private static final String ACTIONS_KEY = "actions";
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
index bc1b7e3..57ce006 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
@@ -77,7 +77,11 @@
     while (currentResolutionResult != null) {
       DexClassAndMethod currentResolvedMethod = currentResolutionResult.getResolutionPair();
       if (canRebindDirectlyToLibraryMethod(
-          currentResolvedMethod, currentResolutionResult, contexts, invokeType)) {
+          currentResolvedMethod,
+          currentResolutionResult.withInitialResolutionHolder(
+              currentResolutionResult.getResolvedHolder()),
+          contexts,
+          invokeType)) {
         eligibleLibraryMethod = currentResolvedMethod.asLibraryMethod();
       }
       if (appView.appInfo().isAssumeMethod(currentResolvedMethod)) {
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 45f4984..4764635 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
@@ -54,10 +54,6 @@
     assert appView.enableWholeProgramOptimizations();
     assert appView.options().isOptimizing();
     assert appView.options().callSiteOptimizationOptions().isEnabled();
-    assert appView
-        .options()
-        .callSiteOptimizationOptions()
-        .isExperimentalArgumentPropagationEnabled();
     this.appView = appView;
   }
 
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorIROptimizer.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorIROptimizer.java
index e7060d3..892c282 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorIROptimizer.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorIROptimizer.java
@@ -58,7 +58,6 @@
       //  value.
       AbstractValue abstractValue = optimizationInfo.getAbstractArgumentValue(argument.getIndex());
       if (abstractValue.isSingleValue()) {
-        assert appView.options().callSiteOptimizationOptions().isConstantPropagationEnabled();
         SingleValue singleValue = abstractValue.asSingleValue();
         if (singleValue.isMaterializableInContext(appView, code.context())) {
           Instruction replacement =
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java
index e050de8..04afa1c 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java
@@ -6,7 +6,6 @@
 
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethodSignature;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
@@ -162,14 +161,7 @@
     }
 
     if (methodState.isBottom()) {
-      if (!appView.options().canUseDefaultAndStaticInterfaceMethods()
-          && method.getHolder().isInterface()) {
-        // TODO(b/190154391): The method has not been moved to the companion class yet, so we can't
-        //  remove its code object.
-        return;
-      }
-      DexEncodedMethod definition = method.getDefinition();
-      definition.setCode(definition.buildEmptyThrowingCode(appView.options()), appView);
+      method.convertToAbstractOrThrowNullMethod(appView);
       return;
     }
 
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceElement.java b/src/main/java/com/android/tools/r8/retrace/RetraceElement.java
index 55de558..d069fcc 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceElement.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceElement.java
@@ -13,7 +13,7 @@
 @KeepForSubclassing
 public interface RetraceElement<R extends RetraceResult<?>> {
 
-  R getRetraceResultContext();
+  R getParentResult();
 
   boolean isCompilerSynthesized();
 }
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceFrameElement.java b/src/main/java/com/android/tools/r8/retrace/RetraceFrameElement.java
index ff7d330..a985fe1 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceFrameElement.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceFrameElement.java
@@ -21,7 +21,7 @@
 
   Stream<RetracedSingleFrame> stream();
 
-  void forEachRewritten(RetraceStackTraceContext context, Consumer<RetracedSingleFrame> consumer);
+  void forEachRewritten(Consumer<RetracedSingleFrame> consumer);
 
   Stream<RetracedSingleFrame> streamRewritten(RetraceStackTraceContext context);
 
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceResult.java b/src/main/java/com/android/tools/r8/retrace/RetraceResult.java
index 7ff9c4e..cda85ce 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceResult.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceResult.java
@@ -5,6 +5,7 @@
 
 import com.android.tools.r8.Keep;
 import java.util.function.Consumer;
+import java.util.function.Function;
 import java.util.stream.Stream;
 
 /**
@@ -32,5 +33,10 @@
     stream().forEach(action);
   }
 
+  /** Short-hand for flat-mapping the elements to some other result type. */
+  default <T> Stream<T> flatMap(Function<? super E, Stream<T>> fn) {
+    return stream().flatMap(fn);
+  }
+
   boolean isEmpty();
 }
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceUnknownMapVersionDiagnostic.java b/src/main/java/com/android/tools/r8/retrace/RetraceUnknownMapVersionDiagnostic.java
index 0a7a7bb..9c1142b 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceUnknownMapVersionDiagnostic.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceUnknownMapVersionDiagnostic.java
@@ -6,6 +6,7 @@
 
 import com.android.tools.r8.Diagnostic;
 import com.android.tools.r8.Keep;
+import com.android.tools.r8.Version;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.position.Position;
 
@@ -31,7 +32,8 @@
   @Override
   public String getDiagnosticMessage() {
     return String.format(
-        "Map version '%s' is unknown or introduced later than this retrace version.", versionName);
+        "Map version '%s' is unknown or introduced later than retrace version '%s'.",
+        versionName, Version.getVersionString());
   }
 
   public static RetraceUnknownMapVersionDiagnostic create(String versionName) {
diff --git a/src/main/java/com/android/tools/r8/retrace/RetracedSingleFrame.java b/src/main/java/com/android/tools/r8/retrace/RetracedSingleFrame.java
index 6f14809..3b17336 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetracedSingleFrame.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetracedSingleFrame.java
@@ -12,4 +12,6 @@
   RetracedMethodReference getMethodReference();
 
   int getIndex();
+
+  RetracedSourceFile getSourceFile();
 }
diff --git a/src/main/java/com/android/tools/r8/retrace/RetracedSourceFile.java b/src/main/java/com/android/tools/r8/retrace/RetracedSourceFile.java
index c0e0a7d..d1d3542 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetracedSourceFile.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetracedSourceFile.java
@@ -12,4 +12,6 @@
   boolean hasRetraceResult();
 
   String getSourceFile();
+
+  String getOrInferSourceFile();
 }
diff --git a/src/main/java/com/android/tools/r8/retrace/Retracer.java b/src/main/java/com/android/tools/r8/retrace/Retracer.java
index 293ac8e..2cbe2a9 100644
--- a/src/main/java/com/android/tools/r8/retrace/Retracer.java
+++ b/src/main/java/com/android/tools/r8/retrace/Retracer.java
@@ -21,17 +21,54 @@
 
   RetraceMethodResult retraceMethod(MethodReference methodReference);
 
-  RetraceFrameResult retraceFrame(MethodReference methodReference, OptionalInt position);
-
+  /**
+   * Retrace a stack trace frame without knowing the full method signature.
+   *
+   * <p>This method retraces a frame of the format:
+   *
+   * <pre>
+   *   [callee-frame-or-exception-line]
+   *   com.example.Type.method(SourceFile:line)
+   * </pre>
+   *
+   * where the context parameter described below is obtained from retracing the preceeding line
+   * `callee-frame-or-exception-line`
+   *
+   * @param context The context of this frame as defined by the frame preceding it, i.e., the
+   *     context obtained by retracing the callee frame (or exception line), with the rest of the
+   *     arguments being those that represent the caller frame.
+   * @param position The optional line/pc information of the frame.
+   * @param classReference The class/holder information of the frame.
+   * @param methodName The method name information of the frame. If the full method signature is
+   *     known, the alternative retraceFrame method should be used instead.
+   * @return The possibly ambiguous result of retracing the frame.
+   */
   RetraceFrameResult retraceFrame(
-      MethodReference methodReference, OptionalInt position, RetraceStackTraceContext context);
+      RetraceStackTraceContext context,
+      OptionalInt position,
+      ClassReference classReference,
+      String methodName);
+
+  /**
+   * Retrace a stack frame with full method signature information.
+   *
+   * <p>Apart from having the full method signature this is the same as retracing without it.
+   *
+   * @param context The context of this frame as defined by the frame preceding it, i.e., the
+   *     context obtained by retracing the callee frame (or exception line), with the rest of the
+   *     arguments being those that represent the caller frame.
+   * @param position The optional line/pc information of the frame.
+   * @param methodReference The qualified method reference information of the frame.
+   * @return The possibly ambiguous result of retracing the frame.
+   */
+  RetraceFrameResult retraceFrame(
+      RetraceStackTraceContext context, OptionalInt position, MethodReference methodReference);
 
   RetraceFieldResult retraceField(FieldReference fieldReference);
 
   RetraceTypeResult retraceType(TypeReference typeReference);
 
-  RetraceThrownExceptionResult retraceThrownException(
-      ClassReference exception, RetraceStackTraceContext context);
+  RetraceThrownExceptionResult retraceThrownException(ClassReference exception);
 
   static Retracer createDefault(
       ProguardMapProducer proguardMapProducer, DiagnosticsHandler diagnosticsHandler) {
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 0d834a3..7f71ad6 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
@@ -201,18 +201,20 @@
 
     @Override
     public RetracedSourceFile getSourceFile() {
+      String sourceFile = null;
       if (mapper != null) {
         for (MappingInformation info : mapper.getAdditionalMappingInfo()) {
           if (info.isFileNameInformation()) {
-            return new RetracedSourceFileImpl(info.asFileNameInformation().getFileName());
+            sourceFile = info.asFileNameInformation().getFileName();
+            break;
           }
         }
       }
-      return new RetracedSourceFileImpl(null);
+      return new RetracedSourceFileImpl(getRetracedClass().getClassReference(), sourceFile);
     }
 
     @Override
-    public RetraceClassResultImpl getRetraceResultContext() {
+    public RetraceClassResultImpl getParentResult() {
       return classResult;
     }
 
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceFieldResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceFieldResultImpl.java
index 33abecc..43065c1 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetraceFieldResultImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceFieldResultImpl.java
@@ -128,7 +128,7 @@
     }
 
     @Override
-    public RetraceFieldResult getRetraceResultContext() {
+    public RetraceFieldResult getParentResult() {
       return retraceFieldResult;
     }
 
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 ee295e2..0aa210c 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
@@ -266,7 +266,7 @@
     }
 
     @Override
-    public RetraceFrameResult getRetraceResultContext() {
+    public RetraceFrameResult getParentResult() {
       return retraceFrameResult;
     }
 
@@ -288,13 +288,13 @@
     @Override
     public void forEach(Consumer<RetracedSingleFrame> consumer) {
       if (mappedRanges == null || mappedRanges.isEmpty()) {
-        consumer.accept(RetracedSingleFrameImpl.create(getTopFrame(), 0));
+        consumer.accept(RetracedSingleFrameImpl.create(this, getTopFrame(), 0));
         return;
       }
       int counter = 0;
-      consumer.accept(RetracedSingleFrameImpl.create(getTopFrame(), counter++));
+      consumer.accept(RetracedSingleFrameImpl.create(this, getTopFrame(), counter++));
       for (RetracedMethodReferenceImpl outerFrame : getOuterFrames()) {
-        consumer.accept(RetracedSingleFrameImpl.create(outerFrame, counter++));
+        consumer.accept(RetracedSingleFrameImpl.create(this, outerFrame, counter++));
       }
     }
 
@@ -306,11 +306,10 @@
     }
 
     @Override
-    public void forEachRewritten(
-        RetraceStackTraceContext context, Consumer<RetracedSingleFrame> consumer) {
-      RetraceStackTraceContextImpl contextImpl = (RetraceStackTraceContextImpl) context;
+    public void forEachRewritten(Consumer<RetracedSingleFrame> consumer) {
+      RetraceStackTraceContextImpl contextImpl = retraceFrameResult.context;
       RetraceStackTraceCurrentEvaluationInformation currentFrameInformation =
-          context == null
+          contextImpl == null
               ? RetraceStackTraceCurrentEvaluationInformation.empty()
               : contextImpl.computeRewriteFrameInformation(
                   ListUtils.map(mappedRanges, MappedRangeForFrame::getMappedRange));
@@ -329,21 +328,21 @@
       List<RetracedMethodReferenceImpl> outerFrames = getOuterFrames();
       for (RetracedMethodReferenceImpl next : outerFrames) {
         if (numberOfFramesToRemove-- <= 0) {
-          consumer.accept(RetracedSingleFrameImpl.create(prev, index++));
+          consumer.accept(RetracedSingleFrameImpl.create(this, prev, index++));
         }
         prev = next;
       }
       // We expect only the last frame, i.e., the outer-most caller to potentially be synthesized.
       // If not include it too.
       if (numberOfFramesToRemove <= 0 && !isOuterMostFrameCompilerSynthesized()) {
-        consumer.accept(RetracedSingleFrameImpl.create(prev, index));
+        consumer.accept(RetracedSingleFrameImpl.create(this, prev, index));
       }
     }
 
     @Override
     public Stream<RetracedSingleFrame> streamRewritten(RetraceStackTraceContext context) {
       Stream.Builder<RetracedSingleFrame> builder = Stream.builder();
-      forEachRewritten(context, builder::add);
+      forEachRewritten(builder::add);
       return builder.build();
     }
 
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceMethodResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceMethodResultImpl.java
index 8cc522d..e5a2579 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetraceMethodResultImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceMethodResultImpl.java
@@ -186,7 +186,7 @@
     }
 
     @Override
-    public RetraceMethodResult getRetraceResultContext() {
+    public RetraceMethodResult getParentResult() {
       return retraceMethodResult;
     }
 
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceThrownExceptionResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceThrownExceptionResultImpl.java
index bb49d70..e5d0df2 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetraceThrownExceptionResultImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceThrownExceptionResultImpl.java
@@ -74,20 +74,22 @@
     }
 
     @Override
-    public RetraceThrownExceptionResult getRetraceResultContext() {
+    public RetraceThrownExceptionResult getParentResult() {
       return thrownExceptionResult;
     }
 
     @Override
     public RetracedSourceFile getSourceFile() {
+      String sourceFile = null;
       if (mapper != null) {
         for (MappingInformation info : mapper.getAdditionalMappingInfo()) {
           if (info.isFileNameInformation()) {
-            return new RetracedSourceFileImpl(info.asFileNameInformation().getFileName());
+            sourceFile = info.asFileNameInformation().getFileName();
+            break;
           }
         }
       }
-      return new RetracedSourceFileImpl(null);
+      return new RetracedSourceFileImpl(getRetracedClass().getClassReference(), sourceFile);
     }
 
     @Override
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetracedSingleFrameImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetracedSingleFrameImpl.java
index c69b148..f8eea0e 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetracedSingleFrameImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetracedSingleFrameImpl.java
@@ -6,13 +6,18 @@
 
 import com.android.tools.r8.retrace.RetracedMethodReference;
 import com.android.tools.r8.retrace.RetracedSingleFrame;
+import com.android.tools.r8.retrace.RetracedSourceFile;
+import com.android.tools.r8.retrace.internal.RetraceFrameResultImpl.ElementImpl;
 
 public class RetracedSingleFrameImpl implements RetracedSingleFrame {
 
+  private final ElementImpl frameElement;
   private final RetracedMethodReference methodReference;
   private final int index;
 
-  private RetracedSingleFrameImpl(RetracedMethodReference methodReference, int index) {
+  private RetracedSingleFrameImpl(
+      ElementImpl frameElement, RetracedMethodReference methodReference, int index) {
+    this.frameElement = frameElement;
     this.methodReference = methodReference;
     this.index = index;
   }
@@ -27,7 +32,13 @@
     return index;
   }
 
-  static RetracedSingleFrameImpl create(RetracedMethodReference methodReference, int index) {
-    return new RetracedSingleFrameImpl(methodReference, index);
+  @Override
+  public RetracedSourceFile getSourceFile() {
+    return frameElement.getSourceFile(getMethodReference());
+  }
+
+  static RetracedSingleFrameImpl create(
+      ElementImpl frameElement, RetracedMethodReference methodReference, int index) {
+    return new RetracedSingleFrameImpl(frameElement, methodReference, index);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetracedSourceFileImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetracedSourceFileImpl.java
index ef19bb3..c7f2fae 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetracedSourceFileImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetracedSourceFileImpl.java
@@ -4,13 +4,17 @@
 
 package com.android.tools.r8.retrace.internal;
 
+import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.retrace.RetracedSourceFile;
 
 public class RetracedSourceFileImpl implements RetracedSourceFile {
 
+  private final ClassReference classReference;
   private final String filename;
 
-  RetracedSourceFileImpl(String filename) {
+  RetracedSourceFileImpl(ClassReference classReference, String filename) {
+    assert classReference != null;
+    this.classReference = classReference;
     this.filename = filename;
   }
 
@@ -23,4 +27,12 @@
   public String getSourceFile() {
     return filename;
   }
+
+  @Override
+  public String getOrInferSourceFile() {
+    String sourceFile = getSourceFile();
+    return sourceFile != null
+        ? sourceFile
+        : RetraceUtils.inferSourceFile(classReference.getTypeName(), "", true);
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetracerImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetracerImpl.java
index 3d62354..6cac8dd 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetracerImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetracerImpl.java
@@ -65,16 +65,24 @@
   }
 
   @Override
-  public RetraceFrameResult retraceFrame(MethodReference methodReference, OptionalInt position) {
-    return retraceFrame(methodReference, position, RetraceStackTraceContext.empty());
+  public RetraceFrameResult retraceFrame(
+      RetraceStackTraceContext context,
+      OptionalInt position,
+      ClassReference classReference,
+      String methodName) {
+    return retraceClass(classReference).lookupFrame(context, position, methodName);
   }
 
   @Override
   public RetraceFrameResult retraceFrame(
-      MethodReference methodReference, OptionalInt position, RetraceStackTraceContext context) {
+      RetraceStackTraceContext context, OptionalInt position, MethodReference methodReference) {
     return retraceClass(methodReference.getHolderClass())
-        .lookupMethod(methodReference.getMethodName())
-        .narrowByPosition(context, position);
+        .lookupFrame(
+            context,
+            position,
+            methodReference.getMethodName(),
+            methodReference.getFormalTypes(),
+            methodReference.getReturnType());
   }
 
   @Override
@@ -94,9 +102,8 @@
   }
 
   @Override
-  public RetraceThrownExceptionResultImpl retraceThrownException(
-      ClassReference exception, RetraceStackTraceContext context) {
-    return retraceClass(exception).lookupThrownException(context);
+  public RetraceThrownExceptionResultImpl retraceThrownException(ClassReference exception) {
+    return retraceClass(exception).lookupThrownException(RetraceStackTraceContext.empty());
   }
 
   public Set<MapVersionMappingInformation> getMapVersions() {
diff --git a/src/main/java/com/android/tools/r8/utils/Int2StructuralItemArrayMap.java b/src/main/java/com/android/tools/r8/utils/Int2StructuralItemArrayMap.java
index 9ed1e4f..3f0f761 100644
--- a/src/main/java/com/android/tools/r8/utils/Int2StructuralItemArrayMap.java
+++ b/src/main/java/com/android/tools/r8/utils/Int2StructuralItemArrayMap.java
@@ -90,6 +90,10 @@
       return this;
     }
 
+    public boolean isEmpty() {
+      return keys.isEmpty();
+    }
+
     public Int2StructuralItemArrayMap<T> build() {
       return new Int2StructuralItemArrayMap<T>(Ints.toArray(keys), values.build());
     }
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 759381b..5cd2455 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -1233,24 +1233,16 @@
 
   public class CallSiteOptimizationOptions {
 
+    private boolean enabled = true;
+
     // Each time we see an invoke with more dispatch targets than the threshold, we stop call site
     // propagation for all these dispatch targets. The motivation for this is that it is expensive
     // and that we are somewhat unlikely to have precise knowledge about the value of arguments when
     // there are many (possibly spurious) call graph edges.
     private final int maxNumberOfDispatchTargetsBeforeAbandoning = 10;
 
-    // TODO(b/69963623): enable if everything is ready, including signature rewriting at call sites.
-    private boolean enableLegacyConstantPropagation = false;
-    private boolean enableExperimentalArgumentPropagation = true;
-    private boolean enableDynamicTypePropagation = true;
-
     public void disableOptimization() {
-      enableLegacyConstantPropagation = false;
-      enableDynamicTypePropagation = false;
-    }
-
-    public void disableDynamicTypePropagationForTesting() {
-      enableDynamicTypePropagation = false;
+      enabled = false;
     }
 
     public int getMaxNumberOfDispatchTargetsBeforeAbandoning() {
@@ -1265,19 +1257,7 @@
       if (!isOptimizing() || !isShrinking()) {
         return false;
       }
-      return enableLegacyConstantPropagation || enableDynamicTypePropagation;
-    }
-
-    public boolean isExperimentalArgumentPropagationEnabled() {
-      return enableExperimentalArgumentPropagation;
-    }
-
-    public boolean isConstantPropagationEnabled() {
-      return enableLegacyConstantPropagation || isExperimentalArgumentPropagationEnabled();
-    }
-
-    public boolean isDynamicTypePropagationEnabled() {
-      return enableDynamicTypePropagation;
+      return enabled;
     }
 
     public CallSiteOptimizationOptions setEnabled(boolean enabled) {
@@ -1288,18 +1268,6 @@
       }
       return this;
     }
-
-    public CallSiteOptimizationOptions setEnableLegacyConstantPropagation() {
-      assert !enableLegacyConstantPropagation;
-      enableLegacyConstantPropagation = true;
-      return this;
-    }
-
-    public CallSiteOptimizationOptions setEnableExperimentalArgumentPropagation(
-        boolean enableExperimentalArgumentPropagation) {
-      this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-      return this;
-    }
   }
 
   public class ClassInlinerOptions {
@@ -1389,6 +1357,8 @@
     private boolean enable =
         !Version.isDevelopmentVersion()
             || System.getProperty("com.android.tools.r8.disableHorizontalClassMerging") == null;
+    private boolean enableInterfaceMerging =
+        System.getProperty("com.android.tools.r8.disableHorizontalInterfaceMerging") == null;
     private boolean enableInterfaceMergingInInitial = false;
     private boolean enableSyntheticMerging = true;
     private boolean ignoreRuntimeTypeChecksForTesting = false;
@@ -1440,6 +1410,9 @@
     }
 
     public boolean isInterfaceMergingEnabled(HorizontalClassMerger.Mode mode) {
+      if (!enableInterfaceMerging) {
+        return false;
+      }
       if (mode.isInitial()) {
         return enableInterfaceMergingInInitial;
       }
diff --git a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
index 16af327..e0ecef3 100644
--- a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
+++ b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
@@ -50,7 +50,6 @@
 import com.android.tools.r8.naming.ClassNaming;
 import com.android.tools.r8.naming.ClassNaming.Builder;
 import com.android.tools.r8.naming.ClassNamingForNameMapper.MappedRange;
-import com.android.tools.r8.naming.MapVersion;
 import com.android.tools.r8.naming.MemberNaming;
 import com.android.tools.r8.naming.MemberNaming.FieldSignature;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
@@ -363,9 +362,7 @@
         }
       }
 
-      MapVersion mapFileVersion = appView.options().getMapFileVersion();
-
-      if (isSyntheticClass && CompilerSynthesizedMappingInformation.isSupported(mapFileVersion)) {
+      if (isSyntheticClass) {
         onDemandClassNamingBuilder
             .get()
             .addMappingInformation(
@@ -446,8 +443,7 @@
           String obfuscatedName = obfuscatedNameDexString.toString();
 
           List<MappingInformation> methodMappingInfo = new ArrayList<>();
-          if (method.isD8R8Synthesized()
-              && CompilerSynthesizedMappingInformation.isSupported(mapFileVersion)) {
+          if (method.isD8R8Synthesized()) {
             methodMappingInfo.add(CompilerSynthesizedMappingInformation.builder().build());
           }
 
@@ -481,17 +477,14 @@
                       m, key -> MethodSignature.fromDexMethod(m, m.holder != clazz.getType()));
 
           // Check if mapped position is an outline
-          if (mappedPositions.get(0).isOutline
-              && OutlineMappingInformation.isSupported(mapFileVersion)) {
+          DexMethod outlineMethod = getOutlineMethod(mappedPositions.get(0));
+          if (outlineMethod != null) {
             outlinesToFix
-                .computeIfAbsent(
-                    mappedPositions.get(0).method, ignored -> new OutlineFixupBuilder())
+                .computeIfAbsent(outlineMethod, ignored -> new OutlineFixupBuilder())
                 .setMappedPositionsOutline(mappedPositions);
             methodMappingInfo.add(OutlineMappingInformation.builder().build());
           }
 
-          int outlineCallersCounter = 0;
-
           // Update memberNaming with the collected positions, merging multiple positions into a
           // single region whenever possible.
           for (int i = 0; i < mappedPositions.size(); /* updated in body */ ) {
@@ -559,8 +552,7 @@
               lastMappedRange.addMappingInformation(info, Unreachable::raise);
             }
             // firstPosition will contain a potential outline caller.
-            if (firstPosition.outlineCallee != null
-                && OutlineCallsiteMappingInformation.isSupported(mapFileVersion)) {
+            if (firstPosition.outlineCallee != null) {
               Int2IntMap positionMap = new Int2IntArrayMap();
               int maxPc = ListUtils.last(mappedPositions).obfuscatedLine;
               firstPosition.outlinePositions.forEach(
@@ -587,7 +579,6 @@
                   .computeIfAbsent(
                       firstPosition.outlineCallee, ignored -> new OutlineFixupBuilder())
                   .addMappedRangeForOutlineCallee(lastMappedRange, positionMap);
-              outlineCallersCounter += 1;
             }
             i = j;
           }
@@ -606,6 +597,17 @@
     return classNameMapperBuilder.build();
   }
 
+  private static DexMethod getOutlineMethod(MappedPosition mappedPosition) {
+    if (mappedPosition.isOutline) {
+      return mappedPosition.method;
+    }
+    if (mappedPosition.caller == null) {
+      return null;
+    }
+    Position outermostCaller = mappedPosition.caller.getOutermostCaller();
+    return outermostCaller.isOutline() ? outermostCaller.getMethod() : null;
+  }
+
   private static MappedRange getMappedRangesForPosition(
       DexItemFactory factory,
       Function<DexMethod, MethodSignature> getOriginalMethodSignature,
@@ -1100,8 +1102,11 @@
     }
 
     public void fixup() {
-      assert mappedOutlinePositions != null;
-      assert !mappedOutlineCalleePositions.isEmpty();
+      if (mappedOutlinePositions == null || mappedOutlineCalleePositions.isEmpty()) {
+        assert mappedOutlinePositions != null : "Mapped outline positions is null";
+        assert false : "Mapped outline positions is empty";
+        return;
+      }
       for (Pair<MappedRange, Int2IntMap> mappingInfo : mappedOutlineCalleePositions) {
         MappedRange mappedRange = mappingInfo.getFirst();
         Int2IntMap positions = mappingInfo.getSecond();
diff --git a/src/test/examples/inlining/KeepConstantArguments.java b/src/test/examples/inlining/KeepConstantArguments.java
new file mode 100644
index 0000000..969bf8e
--- /dev/null
+++ b/src/test/examples/inlining/KeepConstantArguments.java
@@ -0,0 +1,10 @@
+// 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 inlining;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+@Target({ElementType.METHOD})
+public @interface KeepConstantArguments {}
diff --git a/src/test/examples/inlining/Nullability.java b/src/test/examples/inlining/Nullability.java
index 95422f0..4c8dcb0 100644
--- a/src/test/examples/inlining/Nullability.java
+++ b/src/test/examples/inlining/Nullability.java
@@ -32,6 +32,7 @@
     return a != null ? this.f : -1;
   }
 
+  @KeepConstantArguments
   int notInlinableDueToSideEffect(A a) {
     // NPE is not preserved when the receiver is null and a is not null.
     return a != null ? a.a() : this.f;
diff --git a/src/test/examples/inlining/keep-rules.txt b/src/test/examples/inlining/keep-rules.txt
index f6423b1..2c0f288 100644
--- a/src/test/examples/inlining/keep-rules.txt
+++ b/src/test/examples/inlining/keep-rules.txt
@@ -11,7 +11,9 @@
 -alwaysinline class * {
   @inlining.AlwaysInline <methods>;
 }
-
 -neverinline class * {
   @inlining.NeverInline <methods>;
 }
+-keepconstantarguments class * {
+  @inlining.KeepConstantArguments <methods>;
+}
diff --git a/src/test/java/com/android/tools/r8/D8TestBuilder.java b/src/test/java/com/android/tools/r8/D8TestBuilder.java
index c988660..b39af91 100644
--- a/src/test/java/com/android/tools/r8/D8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/D8TestBuilder.java
@@ -71,7 +71,7 @@
     return new D8TestCompileResult(
         getState(),
         app.get(),
-        minApiLevel,
+        getMinApiLevel(),
         getOutputMode(),
         libraryDesugaringTestConfiguration,
         getMapContent());
diff --git a/src/test/java/com/android/tools/r8/DXTestBuilder.java b/src/test/java/com/android/tools/r8/DXTestBuilder.java
index 2459f1d..436f1e7 100644
--- a/src/test/java/com/android/tools/r8/DXTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/DXTestBuilder.java
@@ -52,7 +52,7 @@
       Path outJar = dxOutputFolder.resolve("output.jar");
 
       List<String> args = new ArrayList<>();
-      args.add("--min-sdk-version=" + minApiLevel);
+      args.add("--min-sdk-version=" + getMinApiLevel());
       args.add("--output=" + outJar.toString());
       args.addAll(injars.stream().map(Path::toString).collect(Collectors.toList()));
       ProcessResult result =
@@ -63,7 +63,7 @@
         throw new CompilationFailedException(result.toString());
       }
       return new DXTestCompileResult(
-          getState(), AndroidApp.builder().addProgramFile(outJar).build(), minApiLevel);
+          getState(), AndroidApp.builder().addProgramFile(outJar).build(), getMinApiLevel());
     } catch (IOException e) {
       throw new CompilationFailedException(e);
     }
diff --git a/src/test/java/com/android/tools/r8/ExternalR8TestBuilder.java b/src/test/java/com/android/tools/r8/ExternalR8TestBuilder.java
index 85e7ca6..6d34346 100644
--- a/src/test/java/com/android/tools/r8/ExternalR8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/ExternalR8TestBuilder.java
@@ -190,7 +190,7 @@
               ? FileUtils.readTextFile(proguardMapFile, Charsets.UTF_8)
               : "";
       return new ExternalR8TestCompileResult(
-          getState(), outputJar, processResult, proguardMap, minApiLevel, getOutputMode());
+          getState(), outputJar, processResult, proguardMap, getMinApiLevel(), getOutputMode());
     } catch (IOException e) {
       throw new CompilationFailedException(e);
     }
diff --git a/src/test/java/com/android/tools/r8/L8TestBuilder.java b/src/test/java/com/android/tools/r8/L8TestBuilder.java
index 072da5a..dc4a247 100644
--- a/src/test/java/com/android/tools/r8/L8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/L8TestBuilder.java
@@ -8,6 +8,7 @@
 import static junit.framework.TestCase.assertTrue;
 
 import com.android.tools.r8.TestBase.Backend;
+import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryJDK11Undesugarer;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidAppConsumers;
@@ -38,7 +39,7 @@
   private List<Path> additionalProgramFiles = new ArrayList<>();
   private List<byte[]> additionalProgramClassFileData = new ArrayList<>();
   private Consumer<InternalOptions> optionsModifier = ConsumerUtils.emptyConsumer();
-  private Path desugarJDKLibs = ToolHelper.getDesugarJDKLibs();
+  private Path desugarJDKLibs = DesugaredLibraryJDK11Undesugarer.undesugaredJar();
   private Path desugarJDKLibsConfiguration = null;
   private StringResource desugaredLibraryConfiguration =
       StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting());
diff --git a/src/test/java/com/android/tools/r8/ProguardTestBuilder.java b/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
index 8791b27..8d5bdea 100644
--- a/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
@@ -114,7 +114,7 @@
       }
       String proguardMap =
           Files.exists(mapFile) ? FileUtils.readTextFile(mapFile, Charsets.UTF_8) : "";
-      return new ProguardTestCompileResult(getState(), outJar, minApiLevel, proguardMap);
+      return new ProguardTestCompileResult(getState(), outJar, getMinApiLevel(), proguardMap);
     } catch (IOException e) {
       throw new CompilationFailedException(e);
     }
diff --git a/src/test/java/com/android/tools/r8/R8TestBuilder.java b/src/test/java/com/android/tools/r8/R8TestBuilder.java
index 2db1e9d..0f72c5a 100644
--- a/src/test/java/com/android/tools/r8/R8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/R8TestBuilder.java
@@ -127,7 +127,7 @@
             box.syntheticProguardRules,
             createDefaultProguardMapConsumer ? proguardMapBuilder.toString() : null,
             graphConsumer,
-            minApiLevel,
+            getMinApiLevel(),
             features);
     switch (allowedDiagnosticMessages) {
       case ALL:
diff --git a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
index fbe6f27..2fe8ae0 100644
--- a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
@@ -68,7 +68,7 @@
   private ProgramConsumer programConsumer;
   private MainDexClassesCollector mainDexClassesCollector;
   private StringConsumer mainDexListConsumer;
-  protected int minApiLevel = ToolHelper.getMinApiLevelForDexVm().getLevel();
+  private int minApiLevel = -1;
   private boolean optimizeMultidexForLinearAlloc = false;
   private Consumer<InternalOptions> optionsConsumer = DEFAULT_OPTIONS;
   private ByteArrayOutputStream stdout = null;
@@ -103,6 +103,11 @@
     }
   }
 
+  protected int getMinApiLevel() {
+    // TODO(b/186010707): Enable assert minApiLevel != -1;
+    return minApiLevel;
+  }
+
   abstract CR internalCompile(
       B builder, Consumer<InternalOptions> optionsConsumer, Supplier<AndroidApp> app)
       throws CompilationFailedException;
@@ -190,7 +195,12 @@
     if (backend.isDex() || !isTestShrinkerBuilder()) {
       assert !builder.isMinApiLevelSet()
           : "Don't set the API level directly through BaseCompilerCommand.Builder in tests";
-      builder.setMinApiLevel(minApiLevel);
+      // TODO(b/186010707): This will always be set when fixed.
+      int minApi =
+          getMinApiLevel() == -1
+              ? ToolHelper.getMinApiLevelForDexVm().getLevel()
+              : getMinApiLevel();
+      builder.setMinApiLevel(minApi);
     }
     builder.setOptimizeMultidexForLinearAlloc(optimizeMultidexForLinearAlloc);
     if (useDefaultRuntimeLibrary) {
@@ -203,7 +213,6 @@
         builder.addLibraryFiles(TestBase.runtimeJar(backend));
       }
     }
-    List<String> mainDexClasses = null;
     assertNull(oldStdout);
     oldStdout = System.out;
     assertNull(oldStderr);
@@ -321,6 +330,7 @@
   }
 
   public T setMinApi(int minApiLevel) {
+    assert minApiLevel != -1;
     this.minApiLevel = minApiLevel;
     return self();
   }
diff --git a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
index beb7da4..acd96aa 100644
--- a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
@@ -58,10 +58,12 @@
 
   @Override
   public T setMinApi(AndroidApiLevel minApiLevel) {
-    if (backend == Backend.DEX) {
-      return super.setMinApi(minApiLevel.getLevel());
-    }
-    return self();
+    return backend == Backend.DEX ? super.setMinApi(minApiLevel.getLevel()) : self();
+  }
+
+  @Override
+  protected int getMinApiLevel() {
+    return backend == Backend.DEX ? super.getMinApiLevel() : -1;
   }
 
   public T treeShaking(boolean enable) {
diff --git a/src/test/java/com/android/tools/r8/accessrelaxation/AccessRelaxationProguardCompatTest.java b/src/test/java/com/android/tools/r8/accessrelaxation/AccessRelaxationProguardCompatTest.java
index 11bf740..1307d62 100644
--- a/src/test/java/com/android/tools/r8/accessrelaxation/AccessRelaxationProguardCompatTest.java
+++ b/src/test/java/com/android/tools/r8/accessrelaxation/AccessRelaxationProguardCompatTest.java
@@ -12,6 +12,7 @@
 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.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.FieldSubject;
@@ -46,6 +47,7 @@
             "  private int field;",
             "}")
         .allowAccessModification()
+        .setMinApi(AndroidApiLevel.B)
         .compile()
         .inspect(inspector -> inspect(inspector, true));
   }
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ImplicitClassInitializationSynchronizationTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ImplicitClassInitializationSynchronizationTest.java
new file mode 100644
index 0000000..aa0d663
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ImplicitClassInitializationSynchronizationTest.java
@@ -0,0 +1,182 @@
+// 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.classmerging.horizontal;
+
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.StringUtils;
+import java.lang.Thread.State;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ImplicitClassInitializationSynchronizationTest extends TestBase {
+
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection parameters() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(getClass())
+        .addKeepMainRule(Main.class)
+        // TODO(b/205611444): Should not be merged.
+        .addHorizontallyMergedClassesInspector(
+            inspector -> inspector.assertIsCompleteMergeGroup(B.class, C.class))
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .run(parameters.getRuntime(), Main.class)
+        // TODO(b/205611444): Should succeed.
+        .assertFailure()
+        .assertStdoutMatches(
+            equalTo(
+                StringUtils.lines(
+                    "Main: fork",
+                    "Main: wait",
+                    "Worker: notify",
+                    "Worker: wait",
+                    "Main: notified",
+                    "Main: lock C",
+                    "Worker: notified",
+                    "Worker: lock B")));
+  }
+
+  @Test
+  public void testJvm() throws Exception {
+    assumeTrue(parameters.isCfRuntime());
+    testForJvm()
+        .addTestClasspath()
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines(
+            "Main: fork",
+            "Main: wait",
+            "Worker: notify",
+            "Worker: wait",
+            "Main: notified",
+            "Main: lock C",
+            "Worker: notified",
+            "Worker: lock B",
+            "B",
+            "Worker: unlock B",
+            "C",
+            "Main: unlock C");
+  }
+
+  static class Main {
+
+    static Object lock = new Object();
+    static Thread mainThread = Thread.currentThread();
+
+    public static void main(String[] args) throws Exception {
+      System.out.println("Main: fork");
+      Thread workerThread = new Thread(A::new);
+      workerThread.start();
+
+      // Wait for the worker thread to take the lock for A.
+      System.out.println("Main: wait");
+      synchronized (lock) {
+        lock.wait();
+      }
+
+      // Wait for the worker thread to be waiting on the main thread.
+      while (workerThread.getState() != State.WAITING) {
+        Thread.sleep(100);
+      }
+
+      System.out.println("Main: notified");
+
+      // In one second, let the worker thread continue.
+      doAfter(
+          1000,
+          () -> {
+            synchronized (lock) {
+              lock.notify();
+            }
+          });
+
+      // In five seconds, report a dead lock.
+      doAfter(5000, () -> System.exit(1));
+
+      System.out.println("Main: lock C");
+      System.out.println(new C());
+      System.out.println("Main: unlock C");
+
+      // No deadlock, success.
+      System.exit(0);
+    }
+
+    private static void doAfter(int ms, Runnable runnable) {
+      new Thread(
+              () -> {
+                try {
+                  Thread.sleep(ms);
+                  runnable.run();
+                } catch (InterruptedException e) {
+                  throw new RuntimeException(e);
+                }
+              })
+          .start();
+    }
+  }
+
+  static class A {
+
+    static {
+      try {
+        // Wait for the main thread to be waiting on the worker thread.
+        while (Main.mainThread.getState() != State.WAITING) {
+          Thread.sleep(100);
+        }
+
+        System.out.println("Worker: notify");
+        synchronized (Main.lock) {
+          Main.lock.notify();
+        }
+
+        // Wait for the main thread to take the lock for B.
+        System.out.println("Worker: wait");
+        synchronized (Main.lock) {
+          Main.lock.wait();
+        }
+        System.out.println("Worker: notified");
+
+        // Try to take the lock for B.
+        System.out.println("Worker: lock B");
+        System.out.println(new B());
+        System.out.println("Worker: unlock B");
+      } catch (InterruptedException e) {
+        throw new RuntimeException(e);
+      }
+    }
+  }
+
+  static class B extends A {
+
+    @Override
+    public String toString() {
+      return "B";
+    }
+  }
+
+  static class C extends A {
+
+    @Override
+    public String toString() {
+      return "C";
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/debug/LoadInvokeLoadOptimizationTestRunner.java b/src/test/java/com/android/tools/r8/debug/LoadInvokeLoadOptimizationTestRunner.java
index 18ae157..9242d61 100644
--- a/src/test/java/com/android/tools/r8/debug/LoadInvokeLoadOptimizationTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debug/LoadInvokeLoadOptimizationTestRunner.java
@@ -5,6 +5,7 @@
 
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.debug.DebugTestBase.JUnit3Wrapper.FrameInspector;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.DescriptorUtils;
 import java.util.List;
 import org.apache.harmony.jpda.tests.framework.jdwp.Value;
@@ -20,6 +21,7 @@
   static final String NAME = CLASS.getCanonicalName();
   static final String DESC = DescriptorUtils.javaTypeToDescriptor(NAME);
   static final String FILE = CLASS.getSimpleName() + ".java";
+  static final AndroidApiLevel minApi = AndroidApiLevel.B;
 
   private final String name;
   private final DebugTestConfig config;
@@ -29,7 +31,9 @@
     DebugTestParameters parameters =
         parameters()
             .add("CF", temp -> testForJvm(temp).addTestClasspath().debugConfig())
-            .add("D8", temp -> testForD8(temp).addProgramClasses(CLASS).debugConfig());
+            .add(
+                "D8",
+                temp -> testForD8(temp).setMinApi(minApi).addProgramClasses(CLASS).debugConfig());
     for (Backend backend : ToolHelper.getBackends()) {
       parameters.add(
           "R8/" + backend,
@@ -39,6 +43,7 @@
                   .noMinification()
                   .addKeepRules("-keepattributes SourceFile,LineNumberTable")
                   .addProgramClasses(CLASS)
+                  .setMinApi(minApi)
                   .debug()
                   .debugConfig());
     }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryJDK11Undesugarer.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryJDK11Undesugarer.java
new file mode 100644
index 0000000..f79db70
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryJDK11Undesugarer.java
@@ -0,0 +1,105 @@
+// 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.desugaredlibrary;
+
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.transformers.MethodTransformer;
+import com.android.tools.r8.utils.StreamUtils;
+import com.android.tools.r8.utils.ZipUtils;
+import com.google.common.collect.ImmutableMap;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.Map;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+import org.objectweb.asm.Opcodes;
+
+public class DesugaredLibraryJDK11Undesugarer extends DesugaredLibraryTestBase {
+
+  private static Map<String, String> ownerMap =
+      ImmutableMap.of(
+          "java/io/DesugarBufferedReader", "java/io/BufferedReader",
+          "java/io/DesugarInputStream", "java/io/InputStream");
+
+  public static void main(String[] args) throws Exception {
+    setUpDesugaredLibrary();
+    undesugaredJar();
+  }
+
+  public static Path undesugaredJar() {
+    if (!isJDK11DesugaredLibrary()) {
+      return ToolHelper.getDesugarJDKLibs();
+    }
+    Path desugaredLibJDK11Undesugared = Paths.get("build/libs/desugar_jdk_libs_11_undesugared.jar");
+    if (Files.exists(desugaredLibJDK11Undesugared)) {
+      return desugaredLibJDK11Undesugared;
+    }
+    OpenOption[] options =
+        new OpenOption[] {StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING};
+    try (ZipOutputStream out =
+        new ZipOutputStream(
+            new BufferedOutputStream(
+                Files.newOutputStream(desugaredLibJDK11Undesugared, options)))) {
+      new DesugaredLibraryJDK11Undesugarer().undesugar(ToolHelper.getDesugarJDKLibs(), out);
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+    return desugaredLibJDK11Undesugared;
+  }
+
+  private void undesugar(Path desugaredLibraryFiles, ZipOutputStream out) throws IOException {
+    ZipUtils.iter(
+        desugaredLibraryFiles,
+        ((entry, input) -> {
+          if (!entry.getName().endsWith(".class")) {
+            return;
+          }
+          final byte[] bytes = StreamUtils.StreamToByteArrayClose(input);
+          final byte[] rewrittenBytes =
+              transformInvoke(entry.getName().substring(0, entry.getName().length() - 6), bytes);
+          ZipUtils.writeToZipStream(out, entry.getName(), rewrittenBytes, ZipEntry.STORED);
+        }));
+  }
+
+  private byte[] transformInvoke(String descriptor, byte[] bytes) {
+    return transformer(bytes, Reference.classFromDescriptor(descriptor))
+        .addMethodTransformer(getMethodTransformer())
+        .transform();
+  }
+
+  private MethodTransformer getMethodTransformer() {
+    return new MethodTransformer() {
+      @Override
+      public void visitMethodInsn(
+          int opcode, String owner, String name, String descriptor, boolean isInterface) {
+        if (opcode == Opcodes.INVOKESTATIC) {
+          for (String ownerToRewrite : ownerMap.keySet()) {
+            if (ownerToRewrite.equals(owner)) {
+              super.visitMethodInsn(
+                  Opcodes.INVOKEVIRTUAL,
+                  ownerMap.get(owner),
+                  name,
+                  withoutFirstObjectArg(descriptor),
+                  isInterface);
+              return;
+            }
+          }
+        }
+        super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+      }
+    };
+  }
+
+  private String withoutFirstObjectArg(String descriptor) {
+    int i = descriptor.indexOf(";");
+    return "(" + descriptor.substring(i + 1);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmptyDesugaredLibrary.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmptyDesugaredLibrary.java
index fc35e73..1352a82 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmptyDesugaredLibrary.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmptyDesugaredLibrary.java
@@ -63,6 +63,13 @@
     }
   }
 
+  private int firstEmptyLevel() {
+    return isJDK11DesugaredLibrary()
+        // Some desugarings are required on all API levels including UNKNOWN.
+        ? AndroidApiLevel.NOT_SET.getLevel()
+        : AndroidApiLevel.O.getLevel();
+  }
+
   @Test
   public void testEmptyDesugaredLibrary() throws Exception {
     for (AndroidApiLevel apiLevel : AndroidApiLevel.values()) {
@@ -72,8 +79,7 @@
       }
       CountingProgramConsumer programConsumer = new CountingProgramConsumer();
       ToolHelper.runL8(prepareL8Builder(apiLevel).setProgramConsumer(programConsumer).build());
-      assertEquals(
-          apiLevel.getLevel() >= AndroidApiLevel.O.getLevel() ? 0 : 1, programConsumer.count);
+      assertEquals(apiLevel.getLevel() >= firstEmptyLevel() ? 0 : 1, programConsumer.count);
     }
   }
 
@@ -89,7 +95,7 @@
           prepareL8Builder(apiLevel).setOutput(desugaredLibraryZip, OutputMode.DexIndexed).build());
       assertTrue(Files.exists(desugaredLibraryZip));
       assertEquals(
-          apiLevel.getLevel() >= AndroidApiLevel.O.getLevel() ? 0 : 1,
+          apiLevel.getLevel() >= firstEmptyLevel() ? 0 : 1,
           new ZipFile(desugaredLibraryZip.toFile(), StandardCharsets.UTF_8).size());
     }
   }
@@ -107,7 +113,7 @@
               .setOutput(desugaredLibraryDirectory, OutputMode.DexIndexed)
               .build());
       assertEquals(
-          apiLevel.getLevel() >= AndroidApiLevel.O.getLevel() ? 0 : 1,
+          apiLevel.getLevel() >= firstEmptyLevel() ? 0 : 1,
           Files.walk(desugaredLibraryDirectory)
               .filter(path -> path.toString().endsWith(".dex"))
               .count());
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/B205481246.java b/src/test/java/com/android/tools/r8/ir/optimize/B205481246.java
new file mode 100644
index 0000000..1f8805f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/B205481246.java
@@ -0,0 +1,73 @@
+// 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;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.equalTo;
+
+import com.android.tools.r8.NeverInline;
+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.utils.AndroidApiLevel;
+import java.util.Objects;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class B205481246 extends TestBase {
+
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection parameters() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  @Test
+  public void testRuntime() throws Exception {
+    testForRuntime(parameters)
+        .addInnerClasses(getClass())
+        .run(parameters.getRuntime(), Main.class)
+        .applyIf(
+            parameters.isDexRuntimeVersion(Version.V6_0_1)
+                && parameters.getApiLevel().isEqualTo(AndroidApiLevel.B),
+            runResult ->
+                runResult.assertFailureWithErrorThatMatches(
+                    containsString("Check failed: receiver != nullptr virtual")),
+            runResult ->
+                runResult
+                    .assertFailureWithErrorThatThrows(NullPointerException.class)
+                    .assertStdoutMatches(equalTo("")));
+  }
+
+  static class Main {
+
+    public static void main(String[] args) {
+      Foo alwaysNull = System.currentTimeMillis() > 0 ? null : new Foo();
+      try {
+        if (alwaysNull.alwaysTrue()) {
+          System.out.println("true");
+        }
+      } catch (NullPointerException expected) {
+        Objects.requireNonNull(alwaysNull);
+      }
+    }
+
+    static class Foo {
+
+      boolean alwaysTrue = true;
+
+      @NeverInline
+      boolean alwaysTrue() {
+        return alwaysTrue;
+      }
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/R8InliningTest.java b/src/test/java/com/android/tools/r8/ir/optimize/R8InliningTest.java
index 21f1be3..42bb70f 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/R8InliningTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/R8InliningTest.java
@@ -8,10 +8,12 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
 import com.android.tools.r8.ToolHelper.ProcessResult;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexItemFactory;
@@ -116,16 +118,11 @@
         .addOptionsModification(
             o -> {
               // Disable class inlining to prevent that the instantiation of Nullability is removed,
-              // and
-              // that the class is therefore made abstract.
+              // and that the class is therefore made abstract.
               o.enableClassInlining = false;
               o.inlinerOptions().enableInlining = inlining;
               o.inlinerOptions().enableInliningOfInvokesWithNullableReceivers = false;
               o.inlinerOptions().simpleInliningInstructionLimit = 6;
-              // Tests depend on nullability of receiver and argument in general. Learning very
-              // accurate
-              // nullability from actual usage in tests bothers what we want to test.
-              o.callSiteOptimizationOptions().disableDynamicTypePropagationForTesting();
               o.testing.horizontallyMergedClassesConsumer = this::fixInliningNullabilityClass;
               o.testing.horizontalClassMergingTarget =
                   (appView, candidates, target) -> {
@@ -152,6 +149,8 @@
 
   @Before
   public void generateR8Version() throws Exception {
+    // Triggers ART failure. See also b/205481246.
+    assumeFalse(parameters.isDexRuntimeVersion(Version.V6_0_1));
     outputDir = temp.newFolder().toPath();
     Path mapFile = outputDir.resolve(DEFAULT_MAP_FILENAME);
     generateR8Version(outputDir, mapFile, true);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/SimplifyIfNotNullTest.java b/src/test/java/com/android/tools/r8/ir/optimize/SimplifyIfNotNullTest.java
index da19669..868a400 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/SimplifyIfNotNullTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/SimplifyIfNotNullTest.java
@@ -7,6 +7,8 @@
 
 import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.ThrowableConsumer;
 import com.android.tools.r8.ir.optimize.nonnull.FieldAccessTest;
 import com.android.tools.r8.ir.optimize.nonnull.NonNullAfterArrayAccess;
@@ -20,9 +22,21 @@
 import com.google.common.collect.Streams;
 import java.util.List;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
+@RunWith(Parameterized.class)
 public class SimplifyIfNotNullTest extends TestBase {
 
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  @Parameter public TestParameters parameters;
+
   private void verifyAbsenceOfIf(
       CodeInspector codeInspector, Class<?> testClass, List<MethodSignature> signatures) {
     for (MethodSignature signature : signatures) {
@@ -43,11 +57,14 @@
       ThrowableConsumer<R8FullTestBuilder> configuration)
       throws Exception {
     CodeInspector codeInspector =
-        testForR8(Backend.DEX)
+        testForR8(parameters.getBackend())
+            .setMinApi(parameters.getApiLevel())
             .addProgramClasses(testClass)
             .addKeepRules("-keep class " + testClass.getCanonicalName() + " { *; }")
             .apply(configuration)
             .compile()
+            .run(parameters.getRuntime(), testClass)
+            .assertSuccessWithOutput("")
             .inspector();
     verifyAbsenceOfIf(codeInspector, testClass, signatures);
   }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationLibraryLambdaPropagationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationLibraryLambdaPropagationTest.java
index 9b42105..6f696b9 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationLibraryLambdaPropagationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationLibraryLambdaPropagationTest.java
@@ -8,36 +8,28 @@
 import com.android.tools.r8.NeverInline;
 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.BooleanUtils;
-import java.util.List;
 import java.util.function.Consumer;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class CallSiteOptimizationLibraryLambdaPropagationTest extends TestBase {
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(),
-        getTestParameters()
-            .withCfRuntimes()
-            .withDexRuntimes()
-            .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
-            .build());
-  }
-
-  public CallSiteOptimizationLibraryLambdaPropagationTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters()
+        .withCfRuntimes()
+        .withDexRuntimes()
+        .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+        .build();
   }
 
   @Test
@@ -45,12 +37,6 @@
     testForR8(parameters.getBackend())
         .addInnerClasses(CallSiteOptimizationLibraryLambdaPropagationTest.class)
         .addKeepMainRule(TestClass.class)
-        .addOptionsModification(
-            options ->
-                options
-                    .callSiteOptimizationOptions()
-                    .setEnableExperimentalArgumentPropagation(
-                        enableExperimentalArgumentPropagation))
         .enableInliningAnnotations()
         .enableNeverClassInliningAnnotations()
         .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationPinnedMethodOverridePropagationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationPinnedMethodOverridePropagationTest.java
index ea88ead..b65adaf 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationPinnedMethodOverridePropagationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationPinnedMethodOverridePropagationTest.java
@@ -11,12 +11,12 @@
 import com.android.tools.r8.R8TestCompileResult;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.TestParametersCollection;
 import com.google.common.collect.ImmutableList;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
@@ -25,19 +25,12 @@
   private static final String CLASS_PREFIX =
       "com.android.tools.r8.ir.optimize.callsites.CallSiteOptimizationPinnedMethodOverridePropagationTest$";
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
-  }
-
-  public CallSiteOptimizationPinnedMethodOverridePropagationTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withDexRuntimes().withAllApiLevels().build();
   }
 
   @Test
@@ -63,12 +56,6 @@
                         + "Arg getArg2(); \npublic static "
                         + CLASS_PREFIX
                         + "Call getCaller(); \n}"))
-            .addOptionsModification(
-                options ->
-                    options
-                        .callSiteOptimizationOptions()
-                        .setEnableExperimentalArgumentPropagation(
-                            enableExperimentalArgumentPropagation))
             .enableNoVerticalClassMergingAnnotations()
             .enableNoHorizontalClassMergingAnnotations()
             .enableInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationProgramLambdaPropagationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationProgramLambdaPropagationTest.java
index 2771975..b0624b7 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationProgramLambdaPropagationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationProgramLambdaPropagationTest.java
@@ -8,29 +8,22 @@
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.BooleanUtils;
-import java.util.List;
+import com.android.tools.r8.TestParametersCollection;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class CallSiteOptimizationProgramLambdaPropagationTest extends TestBase {
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
-  }
-
-  public CallSiteOptimizationProgramLambdaPropagationTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   @Test
@@ -38,12 +31,6 @@
     testForR8(parameters.getBackend())
         .addInnerClasses(CallSiteOptimizationProgramLambdaPropagationTest.class)
         .addKeepMainRule(TestClass.class)
-        .addOptionsModification(
-            options ->
-                options
-                    .callSiteOptimizationOptions()
-                    .setEnableExperimentalArgumentPropagation(
-                        enableExperimentalArgumentPropagation))
         .enableInliningAnnotations()
         .enableNeverClassInliningAnnotations()
         .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationWithInvokeCustomTargetTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationWithInvokeCustomTargetTest.java
index 5edca84..283718d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationWithInvokeCustomTargetTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationWithInvokeCustomTargetTest.java
@@ -12,7 +12,7 @@
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.google.common.collect.ImmutableList;
@@ -24,6 +24,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 import org.objectweb.asm.Handle;
 import org.objectweb.asm.Opcodes;
@@ -33,24 +34,16 @@
 
   private static final String EXPECTED = StringUtils.lines("Hello world!");
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(),
-        getTestParameters()
-            .withAllRuntimes()
-            // Only works when invoke-custom/dynamic are supported and ConstantCallSite defined.
-            .withApiLevelsStartingAtIncluding(apiLevelWithInvokeCustomSupport())
-            .build());
-  }
-
-  public CallSiteOptimizationWithInvokeCustomTargetTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters()
+        .withAllRuntimes()
+        // Only works when invoke-custom/dynamic are supported and ConstantCallSite defined.
+        .withApiLevelsStartingAtIncluding(apiLevelWithInvokeCustomSupport())
+        .build();
   }
 
   @Test
@@ -67,12 +60,6 @@
         .addProgramClassFileData(getProgramClassFileData())
         .addKeepMainRule(TestClass.class)
         .addKeepMethodRules(methodFromMethod(TestClass.class.getDeclaredMethod("bar", int.class)))
-        .addOptionsModification(
-            options ->
-                options
-                    .callSiteOptimizationOptions()
-                    .setEnableExperimentalArgumentPropagation(
-                        enableExperimentalArgumentPropagation))
         .enableInliningAnnotations()
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationWithLambdaTargetTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationWithLambdaTargetTest.java
index 20827d8..5b039ad 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationWithLambdaTargetTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/CallSiteOptimizationWithLambdaTargetTest.java
@@ -8,29 +8,22 @@
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.BooleanUtils;
-import java.util.List;
+import com.android.tools.r8.TestParametersCollection;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class CallSiteOptimizationWithLambdaTargetTest extends TestBase {
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
-  }
-
-  public CallSiteOptimizationWithLambdaTargetTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   @Test
@@ -38,12 +31,6 @@
     testForR8(parameters.getBackend())
         .addInnerClasses(CallSiteOptimizationWithLambdaTargetTest.class)
         .addKeepMainRule(TestClass.class)
-        .addOptionsModification(
-            options ->
-                options
-                    .callSiteOptimizationOptions()
-                    .setEnableExperimentalArgumentPropagation(
-                        enableExperimentalArgumentPropagation))
         .enableInliningAnnotations()
         .enableNeverClassInliningAnnotations()
         .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/HashCodeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/HashCodeTest.java
index 509465b..cf5ceb7 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/HashCodeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/HashCodeTest.java
@@ -6,12 +6,12 @@
 import com.android.tools.r8.NoVerticalClassMerging;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.utils.BooleanUtils;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
@@ -19,19 +19,13 @@
 
   private static final Class<?> MAIN = TestClass.class;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public HashCodeTest(boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
@@ -40,11 +34,8 @@
         .addKeepMainRule(MAIN)
         .enableNoVerticalClassMergingAnnotations()
         .addOptionsModification(
-            o -> {
-              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-              o.callSiteOptimizationOptions()
-                  .setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
-            })
+            o ->
+                o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect)
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("10");
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeInterfaceWithRefinedReceiverTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeInterfaceWithRefinedReceiverTest.java
index 2bf775f..f2c3fad 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeInterfaceWithRefinedReceiverTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeInterfaceWithRefinedReceiverTest.java
@@ -14,17 +14,17 @@
 import com.android.tools.r8.NoVerticalClassMerging;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
@@ -32,20 +32,13 @@
 
   private static final Class<?> MAIN = Main.class;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public InvokeInterfaceWithRefinedReceiverTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
@@ -62,8 +55,6 @@
               // target.
               o.enableDevirtualization = false;
               o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-              o.callSiteOptimizationOptions()
-                  .setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
             })
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeVirtualWithRefinedReceiverTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeVirtualWithRefinedReceiverTest.java
index 2556bf4..cedf279 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeVirtualWithRefinedReceiverTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeVirtualWithRefinedReceiverTest.java
@@ -14,37 +14,30 @@
 import com.android.tools.r8.NoVerticalClassMerging;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class InvokeVirtualWithRefinedReceiverTest extends TestBase {
   private static final Class<?> MAIN = Main.class;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public InvokeVirtualWithRefinedReceiverTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
@@ -56,11 +49,8 @@
         .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .addOptionsModification(
-            o -> {
-              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-              o.callSiteOptimizationOptions()
-                  .setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
-            })
+            o ->
+                o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect)
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("null", "C")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/KeptMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/KeptMethodTest.java
index 452e472..25f6b89 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/KeptMethodTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/KeptMethodTest.java
@@ -11,36 +11,30 @@
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import java.lang.reflect.Method;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class KeptMethodTest extends TestBase {
   private static final Class<?> MAIN = Main.class;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public KeptMethodTest(boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
@@ -48,12 +42,6 @@
         .addInnerClasses(KeptMethodTest.class)
         .addKeepMainRule(MAIN)
         .addKeepClassAndMembersRules(A.class)
-        .addOptionsModification(
-            options ->
-                options
-                    .callSiteOptimizationOptions()
-                    .setEnableExperimentalArgumentPropagation(
-                        enableExperimentalArgumentPropagation))
         .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .addOptionsModification(
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/LibraryMethodOverridesTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/LibraryMethodOverridesTest.java
index 2d6bec7..5fd1825 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/LibraryMethodOverridesTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/LibraryMethodOverridesTest.java
@@ -11,42 +11,34 @@
 import com.android.tools.r8.R8TestCompileResult;
 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.graph.ProgramMethod;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
 import java.util.function.Predicate;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 
 @RunWith(Parameterized.class)
 public class LibraryMethodOverridesTest extends TestBase {
   private static final Class<?> MAIN = TestClass.class;
 
-  @Parameterized.Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(),
-        getTestParameters()
-            .withCfRuntimes()
-            // java.util.function.Predicate is not available prior to API level 24 (V7.0).
-            .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
-            .build());
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters()
+        .withCfRuntimes()
+        // java.util.function.Predicate is not available prior to API level 24 (V7.0).
+        .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+        .build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public LibraryMethodOverridesTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
@@ -63,12 +55,6 @@
         .addOptionsModification(
             o ->
                 o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect)
-        .addOptionsModification(
-            options ->
-                options
-                    .callSiteOptimizationOptions()
-                    .setEnableExperimentalArgumentPropagation(
-                        enableExperimentalArgumentPropagation))
         .enableInliningAnnotations()
         .setMinApi(parameters.getRuntime())
         .compile()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/PropagationFromSiblingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/PropagationFromSiblingTest.java
index 0c04377..ff75a24 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/PropagationFromSiblingTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/PropagationFromSiblingTest.java
@@ -9,29 +9,22 @@
 import com.android.tools.r8.NoVerticalClassMerging;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.BooleanUtils;
-import java.util.List;
+import com.android.tools.r8.TestParametersCollection;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class PropagationFromSiblingTest extends TestBase {
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
+  @Parameter(0)
+  public TestParameters parameters;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
-  }
-
-  public PropagationFromSiblingTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   @Test
@@ -39,13 +32,7 @@
     testForR8(parameters.getBackend())
         .addInnerClasses(PropagationFromSiblingTest.class)
         .addKeepMainRule(TestClass.class)
-        .addOptionsModification(
-            options -> {
-              options.enableUnusedInterfaceRemoval = false;
-              options
-                  .callSiteOptimizationOptions()
-                  .setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
-            })
+        .addOptionsModification(options -> options.enableUnusedInterfaceRemoval = false)
         .enableInliningAnnotations()
         .enableNoVerticalClassMergingAnnotations()
         .enableNeverClassInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/WithStaticizerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/WithStaticizerTest.java
index f392b1d..07df10b 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/WithStaticizerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/WithStaticizerTest.java
@@ -13,15 +13,15 @@
 import com.android.tools.r8.NoHorizontalClassMerging;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
@@ -29,33 +29,20 @@
 
   private static final Class<?> MAIN = Main.class;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
     // TODO(b/112831361): support for class staticizer in CF backend.
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
+    return getTestParameters().withDexRuntimes().withAllApiLevels().build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public WithStaticizerTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
     testForR8(parameters.getBackend())
         .addInnerClasses(WithStaticizerTest.class)
         .addKeepMainRule(MAIN)
-        .addOptionsModification(
-            options ->
-                options
-                    .callSiteOptimizationOptions()
-                    .setEnableExperimentalArgumentPropagation(
-                        enableExperimentalArgumentPropagation))
         .enableInliningAnnotations()
         .enableNeverClassInliningAnnotations()
         .enableNoHorizontalClassMergingAnnotations()
@@ -75,12 +62,7 @@
     assertThat(host, isPresent());
     MethodSubject foo = host.uniqueMethodWithName("foo");
     assertThat(foo, isPresent());
-    if (enableExperimentalArgumentPropagation) {
-      assertTrue(foo.streamInstructions().noneMatch(InstructionSubject::isIf));
-    } else {
-      // TODO(b/139246447): Can optimize branches since `arg` is definitely not null.
-      assertTrue(foo.streamInstructions().anyMatch(InstructionSubject::isIf));
-    }
+    assertTrue(foo.streamInstructions().noneMatch(InstructionSubject::isIf));
   }
 
   @NeverClassInline
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectNegativeTest.java
index 3716b6d..0a68ca4 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectNegativeTest.java
@@ -11,17 +11,17 @@
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
@@ -29,20 +29,13 @@
 
   private static final Class<?> MAIN = Main.class;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public InvokeDirectNegativeTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
@@ -52,11 +45,8 @@
         .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .addOptionsModification(
-            o -> {
-              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-              o.callSiteOptimizationOptions()
-                  .setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
-            })
+            o ->
+                o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect)
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("null", "non-null")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectPositiveTest.java
index 70d3f3b..f726e4f 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectPositiveTest.java
@@ -12,18 +12,15 @@
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.analysis.value.AbstractValue;
-import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
@@ -31,72 +28,41 @@
 
   private static final Class<?> MAIN = Main.class;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public InvokeDirectPositiveTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
     testForR8(parameters.getBackend())
         .addInnerClasses(InvokeDirectPositiveTest.class)
         .addKeepMainRule(MAIN)
-        .addOptionsModification(
-            o -> {
-              if (!enableExperimentalArgumentPropagation) {
-                o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-              }
-              o.callSiteOptimizationOptions()
-                  .setEnableLegacyConstantPropagation()
-                  .setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
-            })
         .enableInliningAnnotations()
         .enableNeverClassInliningAnnotations()
         // TODO(b/173398086): uniqueMethodWithName() does not work with argument removal.
-        .minification(!enableExperimentalArgumentPropagation)
+        .noMinification()
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("non-null")
         .inspect(this::inspect);
   }
 
-  private void callSiteOptimizationInfoInspect(ProgramMethod method) {
-    assert method.getReference().name.toString().equals("test")
-        : "Unexpected revisit: " + method.toSourceString();
-    CallSiteOptimizationInfo callSiteOptimizationInfo =
-        method.getDefinition().getCallSiteOptimizationInfo();
-    AbstractValue abstractValue = callSiteOptimizationInfo.getAbstractArgumentValue(1);
-    assert abstractValue.isSingleStringValue()
-        && abstractValue.asSingleStringValue().getDexString().toString().equals("nul");
-  }
-
   private void inspect(CodeInspector inspector) {
     ClassSubject main = inspector.clazz(MAIN);
     assertThat(main, isPresent());
 
-    if (enableExperimentalArgumentPropagation) {
-      // Verify that the "nul" argument has been propagated to the test() method.
-      MethodSubject mainMethodSubject = main.mainMethod();
-      assertThat(mainMethodSubject, isPresent());
-      assertTrue(
-          mainMethodSubject.streamInstructions().noneMatch(InstructionSubject::isConstString));
-    }
+    // Verify that the "nul" argument has been propagated to the test() method.
+    MethodSubject mainMethodSubject = main.mainMethod();
+    assertThat(mainMethodSubject, isPresent());
+    assertTrue(mainMethodSubject.streamInstructions().noneMatch(InstructionSubject::isConstString));
 
     MethodSubject test = main.uniqueMethodWithName("test");
     assertThat(test, isPresent());
-    assertEquals(
-        1 - BooleanUtils.intValue(enableExperimentalArgumentPropagation),
-        test.getProgramMethod().getReference().getArity());
+    assertEquals(0, test.getProgramMethod().getReference().getArity());
     // Can optimize branches since `arg` is definitely "nul", i.e., not containing "null".
     assertTrue(test.streamInstructions().noneMatch(InstructionSubject::isIf));
   }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfaceNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfaceNegativeTest.java
index 896d548..8636291 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfaceNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfaceNegativeTest.java
@@ -12,17 +12,17 @@
 import com.android.tools.r8.NoVerticalClassMerging;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
@@ -30,20 +30,13 @@
 
   private static final Class<?> MAIN = Main.class;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public InvokeInterfaceNegativeTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
@@ -59,8 +52,6 @@
               // target.
               o.enableDevirtualization = false;
               o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-              o.callSiteOptimizationOptions()
-                  .setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
             })
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfacePositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfacePositiveTest.java
index 5612674..7ed853e 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfacePositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfacePositiveTest.java
@@ -13,18 +13,18 @@
 import com.android.tools.r8.NoHorizontalClassMerging;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
 import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
@@ -32,43 +32,27 @@
 
   private static final Class<?> MAIN = Main.class;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public InvokeInterfacePositiveTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
     testForR8(parameters.getBackend())
         .addInnerClasses(InvokeInterfacePositiveTest.class)
         .addKeepMainRule(MAIN)
-        .addOptionsModification(
-            o -> {
-              // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single
-              // target.
-              o.enableDevirtualization = false;
-              if (!enableExperimentalArgumentPropagation) {
-                o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-              }
-              o.callSiteOptimizationOptions()
-                  .setEnableLegacyConstantPropagation()
-                  .setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
-            })
+        // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single
+        // target.
+        .addOptionsModification(o -> o.enableDevirtualization = false)
         .enableInliningAnnotations()
         .enableNeverClassInliningAnnotations()
         .enableNoHorizontalClassMergingAnnotations()
         // TODO(b/173398086): uniqueMethodWithName() does not work with argument removal.
-        .minification(!enableExperimentalArgumentPropagation)
+        .noMinification()
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("non-null")
@@ -90,31 +74,24 @@
     ClassSubject main = inspector.clazz(MAIN);
     assertThat(main, isPresent());
 
-    if (enableExperimentalArgumentPropagation) {
-      // Verify that the "nul" argument has been propagated to the m() methods.
-      MethodSubject mainMethodSubject = main.mainMethod();
-      assertThat(mainMethodSubject, isPresent());
-      assertTrue(
-          mainMethodSubject.streamInstructions().noneMatch(InstructionSubject::isConstString));
-    }
+    // Verify that the "nul" argument has been propagated to the m() methods.
+    MethodSubject mainMethodSubject = main.mainMethod();
+    assertThat(mainMethodSubject, isPresent());
+    assertTrue(mainMethodSubject.streamInstructions().noneMatch(InstructionSubject::isConstString));
 
     ClassSubject i = inspector.clazz(I.class);
     assertThat(i, isPresent());
 
     MethodSubject i_m = i.uniqueMethodWithName("m");
     assertThat(i_m, isPresent());
-    assertEquals(
-        1 - BooleanUtils.intValue(enableExperimentalArgumentPropagation),
-        i_m.getProgramMethod().getReference().getArity());
+    assertEquals(0, i_m.getProgramMethod().getReference().getArity());
 
     ClassSubject a = inspector.clazz(A.class);
     assertThat(a, isPresent());
 
     MethodSubject a_m = a.uniqueMethodWithName("m");
     assertThat(a_m, isPresent());
-    assertEquals(
-        1 - BooleanUtils.intValue(enableExperimentalArgumentPropagation),
-        a_m.getProgramMethod().getReference().getArity());
+    assertEquals(0, a_m.getProgramMethod().getReference().getArity());
     // Can optimize branches since `arg` is definitely "nul", i.e., not containing "null".
     assertTrue(a_m.streamInstructions().noneMatch(InstructionSubject::isIf));
 
@@ -123,9 +100,7 @@
 
     MethodSubject b_m = b.uniqueMethodWithName("m");
     assertThat(b_m, isPresent());
-    assertEquals(
-        1 - BooleanUtils.intValue(enableExperimentalArgumentPropagation),
-        b_m.getProgramMethod().getReference().getArity());
+    assertEquals(0, b_m.getProgramMethod().getReference().getArity());
     // Can optimize branches since `arg` is definitely "nul", i.e., not containing "null".
     assertTrue(b_m.streamInstructions().noneMatch(InstructionSubject::isIf));
   }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeStaticNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeStaticNegativeTest.java
index 8457c5c..ac071d2 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeStaticNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeStaticNegativeTest.java
@@ -10,17 +10,17 @@
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
@@ -28,20 +28,13 @@
 
   private static final Class<?> MAIN = Main.class;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public InvokeStaticNegativeTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
@@ -50,11 +43,8 @@
         .addKeepMainRule(MAIN)
         .enableInliningAnnotations()
         .addOptionsModification(
-            o -> {
-              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-              o.callSiteOptimizationOptions()
-                  .setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
-            })
+            o ->
+                o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect)
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("null", "non-null")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeStaticPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeStaticPositiveTest.java
index 3f9baaa..3694dc8 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeStaticPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeStaticPositiveTest.java
@@ -11,18 +11,15 @@
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.analysis.value.AbstractValue;
-import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
@@ -30,72 +27,41 @@
 
   private static final Class<?> MAIN = Main.class;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public InvokeStaticPositiveTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
     testForR8(parameters.getBackend())
         .addInnerClasses(InvokeStaticPositiveTest.class)
         .addKeepMainRule(MAIN)
-        .addOptionsModification(
-            o -> {
-              if (!enableExperimentalArgumentPropagation) {
-                o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-              }
-              o.callSiteOptimizationOptions()
-                  .setEnableLegacyConstantPropagation()
-                  .setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
-            })
         .enableInliningAnnotations()
         // TODO(b/173398086): uniqueMethodWithName() does not work with argument removal.
-        .minification(!enableExperimentalArgumentPropagation)
+        .noMinification()
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("non-null")
         .inspect(this::inspect);
   }
 
-  private void callSiteOptimizationInfoInspect(ProgramMethod method) {
-    assert method.getReference().name.toString().equals("test")
-        : "Unexpected revisit: " + method.toSourceString();
-    CallSiteOptimizationInfo callSiteOptimizationInfo =
-        method.getDefinition().getCallSiteOptimizationInfo();
-    assert callSiteOptimizationInfo.getDynamicUpperBoundType(0).isDefinitelyNotNull();
-    AbstractValue abstractValue = callSiteOptimizationInfo.getAbstractArgumentValue(0);
-    assert abstractValue.isSingleStringValue()
-        && abstractValue.asSingleStringValue().getDexString().toString().equals("nul");
-  }
-
   private void inspect(CodeInspector inspector) {
     ClassSubject main = inspector.clazz(MAIN);
     assertThat(main, isPresent());
 
-    if (enableExperimentalArgumentPropagation) {
       // Verify that the "nul" argument has been propagated to the test() method.
       MethodSubject mainMethodSubject = main.mainMethod();
       assertThat(mainMethodSubject, isPresent());
       assertTrue(
           mainMethodSubject.streamInstructions().noneMatch(InstructionSubject::isConstString));
-    }
 
     MethodSubject test = main.uniqueMethodWithName("test");
     assertThat(test, isPresent());
-    assertEquals(
-        1 - BooleanUtils.intValue(enableExperimentalArgumentPropagation),
-        test.getProgramMethod().getReference().getArity());
+    assertEquals(0, test.getProgramMethod().getReference().getArity());
     // Can optimize branches since `arg` is definitely "nul", i.e., not containing "null".
     assertTrue(test.streamInstructions().noneMatch(InstructionSubject::isIf));
   }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualNegativeTest.java
index 7464d26..10df35d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualNegativeTest.java
@@ -12,17 +12,17 @@
 import com.android.tools.r8.NoVerticalClassMerging;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
@@ -30,20 +30,13 @@
 
   private static final Class<?> MAIN = Main.class;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public InvokeVirtualNegativeTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
@@ -54,11 +47,8 @@
         .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .addOptionsModification(
-            o -> {
-              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-              o.callSiteOptimizationOptions()
-                  .setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
-            })
+            o ->
+                o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect)
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("null", "non-null", "null", "non-null")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java
index f3b3324..6eef61d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java
@@ -12,38 +12,31 @@
 import com.android.tools.r8.NoVerticalClassMerging;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
 import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class InvokeVirtualPositiveTest extends TestBase {
   private static final Class<?> MAIN = Main.class;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public InvokeVirtualPositiveTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
@@ -51,12 +44,8 @@
         .addInnerClasses(InvokeVirtualPositiveTest.class)
         .addKeepMainRule(MAIN)
         .addOptionsModification(
-            o -> {
-              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-              o.callSiteOptimizationOptions()
-                  .setEnableLegacyConstantPropagation()
-                  .setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
-            })
+            o ->
+                o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect)
         .enableNoVerticalClassMergingAnnotations()
         .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectNegativeTest.java
index 4a6d03d..148d988 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectNegativeTest.java
@@ -11,38 +11,31 @@
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class InvokeDirectNegativeTest extends TestBase {
   private static final Class<?> MAIN = Main.class;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public InvokeDirectNegativeTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
@@ -52,11 +45,8 @@
         .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .addOptionsModification(
-            o -> {
-              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-              o.callSiteOptimizationOptions()
-                  .setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
-            })
+            o ->
+                o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect)
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("Sub1", "Sub2")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectPositiveTest.java
index d23ed49..6bb75b3 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectPositiveTest.java
@@ -12,38 +12,31 @@
 import com.android.tools.r8.NoVerticalClassMerging;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class InvokeDirectPositiveTest extends TestBase {
   private static final Class<?> MAIN = Main.class;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public InvokeDirectPositiveTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
@@ -54,11 +47,8 @@
         .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .addOptionsModification(
-            o -> {
-              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-              o.callSiteOptimizationOptions()
-                  .setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
-            })
+            o ->
+                o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect)
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("Sub1")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfaceNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfaceNegativeTest.java
index 20b0d1f..e77cbaa 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfaceNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfaceNegativeTest.java
@@ -12,38 +12,31 @@
 import com.android.tools.r8.NoVerticalClassMerging;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class InvokeInterfaceNegativeTest extends TestBase {
   private static final Class<?> MAIN = Main.class;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public InvokeInterfaceNegativeTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
@@ -59,8 +52,6 @@
               // target.
               o.enableDevirtualization = false;
               o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-              o.callSiteOptimizationOptions()
-                  .setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
             })
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfacePositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfacePositiveTest.java
index b39540b..045742d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfacePositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfacePositiveTest.java
@@ -13,38 +13,31 @@
 import com.android.tools.r8.NoVerticalClassMerging;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class InvokeInterfacePositiveTest extends TestBase {
   private static final Class<?> MAIN = Main.class;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public InvokeInterfacePositiveTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
@@ -61,8 +54,6 @@
               // target.
               o.enableDevirtualization = false;
               o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-              o.callSiteOptimizationOptions()
-                  .setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
             })
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeStaticNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeStaticNegativeTest.java
index 6ae9004..2362fd6 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeStaticNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeStaticNegativeTest.java
@@ -10,38 +10,31 @@
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class InvokeStaticNegativeTest extends TestBase {
   private static final Class<?> MAIN = Main.class;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public InvokeStaticNegativeTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
@@ -50,11 +43,8 @@
         .addKeepMainRule(MAIN)
         .enableInliningAnnotations()
         .addOptionsModification(
-            o -> {
-              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-              o.callSiteOptimizationOptions()
-                  .setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
-            })
+            o ->
+                o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect)
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("Sub1", "Sub2")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeStaticPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeStaticPositiveTest.java
index 410d528..027d715 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeStaticPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeStaticPositiveTest.java
@@ -11,38 +11,31 @@
 import com.android.tools.r8.NoVerticalClassMerging;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class InvokeStaticPositiveTest extends TestBase {
   private static final Class<?> MAIN = Main.class;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public InvokeStaticPositiveTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
@@ -52,11 +45,8 @@
         .enableNoVerticalClassMergingAnnotations()
         .enableInliningAnnotations()
         .addOptionsModification(
-            o -> {
-              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-              o.callSiteOptimizationOptions()
-                  .setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
-            })
+            o ->
+                o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect)
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("Sub1")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualNegativeTest.java
index 1db7baa..2b666d2 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualNegativeTest.java
@@ -12,38 +12,31 @@
 import com.android.tools.r8.NoVerticalClassMerging;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class InvokeVirtualNegativeTest extends TestBase {
   private static final Class<?> MAIN = Main.class;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public InvokeVirtualNegativeTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
@@ -54,11 +47,8 @@
         .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .addOptionsModification(
-            o -> {
-              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-              o.callSiteOptimizationOptions()
-                  .setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
-            })
+            o ->
+                o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect)
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("A:Sub1", "A:Sub2", "B:Sub1", "B:Sub2")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualPositiveTest.java
index adce8cc..56fdde5 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualPositiveTest.java
@@ -12,38 +12,31 @@
 import com.android.tools.r8.NoVerticalClassMerging;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class InvokeVirtualPositiveTest extends TestBase {
   private static final Class<?> MAIN = Main.class;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public InvokeVirtualPositiveTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
@@ -54,11 +47,8 @@
         .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .addOptionsModification(
-            o -> {
-              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-              o.callSiteOptimizationOptions()
-                  .setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
-            })
+            o ->
+                o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect)
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("A:Sub1", "B:Sub1")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectNegativeTest.java
index 05d1329..0372989 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectNegativeTest.java
@@ -11,36 +11,29 @@
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class InvokeDirectNegativeTest extends TestBase {
   private static final Class<?> MAIN = Main.class;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public InvokeDirectNegativeTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
@@ -50,11 +43,8 @@
         .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .addOptionsModification(
-            o -> {
-              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-              o.callSiteOptimizationOptions()
-                  .setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
-            })
+            o ->
+                o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect)
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("null", "non-null")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectPositiveTest.java
index 3a6fd02..8a88c46 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectPositiveTest.java
@@ -11,37 +11,30 @@
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class InvokeDirectPositiveTest extends TestBase {
   private static final Class<?> MAIN = Main.class;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public InvokeDirectPositiveTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
@@ -51,11 +44,8 @@
         .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .addOptionsModification(
-            o -> {
-              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-              o.callSiteOptimizationOptions()
-                  .setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
-            })
+            o ->
+                o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect)
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("non-null")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfaceNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfaceNegativeTest.java
index 421ebf0..7624d2a 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfaceNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfaceNegativeTest.java
@@ -12,38 +12,31 @@
 import com.android.tools.r8.NoVerticalClassMerging;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class InvokeInterfaceNegativeTest extends TestBase {
   private static final Class<?> MAIN = Main.class;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public InvokeInterfaceNegativeTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
@@ -59,8 +52,6 @@
               // target.
               o.enableDevirtualization = false;
               o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-              o.callSiteOptimizationOptions()
-                  .setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
             })
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfacePositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfacePositiveTest.java
index 6d0aab9..904e53c 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfacePositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfacePositiveTest.java
@@ -12,37 +12,30 @@
 import com.android.tools.r8.NoHorizontalClassMerging;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class InvokeInterfacePositiveTest extends TestBase {
   private static final Class<?> MAIN = Main.class;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public InvokeInterfacePositiveTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
@@ -58,8 +51,6 @@
               // target.
               o.enableDevirtualization = false;
               o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-              o.callSiteOptimizationOptions()
-                  .setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
             })
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeStaticNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeStaticNegativeTest.java
index a7fff40..6175434 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeStaticNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeStaticNegativeTest.java
@@ -10,36 +10,29 @@
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class InvokeStaticNegativeTest extends TestBase {
   private static final Class<?> MAIN = Main.class;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public InvokeStaticNegativeTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
@@ -48,11 +41,8 @@
         .addKeepMainRule(MAIN)
         .enableInliningAnnotations()
         .addOptionsModification(
-            o -> {
-              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-              o.callSiteOptimizationOptions()
-                  .setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
-            })
+            o ->
+                o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect)
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("null", "non-null")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeStaticPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeStaticPositiveTest.java
index 0b27105..c226571 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeStaticPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeStaticPositiveTest.java
@@ -10,37 +10,30 @@
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class InvokeStaticPositiveTest extends TestBase {
   private static final Class<?> MAIN = Main.class;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public InvokeStaticPositiveTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
@@ -49,11 +42,8 @@
         .addKeepMainRule(MAIN)
         .enableInliningAnnotations()
         .addOptionsModification(
-            o -> {
-              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-              o.callSiteOptimizationOptions()
-                  .setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
-            })
+            o ->
+                o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect)
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("non-null")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualCascadeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualCascadeTest.java
index 627171a..60e3dd8 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualCascadeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualCascadeTest.java
@@ -12,47 +12,34 @@
 import com.android.tools.r8.NoVerticalClassMerging;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class InvokeVirtualCascadeTest extends TestBase {
   private static final Class<?> MAIN = Main.class;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public InvokeVirtualCascadeTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
     testForR8(parameters.getBackend())
         .addInnerClasses(InvokeVirtualCascadeTest.class)
         .addKeepMainRule(MAIN)
-        .addOptionsModification(
-            options ->
-                options
-                    .callSiteOptimizationOptions()
-                    .setEnableExperimentalArgumentPropagation(
-                        enableExperimentalArgumentPropagation))
         .enableNoVerticalClassMergingAnnotations()
         .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
@@ -68,24 +55,14 @@
 
     MethodSubject a_m = a.uniqueMethodWithName("m");
     assertThat(a_m, isPresent());
-    if (enableExperimentalArgumentPropagation) {
       assertTrue(a_m.streamInstructions().noneMatch(InstructionSubject::isIf));
-    } else {
-      // TODO(b/139246447): Can optimize branches since `arg` is definitely not null.
-      assertTrue(a_m.streamInstructions().anyMatch(InstructionSubject::isIf));
-    }
 
     ClassSubject b = inspector.clazz(B.class);
     assertThat(b, isPresent());
 
     MethodSubject b_m = b.uniqueMethodWithName("m");
     assertThat(b_m, isPresent());
-    if (enableExperimentalArgumentPropagation) {
-      assertTrue(b_m.streamInstructions().noneMatch(InstructionSubject::isIf));
-    } else {
-      // TODO(b/139246447): Can optimize branches since `arg` is definitely not null.
-      assertTrue(b_m.streamInstructions().anyMatch(InstructionSubject::isIf));
-    }
+    assertTrue(b_m.streamInstructions().noneMatch(InstructionSubject::isIf));
   }
 
   @NoVerticalClassMerging
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualNegativeTest.java
index b9b1f2f..500f34a 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualNegativeTest.java
@@ -12,38 +12,31 @@
 import com.android.tools.r8.NoVerticalClassMerging;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class InvokeVirtualNegativeTest extends TestBase {
   private static final Class<?> MAIN = Main.class;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public InvokeVirtualNegativeTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
@@ -54,11 +47,8 @@
         .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .addOptionsModification(
-            o -> {
-              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-              o.callSiteOptimizationOptions()
-                  .setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
-            })
+            o ->
+                o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect)
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("null", "A", "null", "B")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualPositiveTest.java
index 8e1031a..c294462 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualPositiveTest.java
@@ -12,38 +12,31 @@
 import com.android.tools.r8.NoVerticalClassMerging;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class InvokeVirtualPositiveTest extends TestBase {
   private static final Class<?> MAIN = Main.class;
 
-  @Parameters(name = "{1}, experimental: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final boolean enableExperimentalArgumentPropagation;
-  private final TestParameters parameters;
-
-  public InvokeVirtualPositiveTest(
-      boolean enableExperimentalArgumentPropagation, TestParameters parameters) {
-    this.enableExperimentalArgumentPropagation = enableExperimentalArgumentPropagation;
-    this.parameters = parameters;
-  }
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Test
   public void testR8() throws Exception {
@@ -54,11 +47,8 @@
         .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .addOptionsModification(
-            o -> {
-              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-              o.callSiteOptimizationOptions()
-                  .setEnableExperimentalArgumentPropagation(enableExperimentalArgumentPropagation);
-            })
+            o ->
+                o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect)
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("A", "null")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/B135918413.java b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/B135918413.java
index c9cc17b..b171525 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/B135918413.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/B135918413.java
@@ -90,7 +90,7 @@
       } else {
         dead();
       }
-      if (Config.alwaysEmpty.length == 0) {
+      if (Config.alwaysEmpty.clone().length == 0) {
         System.out.print(" world");
       }
       for (String str : Config.alwaysNonEmpty) {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/StatePropagationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/StatePropagationTest.java
new file mode 100644
index 0000000..f4b90ed
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/StatePropagationTest.java
@@ -0,0 +1,87 @@
+// 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.membervaluepropagation;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ir.optimize.membervaluepropagation.StatePropagationTest.TestClass.Data;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class StatePropagationTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public StatePropagationTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(StatePropagationTest.class)
+        .addKeepMainRule(TestClass.class)
+        .setMinApi(parameters.getApiLevel())
+        .enableInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
+        .compile()
+        .inspect(this::inspect)
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutputLines("1", "1.0", "2", "2.0");
+  }
+
+  private void inspect(CodeInspector inspector) {
+    ClassSubject data = inspector.clazz(Data.class);
+    assertEquals(0, data.allInstanceFields().size());
+  }
+
+  static class TestClass {
+
+    @NeverClassInline
+    static class Data {
+      final int i;
+      final float j;
+
+      private Data(int i, float j) {
+        this.i = i;
+        this.j = j;
+      }
+    }
+
+    @NeverInline
+    public static Data getData1() {
+      return new Data(1, 1.0f);
+    }
+
+    @NeverInline
+    public static Data getData2() {
+      return new Data(2, 2.0f);
+    }
+
+    public static void main(String[] args) {
+      Data data1 = getData1();
+      Data data2 = getData2();
+      System.out.println(data1.i);
+      System.out.println(data1.j);
+      System.out.println(data2.i);
+      System.out.println(data2.j);
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/fields/FieldInitializedByConstantArgumentSubtypeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/fields/FieldInitializedByConstantArgumentSubtypeTest.java
index c460e16..97b57f4 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/fields/FieldInitializedByConstantArgumentSubtypeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/fields/FieldInitializedByConstantArgumentSubtypeTest.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.ir.optimize.membervaluepropagation.fields;
 
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
 
@@ -50,8 +51,7 @@
     ClassSubject testClassSubject = inspector.clazz(TestClass.class);
     assertThat(testClassSubject, isPresent());
     assertThat(testClassSubject.uniqueMethodWithName("live"), isPresent());
-    // TODO(b/147652121): Should be absent.
-    assertThat(testClassSubject.uniqueMethodWithName("dead"), isPresent());
+    assertThat(testClassSubject.uniqueMethodWithName("dead"), isAbsent());
   }
 
   static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetClassTest.java b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetClassTest.java
index 3f0c8d6..55867a1 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetClassTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetClassTest.java
@@ -146,13 +146,6 @@
     this.mode = mode;
   }
 
-  private void configure(InternalOptions options) {
-    // In `getMainClass`, a call with `null`, which will throw NPE, is replaced with null throwing
-    // code. Then, remaining call with non-null argument made getClass() replaceable.
-    // Disable the propagation of call site information to separate the tests.
-    options.callSiteOptimizationOptions().disableDynamicTypePropagationForTesting();
-  }
-
   @Test
   public void testJVM() throws Exception {
     assumeTrue(
@@ -223,7 +216,6 @@
         .enableNoHorizontalClassMergingAnnotations()
         .addKeepMainRule(MAIN)
         .noMinification()
-        .addOptionsModification(this::configure)
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutput(JAVA_OUTPUT)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java b/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java
index e3fe71a..3ea38e7 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java
@@ -9,6 +9,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assume.assumeTrue;
 
+import com.android.tools.r8.KeepConstantArguments;
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.NeverPropagateValue;
 import com.android.tools.r8.SingleTestRunResult;
@@ -55,10 +56,6 @@
   }
 
   private void configure(InternalOptions options) {
-    // Disable the propagation of call site information to test String#valueOf optimization with
-    // nullable argument. Otherwise, e.g., we know that only `null` is used for `hideNPE`, and then
-    // simplify everything in that method.
-    options.callSiteOptimizationOptions().disableDynamicTypePropagationForTesting();
     options.testing.forceNameReflectionOptimization = true;
   }
 
@@ -86,12 +83,12 @@
     ClassSubject mainClass = codeInspector.clazz(MAIN);
     MethodSubject mainMethod = mainClass.mainMethod();
     assertThat(mainMethod, isPresent());
-    int expectedCount = isR8 ? 4 : (isRelease ? 5 : 7);
+    int expectedCount = isR8 ? 3 : (isRelease ? 5 : 7);
     assertEquals(expectedCount, countCall(mainMethod, "String", "valueOf"));
     // Due to the different behavior regarding constant canonicalization.
-    expectedCount = isR8 ? (parameters.isCfRuntime() ? 4 : 1) : 1;
+    expectedCount = isR8 ? (parameters.isCfRuntime() ? 2 : 1) : 1;
     assertEquals(expectedCount, countConstNullNumber(mainMethod));
-    expectedCount = isR8 ? 1 : (isRelease ? 1 : 0);
+    expectedCount = isR8 ? (parameters.isCfRuntime() ? 2 : 1) : (isRelease ? 1 : 0);
     assertEquals(expectedCount, countNullStringNumber(mainMethod));
 
     MethodSubject hideNPE = mainClass.uniqueMethodWithName("hideNPE");
@@ -111,6 +108,7 @@
     SingleTestRunResult<?> result =
         testForR8(parameters.getBackend())
             .addProgramClassesAndInnerClasses(MAIN)
+            .enableConstantArgumentAnnotations()
             .enableInliningAnnotations()
             .enableMemberValuePropagationAnnotations()
             .addKeepMainRule(MAIN)
@@ -155,6 +153,7 @@
       return String.valueOf(arg);
     }
 
+    @KeepConstantArguments
     @NeverInline
     static String hideNPE(String s) {
       return String.valueOf(s);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsDoubleTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsDoubleTest.java
index 282371b..4d4654d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsDoubleTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsDoubleTest.java
@@ -9,23 +9,17 @@
 import com.android.tools.r8.KeepConstantArguments;
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
-import java.util.Collection;
 import org.junit.Assert;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class UnusedArgumentsDoubleTest extends UnusedArgumentsTestBase {
 
-  public UnusedArgumentsDoubleTest(boolean minification) {
-    super(minification);
-  }
-
-  @Parameters(name = "minification:{0}")
-  public static Collection<Object[]> data() {
-    return UnusedArgumentsTestBase.data();
+  public UnusedArgumentsDoubleTest(TestParameters parameters, boolean minification) {
+    super(parameters, minification);
   }
 
   static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsIntTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsIntTest.java
index 80309b2..c1a0a21 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsIntTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsIntTest.java
@@ -9,26 +9,20 @@
 import com.android.tools.r8.KeepConstantArguments;
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.google.common.collect.ImmutableSet;
-import java.util.Collection;
 import java.util.Set;
 import org.junit.Assert;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class UnusedArgumentsIntTest extends UnusedArgumentsTestBase {
   private static final Set<String> methodsThatWontBeOptimized = ImmutableSet.of("main", "iinc");
 
-  public UnusedArgumentsIntTest(boolean minification) {
-    super(minification);
-  }
-
-  @Parameters(name = "minification:{0}")
-  public static Collection<Object[]> data() {
-    return UnusedArgumentsTestBase.data();
+  public UnusedArgumentsIntTest(TestParameters parameters, boolean minification) {
+    super(parameters, minification);
   }
 
   static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsLongTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsLongTest.java
index 0dba75b..8723f36 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsLongTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsLongTest.java
@@ -9,23 +9,17 @@
 import com.android.tools.r8.KeepConstantArguments;
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
-import java.util.Collection;
 import org.junit.Assert;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class UnusedArgumentsLongTest extends UnusedArgumentsTestBase {
 
-  public UnusedArgumentsLongTest(boolean minification) {
-    super(minification);
-  }
-
-  @Parameters(name = "minification:{0}")
-  public static Collection<Object[]> data() {
-    return UnusedArgumentsTestBase.data();
+  public UnusedArgumentsLongTest(TestParameters parameters, boolean minification) {
+    super(parameters, minification);
   }
 
   static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsMixedTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsMixedTest.java
index dd63e78..78a0882 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsMixedTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsMixedTest.java
@@ -9,23 +9,17 @@
 import com.android.tools.r8.KeepConstantArguments;
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
-import java.util.Collection;
 import org.junit.Assert;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class UnusedArgumentsMixedTest extends UnusedArgumentsTestBase {
 
-  public UnusedArgumentsMixedTest(boolean minification) {
-    super(minification);
-  }
-
-  @Parameters(name = "minification:{0}")
-  public static Collection<Object[]> data() {
-    return UnusedArgumentsTestBase.data();
+  public UnusedArgumentsMixedTest(TestParameters parameters, boolean minification) {
+    super(parameters, minification);
   }
 
   static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsMixedWidthTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsMixedWidthTest.java
index 7ed9021..175d3ba 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsMixedWidthTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsMixedWidthTest.java
@@ -9,23 +9,17 @@
 import com.android.tools.r8.KeepConstantArguments;
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
-import java.util.Collection;
 import org.junit.Assert;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class UnusedArgumentsMixedWidthTest extends UnusedArgumentsTestBase {
 
-  public UnusedArgumentsMixedWidthTest(boolean minification) {
-    super(minification);
-  }
-
-  @Parameters(name = "minification:{0}")
-  public static Collection<Object[]> data() {
-    return UnusedArgumentsTestBase.data();
+  public UnusedArgumentsMixedWidthTest(TestParameters parameters, boolean minification) {
+    super(parameters, minification);
   }
 
   static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsObjectTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsObjectTest.java
index 3a4eeda..c06823f 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsObjectTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsObjectTest.java
@@ -9,24 +9,19 @@
 import com.android.tools.r8.NeverClassInline;
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.google.common.collect.ImmutableList;
 import java.util.Collection;
 import org.junit.Assert;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class UnusedArgumentsObjectTest extends UnusedArgumentsTestBase {
 
-  public UnusedArgumentsObjectTest(boolean minification) {
-    super(minification);
-  }
-
-  @Parameters(name = "minification:{0}")
-  public static Collection<Object[]> data() {
-    return UnusedArgumentsTestBase.data();
+  public UnusedArgumentsObjectTest(TestParameters parameters, boolean minification) {
+    super(parameters, minification);
   }
 
   @NeverClassInline
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsTestBase.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsTestBase.java
index 946cc63..d88a978 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsTestBase.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsTestBase.java
@@ -6,27 +6,38 @@
 
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assume.assumeFalse;
 
 import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersBuilder;
+import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.google.common.collect.ImmutableList;
 import java.util.Collection;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 import org.junit.runners.Parameterized.Parameters;
 
+@RunWith(Parameterized.class)
 public abstract class UnusedArgumentsTestBase extends TestBase {
 
+  private final TestParameters parameters;
   private final boolean minification;
 
-  public UnusedArgumentsTestBase(boolean minification) {
+  public UnusedArgumentsTestBase(TestParameters parameters, boolean minification) {
+    this.parameters = parameters;
     this.minification = minification;
   }
 
-  @Parameters(name = "minification:{0}")
+  @Parameters(name = "{0}, minification:{1}")
   public static Collection<Object[]> data() {
-    return ImmutableList.of(new Object[] {true}, new Object[] {false});
+    return buildParameters(
+        TestParametersBuilder.builder().withAllRuntimesAndApiLevels().build(),
+        BooleanUtils.values());
   }
 
   public void configure(R8FullTestBuilder builder) {
@@ -50,21 +61,26 @@
   }
 
   @Test
-  public void test() throws Throwable {
-    testForJvm()
-        .addTestClasspath()
-        .run(getTestClass())
+  public void testReference() throws Exception {
+    assumeFalse(minification);
+    testForRuntime(parameters)
+        .addProgramClasses(getTestClass())
+        .addProgramClasses(getAdditionalClasses())
+        .run(parameters.getRuntime(), getTestClass())
         .assertSuccessWithOutput(getExpectedResult());
+  }
 
-    testForR8(Backend.DEX)
+  @Test
+  public void testR8() throws Throwable {
+    testForR8(parameters.getBackend())
+        .setMinApi(parameters.getApiLevel())
         .addProgramClasses(getTestClass())
         .addProgramClasses(getAdditionalClasses())
         .addKeepMainRule(getTestClass())
         .minification(minification)
         .addOptionsModification(options -> options.enableSideEffectAnalysis = false)
         .apply(this::configure)
-        .compile()
-        .run(getTestClass())
+        .run(parameters.getRuntime(), getTestClass())
         .inspect(this::inspect)
         .assertSuccessWithOutput(getExpectedResult());
   }
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java
index 8cc28de..67c908e 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java
@@ -106,16 +106,9 @@
               MemberNaming.MethodSignature setterAccessor =
                   testedClass.getSetterAccessorForProperty(
                       propertyName, AccessorKind.FROM_COMPANION);
-
-              if (allowAccessModification) {
-                assertTrue(fieldSubject.getField().accessFlags.isPublic());
-                checkMethodIsRemoved(outerClass, getterAccessor);
-                checkMethodIsRemoved(outerClass, setterAccessor);
-              } else {
                 assertTrue(fieldSubject.getField().accessFlags.isPrivate());
                 checkMethodIsKept(outerClass, getterAccessor);
                 checkMethodIsRemoved(outerClass, setterAccessor);
-              }
             });
   }
 
@@ -145,17 +138,10 @@
               MemberNaming.MethodSignature setterAccessor =
                   testedClass.getSetterAccessorForProperty(
                       propertyName, AccessorKind.FROM_COMPANION);
-              if (allowAccessModification) {
-                assertTrue(fieldSubject.getField().accessFlags.isPublic());
-
-                checkMethodIsRemoved(outerClass, getterAccessor);
-                checkMethodIsRemoved(outerClass, setterAccessor);
-              } else {
                 assertTrue(fieldSubject.getField().accessFlags.isPrivate());
 
                 checkMethodIsKept(outerClass, getterAccessor);
                 checkMethodIsRemoved(outerClass, setterAccessor);
-              }
             });
   }
 
@@ -186,15 +172,9 @@
                   testedClass.getSetterAccessorForProperty(
                       propertyName, AccessorKind.FROM_COMPANION);
 
-              if (allowAccessModification) {
-                assertTrue(fieldSubject.getField().accessFlags.isPublic());
-                checkMethodIsRemoved(outerClass, getterAccessor);
-                checkMethodIsRemoved(outerClass, setterAccessor);
-              } else {
-                assertTrue(fieldSubject.getField().accessFlags.isPrivate());
-                checkMethodIsKept(outerClass, getterAccessor);
-                checkMethodIsRemoved(outerClass, setterAccessor);
-              }
+              assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+              checkMethodIsKept(outerClass, getterAccessor);
+              checkMethodIsRemoved(outerClass, setterAccessor);
             });
   }
 
@@ -225,15 +205,9 @@
                   testedClass.getSetterAccessorForProperty(
                       propertyName, AccessorKind.FROM_COMPANION);
 
-              if (allowAccessModification) {
-                assertTrue(fieldSubject.getField().accessFlags.isPublic());
-                checkMethodIsRemoved(outerClass, getterAccessor);
-                checkMethodIsRemoved(outerClass, setterAccessor);
-              } else {
                 assertTrue(fieldSubject.getField().accessFlags.isPrivate());
                 checkMethodIsKept(outerClass, getterAccessor);
                 checkMethodIsRemoved(outerClass, setterAccessor);
-              }
             });
   }
 
@@ -263,15 +237,9 @@
               MemberNaming.MethodSignature setterAccessor =
                   testedClass.getSetterAccessorForProperty(
                       propertyName, AccessorKind.FROM_COMPANION);
-              if (allowAccessModification) {
-                assertTrue(fieldSubject.getField().accessFlags.isPublic());
-                checkMethodIsRemoved(outerClass, getterAccessor);
-                checkMethodIsRemoved(outerClass, setterAccessor);
-              } else {
-                assertTrue(fieldSubject.getField().accessFlags.isPrivate());
-                checkMethodIsKept(outerClass, getterAccessor);
-                checkMethodIsRemoved(outerClass, setterAccessor);
-              }
+              assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+              checkMethodIsKept(outerClass, getterAccessor);
+              checkMethodIsRemoved(outerClass, setterAccessor);
             });
   }
 
@@ -281,36 +249,7 @@
     String mainClass = addMainToClasspath("properties.CompanionLateInitPropertiesKt",
         "companionLateInitProperties_useInternalLateInitProp");
     runTest(PROPERTIES_PACKAGE_NAME, mainClass)
-        .inspect(
-            inspector -> {
-              if (true) {
-                checkClassIsRemoved(inspector, testedClass.getOuterClassName());
-                return;
-              }
-
-              ClassSubject outerClass =
-                  checkClassIsKept(inspector, testedClass.getOuterClassName());
-              String propertyName = "internalLateInitProp";
-              FieldSubject fieldSubject =
-                  checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName);
-              assertTrue(fieldSubject.getField().accessFlags.isStatic());
-              assertTrue(fieldSubject.getField().accessFlags.isPublic());
-
-              MemberNaming.MethodSignature getterAccessor =
-                  testedClass.getGetterAccessorForProperty(
-                      propertyName, AccessorKind.FROM_COMPANION);
-              MemberNaming.MethodSignature setterAccessor =
-                  testedClass.getSetterAccessorForProperty(
-                      propertyName, AccessorKind.FROM_COMPANION);
-
-              assertTrue(fieldSubject.getField().accessFlags.isPublic());
-
-              // kotlinc 1.5 do not generate accessors for public late-init properties.
-              if (kotlinc.isNot(KOTLINC_1_5_0)) {
-                checkMethodIsRemoved(outerClass, getterAccessor);
-                checkMethodIsRemoved(outerClass, setterAccessor);
-              }
-            });
+        .inspect(inspector -> checkClassIsRemoved(inspector, testedClass.getOuterClassName()));
   }
 
   @Test
@@ -319,36 +258,7 @@
     String mainClass = addMainToClasspath("properties.CompanionLateInitPropertiesKt",
         "companionLateInitProperties_usePublicLateInitProp");
     runTest(PROPERTIES_PACKAGE_NAME, mainClass)
-        .inspect(
-            inspector -> {
-              if (true) {
-                checkClassIsRemoved(inspector, testedClass.getOuterClassName());
-                return;
-              }
-
-              ClassSubject outerClass =
-                  checkClassIsKept(inspector, testedClass.getOuterClassName());
-              String propertyName = "publicLateInitProp";
-              FieldSubject fieldSubject =
-                  checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName);
-              assertTrue(fieldSubject.getField().accessFlags.isStatic());
-              assertTrue(fieldSubject.getField().accessFlags.isPublic());
-
-              MemberNaming.MethodSignature getterAccessor =
-                  testedClass.getGetterAccessorForProperty(
-                      propertyName, AccessorKind.FROM_COMPANION);
-              MemberNaming.MethodSignature setterAccessor =
-                  testedClass.getSetterAccessorForProperty(
-                      propertyName, AccessorKind.FROM_COMPANION);
-
-              assertTrue(fieldSubject.getField().accessFlags.isPublic());
-
-              // kotlinc 1.5 do not generate accessors for public late-init properties.
-              if (kotlinc.isNot(KOTLINC_1_5_0)) {
-                checkMethodIsRemoved(outerClass, getterAccessor);
-                checkMethodIsRemoved(outerClass, setterAccessor);
-              }
-            });
+        .inspect(inspector -> checkClassIsRemoved(inspector, testedClass.getOuterClassName()));
   }
 
   @Test
@@ -422,15 +332,9 @@
                   testedClass.getGetterAccessorForProperty(propertyName, AccessorKind.FROM_INNER);
               MemberNaming.MethodSignature setterAccessor =
                   testedClass.getSetterAccessorForProperty(propertyName, AccessorKind.FROM_INNER);
-              if (allowAccessModification) {
-                assertTrue(fieldSubject.getField().accessFlags.isPublic());
-                checkMethodIsRemoved(classSubject, getterAccessor);
-                checkMethodIsRemoved(classSubject, setterAccessor);
-              } else {
                 assertTrue(fieldSubject.getField().accessFlags.isPrivate());
                 checkMethodIsKept(classSubject, getterAccessor);
                 checkMethodIsRemoved(classSubject, setterAccessor);
-              }
             });
   }
 
@@ -449,10 +353,7 @@
     String mainClass = addMainToClasspath(testedClass.className + "Kt",
         "noUseOfPropertyAccessorFromLambda");
     runTest("accessors", mainClass)
-        .inspect(
-            inspector -> {
-              checkClassIsRemoved(inspector, testedClass.getClassName());
-            });
+        .inspect(inspector -> checkClassIsRemoved(inspector, testedClass.getClassName()));
   }
 
   @Test
@@ -482,15 +383,9 @@
                   testedClass.getGetterAccessorForProperty(propertyName, accessorKind);
               MemberNaming.MethodSignature setterAccessor =
                   testedClass.getSetterAccessorForProperty(propertyName, accessorKind);
-              if (allowAccessModification) {
-                assertTrue(fieldSubject.getField().accessFlags.isPublic());
-                checkMethodIsRemoved(classSubject, getterAccessor);
-                checkMethodIsRemoved(classSubject, setterAccessor);
-              } else {
                 assertTrue(fieldSubject.getField().accessFlags.isPrivate());
                 checkMethodIsKept(classSubject, getterAccessor);
                 checkMethodIsKept(classSubject, setterAccessor);
-              }
             });
   }
 
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java
index 1da9c86..8544744 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java
@@ -40,7 +40,8 @@
   private static final MethodSignature COPY_DEFAULT_METHOD =
       TEST_DATA_CLASS.getCopyDefaultSignature();
 
-  private Consumer<InternalOptions> disableClassInliner = o -> o.enableClassInlining = false;
+  private static final Consumer<InternalOptions> disableClassInliner =
+      o -> o.enableClassInlining = false;
 
   @Parameterized.Parameters(name = "{0}, {1}, allowAccessModification: {2}")
   public static Collection<Object[]> data() {
@@ -79,9 +80,8 @@
 
                 // Getters should be removed after inlining, which is possible only if access is
                 // relaxed.
-                boolean areGetterPresent = !allowAccessModification;
-                checkMethodIsKeptOrRemoved(dataClass, NAME_GETTER_METHOD, areGetterPresent);
-                checkMethodIsKeptOrRemoved(dataClass, AGE_GETTER_METHOD, areGetterPresent);
+                checkMethodIsKept(dataClass, NAME_GETTER_METHOD);
+                checkMethodIsKept(dataClass, AGE_GETTER_METHOD);
 
                 // No use of componentN functions.
                 checkMethodIsRemoved(dataClass, COMPONENT1_METHOD);
@@ -91,15 +91,6 @@
                 checkMethodIsRemoved(dataClass, COPY_METHOD);
                 checkMethodIsRemoved(dataClass, COPY_DEFAULT_METHOD);
               }
-
-              ClassSubject classSubject = checkClassIsKept(inspector, mainClassName);
-              MethodSubject testMethod = checkMethodIsKept(classSubject, testMethodSignature);
-              if (allowAccessModification) {
-                // Both getters should be inlined
-                checkMethodIsNeverInvoked(testMethod, NAME_GETTER_METHOD, AGE_GETTER_METHOD);
-              } else {
-                checkMethodIsInvokedAtLeastOnce(testMethod, NAME_GETTER_METHOD, AGE_GETTER_METHOD);
-              }
             });
   }
 
@@ -125,11 +116,8 @@
 
                 // ComponentN functions should be removed after inlining, which is possible only if
                 // access is relaxed.
-                boolean areComponentMethodsPresent = !allowAccessModification;
-                checkMethodIsKeptOrRemoved(
-                    dataClass, COMPONENT1_METHOD, areComponentMethodsPresent);
-                checkMethodIsKeptOrRemoved(
-                    dataClass, COMPONENT2_METHOD, areComponentMethodsPresent);
+                checkMethodIsKept(dataClass, COMPONENT1_METHOD);
+                checkMethodIsKept(dataClass, COMPONENT2_METHOD);
 
                 // No use of getter.
                 checkMethodIsRemoved(dataClass, NAME_GETTER_METHOD);
@@ -139,14 +127,6 @@
                 checkMethodIsRemoved(dataClass, COPY_METHOD);
                 checkMethodIsRemoved(dataClass, COPY_DEFAULT_METHOD);
               }
-
-              ClassSubject classSubject = checkClassIsKept(inspector, mainClassName);
-              MethodSubject testMethod = checkMethodIsKept(classSubject, testMethodSignature);
-              if (allowAccessModification) {
-                checkMethodIsNeverInvoked(testMethod, COMPONENT1_METHOD, COMPONENT2_METHOD);
-              } else {
-                checkMethodIsInvokedAtLeastOnce(testMethod, COMPONENT1_METHOD, COMPONENT2_METHOD);
-              }
             });
   }
 
@@ -169,9 +149,7 @@
               } else {
                 ClassSubject dataClass =
                     checkClassIsKept(inspector, TEST_DATA_CLASS.getClassName());
-
-                boolean component2IsPresent = !allowAccessModification;
-                checkMethodIsKeptOrRemoved(dataClass, COMPONENT2_METHOD, component2IsPresent);
+                checkMethodIsKept(dataClass, COMPONENT2_METHOD);
 
                 // Function component1 is not used.
                 checkMethodIsRemoved(dataClass, COMPONENT1_METHOD);
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/CollisionWithLibraryMethodAfterConstantParameterRemovalTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/CollisionWithLibraryMethodAfterConstantParameterRemovalTest.java
index d12d4ea..a0c58ac 100644
--- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/CollisionWithLibraryMethodAfterConstantParameterRemovalTest.java
+++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/CollisionWithLibraryMethodAfterConstantParameterRemovalTest.java
@@ -39,11 +39,6 @@
     testForR8(parameters.getBackend())
         .addInnerClasses(getClass())
         .addKeepMainRule(Main.class)
-        .addOptionsModification(
-            options ->
-                options
-                    .callSiteOptimizationOptions()
-                    .setEnableExperimentalArgumentPropagation(true))
         .enableInliningAnnotations()
         .enableNeverClassInliningAnnotations()
         .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ConstantUnboxedEnumArgumentTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ConstantUnboxedEnumArgumentTest.java
index 7b7589b..7c4f463 100644
--- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ConstantUnboxedEnumArgumentTest.java
+++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ConstantUnboxedEnumArgumentTest.java
@@ -38,11 +38,6 @@
     testForR8(parameters.getBackend())
         .addInnerClasses(getClass())
         .addKeepMainRule(Main.class)
-        .addOptionsModification(
-            options ->
-                options
-                    .callSiteOptimizationOptions()
-                    .setEnableExperimentalArgumentPropagation(true))
         .addEnumUnboxingInspector(inspector -> inspector.assertUnboxed(MyEnum.class))
         .enableInliningAnnotations()
         // TODO(b/173398086): uniqueMethodWithName() does not work with argument removal.
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ImpreciseReceiverWithUnknownArgumentInformationWidenedToUnknownTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ImpreciseReceiverWithUnknownArgumentInformationWidenedToUnknownTest.java
index 36c74a1..5fe18a3 100644
--- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ImpreciseReceiverWithUnknownArgumentInformationWidenedToUnknownTest.java
+++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ImpreciseReceiverWithUnknownArgumentInformationWidenedToUnknownTest.java
@@ -44,11 +44,6 @@
                     .assertHasBottomMethodState(
                         Reference.methodFromMethod(B.class.getDeclaredMethod("test")))
                     .apply(ignore -> inspected.set()))
-        .addOptionsModification(
-            options ->
-                options
-                    .callSiteOptimizationOptions()
-                    .setEnableExperimentalArgumentPropagation(true))
         .addVerticallyMergedClassesInspector(
             VerticallyMergedClassesInspector::assertNoClassesMerged)
         .enableNoVerticalClassMergingAnnotations()
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/MixedArgumentRemovalAndEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/MixedArgumentRemovalAndEnumUnboxingTest.java
index 58f2423..71d2f1c 100644
--- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/MixedArgumentRemovalAndEnumUnboxingTest.java
+++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/MixedArgumentRemovalAndEnumUnboxingTest.java
@@ -38,11 +38,6 @@
     testForR8(parameters.getBackend())
         .addInnerClasses(getClass())
         .addKeepMainRule(Main.class)
-        .addOptionsModification(
-            options ->
-                options
-                    .callSiteOptimizationOptions()
-                    .setEnableExperimentalArgumentPropagation(true))
         .addEnumUnboxingInspector(inspector -> inspector.assertUnboxed(MyEnum.class))
         .enableInliningAnnotations()
         // TODO(b/173398086): uniqueMethodWithName() does not work with argument removal.
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/MonomorphicVirtualMethodTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/MonomorphicVirtualMethodTest.java
index 74ba4e2..434aeac 100644
--- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/MonomorphicVirtualMethodTest.java
+++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/MonomorphicVirtualMethodTest.java
@@ -42,11 +42,6 @@
                     .assertHasMonomorphicMethodState(
                         Reference.methodFromMethod(A.class.getDeclaredMethod("m", int.class)))
                     .apply(ignore -> inspected.set()))
-        .addOptionsModification(
-            options ->
-                options
-                    .callSiteOptimizationOptions()
-                    .setEnableExperimentalArgumentPropagation(true))
         .enableInliningAnnotations()
         .enableNeverClassInliningAnnotations()
         .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/MonomorphicVirtualMethodWithInterfaceMethodSiblingTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/MonomorphicVirtualMethodWithInterfaceMethodSiblingTest.java
index 8731617..e5b9f02 100644
--- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/MonomorphicVirtualMethodWithInterfaceMethodSiblingTest.java
+++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/MonomorphicVirtualMethodWithInterfaceMethodSiblingTest.java
@@ -52,11 +52,6 @@
                     .apply(ignore -> inspected.set()))
         .addHorizontallyMergedClassesInspector(
             HorizontallyMergedClassesInspector::assertNoClassesMerged)
-        .addOptionsModification(
-            options ->
-                options
-                    .callSiteOptimizationOptions()
-                    .setEnableExperimentalArgumentPropagation(true))
         .addVerticallyMergedClassesInspector(
             VerticallyMergedClassesInspector::assertNoClassesMerged)
         .enableInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ParameterWithUnknownArgumentInformationWidenedToUnknownTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ParameterWithUnknownArgumentInformationWidenedToUnknownTest.java
index ade398c..f7e759f 100644
--- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ParameterWithUnknownArgumentInformationWidenedToUnknownTest.java
+++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/ParameterWithUnknownArgumentInformationWidenedToUnknownTest.java
@@ -41,11 +41,6 @@
                     .assertHasUnknownMethodState(
                         Reference.methodFromMethod(Main.class.getDeclaredMethod("test", A.class)))
                     .apply(ignore -> inspected.set()))
-        .addOptionsModification(
-            options ->
-                options
-                    .callSiteOptimizationOptions()
-                    .setEnableExperimentalArgumentPropagation(true))
         .enableInliningAnnotations()
         .setMinApi(parameters.getApiLevel())
         .compile()
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentTest.java
index e1c2d9b..9b1429f 100644
--- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentTest.java
+++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentTest.java
@@ -39,11 +39,6 @@
     testForR8(parameters.getBackend())
         .addInnerClasses(getClass())
         .addKeepMainRule(Main.class)
-        .addOptionsModification(
-            options ->
-                options
-                    .callSiteOptimizationOptions()
-                    .setEnableExperimentalArgumentPropagation(true))
         .enableInliningAnnotations()
         // TODO(b/173398086): uniqueMethodWithName() does not work with argument removal.
         .noMinification()
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentThroughCallChainTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentThroughCallChainTest.java
index ae1d888..e33fe2a 100644
--- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentThroughCallChainTest.java
+++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/StaticMethodWithConstantArgumentThroughCallChainTest.java
@@ -39,11 +39,6 @@
     testForR8(parameters.getBackend())
         .addInnerClasses(getClass())
         .addKeepMainRule(Main.class)
-        .addOptionsModification(
-            options ->
-                options
-                    .callSiteOptimizationOptions()
-                    .setEnableExperimentalArgumentPropagation(true))
         .enableInliningAnnotations()
         // TODO(b/173398086): uniqueMethodWithName() does not work with argument removal.
         .noMinification()
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/UnboxedEnumUserInMethodWithConstantArgumentTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/UnboxedEnumUserInMethodWithConstantArgumentTest.java
index e5f64cf..9a991c2 100644
--- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/UnboxedEnumUserInMethodWithConstantArgumentTest.java
+++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/UnboxedEnumUserInMethodWithConstantArgumentTest.java
@@ -38,11 +38,6 @@
     testForR8(parameters.getBackend())
         .addInnerClasses(getClass())
         .addKeepMainRule(Main.class)
-        .addOptionsModification(
-            options ->
-                options
-                    .callSiteOptimizationOptions()
-                    .setEnableExperimentalArgumentPropagation(true))
         .addEnumUnboxingInspector(inspector -> inspector.assertUnboxed(MyEnum.class))
         .enableInliningAnnotations()
         // TODO(b/173398086): uniqueMethodWithName() does not work with argument removal.
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/UpwardsArgumentPropagationToResolvedMethodTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/UpwardsArgumentPropagationToResolvedMethodTest.java
index 8464112..dd1d2d2 100644
--- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/UpwardsArgumentPropagationToResolvedMethodTest.java
+++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/UpwardsArgumentPropagationToResolvedMethodTest.java
@@ -42,11 +42,6 @@
         .addKeepMainRule(Main.class)
         .addHorizontallyMergedClassesInspector(
             HorizontallyMergedClassesInspector::assertNoClassesMerged)
-        .addOptionsModification(
-            options ->
-                options
-                    .callSiteOptimizationOptions()
-                    .setEnableExperimentalArgumentPropagation(true))
         .enableInliningAnnotations()
         .enableNeverClassInliningAnnotations()
         .enableNoHorizontalClassMergingAnnotations()
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/UpwardsInterfacePropagationToUnrelatedMethodTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/UpwardsInterfacePropagationToUnrelatedMethodTest.java
index 03d63d9..25ce6a4 100644
--- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/UpwardsInterfacePropagationToUnrelatedMethodTest.java
+++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/UpwardsInterfacePropagationToUnrelatedMethodTest.java
@@ -37,11 +37,6 @@
     testForR8(parameters.getBackend())
         .addInnerClasses(getClass())
         .addKeepMainRule(Main.class)
-        .addOptionsModification(
-            options ->
-                options
-                    .callSiteOptimizationOptions()
-                    .setEnableExperimentalArgumentPropagation(true))
         .addHorizontallyMergedClassesInspector(
             HorizontallyMergedClassesInspector::assertNoClassesMerged)
         .addVerticallyMergedClassesInspector(
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/VirtualMethodWithConstantArgumentThroughSiblingInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/VirtualMethodWithConstantArgumentThroughSiblingInterfaceMethodTest.java
index 7be4823..e226a85 100644
--- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/VirtualMethodWithConstantArgumentThroughSiblingInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/VirtualMethodWithConstantArgumentThroughSiblingInterfaceMethodTest.java
@@ -37,11 +37,6 @@
     testForR8(parameters.getBackend())
         .addInnerClasses(getClass())
         .addKeepMainRule(Main.class)
-        .addOptionsModification(
-            options ->
-                options
-                    .callSiteOptimizationOptions()
-                    .setEnableExperimentalArgumentPropagation(true))
         .enableNoVerticalClassMergingAnnotations()
         .setMinApi(parameters.getApiLevel())
         .compile()
diff --git a/src/test/java/com/android/tools/r8/proguard/configuration/ProguardRuleWithEllipsisForReturnTypeTest.java b/src/test/java/com/android/tools/r8/proguard/configuration/ProguardRuleWithEllipsisForReturnTypeTest.java
index 33b7f00..17b13cf 100644
--- a/src/test/java/com/android/tools/r8/proguard/configuration/ProguardRuleWithEllipsisForReturnTypeTest.java
+++ b/src/test/java/com/android/tools/r8/proguard/configuration/ProguardRuleWithEllipsisForReturnTypeTest.java
@@ -6,34 +6,50 @@
 
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
+@RunWith(Parameterized.class)
 public class ProguardRuleWithEllipsisForReturnTypeTest extends TestBase {
 
   private static final Class<?> clazz = ProguardRuleWithEllipsisForReturnTypeTestClass.class;
   private static final String expectedOutput = StringUtils.lines("Hello world!");
+  
+  @Parameter public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
 
   @Test
   public void testR8() throws Exception {
-    testForR8(Backend.DEX)
+    testForR8(parameters.getBackend())
         .addProgramClasses(clazz)
         .addKeepRules(
             "-keep class " + clazz.getTypeName() + " {",
             "  private static ... unused;",
             "  public static ... main(...);",
             "}")
-        .run(clazz)
+        .run(parameters.getRuntime(), clazz)
         .assertSuccessWithOutput(expectedOutput)
         .inspect(this::inspect);
   }
 
   @Test
   public void testProguard() throws Exception {
+    assumeTrue(parameters.isCfRuntime());
     testForProguard()
         .addProgramClasses(clazz)
         .addKeepRules(
@@ -41,7 +57,7 @@
             "  private static ... unused;",
             "  public static ... main(...);",
             "}")
-        .run(clazz)
+        .run(parameters.getRuntime(), clazz)
         .assertSuccessWithOutput(expectedOutput)
         .inspect(this::inspect);
   }
diff --git a/src/test/java/com/android/tools/r8/proguard/configuration/UnusedKeepRuleTest.java b/src/test/java/com/android/tools/r8/proguard/configuration/UnusedKeepRuleTest.java
index a391a21..e258520 100644
--- a/src/test/java/com/android/tools/r8/proguard/configuration/UnusedKeepRuleTest.java
+++ b/src/test/java/com/android/tools/r8/proguard/configuration/UnusedKeepRuleTest.java
@@ -5,15 +5,32 @@
 package com.android.tools.r8.proguard.configuration;
 
 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 org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
 
+@RunWith(Parameterized.class)
 public class UnusedKeepRuleTest extends TestBase {
 
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withNoneRuntime().build();
+  }
+
+  public UnusedKeepRuleTest(TestParameters parameters) {
+    parameters.assertNoneRuntime();
+  }
+
   @Test
   public void test() throws Exception {
     testForR8(Backend.DEX)
         .addKeepRules("-keep class NotPresent")
         .allowUnusedProguardConfigurationRules()
+        .setMinApi(AndroidApiLevel.B)
         .compile()
         .assertInfosCount(1);
   }
diff --git a/src/test/java/com/android/tools/r8/proguard/printmapping/PrintMappingTest.java b/src/test/java/com/android/tools/r8/proguard/printmapping/PrintMappingTest.java
index 378cf0e..689904c 100644
--- a/src/test/java/com/android/tools/r8/proguard/printmapping/PrintMappingTest.java
+++ b/src/test/java/com/android/tools/r8/proguard/printmapping/PrintMappingTest.java
@@ -7,11 +7,27 @@
 import static org.junit.Assert.assertTrue;
 
 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 java.nio.file.Path;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
 
+@RunWith(Parameterized.class)
 public class PrintMappingTest extends TestBase {
 
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withNoneRuntime().build();
+  }
+
+  public PrintMappingTest(TestParameters parameters) {
+    parameters.assertNoneRuntime();
+  }
+
   @Test
   public void testWithExistingDirectory() throws Exception {
     Path mapping = temp.getRoot().toPath().resolve("existing/directory/mapping.txt");
@@ -29,6 +45,7 @@
         .addInnerClasses(PrintMappingTest.class)
         .addKeepRules("-keep,allowobfuscation class " + TestClass.class.getTypeName())
         .addKeepRules("-printmapping " + mapping)
+        .setMinApi(AndroidApiLevel.B)
         .compile();
     assertTrue(mapping.toFile().exists());
   }
diff --git a/src/test/java/com/android/tools/r8/resolution/PublicFieldInnerClassTest.java b/src/test/java/com/android/tools/r8/resolution/PublicFieldInnerClassTest.java
index 5e93601..4fb3d8b 100644
--- a/src/test/java/com/android/tools/r8/resolution/PublicFieldInnerClassTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/PublicFieldInnerClassTest.java
@@ -5,7 +5,9 @@
 
 import com.android.tools.r8.CompilationMode;
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersBuilder;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.StringUtils;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -69,24 +71,25 @@
   private static final Class CLASS = PublicFieldInnerClassTestMain.class;
   private static final String EXPECTED_OUTPUT = StringUtils.lines("0", "0", "0", "0");
 
-  private final Backend backend;
+  private final TestParameters parameters;
 
   @Parameterized.Parameters(name = "Backend: {0}")
-  public static Object[] data() {
-    return ToolHelper.getBackends();
+  public static TestParametersCollection data() {
+    return TestParametersBuilder.builder().withAllRuntimesAndApiLevels().build();
   }
 
-  public PublicFieldInnerClassTest(Backend backend) {
-    this.backend = backend;
+  public PublicFieldInnerClassTest(TestParameters parameters) {
+    this.parameters = parameters;
   }
 
   @Test
   public void test() throws Exception {
-    testForR8(backend)
+    testForR8(parameters.getBackend())
         .setMode(CompilationMode.DEBUG)
         .addProgramClassesAndInnerClasses(CLASS)
         .addKeepMainRule(CLASS)
-        .run(CLASS)
+        .setMinApi(parameters.getApiLevel())
+        .run(parameters.getRuntime(), CLASS)
         .assertSuccessWithOutput(EXPECTED_OUTPUT);
   }
 }
diff --git a/src/test/java/com/android/tools/r8/resolution/b123730538/B123730538.java b/src/test/java/com/android/tools/r8/resolution/b123730538/B123730538.java
index 4cb3b17..c61d7fa 100644
--- a/src/test/java/com/android/tools/r8/resolution/b123730538/B123730538.java
+++ b/src/test/java/com/android/tools/r8/resolution/b123730538/B123730538.java
@@ -7,8 +7,12 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersBuilder;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.resolution.b123730538.runner.PublicClassExtender;
 import com.android.tools.r8.resolution.b123730538.runner.Runner;
@@ -32,15 +36,15 @@
   private static List<Path> CLASSES;
   private static final String EXPECTED_OUTPUT = StringUtils.lines("pkg.AbstractClass::foo");
 
-  private final Backend backend;
+  private final TestParameters parameters;
 
   @Parameterized.Parameters(name = "Backend: {0}")
-  public static Object[] data() {
-    return ToolHelper.getBackends();
+  public static TestParametersCollection data() {
+    return TestParametersBuilder.builder().withAllRuntimesAndApiLevels().build();
   }
 
-  public B123730538(Backend backend) {
-    this.backend = backend;
+  public B123730538(TestParameters parameters) {
+    this.parameters = parameters;
   }
 
   @BeforeClass
@@ -53,24 +57,26 @@
 
   @Test
   public void testProguard() throws Exception {
+    assumeTrue(parameters.isCfRuntime());
     Path inJar = temp.newFile("input.jar").toPath().toAbsolutePath();
     writeClassFilesToJar(inJar, CLASSES);
     testForProguard()
         .addProgramFiles(inJar)
         .addKeepMainRule(MAIN)
         .addKeepRules("-dontoptimize")
-        .run(MAIN)
+        .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutput(EXPECTED_OUTPUT)
         .inspect(this::inspect);
   }
 
   @Test
   public void testR8() throws Exception {
-    testForR8(backend)
+    testForR8(parameters.getBackend())
         .addProgramFiles(CLASSES)
         .addKeepMainRule(MAIN)
         .addKeepRules("-dontoptimize")
-        .run(MAIN)
+        .setMinApi(parameters.getApiLevel())
+        .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutput(EXPECTED_OUTPUT)
         .inspect(this::inspect);
   }
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiAmbiguousOriginalRangeTest.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiAmbiguousOriginalRangeTest.java
index 3f616f0..6c95559 100644
--- a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiAmbiguousOriginalRangeTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiAmbiguousOriginalRangeTest.java
@@ -15,6 +15,7 @@
 import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.retrace.ProguardMapProducer;
 import com.android.tools.r8.retrace.RetraceFrameResult;
+import com.android.tools.r8.retrace.RetraceStackTraceContext;
 import com.android.tools.r8.retrace.Retracer;
 import java.util.Arrays;
 import java.util.Collections;
@@ -57,7 +58,8 @@
 
       // Check that retracing with position one is ambiguous between line 42, 43 and 44.
       RetraceFrameResult retraceFrameResult =
-          retracer.retraceFrame(methodReference, OptionalInt.of(1));
+          retracer.retraceFrame(
+              RetraceStackTraceContext.empty(), OptionalInt.of(1), methodReference);
       assertTrue(retraceFrameResult.isAmbiguous());
       List<Integer> originalPositions =
           retraceFrameResult.stream()
@@ -66,7 +68,9 @@
       assertEquals(Arrays.asList(42, 43, 44), originalPositions);
 
       // Check that retracing with position 3 is ambiguous between 45 and 46.
-      retraceFrameResult = retracer.retraceFrame(methodReference, OptionalInt.of(3));
+      retraceFrameResult =
+          retracer.retraceFrame(
+              RetraceStackTraceContext.empty(), OptionalInt.of(3), methodReference);
       assertTrue(retraceFrameResult.isAmbiguous());
       originalPositions =
           retraceFrameResult.stream()
@@ -75,7 +79,9 @@
       assertEquals(Arrays.asList(45, 46), originalPositions);
 
       // Check that retracing with position 5 is not ambiguous.
-      retraceFrameResult = retracer.retraceFrame(methodReference, OptionalInt.of(5));
+      retraceFrameResult =
+          retracer.retraceFrame(
+              RetraceStackTraceContext.empty(), OptionalInt.of(5), methodReference);
       assertFalse(retraceFrameResult.isAmbiguous());
       originalPositions =
           retraceFrameResult.stream()
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiInlineInOutlineTest.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiInlineInOutlineTest.java
index 7cce489..d67f6ee 100644
--- a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiInlineInOutlineTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiInlineInOutlineTest.java
@@ -42,7 +42,7 @@
     private final ClassReference callsiteRenamed = Reference.classFromTypeName("b");
 
     private final String mapping =
-        "# { id: 'com.android.tools.r8.mapping', version: 'experimental' }\n"
+        "# { id: 'com.android.tools.r8.mapping', version: '2.0' }\n"
             + "outline.Class -> "
             + outlineRenamed.getTypeName()
             + ":\n"
@@ -68,7 +68,9 @@
       List<RetraceFrameElement> outlineRetraced =
           retracer
               .retraceFrame(
-                  Reference.methodFromDescriptor(outlineRenamed, "a", "()I"), OptionalInt.of(2))
+                  RetraceStackTraceContext.empty(),
+                  OptionalInt.of(2),
+                  Reference.methodFromDescriptor(outlineRenamed, "a", "()I"))
               .stream()
               .collect(Collectors.toList());
       // The retrace result should not be ambiguous or empty.
@@ -98,9 +100,9 @@
       List<RetraceFrameElement> retraceOutlineCallee =
           retracer
               .retraceFrame(
-                  Reference.methodFromDescriptor(callsiteRenamed, "s", "(I)V"),
+                  context,
                   OptionalInt.of(27),
-                  context)
+                  Reference.methodFromDescriptor(callsiteRenamed, "s", "(I)V"))
               .stream()
               .collect(Collectors.toList());
       assertEquals(1, retraceOutlineCallee.size());
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiOutlineInOutlineStackTrace.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiOutlineInOutlineStackTrace.java
index c2b5c47..94824c5 100644
--- a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiOutlineInOutlineStackTrace.java
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiOutlineInOutlineStackTrace.java
@@ -44,7 +44,7 @@
     private final ClassReference callsiteRenamed = Reference.classFromTypeName("c");
 
     private final String mapping =
-        "# { id: 'com.android.tools.r8.mapping', version: 'experimental' }\n"
+        "# { id: 'com.android.tools.r8.mapping', version: '2.0' }\n"
             + "outline1.Class -> "
             + outline1Renamed.getTypeName()
             + ":\n"
@@ -92,9 +92,9 @@
       List<RetraceFrameElement> retraceOutlineCallee =
           retracer
               .retraceFrame(
-                  Reference.methodFromDescriptor(callsiteRenamed, "s", "(I)V"),
+                  outlineContext,
                   OptionalInt.of(28),
-                  outlineContext)
+                  Reference.methodFromDescriptor(callsiteRenamed, "s", "(I)V"))
               .stream()
               .collect(Collectors.toList());
       assertEquals(1, retraceOutlineCallee.size());
@@ -113,7 +113,7 @@
         int position,
         RetraceStackTraceContext context) {
       List<RetraceFrameElement> outlineRetraced =
-          retracer.retraceFrame(reference, OptionalInt.of(position), context).stream()
+          retracer.retraceFrame(context, OptionalInt.of(position), reference).stream()
               .collect(Collectors.toList());
       // The retrace result should not be ambiguous or empty.
       assertEquals(1, outlineRetraced.size());
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiOutlineInlineTest.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiOutlineInlineTest.java
index 6d7fe97..6aaa0fa 100644
--- a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiOutlineInlineTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiOutlineInlineTest.java
@@ -42,7 +42,7 @@
     private final ClassReference callsiteRenamed = Reference.classFromTypeName("b");
 
     private final String mapping =
-        "# { id: 'com.android.tools.r8.mapping', version: 'experimental' }\n"
+        "# { id: 'com.android.tools.r8.mapping', version: '2.0' }\n"
             + "outline.Class -> "
             + outlineRenamed.getTypeName()
             + ":\n"
@@ -67,7 +67,9 @@
       List<RetraceFrameElement> outlineRetraced =
           retracer
               .retraceFrame(
-                  Reference.methodFromDescriptor(outlineRenamed, "a", "()I"), OptionalInt.of(1))
+                  RetraceStackTraceContext.empty(),
+                  OptionalInt.of(1),
+                  Reference.methodFromDescriptor(outlineRenamed, "a", "()I"))
               .stream()
               .collect(Collectors.toList());
       // The retrace result should not be ambiguous or empty.
@@ -95,9 +97,9 @@
       List<RetraceFrameElement> retraceOutlineCallee =
           retracer
               .retraceFrame(
-                  Reference.methodFromDescriptor(callsiteRenamed, "s", "(I)V"),
+                  context,
                   OptionalInt.of(27),
-                  context)
+                  Reference.methodFromDescriptor(callsiteRenamed, "s", "(I)V"))
               .stream()
               .collect(Collectors.toList());
       assertEquals(1, retraceOutlineCallee.size());
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiOutlineNoInlineTest.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiOutlineNoInlineTest.java
index 6330587..e4ef644 100644
--- a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiOutlineNoInlineTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiOutlineNoInlineTest.java
@@ -43,7 +43,7 @@
     private final ClassReference callsiteRenamed = Reference.classFromTypeName("b");
 
     private final String mapping =
-        "# { id: 'com.android.tools.r8.mapping', version: 'experimental' }\n"
+        "# { id: 'com.android.tools.r8.mapping', version: '2.0' }\n"
             + "outline.Class -> "
             + outlineRenamed.getTypeName()
             + ":\n"
@@ -67,7 +67,9 @@
       List<RetraceFrameElement> outlineRetraced =
           retracer
               .retraceFrame(
-                  Reference.methodFromDescriptor(outlineRenamed, "a", "()I"), OptionalInt.of(1))
+                  RetraceStackTraceContext.empty(),
+                  OptionalInt.of(1),
+                  Reference.methodFromDescriptor(outlineRenamed, "a", "()I"))
               .stream()
               .collect(Collectors.toList());
       // The retrace result should not be ambiguous or empty.
@@ -97,9 +99,9 @@
       List<RetraceFrameElement> retraceOutlineCallee =
           retracer
               .retraceFrame(
-                  Reference.methodFromDescriptor(callsiteRenamed, "s", "(I)V"),
+                  context,
                   OptionalInt.of(27),
-                  context)
+                  Reference.methodFromDescriptor(callsiteRenamed, "s", "(I)V"))
               .stream()
               .collect(Collectors.toList());
       assertEquals(1, retraceOutlineCallee.size());
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiRewriteFrameInlineNpeResidualTest.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiRewriteFrameInlineNpeResidualTest.java
index d54bafa..5175ecb 100644
--- a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiRewriteFrameInlineNpeResidualTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiRewriteFrameInlineNpeResidualTest.java
@@ -51,7 +51,7 @@
     private final ClassReference renamedSomeOtherClass = Reference.classFromTypeName("b");
 
     private final String mapping =
-        "# { id: 'com.android.tools.r8.mapping', version: 'experimental' }\n"
+        "# { id: 'com.android.tools.r8.mapping', version: '2.0' }\n"
             + originalException.getTypeName()
             + " -> "
             + renamedException.getTypeName()
@@ -83,10 +83,7 @@
           Retracer.createExperimental(
               ProguardMapProducer.fromString(mapping), new DiagnosticsHandler() {});
       List<RetraceThrownExceptionElement> npeRetraced =
-          retracer
-              .retraceThrownException(renamedException, RetraceStackTraceContext.empty())
-              .stream()
-              .collect(Collectors.toList());
+          retracer.retraceThrownException(renamedException).stream().collect(Collectors.toList());
       assertEquals(1, npeRetraced.size());
       assertEquals(originalException, npeRetraced.get(0).getRetracedClass().getClassReference());
 
@@ -118,7 +115,6 @@
       // Check that rewriting the frames will remove the top 1 frames if the condition is active.
       Map<Integer, RetracedMethodReference> results = new LinkedHashMap<>();
       retraceFrameElement.forEachRewritten(
-          throwingContext,
           frame -> {
             RetracedMethodReference existingValue =
                 results.put(frame.getIndex(), frame.getMethodReference());
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiRewriteFrameInlineNpeTest.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiRewriteFrameInlineNpeTest.java
index 9759f21..66bdc03 100644
--- a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiRewriteFrameInlineNpeTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiRewriteFrameInlineNpeTest.java
@@ -44,7 +44,7 @@
     private final String npeDescriptor = "Ljava/lang/NullPointerException;";
 
     private final String mapping =
-        "# { id: 'com.android.tools.r8.mapping', version: 'experimental' }\n"
+        "# { id: 'com.android.tools.r8.mapping', version: '2.0' }\n"
             + "some.Class -> a:\n"
             + "  4:4:void other.Class.inlinee():23:23 -> a\n"
             + "  4:4:void caller(other.Class):7 -> a\n"
@@ -63,10 +63,7 @@
               ProguardMapProducer.fromString(mapping), testDiagnosticsHandler);
 
       List<RetraceThrownExceptionElement> npeRetraced =
-          retracer
-              .retraceThrownException(
-                  Reference.classFromDescriptor(npeDescriptor), RetraceStackTraceContext.empty())
-              .stream()
+          retracer.retraceThrownException(Reference.classFromDescriptor(npeDescriptor)).stream()
               .collect(Collectors.toList());
       assertEquals(1, npeRetraced.size());
 
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiSingleFrameTest.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiSingleFrameTest.java
index bec1a7f..0c1d0a9 100644
--- a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiSingleFrameTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiSingleFrameTest.java
@@ -54,7 +54,9 @@
       checkResults(
           retracer
               .retraceFrame(
-                  Reference.methodFromDescriptor(renamedClass, "a", "()I"), OptionalInt.empty())
+                  RetraceStackTraceContext.empty(),
+                  OptionalInt.empty(),
+                  Reference.methodFromDescriptor(renamedClass, "a", "()I"))
               .stream()
               .collect(Collectors.toList()));
       checkResults(
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/InlineInOutlineStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/InlineInOutlineStackTrace.java
index a231a0f..df74712 100644
--- a/src/test/java/com/android/tools/r8/retrace/stacktraces/InlineInOutlineStackTrace.java
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/InlineInOutlineStackTrace.java
@@ -18,7 +18,7 @@
   @Override
   public String mapping() {
     return StringUtils.lines(
-        "# { id: 'com.android.tools.r8.mapping', version: 'experimental' }",
+        "# { id: 'com.android.tools.r8.mapping', version: '2.0' }",
         "outline.Class -> a:",
         "  1:2:int some.inlinee():75:76 -> a",
         "  1:2:int outline():0 -> a",
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/NpeInlineRetraceStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/NpeInlineRetraceStackTrace.java
index 3857154..6e9a0be 100644
--- a/src/test/java/com/android/tools/r8/retrace/stacktraces/NpeInlineRetraceStackTrace.java
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/NpeInlineRetraceStackTrace.java
@@ -19,7 +19,7 @@
   @Override
   public String mapping() {
     return StringUtils.lines(
-        "# { id: 'com.android.tools.r8.mapping', version: 'experimental' }",
+        "# { id: 'com.android.tools.r8.mapping', version: '2.0' }",
         "some.Class -> a:",
         "  4:4:void other.Class():23:23 -> a",
         "  4:4:void caller(other.Class):7 -> a",
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/OutlineInOutlineStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/OutlineInOutlineStackTrace.java
index ae8b52b..95e5185 100644
--- a/src/test/java/com/android/tools/r8/retrace/stacktraces/OutlineInOutlineStackTrace.java
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/OutlineInOutlineStackTrace.java
@@ -19,7 +19,7 @@
   @Override
   public String mapping() {
     return StringUtils.lines(
-        "# { id: 'com.android.tools.r8.mapping', version: 'experimental' }",
+        "# { id: 'com.android.tools.r8.mapping', version: '2.0' }",
         "outline1.Class -> a:",
         "  4:4:int outline():0:0 -> a",
         "# { 'id':'com.android.tools.r8.outline' }",
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/OutlineSimpleStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/OutlineSimpleStackTrace.java
index ad0dddc..b8109cf 100644
--- a/src/test/java/com/android/tools/r8/retrace/stacktraces/OutlineSimpleStackTrace.java
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/OutlineSimpleStackTrace.java
@@ -18,7 +18,7 @@
   @Override
   public String mapping() {
     return StringUtils.lines(
-        "# { id: 'com.android.tools.r8.mapping', version: 'experimental' }",
+        "# { id: 'com.android.tools.r8.mapping', version: '2.0' }",
         "outline.Class -> a:",
         "  1:2:int outline() -> a",
         "# { 'id':'com.android.tools.r8.outline' }",
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/OutlineWithInliningStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/OutlineWithInliningStackTrace.java
index a8198a2..238a7d1 100644
--- a/src/test/java/com/android/tools/r8/retrace/stacktraces/OutlineWithInliningStackTrace.java
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/OutlineWithInliningStackTrace.java
@@ -18,7 +18,7 @@
   @Override
   public String mapping() {
     return StringUtils.lines(
-        "# { id: 'com.android.tools.r8.mapping', version: 'experimental' }",
+        "# { id: 'com.android.tools.r8.mapping', version: '2.0' }",
         "outline.Class -> a:",
         "  1:2:int outline():0 -> a",
         "# { 'id':'com.android.tools.r8.outline' }",
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/SyntheticLambdaMethodStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/SyntheticLambdaMethodStackTrace.java
index 6beaba4..fc7a1e5 100644
--- a/src/test/java/com/android/tools/r8/retrace/stacktraces/SyntheticLambdaMethodStackTrace.java
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/SyntheticLambdaMethodStackTrace.java
@@ -44,7 +44,7 @@
   @Override
   public String mapping() {
     return StringUtils.lines(
-        "# {'id':'com.android.tools.r8.mapping','version':'experimental'}",
+        "# {'id':'com.android.tools.r8.mapping','version':'1.0'}",
         "example.Main -> example.Main:",
         "  1:1:void main(java.lang.String[]):123 -> main",
         "example.Foo -> a.a:",
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/SyntheticLambdaMethodWithInliningStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/SyntheticLambdaMethodWithInliningStackTrace.java
index 201700d..bd92f9f 100644
--- a/src/test/java/com/android/tools/r8/retrace/stacktraces/SyntheticLambdaMethodWithInliningStackTrace.java
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/SyntheticLambdaMethodWithInliningStackTrace.java
@@ -43,7 +43,7 @@
   @Override
   public String mapping() {
     return StringUtils.lines(
-        "# {'id':'com.android.tools.r8.mapping','version':'experimental'}",
+        "# {'id':'com.android.tools.r8.mapping','version':'1.0'}",
         "example.Main -> example.Main:",
         "  1:1:void main(java.lang.String[]):123 -> main",
         "example.Foo -> a.a:",
diff --git a/src/test/java/com/android/tools/r8/rewrite/arrays/ArrayLengthRewriteTest.java b/src/test/java/com/android/tools/r8/rewrite/arrays/ArrayLengthRewriteTest.java
index 5a7be26..c38c66f 100644
--- a/src/test/java/com/android/tools/r8/rewrite/arrays/ArrayLengthRewriteTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/arrays/ArrayLengthRewriteTest.java
@@ -68,7 +68,7 @@
         .addProgramClasses(Main.class)
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines(expectedOutput)
-        .inspect(this::inspect);
+        .inspect(i -> inspect(i, true));
   }
 
   @Test public void r8() throws Exception {
@@ -80,10 +80,10 @@
         .enableInliningAnnotations()
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines(expectedOutput)
-        .inspect(this::inspect);
+        .inspect(i -> inspect(i, false));
   }
 
-  private void inspect(CodeInspector inspector) {
+  private void inspect(CodeInspector inspector, boolean d8) {
     ClassSubject mainClass = inspector.clazz(Main.class);
     assertTrue(mainClass.isPresent());
 
@@ -104,10 +104,10 @@
 
     // TODO(139489070): these should be rewritten and result in 0 array-length bytecodes
     MethodSubject staticConstants = mainClass.uniqueMethodWithName("staticConstants");
-    assertArrayLengthCallCount(staticConstants, 3);
+    assertArrayLengthCallCount(staticConstants, (d8 || debugMode) ? 3 : 0);
 
     MethodSubject staticNonConstants = mainClass.uniqueMethodWithName("staticNonConstants");
-    assertArrayLengthCallCount(staticNonConstants, 2);
+    assertArrayLengthCallCount(staticNonConstants, (d8 || debugMode) ? 2 : 0);
   }
 
   private static void assertArrayLengthCallCount(MethodSubject subject, int expected) {
@@ -200,7 +200,7 @@
     }
 
     private static String[] mutable = { "one" };
-    private static final String[] runtimeInit = { System.lineSeparator() };
+    private static final String[] runtimeInit = {"two"};
 
     @NeverInline
     private static void staticNonConstants() {
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/RemoveAssertionsTest.java b/src/test/java/com/android/tools/r8/rewrite/assertions/RemoveAssertionsTest.java
index 7452a5a..adeb90f 100644
--- a/src/test/java/com/android/tools/r8/rewrite/assertions/RemoveAssertionsTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/RemoveAssertionsTest.java
@@ -166,6 +166,7 @@
 @RunWith(Parameterized.class)
 public class RemoveAssertionsTest extends TestBase {
 
+  private static final AndroidApiLevel minApi = AndroidApiLevel.B;
   private final TestParameters parameters;
 
   @Parameterized.Parameters(name = "{0}")
@@ -190,6 +191,7 @@
         .addOptionsModification(o -> o.inlinerOptions().enableInlining = false)
         .allowAccessModification()
         .noMinification()
+        .setMinApi(minApi)
         .compile();
   }
 
@@ -225,6 +227,7 @@
         .debug()
         .noTreeShaking()
         .noMinification()
+        .setMinApi(minApi)
         .compile();
   }
 
@@ -337,7 +340,7 @@
     return testForD8()
         .addProgramClasses(ClassWithAssertions.class)
         .debug()
-        .setMinApi(AndroidApiLevel.B)
+        .setMinApi(minApi)
         .addAssertionsConfiguration(
             builder -> builder.setTransformation(transformation).setScopeAll().build())
         .compile();
@@ -349,7 +352,7 @@
         testForR8(Backend.CF)
             .addProgramClasses(ClassWithAssertions.class)
             .debug()
-            .setMinApi(AndroidApiLevel.B)
+            .setMinApi(minApi)
             .noTreeShaking()
             .noMinification()
             .compile()
@@ -358,7 +361,7 @@
     return testForD8()
         .addProgramFiles(program)
         .debug()
-        .setMinApi(AndroidApiLevel.B)
+        .setMinApi(minApi)
         .addAssertionsConfiguration(
             builder -> builder.setTransformation(transformation).setScopeAll().build())
         .compile();
@@ -379,7 +382,7 @@
             rewriter.apply(ToolHelper.getClassAsBytes(ClassWithAssertions.class)),
             rewriter.apply(ToolHelper.getClassAsBytes(ChromuimAssertionHookMock.class)))
         .debug()
-        .setMinApi(AndroidApiLevel.B)
+        .setMinApi(minApi)
         .compile();
   }
 
diff --git a/src/test/java/com/android/tools/r8/rewrite/switchmaps/RewriteSwitchMapsTest.java b/src/test/java/com/android/tools/r8/rewrite/switchmaps/RewriteSwitchMapsTest.java
index dddb176..cfffbac 100644
--- a/src/test/java/com/android/tools/r8/rewrite/switchmaps/RewriteSwitchMapsTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/switchmaps/RewriteSwitchMapsTest.java
@@ -10,6 +10,7 @@
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersBuilder;
 import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.google.common.collect.ImmutableList;
 import java.nio.file.Paths;
 import java.util.List;
@@ -45,6 +46,7 @@
     testForR8(backend)
         .addProgramFiles(Paths.get(ToolHelper.EXAMPLES_BUILD_DIR).resolve(JAR_FILE))
         .addKeepRules(PG_CONFIG)
+        .setMinApi(AndroidApiLevel.B)
         .compile()
         .inspect(
             inspector -> {
diff --git a/src/test/java/com/android/tools/r8/shaking/ReturnTypeTest.java b/src/test/java/com/android/tools/r8/shaking/ReturnTypeTest.java
index 354c5ae..3cd79f3 100644
--- a/src/test/java/com/android/tools/r8/shaking/ReturnTypeTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ReturnTypeTest.java
@@ -8,6 +8,7 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assume.assumeTrue;
 
+import com.android.tools.r8.KeepConstantArguments;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -26,6 +27,7 @@
 }
 
 class B112517039Caller {
+  @KeepConstantArguments
   public void call(B112517039I i) {
     System.out.println("Ewwo!");
     i.flaf(i.m());
@@ -77,17 +79,9 @@
         .addProgramClasses(
             B112517039ReturnType.class, B112517039I.class, B112517039Caller.class, MAIN)
         .addKeepMainRule(MAIN)
+        .enableConstantArgumentAnnotations()
         .setMinApi(parameters.getApiLevel())
-        .addOptionsModification(
-            o -> {
-              // No actual implementation of B112517039I, rather invoked with `null`.
-              // Call site optimization propagation will conclude that the input of B...Caller#call
-              // is
-              // always null, and replace the last call with null-throwing instruction.
-              // However, we want to test return type and parameter type are kept in this scenario.
-              o.callSiteOptimizationOptions().disableDynamicTypePropagationForTesting();
-              o.inlinerOptions().enableInlining = false;
-            })
+        .addOptionsModification(o -> o.inlinerOptions().enableInlining = false)
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutput(JAVA_OUTPUT)
         .inspect(
diff --git a/src/test/java/com/android/tools/r8/tracereferences/TraceReferencesMissingReferencesInDexTest.java b/src/test/java/com/android/tools/r8/tracereferences/TraceReferencesMissingReferencesInDexTest.java
index b1e75c2..356bfab 100644
--- a/src/test/java/com/android/tools/r8/tracereferences/TraceReferencesMissingReferencesInDexTest.java
+++ b/src/test/java/com/android/tools/r8/tracereferences/TraceReferencesMissingReferencesInDexTest.java
@@ -31,6 +31,8 @@
     return getTestParameters().withNoneRuntime().build();
   }
 
+  private static final AndroidApiLevel minApi = AndroidApiLevel.B;
+
   public TraceReferencesMissingReferencesInDexTest(TestParameters parameters) {
     parameters.assertNoneRuntime();
   }
@@ -91,7 +93,11 @@
   @Test
   public void missingClassReferencedInDexArchive() throws Throwable {
     missingClassReferenced(
-        testForD8(Backend.DEX).addProgramClasses(Source.class).compile().writeToZip());
+        testForD8(Backend.DEX)
+            .addProgramClasses(Source.class)
+            .setMinApi(minApi)
+            .compile()
+            .writeToZip());
   }
 
   @Test
@@ -99,6 +105,7 @@
     missingClassReferenced(
         testForD8(Backend.DEX)
             .addProgramClasses(Source.class)
+            .setMinApi(minApi)
             .compile()
             .writeToDirectory()
             .resolve("classes.dex"));
@@ -131,6 +138,7 @@
         testForD8(Backend.DEX)
             .addProgramClasses(Source.class)
             .addProgramClassFileData(getClassWithTargetRemoved())
+            .setMinApi(minApi)
             .compile()
             .writeToZip());
   }
@@ -141,6 +149,7 @@
         testForD8(Backend.DEX)
             .addProgramClasses(Source.class)
             .addProgramClassFileData(getClassWithTargetRemoved())
+            .setMinApi(minApi)
             .compile()
             .writeToDirectory()
             .resolve("classes.dex"));
diff --git a/third_party/retrace/binary_compatibility.tar.gz.sha1 b/third_party/retrace/binary_compatibility.tar.gz.sha1
index f81f5fc..ee23c0c 100644
--- a/third_party/retrace/binary_compatibility.tar.gz.sha1
+++ b/third_party/retrace/binary_compatibility.tar.gz.sha1
@@ -1 +1 @@
-239b7652dc8282715373a1871987c3919df029d6
\ No newline at end of file
+40f612b228f0520a11a2e2f8745400163c70c82f
\ No newline at end of file
diff --git a/tools/archive_desugar_jdk_libs.py b/tools/archive_desugar_jdk_libs.py
index a44524e..2572610 100755
--- a/tools/archive_desugar_jdk_libs.py
+++ b/tools/archive_desugar_jdk_libs.py
@@ -98,7 +98,10 @@
         bazel,
         '--bazelrc=/dev/null',
         'build',
-        'maven_release' + ('_jdk11' if variant == 'jdk11' else '')]
+        'maven_release' + ('_jdk11' if variant == 'jdk11' else ''),
+         '--java_language_version=' + ('11' if variant == 'jdk11' else '8')]
+    if variant == 'jdk11':
+        cmd.append('--java_runtime_version=remotejdk_11')
     utils.PrintCmd(cmd)
     subprocess.check_call(cmd)
     cmd = [bazel, 'shutdown']
diff --git a/tools/compare_apk_sizes.py b/tools/compare_apk_sizes.py
index da505c7..9a56187 100755
--- a/tools/compare_apk_sizes.py
+++ b/tools/compare_apk_sizes.py
@@ -45,7 +45,7 @@
 def ensure_exists(files):
   for f in files:
     if not os.path.exists(f):
-      raise Exception('%s does not exist')
+      raise Exception('%s does not exist' % f)
 
 def extract_classes(input, output):
   if os.path.exists(output):
diff --git a/tools/internal_test.py b/tools/internal_test.py
index cc2ee93..47d236e 100755
--- a/tools/internal_test.py
+++ b/tools/internal_test.py
@@ -341,6 +341,10 @@
   if cmd == []:
     return
 
+  assert(cmd[0].endswith('.py'))
+  cmd = [sys.executable] + cmd
+
+
   utils.PrintCmd(cmd)
   with utils.TempDir() as temp:
     try: