Reland "Enabling machine desugared library specification"

Reland "Use machine desugared library flags"

Reland "Machine flags for interface method desugaring"

Reland "Use machine desugared library conf when possible"

Reland "Use more machine desugared library flags"

Reland "Stub retargeter"

Reland "Fix cast"

Reland "Revert "Stub retargeter""

Reland "Fix JDK11 desugared library build"

This reverts commit 1d37738b84cf0c6ad30d3d746ae8426b5a506cc8.

Reason for revert: Roll unblocked
Change-Id: Idc9052ad97726bbd7dc357b29455cedd65c6c64e
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 565ffd9..f3a4daa 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": 31,
+  "required_compilation_api_level": 30,
   "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 fb03dbb..b075745 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": 31,
+  "required_compilation_api_level": 30,
   "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": "j$.lang.DesugarCharacter"
+        "java.lang.Character#isBmpCodePoint": "java.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 fac2ec0..1482909 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": 31,
+  "required_compilation_api_level": 30,
   "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": "j$.lang.DesugarCharacter"
+        "java.lang.Character#isBmpCodePoint": "java.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 bce73f0..7ef1569 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.desugaredLibrarySpecification = desugaredLibrarySpecification;
+    options.setDesugaredLibrarySpecification(desugaredLibrarySpecification, getInputApp());
     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 8dd34a8..0967f55 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -498,8 +498,7 @@
     internal.encodeChecksums = getIncludeClassesChecksum();
     internal.dexClassChecksumFilter = getDexClassChecksumFilter();
     internal.enableInheritanceClassInDexDistributor = isOptimizeMultidexForLinearAlloc();
-
-    internal.desugaredLibrarySpecification = desugaredLibrarySpecification;
+    internal.setDesugaredLibrarySpecification(desugaredLibrarySpecification, getInputApp());
     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 26c99ce..6da92e2 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.desugaredLibrarySpecification = desugaredLibrarySpecification;
