Merge commit 'a736e22be57f144c823cc33d03f895d081f7b795' into dev-release
diff --git a/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java b/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java
index 107efb4..61caf95 100644
--- a/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java
+++ b/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java
@@ -104,7 +104,7 @@
 
   InternalOptions getInternalOptions() {
     InternalOptions options = new InternalOptions(factory, getReporter());
-    options.minApiLevel = AndroidApiLevel.getAndroidApiLevel(minApiLevel);
+    options.setMinApiLevel(AndroidApiLevel.getAndroidApiLevel(minApiLevel));
     options.desugaredLibraryConfiguration = desugaredLibraryConfiguration;
     return options;
   }
diff --git a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
index 9e5376f..4af2547 100644
--- a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
+++ b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
@@ -678,7 +678,7 @@
         reporter.error(builder.toString());
       }
       if (getMinApiLevel() > AndroidApiLevel.LATEST.getLevel()) {
-        if (getMinApiLevel() != AndroidApiLevel.magicApiLevelUsedByAndroidPlatformBuild) {
+        if (getMinApiLevel() != AndroidApiLevel.ANDROID_PLATFORM.getLevel()) {
           reporter.warning(
               "An API level of "
                   + getMinApiLevel()
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index 1e6d847..8d0f357 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -465,7 +465,7 @@
     internal.mainDexListConsumer = getMainDexListConsumer();
     internal.minimalMainDex = internal.debug || minimalMainDex;
     internal.enableMainDexListCheck = enableMainDexListCheck;
-    internal.minApiLevel = AndroidApiLevel.getAndroidApiLevel(getMinApiLevel());
+    internal.setMinApiLevel(AndroidApiLevel.getAndroidApiLevel(getMinApiLevel()));
     internal.intermediate = intermediate;
     internal.retainCompileTimeAnnotations = intermediate;
     internal.desugarGraphConsumer = desugarGraphConsumer;
diff --git a/src/main/java/com/android/tools/r8/ExtractMarker.java b/src/main/java/com/android/tools/r8/ExtractMarker.java
index b21bb03..320ad14 100644
--- a/src/main/java/com/android/tools/r8/ExtractMarker.java
+++ b/src/main/java/com/android/tools/r8/ExtractMarker.java
@@ -101,7 +101,7 @@
   private static Collection<Marker> extractMarker(AndroidApp app) throws IOException {
     InternalOptions options = new InternalOptions();
     options.skipReadingDexCode = true;
-    options.minApiLevel = AndroidApiLevel.P;
+    options.setMinApiLevel(AndroidApiLevel.P);
     DexApplication dexApp = new ApplicationReader(app, options, new Timing("ExtractMarker")).read();
     return dexApp.dexItemFactory.extractMarkers();
   }
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index 745d94d..51ea781 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -164,7 +164,7 @@
     internal.debug = getMode() == CompilationMode.DEBUG;
     assert internal.mainDexListConsumer == null;
     assert !internal.minimalMainDex;
-    internal.minApiLevel = AndroidApiLevel.getAndroidApiLevel(getMinApiLevel());
+    internal.setMinApiLevel(AndroidApiLevel.getAndroidApiLevel(getMinApiLevel()));
     assert !internal.intermediate;
     assert internal.retainCompileTimeAnnotations;
     internal.programConsumer = getProgramConsumer();
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index a0ac288..1483137 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -354,7 +354,7 @@
               options.itemFactory, options.getProguardConfiguration().getRules())) {
             synthesizedProguardRules.add(
                 ProguardConfigurationUtils.buildAssumeNoSideEffectsRuleForApiLevel(
-                    options.itemFactory, options.minApiLevel));
+                    options.itemFactory, options.getMinApiLevel()));
           }
         }
         SubtypingInfo subtypingInfo = new SubtypingInfo(appView);
@@ -883,20 +883,16 @@
       return true;
     }
     // This will return false if we find anything in the library which is not modeled.
-    appView
-        .appInfo()
-        .classes()
-        .forEach(
-            clazz -> {
-              clazz.forEachProgramMember(
-                  member -> {
-                    assert member.getDefinition().getApiLevel() != AndroidApiLevel.NOT_SET
-                        : "Every member should have been analyzed";
-                    assert appView.options().apiModelingOptions().enableApiCallerIdentification
-                            || member.getDefinition().getApiLevel() == AndroidApiLevel.UNKNOWN
-                        : "Every member should have level UNKNOWN";
-                  });
-            });
+    for (DexProgramClass clazz : appView.appInfo().classesWithDeterministicOrder()) {
+      clazz.forEachProgramMember(
+          member -> {
+            assert member.getDefinition().getApiLevel() != AndroidApiLevel.NOT_SET
+                : "Every member should have been analyzed";
+            assert appView.options().apiModelingOptions().enableApiCallerIdentification
+                    || member.getDefinition().getApiLevel() == AndroidApiLevel.UNKNOWN
+                : "Every member should have level UNKNOWN";
+          });
+    }
     return true;
   }
 
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index ecc0eff..4923f93 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -833,7 +833,7 @@
     InternalOptions internal = new InternalOptions(getMode(), proguardConfiguration, getReporter());
     assert !internal.testing.allowOutlinerInterfaceArrayArguments;  // Only allow in tests.
     internal.programConsumer = getProgramConsumer();
-    internal.minApiLevel = AndroidApiLevel.getAndroidApiLevel(getMinApiLevel());
+    internal.setMinApiLevel(AndroidApiLevel.getAndroidApiLevel(getMinApiLevel()));
     internal.desugarState = getDesugarState();
     assert internal.isShrinking() == getEnableTreeShaking();
     assert internal.isMinifying() == getEnableMinification();
diff --git a/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelCompute.java b/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelCompute.java
index 406ed61..34a2d65 100644
--- a/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelCompute.java
+++ b/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelCompute.java
@@ -50,7 +50,7 @@
 
     public DefaultAndroidApiLevelCompute(AppView<?> appView) {
       this.cache = AndroidApiReferenceLevelCache.create(appView);
-      this.minApiLevel = appView.options().minApiLevel;
+      this.minApiLevel = appView.options().getMinApiLevel();
     }
 
     @Override
diff --git a/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java b/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java
index 9a4afa3..f4049a0 100644
--- a/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java
+++ b/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java
@@ -66,34 +66,34 @@
     if (contextType.isArrayType()) {
       if (reference.isDexMethod()
           && reference.asDexMethod().match(appView.dexItemFactory().objectMembers.clone)) {
-        return appView.options().minApiLevel;
+        return appView.options().getMinApiLevel();
       }
       return lookup(contextType.toBaseType(appView.dexItemFactory()));
     }
     if (contextType.isPrimitiveType() || contextType.isVoidType()) {
-      return appView.options().minApiLevel;
+      return appView.options().getMinApiLevel();
     }
     DexClass clazz = appView.definitionFor(contextType);
     if (clazz == null) {
       return AndroidApiLevel.UNKNOWN;
     }
     if (!clazz.isLibraryClass()) {
-      return appView.options().minApiLevel;
+      return appView.options().getMinApiLevel();
     }
     if (isReferenceToJavaLangObject(reference)) {
-      return appView.options().minApiLevel;
+      return appView.options().getMinApiLevel();
     }
     if (desugaredLibraryConfiguration.isSupported(reference, appView)) {
       // If we end up desugaring the reference, the library classes is bridged by j$ which is part
       // of the program.
-      return appView.options().minApiLevel;
+      return appView.options().getMinApiLevel();
     }
     return reference
         .apply(
             androidApiLevelDatabase::getTypeApiLevel,
             androidApiLevelDatabase::getFieldApiLevel,
             androidApiLevelDatabase::getMethodApiLevel)
