Merge commit '1d37738b84cf0c6ad30d3d746ae8426b5a506cc8' into dev-release
diff --git a/src/library_desugar/jdk11/chm_only_desugar_jdk_libs.json b/src/library_desugar/jdk11/chm_only_desugar_jdk_libs.json
index f3a4daa..565ffd9 100644
--- a/src/library_desugar/jdk11/chm_only_desugar_jdk_libs.json
+++ b/src/library_desugar/jdk11/chm_only_desugar_jdk_libs.json
@@ -3,7 +3,7 @@
   "group_id" : "com.tools.android",
   "artifact_id" : "chm_only_desugar_jdk_libs",
   "version": "1.0.12",
-  "required_compilation_api_level": 30,
+  "required_compilation_api_level": 31,
   "synthesized_library_classes_package_prefix": "j$.",
   "support_all_callbacks_from_library": false,
   "common_flags": [
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs.json b/src/library_desugar/jdk11/desugar_jdk_libs.json
index b075745..fb03dbb 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs.json
@@ -3,7 +3,7 @@
   "group_id" : "com.tools.android",
   "artifact_id" : "desugar_jdk_libs",
   "version": "2.0.0",
-  "required_compilation_api_level": 30,
+  "required_compilation_api_level": 31,
   "synthesized_library_classes_package_prefix": "j$.",
   "support_all_callbacks_from_library": true,
   "common_flags": [
@@ -205,7 +205,7 @@
         "java.nio.charset.StandardCharsets": "j$.nio.charset.StandardCharsets"
       },
       "retarget_lib_member": {
-        "java.lang.Character#isBmpCodePoint": "java.lang.DesugarCharacter"
+        "java.lang.Character#isBmpCodePoint": "j$.lang.DesugarCharacter"
       }
     }
   ],
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json b/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json
index 1482909..fac2ec0 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json
@@ -3,7 +3,7 @@
   "group_id" : "com.tools.android",
   "artifact_id" : "desugar_jdk_libs_alternative_3",
   "version": "2.0.0",
-  "required_compilation_api_level": 30,
+  "required_compilation_api_level": 31,
   "synthesized_library_classes_package_prefix": "j$.",
   "support_all_callbacks_from_library": false,
   "common_flags": [
@@ -209,7 +209,7 @@
         "java.nio.charset.StandardCharsets": "j$.nio.charset.StandardCharsets"
       },
       "retarget_lib_member": {
-        "java.lang.Character#isBmpCodePoint": "java.lang.DesugarCharacter"
+        "java.lang.Character#isBmpCodePoint": "j$.lang.DesugarCharacter"
       }
     }
   ],
diff --git a/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java b/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java
index 7ef1569..bce73f0 100644
--- a/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java
+++ b/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java
@@ -105,7 +105,7 @@
   InternalOptions getInternalOptions() {
     InternalOptions options = new InternalOptions(factory, getReporter());
     options.setMinApiLevel(AndroidApiLevel.getAndroidApiLevel(minApiLevel));
-    options.setDesugaredLibrarySpecification(desugaredLibrarySpecification, getInputApp());
+    options.desugaredLibrarySpecification = desugaredLibrarySpecification;
     return options;
   }
 
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index 0967f55..8dd34a8 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -498,7 +498,8 @@
     internal.encodeChecksums = getIncludeClassesChecksum();
     internal.dexClassChecksumFilter = getDexClassChecksumFilter();
     internal.enableInheritanceClassInDexDistributor = isOptimizeMultidexForLinearAlloc();
-    internal.setDesugaredLibrarySpecification(desugaredLibrarySpecification, getInputApp());
+
+    internal.desugaredLibrarySpecification = desugaredLibrarySpecification;
     internal.synthesizedClassPrefix = synthesizedClassPrefix;
     internal.desugaredLibraryKeepRuleConsumer = desugaredLibraryKeepRuleConsumer;
 
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index 6da92e2..26c99ce 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -194,7 +194,7 @@
     internal.enableInheritanceClassInDexDistributor = false;
 
     assert desugaredLibrarySpecification != null;
-    internal.setDesugaredLibrarySpecification(desugaredLibrarySpecification, getInputApp());
+    internal.desugaredLibrarySpecification = desugaredLibrarySpecification;
     internal.synthesizedClassPrefix =
         desugaredLibrarySpecification.getSynthesizedLibraryClassesPackagePrefix();
 
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 85c05f6..194c531 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -311,7 +311,7 @@
       if (!options.mainDexKeepRules.isEmpty()) {
         MainDexListBuilder.checkForAssumedLibraryTypes(appView.appInfo());
       }