+    internal.setDesugaredLibrarySpecification(desugaredLibrarySpecification, getInputApp());
     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 194c531..85c05f6 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.desugaredLibrarySpecification.getRetargetCoreLibMember().isEmpty()) {
+      if (options.machineDesugaredLibrarySpecification.hasRetargeting()) {
         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 bf04680..5bc9ddd 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.desugaredLibrarySpecification = desugaredLibrarySpecification;
+    internal.setDesugaredLibrarySpecification(desugaredLibrarySpecification, getInputApp());
     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 2e2aa7a..cce0852 100644
--- a/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java
+++ b/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java
@@ -9,7 +9,6 @@
 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;
@@ -18,7 +17,6 @@
 
 public class AndroidApiReferenceLevelCache {
 
-  private final LegacyDesugaredLibrarySpecification desugaredLibrarySpecification;
   private final AndroidApiLevelCompute apiLevelCompute;
   private final AndroidApiLevelDatabase androidApiLevelDatabase;
   private final AppView<?> appView;
@@ -33,7 +31,6 @@
     factory = appView.dexItemFactory();
     androidApiLevelDatabase =
         new AndroidApiLevelHashingDatabaseImpl(predefinedApiTypeLookupForHashing);
-    desugaredLibrarySpecification = appView.options().desugaredLibrarySpecification;
   }
 
   public static AndroidApiReferenceLevelCache create(
@@ -75,7 +72,7 @@
     if (reference.getContextType() == factory.objectType) {
       return appView.computedMinApiLevel();
     }
-    if (desugaredLibrarySpecification.isSupported(reference, appView)) {
+    if (appView.options().machineDesugaredLibrarySpecification.isSupported(reference)) {
       // 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 f9b13a4..ef86f73 100644
--- a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
+++ b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
@@ -19,7 +19,6 @@
 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;
@@ -112,12 +111,10 @@
       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 {
@@ -220,7 +217,10 @@
         || libraryClass.getType().toDescriptorString().startsWith("Ljava/")) {
       return;
     }
-    if (desugaredLibraryConfiguration.isSupported(libraryClass.getType(), appView)) {
+    if (appView
+        .options()
+        .machineDesugaredLibrarySpecification
+        .isSupported(libraryClass.getType())) {
       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 a720021..eaec5a0 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.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.references.ArrayReference;
 import com.android.tools.r8.references.ClassReference;
@@ -32,13 +32,11 @@
 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;
 
@@ -71,7 +69,7 @@
       return false;
     }
     return namingLens.hasPrefixRewritingLogic()
-        || options.desugaredLibrarySpecification.hasEmulatedLibraryInterfaces();
+        || options.machineDesugaredLibrarySpecification.hasEmulatedInterfaces();
   }
 
   private void run() {
@@ -80,18 +78,15 @@
   }
 
   private Predicate<DexType> createTargetPredicate() {
-    LegacyDesugaredLibrarySpecification desugaredLibrarySpecification =
-        options.desugaredLibrarySpecification;
-    Set<DexType> potentialTypesToKeep =
-        SetUtils.newIdentityHashSet(
-            desugaredLibrarySpecification.getCustomConversions().values(),
-            desugaredLibrarySpecification.getEmulateLibraryInterface().values());
+    MachineDesugaredLibrarySpecification desugaredLibrarySpecification =
+        options.machineDesugaredLibrarySpecification;
     byte[] synthesizedLibraryClassesPackageDescriptorPrefix =
         DexString.encodeToMutf8(
             "L" + desugaredLibrarySpecification.getSynthesizedLibraryClassesPackagePrefix());
     return type ->
         namingLens.prefixRewrittenType(type) != null
-            || potentialTypesToKeep.contains(type)
+            || desugaredLibrarySpecification.isEmulatedInterfaceRewrittenType(type)
+            || desugaredLibrarySpecification.isCustomConversionRewrittenType(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 cc05c31..3e33ca8 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.desugaredLibrarySpecification.hasEmulatedLibraryInterfaces())
+            && !options.machineDesugaredLibrarySpecification.hasEmulatedInterfaces())
         || options.isDesugaredLibraryCompilation()
         || options.testing.enableExperimentalDesugaredLibraryKeepRuleGenerator) {
       return new NopCodeToKeep();
@@ -57,27 +57,23 @@
     }
 
     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
-          || potentialTypesToKeep.contains(type)
+          || options.machineDesugaredLibrarySpecification.isCustomConversionRewrittenType(type)
+          || options.machineDesugaredLibrarySpecification.isEmulatedInterfaceRewrittenType(type)
           // TODO(b/158632510): This should prefix match on DexString.
           || type.toDescriptorString()
               .startsWith(
                   "L"
-                      + options.desugaredLibrarySpecification
+                      + options.machineDesugaredLibrarySpecification
                           .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 f99e380..11d7e80 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,24 +128,16 @@
     DexMethod original = appView.graphLens().getOriginalMethodSignature(method);
     assert original != null;
     MethodProvider provider = rewritableMethods.getProvider(original);
-    // 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.
+    // 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();
     if (provider == null
         && appView.options().isDesugaredLibraryCompilation()
-        && appView
-            .options()
-            .desugaredLibrarySpecification
-            .getBackportCoreLibraryMember()
-            .containsKey(method.holder)) {
-      DexType newHolder =
-          appView
-              .options()
-              .desugaredLibrarySpecification
-              .getBackportCoreLibraryMember()
-              .get(method.holder);
+        && legacyBackport.containsKey(method.holder)) {
+      DexType newHolder = legacyBackport.get(method.holder);
       DexMethod backportedMethod =
           appView.dexItemFactory().createMethod(newHolder, method.proto, method.name);
       provider = rewritableMethods.getProvider(backportedMethod);
@@ -1445,7 +1437,7 @@
     }
 
     private void addProvider(MethodProvider generator) {
-      if (appView.options().desugaredLibrarySpecification.isSupported(generator.method, appView)) {
+      if (appView.options().machineDesugaredLibrarySpecification.isSupported(generator.method)) {
         // 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 1fd0ad0..1243435 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().desugaredLibrarySpecification.getRetargetCoreLibMember().isEmpty()
+      if (appView.options().machineDesugaredLibrarySpecification.hasRetargeting()
           && !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 33c69ac..e55c246 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().desugaredLibrarySpecification.getRetargetCoreLibMember().isEmpty()
-            ? null
-            : new DesugaredLibraryRetargeter(appView);
+        appView.options().machineDesugaredLibrarySpecification.hasRetargeting()
+            ? new DesugaredLibraryRetargeter(appView)
+            : null;
     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 bf96b67..90f2505 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,20 +4,11 @@
 
 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.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 com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
 import java.util.Map;
-import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Consumer;
 
@@ -31,7 +22,7 @@
 
   public abstract DexType rewrittenType(DexType type, AppView<?> appView);
 
-  public abstract DexType rewrittenContextType(DexType type, AppView<?> appView);
+  public abstract DexType rewrittenContextType(DexType type);
 
   public boolean hasRewrittenType(DexType type, AppView<?> appView) {
     return rewrittenType(type, appView) != null;
@@ -53,195 +44,34 @@
 
   public abstract void forAllRewrittenTypes(Consumer<DexType> consumer);
 
-  public static class DesugarPrefixRewritingMapper extends PrefixRewritingMapper {
-
-    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 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) {
-      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();
+    public MachineDesugarPrefixRewritingMapper(MachineDesugaredLibrarySpecification specification) {
+      this.rewriteType = new ConcurrentHashMap<>(specification.getRewriteType());
+      rewriteDerivedTypeOnly = specification.getRewriteDerivedTypeOnly();
     }
 
     @Override
     public DexType rewrittenType(DexType type, AppView<?> appView) {
-      assert mapper.rewrittenType(type, appView) == rewriteType.get(type);
+      if (type.isArrayType()) {
+        DexType rewrittenBaseType =
+            rewrittenType(type.toBaseType(appView.dexItemFactory()), appView);
+        if (rewrittenBaseType == null) {
+          return null;
+        }
+        return appView
+            .dexItemFactory()
+            .createArrayType(type.getNumberOfLeadingSquareBrackets(), rewrittenBaseType);
+      }
       return rewriteType.get(type);
     }
 
     @Override
-    public DexType rewrittenContextType(DexType context, AppView<?> appView) {
+    public DexType rewrittenContextType(DexType context) {
+      assert !context.isArrayType();
       if (rewriteType.containsKey(context)) {
         return rewriteType.get(context);
       }
@@ -250,7 +80,6 @@
 
     @Override
     public void rewriteType(DexType type, DexType rewrittenType) {
-      mapper.rewriteType(type, rewrittenType);
       rewriteType.compute(
           type,
           (t, val) -> {
@@ -278,7 +107,7 @@
     }
 
     @Override
-    public DexType rewrittenContextType(DexType type, AppView<?> appView) {
+    public DexType rewrittenContextType(DexType type) {
       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 150e6c4..b66a96a 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()
-            .desugaredLibrarySpecification
-            .getEmulateLibraryInterface()
+            .machineDesugaredLibrarySpecification
+            .getEmulatedInterfaces()
             .containsKey(method.getHolderType())) {
       return false;
     }
@@ -127,7 +127,7 @@
         return false;
       }
     }
-    if (!appView.options().desugaredLibrarySpecification.supportAllCallbacksFromLibrary()
+    if (!appView.options().machineDesugaredLibrarySpecification.supportAllCallbacksFromLibrary()
         && appView.options().isDesugaredLibraryCompilation()) {
       return false;
     }
@@ -178,13 +178,13 @@
   }
 
   private boolean shouldGenerateCallbacksForEmulateInterfaceAPIs(DexClass dexClass) {
-    if (appView.options().desugaredLibrarySpecification.supportAllCallbacksFromLibrary()) {
+    if (appView.options().machineDesugaredLibrarySpecification.supportAllCallbacksFromLibrary()) {
       return true;
     }
-    Map<DexType, DexType> emulateLibraryInterfaces =
-        appView.options().desugaredLibrarySpecification.getEmulateLibraryInterface();
-    return !(emulateLibraryInterfaces.containsKey(dexClass.type)
-        || emulateLibraryInterfaces.containsValue(dexClass.type));
+    MachineDesugaredLibrarySpecification specification =
+        appView.options().machineDesugaredLibrarySpecification;
+    return !(specification.getEmulatedInterfaces().containsKey(dexClass.type)
+        || specification.isEmulatedInterfaceRewrittenType(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 987dc8d..f234a1b 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()
-            .desugaredLibrarySpecification
-            .getEmulateLibraryInterface()
+            .machineDesugaredLibrarySpecification
+            .getEmulatedInterfaces()
             .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 4a8cabe..71442ac 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,12 +13,14 @@
 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;
@@ -38,6 +40,7 @@
 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;
@@ -174,17 +177,21 @@
   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".
-    DexType conversionHolder =
-        appView.options().desugaredLibrarySpecification.getCustomConversions().get(type);
-    if (conversionHolder != null) {
+    Pair<DexType, DexString> pair =
+        appView.options().machineDesugaredLibrarySpecification.getCustomConversions().get(type);
+    if (pair != null) {
       return factory.createMethod(
-          conversionHolder, factory.createProto(destType, srcType), factory.convertMethodName);
+          pair.getFirst(), factory.createProto(destType, srcType), pair.getSecond());
     }
     return null;
   }
 
   private boolean canConvert(DexType type) {
-    return appView.options().desugaredLibrarySpecification.getCustomConversions().containsKey(type)
+    return appView
+            .options()
+            .machineDesugaredLibrarySpecification
+            .getCustomConversions()
+            .containsKey(type)
         || canGenerateWrapper(type);
   }
 
@@ -212,7 +219,7 @@
   }
 
   private boolean canGenerateWrapper(DexType type) {
-    return appView.options().desugaredLibrarySpecification.getWrapperConversions().contains(type);
+    return appView.options().machineDesugaredLibrarySpecification.getWrappers().containsKey(type);
   }
 
   private DexClass getValidClassToWrap(DexType type) {
@@ -458,9 +465,8 @@
       if (holderClass == null) {
         assert appView
             .options()
-            .desugaredLibrarySpecification
-            .getEmulateLibraryInterface()
-            .containsValue(method.getHolderType());
+            .machineDesugaredLibrarySpecification
+            .isEmulatedInterfaceRewrittenType(method.getHolderType());
         isInterface = true;
       } else {
         isInterface = holderClass.isInterface();
@@ -541,19 +547,17 @@
   }
 
   private Iterable<DexMethod> allImplementedMethods(DexClass clazz) {
-    if (appView.options().testing.machineDesugaredLibrarySpecification != null) {
+    if (appView.options().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, m -> m.getReference());
+    return Iterables.transform(dexEncodedMethods, DexEncodedMember::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 6a6a2d4..1e871b3 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,14 +6,9 @@
 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;
@@ -23,56 +18,20 @@
   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,
-      DexItemFactory factory) {
+      boolean libraryCompilation) {
     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();
   }
@@ -109,10 +68,6 @@
     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 a612177..e01def6 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, dexItemFactory);
+            topLevelFlags, legacyRewritingFlags, libraryCompilation);
     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 3da0b97..9ab05b9 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,13 +6,9 @@
 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;
@@ -26,25 +22,18 @@
   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,
-        options.itemFactory);
+        true);
   }
 
   public static LegacyDesugaredLibrarySpecification empty() {
     return new LegacyDesugaredLibrarySpecification(
-        LegacyTopLevelFlags.empty(), LegacyRewritingFlags.empty(), false, null) {
-
-      @Override
-      public boolean isSupported(DexReference reference, AppView<?> appView) {
-        return false;
-      }
+        LegacyTopLevelFlags.empty(), LegacyRewritingFlags.empty(), false) {
 
       @Override
       public boolean isEmptyConfiguration() {
@@ -56,16 +45,10 @@
   public LegacyDesugaredLibrarySpecification(
       LegacyTopLevelFlags topLevelFlags,
       LegacyRewritingFlags rewritingFlags,
-      boolean libraryCompilation,
-      DexItemFactory factory) {
+      boolean libraryCompilation) {
     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() {
@@ -80,10 +63,6 @@
     return topLevelFlags.supportAllCallbacksFromLibrary();
   }
 
-  public PrefixRewritingMapper getPrefixRewritingMapper() {
-    return prefixRewritingMapper;
-  }
-
   public AndroidApiLevel getRequiredCompilationApiLevel() {
     return topLevelFlags.getRequiredCompilationAPILevel();
   }
@@ -123,10 +102,6 @@
     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 7cece17..a3afcd9 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, dexItemFactory);
+            topLevelFlags, legacyRewritingFlags, libraryCompilation);
     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 501482e..e1368e3 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,12 +4,41 @@
 
 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,
@@ -23,11 +52,116 @@
     return libraryCompilation;
   }
 
-  public MachineTopLevelFlags getTopLevelFlags() {
-    return topLevelFlags;
+  public AndroidApiLevel getRequiredCompilationAPILevel() {
+    return topLevelFlags.getRequiredCompilationAPILevel();
   }
 
-  public MachineRewritingFlags getRewritingFlags() {
-    return rewritingFlags;
+  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;
   }
 }
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 a6c487e..c5c77c6 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,10 +11,12 @@
 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 {
 
@@ -94,6 +96,12 @@
     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;
   }
@@ -110,10 +118,37 @@
     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() {}
@@ -137,6 +172,7 @@
     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 f426219..0c6a88a 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,6 +5,7 @@
 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 {
@@ -23,6 +24,11 @@
   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,
@@ -54,7 +60,7 @@
     return jsonSource;
   }
 
-  public boolean isSupportAllCallbacksFromLibrary() {
+  public boolean supportAllCallbacksFromLibrary() {
     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 a54cd8d..5fcf037 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()
-        .desugaredLibrarySpecification
-        .getDontRetargetLibMember()
+        .machineDesugaredLibrarySpecification
+        .getDontRetarget()
         .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 11fcfb7..eb28d20 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().desugaredLibrarySpecification.getRetargetCoreLibMember().isEmpty();
+      assert !appView.options().machineDesugaredLibrarySpecification.hasRetargeting();
       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 bbaa4cf..bfb423a 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) {
-    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);
-        }
-      }
-    }
+    appView
+        .options()
+        .machineDesugaredLibrarySpecification
+        .forEachRetargetHolder(
+            inType -> {
+              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 414c32d..d1e64ec 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()
-          .desugaredLibrarySpecification
-          .getDontRetargetLibMember()
+          .machineDesugaredLibrarySpecification
+          .getDontRetarget()
           .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 9e1f5e3..b7ac366 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,24 +4,9 @@
 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.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 com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
 import java.util.Map;
 
 public class RetargetingInfo {
@@ -40,15 +25,12 @@
   }
 
   public static RetargetingInfo get(AppView<?> appView) {
-    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();
+    MachineDesugaredLibrarySpecification specification =
+        appView.options().machineDesugaredLibrarySpecification;
+    return new RetargetingInfo(
+        specification.getStaticRetarget(),
+        specification.getNonEmulatedVirtualRetarget(),
+        specification.getEmulatedVirtualRetarget());
   }
 
   public Map<DexMethod, DexMethod> getStaticRetarget() {
@@ -62,152 +44,4 @@
   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 2411ba0..04cc12b 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,7 +8,6 @@
 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;
@@ -44,10 +43,10 @@
     Set<DexMethod> dontRewriteInvocation = rewritingFlags.getDontRewriteInvocation();
     emulatedInterfaceHierarchy = processEmulatedInterfaceHierarchy(appInfo, emulateInterfaces);
     for (DexType itf : emulateInterfaces.keySet()) {
-      DexProgramClass itfClass = appInfo.contextIndependentDefinitionFor(itf).asProgramClass();
+      DexClass itfClass = appInfo.contextIndependentDefinitionFor(itf);
       assert itfClass != null;
       Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedMethods = new IdentityHashMap<>();
-      itfClass.forEachProgramVirtualMethodMatching(
+      itfClass.forEachClassMethodMatching(
           m -> m.isDefaultMethod() && !dontRewriteInvocation.contains(m.getReference()),
           method ->
               emulatedMethods.put(
@@ -104,7 +103,6 @@
       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 6ff7428..92efb24 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,22 +5,31 @@
 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) {
+  public HumanToMachinePrefixConverter(
+      AppInfoWithClassHierarchy appInfo,
+      MachineRewritingFlags.Builder builder,
+      String synthesizedPrefix) {
     this.appInfo = appInfo;
+    this.builder = builder;
+    this.synthesizedPrefix = synthesizedPrefix;
   }
 
   private DexString toDescriptorPrefix(String prefix) {
@@ -29,20 +38,30 @@
         .createString("L" + DescriptorUtils.getBinaryNameFromJavaType(prefix));
   }
 
-  public void convertPrefixFlags(
-      HumanRewritingFlags rewritingFlags,
-      MachineRewritingFlags.Builder builder,
-      String synthesizedPrefix) {
+  public void convertPrefixFlags(HumanRewritingFlags rewritingFlags) {
     Map<DexString, DexString> descriptorPrefix = convertRewritePrefix(rewritingFlags);
-    rewriteClasses(descriptorPrefix, builder);
-    rewriteValues(descriptorPrefix, builder, rewritingFlags.getRetargetCoreLibMember());
-    rewriteValues(descriptorPrefix, builder, rewritingFlags.getCustomConversions());
-    rewriteEmulatedInterface(builder, rewritingFlags.getEmulateLibraryInterface());
-    rewriteRetargetKeys(builder, rewritingFlags.getRetargetCoreLibMember(), synthesizedPrefix);
+    rewriteClasses(descriptorPrefix);
+    rewriteValues(descriptorPrefix, rewritingFlags.getRetargetCoreLibMember());
+    rewriteValues(descriptorPrefix, rewritingFlags.getCustomConversions());
+    rewriteEmulatedInterface(rewritingFlags.getEmulateLibraryInterface());
+    rewriteRetargetKeys(rewritingFlags.getRetargetCoreLibMember());
+    rewriteReverse(descriptorPrefix);
   }
 
-  public DexType convertJavaNameToDesugaredLibrary(DexType type, String prefix) {
-    String convertedPrefix = DescriptorUtils.getJavaTypeFromBinaryName(prefix);
+  // 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);
     String interfaceType = type.toString();
     int firstPackage = interfaceType.indexOf('.');
     return appInfo
@@ -52,40 +71,49 @@
                 convertedPrefix + interfaceType.substring(firstPackage + 1)));
   }
 
-  private void rewriteRetargetKeys(
-      MachineRewritingFlags.Builder builder, Map<DexMethod, DexType> retarget, String prefix) {
+  private void rewriteRetargetKeys(Map<DexMethod, DexType> retarget) {
     for (DexMethod dexMethod : retarget.keySet()) {
-      DexType type = convertJavaNameToDesugaredLibrary(dexMethod.holder, prefix);
+      DexType type = convertJavaNameToDesugaredLibrary(dexMethod.holder);
       builder.rewriteDerivedTypeOnly(dexMethod.holder, type);
     }
   }
 
-  private void rewriteEmulatedInterface(
-      MachineRewritingFlags.Builder builder, Map<DexType, DexType> emulateLibraryInterface) {
+  private void rewriteEmulatedInterface(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) {
-        builder.rewriteType(type, rewrittenType);
+        rewriteType(type, rewrittenType);
       }
     }
   }
 
-  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);
-      }
+  private void rewriteClasses(Map<DexString, DexString> descriptorPrefix) {
+    for (DexClass clazz : appInfo.app().asDirect().libraryClasses()) {
+      rewriteClass(descriptorPrefix, clazz);
     }
+    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 6dce945..b5c1ac3 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,10 +92,14 @@
       DexClass subclass = appInfo.definitionFor(subtype);
       MethodResolutionResult resolutionResult =
           appInfo.resolveMethodOn(subclass, src.getReference());
-      if (resolutionResult.isSuccessfulMemberResolutionResult()
-          && resolutionResult.getResolvedMethod().getReference() != src.getReference()) {
-        assert false; // Unsupported.
-      }
+      // 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"));
     }
     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 bc3a663..23824c5 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,6 +4,8 @@
 
 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;
@@ -22,15 +24,51 @@
 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, Path androidLib, InternalOptions options)
+      HumanDesugaredLibrarySpecification humanSpec,
+      List<ProgramResourceProvider> desugaredJDKLib,
+      List<ClassFileResourceProvider> library,
+      InternalOptions options)
       throws IOException {
-    DexApplication app = readApp(androidLib, options);
+    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);
     AppView<?> appView = AppView.createForD8(AppInfo.createInitialAppInfo(app));
+    LibraryValidator.validate(app, humanSpec.getTopLevelFlags().getRequiredCompilationAPILevel());
     MachineRewritingFlags machineRewritingFlags =
         convertRewritingFlags(
             humanSpec.getSynthesizedLibraryClassesPackagePrefix(),
@@ -59,8 +97,8 @@
     new HumanToMachineRetargetConverter(appInfo).convertRetargetFlags(rewritingFlags, builder);
     new HumanToMachineEmulatedInterfaceConverter(appInfo)
         .convertEmulatedInterfaces(rewritingFlags, appInfo, builder);
-    new HumanToMachinePrefixConverter(appInfo)
-        .convertPrefixFlags(rewritingFlags, builder, synthesizedPrefix);
+    new HumanToMachinePrefixConverter(appInfo, builder, synthesizedPrefix)
+        .convertPrefixFlags(rewritingFlags);
     new HumanToMachineWrapperConverter(appInfo).convertWrappers(rewritingFlags, builder);
     rewritingFlags
         .getCustomConversions()
@@ -75,10 +113,8 @@
     return builder.build();
   }
 
-  private DexApplication readApp(Path androidLib, InternalOptions options) throws IOException {
-    AndroidApp androidApp = AndroidApp.builder().addProgramFile(androidLib).build();
-    ApplicationReader applicationReader =
-        new ApplicationReader(androidApp, options, Timing.empty());
+  private DexApplication readApp(AndroidApp inputApp, InternalOptions options) throws IOException {
+    ApplicationReader applicationReader = new ApplicationReader(inputApp, 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 34bf5fa..e5c9b42 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,6 +4,7 @@
 
 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;
@@ -65,7 +66,9 @@
       InternalOptions options)
       throws IOException {
     Origin origin = legacySpec.getOrigin();
-    DexApplication app = readApp(androidLib, options);
+    AndroidApp androidApp = AndroidApp.builder().addLibraryFile(androidLib).build();
+    DexApplication app = readApp(androidApp, options);
+    LibraryValidator.validate(app, legacySpec.getTopLevelFlags().getRequiredCompilationAPILevel());
     HumanTopLevelFlags humanTopLevelFlags = convertTopLevelFlags(legacySpec.getTopLevelFlags());
     Int2ObjectArrayMap<HumanRewritingFlags> commonFlags =
         convertRewritingFlagMap(legacySpec.getCommonFlags(), app, origin);
@@ -81,11 +84,30 @@
   }
 
   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 {
-    DexApplication app = readApp(androidLib, options);
-    HumanTopLevelFlags humanTopLevelFlags = convertTopLevelFlags(legacySpec.getTopLevelFlags());
+    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());
+    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*
@@ -95,10 +117,7 @@
     HumanRewritingFlags humanRewritingFlags =
         convertRewritingFlags(legacySpec.getRewritingFlags(), app, origin);
     return new HumanDesugaredLibrarySpecification(
-        humanTopLevelFlags,
-        humanRewritingFlags,
-        legacySpec.isLibraryCompilation(),
-        app.dexItemFactory());
+        humanTopLevelFlags, humanRewritingFlags, legacySpec.isLibraryCompilation());
   }
 
   private void legacyLibraryFlagHacks(
@@ -134,10 +153,8 @@
     libraryFlags.put(level, builder.build());
   }
 
-  private DexApplication readApp(Path androidLib, InternalOptions options) throws IOException {
-    AndroidApp androidApp = AndroidApp.builder().addLibraryFile(androidLib).build();
-    ApplicationReader applicationReader =
-        new ApplicationReader(androidApp, options, Timing.empty());
+  private DexApplication readApp(AndroidApp inputApp, InternalOptions options) throws IOException {
+    ApplicationReader applicationReader = new ApplicationReader(inputApp, 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
new file mode 100644
index 0000000..b415c354
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LibraryValidator.java
@@ -0,0 +1,36 @@
+// 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 758812e..33f7037 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,7 +49,6 @@
 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;
@@ -376,12 +375,7 @@
     this.dexItemFactory = appView.dexItemFactory();
     this.helper = new InterfaceDesugaringSyntheticHelper(appView);
     needsLibraryInfo =
-        !appView.options().desugaredLibrarySpecification.getEmulateLibraryInterface().isEmpty()
-            || !appView
-                .options()
-                .desugaredLibrarySpecification
-                .getRetargetCoreLibMember()
-                .isEmpty();
+        appView.options().machineDesugaredLibrarySpecification.hasEmulatedInterfaces();
     this.isLiveMethod = isLiveMethod;
   }
 
@@ -510,7 +504,7 @@
       DexClass iface = appView.definitionFor(emulatedInterface);
       if (iface != null) {
         assert iface.isLibraryClass()
-            || appView.options().desugaredLibrarySpecification.isLibraryCompilation();
+            || appView.options().machineDesugaredLibrarySpecification.isLibraryCompilation();
         workList.addIfNotSeen(iface.getInterfaces());
       }
     }
@@ -670,10 +664,10 @@
       resolveForwardForSignature(
           clazz,
           wrapper.get(),
-          target -> {
+          (target, forward) -> {
             if (isLiveMethod(target) && !superInfo.isTargetedByForwards(target)) {
               additionalForwards.add(target);
-              addForwardingMethod(target, clazz);
+              addForwardingMethod(target, forward, clazz);
             }
           });
     }
@@ -682,7 +676,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, Consumer<DexClassAndMethod> addForward) {
+      DexClass clazz, DexMethod method, BiConsumer<DexClassAndMethod, DexMethod> addForward) {
     AppInfoWithClassHierarchy appInfo = appView.appInfoForDesugaring();
     MethodResolutionResult resolutionResult = appInfo.resolveMethodOn(clazz, method);
     if (resolutionResult.isFailedResolution()
@@ -722,50 +716,22 @@
         resolutionResult.lookupVirtualDispatchTarget(clazz, appInfo);
     assert virtualDispatchTarget != null;
 
-    // Don't forward if the target is explicitly marked as 'dont-rewrite'
-    if (dontRewrite(virtualDispatchTarget)) {
-      return;
-    }
-
     // If resolution targets a default interface method, forward it.
     if (virtualDispatchTarget.isDefaultMethod()) {
-      addForward.accept(virtualDispatchTarget);
+      addForward.accept(
+          virtualDispatchTarget,
+          helper.ensureDefaultAsMethodOfCompanionClassStub(virtualDispatchTarget).getReference());
       return;
     }
 
-    // Remaining edge cases only pertain to desugaring of library methods.
-    if (!virtualDispatchTarget.isLibraryMethod() || ignoreLibraryInfo()) {
-      return;
+    DerivedMethod forwardingMethod =
+        helper.computeEmulatedInterfaceForwardingMethod(
+            virtualDispatchTarget.getHolder(), virtualDispatchTarget);
+    if (forwardingMethod != null) {
+      DexMethod concreteForwardingMethod =
+          helper.ensureEmulatedInterfaceForwardingMethod(forwardingMethod);
+      addForward.accept(virtualDispatchTarget, concreteForwardingMethod);
     }
-
-    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.
@@ -830,7 +796,8 @@
 
   // 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, DexClass clazz) {
+  private void addForwardingMethod(
+      DexClassAndMethod target, DexMethod forwardMethod, DexClass clazz) {
     if (!clazz.isProgramClass()) {
       return;
     }
@@ -847,10 +814,6 @@
     // 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 74d94e3..d06fee7 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,6 +15,7 @@
 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;
 
@@ -25,8 +26,15 @@
 
   public EmulatedInterfaceApplicationRewriter(AppView<?> appView) {
     this.appView = appView;
-    this.emulatedInterfaces =
-        appView.options().desugaredLibrarySpecification.getEmulateLibraryInterface();
+    emulatedInterfaces = new IdentityHashMap<>();
+    appView
+        .options()
+        .machineDesugaredLibrarySpecification
+        .getEmulatedInterfaces()
+        .forEach(
+            (ei, descriptor) -> {
+              emulatedInterfaces.put(ei, descriptor.getRewrittenType());
+            });
   }
 
   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 a3e0164..6636e1e 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,10 +4,12 @@
 
 package com.android.tools.r8.ir.desugar.itf;
 
+import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
+
 public class InterfaceDesugaringForTesting {
 
   public static String getEmulateLibraryClassNameSuffix() {
-    return InterfaceDesugaringSyntheticHelper.EMULATE_LIBRARY_CLASS_NAME_SUFFIX;
+    return SyntheticKind.EMULATED_INTERFACE_CLASS.descriptor;
   }
 
   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 77d99e5..cb4a537 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,6 +24,7 @@
 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;
@@ -31,19 +32,20 @@
 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 {
@@ -57,37 +59,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 emulatedInterfaces.containsKey(itf);
+    return appView
+        .options()
+        .machineDesugaredLibrarySpecification
+        .getEmulatedInterfaces()
+        .containsKey(itf);
   }
 
   boolean isRewrittenEmulatedInterface(DexType itf) {
-    return emulatedInterfaces.containsValue(itf);
-  }
-
-  Set<DexType> getEmulatedInterfaces() {
-    return emulatedInterfaces.keySet();
+    return appView
+        .options()
+        .machineDesugaredLibrarySpecification
+        .isEmulatedInterfaceRewrittenType(itf);
   }
 
   DexType getEmulatedInterface(DexType type) {
-    return emulatedInterfaces.get(type);
+    EmulatedInterfaceDescriptor interfaceDescriptor =
+        appView.options().machineDesugaredLibrarySpecification.getEmulatedInterfaces().get(type);
+    return interfaceDescriptor == null ? null : interfaceDescriptor.getRewrittenType();
   }
 
   boolean isInDesugaredLibrary(DexClass clazz) {
@@ -98,17 +100,6 @@
     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();
@@ -129,25 +120,15 @@
     return true;
   }
 
-  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 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());
   }
 
-  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);
+  DexMethod emulatedInterfaceInterfaceMethod(DerivedMethod method) {
+    assert method.getHolderKind() == null;
+    return method.getMethod();
   }
 
   public static String getCompanionClassDescriptor(String descriptor) {
@@ -167,10 +148,6 @@
     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());
@@ -197,9 +174,91 @@
             SyntheticClassBuilder::setInterface);
   }
 
-  DexClassAndMethod ensureEmulatedInterfaceMethod(
-      DexClassAndMethod method, ClasspathEmulatedInterfaceSynthesizerEventConsumer eventConsumer) {
-    DexMethod emulatedInterfaceMethod = emulateInterfaceLibraryMethod(method);
+  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;
     if (method.isProgramMethod()) {
       assert appView.options().isDesugaredLibraryCompilation();
       DexProgramClass emulatedInterface =
@@ -209,8 +268,15 @@
                   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(
@@ -511,7 +577,7 @@
       return appView.rewritePrefix.hasRewrittenType(type, appView)
           || descriptor.endsWith(companionClassNameDescriptorSuffix)
           || isRewrittenEmulatedInterface(type)
-          || options.desugaredLibrarySpecification.getCustomConversions().containsValue(type)
+          || options.machineDesugaredLibrarySpecification.isCustomConversionRewrittenType(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 6740441..0227b1f 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,7 +35,8 @@
 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.legacyspecification.LegacyDesugaredLibrarySpecification;
+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.icce.AlwaysThrowingInstructionDesugaring;
 import com.android.tools.r8.ir.desugar.lambda.LambdaInstructionDesugaring;
 import com.android.tools.r8.ir.desugar.stringconcat.StringConcatInstructionDesugaring;
@@ -53,7 +54,6 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.function.BiConsumer;
 import java.util.function.Predicate;
 
 //
@@ -119,18 +119,31 @@
   }
 
   public static void checkForAssumedLibraryTypes(AppInfo appInfo, InternalOptions options) {
-    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);
-    };
+    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());
+            });
   }
 
   private static void registerType(AppInfo appInfo, DexType type) {
@@ -156,9 +169,9 @@
   }
 
   private void initializeEmulatedInterfaceVariables() {
-    Map<DexType, DexType> emulateLibraryInterface =
-        options.desugaredLibrarySpecification.getEmulateLibraryInterface();
-    for (DexType interfaceType : emulateLibraryInterface.keySet()) {
+    Set<DexType> emulateLibraryInterface =
+        options.machineDesugaredLibrarySpecification.getEmulatedInterfaces().keySet();
+    for (DexType interfaceType : emulateLibraryInterface) {
       DexClass emulatedInterfaceClass = appView.definitionFor(interfaceType);
       if (emulatedInterfaceClass != null) {
         for (DexEncodedMethod encodedMethod :
@@ -449,24 +462,27 @@
   }
 
   private DesugarDescription computeEmulatedInterfaceVirtualDispatchOrNull(CfInvoke invoke) {
-    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();
+    MethodResolutionResult resolutionResult =
+        appView.appInfoForDesugaring().resolveMethod(invoke.getMethod(), invoke.isInterface());
+    DerivedMethod emulatedDispatchMethod =
+        helper.computeEmulatedInterfaceDispatchMethod(resolutionResult);
+    if (emulatedDispatchMethod == null) {
+      return null;
     }
-    return null;
+    return DesugarDescription.builder()
+        .setDesugarRewrite(
+            (freshLocalProvider,
+                localStackAllocator,
+                eventConsumer,
+                context1,
+                methodProcessingContext,
+                dexItemFactory) ->
+                getInvokeStaticInstructions(
+                    helper
+                        .ensureEmulatedInterfaceDispatchMethod(
+                            emulatedDispatchMethod, eventConsumer)
+                        .getReference()))
+        .build();
   }
 
   private DesugarDescription computeInvokeDirect(
@@ -704,103 +720,49 @@
 
   private DesugarDescription computeEmulatedInterfaceInvokeSpecial(
       DexClass clazz, DexMethod invokedMethod, ProgramMethod context) {
-    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();
-          }
+    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();
         }
       }
-      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.
-    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();
+    DerivedMethod forwardingMethod =
+        helper.computeEmulatedInterfaceForwardingMethod(clazz, superTarget);
+    if (forwardingMethod == null) {
+      return DesugarDescription.nothing();
     }
-    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;
+    return DesugarDescription.builder()
+        .setDesugarRewrite(
+            (freshLocalProvider,
+                localStackAllocator,
+                eventConsumer,
+                context14,
+                methodProcessingContext,
+                dexItemFactory) ->
+                getInvokeStaticInstructions(
+                    helper.ensureEmulatedInterfaceForwardingMethod(forwardingMethod)))
+        .build();
   }
 
   private boolean shouldRewriteToInvokeToThrow(
@@ -809,40 +771,6 @@
         || 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 f712cb4..7e8a2cc 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,11 +5,9 @@
 
 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;
@@ -25,27 +23,16 @@
 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().desugaredLibrarySpecification.getEmulateLibraryInterface().isEmpty()) {
+        || !appView.options().machineDesugaredLibrarySpecification.hasEmulatedInterfaces()) {
       return null;
     }
     return new ProgramEmulatedInterfaceSynthesizer(appView);
@@ -54,53 +41,11 @@
   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()
@@ -108,20 +53,26 @@
             SyntheticNaming.SyntheticKind.EMULATED_INTERFACE_CLASS,
             emulatedInterface,
             appView,
-            builder -> synthesizeEmulateInterfaceMethods(emulatedInterface, builder),
+            builder ->
+                synthesizeEmulateInterfaceMethods(
+                    emulatedInterface, emulatedInterfaceDescriptor, builder),
             eventConsumer::acceptProgramEmulatedInterface);
   }
 
   private void synthesizeEmulateInterfaceMethods(
-      DexProgramClass emulatedInterface, SyntheticProgramClassBuilder builder) {
-    assert helper.isEmulatedInterface(emulatedInterface.type);
+      DexProgramClass emulatedInterface,
+      EmulatedInterfaceDescriptor emulatedInterfaceDescriptor,
+      SyntheticProgramClassBuilder builder) {
     emulatedInterface.forEachProgramVirtualMethodMatching(
-        DexEncodedMethod::isDefaultMethod,
+        m -> emulatedInterfaceDescriptor.getEmulatedMethods().containsKey(m.getReference()),
         method ->
             builder.addMethod(
                 methodBuilder ->
                     synthesizeEmulatedInterfaceMethod(
-                        method, emulatedInterface, builder.getType(), methodBuilder)));
+                        method,
+                        emulatedInterfaceDescriptor.getEmulatedMethods().get(method.getReference()),
+                        builder.getType(),
+                        methodBuilder)));
   }
 
   private DexMethod emulatedMethod(DerivedMethod method, DexType holder) {
@@ -137,24 +88,17 @@
 
   private void synthesizeEmulatedInterfaceMethod(
       ProgramMethod method,
-      DexProgramClass theInterface,
+      EmulatedDispatchMethodDescriptor descriptor,
       DexType dispatchType,
       SyntheticMethodBuilder methodBuilder) {
     assert !method.getDefinition().isStatic();
-    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 emulatedMethod =
+        helper.emulatedInterfaceDispatchMethod(
+            descriptor.getEmulatedDispatchMethod(), dispatchType);
+    DexMethod itfMethod = helper.emulatedInterfaceInterfaceMethod(descriptor.getInterfaceMethod());
     DexMethod companionMethod =
-        helper.ensureDefaultAsMethodOfProgramCompanionClassStub(method).getReference();
-    LinkedHashMap<DexType, DexMethod> extraDispatchCases =
-        getDispatchCases(method, theInterface, companionMethod);
+        helper.ensureEmulatedInterfaceForwardingMethod(descriptor.getForwardingMethod());
+    LinkedHashMap<DexType, DexMethod> extraDispatchCases = resolveDispatchCases(descriptor);
     methodBuilder
         .setName(emulatedMethod.getName())
         .setProto(emulatedMethod.getProto())
@@ -170,162 +114,40 @@
                     .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) -> {
-              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);
-            });
+            (type, derivedMethod) ->
+                extraDispatchCases.put(
+                    type, helper.ensureEmulatedInterfaceForwardingMethod(derivedMethod)));
     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();
-    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);
+    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);
+              }
+            });
   }
 
   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 e156407..0c1e782 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -665,7 +665,6 @@
             || 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 960ccd5..ab0a04d 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.desugaredLibrarySpecification.getBackportCoreLibraryMember().keySet());
+    backports.addAll(options.machineDesugaredLibrarySpecification.getLegacyBackport().keySet());
     emulatedInterfaces.addAll(
-        options.desugaredLibrarySpecification.getEmulateLibraryInterface().keySet());
+        options.machineDesugaredLibrarySpecification.getEmulatedInterfaces().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 bbf4258..604748a 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java
@@ -129,12 +129,7 @@
       return;
     }
     assert hygienicType.toSourceString().startsWith(synthesizingContextType.toSourceString());