-        .max(appView.options().minApiLevel);
+        .max(appView.options().getMinApiLevel());
   }
 
   private boolean isReferenceToJavaLangObject(DexReference reference) {
diff --git a/src/main/java/com/android/tools/r8/androidapi/AvailableApiExceptions.java b/src/main/java/com/android/tools/r8/androidapi/AvailableApiExceptions.java
index 606d653..0525b8f 100644
--- a/src/main/java/com/android/tools/r8/androidapi/AvailableApiExceptions.java
+++ b/src/main/java/com/android/tools/r8/androidapi/AvailableApiExceptions.java
@@ -26,8 +26,8 @@
   private final Set<DexType> exceptions;
 
   public AvailableApiExceptions(InternalOptions options) {
-    assert options.minApiLevel.isLessThan(AndroidApiLevel.L);
-    exceptions = build(options.itemFactory, options.minApiLevel);
+    assert options.getMinApiLevel().isLessThan(AndroidApiLevel.L);
+    exceptions = build(options.itemFactory, options.getMinApiLevel());
   }
 
   public boolean canCauseVerificationError(DexType type) {
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
index 07e0617..f00f7fb 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
@@ -268,7 +268,7 @@
       return true;
     }
     AndroidApiLevel nativeMultiDex = AndroidApiLevel.L;
-    if (options.minApiLevel.isLessThan(nativeMultiDex)) {
+    if (options.getMinApiLevel().isLessThan(nativeMultiDex)) {
       return true;
     }
     assert options.mainDexKeepRules.isEmpty();
@@ -280,11 +280,15 @@
   private AndroidApiLevel validateOrComputeMinApiLevel(
       AndroidApiLevel computedMinApiLevel, DexReader dexReader) {
     DexVersion version = dexReader.getDexVersion();
-    if (options.minApiLevel == AndroidApiLevel.getDefault()) {
+    if (options.getMinApiLevel() == AndroidApiLevel.getDefault()) {
       computedMinApiLevel = computedMinApiLevel.max(AndroidApiLevel.getMinAndroidApiLevel(version));
-    } else if (!version.matchesApiLevel(options.minApiLevel)) {
-      throw new CompilationError("Dex file with version '" + version.getIntValue() +
-          "' cannot be used with min sdk level '" + options.minApiLevel + "'.");
+    } else if (!version.matchesApiLevel(options.getMinApiLevel())) {
+      throw new CompilationError(
+          "Dex file with version '"
+              + version.getIntValue()
+              + "' cannot be used with min sdk level '"
+              + options.getMinApiLevel()
+              + "'.");
     }
     return computedMinApiLevel;
   }
@@ -353,7 +357,7 @@
       }
       hasReadProgramResourceFromDex = true;
       List<DexParser<DexProgramClass>> dexParsers = new ArrayList<>(dexSources.size());
-      AndroidApiLevel computedMinApiLevel = options.minApiLevel;
+      AndroidApiLevel computedMinApiLevel = options.getMinApiLevel();
       for (ProgramResource input : dexSources) {
         DexReader dexReader = new DexReader(input);
         if (options.passthroughDexCode) {
@@ -362,7 +366,7 @@
         dexParsers.add(new DexParser<>(dexReader, PROGRAM, options));
       }
 
-      options.minApiLevel = computedMinApiLevel;
+      options.setMinApiLevel(computedMinApiLevel);
       for (DexParser<DexProgramClass> dexParser : dexParsers) {
         dexParser.populateIndexTables();
       }
diff --git a/src/main/java/com/android/tools/r8/dex/DexParser.java b/src/main/java/com/android/tools/r8/dex/DexParser.java
index 0601b5c..43a9a57 100644
--- a/src/main/java/com/android/tools/r8/dex/DexParser.java
+++ b/src/main/java/com/android/tools/r8/dex/DexParser.java
@@ -302,7 +302,7 @@
 
   private void checkName(DexString name) {
     if (!options.itemFactory.getSkipNameValidationForTesting()
-        && !name.isValidSimpleName(options.minApiLevel)) {
+        && !name.isValidSimpleName(options.getMinApiLevel())) {
       throw new CompilationError("Space characters in SimpleName '"
         + name.toASCIIString()
         + "' are not allowed prior to DEX version 040");
diff --git a/src/main/java/com/android/tools/r8/dex/FileWriter.java b/src/main/java/com/android/tools/r8/dex/FileWriter.java
index 079d0d6..c937839 100644
--- a/src/main/java/com/android/tools/r8/dex/FileWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/FileWriter.java
@@ -317,7 +317,7 @@
       return true;
     }
 
-    AndroidApiLevel apiLevel = options.minApiLevel;
+    AndroidApiLevel apiLevel = options.getMinApiLevel();
     for (DexField field : mapping.getFields()) {
       assert field.name.isValidSimpleName(apiLevel);
     }
@@ -811,7 +811,7 @@
     dest.putBytes(
         options.testing.forceDexVersionBytes != null
             ? options.testing.forceDexVersionBytes
-            : DexVersion.getDexVersion(options.minApiLevel).getBytes());
+            : DexVersion.getDexVersion(options.getMinApiLevel()).getBytes());
     dest.putByte(Constants.DEX_FILE_MAGIC_SUFFIX);
     // Leave out checksum and signature for now.
     dest.moveTo(Constants.FILE_SIZE_OFFSET);
@@ -1109,7 +1109,7 @@
     }
 
     private MixedSectionOffsets(InternalOptions options, MethodToCodeObjectMapping codeMapping) {
-      this.minApiLevel = options.minApiLevel;
+      this.minApiLevel = options.getMinApiLevel();
       this.codeMapping = codeMapping;
     }
 
diff --git a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
index b59c44f..6d3e71c 100644
--- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -544,7 +544,7 @@
 
     private void checkName(String name) {
       if (!application.getFactory().getSkipNameValidationForTesting()
-          && !DexString.isValidSimpleName(application.options.minApiLevel, name)) {
+          && !DexString.isValidSimpleName(application.options.getMinApiLevel(), name)) {
         throw new CompilationError("Space characters in SimpleName '"
           + name + "' are not allowed prior to DEX version 040");
       }
diff --git a/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java b/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
index cf0d761..cce1760 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
@@ -15,10 +15,13 @@
 import com.android.tools.r8.utils.ProgramClassCollection;
 import com.android.tools.r8.utils.Timing;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Sets;
 import java.util.Collections;
 import java.util.IdentityHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 public class LazyLoadedDexApplication extends DexApplication {
 
@@ -130,13 +133,13 @@
       // on the configured lookup order.
       Map<DexType, DexClass> prioritizedClasses = new IdentityHashMap<>(expectedMaxSize);
       if (options.lookupLibraryBeforeProgram) {
-        libraryClasses = fillPrioritizedClasses(allLibraryClasses, prioritizedClasses);
-        programClasses = fillPrioritizedClasses(allProgramClasses, prioritizedClasses);
-        classpathClasses = fillPrioritizedClasses(allClasspathClasses, prioritizedClasses);
+        libraryClasses = fillPrioritizedClasses(allLibraryClasses, prioritizedClasses, options);
+        programClasses = fillPrioritizedClasses(allProgramClasses, prioritizedClasses, options);
+        classpathClasses = fillPrioritizedClasses(allClasspathClasses, prioritizedClasses, options);
       } else {
-        programClasses = fillPrioritizedClasses(allProgramClasses, prioritizedClasses);
-        classpathClasses = fillPrioritizedClasses(allClasspathClasses, prioritizedClasses);
-        libraryClasses = fillPrioritizedClasses(allLibraryClasses, prioritizedClasses);
+        programClasses = fillPrioritizedClasses(allProgramClasses, prioritizedClasses, options);
+        classpathClasses = fillPrioritizedClasses(allClasspathClasses, prioritizedClasses, options);
+        libraryClasses = fillPrioritizedClasses(allLibraryClasses, prioritizedClasses, options);
       }
 
       allClasses = Collections.unmodifiableMap(prioritizedClasses);
@@ -163,22 +166,49 @@
   }
 
   private static <T extends DexClass> ImmutableList<T> fillPrioritizedClasses(
-      Map<DexType, T> classCollection, Map<DexType, DexClass> prioritizedClasses) {
+      Map<DexType, T> classCollection,
+      Map<DexType, DexClass> prioritizedClasses,
+      InternalOptions options) {
     if (classCollection != null) {
+      Set<DexType> javaLibraryOverride = Sets.newIdentityHashSet();
       ImmutableList.Builder<T> builder = ImmutableList.builder();
       classCollection.forEach(
           (type, clazz) -> {
-            if (!prioritizedClasses.containsKey(type)) {
+            DexClass other = prioritizedClasses.get(type);
+            if (other == null) {
               prioritizedClasses.put(type, clazz);
               builder.add(clazz);
+            } else if (type.getPackageName().startsWith("java.")
+                && (clazz.isLibraryClass() || other.isLibraryClass())) {
+              javaLibraryOverride.add(type);
             }
           });
+      if (!javaLibraryOverride.isEmpty()) {
+        warnJavaLibraryOverride(options, javaLibraryOverride);
+      }
       return builder.build();
     } else {
       return ImmutableList.of();
     }
   }
 
+  private static void warnJavaLibraryOverride(
+      InternalOptions options, Set<DexType> javaLibraryOverride) {
+    String joined =
+        javaLibraryOverride.stream()
+            .sorted()
+            .map(DexType::toString)
+            .collect(Collectors.joining(", "));
+    String message =
+        "The following library types, prefixed by java.,"
+            + " are present both as library and non library classes: "
+            + joined
+            + ". "
+            + (options.lookupLibraryBeforeProgram ? "Non library" : "Library")
+            + " classes will be ignored.";
+    options.reporter.warning(message);
+  }
+
   /**
    * Force load all classes and return type -> class map containing all the classes.
    */
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
index 7c52c77..7f4b9f9 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
@@ -23,7 +23,7 @@
 
   public ApiModelAnalysis(AppView<?> appView, AndroidApiLevelCompute apiCompute) {
     this.appView = appView;
-    this.minApiLevel = appView.options().minApiLevel;
+    this.minApiLevel = appView.options().getMinApiLevel();
     this.apiCompute = apiCompute;
   }
 
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 4191a9c..acc4577 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
@@ -46,7 +46,7 @@
 
   @Override
   public boolean equals(Object o) {
-    if (getClass() != o.getClass()) {
+    if (o == null || getClass() != o.getClass()) {
       return false;
     }
     SingleStatefulFieldValue singleFieldValue = (SingleStatefulFieldValue) o;
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 ce9faef..2b72d1e 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
@@ -76,7 +76,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.MemberValuePropagation;
 import com.android.tools.r8.ir.optimize.PeepholeOptimizer;
-import com.android.tools.r8.ir.optimize.RedundantFieldLoadElimination;
+import com.android.tools.r8.ir.optimize.RedundantFieldLoadAndStoreElimination;
 import com.android.tools.r8.ir.optimize.ReflectionOptimizer;
 import com.android.tools.r8.ir.optimize.ServiceLoaderRewriter;
 import com.android.tools.r8.ir.optimize.classinliner.ClassInliner;
@@ -1344,9 +1344,9 @@
       codeRewriter.redundantConstNumberRemoval(code);
       timing.end();
     }
-    if (RedundantFieldLoadElimination.shouldRun(appView, code)) {
+    if (RedundantFieldLoadAndStoreElimination.shouldRun(appView, code)) {
       timing.begin("Remove field loads");
-      new RedundantFieldLoadElimination(appView, code).run();
+      new RedundantFieldLoadAndStoreElimination(appView, code).run();
       timing.end();
     }
 
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
index 2e9fcab..c516da4 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
@@ -169,19 +169,19 @@
 
       DexItemFactory factory = options.itemFactory;
 
-      if (options.minApiLevel.isLessThan(AndroidApiLevel.K)) {
+      if (options.getMinApiLevel().isLessThan(AndroidApiLevel.K)) {
         initializeAndroidKMethodProviders(factory);
       }
-      if (options.minApiLevel.isLessThan(AndroidApiLevel.N)) {
+      if (options.getMinApiLevel().isLessThan(AndroidApiLevel.N)) {
         initializeAndroidNMethodProviders(factory);
       }
-      if (options.minApiLevel.isLessThan(AndroidApiLevel.O)) {
+      if (options.getMinApiLevel().isLessThan(AndroidApiLevel.O)) {
         initializeAndroidOMethodProviders(factory);
       }
-      if (options.minApiLevel.isLessThan(AndroidApiLevel.R)) {
+      if (options.getMinApiLevel().isLessThan(AndroidApiLevel.R)) {
         initializeAndroidRMethodProviders(factory);
       }
-      if (options.minApiLevel.isLessThan(AndroidApiLevel.S)) {
+      if (options.getMinApiLevel().isLessThan(AndroidApiLevel.S)) {
         initializeAndroidSMethodProviders(factory);
       }
 
@@ -190,13 +190,13 @@
       // libraries or natively. If Optional/Stream class is not present, we do not desugar to
       // avoid confusion in error messages.
       if (appView.rewritePrefix.hasRewrittenType(factory.optionalType, appView)
-          || options.minApiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.N)) {
+          || options.getMinApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N)) {
         initializeJava9OptionalMethodProviders(factory);
         initializeJava10OptionalMethodProviders(factory);
         initializeJava11OptionalMethodProviders(factory);
       }
       if (appView.rewritePrefix.hasRewrittenType(factory.streamType, appView)
-          || options.minApiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.N)) {
+          || options.getMinApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N)) {
         initializeStreamMethodProviders(factory);
       }
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
rename to src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
index 290f25b..117ecfc 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
@@ -1,9 +1,10 @@
-// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// 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 com.android.tools.r8.utils.MapUtils.ignoreKey;
 import static com.android.tools.r8.utils.PredicateUtils.not;
 
 import com.android.tools.r8.errors.Unreachable;
@@ -38,6 +39,7 @@
 import com.google.common.collect.Sets;
 import it.unimi.dsi.fastutil.objects.Reference2IntMap;
 import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
+import java.util.IdentityHashMap;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
@@ -52,7 +54,7 @@
  * <p>Simple algorithm that goes through all blocks in one pass in topological order and propagates
  * active field sets across control-flow edges where the target has only one predecessor.
  */
-public class RedundantFieldLoadElimination {
+public class RedundantFieldLoadAndStoreElimination {
 
   private static final int MAX_CAPACITY = 10000;
   private static final int MIN_CAPACITY_PER_BLOCK = 50;
@@ -72,7 +74,9 @@
   // elimination.
   private BlockState activeState;
 
-  public RedundantFieldLoadElimination(AppView<?> appView, IRCode code) {
+  private final Map<BasicBlock, Set<Instruction>> instructionsToRemove = new IdentityHashMap<>();
+
+  public RedundantFieldLoadAndStoreElimination(AppView<?> appView, IRCode code) {
     this.appView = appView;
     this.method = code.context();
     this.code = code;
@@ -81,7 +85,7 @@
 
   public static boolean shouldRun(AppView<?> appView, IRCode code) {
     return appView.options().enableRedundantFieldLoadElimination
-        && (code.metadata().mayHaveFieldGet() || code.metadata().mayHaveInitClass());
+        && (code.metadata().mayHaveFieldInstruction() || code.metadata().mayHaveInitClass());
   }
 
   private interface FieldValue {
@@ -219,48 +223,14 @@
                     fieldAndObject, new ExistingValue(instanceGet.value()));
               }
             } else if (instruction.isInstancePut()) {
-              InstancePut instancePut = instruction.asInstancePut();
-              // An instance-put instruction can potentially write the given field on all objects
-              // because of aliases.
-              killNonFinalActiveFields(instancePut);
-              // ... but at least we know the field value for this particular object.
-              Value object = instancePut.object().getAliasedValue();
-              FieldAndObject fieldAndObject = new FieldAndObject(reference, object);
-              ExistingValue value = new ExistingValue(instancePut.value());
-              if (isFinal(field)) {
-                assert !field.getDefinition().isFinal()
-                    || method.getDefinition().isInstanceInitializer()
-                    || verifyWasInstanceInitializer();
-                activeState.putFinalInstanceField(fieldAndObject, value);
-              } else {
-                activeState.putNonFinalInstanceField(fieldAndObject, value);
-              }
+              handleInstancePut(instruction.asInstancePut(), field);
             } else if (instruction.isStaticGet()) {
               handleStaticGet(it, instruction.asStaticGet(), field);
             } else if (instruction.isStaticPut()) {
-              StaticPut staticPut = instruction.asStaticPut();
-              // A field put on a different class can cause <clinit> to run and change static
-              // field values.
-              killNonFinalActiveFields(staticPut);
-              ExistingValue value = new ExistingValue(staticPut.value());
-              if (isFinal(field)) {
-                assert appView.checkForTesting(
-                    () ->
-                        !field.getDefinition().isFinal()
-                            || method.getDefinition().isClassInitializer());
-                activeState.putFinalStaticField(reference, value);
-              } else {
-                activeState.putNonFinalStaticField(reference, value);
-              }
+              handleStaticPut(instruction.asStaticPut(), field);
             }
           } else if (instruction.isInitClass()) {
-            InitClass initClass = instruction.asInitClass();
-            assert !initClass.outValue().hasAnyUsers();
-            DexType clazz = initClass.getClassValue();
-            if (activeState.isClassInitialized(clazz)) {
-              it.removeOrReplaceByDebugLocalRead();
-            }
-            activeState.markClassAsInitialized(clazz);
+            handleInitClass(it, instruction.asInitClass());
           } else if (instruction.isMonitor()) {
             if (instruction.asMonitor().isEnter()) {
               killAllNonFinalActiveFields();
@@ -322,12 +292,33 @@
       assert end != null;
       activeStates.recordActiveStateOnBlockExit(end, activeState);
     }
+    processInstructionsToRemove();
     if (!affectedValues.isEmpty()) {
       new TypeAnalysis(appView).narrowing(affectedValues);
     }
     assert code.isConsistentSSA();
   }
 
+  private void processInstructionsToRemove() {
+    instructionsToRemove.forEach(
+        (block, instructionsToRemoveInBlock) -> {
+          assert instructionsToRemoveInBlock.stream()
+              .allMatch(instruction -> instruction.getBlock() == block);
+          InstructionListIterator instructionIterator = block.listIterator(code);
+          while (instructionIterator.hasNext()) {
+            Instruction instruction = instructionIterator.next();
+            assert !instruction.isJumpInstruction();
+            if (instructionsToRemoveInBlock.contains(instruction)) {
+              instructionIterator.removeOrReplaceByDebugLocalRead();
+              instructionsToRemoveInBlock.remove(instruction);
+              if (instructionsToRemoveInBlock.isEmpty()) {
+                return;
+              }
+            }
+          }
+        });
+  }
+
   private boolean verifyWasInstanceInitializer() {
     VerticallyMergedClasses verticallyMergedClasses = appView.verticallyMergedClasses();
     assert verticallyMergedClasses != null;
@@ -394,11 +385,48 @@
         });
   }
 
+  private void handleInitClass(InstructionListIterator instructionIterator, InitClass initClass) {
+    assert !initClass.outValue().hasAnyUsers();
+    killNonFinalActiveFields(initClass);
+    DexType clazz = initClass.getClassValue();
+    if (!activeState.markClassAsInitialized(clazz)) {
+      instructionIterator.removeOrReplaceByDebugLocalRead();
+    }
+  }
+
+  private void handleInstancePut(InstancePut instancePut, DexClassAndField field) {
+    // An instance-put instruction can potentially write the given field on all objects
+    // because of aliases.
+    activeState.removeNonFinalInstanceFields(field.getReference());
+    // ... but at least we know the field value for this particular object.
+    Value object = instancePut.object().getAliasedValue();
+    FieldAndObject fieldAndObject = new FieldAndObject(field.getReference(), object);
+    ExistingValue value = new ExistingValue(instancePut.value());
+    if (isFinal(field)) {
+      assert !field.getDefinition().isFinal()
+          || method.getDefinition().isInstanceInitializer()
+          || verifyWasInstanceInitializer();
+      activeState.putFinalInstanceField(fieldAndObject, value);
+    } else {
+      activeState.putNonFinalInstanceField(fieldAndObject, value);
+
+      InstancePut mostRecentInstanceFieldWrite =
+          activeState.putMostRecentInstanceFieldWrite(fieldAndObject, instancePut);
+      if (mostRecentInstanceFieldWrite != null) {
+        instructionsToRemove
+            .computeIfAbsent(
+                mostRecentInstanceFieldWrite.getBlock(), ignoreKey(Sets::newIdentityHashSet))
+            .add(mostRecentInstanceFieldWrite);
+      }
+    }
+  }
+
   private void handleStaticGet(
       InstructionListIterator instructionIterator, StaticGet staticGet, DexClassAndField field) {
     if (staticGet.outValue().hasLocalInfo()) {
       return;
     }
+
     FieldValue replacement = activeState.getStaticFieldValue(field.getReference());
     if (replacement != null) {
       replacement.eliminateRedundantRead(instructionIterator, staticGet);
@@ -406,9 +434,7 @@
     }
 
     // A field get on a different class can cause <clinit> to run and change static field values.
-    if (staticGet.instructionMayHaveSideEffects(appView, method)) {
-      killNonFinalActiveFields(staticGet);
-    }
+    killNonFinalActiveFields(staticGet);
 
     FieldValue value = new ExistingValue(staticGet.value());
     if (isFinal(field)) {
@@ -426,6 +452,28 @@
     }
   }
 
+  private void handleStaticPut(StaticPut staticPut, DexClassAndField field) {
+    // A field put on a different class can cause <clinit> to run and change static field values.
+    killNonFinalActiveFields(staticPut);
+    ExistingValue value = new ExistingValue(staticPut.value());
+    if (isFinal(field)) {
+      assert appView.checkForTesting(
+          () -> !field.getDefinition().isFinal() || method.getDefinition().isClassInitializer());
+      activeState.putFinalStaticField(field.getReference(), value);
+    } else {
+      activeState.putNonFinalStaticField(field.getReference(), value);
+
+      StaticPut mostRecentStaticFieldWrite =
+          activeState.putMostRecentStaticFieldWrite(field.getReference(), staticPut);
+      if (mostRecentStaticFieldWrite != null) {
+        instructionsToRemove
+            .computeIfAbsent(
+                mostRecentStaticFieldWrite.getBlock(), ignoreKey(Sets::newIdentityHashSet))
+            .add(mostRecentStaticFieldWrite);
+      }
+    }
+  }
+
   private void applyObjectState(Value value, ObjectState objectState) {
     objectState.forEachAbstractFieldValue(
         (field, fieldValue) -> {
@@ -443,27 +491,26 @@
   private void killAllNonFinalActiveFields() {
     activeState.clearNonFinalInstanceFields();
     activeState.clearNonFinalStaticFields();
+    activeState.clearMostRecentFieldWrites();
   }
 
-  private void killNonFinalActiveFields(FieldInstruction instruction) {
-    DexField field = instruction.getField();
-    if (instruction.isInstancePut()) {
-      // Remove all the field/object pairs that refer to this field to make sure
-      // that we are conservative.
-      activeState.removeNonFinalInstanceFields(field);
-    } else if (instruction.isStaticPut()) {
-      if (field.holder != code.method().getHolderType()) {
+  private void killNonFinalActiveFields(Instruction instruction) {
+    assert instruction.isInitClass() || instruction.isStaticFieldInstruction();
+    if (instruction.isStaticPut()) {
+      if (instruction.instructionMayTriggerMethodInvocation(appView, method)) {
         // Accessing a static field on a different object could cause <clinit> to run which
         // could modify any static field on any other object.
         activeState.clearNonFinalStaticFields();
+        activeState.clearMostRecentFieldWrites();
       } else {
-        activeState.removeNonFinalStaticField(field);
+        activeState.removeNonFinalStaticField(instruction.asStaticPut().getField());
       }
-    } else if (instruction.isStaticGet()) {
-      if (field.holder != code.method().getHolderType()) {
+    } else if (instruction.isInitClass() || instruction.isStaticGet()) {
+      if (instruction.instructionMayTriggerMethodInvocation(appView, method)) {
         // Accessing a static field on a different object could cause <clinit> to run which
         // could modify any static field on any other object.
         activeState.clearNonFinalStaticFields();
+        activeState.clearMostRecentFieldWrites();
       }
     } else if (instruction.isInstanceGet()) {
       throw new Unreachable();
@@ -564,6 +611,9 @@
       if (state.isEmpty()) {
         return;
       }
+      if (!block.hasUniqueSuccessorWithUniquePredecessor()) {
+        state.clearMostRecentFieldWrites();
+      }
       ensureCapacity(state);
       activeStateAtExit.put(block, state);
       capacity -= state.size();
@@ -602,6 +652,10 @@
 
     private LinkedHashMap<DexField, FieldValue> nonFinalStaticFieldValues;
 
+    private LinkedHashMap<FieldAndObject, InstancePut> mostRecentInstanceFieldWrites;
+
+    private LinkedHashMap<DexField, StaticPut> mostRecentStaticFieldWrites;
+
     private final int maxCapacity;
 
     public BlockState(int maxCapacity) {
@@ -632,9 +686,32 @@
           nonFinalStaticFieldValues = new LinkedHashMap<>();
           nonFinalStaticFieldValues.putAll(state.nonFinalStaticFieldValues);
         }
+        if (state.mostRecentInstanceFieldWrites != null
+            && !state.mostRecentInstanceFieldWrites.isEmpty()) {
+          mostRecentInstanceFieldWrites = new LinkedHashMap<>();
+          mostRecentInstanceFieldWrites.putAll(state.mostRecentInstanceFieldWrites);
+        }
+        if (state.mostRecentStaticFieldWrites != null
+            && !state.mostRecentStaticFieldWrites.isEmpty()) {
+          mostRecentStaticFieldWrites = new LinkedHashMap<>();
+          mostRecentStaticFieldWrites.putAll(state.mostRecentStaticFieldWrites);
+        }
       }
     }
 
+    public void clearMostRecentFieldWrites() {
+      clearMostRecentInstanceFieldWrites();
+      clearMostRecentStaticFieldWrites();
+    }
+
+    public void clearMostRecentInstanceFieldWrites() {
+      mostRecentInstanceFieldWrites = null;
+    }
+
+    public void clearMostRecentStaticFieldWrites() {
+      mostRecentStaticFieldWrites = null;
+    }
+
     public void clearNonFinalInstanceFields() {
       nonFinalInstanceFieldValues = null;
     }
@@ -695,6 +772,8 @@
       } else {
         nonFinalStaticFieldValues = null;
       }
+      assert mostRecentInstanceFieldWrites == null;
+      assert mostRecentStaticFieldWrites == null;
     }
 
     private static <K> void intersectFieldValues(
@@ -747,12 +826,12 @@
       }
     }
 
-    public void markClassAsInitialized(DexType clazz) {
+    public boolean markClassAsInitialized(DexType clazz) {
       ensureCapacityForNewElement();
       if (initializedClasses == null) {
         initializedClasses = new LinkedHashSet<>();
       }
-      initializedClasses.add(clazz);
+      return initializedClasses.add(clazz);
     }
 
     public void reduceSize(int numberOfItemsToRemove) {
@@ -763,6 +842,8 @@
       numberOfItemsToRemove = reduceSize(numberOfItemsToRemove, nonFinalStaticFieldValues);
       numberOfItemsToRemove = reduceSize(numberOfItemsToRemove, finalInstanceFieldValues);
       numberOfItemsToRemove = reduceSize(numberOfItemsToRemove, finalStaticFieldValues);
+      numberOfItemsToRemove = reduceSize(numberOfItemsToRemove, mostRecentInstanceFieldWrites);
+      numberOfItemsToRemove = reduceSize(numberOfItemsToRemove, mostRecentStaticFieldWrites);
       assert numberOfItemsToRemove == 0;
     }
 
@@ -786,6 +867,7 @@
     public void removeInstanceField(FieldAndObject field) {
       removeFinalInstanceField(field);
       removeNonFinalInstanceField(field);
+      removeMostRecentInstanceFieldWrite(field);
     }
 
     public void removeFinalInstanceField(FieldAndObject field) {
@@ -809,6 +891,7 @@
     public void removeStaticField(DexField field) {
       removeFinalStaticField(field);
       removeNonFinalStaticField(field);
+      removeMostRecentStaticFieldWrite(field);
     }
 
     public void removeFinalStaticField(DexField field) {
@@ -823,6 +906,18 @@
       }
     }
 
+    public void removeMostRecentInstanceFieldWrite(FieldAndObject field) {
+      if (mostRecentInstanceFieldWrites != null) {
+        mostRecentInstanceFieldWrites.remove(field);
+      }
+    }
+
+    public void removeMostRecentStaticFieldWrite(DexField field) {
+      if (mostRecentStaticFieldWrites != null) {
+        mostRecentStaticFieldWrites.remove(field);
+      }
+    }
+
     public void putFinalInstanceField(FieldAndObject field, FieldValue value) {
       ensureCapacityForNewElement();
       if (finalInstanceFieldValues == null) {
@@ -839,6 +934,23 @@
       finalStaticFieldValues.put(field, value);
     }
 
+    public InstancePut putMostRecentInstanceFieldWrite(
+        FieldAndObject field, InstancePut instancePut) {
+      ensureCapacityForNewElement();
+      if (mostRecentInstanceFieldWrites == null) {
+        mostRecentInstanceFieldWrites = new LinkedHashMap<>();
+      }
+      return mostRecentInstanceFieldWrites.put(field, instancePut);
+    }
+
+    public StaticPut putMostRecentStaticFieldWrite(DexField field, StaticPut staticPut) {
+      ensureCapacityForNewElement();
+      if (mostRecentStaticFieldWrites == null) {
+        mostRecentStaticFieldWrites = new LinkedHashMap<>();
+      }
+      return mostRecentStaticFieldWrites.put(field, staticPut);
+    }
+
     public void putNonFinalInstanceField(FieldAndObject field, FieldValue value) {
       ensureCapacityForNewElement();
       assert finalInstanceFieldValues == null || !finalInstanceFieldValues.containsKey(field);
@@ -862,7 +974,9 @@
           + size(finalStaticFieldValues)
           + size(initializedClasses)
           + size(nonFinalInstanceFieldValues)
-          + size(nonFinalStaticFieldValues);
+          + size(nonFinalStaticFieldValues)
+          + size(mostRecentInstanceFieldWrites)
+          + size(mostRecentStaticFieldWrites);
     }
 
     private static int size(Set<?> set) {
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java b/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java
index 524790c..aa91add 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java
@@ -109,7 +109,7 @@
             + Version.LABEL
             + "\n");
     if (options.isGeneratingDex()) {
-      builder.append("# " + MARKER_KEY_MIN_API + ": " + options.minApiLevel.getLevel() + "\n");
+      builder.append("# " + MARKER_KEY_MIN_API + ": " + options.getMinApiLevel().getLevel() + "\n");
     }
     if (Version.isDevelopmentVersion()) {
       builder.append(
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 72b0295..a198bb7 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.optimize;
 
+import static com.android.tools.r8.utils.AndroidApiLevelUtils.isApiSafeForMemberRebinding;
+
 import com.android.tools.r8.androidapi.AndroidApiLevelCompute;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
@@ -25,7 +27,6 @@
 import com.android.tools.r8.ir.code.Invoke.Type;
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BiForEachable;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.Pair;
@@ -126,7 +127,8 @@
     return resolvedMethod.isLibraryMethod()
         && isAccessibleInAllContexts(resolvedMethod, resolutionResult, contexts)
         && !isInvokeSuperToInterfaceMethod(resolvedMethod, invokeType)
-        && isPresentSinceMinApi(resolvedMethod.asLibraryMethod());
+        && isApiSafeForMemberRebinding(
+            resolvedMethod.asLibraryMethod(), androidApiLevelCompute, options);
   }
 
   private boolean isAccessibleInAllContexts(
@@ -145,12 +147,6 @@
     return method.getHolder().isInterface() && invokeType.isSuper();
   }
 
-  private boolean isPresentSinceMinApi(LibraryMethod method) {
-    AndroidApiLevel apiLevel =
-        androidApiLevelCompute.computeApiLevelForLibraryReference(method.getReference());
-    return apiLevel != AndroidApiLevel.UNKNOWN && apiLevel.isLessThanOrEqualTo(options.minApiLevel);
-  }
-
   public static DexField validMemberRebindingTargetFor(
       DexDefinitionSupplier definitions, DexClassAndField field, DexField original) {
     if (field.isProgramField()) {
diff --git a/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java b/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java
index d0bf27c..941bcff 100644
--- a/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java
+++ b/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java
@@ -40,7 +40,7 @@
     this.appView = appView;
     this.enqueuer = enqueuer;
     this.computeApiLevel = computeApiLevel;
-    this.maxApiReferenceLevel = appView.options().minApiLevel;
+    this.maxApiReferenceLevel = appView.options().getMinApiLevel();
   }
 
   public DexProgramClass getContextHolder() {
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
index e1a79db..6b82664 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
@@ -43,16 +43,15 @@
   R(30),
   S(31),
   Sv2(32),
-  UNKNOWN(10000),
-  NOT_SET(10001);
+  ANDROID_PLATFORM(10000),
+  UNKNOWN(10001),
+  NOT_SET(10002);
 
   // When updating LATEST and a new version goes stable, add a new api-versions.xml to third_party
   // and update the version and generated jar in AndroidApiDatabaseBuilderGeneratorTest.
   // TODO(b/204738868): Update API database for Sv2.
   public static final AndroidApiLevel LATEST = Sv2;
 
-  public static final int magicApiLevelUsedByAndroidPlatformBuild = 10000;
-
   private final int level;
 
   AndroidApiLevel(int level) {
@@ -82,7 +81,7 @@
   public static AndroidApiLevel minApiLevelIfEnabledOrUnknown(AppView<?> appView) {
     InternalOptions options = appView.options();
     return options.apiModelingOptions().enableApiCallerIdentification
-        ? options.minApiLevel
+        ? options.getMinApiLevel()
         : UNKNOWN;
   }
 
@@ -107,7 +106,7 @@
 
   public static AndroidApiLevel getAndroidApiLevel(int apiLevel) {
     assert apiLevel > 0;
-    assert UNKNOWN.isGreaterThan(LATEST);
+    assert ANDROID_PLATFORM.isGreaterThan(LATEST);
     switch (apiLevel) {
       case 1:
         return B;
@@ -173,10 +172,12 @@
         return S;
       case 32:
         return Sv2;
+      case 10000:
+        return ANDROID_PLATFORM;
       default:
         // This has to be updated when we add new api levels.
         assert Sv2 == LATEST;
-        return UNKNOWN;
+        return LATEST;
     }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java b/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java
index 73ee4de..c4a7396 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.utils;
 
+import com.android.tools.r8.androidapi.AndroidApiLevelCompute;
+import com.android.tools.r8.graph.LibraryMethod;
 import com.android.tools.r8.graph.ProgramMethod;
 
 public class AndroidApiLevelUtils {
@@ -13,6 +15,10 @@
     if (!options.apiModelingOptions().enableApiCallerIdentification) {
       return true;
     }
+    if (options.isAndroidPlatform()) {
+      // Don't disable inlining in the Android platform based on the Api database.
+      return true;
+    }
     if (caller.getHolderType() == inlinee.getHolderType()) {
       return true;
     }
@@ -21,4 +27,17 @@
         .getApiLevel()
         .isGreaterThanOrEqualTo(inlinee.getDefinition().getApiLevelForCode());
   }
+
+  public static boolean isApiSafeForMemberRebinding(
+      LibraryMethod method,
+      AndroidApiLevelCompute androidApiLevelCompute,
+      InternalOptions options) {
+    AndroidApiLevel apiLevel =
+        androidApiLevelCompute.computeApiLevelForLibraryReference(method.getReference());
+    if (apiLevel == AndroidApiLevel.UNKNOWN) {
+      return false;
+    }
+    assert options.apiModelingOptions().enableApiCallerIdentification;
+    return apiLevel.isLessThanOrEqualTo(options.getMinApiLevel());
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/utils/DexVersion.java b/src/main/java/com/android/tools/r8/utils/DexVersion.java
index 24d374e..a807bba 100644
--- a/src/main/java/com/android/tools/r8/utils/DexVersion.java
+++ b/src/main/java/com/android/tools/r8/utils/DexVersion.java
@@ -38,9 +38,9 @@
 
   public static DexVersion getDexVersion(AndroidApiLevel androidApiLevel) {
     switch (androidApiLevel) {
-        // UNKNOWN is an unknown higher api version we therefore choose the highest known
+        // ANDROID_PLATFORM is an unknown higher api version we therefore choose the highest known
         // version.
-      case UNKNOWN:
+      case ANDROID_PLATFORM:
       case Sv2:
       case S:
       case R:
@@ -77,7 +77,8 @@
       case L_MR1:
       case M:
         return DexVersion.V35;
-      default :
+      case UNKNOWN:
+      default:
         throw new Unreachable("Unsupported api level " + androidApiLevel);
     }
   }
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 acdf404..c012686 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -377,7 +377,7 @@
     // since the output depends on the min API in this case. There is basically no min API entry
     // in R8 cf to cf.
     if (isGeneratingDex() || desugarState == DesugarState.ON) {
-      marker.setMinApi(minApiLevel.getLevel());
+      marker.setMinApi(getMinApiLevel().getLevel());
     }
     if (desugaredLibraryConfiguration.getIdentifier() != null) {
       marker.setDesugaredLibraryIdentifiers(desugaredLibraryConfiguration.getIdentifier());
@@ -422,6 +422,10 @@
     throw new UnsupportedOperationException("Cannot find internal output mode.");
   }
 
+  public boolean isAndroidPlatform() {
+    return minApiLevel == AndroidApiLevel.ANDROID_PLATFORM;
+  }
+
   public boolean isDesugaredLibraryCompilation() {
     return desugaredLibraryConfiguration.isLibraryCompilation();
   }
@@ -512,7 +516,7 @@
       getExtensiveInterfaceMethodMinifierLoggingFilter();
 
   public List<String> methodsFilter = ImmutableList.of();
-  public AndroidApiLevel minApiLevel = AndroidApiLevel.getDefault();
+  private AndroidApiLevel minApiLevel = AndroidApiLevel.getDefault();
   // Skipping min_api check and compiling an intermediate result intended for later merging.
   // Intermediate builds also emits or update synthesized classes mapping.
   public boolean intermediate = false;
@@ -553,6 +557,16 @@
   private final boolean enableTreeShaking;
   private final boolean enableMinification;
 
+  public AndroidApiLevel getMinApiLevel() {
+    return minApiLevel;
+  }
+
+  public void setMinApiLevel(AndroidApiLevel minApiLevel) {
+    assert minApiLevel != null;
+    assert minApiLevel.isLessThan(AndroidApiLevel.UNKNOWN);
+    this.minApiLevel = minApiLevel;
+  }
+
   public boolean isOptimizing() {
     return hasProguardConfiguration() && getProguardConfiguration().isOptimizing();
   }
@@ -1742,7 +1756,7 @@
   }
 
   private boolean hasMinApi(AndroidApiLevel level) {
-    return minApiLevel.isGreaterThanOrEqualTo(level);
+    return getMinApiLevel().isGreaterThanOrEqualTo(level);
   }
 
   /**
@@ -1825,7 +1839,7 @@
     // the highest known API level when the compiler is built. This ensures that when this is used
     // by the Android Platform build (which normally use an API level of 10000) there will be
     // no rewriting of backported methods. See b/147480264.
-    return desugarState.isOn() && minApiLevel.isLessThanOrEqualTo(AndroidApiLevel.LATEST);
+    return desugarState.isOn() && getMinApiLevel().isLessThanOrEqualTo(AndroidApiLevel.LATEST);
   }
 
   public boolean enableTryWithResourcesDesugaring() {
@@ -1927,7 +1941,7 @@
   // being thrown on out of bounds.
   public boolean canUseSameArrayAndResultRegisterInArrayGetWide() {
     assert isGeneratingDex();
-    return minApiLevel.isGreaterThan(AndroidApiLevel.O_MR1);
+    return getMinApiLevel().isGreaterThan(AndroidApiLevel.O_MR1);
   }
 
   // Some Lollipop versions of Art found in the wild perform invalid bounds
@@ -1944,7 +1958,7 @@
   //
   // See b/69364976 and b/77996377.
   public boolean canHaveBoundsCheckEliminationBug() {
-    return isGeneratingDex() && minApiLevel.isLessThan(AndroidApiLevel.M);
+    return isGeneratingDex() && getMinApiLevel().isLessThan(AndroidApiLevel.M);
   }
 
   // MediaTek JIT compilers for KitKat phones did not implement the not
@@ -1960,7 +1974,7 @@
   // assumed to not change. If the receiver register is reused for something else the verifier
   // will fail and the code will not run.
   public boolean canHaveThisTypeVerifierBug() {
-    return isGeneratingDex() && minApiLevel.isLessThan(AndroidApiLevel.M);
+    return isGeneratingDex() && getMinApiLevel().isLessThan(AndroidApiLevel.M);
   }
 
   // Art crashes if we do dead reference elimination of the receiver in release mode and Art
@@ -1969,13 +1983,13 @@
   //
   // See b/116683601 and b/116837585.
   public boolean canHaveThisJitCodeDebuggingBug() {
-    return minApiLevel.isLessThan(AndroidApiLevel.Q);
+    return getMinApiLevel().isLessThan(AndroidApiLevel.Q);
   }
 
   // The dalvik jit had a bug where the long operations add, sub, or, xor and and would write
   // the first part of the result long before reading the second part of the input longs.
   public boolean canHaveOverlappingLongRegisterBug() {
-    return isGeneratingDex() && minApiLevel.isLessThan(AndroidApiLevel.L);
+    return isGeneratingDex() && getMinApiLevel().isLessThan(AndroidApiLevel.L);
   }
 
   // Some dalvik versions found in the wild perform invalid JIT compilation of cmp-long
@@ -2008,7 +2022,7 @@
   //
   // See b/75408029.
   public boolean canHaveCmpLongBug() {
-    return isGeneratingDex() && minApiLevel.isLessThan(AndroidApiLevel.L);
+    return isGeneratingDex() && getMinApiLevel().isLessThan(AndroidApiLevel.L);
   }
 
   // Some Lollipop VMs crash if there is a const instruction between a cmp and an if instruction.
@@ -2036,7 +2050,7 @@
   //
   // See b/115552239.
   public boolean canHaveCmpIfFloatBug() {
-    return minApiLevel.isLessThan(AndroidApiLevel.M);
+    return getMinApiLevel().isLessThan(AndroidApiLevel.M);
   }
 
   // Some Lollipop VMs incorrectly optimize code with mul2addr instructions. In particular,
@@ -2058,7 +2072,7 @@
   //
   // This issue has only been observed on a Verizon Ellipsis 8 tablet. See b/76115465.
   public boolean canHaveMul2AddrBug() {
-    return isGeneratingDex() && minApiLevel.isLessThan(AndroidApiLevel.M);
+    return isGeneratingDex() && getMinApiLevel().isLessThan(AndroidApiLevel.M);
   }
 
   // Some Marshmallow VMs create an incorrect doubly-linked list of instructions. When the VM
@@ -2067,7 +2081,7 @@
   //
   // See b/77842465.
   public boolean canHaveDex2OatLinkedListBug() {
-    return isGeneratingDex() && minApiLevel.isLessThan(AndroidApiLevel.N);
+    return isGeneratingDex() && getMinApiLevel().isLessThan(AndroidApiLevel.N);
   }
 
   // dex2oat on Marshmallow VMs does aggressive inlining which can eat up all the memory on
@@ -2075,7 +2089,7 @@
   //
   // See b/111960171
   public boolean canHaveDex2OatInliningIssue() {
-    return isGeneratingDex() && minApiLevel.isLessThan(AndroidApiLevel.N);
+    return isGeneratingDex() && getMinApiLevel().isLessThan(AndroidApiLevel.N);
   }
 
   // Art 7.0.0 and later Art JIT may perform an invalid optimization if a string new-instance does
@@ -2083,7 +2097,7 @@
   //
   // See b/78493232 and b/80118070.
   public boolean canHaveArtStringNewInitBug() {
-    return isGeneratingDex() && minApiLevel.isLessThan(AndroidApiLevel.Q);
+    return isGeneratingDex() && getMinApiLevel().isLessThan(AndroidApiLevel.Q);
   }
 
   // Dalvik tracing JIT may perform invalid optimizations when int/float values are converted to
@@ -2091,7 +2105,7 @@
   //
   // See b/77496850.
   public boolean canHaveNumberConversionRegisterAllocationBug() {
-    return isGeneratingDex() && minApiLevel.isLessThan(AndroidApiLevel.L);
+    return isGeneratingDex() && getMinApiLevel().isLessThan(AndroidApiLevel.L);
   }
 
   // Some Lollipop mediatek VMs have a peculiar bug where the inliner crashes if there is a
@@ -2104,7 +2118,7 @@
   //
   // See b/68378480.
   public boolean canHaveForwardingInitInliningBug() {
-    return isGeneratingDex() && minApiLevel.isLessThan(AndroidApiLevel.M);
+    return isGeneratingDex() && getMinApiLevel().isLessThan(AndroidApiLevel.M);
   }
 
   // Some Lollipop x86_64 VMs have a bug causing a segfault if an exception handler directly targets
@@ -2116,7 +2130,7 @@
   //
   // See b/111337896.
   public boolean canHaveExceptionTargetingLoopHeaderBug() {
-    return isGeneratingDex() && !debug && minApiLevel.isLessThan(AndroidApiLevel.M);
+    return isGeneratingDex() && !debug && getMinApiLevel().isLessThan(AndroidApiLevel.M);
   }
 
   // The Dalvik tracing JIT can trace past the end of the instruction stream and end up
@@ -2131,7 +2145,7 @@
   // We also could not insert any dead code (e.g. a return) because that would make mediatek
   // dominator calculations on 7.0.0 crash. See b/128926846.
   public boolean canHaveTracingPastInstructionsStreamBug() {
-    return minApiLevel.isLessThan(AndroidApiLevel.L);
+    return getMinApiLevel().isLessThan(AndroidApiLevel.L);
   }
 
   // The art verifier incorrectly propagates type information for the following pattern:
@@ -2159,7 +2173,7 @@
   // Fixed in Android Q, see b/120985556.
   public boolean canHaveArtInstanceOfVerifierBug() {
     assert isGeneratingDex();
-    return minApiLevel.isLessThan(AndroidApiLevel.Q);
+    return getMinApiLevel().isLessThan(AndroidApiLevel.Q);
   }
 
   // Some Art Lollipop version do not deal correctly with long-to-int conversions.
@@ -2182,7 +2196,7 @@
   public boolean canHaveLongToIntBug() {
     // We have only seen this happening on Lollipop arm64 backends. We have tested on
     // Marshmallow and Nougat arm64 devices and they do not have the bug.
-    return minApiLevel.isLessThan(AndroidApiLevel.M);
+    return getMinApiLevel().isLessThan(AndroidApiLevel.M);
   }
 
   // The Art VM for Android N through P has a bug in the JIT that means that if the same
@@ -2195,7 +2209,7 @@
   //
   // See b/120164595.
   public boolean canHaveExceptionTypeBug() {
-    return minApiLevel.isLessThan(AndroidApiLevel.Q);
+    return getMinApiLevel().isLessThan(AndroidApiLevel.Q);
   }
 
   // Art 4.0.4 fails with a verification error when a null-literal is being passed directly to an
@@ -2203,7 +2217,7 @@
   // elimination of check-cast instructions where the value being cast is the constant null.
   // See b/123269162.
   public boolean canHaveArtCheckCastVerifierBug() {
-    return minApiLevel.isLessThan(AndroidApiLevel.J);
+    return getMinApiLevel().isLessThan(AndroidApiLevel.J);
   }
 
   // The verifier will merge A[] and B[] to Object[], even when both A and B implement an interface
@@ -2227,7 +2241,7 @@
   //
   // See b/131349148
   public boolean canHaveDalvikCatchHandlerVerificationBug() {
-    return isGeneratingClassFiles() || minApiLevel.isLessThan(AndroidApiLevel.L);
+    return isGeneratingClassFiles() || getMinApiLevel().isLessThan(AndroidApiLevel.L);
   }
 
   // Having an invoke instruction that targets an abstract method on a non-abstract class will fail
@@ -2235,7 +2249,7 @@
   //
   // See b/132953944.
   public boolean canHaveDalvikAbstractMethodOnNonAbstractClassVerificationBug() {
-    return isGeneratingDex() && minApiLevel.isLessThan(AndroidApiLevel.L);
+    return isGeneratingDex() && getMinApiLevel().isLessThan(AndroidApiLevel.L);
   }
 
   // On dalvik we see issues when using an int value in places where a boolean, byte, char, or short
@@ -2249,14 +2263,14 @@
   //
   // See also b/134304597 and b/124152497.
   public boolean canHaveDalvikIntUsedAsNonIntPrimitiveTypeBug() {
-    return isGeneratingClassFiles() || minApiLevel.isLessThan(AndroidApiLevel.L);
+    return isGeneratingClassFiles() || getMinApiLevel().isLessThan(AndroidApiLevel.L);
   }
 
   // The standard library prior to API 19 did not contain a ZipFile that implemented Closable.
   //
   // See b/177532008.
   public boolean canHaveZipFileWithMissingCloseableBug() {
-    return isGeneratingClassFiles() || minApiLevel.isLessThan(AndroidApiLevel.K);
+    return isGeneratingClassFiles() || getMinApiLevel().isLessThan(AndroidApiLevel.K);
   }
 
   // Some versions of Dalvik had a bug where a switch with a MAX_INT key would still go to
@@ -2264,7 +2278,7 @@
   //
   // See b/177790310.
   public boolean canHaveSwitchMaxIntBug() {
-    return isGeneratingDex() && minApiLevel.isLessThan(AndroidApiLevel.K);
+    return isGeneratingDex() && getMinApiLevel().isLessThan(AndroidApiLevel.K);
   }
 
   // On Dalvik the methods Integer.parseInt and Long.parseLong does not support strings with a '+'
@@ -2272,6 +2286,6 @@
   //
   // See b/182137865.
   public boolean canParseNumbersWithPlusPrefix() {
-    return minApiLevel.isGreaterThan(AndroidApiLevel.K);
+    return getMinApiLevel().isGreaterThan(AndroidApiLevel.K);
   }
 }
diff --git a/src/test/java/com/android/tools/r8/AsmTestBase.java b/src/test/java/com/android/tools/r8/AsmTestBase.java
index a3d5cf6..2e7cd20 100644
--- a/src/test/java/com/android/tools/r8/AsmTestBase.java
+++ b/src/test/java/com/android/tools/r8/AsmTestBase.java
@@ -29,7 +29,7 @@
   protected void ensureSameOutput(String main, AndroidApiLevel apiLevel,
       List<String> args, byte[]... classes) throws Exception {
     AndroidApp app = buildAndroidApp(classes);
-    Consumer<InternalOptions> setMinApiLevel = o -> o.minApiLevel = apiLevel;
+    Consumer<InternalOptions> setMinApiLevel = o -> o.setMinApiLevel(apiLevel);
     ProcessResult javaResult = runOnJavaRaw(main, Arrays.asList(classes), args);
     Consumer<ArtCommandBuilder> cmdBuilder = builder -> {
       for (String arg : args) {
diff --git a/src/test/java/com/android/tools/r8/TestAppViewBuilder.java b/src/test/java/com/android/tools/r8/TestAppViewBuilder.java
index d5ef230..e8e75f5 100644
--- a/src/test/java/com/android/tools/r8/TestAppViewBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestAppViewBuilder.java
@@ -92,7 +92,7 @@
   }
 
   public TestAppViewBuilder setMinApi(AndroidApiLevel minApi) {
-    optionModifications.add(options -> options.minApiLevel = minApi);
+    optionModifications.add(options -> options.setMinApiLevel(minApi));
     return this;
   }
 
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 11dfa2d..033e512 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -861,6 +861,7 @@
       case J_MR1:
       case J_MR2:
       case K_WATCH:
+      case ANDROID_PLATFORM:
       case UNKNOWN:
       case NOT_SET:
         return false;
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClinitDeadlockAfterMergingClassInitializedBySuperTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClinitDeadlockAfterMergingClassInitializedBySuperTest.java
new file mode 100644
index 0000000..aa46eb2
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClinitDeadlockAfterMergingClassInitializedBySuperTest.java
@@ -0,0 +1,67 @@
+// 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 com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.HorizontallyMergedClassesInspector;
+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 ClinitDeadlockAfterMergingClassInitializedBySuperTest 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())
+        .addKeepClassAndMembersRules(Main.class)
+        .addHorizontallyMergedClassesInspector(
+            HorizontallyMergedClassesInspector::assertNoClassesMerged)
+        .addOptionsModification(
+            options ->
+                options.horizontalClassMergerOptions().setEnableClassInitializerDeadlockDetection())
+        .setMinApi(parameters.getApiLevel())
+        .compile();
+  }
+
+  static class Main {
+
+    // @Keep
+    public static void thread0() {
+      // This will take the lock for A and then wait to take the lock for B (BC if B and C are
+      // merged).
+      System.out.println(A.b);
+    }
+
+    // @Keep
+    public static void thread1() {
+      // This will take the lock for C (BC if B and C are merged) and then wait to the the lock for
+      // its superclass A.
+      System.out.println(new C());
+    }
+  }
+
+  static class A {
+
+    static B b = new B();
+  }
+
+  static class B extends A {}
+
+  static class C extends A {}
+}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClinitDeadlockAfterMergingMutuallyDependentClassesTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClinitDeadlockAfterMergingMutuallyDependentClassesTest.java
new file mode 100644
index 0000000..ae35061
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClinitDeadlockAfterMergingMutuallyDependentClassesTest.java
@@ -0,0 +1,74 @@
+// 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 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.utils.codeinspector.HorizontallyMergedClassesInspector;
+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 ClinitDeadlockAfterMergingMutuallyDependentClassesTest 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())
+        .addKeepClassAndMembersRules(Main.class)
+        .addHorizontallyMergedClassesInspector(
+            HorizontallyMergedClassesInspector::assertNoClassesMerged)
+        .addOptionsModification(
+            options ->
+                options.horizontalClassMergerOptions().setEnableClassInitializerDeadlockDetection())
+        .enableNoHorizontalClassMergingAnnotations()
+        .setMinApi(parameters.getApiLevel())
+        .compile();
+  }
+
+  static class Main {
+
+    // @Keep
+    public static void thread0() {
+      // This will take the lock for A and then wait to take the lock for C (BC if B and C are
+      // merged).
+      System.out.println(A.c);
+    }
+
+    // @Keep
+    public static void thread1() {
+      // This will take the lock for B (BC if B and C are merged) and then wait to take the lock for
+      // A.
+      System.out.println(new B());
+      System.out.println(B.a);
+    }
+  }
+
+  @NoHorizontalClassMerging
+  static class A {
+
+    static C c = new C();
+  }
+
+  static class B {
+
+    static A a = new A();
+  }
+
+  static class C {}
+}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClinitDeadlockAfterMergingSingletonClassesInstantiatedByCompanionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClinitDeadlockAfterMergingSingletonClassesInstantiatedByCompanionTest.java
new file mode 100644
index 0000000..2ea472e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClinitDeadlockAfterMergingSingletonClassesInstantiatedByCompanionTest.java
@@ -0,0 +1,110 @@
+// 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 com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.classmerging.horizontal.ClinitDeadlockAfterMergingSingletonClassesInstantiatedByCompanionTest.Host.Companion.HostA;
+import com.android.tools.r8.classmerging.horizontal.ClinitDeadlockAfterMergingSingletonClassesInstantiatedByCompanionTest.Host.Companion.HostB;
+import com.android.tools.r8.utils.codeinspector.HorizontallyMergedClassesInspector;
+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)
+public class ClinitDeadlockAfterMergingSingletonClassesInstantiatedByCompanionTest
+    extends TestBase {
+
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameter(1)
+  public int thread;
+
+  @Parameters(name = "{0}, thread: {1}")
+  public static List<Object[]> parameters() {
+    return buildParameters(
+        getTestParameters().withAllRuntimesAndApiLevels().build(), ImmutableList.of(1, 2, 3));
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(getClass())
+        .addKeepRules(
+            "-keep class " + Main.class.getTypeName() + " {",
+            "  public static void thread0();",
+            "  public static void thread" + thread + "();",
+            "}")
+        // TODO(b/205611444): HostA and HostB should be merged when thread is 1.
+        .addHorizontallyMergedClassesInspector(
+            HorizontallyMergedClassesInspector::assertNoClassesMerged)
+        .addOptionsModification(
+            options ->
+                options.horizontalClassMergerOptions().setEnableClassInitializerDeadlockDetection())
+        .enableInliningAnnotations()
+        .setMinApi(parameters.getApiLevel())
+        .compile();
+  }
+
+  static class Main {
+
+    // @Keep
+    public static void thread0() {
+      // Takes the lock for Host, then Companion, and then waits to take the lock for HostA.
+      System.out.println(Host.companion.a);
+      System.out.println(Host.companion.b);
+    }
+
+    // @Keep
+    public static void thread1() {
+      // Ditto. In this case there is no risk of a deadlock, since one of thread0 and thread1 will
+      // take the lock for Host and the other thread will then wait on the lock for Host to be
+      // released.
+      System.out.println(Host.companion.a);
+      System.out.println(Host.companion.b);
+    }
+
+    // @Keep
+    public static void thread2() {
+      // Takes the lock for Companion, then HostA, and then waits to take the lock for its
+      // superclass Host.
+      System.out.println(new Host.Companion());
+    }
+
+    // @Keep
+    public static void thread3() {
+      // Takes the lock for HostA, and then waits to take the lock for its superclass Host.
+      HostA.init();
+    }
+  }
+
+  static class Host {
+
+    static Companion companion = new Companion();
+
+    static class Companion {
+
+      Host a = new HostA();
+
+      Host b = new HostB();
+
+      static class HostA extends Host {
+
+        @NeverInline
+        static void init() {
+          System.out.println("HostA.init");
+        }
+      }
+
+      static class HostB extends Host {}
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/debug/DoNotCrashOnAccessToThisRunner.java b/src/test/java/com/android/tools/r8/debug/DoNotCrashOnAccessToThisRunner.java
index 2363533..53d4d26 100644
--- a/src/test/java/com/android/tools/r8/debug/DoNotCrashOnAccessToThisRunner.java
+++ b/src/test/java/com/android/tools/r8/debug/DoNotCrashOnAccessToThisRunner.java
@@ -38,7 +38,7 @@
                       // Api level M so that the workarounds for Lollipop verifier doesn't
                       // block the receiver register. We want to check b/116683601 which
                       // happens on at least 7.0.0.
-                      options.minApiLevel = AndroidApiLevel.M;
+                      options.setMinApiLevel(AndroidApiLevel.M);
                     });
     return ImmutableList.of(new Object[]{"CF", cf}, new Object[]{"D8", d8});
   }
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java b/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java
index 67db3d7..ea0f614 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java
@@ -79,17 +79,14 @@
         .assertOnlyWarnings()
         .assertWarningMessageThatMatches(containsString("is not supported by this compiler"))
         .run(parameters.getRuntime(), TestMathMultiplyExactLongInt.class)
-        .assertFailureWithErrorThatMatches(
-            containsString(
-                "java.lang.NoSuchMethodError: No static method"
-                    + " parseInt(Ljava/lang/CharSequence;III)I"));
+        .assertSuccessWithOutputLines("4");
   }
 
   @Test
   public void noWarningForPlatformBuild() throws Exception {
     testForD8()
         .addProgramClassFileData(transformTestMathMultiplyExactLongInt())
-        .setMinApi(AndroidApiLevel.magicApiLevelUsedByAndroidPlatformBuild)
+        .setMinApi(AndroidApiLevel.ANDROID_PLATFORM)
         .run(parameters.getRuntime(), TestMathMultiplyExactLongInt.class)
         .assertFailureWithErrorThatMatches(
             containsString(
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/TestBackportedNotPresentInAndroidJar.java b/src/test/java/com/android/tools/r8/desugar/backports/TestBackportedNotPresentInAndroidJar.java
index 5cfc6cd..bd338b6 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/TestBackportedNotPresentInAndroidJar.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/TestBackportedNotPresentInAndroidJar.java
@@ -39,7 +39,7 @@
       // android.jar for that level.
       CodeInspector inspector = new CodeInspector(ToolHelper.getAndroidJar(apiLevel));
       InternalOptions options = new InternalOptions();
-      options.minApiLevel = apiLevel;
+      options.setMinApiLevel(apiLevel);
       List<DexMethod> backportedMethods =
           BackportedMethodRewriter.generateListOfBackportedMethods(
               AndroidApp.builder().build(), options, ThreadUtils.getExecutorService(options));
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java
index 905529a..f84c38c 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java
@@ -126,7 +126,7 @@
             .parse(StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()));
 
     for (AndroidApiLevel apiLevel : AndroidApiLevel.values()) {
-      if (apiLevel == AndroidApiLevel.UNKNOWN || apiLevel == AndroidApiLevel.NOT_SET) {
+      if (apiLevel.isGreaterThan(AndroidApiLevel.LATEST)) {
         continue;
       }
       Path compileApiLevelDirectory = directory.resolve("compile_api_level_" + apiLevel.getLevel());
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/DurationJDK11Test.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/DurationJDK11Test.java
new file mode 100644
index 0000000..7f76531
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/DurationJDK11Test.java
@@ -0,0 +1,136 @@
+// 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.jdk11;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
+import com.android.tools.r8.transformers.MethodTransformer;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
+import java.io.IOException;
+import java.time.Duration;
+import java.util.Collection;
+import java.util.List;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.objectweb.asm.Opcodes;
+
+@RunWith(Parameterized.class)
+public class DurationJDK11Test extends DesugaredLibraryTestBase {
+
+  private static final String EXPECTED_RESULT = StringUtils.lines("7");
+
+  private final TestParameters parameters;
+  private final boolean shrinkDesugaredLibrary;
+
+  @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
+  }
+
+  public DurationJDK11Test(boolean shrinkDesugaredLibrary, TestParameters parameters) {
+    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testD8() throws Exception {
+    Assume.assumeTrue(isJDK11DesugaredLibrary());
+    Assume.assumeFalse(
+        "TODO(b/206068300)",
+        parameters.getApiLevel().getLevel() >= AndroidApiLevel.O.getLevel()
+            && parameters.getApiLevel().getLevel() < AndroidApiLevel.S.getLevel());
+    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
+    testForD8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+        .addProgramClassFileData(getProgramClassFileData())
+        .setMinApi(parameters.getApiLevel())
+        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+        .compile()
+        .addDesugaredCoreLibraryRunClassPath(
+            this::buildDesugaredLibrary,
+            parameters.getApiLevel(),
+            keepRuleConsumer.get(),
+            shrinkDesugaredLibrary)
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED_RESULT);
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    Assume.assumeTrue(isJDK11DesugaredLibrary());
+    Assume.assumeFalse(
+        "TODO(b/206068300)",
+        parameters.getApiLevel().getLevel() >= AndroidApiLevel.O.getLevel()
+            && parameters.getApiLevel().getLevel() < AndroidApiLevel.S.getLevel());
+    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
+    testForR8(Backend.DEX)
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+        .addProgramClassFileData(getProgramClassFileData())
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(TestClass.class)
+        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+        .compile()
+        .addDesugaredCoreLibraryRunClassPath(
+            this::buildDesugaredLibrary,
+            parameters.getApiLevel(),
+            keepRuleConsumer.get(),
+            shrinkDesugaredLibrary)
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED_RESULT);
+  }
+
+  private Collection<byte[]> getProgramClassFileData() throws IOException {
+    return ImmutableList.of(
+        transformer(TestClass.class)
+            .addMethodTransformer(
+                new MethodTransformer() {
+                  @Override
+                  public void visitMethodInsn(
+                      int opcode,
+                      String owner,
+                      String name,
+                      String descriptor,
+                      boolean isInterface) {
+                    if (opcode == Opcodes.INVOKESTATIC && name.equals("toHoursPart")) {
+                      super.visitMethodInsn(
+                          Opcodes.INVOKEVIRTUAL,
+                          "java/time/Duration",
+                          name,
+                          withoutFirstObjectArg(descriptor),
+                          isInterface);
+                      return;
+                    }
+                    super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+                  }
+                })
+            .transform());
+  }
+
+  private String withoutFirstObjectArg(String descriptor) {
+    int i = descriptor.indexOf(";");
+    return "(" + descriptor.substring(i + 1);
+  }
+
+  public static class TestClass {
+
+    public static void main(String[] args) {
+      Duration duration = Duration.ofHours(31);
+      System.out.println(toHoursPart(duration));
+    }
+
+    // Replaced in the transformer by JDK 11 Duration#toHoursPart.
+    private static int toHoursPart(Duration duration) {
+      return -1;
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/TrivialArrayCheckCastTest.java b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/TrivialArrayCheckCastTest.java
index b4d7969..c885a62 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/TrivialArrayCheckCastTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/TrivialArrayCheckCastTest.java
@@ -27,7 +27,7 @@
     testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expectedOutput);
 
     InternalOptions options = new InternalOptions();
-    options.minApiLevel = AndroidApiLevel.I_MR1;
+    options.setMinApiLevel(AndroidApiLevel.I_MR1);
     assert options.canHaveArtCheckCastVerifierBug();
 
     testForR8(Backend.DEX)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/ZipFileInstanceOfAutoCloseableTest.java b/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/ZipFileInstanceOfAutoCloseableTest.java
index 14d84e7..ea167e3 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/ZipFileInstanceOfAutoCloseableTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/ZipFileInstanceOfAutoCloseableTest.java
@@ -103,7 +103,7 @@
     assumeTrue(parameters.isDexRuntime());
     // Set the min API and create the raw app.
     InternalOptions options = new InternalOptions();
-    options.minApiLevel = parameters.getApiLevel();
+    options.setMinApiLevel(parameters.getApiLevel());
     DirectMappedDexApplication application =
         new ApplicationReader(
                 AndroidApp.builder()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/EscapeBeforeStaticPutTest.java b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/EscapeBeforeStaticPutTest.java
index cde325b..d8cf4f3 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/EscapeBeforeStaticPutTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/EscapeBeforeStaticPutTest.java
@@ -19,7 +19,7 @@
 
   @Parameterized.Parameters(name = "{0}")
   public static TestParametersCollection data() {
-    return getTestParameters().withAllRuntimes().build();
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   public EscapeBeforeStaticPutTest(TestParameters parameters) {
@@ -32,7 +32,7 @@
         .addInnerClasses(EscapeBeforeStaticPutTest.class)
         .addKeepMainRule(TestClass.class)
         .enableInliningAnnotations()
-        .setMinApi(parameters.getRuntime())
+        .setMinApi(parameters.getApiLevel())
         .compile()
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutputLines("Hello world!");
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/RedundantStaticFieldStoreBeforeStoreTest.java b/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/RedundantStaticFieldStoreBeforeStoreTest.java
new file mode 100644
index 0000000..d885356
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/RedundantStaticFieldStoreBeforeStoreTest.java
@@ -0,0 +1,74 @@
+// 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.redundantfieldloadelimination;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+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 RedundantStaticFieldStoreBeforeStoreTest 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)
+        .enableInliningAnnotations()
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .inspect(
+            inspector -> {
+              ClassSubject mainClassSubject = inspector.clazz(Main.class);
+              MethodSubject mainMethodSubject = mainClassSubject.mainMethod();
+              assertThat(mainMethodSubject, isPresent());
+              assertEquals(
+                  1,
+                  mainMethodSubject
+                      .streamInstructions()
+                      .filter(InstructionSubject::isStaticPut)
+                      .count());
+            })
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines("2");
+  }
+
+  static class Main {
+
+    static int f;
+
+    public static void main(String[] args) {
+      f = 1;
+      f = 2;
+      print();
+    }
+
+    @NeverInline
+    private static void print() {
+      System.out.println(f);
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/jasmin/MemberResolutionTest.java b/src/test/java/com/android/tools/r8/jasmin/MemberResolutionTest.java
index fd893ea..5db275b 100644
--- a/src/test/java/com/android/tools/r8/jasmin/MemberResolutionTest.java
+++ b/src/test/java/com/android/tools/r8/jasmin/MemberResolutionTest.java
@@ -124,7 +124,7 @@
 
     ClassBuilder superClass = builder.addClass("SuperClass");
     superClass.addDefaultConstructor();
-    superClass.addStaticFinalField("aField", "I", "42");
+    superClass.addStaticField("aField", "I", "42");
 
     ClassBuilder subClass = builder.addClass("SubClass", "SuperClass");
     subClass.addDefaultConstructor();
diff --git a/src/test/java/com/android/tools/r8/jasmin/NameTestBase.java b/src/test/java/com/android/tools/r8/jasmin/NameTestBase.java
index f0d186f..594bdbe 100644
--- a/src/test/java/com/android/tools/r8/jasmin/NameTestBase.java
+++ b/src/test/java/com/android/tools/r8/jasmin/NameTestBase.java
@@ -113,13 +113,15 @@
           runOnArtD8(
               jasminBuilder,
               mainClassName,
-              o -> o.minApiLevel = ToolHelper.getMinApiLevelForDexVm());
+              o -> o.setMinApiLevel(ToolHelper.getMinApiLevelForDexVm()));
       assertEquals(expectedResult, artResult);
     } else {
       // Make sure the compiler fails.
       try {
         runOnArtD8(
-            jasminBuilder, mainClassName, o -> o.minApiLevel = ToolHelper.getMinApiLevelForDexVm());
+            jasminBuilder,
+            mainClassName,
+            o -> o.setMinApiLevel(ToolHelper.getMinApiLevelForDexVm()));
         fail("D8 should have rejected this case.");
       } catch (CompilationFailedException t) {
         assertTrue(t.getCause().getMessage().contains(expectedNameInFailingD8Message));
@@ -132,7 +134,7 @@
             mainClassName,
             options -> {
               options.itemFactory.setSkipNameValidationForTesting(true);
-              options.minApiLevel = ToolHelper.getMinApiLevelForDexVm();
+              options.setMinApiLevel(ToolHelper.getMinApiLevelForDexVm());
             });
         fail("Art should have failed.");
       } catch (AssertionError e) {
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
index 441b85f..9347e50 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -814,7 +814,7 @@
     Timing timing = Timing.empty();
     InternalOptions options =
         new InternalOptions(new DexItemFactory(), new Reporter(diagnosticsHandler));
-    options.minApiLevel = AndroidApiLevel.getAndroidApiLevel(minApi);
+    options.setMinApiLevel(AndroidApiLevel.getAndroidApiLevel(minApi));
     options.intermediate = intermediate;
     DexItemFactory factory = options.itemFactory;
     AppView<?> appView = AppView.createForR8(DexApplication.builder(options, timing).build());
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/sourcelibrary/MemberResolutionTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/sourcelibrary/MemberResolutionTest.java
index 7ed73c6..1a7919f 100644
--- a/src/test/java/com/android/tools/r8/naming/applymapping/sourcelibrary/MemberResolutionTest.java
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/sourcelibrary/MemberResolutionTest.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.naming.applymapping.sourcelibrary;
 
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -142,8 +143,7 @@
     ClassSubject sub = inspector.clazz(ConcreteChecker.class);
     assertThat(sub, isPresent());
     FieldSubject q = sub.field("java.lang.String", "tag");
-    assertThat(q, isPresentAndRenamed());
-    assertEquals("q", q.getFinalName());
+    assertThat(q, isAbsent());
     MethodSubject y = sub.method("void", "check", ImmutableList.of());
     assertThat(y, isPresentAndRenamed());
     assertEquals("y", y.getFinalName());
diff --git a/src/test/java/com/android/tools/r8/regress/b69906048/Regress69906048Test.java b/src/test/java/com/android/tools/r8/regress/b69906048/Regress69906048Test.java
index bb1fed9..aeb2ba4 100644
--- a/src/test/java/com/android/tools/r8/regress/b69906048/Regress69906048Test.java
+++ b/src/test/java/com/android/tools/r8/regress/b69906048/Regress69906048Test.java
@@ -24,7 +24,7 @@
                 .addProguardConfiguration(
                     ImmutableList.of("-keepattributes *Annotation*"), Origin.unknown())
                 .build(),
-            options -> options.minApiLevel = ToolHelper.getMinApiLevelForDexVm());
+            options -> options.setMinApiLevel(ToolHelper.getMinApiLevelForDexVm()));
     String result = runOnArt(androidApp, ClassWithAnnotations.class);
     Assert.assertEquals("@" + AnAnnotation.class.getCanonicalName() + "()", result);
   }
diff --git a/src/test/java/com/android/tools/r8/regress/b77496850/B77496850.java b/src/test/java/com/android/tools/r8/regress/b77496850/B77496850.java
index 03efc25..7fb7e88 100644
--- a/src/test/java/com/android/tools/r8/regress/b77496850/B77496850.java
+++ b/src/test/java/com/android/tools/r8/regress/b77496850/B77496850.java
@@ -456,10 +456,10 @@
       throws Exception {
     AndroidApp app = readClasses(Path.class, Log.class, testClass);
     if (compiler == Tool.D8) {
-      app = compileWithD8(app, o -> o.minApiLevel = apiLevel);
+      app = compileWithD8(app, o -> o.setMinApiLevel(apiLevel));
     } else {
       assert compiler == Tool.R8;
-      app = compileWithR8(app, "-keep class * { *; }", o -> o.minApiLevel = apiLevel);
+      app = compileWithR8(app, "-keep class * { *; }", o -> o.setMinApiLevel(apiLevel));
     }
     checkPathParserMethods(app, testClass, a, b);
   }
@@ -479,10 +479,10 @@
       throws Exception {
     AndroidApp app = readClasses(testClass);
     if (compiler == Tool.D8) {
-      app = compileWithD8(app, o -> o.minApiLevel = apiLevel);
+      app = compileWithD8(app, o -> o.setMinApiLevel(apiLevel));
     } else {
       assert compiler == Tool.R8;
-      app = compileWithR8(app, "-keep class * { *; }", o -> o.minApiLevel = apiLevel);
+      app = compileWithR8(app, "-keep class * { *; }", o -> o.setMinApiLevel(apiLevel));
     }
     CodeInspector inspector = new CodeInspector(app);
     DexItemFactory factory = inspector.getFactory();
diff --git a/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalInstanceFieldsTest.java b/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalInstanceFieldsTest.java
index d408a4f..d19d8b8 100644
--- a/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalInstanceFieldsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalInstanceFieldsTest.java
@@ -74,8 +74,7 @@
                   mainMethod
                       .streamInstructions()
                       .noneMatch(i -> i.isConstString("Dead code: 2", JumboStringMode.ALLOW)));
-              // TODO(b/138913138): not trivial; assigned only once in <init>
-              assertFalse(
+              assertTrue(
                   mainMethod
                       .streamInstructions()
                       .noneMatch(i -> i.isConstString("Dead code: 3", JumboStringMode.ALLOW)));
diff --git a/src/test/java/com/android/tools/r8/utils/Smali.java b/src/test/java/com/android/tools/r8/utils/Smali.java
index d698e0b..84099dc 100644
--- a/src/test/java/com/android/tools/r8/utils/Smali.java
+++ b/src/test/java/com/android/tools/r8/utils/Smali.java
@@ -108,7 +108,7 @@
     SingleFileConsumer consumer = new SingleFileConsumer();
     AndroidApp app = AndroidApp.builder().addDexProgramData(data, Origin.unknown()).build();
     InternalOptions options = new InternalOptions();
-    options.minApiLevel = AndroidApiLevel.getAndroidApiLevel(apiLevel);
+    options.setMinApiLevel(AndroidApiLevel.getAndroidApiLevel(apiLevel));
     options.programConsumer = consumer;
     ExecutorService executor = ThreadUtils.getExecutorService(1);
     try {
diff --git a/tools/run_on_app_dump.py b/tools/run_on_app_dump.py
index 88c758d..f71a314 100755
--- a/tools/run_on_app_dump.py
+++ b/tools/run_on_app_dump.py
@@ -1107,7 +1107,7 @@
           quiet=options.quiet)
     elif options.version == 'main':
       if not (options.no_build or options.golem):
-        gradle.RunGradle(['r8', '-Pno_internal'])
+        gradle.RunGradle(['R8Retrace', 'r8', '-Pno_internal'])
         build_r8lib = False
         for shrinker in options.shrinker:
           if is_minified_r8(shrinker):