-      if (options.machineDesugaredLibrarySpecification.hasRetargeting()) {
+      if (!options.desugaredLibrarySpecification.getRetargetCoreLibMember().isEmpty()) {
         DesugaredLibraryRetargeterLibraryTypeSynthesizer.checkForAssumedLibraryTypes(appView);
         DesugaredLibraryRetargeterLibraryTypeSynthesizer.amendLibraryWithRetargetedMembers(appView);
       }
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 5bc9ddd..bf04680 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -943,7 +943,7 @@
 
     internal.enableInheritanceClassInDexDistributor = isOptimizeMultidexForLinearAlloc();
 
-    internal.setDesugaredLibrarySpecification(desugaredLibrarySpecification, getInputApp());
+    internal.desugaredLibrarySpecification = desugaredLibrarySpecification;
     internal.synthesizedClassPrefix = synthesizedClassPrefix;
     internal.desugaredLibraryKeepRuleConsumer = desugaredLibraryKeepRuleConsumer;
 
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 cce0852..2e2aa7a 100644
--- a/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java
+++ b/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java
@@ -9,6 +9,7 @@
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.ConsumerUtils;
 import com.google.common.collect.ImmutableList;
@@ -17,6 +18,7 @@
 
 public class AndroidApiReferenceLevelCache {
 
+  private final LegacyDesugaredLibrarySpecification desugaredLibrarySpecification;
   private final AndroidApiLevelCompute apiLevelCompute;
   private final AndroidApiLevelDatabase androidApiLevelDatabase;
   private final AppView<?> appView;
@@ -31,6 +33,7 @@
     factory = appView.dexItemFactory();
     androidApiLevelDatabase =
         new AndroidApiLevelHashingDatabaseImpl(predefinedApiTypeLookupForHashing);
+    desugaredLibrarySpecification = appView.options().desugaredLibrarySpecification;
   }
 
   public static AndroidApiReferenceLevelCache create(
@@ -72,7 +75,7 @@
     if (reference.getContextType() == factory.objectType) {
       return appView.computedMinApiLevel();
     }
-    if (appView.options().machineDesugaredLibrarySpecification.isSupported(reference)) {
+    if (desugaredLibrarySpecification.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.computedMinApiLevel();
diff --git a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
index ef86f73..f9b13a4 100644
--- a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
+++ b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
@@ -19,6 +19,7 @@
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.ThrowExceptionCode;
 import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.synthesis.CommittedItems;
 import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
@@ -111,10 +112,12 @@
       new ConcurrentHashMap<>();
   private final Set<DexType> seenTypes = Sets.newConcurrentHashSet();
   private final AndroidApiLevelCompute apiLevelCompute;
+  private final LegacyDesugaredLibrarySpecification desugaredLibraryConfiguration;
 
   public ApiReferenceStubber(AppView<? extends AppInfoWithClassHierarchy> appView) {
     this.appView = appView;
     apiLevelCompute = appView.apiLevelCompute();
+    desugaredLibraryConfiguration = appView.options().desugaredLibrarySpecification;
   }
 
   public void run(ExecutorService executorService) throws ExecutionException {
@@ -217,10 +220,7 @@
         || libraryClass.getType().toDescriptorString().startsWith("Ljava/")) {
       return;
     }
-    if (appView
-        .options()
-        .machineDesugaredLibrarySpecification
-        .isSupported(libraryClass.getType())) {
+    if (desugaredLibraryConfiguration.isSupported(libraryClass.getType(), appView)) {
       return;
     }
     appView
diff --git a/src/main/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryKeepRuleGenerator.java b/src/main/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryKeepRuleGenerator.java
index eaec5a0..a720021 100644
--- a/src/main/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryKeepRuleGenerator.java
+++ b/src/main/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryKeepRuleGenerator.java
@@ -13,7 +13,7 @@
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.references.ArrayReference;
 import com.android.tools.r8.references.ClassReference;
@@ -32,11 +32,13 @@
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.NopDiagnosticsHandler;
+import com.android.tools.r8.utils.SetUtils;
 import com.android.tools.r8.utils.Timing;
 import com.android.tools.r8.utils.TypeReferenceUtils;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Predicate;
 
@@ -69,7 +71,7 @@
       return false;
     }
     return namingLens.hasPrefixRewritingLogic()
-        || options.machineDesugaredLibrarySpecification.hasEmulatedInterfaces();
+        || options.desugaredLibrarySpecification.hasEmulatedLibraryInterfaces();
   }
 
   private void run() {
@@ -78,15 +80,18 @@
   }
 
   private Predicate<DexType> createTargetPredicate() {
-    MachineDesugaredLibrarySpecification desugaredLibrarySpecification =
-        options.machineDesugaredLibrarySpecification;
+    LegacyDesugaredLibrarySpecification desugaredLibrarySpecification =
+        options.desugaredLibrarySpecification;
+    Set<DexType> potentialTypesToKeep =
+        SetUtils.newIdentityHashSet(
+            desugaredLibrarySpecification.getCustomConversions().values(),
+            desugaredLibrarySpecification.getEmulateLibraryInterface().values());
     byte[] synthesizedLibraryClassesPackageDescriptorPrefix =
         DexString.encodeToMutf8(
             "L" + desugaredLibrarySpecification.getSynthesizedLibraryClassesPackagePrefix());
     return type ->
         namingLens.prefixRewrittenType(type) != null
-            || desugaredLibrarySpecification.isEmulatedInterfaceRewrittenType(type)
-            || desugaredLibrarySpecification.isCustomConversionRewrittenType(type)
+            || potentialTypesToKeep.contains(type)
             || type.getDescriptor().startsWith(synthesizedLibraryClassesPackageDescriptorPrefix);
   }
 
diff --git a/src/main/java/com/android/tools/r8/dex/CodeToKeep.java b/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
index 3e33ca8..cc05c31 100644
--- a/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
+++ b/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
@@ -25,7 +25,7 @@
 
   static CodeToKeep createCodeToKeep(InternalOptions options, NamingLens namingLens) {
     if ((!namingLens.hasPrefixRewritingLogic()
-            && !options.machineDesugaredLibrarySpecification.hasEmulatedInterfaces())
+            && !options.desugaredLibrarySpecification.hasEmulatedLibraryInterfaces())
         || options.isDesugaredLibraryCompilation()
         || options.testing.enableExperimentalDesugaredLibraryKeepRuleGenerator) {
       return new NopCodeToKeep();
@@ -57,23 +57,27 @@
     }
 
     private final NamingLens namingLens;
+    private final Set<DexType> potentialTypesToKeep = Sets.newIdentityHashSet();
     private final Map<DexType, KeepStruct> toKeep = new ConcurrentHashMap<>();
     private final InternalOptions options;
 
     public DesugaredLibraryCodeToKeep(NamingLens namingLens, InternalOptions options) {
       this.namingLens = namingLens;
       this.options = options;
+      potentialTypesToKeep.addAll(
+          options.desugaredLibrarySpecification.getEmulateLibraryInterface().values());
+      potentialTypesToKeep.addAll(
+          options.desugaredLibrarySpecification.getCustomConversions().values());
     }
 
     private boolean shouldKeep(DexType type) {
       return namingLens.prefixRewrittenType(type) != null
-          || options.machineDesugaredLibrarySpecification.isCustomConversionRewrittenType(type)
-          || options.machineDesugaredLibrarySpecification.isEmulatedInterfaceRewrittenType(type)
+          || potentialTypesToKeep.contains(type)
           // TODO(b/158632510): This should prefix match on DexString.
           || type.toDescriptorString()
               .startsWith(
                   "L"
-                      + options.machineDesugaredLibrarySpecification
+                      + options.desugaredLibrarySpecification
                           .getSynthesizedLibraryClassesPackagePrefix());
     }
 
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 11d7e80..f99e380 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
@@ -128,16 +128,24 @@
     DexMethod original = appView.graphLens().getOriginalMethodSignature(method);
     assert original != null;
     MethodProvider provider = rewritableMethods.getProvider(original);
-    // Old versions of desugared library have in the jar file pre-desugared code. This is used
-    // to undesugar pre-desugared code, then the code is re-desugared with D8/R8. This is
-    // maintained for legacy only, recent desugared library should not be shipped with
-    // pre-desugared code.
-    Map<DexType, DexType> legacyBackport =
-        appView.options().machineDesugaredLibrarySpecification.getLegacyBackport();
+    // TODO(b/150693139): Since the DesugarLibraryRetargeter is run during IR processing while the
+    // backported method rewriter is run in cf to cf, we need here to compute if the method is
+    // actually going to be retargeted through desugared library backports, and compute the
+    // corresponding backported method if so. This can be removed once the DesugarLibraryRetargeter
+    // has been moved as a cf to cf transformation.
     if (provider == null
         && appView.options().isDesugaredLibraryCompilation()
-        && legacyBackport.containsKey(method.holder)) {
-      DexType newHolder = legacyBackport.get(method.holder);
+        && appView
+            .options()
+            .desugaredLibrarySpecification
+            .getBackportCoreLibraryMember()
+            .containsKey(method.holder)) {
+      DexType newHolder =
+          appView
+              .options()
+              .desugaredLibrarySpecification
+              .getBackportCoreLibraryMember()
+              .get(method.holder);
       DexMethod backportedMethod =
           appView.dexItemFactory().createMethod(newHolder, method.proto, method.name);
       provider = rewritableMethods.getProvider(backportedMethod);
@@ -1437,7 +1445,7 @@
     }
 
     private void addProvider(MethodProvider generator) {
-      if (appView.options().machineDesugaredLibrarySpecification.isSupported(generator.method)) {
+      if (appView.options().desugaredLibrarySpecification.isSupported(generator.method, appView)) {
         // TODO(b/174453232): Remove this after the configuration file format has bee updated
         // with the "rewrite_method" section.
         if (generator.method.getHolderType() == appView.dexItemFactory().objectsType) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java
index 1243435..1fd0ad0 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java
@@ -57,7 +57,7 @@
         InterfaceMethodProcessorFacade interfaceMethodProcessorFacade,
         RetargetingInfo retargetingInfo) {
       ArrayList<CfPostProcessingDesugaring> desugarings = new ArrayList<>();
-      if (appView.options().machineDesugaredLibrarySpecification.hasRetargeting()
+      if (!appView.options().desugaredLibrarySpecification.getRetargetCoreLibMember().isEmpty()
           && !appView.options().isDesugaredLibraryCompilation()) {
         desugarings.add(new DesugaredLibraryRetargeterPostProcessor(appView, retargetingInfo));
       }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
index e55c246..33c69ac 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
@@ -82,9 +82,9 @@
     this.nestBasedAccessDesugaring = NestBasedAccessDesugaring.create(appView);
     BackportedMethodRewriter backportedMethodRewriter = null;
     desugaredLibraryRetargeter =
-        appView.options().machineDesugaredLibrarySpecification.hasRetargeting()
-            ? new DesugaredLibraryRetargeter(appView)
-            : null;
+        appView.options().desugaredLibrarySpecification.getRetargetCoreLibMember().isEmpty()
+            ? null
+            : new DesugaredLibraryRetargeter(appView);
     if (desugaredLibraryRetargeter != null) {
       desugarings.add(desugaredLibraryRetargeter);
     }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/PrefixRewritingMapper.java b/src/main/java/com/android/tools/r8/ir/desugar/PrefixRewritingMapper.java
index 90f2505..bf96b67 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/PrefixRewritingMapper.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/PrefixRewritingMapper.java
@@ -4,11 +4,20 @@
 
 package com.android.tools.r8.ir.desugar;
 
+import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProto;
+import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineRewritingFlags;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Sets;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Consumer;
 
@@ -22,7 +31,7 @@
 
   public abstract DexType rewrittenType(DexType type, AppView<?> appView);
 
-  public abstract DexType rewrittenContextType(DexType type);
+  public abstract DexType rewrittenContextType(DexType type, AppView<?> appView);
 
   public boolean hasRewrittenType(DexType type, AppView<?> appView) {
     return rewrittenType(type, appView) != null;
@@ -44,34 +53,195 @@
 
   public abstract void forAllRewrittenTypes(Consumer<DexType> consumer);
 
-  public static class MachineDesugarPrefixRewritingMapper extends PrefixRewritingMapper {
+  public static class DesugarPrefixRewritingMapper extends PrefixRewritingMapper {
 
-    private final Map<DexType, DexType> rewriteType;
-    private final Map<DexType, DexType> rewriteDerivedTypeOnly;
+    private final Set<DexType> notRewritten = Sets.newConcurrentHashSet();
+    private final Map<DexType, DexType> rewritten = new ConcurrentHashMap<>();
+    private final Map<DexString, DexString> initialPrefixes;
+    private final DexItemFactory factory;
+    private final boolean l8Compilation;
 
-    public MachineDesugarPrefixRewritingMapper(MachineDesugaredLibrarySpecification specification) {
-      this.rewriteType = new ConcurrentHashMap<>(specification.getRewriteType());
-      rewriteDerivedTypeOnly = specification.getRewriteDerivedTypeOnly();
+    public DesugarPrefixRewritingMapper(
+        Map<String, String> prefixes, DexItemFactory itemFactory, boolean libraryCompilation) {
+      assert itemFactory != null || prefixes.isEmpty();
+      this.factory = itemFactory;
+      this.l8Compilation = libraryCompilation;
+      ImmutableMap.Builder<DexString, DexString> builder = ImmutableMap.builder();
+      for (String key : prefixes.keySet()) {
+        builder.put(toDescriptorPrefix(key), toDescriptorPrefix(prefixes.get(key)));
+      }
+      this.initialPrefixes = builder.build();
+      validatePrefixes(prefixes);
+    }
+
+    private DexString toDescriptorPrefix(String prefix) {
+      return factory.createString("L" + DescriptorUtils.getBinaryNameFromJavaType(prefix));
+    }
+
+    @Override
+    public void forAllRewrittenTypes(Consumer<DexType> consumer) {
+      rewritten.keySet().forEach(consumer);
+    }
+
+    private void validatePrefixes(Map<String, String> initialPrefixes) {
+      String[] prefixes = initialPrefixes.keySet().toArray(new String[0]);
+      for (int i = 0; i < prefixes.length; i++) {
+        for (int j = i + 1; j < prefixes.length; j++) {
+          String small, large;
+          if (prefixes[i].length() < prefixes[j].length()) {
+            small = prefixes[i];
+            large = prefixes[j];
+          } else {
+            small = prefixes[j];
+            large = prefixes[i];
+          }
+          if (large.startsWith(small)) {
+            throw new CompilationError(
+                "Inconsistent prefix in desugared library:"
+                    + " Should a class starting with "
+                    + small
+                    + " be rewritten using "
+                    + small
+                    + " -> "
+                    + initialPrefixes.get(small)
+                    + " or using "
+                    + large
+                    + " - > "
+                    + initialPrefixes.get(large)
+                    + " ?");
+          }
+        }
+      }
     }
 
     @Override
     public DexType rewrittenType(DexType type, AppView<?> appView) {
-      if (type.isArrayType()) {
-        DexType rewrittenBaseType =
-            rewrittenType(type.toBaseType(appView.dexItemFactory()), appView);
-        if (rewrittenBaseType == null) {
-          return null;
-        }
-        return appView
-            .dexItemFactory()
-            .createArrayType(type.getNumberOfLeadingSquareBrackets(), rewrittenBaseType);
+      assert appView != null || l8Compilation;
+      if (notRewritten.contains(type)) {
+        return null;
       }
+      if (rewritten.containsKey(type)) {
+        return rewritten.get(type);
+      }
+      return computePrefix(type, appView);
+    }
+
+    @Override
+    public DexType rewrittenContextType(DexType type, AppView<?> appView) {
+      DexType rewritten = rewrittenType(type, appView);
+      if (rewritten != null) {
+        return rewritten;
+      }
+      LegacyDesugaredLibrarySpecification desugaredLibrarySpecification =
+          appView.options().desugaredLibrarySpecification;
+      if (desugaredLibrarySpecification.getEmulateLibraryInterface().containsKey(type)) {
+        return desugaredLibrarySpecification.getEmulateLibraryInterface().get(type);
+      }
+      for (Map<DexType, DexType> value :
+          desugaredLibrarySpecification.getRetargetCoreLibMember().values()) {
+        if (value.containsKey(type)) {
+          // Hack until machine specification are ready.
+          String prefix =
+              DescriptorUtils.getJavaTypeFromBinaryName(
+                  desugaredLibrarySpecification.getSynthesizedLibraryClassesPackagePrefix());
+          String interfaceType = type.toString();
+          int firstPackage = interfaceType.indexOf('.');
+          return appView
+              .dexItemFactory()
+              .createType(
+                  DescriptorUtils.javaTypeToDescriptor(
+                      prefix + interfaceType.substring(firstPackage + 1)));
+        }
+      }
+      return null;
+    }
+
+    // Besides L8 compilation, program types should not be rewritten.
+    private void failIfRewritingProgramType(DexType type, AppView<?> appView) {
+      if (l8Compilation) {
+        return;
+      }
+
+      DexType dexType = type.isArrayType() ? type.toBaseType(appView.dexItemFactory()) : type;
+      DexClass dexClass = appView.definitionFor(dexType);
+      if (dexClass != null && dexClass.isProgramClass()) {
+        appView
+            .options()
+            .reporter
+            .error(
+                "Cannot compile program class "
+                    + dexType
+                    + " since it conflicts with a desugared library rewriting rule.");
+      }
+    }
+
+    @Override
+    public void rewriteType(DexType type, DexType rewrittenType) {
+      assert !notRewritten.contains(type)
+          : "New rewriting rule for "
+              + type
+              + " but the compiler has already made decisions based on the fact that this type was"
+              + " not rewritten";
+      assert !rewritten.containsKey(type) || rewritten.get(type) == rewrittenType
+          : "New rewriting rule for "
+              + type
+              + " but the compiler has already made decisions based on a different rewriting rule"
+              + " for this type";
+      rewritten.put(type, rewrittenType);
+    }
+
+    private DexType computePrefix(DexType type, AppView<?> appView) {
+      DexString prefixToMatch = type.descriptor.withoutArray(factory);
+      DexType result = lookup(type, prefixToMatch, initialPrefixes);
+      if (result != null) {
+        failIfRewritingProgramType(type, appView);
+        return result;
+      }
+      notRewritten.add(type);
+      return null;
+    }
+
+    private DexType lookup(DexType type, DexString prefixToMatch, Map<DexString, DexString> map) {
+      // TODO(b/154800164): We could use tries instead of looking-up everywhere.
+      for (DexString prefix : map.keySet()) {
+        if (prefixToMatch.startsWith(prefix)) {
+          DexString rewrittenTypeDescriptor =
+              type.descriptor.withNewPrefix(prefix, map.get(prefix), factory);
+          DexType rewrittenType = factory.createType(rewrittenTypeDescriptor);
+          rewriteType(type, rewrittenType);
+          return rewrittenType;
+        }
+      }
+      return null;
+    }
+
+    @Override
+    public boolean isRewriting() {
+      return true;
+    }
+  }
+
+  public static class MachineDesugarPrefixRewritingMapper extends PrefixRewritingMapper {
+
+    private final PrefixRewritingMapper mapper;
+    private final Map<DexType, DexType> rewriteType;
+    private final Map<DexType, DexType> rewriteDerivedTypeOnly;
+
+    public MachineDesugarPrefixRewritingMapper(
+        PrefixRewritingMapper mapper, MachineRewritingFlags flags) {
+      this.mapper = mapper;
+      this.rewriteType = new ConcurrentHashMap<>(flags.getRewriteType());
+      rewriteDerivedTypeOnly = flags.getRewriteDerivedTypeOnly();
+    }
+
+    @Override
+    public DexType rewrittenType(DexType type, AppView<?> appView) {
+      assert mapper.rewrittenType(type, appView) == rewriteType.get(type);
       return rewriteType.get(type);
     }
 
     @Override
-    public DexType rewrittenContextType(DexType context) {
-      assert !context.isArrayType();
+    public DexType rewrittenContextType(DexType context, AppView<?> appView) {
       if (rewriteType.containsKey(context)) {
         return rewriteType.get(context);
       }
@@ -80,6 +250,7 @@
 
     @Override
     public void rewriteType(DexType type, DexType rewrittenType) {
+      mapper.rewriteType(type, rewrittenType);
       rewriteType.compute(
           type,
           (t, val) -> {
@@ -107,7 +278,7 @@
     }
 
     @Override
-    public DexType rewrittenContextType(DexType type) {
+    public DexType rewrittenContextType(DexType type, AppView<?> appView) {
       return null;
     }
 
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPICallbackSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPICallbackSynthesizer.java
index b66a96a..150e6c4 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPICallbackSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPICallbackSynthesizer.java
@@ -20,13 +20,13 @@
 import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaring;
 import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryAPICallbackSynthesizorEventConsumer;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
 import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APICallbackWrapperCfCodeProvider;
 import com.android.tools.r8.utils.OptionalBool;
 import com.android.tools.r8.utils.WorkList;
 import com.google.common.collect.Sets;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ExecutorService;
 
@@ -109,8 +109,8 @@
     if (!appView.rewritePrefix.hasRewrittenTypeInSignature(definition.getProto(), appView)
         || appView
             .options()
-            .machineDesugaredLibrarySpecification
-            .getEmulatedInterfaces()
+            .desugaredLibrarySpecification
+            .getEmulateLibraryInterface()
             .containsKey(method.getHolderType())) {
       return false;
     }
@@ -127,7 +127,7 @@
         return false;
       }
     }
-    if (!appView.options().machineDesugaredLibrarySpecification.supportAllCallbacksFromLibrary()
+    if (!appView.options().desugaredLibrarySpecification.supportAllCallbacksFromLibrary()
         && appView.options().isDesugaredLibraryCompilation()) {
       return false;
     }
@@ -178,13 +178,13 @@
   }
 
   private boolean shouldGenerateCallbacksForEmulateInterfaceAPIs(DexClass dexClass) {
-    if (appView.options().machineDesugaredLibrarySpecification.supportAllCallbacksFromLibrary()) {
+    if (appView.options().desugaredLibrarySpecification.supportAllCallbacksFromLibrary()) {
       return true;
     }
-    MachineDesugaredLibrarySpecification specification =
-        appView.options().machineDesugaredLibrarySpecification;
-    return !(specification.getEmulatedInterfaces().containsKey(dexClass.type)
-        || specification.isEmulatedInterfaceRewrittenType(dexClass.type));
+    Map<DexType, DexType> emulateLibraryInterfaces =
+        appView.options().desugaredLibrarySpecification.getEmulateLibraryInterface();
+    return !(emulateLibraryInterfaces.containsKey(dexClass.type)
+        || emulateLibraryInterfaces.containsValue(dexClass.type));
   }
 
   private ProgramMethod generateCallbackMethod(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java
index f234a1b..987dc8d 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java
@@ -181,8 +181,8 @@
     return interfaceResult != null
         && appView
             .options()
-            .machineDesugaredLibrarySpecification
-            .getEmulatedInterfaces()
+            .desugaredLibrarySpecification
+            .getEmulateLibraryInterface()
             .containsKey(interfaceResult.getHolderType());
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java
index 71442ac..4a8cabe 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java
@@ -13,14 +13,12 @@
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexClasspathClass;
 import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexEncodedMember;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexProto;
-import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.FieldAccessFlags;
 import com.android.tools.r8.graph.MethodAccessFlags;
@@ -40,7 +38,6 @@
 import com.android.tools.r8.synthesis.SyntheticClassBuilder;
 import com.android.tools.r8.synthesis.SyntheticMethodBuilder;
 import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
-import com.android.tools.r8.utils.Pair;
 import com.android.tools.r8.utils.StringDiagnostic;
 import com.google.common.collect.Iterables;
 import java.util.ArrayList;
@@ -177,21 +174,17 @@
   private DexMethod getCustomConversion(DexType type, DexType srcType, DexType destType) {
     // ConversionType holds the methods "rewrittenType convert(type)" and the other way around.
     // But everything is going to be rewritten, so we need to use vivifiedType and type".
-    Pair<DexType, DexString> pair =
-        appView.options().machineDesugaredLibrarySpecification.getCustomConversions().get(type);
-    if (pair != null) {
+    DexType conversionHolder =
+        appView.options().desugaredLibrarySpecification.getCustomConversions().get(type);
+    if (conversionHolder != null) {
       return factory.createMethod(
-          pair.getFirst(), factory.createProto(destType, srcType), pair.getSecond());
+          conversionHolder, factory.createProto(destType, srcType), factory.convertMethodName);
     }
     return null;
   }
 
   private boolean canConvert(DexType type) {
-    return appView
-            .options()
-            .machineDesugaredLibrarySpecification
-            .getCustomConversions()
-            .containsKey(type)
+    return appView.options().desugaredLibrarySpecification.getCustomConversions().containsKey(type)
         || canGenerateWrapper(type);
   }
 
@@ -219,7 +212,7 @@
   }
 
   private boolean canGenerateWrapper(DexType type) {
-    return appView.options().machineDesugaredLibrarySpecification.getWrappers().containsKey(type);
+    return appView.options().desugaredLibrarySpecification.getWrapperConversions().contains(type);
   }
 
   private DexClass getValidClassToWrap(DexType type) {
@@ -465,8 +458,9 @@
       if (holderClass == null) {
         assert appView
             .options()
-            .machineDesugaredLibrarySpecification
-            .isEmulatedInterfaceRewrittenType(method.getHolderType());
+            .desugaredLibrarySpecification
+            .getEmulateLibraryInterface()
+            .containsValue(method.getHolderType());
         isInterface = true;
       } else {
         isInterface = holderClass.isInterface();
@@ -547,17 +541,19 @@
   }
 
   private Iterable<DexMethod> allImplementedMethods(DexClass clazz) {
-    if (appView.options().machineDesugaredLibrarySpecification != null) {
+    if (appView.options().testing.machineDesugaredLibrarySpecification != null) {
       return appView
           .options()
+          .testing
           .machineDesugaredLibrarySpecification
+          .getRewritingFlags()
           .getWrappers()
           .get(clazz.type);
     }
     List<DexEncodedMethod> dexEncodedMethods =
         allImplementedMethodsCache.computeIfAbsent(
             clazz.type, type -> internalAllImplementedMethods(clazz));
-    return Iterables.transform(dexEncodedMethods, DexEncodedMember::getReference);
+    return Iterables.transform(dexEncodedMethods, m -> m.getReference());
   }
 
   private List<DexEncodedMethod> internalAllImplementedMethods(DexClass libraryClass) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecification.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecification.java
index 1e871b3..6a6a2d4 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecification.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecification.java
@@ -6,9 +6,14 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.desugar.PrefixRewritingMapper;
+import com.android.tools.r8.ir.desugar.PrefixRewritingMapper.DesugarPrefixRewritingMapper;
 import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.InternalOptions;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -18,20 +23,56 @@
   private final boolean libraryCompilation;
   private final HumanTopLevelFlags topLevelFlags;
   private final HumanRewritingFlags rewritingFlags;
+  private final PrefixRewritingMapper prefixRewritingMapper;
+
+  public static HumanDesugaredLibrarySpecification withOnlyRewritePrefixForTesting(
+      Map<String, String> prefix, InternalOptions options) {
+    return new HumanDesugaredLibrarySpecification(
+        HumanTopLevelFlags.empty(),
+        HumanRewritingFlags.withOnlyRewritePrefixForTesting(prefix, options),
+        true,
+        options.itemFactory);
+  }
+
+  public static HumanDesugaredLibrarySpecification empty() {
+    return new HumanDesugaredLibrarySpecification(
+        HumanTopLevelFlags.empty(), HumanRewritingFlags.empty(), false, null) {
+
+      @Override
+      public boolean isSupported(DexReference reference, AppView<?> appView) {
+        return false;
+      }
+
+      @Override
+      public boolean isEmptyConfiguration() {
+        return true;
+      }
+    };
+  }
 
   public HumanDesugaredLibrarySpecification(
       HumanTopLevelFlags topLevelFlags,
       HumanRewritingFlags rewritingFlags,
-      boolean libraryCompilation) {
+      boolean libraryCompilation,
+      DexItemFactory factory) {
     this.libraryCompilation = libraryCompilation;
     this.topLevelFlags = topLevelFlags;
     this.rewritingFlags = rewritingFlags;
+    this.prefixRewritingMapper =
+        rewritingFlags.getRewritePrefix().isEmpty()
+            ? PrefixRewritingMapper.empty()
+            : new DesugarPrefixRewritingMapper(
+                rewritingFlags.getRewritePrefix(), factory, libraryCompilation);
   }
 
   public boolean supportAllCallbacksFromLibrary() {
     return topLevelFlags.supportAllCallbacksFromLibrary();
   }
 
+  public PrefixRewritingMapper getPrefixRewritingMapper() {
+    return prefixRewritingMapper;
+  }
+
   public AndroidApiLevel getRequiredCompilationApiLevel() {
     return topLevelFlags.getRequiredCompilationAPILevel();
   }
@@ -68,6 +109,10 @@
     return rewritingFlags.getEmulateLibraryInterface();
   }
 
+  public boolean isSupported(DexReference reference, AppView<?> appView) {
+    return prefixRewritingMapper.hasRewrittenType(reference.getContextType(), appView);
+  }
+
   // If the method is retargeted, answers the retargeted method, else null.
   public DexMethod retargetMethod(DexEncodedMethod method, AppView<?> appView) {
     Map<DexMethod, DexType> retargetCoreLibMember = rewritingFlags.getRetargetCoreLibMember();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
index e01def6..a612177 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
@@ -103,7 +103,7 @@
 
     HumanDesugaredLibrarySpecification config =
         new HumanDesugaredLibrarySpecification(
-            topLevelFlags, legacyRewritingFlags, libraryCompilation);
+            topLevelFlags, legacyRewritingFlags, libraryCompilation, dexItemFactory);
     origin = null;
     return config;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecification.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecification.java
index 9ab05b9..3da0b97 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecification.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecification.java
@@ -6,9 +6,13 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.desugar.PrefixRewritingMapper;
+import com.android.tools.r8.ir.desugar.PrefixRewritingMapper.DesugarPrefixRewritingMapper;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.InternalOptions;
@@ -22,18 +26,25 @@
   private final boolean libraryCompilation;
   private final LegacyTopLevelFlags topLevelFlags;
   private final LegacyRewritingFlags rewritingFlags;
+  private final PrefixRewritingMapper prefixRewritingMapper;
 
   public static LegacyDesugaredLibrarySpecification withOnlyRewritePrefixForTesting(
       Map<String, String> prefix, InternalOptions options) {
     return new LegacyDesugaredLibrarySpecification(
         LegacyTopLevelFlags.empty(),
         LegacyRewritingFlags.withOnlyRewritePrefixForTesting(prefix, options),
-        true);
+        true,
+        options.itemFactory);
   }
 
   public static LegacyDesugaredLibrarySpecification empty() {
     return new LegacyDesugaredLibrarySpecification(
-        LegacyTopLevelFlags.empty(), LegacyRewritingFlags.empty(), false) {
+        LegacyTopLevelFlags.empty(), LegacyRewritingFlags.empty(), false, null) {
+
+      @Override
+      public boolean isSupported(DexReference reference, AppView<?> appView) {
+        return false;
+      }
 
       @Override
       public boolean isEmptyConfiguration() {
@@ -45,10 +56,16 @@
   public LegacyDesugaredLibrarySpecification(
       LegacyTopLevelFlags topLevelFlags,
       LegacyRewritingFlags rewritingFlags,
-      boolean libraryCompilation) {
+      boolean libraryCompilation,
+      DexItemFactory factory) {
     this.libraryCompilation = libraryCompilation;
     this.topLevelFlags = topLevelFlags;
     this.rewritingFlags = rewritingFlags;
+    this.prefixRewritingMapper =
+        rewritingFlags.getRewritePrefix().isEmpty()
+            ? PrefixRewritingMapper.empty()
+            : new DesugarPrefixRewritingMapper(
+                rewritingFlags.getRewritePrefix(), factory, libraryCompilation);
   }
 
   public LegacyTopLevelFlags getTopLevelFlags() {
@@ -63,6 +80,10 @@
     return topLevelFlags.supportAllCallbacksFromLibrary();
   }
 
+  public PrefixRewritingMapper getPrefixRewritingMapper() {
+    return prefixRewritingMapper;
+  }
+
   public AndroidApiLevel getRequiredCompilationApiLevel() {
     return topLevelFlags.getRequiredCompilationAPILevel();
   }
@@ -102,6 +123,10 @@
     return rewritingFlags.getEmulateLibraryInterface();
   }
 
+  public boolean isSupported(DexReference reference, AppView<?> appView) {
+    return prefixRewritingMapper.hasRewrittenType(reference.getContextType(), appView);
+  }
+
   // If the method is retargeted, answers the retargeted method, else null.
   public DexMethod retargetMethod(DexEncodedMethod method, AppView<?> appView) {
     Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecificationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecificationParser.java
index a3afcd9..7cece17 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecificationParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecificationParser.java
@@ -110,7 +110,7 @@
 
     LegacyDesugaredLibrarySpecification config =
         new LegacyDesugaredLibrarySpecification(
-            topLevelFlags, legacyRewritingFlags, libraryCompilation);
+            topLevelFlags, legacyRewritingFlags, libraryCompilation, dexItemFactory);
     origin = null;
     return config;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java
index e1368e3..501482e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java
@@ -4,41 +4,12 @@
 
 package com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification;
 
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexReference;
-import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.Pair;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.function.Consumer;
-
 public class MachineDesugaredLibrarySpecification {
 
   private final boolean libraryCompilation;
   private final MachineTopLevelFlags topLevelFlags;
   private final MachineRewritingFlags rewritingFlags;
 
-  public static MachineDesugaredLibrarySpecification empty() {
-    return new MachineDesugaredLibrarySpecification(
-        false, MachineTopLevelFlags.empty(), MachineRewritingFlags.builder().build()) {
-      @Override
-      public boolean isSupported(DexReference reference) {
-        return false;
-      }
-    };
-  }
-
-  public static MachineDesugaredLibrarySpecification withOnlyRewriteTypeForTesting(
-      Map<DexType, DexType> rewriteTypeForTesting) {
-    MachineRewritingFlags.Builder builder = MachineRewritingFlags.builder();
-    rewriteTypeForTesting.forEach(builder::rewriteType);
-    return new MachineDesugaredLibrarySpecification(
-        true, MachineTopLevelFlags.empty(), builder.build());
-  }
-
   public MachineDesugaredLibrarySpecification(
       boolean libraryCompilation,
       MachineTopLevelFlags topLevelFlags,
@@ -52,116 +23,11 @@
     return libraryCompilation;
   }
 
-  public AndroidApiLevel getRequiredCompilationAPILevel() {
-    return topLevelFlags.getRequiredCompilationAPILevel();
+  public MachineTopLevelFlags getTopLevelFlags() {
+    return topLevelFlags;
   }
 
-  public String getSynthesizedLibraryClassesPackagePrefix() {
-    return topLevelFlags.getSynthesizedLibraryClassesPackagePrefix();
-  }
-
-  public String getIdentifier() {
-    return topLevelFlags.getIdentifier();
-  }
-
-  public String getJsonSource() {
-    return topLevelFlags.getJsonSource();
-  }
-
-  public boolean supportAllCallbacksFromLibrary() {
-    return topLevelFlags.supportAllCallbacksFromLibrary();
-  }
-
-  public List<String> getExtraKeepRules() {
-    return topLevelFlags.getExtraKeepRules();
-  }
-
-  public Map<DexType, DexType> getRewriteType() {
-    return rewritingFlags.getRewriteType();
-  }
-
-  public Map<DexType, DexType> getRewriteDerivedTypeOnly() {
-    return rewritingFlags.getRewriteDerivedTypeOnly();
-  }
-
-  public Map<DexMethod, DexMethod> getStaticRetarget() {
-    return rewritingFlags.getStaticRetarget();
-  }
-
-  public Map<DexMethod, DexMethod> getNonEmulatedVirtualRetarget() {
-    return rewritingFlags.getNonEmulatedVirtualRetarget();
-  }
-
-  public Map<DexMethod, EmulatedDispatchMethodDescriptor> getEmulatedVirtualRetarget() {
-    return rewritingFlags.getEmulatedVirtualRetarget();
-  }
-
-  public void forEachRetargetHolder(Consumer<DexType> consumer) {
-    rewritingFlags.forEachRetargetHolder(consumer);
-  }
-
-  public Map<DexType, EmulatedInterfaceDescriptor> getEmulatedInterfaces() {
-    return rewritingFlags.getEmulatedInterfaces();
-  }
-
-  public EmulatedDispatchMethodDescriptor getEmulatedInterfaceEmulatedDispatchMethodDescriptor(
-      DexMethod method) {
-    return rewritingFlags.getEmulatedInterfaceEmulatedDispatchMethodDescriptor(method);
-  }
-
-  public boolean isCustomConversionRewrittenType(DexType type) {
-    return rewritingFlags.isCustomConversionRewrittenType(type);
-  }
-
-  public boolean isEmulatedInterfaceRewrittenType(DexType type) {
-    return rewritingFlags.isEmulatedInterfaceRewrittenType(type);
-  }
-
-  public Map<DexType, List<DexMethod>> getWrappers() {
-    return rewritingFlags.getWrappers();
-  }
-
-  public Map<DexType, DexType> getLegacyBackport() {
-    return rewritingFlags.getLegacyBackport();
-  }
-
-  public Set<DexType> getDontRetarget() {
-    return rewritingFlags.getDontRetarget();
-  }
-
-  public Map<DexType, Pair<DexType, DexString>> getCustomConversions() {
-    return rewritingFlags.getCustomConversions();
-  }
-
-  public boolean hasRetargeting() {
-    return rewritingFlags.hasRetargeting();
-  }
-
-  public boolean hasEmulatedInterfaces() {
-    return rewritingFlags.hasEmulatedInterfaces();
-  }
-
-  public boolean isSupported(DexReference reference) {
-    // Support through type rewriting.
-    if (rewritingFlags.getRewriteType().containsKey(reference.getContextType())) {
-      return true;
-    }
-    if (!reference.isDexMethod()) {
-      return false;
-    }
-    // Support through retargeting.
-    DexMethod dexMethod = reference.asDexMethod();
-    if (getStaticRetarget().containsKey(dexMethod)
-        || getNonEmulatedVirtualRetarget().containsKey(dexMethod)
-        || getEmulatedVirtualRetarget().containsKey(dexMethod)) {
-      return true;
-    }
-    // Support through emulated interface.
-    for (EmulatedInterfaceDescriptor descriptor : getEmulatedInterfaces().values()) {
-      if (descriptor.getEmulatedMethods().containsKey(dexMethod)) {
-        return true;
-      }
-    }
-    return false;
+  public MachineRewritingFlags getRewritingFlags() {
+    return rewritingFlags;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java
index c5c77c6..a6c487e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java
@@ -11,12 +11,10 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
 import java.util.IdentityHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.function.Consumer;
 
 public class MachineRewritingFlags {
 
@@ -96,12 +94,6 @@
     return emulatedVirtualRetarget;
   }
 
-  public void forEachRetargetHolder(Consumer<DexType> consumer) {
-    staticRetarget.keySet().forEach(m -> consumer.accept(m.getHolderType()));
-    nonEmulatedVirtualRetarget.keySet().forEach(m -> consumer.accept(m.getHolderType()));
-    emulatedVirtualRetarget.keySet().forEach(m -> consumer.accept(m.getHolderType()));
-  }
-
   public Map<DexType, EmulatedInterfaceDescriptor> getEmulatedInterfaces() {
     return emulatedInterfaces;
   }
@@ -118,37 +110,10 @@
     return dontRetarget;
   }
 
-  public boolean isCustomConversionRewrittenType(DexType type) {
-    return Iterables.any(customConversions.values(), pair -> pair.getFirst() == type);
-  }
-
   public Map<DexType, Pair<DexType, DexString>> getCustomConversions() {
     return customConversions;
   }
 
-  public boolean hasRetargeting() {
-    return !staticRetarget.isEmpty()
-        || !nonEmulatedVirtualRetarget.isEmpty()
-        || !emulatedVirtualRetarget.isEmpty();
-  }
-
-  public boolean isEmulatedInterfaceRewrittenType(DexType type) {
-    return Iterables.any(
-        emulatedInterfaces.values(), descriptor -> descriptor.getRewrittenType() == type);
-  }
-
-  public boolean hasEmulatedInterfaces() {
-    return !emulatedInterfaces.isEmpty();
-  }
-
-  EmulatedDispatchMethodDescriptor getEmulatedInterfaceEmulatedDispatchMethodDescriptor(
-      DexMethod method) {
-    if (!emulatedInterfaces.containsKey(method.getHolderType())) {
-      return null;
-    }
-    return emulatedInterfaces.get(method.getHolderType()).getEmulatedMethods().get(method);
-  }
-
   public static class Builder {
 
     Builder() {}
@@ -172,7 +137,6 @@
     public void rewriteType(DexType src, DexType target) {
       assert src != null;
       assert target != null;
-      assert src != target;
       rewriteType.put(src, target);
     }
 
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineTopLevelFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineTopLevelFlags.java
index 0c6a88a..f426219 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineTopLevelFlags.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineTopLevelFlags.java
@@ -5,7 +5,6 @@
 package com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification;
 
 import com.android.tools.r8.utils.AndroidApiLevel;
-import com.google.common.collect.ImmutableList;
 import java.util.List;
 
 public class MachineTopLevelFlags {
@@ -24,11 +23,6 @@
   private final boolean supportAllCallbacksFromLibrary;
   private final List<String> extraKeepRules;
 
-  public static MachineTopLevelFlags empty() {
-    return new MachineTopLevelFlags(
-        AndroidApiLevel.B, "unused", null, null, false, ImmutableList.of());
-  }
-
   public MachineTopLevelFlags(
       AndroidApiLevel requiredCompilationAPILevel,
       String synthesizedLibraryClassesPackagePrefix,
@@ -60,7 +54,7 @@
     return jsonSource;
   }
 
-  public boolean supportAllCallbacksFromLibrary() {
+  public boolean isSupportAllCallbacksFromLibrary() {
     return supportAllCallbacksFromLibrary;
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
index 5fcf037..a54cd8d 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
@@ -129,8 +129,8 @@
     }
     if (appView
         .options()
-        .machineDesugaredLibrarySpecification
-        .getDontRetarget()
+        .desugaredLibrarySpecification
+        .getDontRetargetLibMember()
         .contains(context.getContextType())) {
       return NO_REWRITING;
     }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterL8Synthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterL8Synthesizer.java
index eb28d20..11fcfb7 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterL8Synthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterL8Synthesizer.java
@@ -20,7 +20,7 @@
       AppView<?> appView, RetargetingInfo retargetingInfo) {
     assert appView.options().isDesugaredLibraryCompilation();
     if (retargetingInfo == null || retargetingInfo.getEmulatedVirtualRetarget().isEmpty()) {
-      assert !appView.options().machineDesugaredLibrarySpecification.hasRetargeting();
+      assert appView.options().desugaredLibrarySpecification.getRetargetCoreLibMember().isEmpty();
       return null;
     }
     return new DesugaredLibraryRetargeterL8Synthesizer(appView, retargetingInfo);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterLibraryTypeSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterLibraryTypeSynthesizer.java
index bfb423a..bbaa4cf 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterLibraryTypeSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterLibraryTypeSynthesizer.java
@@ -39,16 +39,16 @@
 public class DesugaredLibraryRetargeterLibraryTypeSynthesizer {
 
   public static void checkForAssumedLibraryTypes(AppView<?> appView) {
-    appView
-        .options()
-        .machineDesugaredLibrarySpecification
-        .forEachRetargetHolder(
-            inType -> {
-              DexClass typeClass = appView.definitionFor(inType);
-              if (typeClass == null) {
-                warnMissingRetargetCoreLibraryMember(inType, appView);
-              }
-            });
+    Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
+        appView.options().desugaredLibrarySpecification.getRetargetCoreLibMember();
+    for (DexString methodName : retargetCoreLibMember.keySet()) {
+      for (DexType inType : retargetCoreLibMember.get(methodName).keySet()) {
+        DexClass typeClass = appView.definitionFor(inType);
+        if (typeClass == null) {
+          warnMissingRetargetCoreLibraryMember(inType, appView);
+        }
+      }
+    }
   }
 
   public static void amendLibraryWithRetargetedMembers(AppView<AppInfoWithClassHierarchy> appView) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java
index d1e64ec..414c32d 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java
@@ -127,8 +127,8 @@
       }
       if (appView
           .options()
-          .machineDesugaredLibrarySpecification
-          .getDontRetarget()
+          .desugaredLibrarySpecification
+          .getDontRetargetLibMember()
           .contains(clazz.getType())) {
         continue;
       }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/RetargetingInfo.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/RetargetingInfo.java
index b7ac366..9e1f5e3 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/RetargetingInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/RetargetingInfo.java
@@ -4,9 +4,24 @@
 package com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter;
 
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProto;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.DerivedMethod;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.EmulatedDispatchMethodDescriptor;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineRewritingFlags;
+import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
+import com.android.tools.r8.utils.WorkList;
+import com.google.common.collect.ImmutableMap;
+import java.util.ArrayList;
+import java.util.IdentityHashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
 import java.util.Map;
 
 public class RetargetingInfo {
@@ -25,12 +40,15 @@
   }
 
   public static RetargetingInfo get(AppView<?> appView) {
-    MachineDesugaredLibrarySpecification specification =
-        appView.options().machineDesugaredLibrarySpecification;
-    return new RetargetingInfo(
-        specification.getStaticRetarget(),
-        specification.getNonEmulatedVirtualRetarget(),
-        specification.getEmulatedVirtualRetarget());
+    if (appView.options().testing.machineDesugaredLibrarySpecification != null) {
+      MachineRewritingFlags rewritingFlags =
+          appView.options().testing.machineDesugaredLibrarySpecification.getRewritingFlags();
+      return new RetargetingInfo(
+          rewritingFlags.getStaticRetarget(),
+          rewritingFlags.getNonEmulatedVirtualRetarget(),
+          rewritingFlags.getEmulatedVirtualRetarget());
+    }
+    return new RetargetingInfoBuilder(appView).computeRetargetingInfo();
   }
 
   public Map<DexMethod, DexMethod> getStaticRetarget() {
@@ -44,4 +62,152 @@
   public Map<DexMethod, EmulatedDispatchMethodDescriptor> getEmulatedVirtualRetarget() {
     return emulatedVirtualRetarget;
   }
+
+  private static class RetargetingInfoBuilder {
+
+    private final AppView<?> appView;
+    private final Map<DexMethod, DexMethod> staticRetarget = new IdentityHashMap<>();
+    private final Map<DexMethod, DexMethod> nonEmulatedVirtualRetarget = new IdentityHashMap<>();
+    private final Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedVirtualRetarget =
+        new IdentityHashMap<>();
+
+    public RetargetingInfoBuilder(AppView<?> appView) {
+      this.appView = appView;
+    }
+
+    private RetargetingInfo computeRetargetingInfo() {
+      LegacyDesugaredLibrarySpecification desugaredLibrarySpecification =
+          appView.options().desugaredLibrarySpecification;
+      Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
+          desugaredLibrarySpecification.getRetargetCoreLibMember();
+      if (retargetCoreLibMember.isEmpty()) {
+        return new RetargetingInfo(ImmutableMap.of(), ImmutableMap.of(), ImmutableMap.of());
+      }
+      for (DexString methodName : retargetCoreLibMember.keySet()) {
+        for (DexType inType : retargetCoreLibMember.get(methodName).keySet()) {
+          DexClass typeClass = appView.definitionFor(inType);
+          if (typeClass != null) {
+            DexType newHolder = retargetCoreLibMember.get(methodName).get(inType);
+            List<DexClassAndMethod> found = findMethodsWithName(methodName, typeClass);
+            for (DexClassAndMethod method : found) {
+              DexMethod methodReference = method.getReference();
+              if (method.getAccessFlags().isStatic()) {
+                staticRetarget.put(
+                    methodReference,
+                    computeRetargetMethod(
+                        methodReference, method.getAccessFlags().isStatic(), newHolder));
+                continue;
+              }
+              if (isEmulatedInterfaceDispatch(method)) {
+                continue;
+              }
+              if (typeClass.isFinal() || method.getAccessFlags().isFinal()) {
+                nonEmulatedVirtualRetarget.put(
+                    methodReference,
+                    computeRetargetMethod(
+                        methodReference, method.getAccessFlags().isStatic(), newHolder));
+              } else {
+                // Virtual rewrites require emulated dispatch for inheritance.
+                // The call is rewritten to the dispatch holder class instead.
+                DexProto newProto = appView.dexItemFactory().prependHolderToProto(methodReference);
+                DexMethod forwardingDexMethod =
+                    appView.dexItemFactory().createMethod(newHolder, newProto, methodName);
+                DerivedMethod forwardingMethod = new DerivedMethod(forwardingDexMethod);
+                DerivedMethod interfaceMethod =
+                    new DerivedMethod(methodReference, SyntheticKind.RETARGET_INTERFACE);
+                DerivedMethod dispatchMethod =
+                    new DerivedMethod(methodReference, SyntheticKind.RETARGET_CLASS);
+                emulatedVirtualRetarget.put(
+                    methodReference,
+                    new EmulatedDispatchMethodDescriptor(
+                        interfaceMethod, dispatchMethod, forwardingMethod, new LinkedHashMap<>()));
+              }
+            }
+          }
+        }
+      }
+      if (desugaredLibrarySpecification.isLibraryCompilation()) {
+        // TODO(b/177977763): This is only a workaround rewriting invokes of j.u.Arrays.deepEquals0
+        // to j.u.DesugarArrays.deepEquals0.
+        DexItemFactory itemFactory = appView.options().dexItemFactory();
+        DexString name = itemFactory.createString("deepEquals0");
+        DexProto proto =
+            itemFactory.createProto(
+                itemFactory.booleanType, itemFactory.objectType, itemFactory.objectType);
+        DexMethod source =
+            itemFactory.createMethod(
+                itemFactory.createType(itemFactory.arraysDescriptor), proto, name);
+        DexMethod target =
+            computeRetargetMethod(
+                source, true, itemFactory.createType("Ljava/util/DesugarArrays;"));
+        staticRetarget.put(source, target);
+        // TODO(b/181629049): This is only a workaround rewriting invokes of
+        //  j.u.TimeZone.getTimeZone taking a java.time.ZoneId.
+        name = itemFactory.createString("getTimeZone");
+        proto =
+            itemFactory.createProto(
+                itemFactory.createType("Ljava/util/TimeZone;"),
+                itemFactory.createType("Ljava/time/ZoneId;"));
+        source =
+            itemFactory.createMethod(itemFactory.createType("Ljava/util/TimeZone;"), proto, name);
+        target =
+            computeRetargetMethod(
+                source, true, itemFactory.createType("Ljava/util/DesugarTimeZone;"));
+        staticRetarget.put(source, target);
+      }
+      return new RetargetingInfo(
+          ImmutableMap.copyOf(staticRetarget),
+          ImmutableMap.copyOf(nonEmulatedVirtualRetarget),
+          emulatedVirtualRetarget);
+    }
+
+    DexMethod computeRetargetMethod(DexMethod method, boolean isStatic, DexType newHolder) {
+      DexItemFactory factory = appView.dexItemFactory();
+      DexProto newProto = isStatic ? method.getProto() : factory.prependHolderToProto(method);
+      return factory.createMethod(newHolder, newProto, method.getName());
+    }
+
+    private boolean isEmulatedInterfaceDispatch(DexClassAndMethod method) {
+      // Answers true if this method is already managed through emulated interface dispatch.
+      Map<DexType, DexType> emulateLibraryInterface =
+          appView.options().desugaredLibrarySpecification.getEmulateLibraryInterface();
+      if (emulateLibraryInterface.isEmpty()) {
+        return false;
+      }
+      DexMethod methodToFind = method.getReference();
+      // Look-up all superclass and interfaces, if an emulated interface is found, and it implements
+      // the method, answers true.
+      WorkList<DexClass> worklist = WorkList.newIdentityWorkList(method.getHolder());
+      while (worklist.hasNext()) {
+        DexClass clazz = worklist.next();
+        if (clazz.isInterface()
+            && emulateLibraryInterface.containsKey(clazz.getType())
+            && clazz.lookupMethod(methodToFind) != null) {
+          return true;
+        }
+        // All super types are library class, or we are doing L8 compilation.
+        clazz.forEachImmediateSupertype(
+            superType -> {
+              DexClass superClass = appView.definitionFor(superType);
+              if (superClass != null) {
+                worklist.addIfNotSeen(superClass);
+              }
+            });
+      }
+      return false;
+    }
+
+    private List<DexClassAndMethod> findMethodsWithName(DexString methodName, DexClass clazz) {
+      List<DexClassAndMethod> found = new ArrayList<>();
+      clazz.forEachClassMethodMatching(
+          definition -> definition.getName() == methodName, found::add);
+      assert !found.isEmpty()
+          : "Should have found a method (library specifications) for "
+              + clazz.toSourceString()
+              + "."
+              + methodName
+              + ". Maybe the library used for the compilation should be newer.";
+      return found;
+    }
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineEmulatedInterfaceConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineEmulatedInterfaceConverter.java
index 04cc12b..2411ba0 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineEmulatedInterfaceConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineEmulatedInterfaceConverter.java
@@ -8,6 +8,7 @@
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanRewritingFlags;
@@ -43,10 +44,10 @@
     Set<DexMethod> dontRewriteInvocation = rewritingFlags.getDontRewriteInvocation();
     emulatedInterfaceHierarchy = processEmulatedInterfaceHierarchy(appInfo, emulateInterfaces);
     for (DexType itf : emulateInterfaces.keySet()) {
-      DexClass itfClass = appInfo.contextIndependentDefinitionFor(itf);
+      DexProgramClass itfClass = appInfo.contextIndependentDefinitionFor(itf).asProgramClass();
       assert itfClass != null;
       Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedMethods = new IdentityHashMap<>();
-      itfClass.forEachClassMethodMatching(
+      itfClass.forEachProgramVirtualMethodMatching(
           m -> m.isDefaultMethod() && !dontRewriteInvocation.contains(m.getReference()),
           method ->
               emulatedMethods.put(
@@ -103,6 +104,7 @@
       for (int i = subInterfaces.size() - 1; i >= 0; i--) {
         DexClass subInterfaceClass = appInfo.definitionFor(subInterfaces.get(i));
         assert subInterfaceClass != null;
+        assert subInterfaceClass.isProgramClass();
         // Else computation of subInterface would have failed.
         // if the method is implemented, extra dispatch is required.
         DexEncodedMethod result = subInterfaceClass.lookupVirtualMethod(method);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java
index 92efb24..6ff7428 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java
@@ -5,31 +5,22 @@
 package com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion;
 
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
-import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanRewritingFlags;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineRewritingFlags;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.google.common.collect.ImmutableMap;
-import java.util.IdentityHashMap;
 import java.util.Map;
 
 public class HumanToMachinePrefixConverter {
 
   private final AppInfoWithClassHierarchy appInfo;
-  private final MachineRewritingFlags.Builder builder;
-  private final String synthesizedPrefix;
-  private final Map<DexType, DexType> reverse = new IdentityHashMap<>();
 
-  public HumanToMachinePrefixConverter(
-      AppInfoWithClassHierarchy appInfo,
-      MachineRewritingFlags.Builder builder,
-      String synthesizedPrefix) {
+  public HumanToMachinePrefixConverter(AppInfoWithClassHierarchy appInfo) {
     this.appInfo = appInfo;
-    this.builder = builder;
-    this.synthesizedPrefix = synthesizedPrefix;
   }
 
   private DexString toDescriptorPrefix(String prefix) {
@@ -38,30 +29,20 @@
         .createString("L" + DescriptorUtils.getBinaryNameFromJavaType(prefix));
   }
 
-  public void convertPrefixFlags(HumanRewritingFlags rewritingFlags) {
+  public void convertPrefixFlags(
+      HumanRewritingFlags rewritingFlags,
+      MachineRewritingFlags.Builder builder,
+      String synthesizedPrefix) {
     Map<DexString, DexString> descriptorPrefix = convertRewritePrefix(rewritingFlags);
-    rewriteClasses(descriptorPrefix);
-    rewriteValues(descriptorPrefix, rewritingFlags.getRetargetCoreLibMember());
-    rewriteValues(descriptorPrefix, rewritingFlags.getCustomConversions());
-    rewriteEmulatedInterface(rewritingFlags.getEmulateLibraryInterface());
-    rewriteRetargetKeys(rewritingFlags.getRetargetCoreLibMember());
-    rewriteReverse(descriptorPrefix);
+    rewriteClasses(descriptorPrefix, builder);
+    rewriteValues(descriptorPrefix, builder, rewritingFlags.getRetargetCoreLibMember());
+    rewriteValues(descriptorPrefix, builder, rewritingFlags.getCustomConversions());
+    rewriteEmulatedInterface(builder, rewritingFlags.getEmulateLibraryInterface());
+    rewriteRetargetKeys(builder, rewritingFlags.getRetargetCoreLibMember(), synthesizedPrefix);
   }
 
-  // For custom conversions, this is responsible in rewriting backward.
-  private void rewriteReverse(Map<DexString, DexString> descriptorPrefix) {
-    reverse.forEach(
-        (rewrittenType, type) -> {
-          DexType backwardRewrittenType = rewrittenType(descriptorPrefix, rewrittenType);
-          if (backwardRewrittenType != null) {
-            assert backwardRewrittenType == type;
-            builder.rewriteType(rewrittenType, type);
-          }
-        });
-  }
-
-  public DexType convertJavaNameToDesugaredLibrary(DexType type) {
-    String convertedPrefix = DescriptorUtils.getJavaTypeFromBinaryName(synthesizedPrefix);
+  public DexType convertJavaNameToDesugaredLibrary(DexType type, String prefix) {
+    String convertedPrefix = DescriptorUtils.getJavaTypeFromBinaryName(prefix);
     String interfaceType = type.toString();
     int firstPackage = interfaceType.indexOf('.');
     return appInfo
@@ -71,49 +52,40 @@
                 convertedPrefix + interfaceType.substring(firstPackage + 1)));
   }
 
-  private void rewriteRetargetKeys(Map<DexMethod, DexType> retarget) {
+  private void rewriteRetargetKeys(
+      MachineRewritingFlags.Builder builder, Map<DexMethod, DexType> retarget, String prefix) {
     for (DexMethod dexMethod : retarget.keySet()) {
-      DexType type = convertJavaNameToDesugaredLibrary(dexMethod.holder);
+      DexType type = convertJavaNameToDesugaredLibrary(dexMethod.holder, prefix);
       builder.rewriteDerivedTypeOnly(dexMethod.holder, type);
     }
   }
 
-  private void rewriteEmulatedInterface(Map<DexType, DexType> emulateLibraryInterface) {
+  private void rewriteEmulatedInterface(
+      MachineRewritingFlags.Builder builder, Map<DexType, DexType> emulateLibraryInterface) {
     emulateLibraryInterface.forEach(builder::rewriteDerivedTypeOnly);
   }
 
-  private void rewriteType(DexType type, DexType rewrittenType) {
-    builder.rewriteType(type, rewrittenType);
-    reverse.put(rewrittenType, type);
-  }
-
   private void rewriteValues(
       Map<DexString, DexString> descriptorPrefix,
+      MachineRewritingFlags.Builder builder,
       Map<?, DexType> flags) {
     for (DexType type : flags.values()) {
       DexType rewrittenType = rewrittenType(descriptorPrefix, type);
       if (rewrittenType != null) {
-        rewriteType(type, rewrittenType);
+        builder.rewriteType(type, rewrittenType);
       }
     }
   }
 
-  private void rewriteClasses(Map<DexString, DexString> descriptorPrefix) {
-    for (DexClass clazz : appInfo.app().asDirect().libraryClasses()) {
-      rewriteClass(descriptorPrefix, clazz);
+  private void rewriteClasses(
+      Map<DexString, DexString> descriptorPrefix, MachineRewritingFlags.Builder builder) {
+    for (DexProgramClass clazz : appInfo.classes()) {
+      DexType type = clazz.type;
+      DexType rewrittenType = rewrittenType(descriptorPrefix, type);
+      if (rewrittenType != null) {
+        builder.rewriteType(type, rewrittenType);
+      }
     }
-    for (DexClass clazz : appInfo.classes()) {
-      rewriteClass(descriptorPrefix, clazz);
-    }
-  }
-
-  private void rewriteClass(Map<DexString, DexString> descriptorPrefix, DexClass clazz) {
-    DexType type = clazz.type;
-    DexType rewrittenType = rewrittenType(descriptorPrefix, type);
-    if (rewrittenType == null) {
-      return;
-    }
-    rewriteType(type, rewrittenType);
   }
 
   private DexType rewrittenType(Map<DexString, DexString> descriptorPrefix, DexType type) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java
index b5c1ac3..6dce945 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java
@@ -92,14 +92,10 @@
       DexClass subclass = appInfo.definitionFor(subtype);
       MethodResolutionResult resolutionResult =
           appInfo.resolveMethodOn(subclass, src.getReference());
-      // The resolution is not successful when compiling to dex if the method rewritten is missing
-      // in Android.jar.
-      assert !resolutionResult.isSuccessfulMemberResolutionResult()
-          || resolutionResult.getResolvedMethod().getReference() == src.getReference()
-          // There is a difference in the sql library between Android.jar and the JDK which leads
-          // to this resolution when compiling Cf to Cf while the methods do not exist in Android.
-          || (resolutionResult.getResolvedMethod().getHolderType().toString().contains("java.sql")
-              && resolutionResult.getResolvedMethod().getName().toString().equals("toInstant"));
+      if (resolutionResult.isSuccessfulMemberResolutionResult()
+          && resolutionResult.getResolvedMethod().getReference() != src.getReference()) {
+        assert false; // Unsupported.
+      }
     }
     return true;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java
index 23824c5..bc3a663 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java
@@ -4,8 +4,6 @@
 
 package com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion;
 
-import com.android.tools.r8.ClassFileResourceProvider;
-import com.android.tools.r8.ProgramResourceProvider;
 import com.android.tools.r8.dex.ApplicationReader;
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
@@ -24,51 +22,15 @@
 import com.android.tools.r8.utils.Timing;
 import java.io.IOException;
 import java.nio.file.Path;
-import java.util.List;
 import java.util.concurrent.ExecutorService;
 
 public class HumanToMachineSpecificationConverter {
 
   public MachineDesugaredLibrarySpecification convert(
-      HumanDesugaredLibrarySpecification humanSpec,
-      List<ProgramResourceProvider> desugaredJDKLib,
-      List<ClassFileResourceProvider> library,
-      InternalOptions options)
+      HumanDesugaredLibrarySpecification humanSpec, Path androidLib, InternalOptions options)
       throws IOException {
-    assert !humanSpec.isLibraryCompilation() || desugaredJDKLib != null;
-    AndroidApp.Builder builder = AndroidApp.builder();
-    for (ClassFileResourceProvider classFileResourceProvider : library) {
-      builder.addLibraryResourceProvider(classFileResourceProvider);
-    }
-    if (humanSpec.isLibraryCompilation()) {
-      for (ProgramResourceProvider programResourceProvider : desugaredJDKLib) {
-        builder.addProgramResourceProvider(programResourceProvider);
-      }
-    }
-    return internalConvert(humanSpec, builder.build(), options);
-  }
-
-  public MachineDesugaredLibrarySpecification convert(
-      HumanDesugaredLibrarySpecification humanSpec,
-      Path desugaredJDKLib,
-      Path androidLib,
-      InternalOptions options)
-      throws IOException {
-    assert !humanSpec.isLibraryCompilation() || desugaredJDKLib != null;
-    AndroidApp.Builder builder = AndroidApp.builder();
-    if (humanSpec.isLibraryCompilation()) {
-      builder.addProgramFile(desugaredJDKLib);
-    }
-    AndroidApp inputApp = builder.addLibraryFile(androidLib).build();
-    return internalConvert(humanSpec, inputApp, options);
-  }
-
-  public MachineDesugaredLibrarySpecification internalConvert(
-      HumanDesugaredLibrarySpecification humanSpec, AndroidApp inputApp, InternalOptions options)
-      throws IOException {
-    DexApplication app = readApp(inputApp, options);
+    DexApplication app = readApp(androidLib, options);
     AppView<?> appView = AppView.createForD8(AppInfo.createInitialAppInfo(app));
-    LibraryValidator.validate(app, humanSpec.getTopLevelFlags().getRequiredCompilationAPILevel());
     MachineRewritingFlags machineRewritingFlags =
         convertRewritingFlags(
             humanSpec.getSynthesizedLibraryClassesPackagePrefix(),
@@ -97,8 +59,8 @@
     new HumanToMachineRetargetConverter(appInfo).convertRetargetFlags(rewritingFlags, builder);
     new HumanToMachineEmulatedInterfaceConverter(appInfo)
         .convertEmulatedInterfaces(rewritingFlags, appInfo, builder);
-    new HumanToMachinePrefixConverter(appInfo, builder, synthesizedPrefix)
-        .convertPrefixFlags(rewritingFlags);
+    new HumanToMachinePrefixConverter(appInfo)
+        .convertPrefixFlags(rewritingFlags, builder, synthesizedPrefix);
     new HumanToMachineWrapperConverter(appInfo).convertWrappers(rewritingFlags, builder);
     rewritingFlags
         .getCustomConversions()
@@ -113,8 +75,10 @@
     return builder.build();
   }
 
-  private DexApplication readApp(AndroidApp inputApp, InternalOptions options) throws IOException {
-    ApplicationReader applicationReader = new ApplicationReader(inputApp, options, Timing.empty());
+  private DexApplication readApp(Path androidLib, InternalOptions options) throws IOException {
+    AndroidApp androidApp = AndroidApp.builder().addProgramFile(androidLib).build();
+    ApplicationReader applicationReader =
+        new ApplicationReader(androidApp, options, Timing.empty());
     ExecutorService executorService = ThreadUtils.getExecutorService(options);
     return applicationReader.read(executorService).toDirect();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LegacyToHumanSpecificationConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LegacyToHumanSpecificationConverter.java
index e5c9b42..34bf5fa 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LegacyToHumanSpecificationConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LegacyToHumanSpecificationConverter.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion;
 
-import com.android.tools.r8.ClassFileResourceProvider;
 import com.android.tools.r8.StringConsumer;
 import com.android.tools.r8.StringResource;
 import com.android.tools.r8.dex.ApplicationReader;
@@ -66,9 +65,7 @@
       InternalOptions options)
       throws IOException {
     Origin origin = legacySpec.getOrigin();
-    AndroidApp androidApp = AndroidApp.builder().addLibraryFile(androidLib).build();
-    DexApplication app = readApp(androidApp, options);
-    LibraryValidator.validate(app, legacySpec.getTopLevelFlags().getRequiredCompilationAPILevel());
+    DexApplication app = readApp(androidLib, options);
     HumanTopLevelFlags humanTopLevelFlags = convertTopLevelFlags(legacySpec.getTopLevelFlags());
     Int2ObjectArrayMap<HumanRewritingFlags> commonFlags =
         convertRewritingFlagMap(legacySpec.getCommonFlags(), app, origin);
@@ -84,30 +81,11 @@
   }
 
   public HumanDesugaredLibrarySpecification convert(
-      LegacyDesugaredLibrarySpecification legacySpec,
-      List<ClassFileResourceProvider> library,
-      InternalOptions options)
-      throws IOException {
-    AndroidApp.Builder builder = AndroidApp.builder();
-    for (ClassFileResourceProvider classFileResourceProvider : library) {
-      builder.addLibraryResourceProvider(classFileResourceProvider);
-    }
-    return internalConvert(legacySpec, builder.build(), options);
-  }
-
-  public HumanDesugaredLibrarySpecification convert(
       LegacyDesugaredLibrarySpecification legacySpec, Path androidLib, InternalOptions options)
       throws IOException {
-    AndroidApp androidApp = AndroidApp.builder().addLibraryFile(androidLib).build();
-    return internalConvert(legacySpec, androidApp, options);
-  }
-
-  public HumanDesugaredLibrarySpecification internalConvert(
-      LegacyDesugaredLibrarySpecification legacySpec, AndroidApp inputApp, InternalOptions options)
-      throws IOException {
-    DexApplication app = readApp(inputApp, options);
-    LibraryValidator.validate(app, legacySpec.getTopLevelFlags().getRequiredCompilationAPILevel());
+    DexApplication app = readApp(androidLib, options);
     HumanTopLevelFlags humanTopLevelFlags = convertTopLevelFlags(legacySpec.getTopLevelFlags());
+
     // The origin is not maintained in non multi-level specifications.
     // It should not matter since the origin is used to report invalid specifications, and
     // converting non multi-level specifications should be performed only with *valid*
@@ -117,7 +95,10 @@
     HumanRewritingFlags humanRewritingFlags =
         convertRewritingFlags(legacySpec.getRewritingFlags(), app, origin);
     return new HumanDesugaredLibrarySpecification(
-        humanTopLevelFlags, humanRewritingFlags, legacySpec.isLibraryCompilation());
+        humanTopLevelFlags,
+        humanRewritingFlags,
+        legacySpec.isLibraryCompilation(),
+        app.dexItemFactory());
   }
 
   private void legacyLibraryFlagHacks(
@@ -153,8 +134,10 @@
     libraryFlags.put(level, builder.build());
   }
 
-  private DexApplication readApp(AndroidApp inputApp, InternalOptions options) throws IOException {
-    ApplicationReader applicationReader = new ApplicationReader(inputApp, options, Timing.empty());
+  private DexApplication readApp(Path androidLib, InternalOptions options) throws IOException {
+    AndroidApp androidApp = AndroidApp.builder().addLibraryFile(androidLib).build();
+    ApplicationReader applicationReader =
+        new ApplicationReader(androidApp, options, Timing.empty());
     ExecutorService executorService = ThreadUtils.getExecutorService(options);
     return applicationReader.read(executorService).toDirect();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LibraryValidator.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LibraryValidator.java
deleted file mode 100644
index b415c354..0000000
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LibraryValidator.java
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (c) 2022, 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.desugar.desugaredlibrary.specificationconversion;
-
-import com.android.tools.r8.graph.DexApplication;
-import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.utils.AndroidApiLevel;
-
-public class LibraryValidator {
-
-  // Estimates if the library passed is at the expected minimum level, if it is not, raise
-  // a warning.
-  public static void validate(DexApplication app, AndroidApiLevel requiredCompilationAPILevel) {
-    DexType levelType;
-    if (requiredCompilationAPILevel.isEqualTo(AndroidApiLevel.O)) {
-      levelType = app.dexItemFactory.createType("Ljava/time/LocalTime;");
-    } else if (requiredCompilationAPILevel.isEqualTo(AndroidApiLevel.R)) {
-      levelType = app.dexItemFactory.createType("Ljava/util/concurrent/Flow;");
-    } else {
-      app.options.reporter.warning(
-          "Unsupported requiredCompilationAPILevel: " + requiredCompilationAPILevel);
-      return;
-    }
-    DexClass dexClass = app.definitionFor(levelType);
-    if (dexClass == null) {
-      app.options.reporter.warning(
-          "Desugared library requires to be compiled with a library file of API greater or equal to"
-              + " "
-              + requiredCompilationAPILevel
-              + ", but it seems the library file passed is of a lower API.");
-    }
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
index 33f7037..758812e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
@@ -24,10 +24,10 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GenericSignature;
 import com.android.tools.r8.graph.GenericSignature.ClassTypeSignature;
+import com.android.tools.r8.graph.LibraryMethod;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.MethodResolutionResult;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.DerivedMethod;
 import com.android.tools.r8.position.MethodPosition;
 import com.android.tools.r8.utils.BooleanBox;
 import com.android.tools.r8.utils.BooleanUtils;
@@ -49,6 +49,7 @@
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.BiConsumer;
+import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.Predicate;
 import org.objectweb.asm.Opcodes;
@@ -375,7 +376,12 @@
     this.dexItemFactory = appView.dexItemFactory();
     this.helper = new InterfaceDesugaringSyntheticHelper(appView);
     needsLibraryInfo =
-        appView.options().machineDesugaredLibrarySpecification.hasEmulatedInterfaces();
+        !appView.options().desugaredLibrarySpecification.getEmulateLibraryInterface().isEmpty()
+            || !appView
+                .options()
+                .desugaredLibrarySpecification
+                .getRetargetCoreLibMember()
+                .isEmpty();
     this.isLiveMethod = isLiveMethod;
   }
 
@@ -504,7 +510,7 @@
       DexClass iface = appView.definitionFor(emulatedInterface);
       if (iface != null) {
         assert iface.isLibraryClass()
-            || appView.options().machineDesugaredLibrarySpecification.isLibraryCompilation();
+            || appView.options().desugaredLibrarySpecification.isLibraryCompilation();
         workList.addIfNotSeen(iface.getInterfaces());
       }
     }
@@ -664,10 +670,10 @@
       resolveForwardForSignature(
           clazz,
           wrapper.get(),
-          (target, forward) -> {
+          target -> {
             if (isLiveMethod(target) && !superInfo.isTargetedByForwards(target)) {
               additionalForwards.add(target);
-              addForwardingMethod(target, forward, clazz);
+              addForwardingMethod(target, clazz);
             }
           });
     }
@@ -676,7 +682,7 @@
   // Looks up a method signature from the point of 'clazz', if it can dispatch to a default method
   // the 'addForward' call-back is called with the target of the forward.
   private void resolveForwardForSignature(
-      DexClass clazz, DexMethod method, BiConsumer<DexClassAndMethod, DexMethod> addForward) {
+      DexClass clazz, DexMethod method, Consumer<DexClassAndMethod> addForward) {
     AppInfoWithClassHierarchy appInfo = appView.appInfoForDesugaring();
     MethodResolutionResult resolutionResult = appInfo.resolveMethodOn(clazz, method);
     if (resolutionResult.isFailedResolution()
@@ -716,22 +722,50 @@
         resolutionResult.lookupVirtualDispatchTarget(clazz, appInfo);
     assert virtualDispatchTarget != null;
 
-    // If resolution targets a default interface method, forward it.
-    if (virtualDispatchTarget.isDefaultMethod()) {
-      addForward.accept(
-          virtualDispatchTarget,
-          helper.ensureDefaultAsMethodOfCompanionClassStub(virtualDispatchTarget).getReference());
+    // Don't forward if the target is explicitly marked as 'dont-rewrite'
+    if (dontRewrite(virtualDispatchTarget)) {
       return;
     }
 
-    DerivedMethod forwardingMethod =
-        helper.computeEmulatedInterfaceForwardingMethod(
-            virtualDispatchTarget.getHolder(), virtualDispatchTarget);
-    if (forwardingMethod != null) {
-      DexMethod concreteForwardingMethod =
-          helper.ensureEmulatedInterfaceForwardingMethod(forwardingMethod);
-      addForward.accept(virtualDispatchTarget, concreteForwardingMethod);
+    // If resolution targets a default interface method, forward it.
+    if (virtualDispatchTarget.isDefaultMethod()) {
+      addForward.accept(virtualDispatchTarget);
+      return;
     }
+
+    // Remaining edge cases only pertain to desugaring of library methods.
+    if (!virtualDispatchTarget.isLibraryMethod() || ignoreLibraryInfo()) {
+      return;
+    }
+
+    LibraryMethod libraryMethod = virtualDispatchTarget.asLibraryMethod();
+    if (isRetargetMethod(libraryMethod)) {
+      addForward.accept(virtualDispatchTarget);
+      return;
+    }
+
+    // If target is a non-interface library class it may be an emulated interface,
+    // except on a rewritten type, where L8 has already dealt with the desugaring.
+    if (!libraryMethod.getHolder().isInterface()
+        && !appView.rewritePrefix.hasRewrittenType(libraryMethod.getHolderType(), appView)) {
+      // Here we use step-3 of resolution to find a maximally specific default interface method.
+      DexClassAndMethod result =
+          appInfo.lookupMaximallySpecificMethod(libraryMethod.getHolder(), method);
+      if (result != null && helper.isEmulatedInterface(result.getHolderType())) {
+        addForward.accept(result);
+      }
+    }
+  }
+
+  private boolean isRetargetMethod(LibraryMethod method) {
+    assert needsLibraryInfo();
+    assert method.getDefinition().isNonPrivateVirtualMethod();
+    return !method.getAccessFlags().isFinal()
+        && appView.options().desugaredLibrarySpecification.retargetMethod(method, appView) != null;
+  }
+
+  private boolean dontRewrite(DexClassAndMethod method) {
+    return needsLibraryInfo() && method.getHolder().isLibraryClass() && helper.dontRewrite(method);
   }
 
   // Construction of actual forwarding methods.
@@ -796,8 +830,7 @@
 
   // Note: The parameter 'target' may be a public method on a class in case of desugared
   // library retargeting (See below target.isInterface check).
-  private void addForwardingMethod(
-      DexClassAndMethod target, DexMethod forwardMethod, DexClass clazz) {
+  private void addForwardingMethod(DexClassAndMethod target, DexClass clazz) {
     if (!clazz.isProgramClass()) {
       return;
     }
@@ -814,6 +847,10 @@
     // NOTE: Never add a forwarding method to methods of classes unknown or coming from android.jar
     // even if this results in invalid code, these classes are never desugared.
     // In desugared library, emulated interface methods can be overridden by retarget lib members.
+    DexMethod forwardMethod =
+        target.getHolder().isInterface()
+            ? helper.ensureDefaultAsMethodOfCompanionClassStub(target).getReference()
+            : appView.options().desugaredLibrarySpecification.retargetMethod(target, appView);
     DexEncodedMethod desugaringForwardingMethod =
         DexEncodedMethod.createDesugaringForwardingMethod(
             target.getDefinition(), clazz, forwardMethod, dexItemFactory);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceApplicationRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceApplicationRewriter.java
index d06fee7..74d94e3 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceApplicationRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceApplicationRewriter.java
@@ -15,7 +15,6 @@
 import com.android.tools.r8.utils.IterableUtils;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.IdentityHashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -26,15 +25,8 @@
 
   public EmulatedInterfaceApplicationRewriter(AppView<?> appView) {
     this.appView = appView;
-    emulatedInterfaces = new IdentityHashMap<>();
-    appView
-        .options()
-        .machineDesugaredLibrarySpecification
-        .getEmulatedInterfaces()
-        .forEach(
-            (ei, descriptor) -> {
-              emulatedInterfaces.put(ei, descriptor.getRewrittenType());
-            });
+    this.emulatedInterfaces =
+        appView.options().desugaredLibrarySpecification.getEmulateLibraryInterface();
   }
 
   public void rewriteApplication(DexApplication.Builder<?> builder) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringForTesting.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringForTesting.java
index 6636e1e..a3e0164 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringForTesting.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringForTesting.java
@@ -4,12 +4,10 @@
 
 package com.android.tools.r8.ir.desugar.itf;
 
-import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
-
 public class InterfaceDesugaringForTesting {
 
   public static String getEmulateLibraryClassNameSuffix() {
-    return SyntheticKind.EMULATED_INTERFACE_CLASS.descriptor;
+    return InterfaceDesugaringSyntheticHelper.EMULATE_LIBRARY_CLASS_NAME_SUFFIX;
   }
 
   public static String getCompanionClassNameSuffix() {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
index cb4a537..77d99e5 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
@@ -24,7 +24,6 @@
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.DexValue.DexValueInt;
@@ -32,20 +31,19 @@
 import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
 import com.android.tools.r8.graph.InvalidCode;
 import com.android.tools.r8.graph.MethodAccessFlags;
-import com.android.tools.r8.graph.MethodResolutionResult;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.ThrowNullCode;
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.DerivedMethod;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.EmulatedDispatchMethodDescriptor;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.EmulatedInterfaceDescriptor;
 import com.android.tools.r8.ir.desugar.itf.EmulatedInterfaceSynthesizerEventConsumer.ClasspathEmulatedInterfaceSynthesizerEventConsumer;
 import com.android.tools.r8.synthesis.SyntheticClassBuilder;
 import com.android.tools.r8.synthesis.SyntheticMethodBuilder;
 import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
 import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.Pair;
 import com.android.tools.r8.utils.structural.Ordered;
 import com.google.common.collect.ImmutableList;
+import java.util.Map;
+import java.util.Set;
 import java.util.function.Predicate;
 
 public class InterfaceDesugaringSyntheticHelper {
@@ -59,37 +57,37 @@
   }
 
   // Use InterfaceDesugaringForTesting for public accesses in tests.
+  static final String EMULATE_LIBRARY_CLASS_NAME_SUFFIX = "$-EL";
   static final String COMPANION_CLASS_NAME_SUFFIX = "$-CC";
   static final String DEFAULT_METHOD_PREFIX = "$default$";
   static final String PRIVATE_METHOD_PREFIX = "$private$";
 
   private final AppView<?> appView;
+  private final Map<DexType, DexType> emulatedInterfaces;
   private final Predicate<DexType> shouldIgnoreFromReportsPredicate;
 
   public InterfaceDesugaringSyntheticHelper(AppView<?> appView) {
     this.appView = appView;
+    emulatedInterfaces =
+        appView.options().desugaredLibrarySpecification.getEmulateLibraryInterface();
+
     this.shouldIgnoreFromReportsPredicate = getShouldIgnoreFromReportsPredicate(appView);
   }
 
   boolean isEmulatedInterface(DexType itf) {
-    return appView
-        .options()
-        .machineDesugaredLibrarySpecification
-        .getEmulatedInterfaces()
-        .containsKey(itf);
+    return emulatedInterfaces.containsKey(itf);
   }
 
   boolean isRewrittenEmulatedInterface(DexType itf) {
-    return appView
-        .options()
-        .machineDesugaredLibrarySpecification
-        .isEmulatedInterfaceRewrittenType(itf);
+    return emulatedInterfaces.containsValue(itf);
+  }
+
+  Set<DexType> getEmulatedInterfaces() {
+    return emulatedInterfaces.keySet();
   }
 
   DexType getEmulatedInterface(DexType type) {
-    EmulatedInterfaceDescriptor interfaceDescriptor =
-        appView.options().machineDesugaredLibrarySpecification.getEmulatedInterfaces().get(type);
-    return interfaceDescriptor == null ? null : interfaceDescriptor.getRewrittenType();
+    return emulatedInterfaces.get(type);
   }
 
   boolean isInDesugaredLibrary(DexClass clazz) {
@@ -100,6 +98,17 @@
     return appView.rewritePrefix.hasRewrittenType(clazz.type, appView);
   }
 
+  boolean dontRewrite(DexClassAndMethod method) {
+    for (Pair<DexType, DexString> dontRewrite :
+        appView.options().desugaredLibrarySpecification.getDontRewriteInvocation()) {
+      if (method.getHolderType() == dontRewrite.getFirst()
+          && method.getName() == dontRewrite.getSecond()) {
+        return true;
+      }
+    }
+    return false;
+  }
+
   final boolean isCompatibleDefaultMethod(DexEncodedMethod method) {
     assert !method.accessFlags.isConstructor();
     assert !method.accessFlags.isStatic();
@@ -120,15 +129,25 @@
     return true;
   }
 
-  DexMethod emulatedInterfaceDispatchMethod(DerivedMethod method, DexType holder) {
-    assert method.getHolderKind() == SyntheticKind.EMULATED_INTERFACE_CLASS;
-    DexProto newProto = appView.dexItemFactory().prependHolderToProto(method.getMethod());
-    return appView.dexItemFactory().createMethod(holder, newProto, method.getName());
+  public DexMethod emulateInterfaceLibraryMethod(DexClassAndMethod method) {
+    DexItemFactory factory = appView.dexItemFactory();
+    return factory.createMethod(
+        getEmulateLibraryInterfaceClassType(method.getHolderType(), factory),
+        factory.prependTypeToProto(method.getHolderType(), method.getProto()),
+        method.getName());
   }
 
-  DexMethod emulatedInterfaceInterfaceMethod(DerivedMethod method) {
-    assert method.getHolderKind() == null;
-    return method.getMethod();
+  private static String getEmulateLibraryInterfaceClassDescriptor(String descriptor) {
+    return descriptor.substring(0, descriptor.length() - 1)
+        + EMULATE_LIBRARY_CLASS_NAME_SUFFIX
+        + ";";
+  }
+
+  public static DexType getEmulateLibraryInterfaceClassType(DexType type, DexItemFactory factory) {
+    assert type.isClassType();
+    String descriptor = type.descriptor.toString();
+    String elTypeDescriptor = getEmulateLibraryInterfaceClassDescriptor(descriptor);
+    return factory.createSynthesizedType(elTypeDescriptor);
   }
 
   public static String getCompanionClassDescriptor(String descriptor) {
@@ -148,6 +167,10 @@
     return type.descriptor.toString().endsWith(COMPANION_CLASS_NAME_SUFFIX + ";");
   }
 
+  public static boolean isEmulatedLibraryClassType(DexType type) {
+    return type.descriptor.toString().endsWith(EMULATE_LIBRARY_CLASS_NAME_SUFFIX + ";");
+  }
+
   // Gets the interface class for a companion class `type`.
   DexType getInterfaceClassType(DexType type) {
     return getInterfaceClassType(type, appView.dexItemFactory());
@@ -174,91 +197,9 @@
             SyntheticClassBuilder::setInterface);
   }
 
-  DexClassAndMethod lookupMaximallySpecificIncludingSelf(
-      DexClass initialResolutionHolder, DexClassAndMethod method) {
-    assert method.getHolderType().isClassType();
-    if (method.getHolder().isInterface()) {
-      return method;
-    }
-    return appView
-        .appInfoForDesugaring()
-        .lookupMaximallySpecificMethod(initialResolutionHolder, method.getReference());
-  }
-
-  EmulatedDispatchMethodDescriptor getEmulatedDispatchDescriptor(
-      DexClass initialResolutionHolder, DexClassAndMethod method) {
-    if (method == null) {
-      return null;
-    }
-    assert initialResolutionHolder != null;
-    // Outside L8 compilation, only library methods can lead to emulated interface dispatch.
-    if (!method.isLibraryMethod() && !appView.options().isDesugaredLibraryCompilation()) {
-      return null;
-    }
-    DexClassAndMethod maximallySpecificMethod =
-        lookupMaximallySpecificIncludingSelf(initialResolutionHolder, method);
-    if (maximallySpecificMethod == null) {
-      return null;
-    }
-    EmulatedDispatchMethodDescriptor descriptor =
-        appView
-            .options()
-            .machineDesugaredLibrarySpecification
-            .getEmulatedInterfaceEmulatedDispatchMethodDescriptor(
-                maximallySpecificMethod.getReference());
-    if (!appView.options().isDesugaredLibraryCompilation()) {
-      return descriptor;
-    }
-    return requiresEmulatedDispatchInL8(method, descriptor) ? descriptor : null;
-  }
-
-  private boolean requiresEmulatedDispatchInL8(
-      DexClassAndMethod method, EmulatedDispatchMethodDescriptor descriptor) {
-    return method.isLibraryMethod()
-        || isEmulatedInterface(method.getHolderType())
-        || (descriptor != null
-            && descriptor.getDispatchCases().containsKey(method.getHolderType()));
-  }
-
-  DerivedMethod computeEmulatedInterfaceDispatchMethod(MethodResolutionResult resolutionResult) {
-    EmulatedDispatchMethodDescriptor descriptor =
-        getEmulatedDispatchDescriptor(
-            resolutionResult.getInitialResolutionHolder(), resolutionResult.getResolutionPair());
-    return descriptor == null ? null : descriptor.getEmulatedDispatchMethod();
-  }
-
-  DerivedMethod computeEmulatedInterfaceForwardingMethod(
-      DexClass initialResolutionHolder, DexClassAndMethod method) {
-    EmulatedDispatchMethodDescriptor descriptor =
-        getEmulatedDispatchDescriptor(initialResolutionHolder, method);
-    if (descriptor == null) {
-      return null;
-    }
-    return descriptor.getDispatchCases().containsKey(method.getHolderType())
-        ? descriptor.getDispatchCases().get(method.getHolderType())
-        : descriptor.getForwardingMethod();
-  }
-
-  DexMethod ensureEmulatedInterfaceForwardingMethod(DerivedMethod method) {
-    if (method.getHolderKind() == null) {
-      return method.getMethod();
-    }
-    assert method.getHolderKind() == SyntheticKind.COMPANION_CLASS;
-    DexClassAndMethod resolvedMethod =
-        appView.appInfoForDesugaring().resolveMethod(method.getMethod(), true).getResolutionPair();
-    return ensureDefaultAsMethodOfCompanionClassStub(resolvedMethod).getReference();
-  }
-
-  DexClassAndMethod ensureEmulatedInterfaceDispatchMethod(
-      DerivedMethod emulatedDispatchMethod,
-      ClasspathEmulatedInterfaceSynthesizerEventConsumer eventConsumer) {
-    assert emulatedDispatchMethod.getHolderKind() == SyntheticKind.EMULATED_INTERFACE_CLASS;
-    DexClassAndMethod method =
-        appView
-            .appInfoForDesugaring()
-            .resolveMethod(emulatedDispatchMethod.getMethod(), true)
-            .getResolutionPair();
-    assert emulatedDispatchMethod.getHolderKind() == SyntheticKind.EMULATED_INTERFACE_CLASS;
+  DexClassAndMethod ensureEmulatedInterfaceMethod(
+      DexClassAndMethod method, ClasspathEmulatedInterfaceSynthesizerEventConsumer eventConsumer) {
+    DexMethod emulatedInterfaceMethod = emulateInterfaceLibraryMethod(method);
     if (method.isProgramMethod()) {
       assert appView.options().isDesugaredLibraryCompilation();
       DexProgramClass emulatedInterface =
@@ -268,15 +209,8 @@
                   SyntheticKind.EMULATED_INTERFACE_CLASS,
                   method.asProgramMethod().getHolder(),
                   appView);
-      DexMethod emulatedInterfaceMethod =
-          emulatedInterfaceDispatchMethod(emulatedDispatchMethod, emulatedInterface.type);
-      assert emulatedInterface.lookupProgramMethod(emulatedInterfaceMethod) != null;
       return emulatedInterface.lookupProgramMethod(emulatedInterfaceMethod);
     }
-    // The holder is not used.
-    DexMethod emulatedInterfaceMethod =
-        emulatedInterfaceDispatchMethod(
-            emulatedDispatchMethod, appView.dexItemFactory().objectType);
     return appView
         .getSyntheticItems()
         .ensureFixedClasspathClassMethod(
@@ -577,7 +511,7 @@
       return appView.rewritePrefix.hasRewrittenType(type, appView)
           || descriptor.endsWith(companionClassNameDescriptorSuffix)
           || isRewrittenEmulatedInterface(type)
-          || options.machineDesugaredLibrarySpecification.isCustomConversionRewrittenType(type)
+          || options.desugaredLibrarySpecification.getCustomConversions().containsValue(type)
           || appView.getDontWarnConfiguration().matches(type);
     };
   }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
index 0227b1f..6740441 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
@@ -35,8 +35,7 @@
 import com.android.tools.r8.ir.desugar.DesugarDescription;
 import com.android.tools.r8.ir.desugar.FreshLocalProvider;
 import com.android.tools.r8.ir.desugar.LocalStackAllocator;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.DerivedMethod;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
 import com.android.tools.r8.ir.desugar.icce.AlwaysThrowingInstructionDesugaring;
 import com.android.tools.r8.ir.desugar.lambda.LambdaInstructionDesugaring;
 import com.android.tools.r8.ir.desugar.stringconcat.StringConcatInstructionDesugaring;
@@ -54,6 +53,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.BiConsumer;
 import java.util.function.Predicate;
 
 //
@@ -119,31 +119,18 @@
   }
 
   public static void checkForAssumedLibraryTypes(AppInfo appInfo, InternalOptions options) {
-    MachineDesugaredLibrarySpecification machineDesugaredLibrarySpecification =
-        options.machineDesugaredLibrarySpecification;
-    machineDesugaredLibrarySpecification
-        .getEmulatedInterfaces()
-        .forEach(
-            (ei, descriptor) -> {
-              registerType(appInfo, ei);
-              registerType(appInfo, descriptor.getRewrittenType());
-              descriptor
-                  .getEmulatedMethods()
-                  .forEach(
-                      (method, methodDescriptor) -> {
-                        methodDescriptor
-                            .getDispatchCases()
-                            .keySet()
-                            .forEach(t -> registerType(appInfo, t));
-                      });
-            });
-    machineDesugaredLibrarySpecification
-        .getCustomConversions()
-        .forEach(
-            (type, conversionPair) -> {
-              registerType(appInfo, type);
-              registerType(appInfo, conversionPair.getFirst());
-            });
+    LegacyDesugaredLibrarySpecification spec = options.desugaredLibrarySpecification;
+    BiConsumer<DexType, DexType> registerEntry = registerMapEntry(appInfo);
+    spec.getEmulateLibraryInterface().forEach(registerEntry);
+    spec.getCustomConversions().forEach(registerEntry);
+    spec.getRetargetCoreLibMember().forEach((method, types) -> types.forEach(registerEntry));
+  }
+
+  private static BiConsumer<DexType, DexType> registerMapEntry(AppInfo appInfo) {
+    return (key, value) -> {
+      registerType(appInfo, key);
+      registerType(appInfo, value);
+    };
   }
 
   private static void registerType(AppInfo appInfo, DexType type) {
@@ -169,9 +156,9 @@
   }
 
   private void initializeEmulatedInterfaceVariables() {
-    Set<DexType> emulateLibraryInterface =
-        options.machineDesugaredLibrarySpecification.getEmulatedInterfaces().keySet();
-    for (DexType interfaceType : emulateLibraryInterface) {
+    Map<DexType, DexType> emulateLibraryInterface =
+        options.desugaredLibrarySpecification.getEmulateLibraryInterface();
+    for (DexType interfaceType : emulateLibraryInterface.keySet()) {
       DexClass emulatedInterfaceClass = appView.definitionFor(interfaceType);
       if (emulatedInterfaceClass != null) {
         for (DexEncodedMethod encodedMethod :
@@ -462,27 +449,24 @@
   }
 
   private DesugarDescription computeEmulatedInterfaceVirtualDispatchOrNull(CfInvoke invoke) {
-    MethodResolutionResult resolutionResult =
-        appView.appInfoForDesugaring().resolveMethod(invoke.getMethod(), invoke.isInterface());
-    DerivedMethod emulatedDispatchMethod =
-        helper.computeEmulatedInterfaceDispatchMethod(resolutionResult);
-    if (emulatedDispatchMethod == null) {
-      return null;
+    DexClassAndMethod defaultMethod =
+        defaultMethodForEmulatedDispatchOrNull(invoke.getMethod(), invoke.isInterface());
+    if (defaultMethod != null) {
+      return DesugarDescription.builder()
+          .setDesugarRewrite(
+              (freshLocalProvider,
+                  localStackAllocator,
+                  eventConsumer,
+                  context1,
+                  methodProcessingContext,
+                  dexItemFactory) ->
+                  getInvokeStaticInstructions(
+                      helper
+                          .ensureEmulatedInterfaceMethod(defaultMethod, eventConsumer)
+                          .getReference()))
+          .build();
     }
-    return DesugarDescription.builder()
-        .setDesugarRewrite(
-            (freshLocalProvider,
-                localStackAllocator,
-                eventConsumer,
-                context1,
-                methodProcessingContext,
-                dexItemFactory) ->
-                getInvokeStaticInstructions(
-                    helper
-                        .ensureEmulatedInterfaceDispatchMethod(
-                            emulatedDispatchMethod, eventConsumer)
-                        .getReference()))
-        .build();
+    return null;
   }
 
   private DesugarDescription computeInvokeDirect(
@@ -720,49 +704,103 @@
 
   private DesugarDescription computeEmulatedInterfaceInvokeSpecial(
       DexClass clazz, DexMethod invokedMethod, ProgramMethod context) {
-    DexClassAndMethod superTarget =
-        appView.appInfoForDesugaring().lookupSuperTarget(invokedMethod, context);
-    if (clazz.isInterface() && appView.rewritePrefix.hasRewrittenType(clazz.type, appView)) {
-      if (superTarget != null && superTarget.getDefinition().isDefaultMethod()) {
-        DexClass holder = superTarget.getHolder();
-        if (holder.isLibraryClass() && holder.isInterface()) {
-          return DesugarDescription.builder()
-              .setDesugarRewrite(
-                  (freshLocalProvider,
-                      localStackAllocator,
-                      eventConsumer,
-                      context13,
-                      methodProcessingContext,
-                      dexItemFactory) -> {
-                    DexClassAndMethod companionTarget =
-                        helper.ensureDefaultAsMethodOfCompanionClassStub(superTarget);
-                    acceptCompanionMethod(superTarget, companionTarget, eventConsumer);
-                    return getInvokeStaticInstructions(companionTarget.getReference());
-                  })
-              .build();
+    DexType emulatedItf = maximallySpecificEmulatedInterfaceOrNull(invokedMethod);
+    if (emulatedItf == null) {
+      if (clazz.isInterface() && appView.rewritePrefix.hasRewrittenType(clazz.type, appView)) {
+        DexClassAndMethod target =
+            appView.appInfoForDesugaring().lookupSuperTarget(invokedMethod, context);
+        if (target != null && target.getDefinition().isDefaultMethod()) {
+          DexClass holder = target.getHolder();
+          if (holder.isLibraryClass() && holder.isInterface()) {
+            return DesugarDescription.builder()
+                .setDesugarRewrite(
+                    (freshLocalProvider,
+                        localStackAllocator,
+                        eventConsumer,
+                        context13,
+                        methodProcessingContext,
+                        dexItemFactory) -> {
+                      DexClassAndMethod companionTarget =
+                          helper.ensureDefaultAsMethodOfCompanionClassStub(target);
+                      acceptCompanionMethod(target, companionTarget, eventConsumer);
+                      return getInvokeStaticInstructions(companionTarget.getReference());
+                    })
+                .build();
+          }
         }
       }
+      return DesugarDescription.nothing();
     }
     // That invoke super may not resolve since the super method may not be present
     // since it's in the emulated interface. We need to force resolution. If it resolves
     // to a library method, then it needs to be rewritten.
     // If it resolves to a program overrides, the invoke-super can remain.
-    DerivedMethod forwardingMethod =
-        helper.computeEmulatedInterfaceForwardingMethod(clazz, superTarget);
-    if (forwardingMethod == null) {
-      return DesugarDescription.nothing();
+    DexClassAndMethod superTarget =
+        appView.appInfoForDesugaring().lookupSuperTarget(invokedMethod, context);
+    if (superTarget != null && superTarget.isLibraryMethod()) {
+      // Rewriting is required because the super invoke resolves into a missing
+      // method (method is on desugared library). Find out if it needs to be
+      // retargeted or if it just calls a companion class method and rewrite.
+      DexMethod retargetMethod =
+          options.desugaredLibrarySpecification.retargetMethod(superTarget, appView);
+      if (retargetMethod != null) {
+        return DesugarDescription.builder()
+            .setDesugarRewrite(
+                (freshLocalProvider,
+                    localStackAllocator,
+                    eventConsumer,
+                    context14,
+                    methodProcessingContext,
+                    dexItemFactory) -> getInvokeStaticInstructions(retargetMethod))
+            .build();
+      }
+      DexClassAndMethod emulatedMethod =
+          superTarget.getReference().lookupMemberOnClass(appView.definitionFor(emulatedItf));
+      if (emulatedMethod == null) {
+        assert false;
+        return DesugarDescription.nothing();
+      }
+      return DesugarDescription.builder()
+          .setDesugarRewrite(
+              (freshLocalProvider,
+                  localStackAllocator,
+                  eventConsumer,
+                  context15,
+                  methodProcessingContext,
+                  dexItemFactory) -> {
+                DexClassAndMethod companionMethod =
+                    helper.ensureDefaultAsMethodOfCompanionClassStub(emulatedMethod);
+                return getInvokeStaticInstructions(companionMethod.getReference());
+              })
+          .build();
     }
-    return DesugarDescription.builder()
-        .setDesugarRewrite(
-            (freshLocalProvider,
-                localStackAllocator,
-                eventConsumer,
-                context14,
-                methodProcessingContext,
-                dexItemFactory) ->
-                getInvokeStaticInstructions(
-                    helper.ensureEmulatedInterfaceForwardingMethod(forwardingMethod)))
-        .build();
+    return DesugarDescription.nothing();
+  }
+
+  private DexClassAndMethod defaultMethodForEmulatedDispatchOrNull(
+      DexMethod invokedMethod, boolean interfaceBit) {
+    DexType emulatedItf = maximallySpecificEmulatedInterfaceOrNull(invokedMethod);
+    if (emulatedItf == null) {
+      return null;
+    }
+    // The call potentially ends up in a library class, in which case we need to rewrite, since the
+    // code may be in the desugared library.
+    SingleResolutionResult resolution =
+        appView
+            .appInfoForDesugaring()
+            .resolveMethod(invokedMethod, interfaceBit)
+            .asSingleResolution();
+    if (resolution != null
+        && (resolution.getResolvedHolder().isLibraryClass()
+            || helper.isEmulatedInterface(resolution.getResolvedHolder().type))) {
+      DexClassAndMethod defaultMethod =
+          appView.definitionFor(emulatedItf).lookupClassMethod(invokedMethod);
+      if (defaultMethod != null && !helper.dontRewrite(defaultMethod)) {
+        assert !defaultMethod.getAccessFlags().isAbstract();
+        return defaultMethod;
+      }
+    }
+    return null;
   }
 
   private boolean shouldRewriteToInvokeToThrow(
@@ -771,6 +809,40 @@
         || resolutionResult.getResolvedMethod().isStatic() != isInvokeStatic;
   }
 
+  private DexType maximallySpecificEmulatedInterfaceOrNull(DexMethod invokedMethod) {
+    // Here we try to avoid doing the expensive look-up on all invokes.
+    if (!emulatedMethods.contains(invokedMethod.name)) {
+      return null;
+    }
+    DexClass dexClass = appView.definitionFor(invokedMethod.holder);
+    // We cannot rewrite the invoke we do not know what the class is.
+    if (dexClass == null) {
+      return null;
+    }
+    DexEncodedMethod singleTarget = null;
+    if (dexClass.isInterface()) {
+      // Look for exact method on the interface.
+      singleTarget = dexClass.lookupMethod(invokedMethod);
+    }
+    if (singleTarget == null) {
+      DexClassAndMethod result =
+          appView.appInfoForDesugaring().lookupMaximallySpecificMethod(dexClass, invokedMethod);
+      if (result != null) {
+        singleTarget = result.getDefinition();
+      }
+    }
+    if (singleTarget == null) {
+      // At this point we are in a library class. Failures can happen with NoSuchMethod if a
+      // library class implement a method with same signature but not related to emulated
+      // interfaces.
+      return null;
+    }
+    if (!singleTarget.isAbstract() && helper.isEmulatedInterface(singleTarget.getHolderType())) {
+      return singleTarget.getHolderType();
+    }
+    return null;
+  }
+
   private boolean isNonDesugaredLibraryClass(DexClass clazz) {
     return clazz.isLibraryClass() && !helper.isInDesugaredLibrary(clazz);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/ProgramEmulatedInterfaceSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/ProgramEmulatedInterfaceSynthesizer.java
index 7e8a2cc..f712cb4 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/ProgramEmulatedInterfaceSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/ProgramEmulatedInterfaceSynthesizer.java
@@ -5,9 +5,11 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexProto;
+import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -23,16 +25,27 @@
 import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
 import com.android.tools.r8.synthesis.SyntheticProgramClassBuilder;
 import com.android.tools.r8.utils.StringDiagnostic;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.IdentityHashMap;
 import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 public final class ProgramEmulatedInterfaceSynthesizer implements CfClassSynthesizerDesugaring {
 
   private final AppView<?> appView;
   private final InterfaceDesugaringSyntheticHelper helper;
+  private final Map<DexType, List<DexType>> emulatedInterfacesHierarchy;
 
   public static ProgramEmulatedInterfaceSynthesizer create(AppView<?> appView) {
     if (!appView.options().isDesugaredLibraryCompilation()
-        || !appView.options().machineDesugaredLibrarySpecification.hasEmulatedInterfaces()) {
+        || appView.options().desugaredLibrarySpecification.getEmulateLibraryInterface().isEmpty()) {
       return null;
     }
     return new ProgramEmulatedInterfaceSynthesizer(appView);
@@ -41,11 +54,53 @@
   public ProgramEmulatedInterfaceSynthesizer(AppView<?> appView) {
     this.appView = appView;
     helper = new InterfaceDesugaringSyntheticHelper(appView);
+    // Avoid the computation outside L8 since it is not needed.
+    emulatedInterfacesHierarchy =
+        appView.options().isDesugaredLibraryCompilation()
+            ? processEmulatedInterfaceHierarchy()
+            : Collections.emptyMap();
+  }
+
+  private Map<DexType, List<DexType>> processEmulatedInterfaceHierarchy() {
+    Map<DexType, List<DexType>> emulatedInterfacesHierarchy = new IdentityHashMap<>();
+    Set<DexType> processed = Sets.newIdentityHashSet();
+    ArrayList<DexType> emulatedInterfacesSorted = new ArrayList<>(helper.getEmulatedInterfaces());
+    emulatedInterfacesSorted.sort(DexType::compareTo);
+    for (DexType interfaceType : emulatedInterfacesSorted) {
+      processEmulatedInterfaceHierarchy(interfaceType, processed, emulatedInterfacesHierarchy);
+    }
+    return emulatedInterfacesHierarchy;
+  }
+
+  private void processEmulatedInterfaceHierarchy(
+      DexType interfaceType,
+      Set<DexType> processed,
+      Map<DexType, List<DexType>> emulatedInterfacesHierarchy) {
+    if (processed.contains(interfaceType)) {
+      return;
+    }
+    emulatedInterfacesHierarchy.put(interfaceType, new ArrayList<>());
+    processed.add(interfaceType);
+    DexClass theInterface = appView.definitionFor(interfaceType);
+    if (theInterface == null) {
+      return;
+    }
+    LinkedList<DexType> workList = new LinkedList<>(Arrays.asList(theInterface.interfaces.values));
+    while (!workList.isEmpty()) {
+      DexType next = workList.removeLast();
+      if (helper.isEmulatedInterface(next)) {
+        processEmulatedInterfaceHierarchy(next, processed, emulatedInterfacesHierarchy);
+        emulatedInterfacesHierarchy.get(next).add(interfaceType);
+        DexClass nextClass = appView.definitionFor(next);
+        if (nextClass != null) {
+          workList.addAll(Arrays.asList(nextClass.interfaces.values));
+        }
+      }
+    }
   }
 
   DexProgramClass synthesizeProgramEmulatedInterface(
       DexProgramClass emulatedInterface,
-      EmulatedInterfaceDescriptor emulatedInterfaceDescriptor,
       L8ProgramEmulatedInterfaceSynthesizerEventConsumer eventConsumer) {
     return appView
         .getSyntheticItems()
@@ -53,26 +108,20 @@
             SyntheticNaming.SyntheticKind.EMULATED_INTERFACE_CLASS,
             emulatedInterface,
             appView,
-            builder ->
-                synthesizeEmulateInterfaceMethods(
-                    emulatedInterface, emulatedInterfaceDescriptor, builder),
+            builder -> synthesizeEmulateInterfaceMethods(emulatedInterface, builder),
             eventConsumer::acceptProgramEmulatedInterface);
   }
 
   private void synthesizeEmulateInterfaceMethods(
-      DexProgramClass emulatedInterface,
-      EmulatedInterfaceDescriptor emulatedInterfaceDescriptor,
-      SyntheticProgramClassBuilder builder) {
+      DexProgramClass emulatedInterface, SyntheticProgramClassBuilder builder) {
+    assert helper.isEmulatedInterface(emulatedInterface.type);
     emulatedInterface.forEachProgramVirtualMethodMatching(
-        m -> emulatedInterfaceDescriptor.getEmulatedMethods().containsKey(m.getReference()),
+        DexEncodedMethod::isDefaultMethod,
         method ->
             builder.addMethod(
                 methodBuilder ->
                     synthesizeEmulatedInterfaceMethod(
-                        method,
-                        emulatedInterfaceDescriptor.getEmulatedMethods().get(method.getReference()),
-                        builder.getType(),
-                        methodBuilder)));
+                        method, emulatedInterface, builder.getType(), methodBuilder)));
   }
 
   private DexMethod emulatedMethod(DerivedMethod method, DexType holder) {
@@ -88,17 +137,24 @@
 
   private void synthesizeEmulatedInterfaceMethod(
       ProgramMethod method,
-      EmulatedDispatchMethodDescriptor descriptor,
+      DexProgramClass theInterface,
       DexType dispatchType,
       SyntheticMethodBuilder methodBuilder) {
     assert !method.getDefinition().isStatic();
-    DexMethod emulatedMethod =
-        helper.emulatedInterfaceDispatchMethod(
-            descriptor.getEmulatedDispatchMethod(), dispatchType);
-    DexMethod itfMethod = helper.emulatedInterfaceInterfaceMethod(descriptor.getInterfaceMethod());
+    if (appView.options().testing.machineDesugaredLibrarySpecification != null) {
+      synthesizeEmulatedInterfaceMethodFromMachineSpecification(
+          method, theInterface, dispatchType, methodBuilder);
+      return;
+    }
+    DexMethod emulatedMethod = helper.emulateInterfaceLibraryMethod(method);
+    DexMethod itfMethod =
+        method
+            .getReference()
+            .withHolder(helper.getEmulatedInterface(theInterface.type), appView.dexItemFactory());
     DexMethod companionMethod =
-        helper.ensureEmulatedInterfaceForwardingMethod(descriptor.getForwardingMethod());
-    LinkedHashMap<DexType, DexMethod> extraDispatchCases = resolveDispatchCases(descriptor);
+        helper.ensureDefaultAsMethodOfProgramCompanionClassStub(method).getReference();
+    LinkedHashMap<DexType, DexMethod> extraDispatchCases =
+        getDispatchCases(method, theInterface, companionMethod);
     methodBuilder
         .setName(emulatedMethod.getName())
         .setProto(emulatedMethod.getProto())
@@ -114,40 +170,162 @@
                     .generateCfCode());
   }
 
+  private void synthesizeEmulatedInterfaceMethodFromMachineSpecification(
+      ProgramMethod method,
+      DexProgramClass theInterface,
+      DexType dispatchType,
+      SyntheticMethodBuilder methodBuilder) {
+    EmulatedInterfaceDescriptor emulatedInterfaceDescriptor =
+        appView
+            .options()
+            .testing
+            .machineDesugaredLibrarySpecification
+            .getRewritingFlags()
+            .getEmulatedInterfaces()
+            .get(theInterface.type);
+    EmulatedDispatchMethodDescriptor descriptor =
+        emulatedInterfaceDescriptor.getEmulatedMethods().get(method.getReference());
+    DexMethod emulatedMethod = emulatedMethod(descriptor.getEmulatedDispatchMethod(), dispatchType);
+    DexMethod itfMethod = interfaceMethod(descriptor.getInterfaceMethod());
+    // TODO(b/184026720): Adapt to use the forwarding method.
+    DerivedMethod forwardingMethod = descriptor.getForwardingMethod();
+    assert forwardingMethod.getHolderKind() == SyntheticKind.COMPANION_CLASS;
+    assert forwardingMethod.getMethod() == method.getReference();
+    DexMethod companionMethod =
+        helper.ensureDefaultAsMethodOfProgramCompanionClassStub(method).getReference();
+    LinkedHashMap<DexType, DexMethod> extraDispatchCases = resolveDispatchCases(descriptor);
+    methodBuilder
+        .setName(descriptor.getEmulatedDispatchMethod().getName())
+        .setProto(descriptor.getEmulatedDispatchMethod().getProto())
+        .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic())
+        .setCode(
+            emulatedInterfaceMethod ->
+                new EmulateDispatchSyntheticCfCodeProvider(
+                        emulatedMethod.getHolderType(),
+                        companionMethod,
+                        itfMethod,
+                        extraDispatchCases,
+                        appView)
+                    .generateCfCode());
+  }
+
   private LinkedHashMap<DexType, DexMethod> resolveDispatchCases(
       EmulatedDispatchMethodDescriptor descriptor) {
     LinkedHashMap<DexType, DexMethod> extraDispatchCases = new LinkedHashMap<>();
     descriptor
         .getDispatchCases()
         .forEach(
-            (type, derivedMethod) ->
-                extraDispatchCases.put(
-                    type, helper.ensureEmulatedInterfaceForwardingMethod(derivedMethod)));
+            (type, derivedMethod) -> {
+              DexMethod caseMethod;
+              if (derivedMethod.getHolderKind() == null) {
+                caseMethod = derivedMethod.getMethod();
+              } else {
+                assert derivedMethod.getHolderKind() == SyntheticKind.COMPANION_CLASS;
+                ProgramMethod resolvedProgramMethod =
+                    appView
+                        .appInfoForDesugaring()
+                        .resolveMethod(derivedMethod.getMethod(), true)
+                        .getResolvedProgramMethod();
+                caseMethod =
+                    helper
+                        .ensureDefaultAsMethodOfProgramCompanionClassStub(resolvedProgramMethod)
+                        .getReference();
+              }
+              extraDispatchCases.put(type, caseMethod);
+            });
     return extraDispatchCases;
   }
 
+  private LinkedHashMap<DexType, DexMethod> getDispatchCases(
+      ProgramMethod method, DexProgramClass theInterface, DexMethod companionMethod) {
+    // To properly emulate the library interface call, we need to compute the interfaces
+    // inheriting from the interface and manually implement the dispatch with instance of.
+    // The list guarantees that an interface is always after interfaces it extends,
+    // hence reverse iteration.
+    List<DexType> subInterfaces = emulatedInterfacesHierarchy.get(theInterface.type);
+    LinkedHashMap<DexType, DexMethod> extraDispatchCases = new LinkedHashMap<>();
+    // In practice, there is usually a single case (except for tests),
+    // so we do not bother to make the following loop more clever.
+    Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
+        appView.options().desugaredLibrarySpecification.getRetargetCoreLibMember();
+    for (DexString methodName : retargetCoreLibMember.keySet()) {
+      if (method.getName() == methodName) {
+        for (DexType inType : retargetCoreLibMember.get(methodName).keySet()) {
+          DexClass inClass = appView.definitionFor(inType);
+          if (inClass != null && implementsInterface(inClass, theInterface.type)) {
+            extraDispatchCases.put(
+                inType,
+                appView
+                    .dexItemFactory()
+                    .createMethod(
+                        retargetCoreLibMember.get(methodName).get(inType),
+                        appView
+                            .dexItemFactory()
+                            .protoWithDifferentFirstParameter(companionMethod.proto, inType),
+                        method.getName()));
+          }
+        }
+      }
+    }
+    if (subInterfaces != null) {
+      for (int i = subInterfaces.size() - 1; i >= 0; i--) {
+        DexClass subInterfaceClass = appView.definitionFor(subInterfaces.get(i));
+        assert subInterfaceClass != null;
+        assert subInterfaceClass.isProgramClass();
+        // Else computation of subInterface would have failed.
+        // if the method is implemented, extra dispatch is required.
+        DexEncodedMethod result = subInterfaceClass.lookupVirtualMethod(method.getReference());
+        if (result != null && !result.isAbstract()) {
+          assert result.isDefaultMethod();
+          DexMethod forward =
+              helper
+                  .ensureDefaultAsMethodOfProgramCompanionClassStub(
+                      new ProgramMethod(subInterfaceClass.asProgramClass(), result))
+                  .getReference();
+          extraDispatchCases.put(subInterfaceClass.type, forward);
+        }
+      }
+    } else {
+      assert extraDispatchCases.size() <= 1;
+    }
+    return extraDispatchCases;
+  }
+
+  private boolean implementsInterface(DexClass clazz, DexType interfaceType) {
+    LinkedList<DexType> workList = new LinkedList<>(Arrays.asList(clazz.interfaces.values));
+    while (!workList.isEmpty()) {
+      DexType next = workList.removeLast();
+      if (interfaceType == next) {
+        return true;
+      }
+      DexClass nextClass = appView.definitionFor(next);
+      if (nextClass != null) {
+        workList.addAll(Arrays.asList(nextClass.interfaces.values));
+      }
+    }
+    return false;
+  }
+
   @Override
   public void synthesizeClasses(CfClassSynthesizerDesugaringEventConsumer eventConsumer) {
     assert appView.options().isDesugaredLibraryCompilation();
-    appView
-        .options()
-        .machineDesugaredLibrarySpecification
-        .getEmulatedInterfaces()
-        .forEach(
-            (emulatedInterfaceType, emulatedInterfaceDescriptor) -> {
-              DexClass emulatedInterfaceClazz = appView.definitionFor(emulatedInterfaceType);
-              if (emulatedInterfaceClazz == null || !emulatedInterfaceClazz.isProgramClass()) {
-                warnMissingEmulatedInterface(emulatedInterfaceType);
-                return;
-              }
-              DexProgramClass emulatedInterface = emulatedInterfaceClazz.asProgramClass();
-              assert emulatedInterface != null;
-              if (!appView.isAlreadyLibraryDesugared(emulatedInterface)
-                  && !emulatedInterfaceDescriptor.getEmulatedMethods().isEmpty()) {
-                synthesizeProgramEmulatedInterface(
-                    emulatedInterface, emulatedInterfaceDescriptor, eventConsumer);
-              }
-            });
+    for (DexType emulatedInterfaceType : helper.getEmulatedInterfaces()) {
+      DexClass emulatedInterfaceClazz = appView.definitionFor(emulatedInterfaceType);
+      if (emulatedInterfaceClazz == null || !emulatedInterfaceClazz.isProgramClass()) {
+        warnMissingEmulatedInterface(emulatedInterfaceType);
+        continue;
+      }
+      DexProgramClass emulatedInterface = emulatedInterfaceClazz.asProgramClass();
+      assert emulatedInterface != null;
+      if (!appView.isAlreadyLibraryDesugared(emulatedInterface)
+          && needsEmulateInterfaceLibrary(emulatedInterface)) {
+        synthesizeProgramEmulatedInterface(emulatedInterface, eventConsumer);
+      }
+    }
+  }
+
+  private boolean needsEmulateInterfaceLibrary(DexClass emulatedInterface) {
+    return Iterables.any(emulatedInterface.methods(), DexEncodedMethod::isDefaultMethod);
   }
 
   private void warnMissingEmulatedInterface(DexType interfaceType) {
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index 0c1e782..e156407 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -665,6 +665,7 @@
             || getMissingClasses().contains(type)
             // TODO(b/150693139): Remove these exceptions once fixed.
             || InterfaceDesugaringSyntheticHelper.isCompanionClassType(type)
+            || InterfaceDesugaringSyntheticHelper.isEmulatedLibraryClassType(type)
             // TODO(b/150736225): Not sure how to remove these.
             || DesugaredLibraryAPIConverter.isVivifiedType(type)
         : "Failed lookup of non-missing type: " + type;
diff --git a/src/main/java/com/android/tools/r8/shaking/L8TreePruner.java b/src/main/java/com/android/tools/r8/shaking/L8TreePruner.java
index ab0a04d..960ccd5 100644
--- a/src/main/java/com/android/tools/r8/shaking/L8TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/L8TreePruner.java
@@ -28,9 +28,9 @@
 
   public L8TreePruner(InternalOptions options) {
     this.options = options;
-    backports.addAll(options.machineDesugaredLibrarySpecification.getLegacyBackport().keySet());
+    backports.addAll(options.desugaredLibrarySpecification.getBackportCoreLibraryMember().keySet());
     emulatedInterfaces.addAll(
-        options.machineDesugaredLibrarySpecification.getEmulatedInterfaces().keySet());
+        options.desugaredLibrarySpecification.getEmulateLibraryInterface().keySet());
   }
 
   public DexApplication prune(DexApplication app, PrefixRewritingMapper rewritePrefix) {
diff --git a/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java b/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java
index 604748a..bbf4258 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java
@@ -129,7 +129,12 @@
       return;
     }
     assert hygienicType.toSourceString().startsWith(synthesizingContextType.toSourceString());
-    DexType rewrittenContext = appView.rewritePrefix.rewrittenContextType(synthesizingContextType);
+    DexType rewrittenContext =
+        appView
+            .options()
+            .desugaredLibrarySpecification
+            .getEmulateLibraryInterface()
+            .get(synthesizingContextType);
     if (rewrittenContext == null) {
       return;
     }
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
index 6d45ee1..0cb0137 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
@@ -483,7 +483,8 @@
       AppView<?> appView,
       DexType type) {
     DexType rewrittenContextType =
-        appView.rewritePrefix.rewrittenContextType(outerContext.getSynthesizingContextType());
+        appView.rewritePrefix.rewrittenContextType(
+            outerContext.getSynthesizingContextType(), appView);
     if (rewrittenContextType == null) {
       return;
     }
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 467ac25..ec5dca6 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -54,11 +54,8 @@
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.desugar.PrefixRewritingMapper;
 import com.android.tools.r8.ir.desugar.PrefixRewritingMapper.MachineDesugarPrefixRewritingMapper;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecification;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.HumanToMachineSpecificationConverter;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.LegacyToHumanSpecificationConverter;
 import com.android.tools.r8.ir.desugar.nest.Nest;
 import com.android.tools.r8.ir.optimize.Inliner;
 import com.android.tools.r8.ir.optimize.enums.EnumDataMap;
@@ -88,9 +85,7 @@
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
-import java.io.IOException;
 import java.io.PrintStream;
-import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -395,8 +390,8 @@
     if (isGeneratingDex() || desugarState == DesugarState.ON) {
       marker.setMinApi(getMinApiLevel().getLevel());
     }
-    if (machineDesugaredLibrarySpecification.getIdentifier() != null) {
-      marker.setDesugaredLibraryIdentifiers(machineDesugaredLibrarySpecification.getIdentifier());
+    if (desugaredLibrarySpecification.getIdentifier() != null) {
+      marker.setDesugaredLibraryIdentifiers(desugaredLibrarySpecification.getIdentifier());
     }
     if (Version.isDevelopmentVersion()) {
       marker.setSha1(VersionProperties.INSTANCE.getSha());
@@ -443,7 +438,7 @@
   }
 
   public boolean isDesugaredLibraryCompilation() {
-    return machineDesugaredLibrarySpecification.isLibraryCompilation();
+    return desugaredLibrarySpecification.isLibraryCompilation();
   }
 
   public boolean isRelocatorCompilation() {
@@ -893,51 +888,13 @@
   public LegacyDesugaredLibrarySpecification desugaredLibrarySpecification =
       LegacyDesugaredLibrarySpecification.empty();
 
-  public void setDesugaredLibrarySpecification(
-      LegacyDesugaredLibrarySpecification specification, AndroidApp app) {
-    if (specification.isEmptyConfiguration()) {
-      return;
-    }
-    desugaredLibrarySpecification = specification;
-    try {
-      HumanDesugaredLibrarySpecification human =
-          new LegacyToHumanSpecificationConverter()
-              .convert(specification, app.getLibraryResourceProviders(), this);
-      machineDesugaredLibrarySpecification =
-          new HumanToMachineSpecificationConverter()
-              .convert(
-                  human,
-                  specification.isLibraryCompilation() ? app.getProgramResourceProviders() : null,
-                  app.getLibraryResourceProviders(),
-                  this);
-    } catch (IOException e) {
-      reporter.error(new ExceptionDiagnostic(e, Origin.unknown()));
-    }
-  }
-
-  public void setDesugaredLibrarySpecificationForTesting(
-      LegacyDesugaredLibrarySpecification specification, Path desugaredJDKLib, Path library)
-      throws IOException {
-    desugaredLibrarySpecification = specification;
-    HumanDesugaredLibrarySpecification human =
-        new LegacyToHumanSpecificationConverter().convert(specification, library, this);
-    machineDesugaredLibrarySpecification =
-        new HumanToMachineSpecificationConverter()
-            .convert(
-                human,
-                specification.isLibraryCompilation() ? desugaredJDKLib : null,
-                library,
-                this);
-  }
-
-  // Meant to replace desugaredLibrarySpecification, set only from tests at the moment.
-  public MachineDesugaredLibrarySpecification machineDesugaredLibrarySpecification =
-      MachineDesugaredLibrarySpecification.empty();
-
   public PrefixRewritingMapper getPrefixRewritingMapper() {
-    return machineDesugaredLibrarySpecification.getRewriteType().isEmpty()
-        ? PrefixRewritingMapper.empty()
-        : new MachineDesugarPrefixRewritingMapper(machineDesugaredLibrarySpecification);
+    if (testing.machineDesugaredLibrarySpecification != null) {
+      return new MachineDesugarPrefixRewritingMapper(
+          desugaredLibrarySpecification.getPrefixRewritingMapper(),
+          testing.machineDesugaredLibrarySpecification.getRewritingFlags());
+    }
+    return desugaredLibrarySpecification.getPrefixRewritingMapper();
   }
 
   public boolean relocatorCompilation = false;
@@ -1642,6 +1599,9 @@
 
     public Consumer<Deque<ProgramMethodSet>> waveModifier = waves -> {};
 
+    // Meant to replace desugaredLibrarySpecification, set only from tests at the moment.
+    public MachineDesugaredLibrarySpecification machineDesugaredLibrarySpecification = null;
+
     /**
      * If this flag is enabled, we will also compute the set of possible targets for invoke-
      * interface and invoke-virtual instructions that target a library method, and add the
diff --git a/src/test/java/com/android/tools/r8/BackportedMethodListTest.java b/src/test/java/com/android/tools/r8/BackportedMethodListTest.java
index 6ed9d46..706126c 100644
--- a/src/test/java/com/android/tools/r8/BackportedMethodListTest.java
+++ b/src/test/java/com/android/tools/r8/BackportedMethodListTest.java
@@ -155,8 +155,8 @@
               .setConsumer(new ListStringConsumer())
               .build());
       fail("Expected failure");
-    } catch (Throwable e) {
-      // This should throw a CompilationFailedException but an assertion is failing first.
+    } catch (CompilationFailedException e) {
+      // Expected.
     }
   }
 }
diff --git a/src/test/java/com/android/tools/r8/D8CommandTest.java b/src/test/java/com/android/tools/r8/D8CommandTest.java
index cf095b1..9740064 100644
--- a/src/test/java/com/android/tools/r8/D8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/D8CommandTest.java
@@ -632,18 +632,9 @@
 
   @Test
   public void desugaredLibrary() throws CompilationFailedException {
-    D8Command d8Command =
-        parse(
-            "--desugared-lib",
-            "src/library_desugar/desugar_jdk_libs.json",
-            "--lib",
-            ToolHelper.getAndroidJar(AndroidApiLevel.P).toString());
+    D8Command d8Command = parse("--desugared-lib", "src/library_desugar/desugar_jdk_libs.json");
     assertFalse(
-        d8Command
-            .getInternalOptions()
-            .machineDesugaredLibrarySpecification
-            .getRewriteType()
-            .isEmpty());
+        d8Command.getInternalOptions().desugaredLibrarySpecification.getRewritePrefix().isEmpty());
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/L8CommandTest.java b/src/test/java/com/android/tools/r8/L8CommandTest.java
index 358d863..e1902f4 100644
--- a/src/test/java/com/android/tools/r8/L8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/L8CommandTest.java
@@ -355,17 +355,9 @@
   @Test
   public void desugaredLibrary() throws CompilationFailedException {
     L8Command l8Command =
-        parse(
-            "--desugared-lib",
-            ToolHelper.getDesugarLibJsonForTesting().toString(),
-            "--lib",
-            ToolHelper.getAndroidJar(AndroidApiLevel.P).toString());
+        parse("--desugared-lib", ToolHelper.getDesugarLibJsonForTesting().toString());
     assertFalse(
-        l8Command
-            .getInternalOptions()
-            .machineDesugaredLibrarySpecification
-            .getRewriteType()
-            .isEmpty());
+        l8Command.getInternalOptions().desugaredLibrarySpecification.getRewritePrefix().isEmpty());
   }
 
   private void checkSingleForceAllAssertion(
diff --git a/src/test/java/com/android/tools/r8/L8TestBuilder.java b/src/test/java/com/android/tools/r8/L8TestBuilder.java
index 7a42ab1..44202c6 100644
--- a/src/test/java/com/android/tools/r8/L8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/L8TestBuilder.java
@@ -108,10 +108,6 @@
     return this;
   }
 
-  public TestDiagnosticMessages getDiagnosticMessages() {
-    return state.getDiagnosticsMessages();
-  }
-
   public L8TestBuilder setDebug() {
     this.mode = CompilationMode.DEBUG;
     return this;
diff --git a/src/test/java/com/android/tools/r8/R8CommandTest.java b/src/test/java/com/android/tools/r8/R8CommandTest.java
index 325344f..0b48fc2 100644
--- a/src/test/java/com/android/tools/r8/R8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/R8CommandTest.java
@@ -763,18 +763,9 @@
 
   @Test
   public void desugaredLibrary() throws CompilationFailedException {
-    R8Command r8Command =
-        parse(
-            "--desugared-lib",
-            "src/library_desugar/desugar_jdk_libs.json",
-            "--lib",
-            ToolHelper.getAndroidJar(AndroidApiLevel.P).toString());
+    R8Command r8Command = parse("--desugared-lib", "src/library_desugar/desugar_jdk_libs.json");
     assertFalse(
-        r8Command
-            .getInternalOptions()
-            .machineDesugaredLibrarySpecification
-            .getRewriteType()
-            .isEmpty());
+        r8Command.getInternalOptions().desugaredLibrarySpecification.getRewritePrefix().isEmpty());
   }
 
   @Test
@@ -784,16 +775,10 @@
         parse(
             "--desugared-lib",
             "src/library_desugar/desugar_jdk_libs.json",
-            "--lib",
-            ToolHelper.getAndroidJar(AndroidApiLevel.P).toString(),
             "--desugared-lib-pg-conf-output",
             pgout.toString());
     assertFalse(
-        r8Command
-            .getInternalOptions()
-            .machineDesugaredLibrarySpecification
-            .getRewriteType()
-            .isEmpty());
+        r8Command.getInternalOptions().desugaredLibrarySpecification.getRewritePrefix().isEmpty());
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/desugar/InvokeSuperToRewrittenDefaultMethodTest.java b/src/test/java/com/android/tools/r8/desugar/InvokeSuperToRewrittenDefaultMethodTest.java
index c8f932d..72cdc59 100644
--- a/src/test/java/com/android/tools/r8/desugar/InvokeSuperToRewrittenDefaultMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/InvokeSuperToRewrittenDefaultMethodTest.java
@@ -3,15 +3,23 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.desugar;
 
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
+import static org.hamcrest.CoreMatchers.allOf;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
 
+import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.LibraryDesugaringTestConfiguration;
-import com.android.tools.r8.TestDiagnosticMessages;
 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.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.ExceptionDiagnostic;
 import com.android.tools.r8.utils.StringUtils;
 import java.util.List;
 import java.util.function.Consumer;
@@ -25,15 +33,19 @@
 
   private static final String EXPECTED = StringUtils.lines("Y", "89");
 
-  @Parameterized.Parameters(name = "{0}")
+  @Parameterized.Parameters(name = "{0}, old-rt:{1}")
   public static List<Object[]> data() {
-    return buildParameters(getTestParameters().withAllRuntimesAndApiLevels().build());
+    return buildParameters(
+        getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values());
   }
 
   private final TestParameters parameters;
+  private final boolean rtWithoutConsumer;
 
-  public InvokeSuperToRewrittenDefaultMethodTest(TestParameters parameters) {
+  public InvokeSuperToRewrittenDefaultMethodTest(
+      TestParameters parameters, boolean rtWithoutConsumer) {
     this.parameters = parameters;
+    this.rtWithoutConsumer = rtWithoutConsumer;
   }
 
   private boolean needsDefaultInterfaceMethodDesugaring() {
@@ -53,15 +65,35 @@
   @Test
   public void testDesugaring() throws Exception {
     assumeTrue(needsDefaultInterfaceMethodDesugaring());
-    testForD8()
-        .addInnerClasses(InvokeSuperToRewrittenDefaultMethodTest.class)
-        .setMinApi(parameters.getApiLevel())
-        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
-        .enableCoreLibraryDesugaring(
-            LibraryDesugaringTestConfiguration.forApiLevel(parameters.getApiLevel()))
-        .compileWithExpectedDiagnostics(TestDiagnosticMessages::assertNoMessages)
-        .run(parameters.getRuntime(), TestClass.class)
-        .assertSuccessWithOutput(EXPECTED);
+    try {
+      testForD8()
+          .addInnerClasses(InvokeSuperToRewrittenDefaultMethodTest.class)
+          .setMinApi(parameters.getApiLevel())
+          .addLibraryFiles(
+              rtWithoutConsumer
+                  ? ToolHelper.getAndroidJar(AndroidApiLevel.B)
+                  : ToolHelper.getAndroidJar(AndroidApiLevel.P))
+          .enableCoreLibraryDesugaring(
+              LibraryDesugaringTestConfiguration.forApiLevel(parameters.getApiLevel()))
+          .compileWithExpectedDiagnostics(
+              diagnostics -> {
+                if (rtWithoutConsumer) {
+                  diagnostics.assertOnlyErrors();
+                  // TODO(b/158543011): Should fail with a nice user error for invalid library.
+                  diagnostics.assertErrorsMatch(
+                      allOf(
+                          diagnosticType(ExceptionDiagnostic.class),
+                          diagnosticMessage(containsString("AssertionError"))));
+                } else {
+                  diagnostics.assertNoMessages();
+                }
+              })
+          .run(parameters.getRuntime(), TestClass.class)
+          .assertSuccessWithOutput(EXPECTED);
+      assertFalse(rtWithoutConsumer);
+    } catch (CompilationFailedException e) {
+      assertTrue(rtWithoutConsumer);
+    }
   }
 
   public interface CharConsumer extends Consumer<Character>, IntConsumer {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java
index b5e5c03..6b54606 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java
@@ -73,13 +73,11 @@
   }
 
   private void configurationForProgramCompilation(InternalOptions options) {
-    setDesugaredLibrarySpecificationForTesting(
-        options, configurationAlternative3(options, false, parameters));
+    options.desugaredLibrarySpecification = configurationAlternative3(options, false, parameters);
   }
 
   private void configurationForLibraryCompilation(InternalOptions options) {
-    setDesugaredLibrarySpecificationForTesting(
-        options, configurationAlternative3(options, true, parameters));
+    options.desugaredLibrarySpecification = configurationAlternative3(options, true, parameters);
   }
 
   @Test
@@ -143,7 +141,10 @@
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
         .addLibraryFiles(getLibraryFile())
-        .addOptionsModification(this::configurationForProgramCompilation)
+        .addOptionsModification(
+            options ->
+                options.desugaredLibrarySpecification =
+                    configurationAlternative3(options, false, parameters))
         .addInnerClasses(BufferedReaderTest.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -169,7 +170,10 @@
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
         .addLibraryFiles(getLibraryFile())
-        .addOptionsModification(this::configurationForProgramCompilation)
+        .addOptionsModification(
+            options ->
+                options.desugaredLibrarySpecification =
+                    configurationAlternative3(options, false, parameters))
         .addInnerClasses(BufferedReaderTest.class)
         .addKeepMainRule(TestClass.class)
         .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionTest.java
index 473153c..d1e9746 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionTest.java
@@ -10,11 +10,17 @@
 import com.android.tools.r8.D8TestRunResult;
 import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.HumanToMachineSpecificationConverter;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.LegacyToHumanSpecificationConverter;
 import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject.JumboStringMode;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import java.io.IOException;
 import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -34,15 +40,19 @@
 
   private final TestParameters parameters;
   private final boolean shrinkDesugaredLibrary;
+  private final boolean machineSpec;
 
-  @Parameters(name = "machine: {0}, shrink: {1}")
+  @Parameters(name = "machine: {0}, {2}, shrink: {1}")
   public static List<Object[]> data() {
     return buildParameters(
         BooleanUtils.values(),
+        BooleanUtils.values(),
         getTestParameters().withDexRuntimes().withAllApiLevels().build());
   }
 
-  public CustomCollectionTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
+  public CustomCollectionTest(
+      boolean machineSpec, boolean shrinkDesugaredLibrary, TestParameters parameters) {
+    this.machineSpec = machineSpec;
     this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
     this.parameters = parameters;
   }
@@ -50,6 +60,22 @@
   private final String EXECUTOR =
       "com.android.tools.r8.desugar.desugaredlibrary.CustomCollectionTest$Executor";
 
+  private void setMachineSpec(InternalOptions opt) {
+    if (!machineSpec) {
+      return;
+    }
+    try {
+      HumanDesugaredLibrarySpecification human =
+          new LegacyToHumanSpecificationConverter()
+              .convert(opt.desugaredLibrarySpecification, getLibraryFile(), opt);
+      MachineDesugaredLibrarySpecification machine =
+          new HumanToMachineSpecificationConverter().convert(human, getLibraryFile(), opt);
+      opt.testing.machineDesugaredLibrarySpecification = machine;
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
   @Test
   public void testCustomCollectionD8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
@@ -57,6 +83,7 @@
         testForD8()
             .addLibraryFiles(getLibraryFile())
             .addInnerClasses(CustomCollectionTest.class)
+            .addOptionsModification(this::setMachineSpec)
             .setMinApi(parameters.getApiLevel())
             .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
             .compile()
@@ -79,6 +106,7 @@
     Path jar =
         testForD8(Backend.CF)
             .addInnerClasses(CustomCollectionTest.class)
+            .addOptionsModification(this::setMachineSpec)
             .setMinApi(parameters.getApiLevel())
             .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
             .compile()
@@ -134,6 +162,7 @@
         testForR8(Backend.DEX)
             .addLibraryFiles(getLibraryFile())
             .addInnerClasses(CustomCollectionTest.class)
+            .addOptionsModification(this::setMachineSpec)
             .setMinApi(parameters.getApiLevel())
             .addKeepClassAndMembersRules(Executor.class)
             .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCHMOnlyContentTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCHMOnlyContentTest.java
index e27dda9..3e7d97d 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCHMOnlyContentTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCHMOnlyContentTest.java
@@ -43,9 +43,10 @@
             "",
             false,
             Collections.emptyList(),
-            options ->
-                setDesugaredLibrarySpecificationForTesting(
-                    options, chmOnlyConfiguration(options, true, parameters)));
+            options -> {
+              options.desugaredLibrarySpecification =
+                  chmOnlyConfiguration(options, true, parameters);
+            });
     CodeInspector inspector = new CodeInspector(desugaredLib);
     assert inspector.clazz("j$.util.concurrent.ConcurrentHashMap").isPresent();
   }
@@ -60,9 +61,10 @@
             "-keep class * { *; }",
             true,
             Collections.emptyList(),
-            options ->
-                setDesugaredLibrarySpecificationForTesting(
-                    options, chmOnlyConfiguration(options, true, parameters)));
+            options -> {
+              options.desugaredLibrarySpecification =
+                  chmOnlyConfiguration(options, true, parameters);
+            });
     CodeInspector inspector = new CodeInspector(desugaredLib);
     assert inspector.clazz("j$.util.concurrent.ConcurrentHashMap").isPresent();
   }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java
index 819aa45..e353126 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java
@@ -5,19 +5,15 @@
 package com.android.tools.r8.desugar.desugaredlibrary;
 
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static junit.framework.TestCase.assertEquals;
 import static junit.framework.TestCase.assertTrue;
 import static org.hamcrest.CoreMatchers.startsWith;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.fail;
 
 import com.android.tools.r8.L8Command;
-import com.android.tools.r8.L8TestBuilder;
 import com.android.tools.r8.OutputMode;
 import com.android.tools.r8.StringResource;
-import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestDiagnosticMessagesImpl;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -29,7 +25,6 @@
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import java.nio.file.Path;
 import java.util.ArrayList;
-import java.util.Collections;
 import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -50,33 +45,6 @@
   }
 
   @Test
-  public void testInvalidLibrary() throws Exception {
-    Assume.assumeTrue(requiresAnyCoreLibDesugaring(parameters));
-    L8TestBuilder l8TestBuilder =
-        testForL8(parameters.getApiLevel())
-            .addProgramFiles(Collections.singleton(ToolHelper.getDesugarJDKLibs()))
-            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.L))
-            .setDesugarJDKLibsConfiguration(ToolHelper.DESUGAR_LIB_CONVERSIONS);
-    try {
-      l8TestBuilder.compile();
-      fail();
-    } catch (AssertionError ae) {
-      // Expected since the library is invalid.
-    }
-    TestDiagnosticMessages diagnosticMessages = l8TestBuilder.getDiagnosticMessages();
-    diagnosticMessages.assertOnlyWarnings();
-    assertEquals(diagnosticMessages.getWarnings().size(), 1);
-    assertTrue(
-        diagnosticMessages
-            .getWarnings()
-            .get(0)
-            .getDiagnosticMessage()
-            .contains(
-                "Desugared library requires to be compiled with a library file of API greater or"
-                    + " equal to"));
-  }
-
-  @Test
   public void testDesugaredLibraryContentD8() throws Exception {
     Assume.assumeTrue(requiresAnyCoreLibDesugaring(parameters));
     CodeInspector inspector = new CodeInspector(buildDesugaredLibrary(parameters.getApiLevel()));
@@ -121,16 +89,11 @@
     ToolHelper.runL8(l8Builder.build(), options -> {});
     CodeInspector codeInspector = new CodeInspector(desugaredLib);
     assertCorrect(codeInspector);
-    assertOneWarning(diagnosticsHandler);
+    assertNoWarningsErrors(diagnosticsHandler);
   }
 
-  private void assertOneWarning(TestDiagnosticMessagesImpl diagnosticsHandler) {
-    assertEquals(1, diagnosticsHandler.getWarnings().size());
-    String msg = diagnosticsHandler.getWarnings().get(0).getDiagnosticMessage();
-    assertTrue(
-        msg.contains(
-            "The following library types, prefixed by java., are present both as library and non"
-                + " library classes"));
+  private void assertNoWarningsErrors(TestDiagnosticMessagesImpl diagnosticsHandler) {
+    assertTrue(diagnosticsHandler.getWarnings().isEmpty());
     assertTrue(diagnosticsHandler.getErrors().isEmpty());
   }
 
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java
index a3832c1..34faa58 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java
@@ -67,18 +67,6 @@
     return property.contains("jdk11");
   }
 
-  public void setDesugaredLibrarySpecificationForTesting(
-      InternalOptions options, LegacyDesugaredLibrarySpecification specification) {
-    try {
-      options.setDesugaredLibrarySpecificationForTesting(
-          specification,
-          ToolHelper.getDesugarJDKLibs(),
-          ToolHelper.getAndroidJar(AndroidApiLevel.R));
-    } catch (IOException e) {
-      throw new RuntimeException(e);
-    }
-  }
-
   // For conversions tests, we need DexRuntimes where classes to convert are present (DexRuntimes
   // above N and O depending if Stream or Time APIs are used), but we need to compile the program
   // with a minAPI below to force the use of conversions.
@@ -101,7 +89,7 @@
 
   protected Path getLibraryFile() {
     return isJDK11DesugaredLibrary()
-        ? ToolHelper.getAndroidJar(AndroidApiLevel.R)
+        ? ToolHelper.getAndroidJar(AndroidApiLevel.S)
         : ToolHelper.getAndroidJar(AndroidApiLevel.P);
   }
 
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryWarningTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryWarningTest.java
index e1a8586..0c61a06 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryWarningTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryWarningTest.java
@@ -4,9 +4,6 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
 import com.android.tools.r8.CompilationMode;
 import com.android.tools.r8.L8Command;
 import com.android.tools.r8.OutputMode;
@@ -68,15 +65,6 @@
           Arrays.asList(FUNCTION_KEEP.split(System.lineSeparator())), Origin.unknown());
     }
     ToolHelper.runL8(l8Builder.build(), options -> {});
-    assertEquals(diagnosticsHandler.getWarnings().size(), 1);
-    diagnosticsHandler.assertNoErrors();
-    assertTrue(
-        diagnosticsHandler
-            .getWarnings()
-            .get(0)
-            .getDiagnosticMessage()
-            .contains(
-                "The following library types, prefixed by java., are present both as library and"
-                    + " non library classes:"));
+    diagnosticsHandler.assertNoMessages();
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InconsistentPrefixTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InconsistentPrefixTest.java
new file mode 100644
index 0000000..b1f57e1
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InconsistentPrefixTest.java
@@ -0,0 +1,59 @@
+// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.desugar.desugaredlibrary;
+
+import static org.hamcrest.CoreMatchers.containsString;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.jasmin.JasminBuilder;
+import java.nio.file.Path;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class InconsistentPrefixTest extends TestBase {
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withNoneRuntime().build();
+  }
+
+  public InconsistentPrefixTest(TestParameters parameters) {
+    parameters.assertNoneRuntime();
+  }
+
+  @Test(expected = CompilationFailedException.class)
+  public void testNoInconsistentPrefixes() throws Exception {
+    Map<String, String> x = new HashMap<>();
+    x.put("pkg.sub", "p$.bus");
+    x.put("pkg", "p$");
+
+    JasminBuilder jasminBuilder = new JasminBuilder();
+    jasminBuilder.addClass("pkg/notsub/A");
+    jasminBuilder.addClass("pkg/sub/A");
+    Path inputJar = temp.getRoot().toPath().resolve("input.jar");
+    jasminBuilder.writeJar(inputJar);
+
+    testForD8()
+        .addProgramFiles(inputJar)
+        .addOptionsModification(
+            options ->
+                options.desugaredLibrarySpecification =
+                    LegacyDesugaredLibrarySpecification.withOnlyRewritePrefixForTesting(x, options))
+        .compileWithExpectedDiagnostics(
+            diagnostics -> {
+              diagnostics.assertErrorMessageThatMatches(
+                  containsString("Inconsistent prefix in desugared library"));
+            });
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/J$ExtensionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/J$ExtensionTest.java
index 371443d..88f3ca9 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/J$ExtensionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/J$ExtensionTest.java
@@ -5,12 +5,15 @@
 package com.android.tools.r8.desugar.desugaredlibrary;
 
 import static junit.framework.TestCase.assertTrue;
+import static junit.framework.TestCase.fail;
 
+import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestRuntime;
 import com.android.tools.r8.TestRuntime.CfVm;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.utils.BooleanUtils;
 import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileWriter;
@@ -28,6 +31,7 @@
 public class J$ExtensionTest extends DesugaredLibraryTestBase {
 
   private final TestParameters parameters;
+  private final boolean shrinkDesugaredLibrary;
 
   private static final String MAIN_CLASS_NAME = "Main";
   private static final String MAIN_CLASS =
@@ -51,12 +55,14 @@
           + "}";
   private static Path[] compiledClasses = new Path[2];
 
-  @Parameters(name = "{0}")
+  @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
   public static List<Object[]> data() {
-    return buildParameters(getTestParameters().withAllRuntimes().withAllApiLevels().build());
+    return buildParameters(
+        BooleanUtils.values(), getTestParameters().withAllRuntimes().withAllApiLevels().build());
   }
 
-  public J$ExtensionTest(TestParameters parameters) {
+  public J$ExtensionTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
+    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
     this.parameters = parameters;
   }
 
@@ -86,6 +92,7 @@
 
   @Test
   public void testJ$ExtensionNoDesugaring() throws Exception {
+    Assume.assumeFalse(shrinkDesugaredLibrary);
     String stderr;
     if (parameters.isCfRuntime()) {
       stderr =
@@ -103,31 +110,24 @@
               .assertFailure()
               .getStdErr();
     }
-    assertError(stderr, false);
+    assertError(stderr);
   }
 
-  private void assertError(String stderr, boolean desugaring) {
-    if (parameters.isCfRuntime()) {
-      if (parameters.getRuntime().asCf().getVm() == CfVm.JDK8) {
-        assertTrue(
-            stderr.contains("java.lang.SecurityException: Prohibited package name: java.time"));
-      } else {
-        assertTrue(stderr.contains("java.lang.ClassNotFoundException: java.time.LocalTimeAccess"));
-      }
-      return;
-    }
-    assert !parameters.isCfRuntime();
-    if (!desugaring) {
-      if (parameters.getDexRuntimeVersion().isOlderThanOrEqual(Version.V6_0_1)) {
-        assertTrue(stderr.contains("java.lang.NoClassDefFoundError"));
-      } else if (parameters.getDexRuntimeVersion() == Version.V7_0_0) {
-        assertTrue(stderr.contains("java.lang.ClassNotFoundException"));
-      }
-      return;
-    }
-    if (parameters.getDexRuntimeVersion() == Version.V8_1_0) {
-      // On Android 8 the library package private method is accessible.
-      assertTrue(stderr.contains("java.lang.NullPointerException"));
+  private void assertError(String stderr) {
+    if (parameters.isCfRuntime() && parameters.getRuntime().asCf().getVm() == CfVm.JDK8) {
+      assertTrue(
+          stderr.contains("java.lang.SecurityException: Prohibited package name: java.time"));
+    } else if (parameters.isCfRuntime()) {
+      assertTrue(stderr.contains("java.lang.ClassNotFoundException: java.time.LocalTimeAccess"));
+    } else if (parameters
+        .getRuntime()
+        .asDex()
+        .getVm()
+        .getVersion()
+        .isOlderThanOrEqual(Version.V6_0_1)) {
+      assertTrue(stderr.contains("java.lang.NoClassDefFoundError"));
+    } else if (parameters.getRuntime().asDex().getVm().getVersion() == Version.V7_0_0) {
+      assertTrue(stderr.contains("java.lang.ClassNotFoundException"));
     } else {
       assertTrue(stderr.contains("java.lang.IllegalAccessError"));
     }
@@ -140,18 +140,19 @@
     Assume.assumeTrue(requiresTimeDesugaring(parameters));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
 
-    String stdErr =
-        testForD8()
-            .addLibraryFiles(getLibraryFile())
-            .addProgramFiles(compiledClasses)
-            .setMinApi(parameters.getApiLevel())
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-            .compile()
-            .addDesugaredCoreLibraryRunClassPath(
-                this::buildDesugaredLibrary, parameters.getApiLevel())
-            .run(parameters.getRuntime(), MAIN_CLASS_NAME)
-            .assertFailure()
-            .getStdErr();
-    assertError(stdErr, true);
+    try {
+      testForD8()
+          .addLibraryFiles(getLibraryFile())
+          .addProgramFiles(compiledClasses)
+          .setMinApi(parameters.getApiLevel())
+          .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+          .compile();
+      fail();
+    } catch (CompilationFailedException e) {
+      assertTrue(
+          e.getCause()
+              .getMessage()
+              .contains("Cannot compile program class java.time.LocalTimeAccess"));
+    }
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
index d78df31..6598d6b 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
@@ -144,22 +144,16 @@
             .map(TypeSubject::toString)
             .collect(Collectors.toSet());
     assertEquals(expectedCatchGuards, foundCatchGuards);
-    if (!(parameters
-            .getApiLevel()
-            .isGreaterThanOrEqualTo(TestBase.apiLevelWithDefaultInterfaceMethodsSupport())
-        && isR8)) {
+
+    if (isR8) {
+      assertThat(
+          inspector.clazz(TemporalAccessorImpl.class).uniqueMethodWithFinalName("query"),
+          not(isPresent()));
+    } else {
       assertThat(
           inspector.clazz(TemporalAccessorImplSub.class).uniqueMethodWithFinalName("query"),
           CodeMatchers.invokesMethod(
-              null, inspector.clazz(TemporalAccessorImpl.class).getFinalName(), "query", null));
-    } else {
-      String holder =
-          requiresTimeDesugaring(parameters)
-              ? "j$.time.temporal.TemporalAccessor"
-              : "java.time.temporal.TemporalAccessor";
-      assertThat(
-          inspector.clazz(TemporalAccessorImplSub.class).uniqueMethodWithFinalName("query"),
-          CodeMatchers.invokesMethod(null, holder, "query", null));
+              null, TemporalAccessorImpl.class.getTypeName(), "query", null));
     }
     if (parameters
         .getApiLevel()
@@ -169,7 +163,9 @@
           not(isPresent()));
     } else {
       assertThat(
-          inspector.clazz(TemporalAccessorImpl.class).uniqueMethodWithFinalName("query"),
+          inspector
+              .clazz(isR8 ? TemporalAccessorImplSub.class : TemporalAccessorImpl.class)
+              .uniqueMethodWithFinalName("query"),
           CodeMatchers.invokesMethod(
               null, "j$.time.temporal.TemporalAccessor$-CC", "$default$query", null));
     }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LinkedHashSetTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LinkedHashSetTest.java
index de87214..981edea 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LinkedHashSetTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LinkedHashSetTest.java
@@ -11,7 +11,6 @@
 import java.util.Set;
 import java.util.Spliterator;
 import java.util.Spliterators;
-import java.util.function.Predicate;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -166,14 +165,6 @@
       System.out.println("true");
       System.out.println(spliterator.hasCharacteristics(Spliterator.IMMUTABLE));
       System.out.println("false");
-
-      spliterator = ((Set<String>) new CustomLinkedHashSetForceForwarding<String>()).spliterator();
-      System.out.println(spliterator.hasCharacteristics(Spliterator.DISTINCT));
-      System.out.println("true");
-      System.out.println(spliterator.hasCharacteristics(Spliterator.ORDERED));
-      System.out.println("true");
-      System.out.println(spliterator.hasCharacteristics(Spliterator.IMMUTABLE));
-      System.out.println("false");
     }
   }
 
@@ -207,13 +198,4 @@
       return super.spliterator();
     }
   }
-
-  // The over method force the forwarding methods to be installed.
-  static class CustomLinkedHashSetForceForwarding<E> extends LinkedHashSet<E> {
-
-    @Override
-    public boolean removeIf(Predicate<? super E> filter) {
-      return super.removeIf(filter);
-    }
-  }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingJ$Test.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingJ$Test.java
index 1208414..d5300ad 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingJ$Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingJ$Test.java
@@ -118,8 +118,8 @@
     L8.run(
         L8Command.builder()
             .addLibraryFiles(getLibraryFile())
-            .addLibraryFiles(ToolHelper.getDesugarJDKLibs())
             .addProgramFiles(JDK_11_JAVA_BASE_EXTENSION_COMPILED_FILES)
+            .addClasspathFiles(ToolHelper.getDesugarJDKLibs())
             .addDesugaredLibraryConfiguration(
                 StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
             .setMinApiLevel(AndroidApiLevel.B.getLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ObjectsTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ObjectsTest.java
index f3caf57..abdf5c5 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ObjectsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ObjectsTest.java
@@ -99,13 +99,13 @@
   }
 
   private void configurationForProgramCompilation(InternalOptions options) {
-    setDesugaredLibrarySpecificationForTesting(
-        options, desugaredLibrarySpecification(options, false, parameters));
+    options.desugaredLibrarySpecification =
+        desugaredLibrarySpecification(options, false, parameters);
   }
 
   private void configurationForLibraryCompilation(InternalOptions options) {
-    setDesugaredLibrarySpecificationForTesting(
-        options, desugaredLibrarySpecification(options, true, parameters));
+    options.desugaredLibrarySpecification =
+        desugaredLibrarySpecification(options, true, parameters);
   }
 
   private Matcher<MethodSubject> invokesObjectsCompare(String holder) {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetAndBackportTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetAndBackportTest.java
index 9b1804e..359a18c 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetAndBackportTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetAndBackportTest.java
@@ -7,7 +7,6 @@
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyRewritingFlags;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyTopLevelFlags;
@@ -15,7 +14,6 @@
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
-import java.io.IOException;
 import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -57,15 +55,9 @@
             .putBackportCoreLibraryMember("java.lang.DesugarMath", "java.lang.Math")
             .putRetargetCoreLibMember("java.util.Date#toInstant", "java.util.DesugarDate")
             .build();
-    try {
-      options.setDesugaredLibrarySpecificationForTesting(
-          new LegacyDesugaredLibrarySpecification(
-              LegacyTopLevelFlags.testing(), rewritingFlags, true),
-          ToolHelper.getDesugarJDKLibs(),
-          ToolHelper.getAndroidJar(AndroidApiLevel.R));
-    } catch (IOException e) {
-      throw new RuntimeException(e);
-    }
+    options.desugaredLibrarySpecification =
+        new LegacyDesugaredLibrarySpecification(
+            LegacyTopLevelFlags.testing(), rewritingFlags, true, options.itemFactory);
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetOverrideTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetOverrideTest.java
index e629c47..6bf49a0 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetOverrideTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetOverrideTest.java
@@ -5,7 +5,13 @@
 package com.android.tools.r8.desugar.desugaredlibrary;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.HumanToMachineSpecificationConverter;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.LegacyToHumanSpecificationConverter;
 import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.InternalOptions;
+import java.io.IOException;
 import java.nio.file.Path;
 import java.time.Instant;
 import java.time.ZonedDateTime;
@@ -25,15 +31,19 @@
 
   private final TestParameters parameters;
   private final boolean shrinkDesugaredLibrary;
+  private final boolean machineSpec;
 
   @Parameters(name = "machine: {0}, {2}, shrink: {1}")
   public static List<Object[]> data() {
     return buildParameters(
         BooleanUtils.values(),
+        BooleanUtils.values(),
         getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build());
   }
 
-  public RetargetOverrideTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
+  public RetargetOverrideTest(
+      boolean machineSpec, boolean shrinkDesugaredLibrary, TestParameters parameters) {
+    this.machineSpec = machineSpec;
     this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
     this.parameters = parameters;
   }
@@ -44,6 +54,7 @@
     Path desugaredTwice =
         testForD8(Backend.CF)
             .addLibraryFiles(getLibraryFile())
+            .addOptionsModification(this::setMachineSpec)
             .addProgramFiles(
                 testForD8(Backend.CF)
                     .addLibraryFiles(getLibraryFile())
@@ -65,6 +76,7 @@
       stdout =
           testForD8(Backend.DEX)
               .addProgramFiles(desugaredTwice)
+              .addOptionsModification(this::setMachineSpec)
               .setMinApi(parameters.getApiLevel())
               .disableDesugaring()
               .compile()
@@ -95,6 +107,22 @@
     assertLines2By2Correct(stdout);
   }
 
+  private void setMachineSpec(InternalOptions opt) {
+    if (!machineSpec) {
+      return;
+    }
+    try {
+      HumanDesugaredLibrarySpecification human =
+          new LegacyToHumanSpecificationConverter()
+              .convert(opt.desugaredLibrarySpecification, getLibraryFile(), opt);
+      MachineDesugaredLibrarySpecification machine =
+          new HumanToMachineSpecificationConverter().convert(human, getLibraryFile(), opt);
+      opt.testing.machineDesugaredLibrarySpecification = machine;
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
   @Test
   public void testRetargetOverrideD8() throws Exception {
     Assume.assumeTrue(parameters.getRuntime().isDex());
@@ -102,6 +130,7 @@
     String stdout =
         testForD8()
             .addLibraryFiles(getLibraryFile())
+            .addOptionsModification(this::setMachineSpec)
             .addInnerClasses(RetargetOverrideTest.class)
             .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
             .setMinApi(parameters.getApiLevel())
@@ -127,6 +156,7 @@
     String stdout =
         testForR8(Backend.DEX)
             .addLibraryFiles(getLibraryFile())
+            .addOptionsModification(this::setMachineSpec)
             .addKeepMainRule(Executor.class)
             .addInnerClasses(RetargetOverrideTest.class)
             .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/APIConversionFinalClassTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/APIConversionFinalClassTest.java
index 7abed46..f9d1828 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/APIConversionFinalClassTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/APIConversionFinalClassTest.java
@@ -58,7 +58,6 @@
         .setMinApi(AndroidApiLevel.B)
         .addProgramClasses(Executor.class)
         .addLibraryClasses(CustomLibClass.class)
-        .addLibraryFiles(getLibraryFile())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
         .compile()
         .addDesugaredCoreLibraryRunClassPath(
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/AccessModeConversionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/AccessModeConversionTest.java
index a57140b..6691cb1 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/AccessModeConversionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/AccessModeConversionTest.java
@@ -66,8 +66,8 @@
             .build();
     LegacyDesugaredLibrarySpecification specification =
         new LegacyDesugaredLibrarySpecification(
-            LegacyTopLevelFlags.testing(), rewritingFlags, l8Compilation);
-    setDesugaredLibrarySpecificationForTesting(options, specification);
+            LegacyTopLevelFlags.testing(), rewritingFlags, l8Compilation, options.itemFactory);
+    options.desugaredLibrarySpecification = specification;
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java
index 957515a..aa97e55 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java
@@ -87,10 +87,9 @@
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
         .addOptionsModification(
             opt ->
-                setDesugaredLibrarySpecificationForTesting(
-                    opt,
+                opt.desugaredLibrarySpecification =
                     configurationWithSupportAllCallbacksFromLibrary(
-                        opt, false, parameters, supportAllCallbacksFromLibrary)))
+                        opt, false, parameters, supportAllCallbacksFromLibrary))
         .compile()
         .inspect(this::assertDoubleForEach)
         .inspect(this::assertWrapperMethodsPresent)
@@ -152,10 +151,9 @@
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
         .addOptionsModification(
             opt ->
-                setDesugaredLibrarySpecificationForTesting(
-                    opt,
+                opt.desugaredLibrarySpecification =
                     configurationWithSupportAllCallbacksFromLibrary(
-                        opt, false, parameters, supportAllCallbacksFromLibrary)))
+                        opt, false, parameters, supportAllCallbacksFromLibrary))
         .compile()
         .inspect(this::assertDoubleForEach)
         .inspect(this::assertWrapperMethodsPresent)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIDesugaredLibTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIDesugaredLibTest.java
index b966b00..6b7d86e 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIDesugaredLibTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIDesugaredLibTest.java
@@ -71,10 +71,9 @@
                         this.buildDesugaredLibrary(
                             api,
                             opt ->
-                                setDesugaredLibrarySpecificationForTesting(
-                                    opt,
+                                opt.desugaredLibrarySpecification =
                                     configurationWithSupportAllCallbacksFromLibrary(
-                                        opt, true, parameters, supportAllCallbacksFromLibrary))));
+                                        opt, true, parameters, supportAllCallbacksFromLibrary)));
                     return desugaredLibBox.get();
                   },
                   AndroidApiLevel.B)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/TryCatchTimeConversionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/TryCatchTimeConversionTest.java
index aaab5cb..a669527 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/TryCatchTimeConversionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/TryCatchTimeConversionTest.java
@@ -58,7 +58,6 @@
         .setMinApi(parameters.getApiLevel())
         .addProgramClasses(BaselineExecutor.class)
         .addLibraryClasses(CustomLibClass.class)
-        .addLibraryFiles(getLibraryFile())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
         .compile()
         .addDesugaredCoreLibraryRunClassPath(
@@ -99,7 +98,6 @@
         .setMinApi(parameters.getApiLevel())
         .addProgramClasses(TryCatchExecutor.class)
         .addLibraryClasses(CustomLibClass.class)
-        .addLibraryFiles(getLibraryFile())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
         .compile()
         .addDesugaredCoreLibraryRunClassPath(
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11StreamTests.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11StreamTests.java
index 3b6ae0a..2bd50b2 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11StreamTests.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11StreamTests.java
@@ -270,7 +270,6 @@
               .addProgramFiles(testNGSupportProgramFiles())
               .addOptionsModification(opt -> opt.testing.trackDesugaredAPIConversions = true)
               .addLibraryFiles(getLibraryFile())
-              .addLibraryFiles(JDK_11_JAVA_BASE_EXTENSION_CLASSES_DIR)
               .setMinApi(parameters.getApiLevel())
               .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
               .allowStdoutMessages()
@@ -304,7 +303,6 @@
           .addProgramFiles(testNGSupportProgramFiles())
           .addOptionsModification(opt -> opt.testing.trackDesugaredAPIConversions = true)
           .addLibraryFiles(getLibraryFile())
-          .addLibraryFiles(JDK_11_JAVA_BASE_EXTENSION_CLASSES_DIR)
           .setMinApi(parameters.getApiLevel())
           .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
           .compile()
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/b135627418/B135627418.java b/src/test/java/com/android/tools/r8/memberrebinding/b135627418/B135627418.java
index bf94752..f3103f1 100644
--- a/src/test/java/com/android/tools/r8/memberrebinding/b135627418/B135627418.java
+++ b/src/test/java/com/android/tools/r8/memberrebinding/b135627418/B135627418.java
@@ -12,13 +12,10 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
 import com.android.tools.r8.memberrebinding.b135627418.library.Drawable;
 import com.android.tools.r8.memberrebinding.b135627418.library.DrawableWrapper;
 import com.android.tools.r8.memberrebinding.b135627418.library.InsetDrawable;
-import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
@@ -78,27 +75,11 @@
                 com.android.tools.r8.memberrebinding.b135627418.runtime.InsetDrawable.class)
             .setMinApi(parameters.getRuntime())
             .addOptionsModification(
-                options -> {
-                  options.desugaredLibrarySpecification =
-                      LegacyDesugaredLibrarySpecification.withOnlyRewritePrefixForTesting(
-                          ImmutableMap.of(packageName + ".runtime", packageName + ".library"),
-                          options);
-                  DexType type =
-                      options
-                          .dexItemFactory()
-                          .createType(
-                              DescriptorUtils.javaTypeToDescriptor(
-                                  packageName + ".runtime.InsetDrawable"));
-                  DexType rewrittenType =
-                      options
-                          .dexItemFactory()
-                          .createType(
-                              DescriptorUtils.javaTypeToDescriptor(
-                                  packageName + ".library.InsetDrawable"));
-                  options.machineDesugaredLibrarySpecification =
-                      MachineDesugaredLibrarySpecification.withOnlyRewriteTypeForTesting(
-                          ImmutableMap.of(type, rewrittenType));
-                })
+                options ->
+                    options.desugaredLibrarySpecification =
+                        LegacyDesugaredLibrarySpecification.withOnlyRewritePrefixForTesting(
+                            ImmutableMap.of(packageName + ".runtime", packageName + ".library"),
+                            options))
             .compile();
 
     testForR8(parameters.getBackend())