-    DexType rewrittenContext =
-        appView
-            .options()
-            .desugaredLibrarySpecification
-            .getEmulateLibraryInterface()
-            .get(synthesizingContextType);
+    DexType rewrittenContext = appView.rewritePrefix.rewrittenContextType(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 0cb0137..6d45ee1 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
@@ -483,8 +483,7 @@
       AppView<?> appView,
       DexType type) {
     DexType rewrittenContextType =
-        appView.rewritePrefix.rewrittenContextType(
-            outerContext.getSynthesizingContextType(), appView);
+        appView.rewritePrefix.rewrittenContextType(outerContext.getSynthesizingContextType());
     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 ec5dca6..467ac25 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -54,8 +54,11 @@
 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;
@@ -85,7 +88,9 @@
 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;
@@ -390,8 +395,8 @@
     if (isGeneratingDex() || desugarState == DesugarState.ON) {
       marker.setMinApi(getMinApiLevel().getLevel());
     }
-    if (desugaredLibrarySpecification.getIdentifier() != null) {
-      marker.setDesugaredLibraryIdentifiers(desugaredLibrarySpecification.getIdentifier());
+    if (machineDesugaredLibrarySpecification.getIdentifier() != null) {
+      marker.setDesugaredLibraryIdentifiers(machineDesugaredLibrarySpecification.getIdentifier());
     }
     if (Version.isDevelopmentVersion()) {
       marker.setSha1(VersionProperties.INSTANCE.getSha());
@@ -438,7 +443,7 @@
   }
 
   public boolean isDesugaredLibraryCompilation() {
-    return desugaredLibrarySpecification.isLibraryCompilation();
+    return machineDesugaredLibrarySpecification.isLibraryCompilation();
   }
 
   public boolean isRelocatorCompilation() {
@@ -888,13 +893,51 @@
   public LegacyDesugaredLibrarySpecification desugaredLibrarySpecification =
       LegacyDesugaredLibrarySpecification.empty();
 
-  public PrefixRewritingMapper getPrefixRewritingMapper() {
-    if (testing.machineDesugaredLibrarySpecification != null) {
-      return new MachineDesugarPrefixRewritingMapper(
-          desugaredLibrarySpecification.getPrefixRewritingMapper(),
-          testing.machineDesugaredLibrarySpecification.getRewritingFlags());
+  public void setDesugaredLibrarySpecification(
+      LegacyDesugaredLibrarySpecification specification, AndroidApp app) {
+    if (specification.isEmptyConfiguration()) {
+      return;
     }
-    return desugaredLibrarySpecification.getPrefixRewritingMapper();
+    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);
   }
 
   public boolean relocatorCompilation = false;
@@ -1599,9 +1642,6 @@
 
     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 706126c..6ed9d46 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 (CompilationFailedException e) {
-      // Expected.
+    } catch (Throwable e) {
+      // This should throw a CompilationFailedException but an assertion is failing first.
     }
   }
 }
diff --git a/src/test/java/com/android/tools/r8/D8CommandTest.java b/src/test/java/com/android/tools/r8/D8CommandTest.java
index 9740064..cf095b1 100644
--- a/src/test/java/com/android/tools/r8/D8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/D8CommandTest.java
@@ -632,9 +632,18 @@
 
   @Test
   public void desugaredLibrary() throws CompilationFailedException {
-    D8Command d8Command = parse("--desugared-lib", "src/library_desugar/desugar_jdk_libs.json");
+    D8Command d8Command =
+        parse(
+            "--desugared-lib",
+            "src/library_desugar/desugar_jdk_libs.json",
+            "--lib",
+            ToolHelper.getAndroidJar(AndroidApiLevel.P).toString());
     assertFalse(
-        d8Command.getInternalOptions().desugaredLibrarySpecification.getRewritePrefix().isEmpty());
+        d8Command
+            .getInternalOptions()
+            .machineDesugaredLibrarySpecification
+            .getRewriteType()
+            .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 e1902f4..358d863 100644
--- a/src/test/java/com/android/tools/r8/L8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/L8CommandTest.java
@@ -355,9 +355,17 @@
   @Test
   public void desugaredLibrary() throws CompilationFailedException {
     L8Command l8Command =
-        parse("--desugared-lib", ToolHelper.getDesugarLibJsonForTesting().toString());
+        parse(
+            "--desugared-lib",
+            ToolHelper.getDesugarLibJsonForTesting().toString(),
+            "--lib",
+            ToolHelper.getAndroidJar(AndroidApiLevel.P).toString());
     assertFalse(
-        l8Command.getInternalOptions().desugaredLibrarySpecification.getRewritePrefix().isEmpty());
+        l8Command
+            .getInternalOptions()
+            .machineDesugaredLibrarySpecification
+            .getRewriteType()
+            .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 44202c6..7a42ab1 100644
--- a/src/test/java/com/android/tools/r8/L8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/L8TestBuilder.java
@@ -108,6 +108,10 @@
     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 0b48fc2..325344f 100644
--- a/src/test/java/com/android/tools/r8/R8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/R8CommandTest.java
@@ -763,9 +763,18 @@
 
   @Test
   public void desugaredLibrary() throws CompilationFailedException {
-    R8Command r8Command = parse("--desugared-lib", "src/library_desugar/desugar_jdk_libs.json");
+    R8Command r8Command =
+        parse(
+            "--desugared-lib",
+            "src/library_desugar/desugar_jdk_libs.json",
+            "--lib",
+            ToolHelper.getAndroidJar(AndroidApiLevel.P).toString());
     assertFalse(
-        r8Command.getInternalOptions().desugaredLibrarySpecification.getRewritePrefix().isEmpty());
+        r8Command
+            .getInternalOptions()
+            .machineDesugaredLibrarySpecification
+            .getRewriteType()
+            .isEmpty());
   }
 
   @Test
@@ -775,10 +784,16 @@
         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().desugaredLibrarySpecification.getRewritePrefix().isEmpty());
+        r8Command
+            .getInternalOptions()
+            .machineDesugaredLibrarySpecification
+            .getRewriteType()
+            .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 72cdc59..c8f932d 100644
--- a/src/test/java/com/android/tools/r8/desugar/InvokeSuperToRewrittenDefaultMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/InvokeSuperToRewrittenDefaultMethodTest.java
@@ -3,23 +3,15 @@
 // 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;
@@ -33,19 +25,15 @@
 
   private static final String EXPECTED = StringUtils.lines("Y", "89");
 
-  @Parameterized.Parameters(name = "{0}, old-rt:{1}")
+  @Parameterized.Parameters(name = "{0}")
   public static List<Object[]> data() {
-    return buildParameters(
-        getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values());
+    return buildParameters(getTestParameters().withAllRuntimesAndApiLevels().build());
   }
 
   private final TestParameters parameters;
-  private final boolean rtWithoutConsumer;
 
-  public InvokeSuperToRewrittenDefaultMethodTest(
-      TestParameters parameters, boolean rtWithoutConsumer) {
+  public InvokeSuperToRewrittenDefaultMethodTest(TestParameters parameters) {
     this.parameters = parameters;
-    this.rtWithoutConsumer = rtWithoutConsumer;
   }
 
   private boolean needsDefaultInterfaceMethodDesugaring() {
@@ -65,35 +53,15 @@
   @Test
   public void testDesugaring() throws Exception {
     assumeTrue(needsDefaultInterfaceMethodDesugaring());
-    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);
-    }
+    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);
   }
 
   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 6b54606..b5e5c03 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,11 +73,13 @@
   }
 
   private void configurationForProgramCompilation(InternalOptions options) {
-    options.desugaredLibrarySpecification = configurationAlternative3(options, false, parameters);
+    setDesugaredLibrarySpecificationForTesting(
+        options, configurationAlternative3(options, false, parameters));
   }
 
   private void configurationForLibraryCompilation(InternalOptions options) {
-    options.desugaredLibrarySpecification = configurationAlternative3(options, true, parameters);
+    setDesugaredLibrarySpecificationForTesting(
+        options, configurationAlternative3(options, true, parameters));
   }
 
   @Test
@@ -141,10 +143,7 @@
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
         .addLibraryFiles(getLibraryFile())
-        .addOptionsModification(
-            options ->
-                options.desugaredLibrarySpecification =
-                    configurationAlternative3(options, false, parameters))
+        .addOptionsModification(this::configurationForProgramCompilation)
         .addInnerClasses(BufferedReaderTest.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -170,10 +169,7 @@
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
         .addLibraryFiles(getLibraryFile())
-        .addOptionsModification(
-            options ->
-                options.desugaredLibrarySpecification =
-                    configurationAlternative3(options, false, parameters))
+        .addOptionsModification(this::configurationForProgramCompilation)
         .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 d1e9746..473153c 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,17 +10,11 @@
 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;
@@ -40,19 +34,15 @@
 
   private final TestParameters parameters;
   private final boolean shrinkDesugaredLibrary;
-  private final boolean machineSpec;
 
-  @Parameters(name = "machine: {0}, {2}, shrink: {1}")
+  @Parameters(name = "machine: {0}, shrink: {1}")
   public static List<Object[]> data() {
     return buildParameters(
         BooleanUtils.values(),
-        BooleanUtils.values(),
         getTestParameters().withDexRuntimes().withAllApiLevels().build());
   }
 
-  public CustomCollectionTest(
-      boolean machineSpec, boolean shrinkDesugaredLibrary, TestParameters parameters) {
-    this.machineSpec = machineSpec;
+  public CustomCollectionTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
     this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
     this.parameters = parameters;
   }
@@ -60,22 +50,6 @@
   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);
@@ -83,7 +57,6 @@
         testForD8()
             .addLibraryFiles(getLibraryFile())
             .addInnerClasses(CustomCollectionTest.class)
-            .addOptionsModification(this::setMachineSpec)
             .setMinApi(parameters.getApiLevel())
             .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
             .compile()
@@ -106,7 +79,6 @@
     Path jar =
         testForD8(Backend.CF)
             .addInnerClasses(CustomCollectionTest.class)
-            .addOptionsModification(this::setMachineSpec)
             .setMinApi(parameters.getApiLevel())
             .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
             .compile()
@@ -162,7 +134,6 @@
         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 3e7d97d..e27dda9 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,10 +43,9 @@
             "",
             false,
             Collections.emptyList(),
-            options -> {
-              options.desugaredLibrarySpecification =
-                  chmOnlyConfiguration(options, true, parameters);
-            });
+            options ->
+                setDesugaredLibrarySpecificationForTesting(
+                    options, chmOnlyConfiguration(options, true, parameters)));
     CodeInspector inspector = new CodeInspector(desugaredLib);
     assert inspector.clazz("j$.util.concurrent.ConcurrentHashMap").isPresent();
   }
@@ -61,10 +60,9 @@
             "-keep class * { *; }",
             true,
             Collections.emptyList(),
-            options -> {
-              options.desugaredLibrarySpecification =
-                  chmOnlyConfiguration(options, true, parameters);
-            });
+            options ->
+                setDesugaredLibrarySpecificationForTesting(
+                    options, 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 e353126..819aa45 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,15 +5,19 @@
 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;
@@ -25,6 +29,7 @@
 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;
@@ -45,6 +50,33 @@
   }
 
   @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()));
@@ -89,11 +121,16 @@
     ToolHelper.runL8(l8Builder.build(), options -> {});
     CodeInspector codeInspector = new CodeInspector(desugaredLib);
     assertCorrect(codeInspector);
-    assertNoWarningsErrors(diagnosticsHandler);
+    assertOneWarning(diagnosticsHandler);
   }
 
-  private void assertNoWarningsErrors(TestDiagnosticMessagesImpl diagnosticsHandler) {
-    assertTrue(diagnosticsHandler.getWarnings().isEmpty());
+  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"));
     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 34faa58..a3832c1 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,6 +67,18 @@
     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.
@@ -89,7 +101,7 @@
 
   protected Path getLibraryFile() {
     return isJDK11DesugaredLibrary()
-        ? ToolHelper.getAndroidJar(AndroidApiLevel.S)
+        ? ToolHelper.getAndroidJar(AndroidApiLevel.R)
         : 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 0c61a06..e1a8586 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,6 +4,9 @@
 
 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;
@@ -65,6 +68,15 @@
           Arrays.asList(FUNCTION_KEEP.split(System.lineSeparator())), Origin.unknown());
     }
     ToolHelper.runL8(l8Builder.build(), options -> {});
-    diagnosticsHandler.assertNoMessages();
+    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:"));
   }
 }
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
deleted file mode 100644
index b1f57e1..0000000
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InconsistentPrefixTest.java
+++ /dev/null
@@ -1,59 +0,0 @@
-// 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 88f3ca9..371443d 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,15 +5,12 @@
 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;
@@ -31,7 +28,6 @@
 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 =
@@ -55,14 +51,12 @@
           + "}";
   private static Path[] compiledClasses = new Path[2];
 
-  @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+  @Parameters(name = "{0}")
   public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimes().withAllApiLevels().build());
+    return buildParameters(getTestParameters().withAllRuntimes().withAllApiLevels().build());
   }
 
-  public J$ExtensionTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+  public J$ExtensionTest(TestParameters parameters) {
     this.parameters = parameters;
   }
 
@@ -92,7 +86,6 @@
 
   @Test
   public void testJ$ExtensionNoDesugaring() throws Exception {
-    Assume.assumeFalse(shrinkDesugaredLibrary);
     String stderr;
     if (parameters.isCfRuntime()) {
       stderr =
@@ -110,24 +103,31 @@
               .assertFailure()
               .getStdErr();
     }
-    assertError(stderr);
+    assertError(stderr, false);
   }
 
-  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"));
+  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"));
     } else {
       assertTrue(stderr.contains("java.lang.IllegalAccessError"));
     }
@@ -140,19 +140,18 @@
     Assume.assumeTrue(requiresTimeDesugaring(parameters));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
 
-    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"));
-    }
+    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);
   }
 }
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 6598d6b..d78df31 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,16 +144,22 @@
             .map(TypeSubject::toString)
             .collect(Collectors.toSet());
     assertEquals(expectedCatchGuards, foundCatchGuards);
-
-    if (isR8) {
-      assertThat(
-          inspector.clazz(TemporalAccessorImpl.class).uniqueMethodWithFinalName("query"),
-          not(isPresent()));
-    } else {
+    if (!(parameters
+            .getApiLevel()
+            .isGreaterThanOrEqualTo(TestBase.apiLevelWithDefaultInterfaceMethodsSupport())
+        && isR8)) {
       assertThat(
           inspector.clazz(TemporalAccessorImplSub.class).uniqueMethodWithFinalName("query"),
           CodeMatchers.invokesMethod(
-              null, TemporalAccessorImpl.class.getTypeName(), "query", null));
+              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));
     }
     if (parameters
         .getApiLevel()
@@ -163,9 +169,7 @@
           not(isPresent()));
     } else {
       assertThat(
-          inspector
-              .clazz(isR8 ? TemporalAccessorImplSub.class : TemporalAccessorImpl.class)
-              .uniqueMethodWithFinalName("query"),
+          inspector.clazz(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 981edea..de87214 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,6 +11,7 @@
 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;
@@ -165,6 +166,14 @@
       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");
     }
   }
 
@@ -198,4 +207,13 @@
       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 d5300ad..1208414 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 abdf5c5..f3caf57 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) {
-    options.desugaredLibrarySpecification =
-        desugaredLibrarySpecification(options, false, parameters);
+    setDesugaredLibrarySpecificationForTesting(
+        options, desugaredLibrarySpecification(options, false, parameters));
   }
 
   private void configurationForLibraryCompilation(InternalOptions options) {
-    options.desugaredLibrarySpecification =
-        desugaredLibrarySpecification(options, true, parameters);
+    setDesugaredLibrarySpecificationForTesting(
+        options, 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 359a18c..9b1804e 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,6 +7,7 @@
 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;
@@ -14,6 +15,7 @@
 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;
@@ -55,9 +57,15 @@
             .putBackportCoreLibraryMember("java.lang.DesugarMath", "java.lang.Math")
             .putRetargetCoreLibMember("java.util.Date#toInstant", "java.util.DesugarDate")
             .build();
-    options.desugaredLibrarySpecification =
-        new LegacyDesugaredLibrarySpecification(
-            LegacyTopLevelFlags.testing(), rewritingFlags, true, options.itemFactory);
+    try {
+      options.setDesugaredLibrarySpecificationForTesting(
+          new LegacyDesugaredLibrarySpecification(
+              LegacyTopLevelFlags.testing(), rewritingFlags, true),
+          ToolHelper.getDesugarJDKLibs(),
+          ToolHelper.getAndroidJar(AndroidApiLevel.R));
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
   }
 
   @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 6bf49a0..e629c47 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,13 +5,7 @@
 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;
@@ -31,19 +25,15 @@
 
   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 machineSpec, boolean shrinkDesugaredLibrary, TestParameters parameters) {
-    this.machineSpec = machineSpec;
+  public RetargetOverrideTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
     this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
     this.parameters = parameters;
   }
@@ -54,7 +44,6 @@
     Path desugaredTwice =
         testForD8(Backend.CF)
             .addLibraryFiles(getLibraryFile())
-            .addOptionsModification(this::setMachineSpec)
             .addProgramFiles(
                 testForD8(Backend.CF)
                     .addLibraryFiles(getLibraryFile())
@@ -76,7 +65,6 @@
       stdout =
           testForD8(Backend.DEX)
               .addProgramFiles(desugaredTwice)
-              .addOptionsModification(this::setMachineSpec)
               .setMinApi(parameters.getApiLevel())
               .disableDesugaring()
               .compile()
@@ -107,22 +95,6 @@
     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());
@@ -130,7 +102,6 @@
     String stdout =
         testForD8()
             .addLibraryFiles(getLibraryFile())
-            .addOptionsModification(this::setMachineSpec)
             .addInnerClasses(RetargetOverrideTest.class)
             .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
             .setMinApi(parameters.getApiLevel())
@@ -156,7 +127,6 @@
     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 f9d1828..7abed46 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,6 +58,7 @@
         .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 6691cb1..a57140b 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, options.itemFactory);
-    options.desugaredLibrarySpecification = specification;
+            LegacyTopLevelFlags.testing(), rewritingFlags, l8Compilation);
+    setDesugaredLibrarySpecificationForTesting(options, 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 aa97e55..957515a 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,9 +87,10 @@
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
         .addOptionsModification(
             opt ->
-                opt.desugaredLibrarySpecification =
+                setDesugaredLibrarySpecificationForTesting(
+                    opt,
                     configurationWithSupportAllCallbacksFromLibrary(
-                        opt, false, parameters, supportAllCallbacksFromLibrary))
+                        opt, false, parameters, supportAllCallbacksFromLibrary)))
         .compile()
         .inspect(this::assertDoubleForEach)
         .inspect(this::assertWrapperMethodsPresent)
@@ -151,9 +152,10 @@
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
         .addOptionsModification(
             opt ->
-                opt.desugaredLibrarySpecification =
+                setDesugaredLibrarySpecificationForTesting(
+                    opt,
                     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 6b7d86e..b966b00 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,9 +71,10 @@
                         this.buildDesugaredLibrary(
                             api,
                             opt ->
-                                opt.desugaredLibrarySpecification =
+                                setDesugaredLibrarySpecificationForTesting(
+                                    opt,
                                     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 a669527..aaab5cb 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,6 +58,7 @@
         .setMinApi(parameters.getApiLevel())
         .addProgramClasses(BaselineExecutor.class)
         .addLibraryClasses(CustomLibClass.class)
+        .addLibraryFiles(getLibraryFile())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
         .compile()
         .addDesugaredCoreLibraryRunClassPath(
@@ -98,6 +99,7 @@
         .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 2bd50b2..3b6ae0a 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,6 +270,7 @@
               .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()
@@ -303,6 +304,7 @@
           .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 f3103f1..bf94752 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,10 +12,13 @@
 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;
@@ -75,11 +78,27 @@
                 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))
+                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));
+                })
             .compile();
 
     testForR8(parameters.getBackend())