Relands "Read the app once while converting specification"

Relands "Use LazyLoadedDexApp on Specification conversion"
This reverts commit fc09dd0c879b782b226c328ee0771615febd0f06.
This reverts commit d1ea2cd6ea53b58791528e53e53ca82d9241909d.

Bug: 221224178
Change-Id: Ib810acbd04e9644d8363a5510251aff994efac63
diff --git a/src/main/java/com/android/tools/r8/GenerateLintFiles.java b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
index bc6cb77..051565e 100644
--- a/src/main/java/com/android/tools/r8/GenerateLintFiles.java
+++ b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
@@ -87,7 +87,7 @@
         readDesugaredLibraryConfiguration(desugarConfigurationPath);
     Path androidJarPath = getAndroidJarPath(specification.getRequiredCompilationApiLevel());
     this.desugaredLibrarySpecification =
-        specification.toMachineSpecification(options, androidJarPath);
+        specification.toMachineSpecification(options, androidJarPath, Timing.empty());
 
     this.desugaredLibraryImplementation = Paths.get(desugarImplementationPath);
     this.outputDirectory = Paths.get(outputDirectory);
diff --git a/src/main/java/com/android/tools/r8/graph/DexApplication.java b/src/main/java/com/android/tools/r8/graph/DexApplication.java
index feedd6c..5dd4a97 100644
--- a/src/main/java/com/android/tools/r8/graph/DexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DexApplication.java
@@ -20,6 +20,7 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
+import java.util.function.Consumer;
 import java.util.function.Predicate;
 
 public abstract class DexApplication implements DexDefinitionSupplier {
@@ -116,6 +117,10 @@
 
   abstract Collection<DexProgramClass> programClasses();
 
+  public abstract void forEachProgramType(Consumer<DexType> consumer);
+
+  public abstract void forEachLibraryType(Consumer<DexType> consumer);
+
   public Collection<DexProgramClass> classes() {
     ReorderBox<DexProgramClass> box = new ReorderBox<>(programClasses());
     assert box.reorderClasses();
diff --git a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
index dd95a2d..1f756ee 100644
--- a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
@@ -23,6 +23,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.Consumer;
 
 public class DirectMappedDexApplication extends DexApplication {
 
@@ -65,6 +66,16 @@
     return programClasses;
   }
 
+  @Override
+  public void forEachProgramType(Consumer<DexType> consumer) {
+    programClasses.forEach(clazz -> consumer.accept(clazz.type));
+  }
+
+  @Override
+  public void forEachLibraryType(Consumer<DexType> consumer) {
+    libraryClasses.forEach((type, clazz) -> consumer.accept(type));
+  }
+
   public Collection<DexLibraryClass> libraryClasses() {
     return libraryClasses.values();
   }
diff --git a/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java b/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
index b781f0b..49ef4af 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
@@ -54,6 +54,16 @@
   }
 
   @Override
+  public void forEachProgramType(Consumer<DexType> consumer) {
+    programClasses.getAllTypes().forEach(consumer);
+  }
+
+  @Override
+  public void forEachLibraryType(Consumer<DexType> consumer) {
+    libraryClasses.getAllClassProviderTypes().forEach(consumer);
+  }
+
+  @Override
   public ClassResolutionResult contextIndependentDefinitionForWithResolutionResult(DexType type) {
     ClassResolutionResult.Builder builder = ClassResolutionResult.builder();
     if (libraryClasses != null) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAmender.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAmender.java
index bd146e9..c943028 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAmender.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAmender.java
@@ -4,11 +4,14 @@
 
 package com.android.tools.r8.ir.desugar.desugaredlibrary;
 
+import com.android.tools.r8.androidapi.ComputedApiLevel;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.MethodAccessFlags;
+import com.android.tools.r8.utils.Reporter;
 import java.util.Map;
 
 /**
@@ -18,21 +21,34 @@
  */
 public class DesugaredLibraryAmender {
 
-  private final AppView<?> appView;
+  private final DexDefinitionSupplier definitions;
+  private final Reporter reporter;
+  private final ComputedApiLevel minAPILevel;
 
   public static void run(AppView<?> appView) {
-    run(appView, appView.options().machineDesugaredLibrarySpecification.getAmendLibraryMethods());
+    run(
+        appView.options().machineDesugaredLibrarySpecification.getAmendLibraryMethods(),
+        appView,
+        appView.options().reporter,
+        appView.computedMinApiLevel());
   }
 
-  public static void run(AppView<?> appView, Map<DexMethod, MethodAccessFlags> amendLibrary) {
+  public static void run(
+      Map<DexMethod, MethodAccessFlags> amendLibrary,
+      DexDefinitionSupplier definitions,
+      Reporter reporter,
+      ComputedApiLevel minAPILevel) {
     if (amendLibrary.isEmpty()) {
       return;
     }
-    new DesugaredLibraryAmender(appView).run(amendLibrary);
+    new DesugaredLibraryAmender(definitions, reporter, minAPILevel).run(amendLibrary);
   }
 
-  private DesugaredLibraryAmender(AppView<?> appView) {
-    this.appView = appView;
+  private DesugaredLibraryAmender(
+      DexDefinitionSupplier definitions, Reporter reporter, ComputedApiLevel minAPILevel) {
+    this.definitions = definitions;
+    this.reporter = reporter;
+    this.minAPILevel = minAPILevel;
   }
 
   private void run(Map<DexMethod, MethodAccessFlags> amendLibrary) {
@@ -40,17 +56,14 @@
   }
 
   private void amendLibraryMethod(DexMethod method, MethodAccessFlags methodAccessFlags) {
-    DexClass dexClass = appView.contextIndependentDefinitionFor(method.getHolderType());
+    DexClass dexClass = definitions.contextIndependentDefinitionFor(method.getHolderType());
     if (dexClass == null || !dexClass.isLibraryClass()) {
       // Consider just throwing an error.
-      appView
-          .options()
-          .reporter
-          .warning(
-              "Desugared library: Cannot amend library method "
-                  + method
-                  + " because the holder is not a library class"
-                  + (dexClass == null ? "(null)." : "."));
+      reporter.warning(
+          "Desugared library: Cannot amend library method "
+              + method
+              + " because the holder is not a library class"
+              + (dexClass == null ? "(null)." : "."));
       return;
     }
     if (dexClass.lookupMethod(method) != null) {
@@ -61,7 +74,7 @@
             .setMethod(method)
             .setAccessFlags(methodAccessFlags)
             .setCode(null)
-            .setApiLevelForDefinition(appView.computedMinApiLevel())
+            .setApiLevelForDefinition(minAPILevel)
             .build();
     dexClass.getMethodCollection().addMethod(encodedMethod);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecification.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecification.java
index f96e5cd..9d3bf12 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecification.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecification.java
@@ -4,12 +4,11 @@
 
 package com.android.tools.r8.ir.desugar.desugaredlibrary;
 
-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.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.Timing;
 import java.io.IOException;
 import java.nio.file.Path;
 import java.util.List;
@@ -24,14 +23,6 @@
     return false;
   }
 
-  default LegacyDesugaredLibrarySpecification asLegacyDesugaredLibrarySpecification() {
-    return null;
-  }
-
-  default HumanDesugaredLibrarySpecification asHumanDesugaredLibrarySpecification() {
-    return null;
-  }
-
   boolean isEmpty();
 
   boolean isLibraryCompilation();
@@ -45,14 +36,15 @@
   AndroidApiLevel getRequiredCompilationApiLevel();
 
   MachineDesugaredLibrarySpecification toMachineSpecification(
-      InternalOptions options, AndroidApp app) throws IOException;
+      InternalOptions options, AndroidApp app, Timing timing) throws IOException;
 
   MachineDesugaredLibrarySpecification toMachineSpecification(
-      InternalOptions options, Path library, Path desugaredJDKLib) throws IOException;
+      InternalOptions options, Path library, Timing timing, Path desugaredJDKLib)
+      throws IOException;
 
   default MachineDesugaredLibrarySpecification toMachineSpecification(
-      InternalOptions options, Path library) throws IOException {
+      InternalOptions options, Path library, Timing timing) throws IOException {
     assert !isLibraryCompilation();
-    return toMachineSpecification(options, library, null);
+    return toMachineSpecification(options, library, timing, null);
   }
 }
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 6291b7b..238ae7b 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
@@ -3,22 +3,16 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification;
 
-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.DexMethod;
-import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
 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.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.Timing;
 import java.io.IOException;
 import java.nio.file.Path;
 import java.util.List;
-import java.util.Map;
-import java.util.Set;
 
 public class HumanDesugaredLibrarySpecification implements DesugaredLibrarySpecification {
 
@@ -50,11 +44,6 @@
     return true;
   }
 
-  @Override
-  public HumanDesugaredLibrarySpecification asHumanDesugaredLibrarySpecification() {
-    return this;
-  }
-
   public boolean supportAllCallbacksFromLibrary() {
     return topLevelFlags.supportAllCallbacksFromLibrary();
   }
@@ -86,61 +75,6 @@
     return topLevelFlags.getIdentifier();
   }
 
-  public Map<String, String> getRewritePrefix() {
-    return rewritingFlags.getRewritePrefix();
-  }
-
-  public boolean hasEmulatedLibraryInterfaces() {
-    return !getEmulateLibraryInterface().isEmpty();
-  }
-
-  public Map<DexType, DexType> getEmulateLibraryInterface() {
-    return rewritingFlags.getEmulatedInterfaces();
-  }
-
-  // If the method is retargeted, answers the retargeted method, else null.
-  public DexMethod retargetMethod(DexEncodedMethod method, AppView<?> appView) {
-    Map<DexMethod, DexType> retargetCoreLibMember = rewritingFlags.getRetargetMethod();
-    DexType dexType = retargetCoreLibMember.get(method.getReference());
-    if (dexType != null) {
-      return appView
-          .dexItemFactory()
-          .createMethod(
-              dexType,
-              appView.dexItemFactory().prependHolderToProto(method.getReference()),
-              method.getName());
-    }
-    return null;
-  }
-
-  public DexMethod retargetMethod(DexClassAndMethod method, AppView<?> appView) {
-    return retargetMethod(method.getDefinition(), appView);
-  }
-
-  public Map<DexMethod, DexType> getRetargetCoreLibMember() {
-    return rewritingFlags.getRetargetMethod();
-  }
-
-  public Map<DexType, DexType> getBackportCoreLibraryMember() {
-    return rewritingFlags.getLegacyBackport();
-  }
-
-  public Map<DexType, DexType> getCustomConversions() {
-    return rewritingFlags.getCustomConversions();
-  }
-
-  public Set<DexType> getWrapperConversions() {
-    return rewritingFlags.getWrapperConversions();
-  }
-
-  public Set<DexMethod> getDontRewriteInvocation() {
-    return rewritingFlags.getDontRewriteInvocation();
-  }
-
-  public Set<DexType> getDontRetargetLibMember() {
-    return rewritingFlags.getDontRetarget();
-  }
-
   @Override
   public List<String> getExtraKeepRules() {
     return topLevelFlags.getExtraKeepRules();
@@ -157,19 +91,15 @@
 
   @Override
   public MachineDesugaredLibrarySpecification toMachineSpecification(
-      InternalOptions options, AndroidApp app) throws IOException {
-    return new HumanToMachineSpecificationConverter()
-        .convert(
-            this,
-            isLibraryCompilation() ? app.getProgramResourceProviders() : null,
-            app.getLibraryResourceProviders(),
-            options);
+      InternalOptions options, AndroidApp app, Timing timing) throws IOException {
+    return new HumanToMachineSpecificationConverter(timing).convert(this, app, options);
   }
 
   @Override
   public MachineDesugaredLibrarySpecification toMachineSpecification(
-      InternalOptions options, Path library, Path desugaredJDKLib) throws IOException {
-    return new HumanToMachineSpecificationConverter()
-        .convert(this, isLibraryCompilation() ? desugaredJDKLib : null, library, options);
+      InternalOptions options, Path library, Timing timing, Path desugaredJDKLib)
+      throws IOException {
+    return new HumanToMachineSpecificationConverter(timing)
+        .convertForTesting(this, desugaredJDKLib, library, options);
   }
 }
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 3616303..3daf522 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
@@ -15,7 +15,7 @@
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.Pair;
+import com.android.tools.r8.utils.Timing;
 import java.io.IOException;
 import java.nio.file.Path;
 import java.util.List;
@@ -47,11 +47,6 @@
     return true;
   }
 
-  @Override
-  public LegacyDesugaredLibrarySpecification asLegacyDesugaredLibrarySpecification() {
-    return this;
-  }
-
   public LegacyTopLevelFlags getTopLevelFlags() {
     return topLevelFlags;
   }
@@ -83,18 +78,6 @@
     return topLevelFlags.getIdentifier();
   }
 
-  public Map<String, String> getRewritePrefix() {
-    return rewritingFlags.getRewritePrefix();
-  }
-
-  public boolean hasEmulatedLibraryInterfaces() {
-    return !getEmulateLibraryInterface().isEmpty();
-  }
-
-  public Map<DexType, DexType> getEmulateLibraryInterface() {
-    return rewritingFlags.getEmulateLibraryInterface();
-  }
-
   // If the method is retargeted, answers the retargeted method, else null.
   public DexMethod retargetMethod(DexEncodedMethod method, AppView<?> appView) {
     Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
@@ -115,14 +98,6 @@
     return retargetMethod(method.getDefinition(), appView);
   }
 
-  public Map<DexString, Map<DexType, DexType>> getRetargetCoreLibMember() {
-    return rewritingFlags.getRetargetCoreLibMember();
-  }
-
-  public Map<DexType, DexType> getBackportCoreLibraryMember() {
-    return rewritingFlags.getBackportCoreLibraryMember();
-  }
-
   public Map<DexType, DexType> getCustomConversions() {
     return rewritingFlags.getCustomConversions();
   }
@@ -131,13 +106,6 @@
     return rewritingFlags.getWrapperConversions();
   }
 
-  public List<Pair<DexType, DexString>> getDontRewriteInvocation() {
-    return rewritingFlags.getDontRewriteInvocation();
-  }
-
-  public Set<DexType> getDontRetargetLibMember() {
-    return rewritingFlags.getDontRetargetLibMember();
-  }
 
   @Override
   public List<String> getExtraKeepRules() {
@@ -151,17 +119,18 @@
 
   @Override
   public MachineDesugaredLibrarySpecification toMachineSpecification(
-      InternalOptions options, AndroidApp app) throws IOException {
-    return new LegacyToHumanSpecificationConverter()
-        .convert(this, app.getLibraryResourceProviders(), options)
-        .toMachineSpecification(options, app);
+      InternalOptions options, AndroidApp app, Timing timing) throws IOException {
+    return new LegacyToHumanSpecificationConverter(timing)
+        .convert(this, app, options)
+        .toMachineSpecification(options, app, timing);
   }
 
   @Override
   public MachineDesugaredLibrarySpecification toMachineSpecification(
-      InternalOptions options, Path library, Path desugaredJDKLib) throws IOException {
-    return new LegacyToHumanSpecificationConverter()
-        .convert(this, library, options)
-        .toMachineSpecification(options, library, desugaredJDKLib);
+      InternalOptions options, Path library, Timing timing, Path desugaredJDKLib)
+      throws IOException {
+    return new LegacyToHumanSpecificationConverter(timing)
+        .convertForTesting(this, desugaredJDKLib, library, options)
+        .toMachineSpecification(options, library, timing, desugaredJDKLib);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/AppForSpecConversion.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/AppForSpecConversion.java
new file mode 100644
index 0000000..45f9dae
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/AppForSpecConversion.java
@@ -0,0 +1,71 @@
+// 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.ClassFileResourceProvider;
+import com.android.tools.r8.ProgramResourceProvider;
+import com.android.tools.r8.dex.ApplicationReader;
+import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.ThreadUtils;
+import com.android.tools.r8.utils.Timing;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.concurrent.ExecutorService;
+
+public class AppForSpecConversion {
+  static DexApplication readApp(
+      AndroidApp inputApp, InternalOptions options, boolean libraryCompilation, Timing timing)
+      throws IOException {
+    timing.begin("Read App");
+    AndroidApp.Builder builder = AndroidApp.builder();
+    for (ClassFileResourceProvider classFileResourceProvider :
+        inputApp.getLibraryResourceProviders()) {
+      builder.addLibraryResourceProvider(classFileResourceProvider);
+    }
+    if (libraryCompilation) {
+      for (ProgramResourceProvider programResourceProvider :
+          inputApp.getProgramResourceProviders()) {
+        builder.addProgramResourceProvider(programResourceProvider);
+      }
+    }
+    DexApplication app = internalReadApp(builder.build(), options, timing);
+    timing.end();
+    return app;
+  }
+
+  static DexApplication readAppForTesting(
+      Path desugaredJDKLib,
+      Path androidLib,
+      InternalOptions options,
+      boolean libraryCompilation,
+      Timing timing)
+      throws IOException {
+    timing.begin("Read App for testing");
+    assert !libraryCompilation || desugaredJDKLib != null;
+    AndroidApp.Builder builder = AndroidApp.builder();
+    if (libraryCompilation) {
+      builder.addProgramFile(desugaredJDKLib);
+    }
+    AndroidApp inputApp = builder.addLibraryFile(androidLib).build();
+    DexApplication app = internalReadApp(inputApp, options, timing);
+    timing.end();
+    return app;
+  }
+
+  private static DexApplication internalReadApp(
+      AndroidApp inputApp, InternalOptions options, Timing timing) throws IOException {
+    timing.begin("Internal Read App");
+    ApplicationReader applicationReader = new ApplicationReader(inputApp, options, timing);
+    ExecutorService executorService = ThreadUtils.getExecutorService(options);
+    assert !options.ignoreJavaLibraryOverride;
+    options.ignoreJavaLibraryOverride = true;
+    DexApplication app = applicationReader.read(executorService);
+    options.ignoreJavaLibraryOverride = false;
+    timing.end();
+    return app;
+  }
+}
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 5dad42c..e0ae560 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,7 +5,6 @@
 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.DexString;
 import com.android.tools.r8.graph.DexType;
@@ -88,14 +87,13 @@
   }
 
   private void rewriteClasses() {
-    for (DexClass clazz : appInfo.app().asDirect().libraryClasses()) {
-      registerType(clazz.type);
-      registerDifferentType(clazz.type);
-    }
-    for (DexClass clazz : appInfo.classes()) {
-      registerType(clazz.type);
-      registerDifferentType(clazz.type);
-    }
+    appInfo.app().forEachLibraryType(this::registerClassType);
+    appInfo.app().forEachProgramType(this::registerClassType);
+  }
+
+  private void registerClassType(DexType type) {
+    registerType(type);
+    registerDifferentType(type);
   }
 
   private void registerType(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 6268125..a5a27aa 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
@@ -11,8 +11,6 @@
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.MethodResolutionResult;
-import com.android.tools.r8.graph.SubtypingInfo;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanRewritingFlags;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.DerivedMethod;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.EmulatedDispatchMethodDescriptor;
@@ -28,12 +26,10 @@
 public class HumanToMachineRetargetConverter {
 
   private final AppInfoWithClassHierarchy appInfo;
-  private final SubtypingInfo subtypingInfo;
   private final Set<DexMethod> missingMethods = Sets.newIdentityHashSet();
 
   public HumanToMachineRetargetConverter(AppInfoWithClassHierarchy appInfo) {
     this.appInfo = appInfo;
-    subtypingInfo = SubtypingInfo.create(appInfo);
   }
 
   public void convertRetargetFlags(
@@ -91,31 +87,12 @@
     DerivedMethod dispatchMethod =
         new DerivedMethod(src.getReference(), SyntheticKind.RETARGET_CLASS);
     LinkedHashMap<DexType, DerivedMethod> dispatchCases = new LinkedHashMap<>();
-    assert validateNoOverride(src, appInfo, subtypingInfo);
     builder.putEmulatedVirtualRetarget(
         src.getReference(),
         new EmulatedDispatchMethodDescriptor(
             interfaceMethod, dispatchMethod, forwardingMethod, dispatchCases));
   }
 
-  private boolean validateNoOverride(
-      DexEncodedMethod src, AppInfoWithClassHierarchy appInfo, SubtypingInfo subtypingInfo) {
-    for (DexType subtype : subtypingInfo.subtypes(src.getHolderType())) {
-      DexClass subclass = appInfo.definitionFor(subtype);
-      MethodResolutionResult resolutionResult =
-          appInfo.resolveMethodOn(subclass, src.getReference());
-      // The resolution is not successful when compiling to dex if the method rewritten is missing
-      // in Android.jar.
-      assert !resolutionResult.isSuccessfulMemberResolutionResult()
-          || resolutionResult.getResolvedMethod().getReference() == src.getReference()
-          // There is a difference in the sql library between Android.jar and the JDK which leads
-          // to this resolution when compiling Cf to Cf while the methods do not exist in Android.
-          || (resolutionResult.getResolvedMethod().getHolderType().toString().contains("java.sql")
-              && resolutionResult.getResolvedMethod().getName().toString().equals("toInstant"));
-    }
-    return true;
-  }
-
   private boolean isEmulatedInterfaceDispatch(
       DexEncodedMethod method,
       AppInfoWithClassHierarchy appInfo,
@@ -146,19 +123,10 @@
       DexEncodedMethod foundMethod,
       DexType type,
       AppInfoWithClassHierarchy appInfo,
-      SubtypingInfo subtypingInfo,
       BiConsumer<DexMethod, DexMethod> consumer) {
     DexMethod src = foundMethod.getReference();
     DexMethod dest = src.withHolder(type, appInfo.dexItemFactory());
     consumer.accept(src, dest);
-    for (DexType subtype : subtypingInfo.subtypes(foundMethod.getHolderType())) {
-      DexClass subclass = appInfo.definitionFor(subtype);
-      MethodResolutionResult resolutionResult = appInfo.resolveMethodOn(subclass, src);
-      if (resolutionResult.isSuccessfulMemberResolutionResult()
-          && resolutionResult.getResolvedMethod().getReference() == src) {
-        consumer.accept(src.withHolder(subtype, appInfo.dexItemFactory()), dest);
-      }
-    }
   }
 
   private void convertNonEmulatedVirtualRetarget(
@@ -167,7 +135,6 @@
         foundMethod,
         type,
         appInfo,
-        subtypingInfo,
         (src, dest) ->
             builder.putNonEmulatedVirtualRetarget(
                 src,
@@ -177,7 +144,6 @@
 
   private void convertStaticRetarget(
       MachineRewritingFlags.Builder builder, DexEncodedMethod foundMethod, DexType type) {
-    convertNonEmulatedRetarget(
-        foundMethod, type, appInfo, subtypingInfo, builder::putStaticRetarget);
+    convertNonEmulatedRetarget(foundMethod, type, appInfo, builder::putStaticRetarget);
   }
 }
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 51516d4..c0bcd82 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,19 +4,15 @@
 
 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.androidapi.ComputedApiLevel;
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
-import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProto;
 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.graph.DirectMappedDexApplication;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAmender;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecification;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanRewritingFlags;
@@ -27,7 +23,7 @@
 import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineTopLevelFlags;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.ThreadUtils;
+import com.android.tools.r8.utils.Reporter;
 import com.android.tools.r8.utils.Timing;
 import com.google.common.collect.Sets;
 import java.io.IOException;
@@ -35,52 +31,43 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
-import java.util.concurrent.ExecutorService;
 
 public class HumanToMachineSpecificationConverter {
 
-  private AppView<?> appView;
+  private AppInfoWithClassHierarchy appInfo;
+  private Reporter reporter;
   private final Set<DexType> missingCustomConversions = Sets.newIdentityHashSet();
+  private final Timing timing;
 
-  public MachineDesugaredLibrarySpecification convert(
-      HumanDesugaredLibrarySpecification humanSpec,
-      List<ProgramResourceProvider> desugaredJDKLib,
-      List<ClassFileResourceProvider> library,
-      InternalOptions options)
-      throws IOException {
-    assert !humanSpec.isLibraryCompilation() || desugaredJDKLib != null;
-    AndroidApp.Builder builder = AndroidApp.builder();
-    for (ClassFileResourceProvider classFileResourceProvider : library) {
-      builder.addLibraryResourceProvider(classFileResourceProvider);
-    }
-    if (humanSpec.isLibraryCompilation()) {
-      for (ProgramResourceProvider programResourceProvider : desugaredJDKLib) {
-        builder.addProgramResourceProvider(programResourceProvider);
-      }
-    }
-    return internalConvert(humanSpec, builder.build(), options);
+  public HumanToMachineSpecificationConverter(Timing timing) {
+    this.timing = timing;
   }
 
   public MachineDesugaredLibrarySpecification convert(
+      HumanDesugaredLibrarySpecification humanSpec, AndroidApp inputApp, InternalOptions options)
+      throws IOException {
+    DexApplication app =
+        AppForSpecConversion.readApp(inputApp, options, humanSpec.isLibraryCompilation(), timing);
+    return convert(humanSpec, app);
+  }
+
+  public MachineDesugaredLibrarySpecification convertForTesting(
       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);
+    DexApplication app =
+        AppForSpecConversion.readAppForTesting(
+            desugaredJDKLib, androidLib, options, humanSpec.isLibraryCompilation(), timing);
+    return convert(humanSpec, app);
   }
 
-  private MachineDesugaredLibrarySpecification internalConvert(
-      HumanDesugaredLibrarySpecification humanSpec, AndroidApp inputApp, InternalOptions options)
-      throws IOException {
-    DexApplication app = readApp(inputApp, options);
-    appView = AppView.createForD8(AppInfo.createInitialAppInfo(app));
+  private MachineDesugaredLibrarySpecification convert(
+      HumanDesugaredLibrarySpecification humanSpec, DexApplication app) {
+    timing.begin("Human to machine convert");
+    reporter = app.options.reporter;
+    appInfo = AppInfoWithClassHierarchy.createForDesugaring(AppInfo.createInitialAppInfo(app));
     LibraryValidator.validate(
         app,
         humanSpec.isLibraryCompilation(),
@@ -89,6 +76,7 @@
         convertRewritingFlags(
             humanSpec.getSynthesizedLibraryClassesPackagePrefix(), humanSpec.getRewritingFlags());
     MachineTopLevelFlags topLevelFlags = convertTopLevelFlags(humanSpec.getTopLevelFlags());
+    timing.end();
     return new MachineDesugaredLibrarySpecification(
         humanSpec.isLibraryCompilation(), topLevelFlags, machineRewritingFlags);
   }
@@ -105,9 +93,10 @@
 
   private MachineRewritingFlags convertRewritingFlags(
       String synthesizedPrefix, HumanRewritingFlags rewritingFlags) {
-    AppInfoWithClassHierarchy appInfo = appView.appInfoForDesugaring();
+    timing.begin("convert rewriting flags");
     MachineRewritingFlags.Builder builder = MachineRewritingFlags.builder();
-    DesugaredLibraryAmender.run(appView, rewritingFlags.getAmendLibraryMethod());
+    DesugaredLibraryAmender.run(
+        rewritingFlags.getAmendLibraryMethod(), appInfo, reporter, ComputedApiLevel.unknown());
     rewritingFlags.getAmendLibraryMethod().forEach(builder::amendLibraryMethod);
     new HumanToMachineRetargetConverter(appInfo)
         .convertRetargetFlags(rewritingFlags, builder, this::warnMissingReferences);
@@ -126,7 +115,9 @@
         "Cannot register custom conversion due to missing type: ", missingCustomConversions);
     rewritingFlags.getDontRetarget().forEach(builder::addDontRetarget);
     rewritingFlags.getLegacyBackport().forEach(builder::putLegacyBackport);
-    return builder.build();
+    MachineRewritingFlags machineFlags = builder.build();
+    timing.end();
+    return machineFlags;
   }
 
   private void convertCustomConversion(
@@ -152,16 +143,6 @@
     builder.putCustomConversion(type, new CustomConversionDescriptor(toMethod, fromMethod));
   }
 
-  private DexApplication readApp(AndroidApp inputApp, InternalOptions options) throws IOException {
-    ApplicationReader applicationReader = new ApplicationReader(inputApp, options, Timing.empty());
-    ExecutorService executorService = ThreadUtils.getExecutorService(options);
-    assert !options.ignoreJavaLibraryOverride;
-    options.ignoreJavaLibraryOverride = true;
-    DirectMappedDexApplication app = applicationReader.read(executorService).toDirect();
-    options.ignoreJavaLibraryOverride = false;
-    return app;
-  }
-
   void warnMissingReferences(String message, Set<? extends DexReference> missingReferences) {
     List<DexReference> memberList = new ArrayList<>(missingReferences);
     memberList.sort(DexReference::compareTo);
@@ -178,6 +159,6 @@
     if (memberList.isEmpty()) {
       return;
     }
-    appView.options().reporter.warning("Specification conversion: " + message + memberList);
+    reporter.warning("Specification conversion: " + message + memberList);
   }
 }
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 083b880..47ef9e3 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,10 +4,8 @@
 
 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;
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexClass;
@@ -35,7 +33,6 @@
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.Pair;
-import com.android.tools.r8.utils.ThreadUtils;
 import com.android.tools.r8.utils.Timing;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
@@ -46,15 +43,22 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.ExecutorService;
 
 public class LegacyToHumanSpecificationConverter {
 
-  private static final String wrapperPrefix = "__wrapper__.";
-  private AndroidApiLevel legacyHackLevel = AndroidApiLevel.N_MR1;
+  private static final String WRAPPER_PREFIX = "__wrapper__.";
+  private static final AndroidApiLevel LEGACY_HACK_LEVEL = AndroidApiLevel.N_MR1;
+  private final Timing timing;
+
+  public LegacyToHumanSpecificationConverter(Timing timing) {
+    this.timing = timing;
+  }
 
   public void convertAllAPILevels(
-      StringResource inputSpecification, Path androidLib, StringConsumer output)
+      StringResource inputSpecification,
+      Path desugaredJDKLib,
+      Path androidLib,
+      StringConsumer output)
       throws IOException {
     InternalOptions options = new InternalOptions();
     MultiAPILevelLegacyDesugaredLibrarySpecification legacySpec =
@@ -62,18 +66,21 @@
                 options.dexItemFactory(), options.reporter)
             .parseMultiLevelConfiguration(inputSpecification);
     MultiAPILevelHumanDesugaredLibrarySpecification humanSpec =
-        convertAllAPILevels(legacySpec, androidLib, options);
+        convertAllAPILevels(legacySpec, desugaredJDKLib, androidLib, options);
     MultiAPILevelHumanDesugaredLibrarySpecificationJsonExporter.export(humanSpec, output);
   }
 
   public MultiAPILevelHumanDesugaredLibrarySpecification convertAllAPILevels(
       MultiAPILevelLegacyDesugaredLibrarySpecification legacySpec,
+      Path desugaredJDKLib,
       Path androidLib,
       InternalOptions options)
       throws IOException {
+    timing.begin("Legacy to human all API convert");
     Origin origin = legacySpec.getOrigin();
-    AndroidApp androidApp = AndroidApp.builder().addLibraryFile(androidLib).build();
-    DexApplication app = readApp(androidApp, options);
+    DexApplication app =
+        AppForSpecConversion.readAppForTesting(desugaredJDKLib, androidLib, options, true, timing);
+
     HumanTopLevelFlags humanTopLevelFlags = convertTopLevelFlags(legacySpec.getTopLevelFlags());
     Int2ObjectArrayMap<HumanRewritingFlags> commonFlags =
         convertRewritingFlagMap(legacySpec.getCommonFlags(), app, origin);
@@ -89,32 +96,34 @@
             origin, humanTopLevelFlags, commonFlags, libraryFlags, programFlags);
     MultiAPILevelHumanDesugaredLibrarySpecificationFlagDeduplicator.deduplicateFlags(
         humanSpec, options.reporter);
+    timing.end();
     return humanSpec;
   }
 
   public HumanDesugaredLibrarySpecification convert(
+      LegacyDesugaredLibrarySpecification legacySpec, AndroidApp inputApp, InternalOptions options)
+      throws IOException {
+    DexApplication app =
+        AppForSpecConversion.readApp(inputApp, options, legacySpec.isLegacy(), timing);
+    return convert(legacySpec, app, options);
+  }
+
+  public HumanDesugaredLibrarySpecification convertForTesting(
       LegacyDesugaredLibrarySpecification legacySpec,
-      List<ClassFileResourceProvider> library,
+      Path desugaredJDKLib,
+      Path androidLib,
       InternalOptions options)
       throws IOException {
-    AndroidApp.Builder builder = AndroidApp.builder();
-    for (ClassFileResourceProvider classFileResourceProvider : library) {
-      builder.addLibraryResourceProvider(classFileResourceProvider);
-    }
-    return internalConvert(legacySpec, builder.build(), options);
+    DexApplication app =
+        AppForSpecConversion.readAppForTesting(
+            desugaredJDKLib, androidLib, options, legacySpec.isLibraryCompilation(), timing);
+    return convert(legacySpec, app, options);
   }
 
   public HumanDesugaredLibrarySpecification convert(
-      LegacyDesugaredLibrarySpecification legacySpec, Path androidLib, InternalOptions options)
+      LegacyDesugaredLibrarySpecification legacySpec, DexApplication app, InternalOptions options)
       throws IOException {
-    AndroidApp androidApp = AndroidApp.builder().addLibraryFile(androidLib).build();
-    return internalConvert(legacySpec, androidApp, options);
-  }
-
-  public HumanDesugaredLibrarySpecification internalConvert(
-      LegacyDesugaredLibrarySpecification legacySpec, AndroidApp inputApp, InternalOptions options)
-      throws IOException {
-    DexApplication app = readApp(inputApp, options);
+    timing.begin("Legacy to Human convert");
     LibraryValidator.validate(
         app,
         legacySpec.isLibraryCompilation(),
@@ -127,20 +136,24 @@
     Origin origin = Origin.unknown();
     HumanRewritingFlags humanRewritingFlags =
         convertRewritingFlags(legacySpec.getRewritingFlags(), app, origin);
-    if (options.getMinApiLevel().isLessThanOrEqualTo(legacyHackLevel)
+    if (options.getMinApiLevel().isLessThanOrEqualTo(LEGACY_HACK_LEVEL)
         && legacySpec.isLibraryCompilation()) {
+      timing.begin("Legacy hacks");
       HumanRewritingFlags.Builder builder =
           humanRewritingFlags.newBuilder(app.options.reporter, origin);
       legacyLibraryFlagHacks(app.dexItemFactory(), builder);
       humanRewritingFlags = builder.build();
+      timing.end();
     }
+
+    timing.end();
     return new HumanDesugaredLibrarySpecification(
         humanTopLevelFlags, humanRewritingFlags, legacySpec.isLibraryCompilation());
   }
 
   private void legacyLibraryFlagHacks(
       Int2ObjectArrayMap<HumanRewritingFlags> libraryFlags, DexApplication app, Origin origin) {
-    int level = legacyHackLevel.getLevel();
+    int level = LEGACY_HACK_LEVEL.getLevel();
     HumanRewritingFlags humanRewritingFlags = libraryFlags.get(level);
     if (humanRewritingFlags == null) {
       // Skip CHM only configuration.
@@ -183,12 +196,6 @@
     builder.retargetMethod(source, target);
   }
 
-  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();
-  }
-
   private Int2ObjectArrayMap<HumanRewritingFlags> convertRewritingFlagMap(
       Int2ObjectMap<LegacyRewritingFlags> libFlags, DexApplication app, Origin origin) {
     Int2ObjectArrayMap<HumanRewritingFlags> map = new Int2ObjectArrayMap<>();
@@ -198,8 +205,8 @@
 
   private HumanRewritingFlags convertRewritingFlags(
       LegacyRewritingFlags flags, DexApplication app, Origin origin) {
+    timing.begin("Convert rewriting flags");
     HumanRewritingFlags.Builder builder = HumanRewritingFlags.builder(app.options.reporter, origin);
-
     flags
         .getRewritePrefix()
         .forEach((prefix, rewritten) -> rewritePrefix(builder, prefix, rewritten));
@@ -208,15 +215,15 @@
     flags.getCustomConversions().forEach(builder::putCustomConversion);
     flags.getDontRetargetLibMember().forEach(builder::addDontRetargetLibMember);
     flags.getWrapperConversions().forEach(builder::addWrapperConversion);
-
     flags
         .getRetargetCoreLibMember()
         .forEach((name, typeMap) -> convertRetargetCoreLibMember(builder, app, name, typeMap));
     flags
         .getDontRewriteInvocation()
         .forEach(pair -> convertDontRewriteInvocation(builder, app, pair));
-
-    return builder.build();
+    HumanRewritingFlags humanFlags = builder.build();
+    timing.end();
+    return humanFlags;
   }
 
   private void rewritePrefix(HumanRewritingFlags.Builder builder, String prefix, String rewritten) {
@@ -227,14 +234,14 @@
       builder.putRewriteDerivedPrefix(rewritten, prefix, rewritten);
       return;
     }
-    if (prefix.equals(wrapperPrefix)) {
+    if (prefix.equals(WRAPPER_PREFIX)) {
       // We hard code here this applies to java.nio and java.io only.
       ImmutableMap<String, String> map =
           ImmutableMap.of("java.nio.", "j$.nio.", "java.io.", "j$.io.");
       map.forEach(
           (k, v) -> {
-            builder.putRewriteDerivedPrefix(k, wrapperPrefix + k, k);
-            builder.putRewriteDerivedPrefix(k, wrapperPrefix + v, v);
+            builder.putRewriteDerivedPrefix(k, WRAPPER_PREFIX + k, k);
+            builder.putRewriteDerivedPrefix(k, WRAPPER_PREFIX + v, v);
           });
       return;
     }
diff --git a/src/main/java/com/android/tools/r8/utils/ClassMap.java b/src/main/java/com/android/tools/r8/utils/ClassMap.java
index 506a990..915a2f7 100644
--- a/src/main/java/com/android/tools/r8/utils/ClassMap.java
+++ b/src/main/java/com/android/tools/r8/utils/ClassMap.java
@@ -163,6 +163,15 @@
     return classes.keySet();
   }
 
+  public Iterable<DexType> getAllClassProviderTypes() {
+    ClassProvider<T> theClassProvider = classProvider.get();
+    if (theClassProvider != null) {
+      return theClassProvider.collectTypes();
+    }
+    throw new CompilationError(
+        "Cannot access all types since the classProvider is no longer available");
+  }
+
   /**
    * Forces loading of all the classes satisfying the criteria specified.
    * <p>
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 38f5093..2b8d72a 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -896,7 +896,13 @@
       return;
     }
     try {
-      machineDesugaredLibrarySpecification = specification.toMachineSpecification(this, app);
+      // TODO(b/221224178): Move the timing to top level timing in D8, R8 and L8.
+      Timing timing = Timing.create("Desugared library specification conversion", this);
+      machineDesugaredLibrarySpecification =
+          specification.toMachineSpecification(this, app, timing);
+      if (printTimes) {
+        timing.report();
+      }
     } catch (IOException e) {
       reporter.error(new ExceptionDiagnostic(e, Origin.unknown()));
     }
@@ -908,8 +914,13 @@
     if (specification.isEmpty()) {
       return;
     }
+    // TODO(b/221224178): Move the timing to top level timing in D8, R8 and L8.
+    Timing timing = Timing.create("Desugared library specification conversion", this);
     machineDesugaredLibrarySpecification =
-        specification.toMachineSpecification(this, library, desugaredJDKLib);
+        specification.toMachineSpecification(this, library, timing, desugaredJDKLib);
+    if (printTimes) {
+      timing.report();
+    }
   }
 
   // Contains flags describing library desugaring.
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java
index 86d87d5..0c4d6f6 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java
@@ -26,6 +26,7 @@
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.Reporter;
+import com.android.tools.r8.utils.Timing;
 import com.android.tools.r8.utils.WorkList;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -139,7 +140,8 @@
             false,
             minApi.getLevel());
     MachineDesugaredLibrarySpecification specification =
-        spec.toMachineSpecification(new InternalOptions(factory, new Reporter()), getLibraryFile());
+        spec.toMachineSpecification(
+            new InternalOptions(factory, new Reporter()), getLibraryFile(), Timing.empty());
     Set<String> wrappersInSpec =
         specification.getWrappers().keySet().stream()
             .map(DexType::toString)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetOverrideTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetOverrideTest.java
index e629c47..5d9cf31 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
@@ -26,7 +26,7 @@
   private final TestParameters parameters;
   private final boolean shrinkDesugaredLibrary;
 
-  @Parameters(name = "machine: {0}, {2}, shrink: {1}")
+  @Parameters(name = "{1}, shrink: {0}")
   public static List<Object[]> data() {
     return buildParameters(
         BooleanUtils.values(),
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java
index 125b4ec..f107b2a 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java
@@ -23,6 +23,7 @@
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.Box;
 import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.Timing;
 import java.io.IOException;
 import java.util.Map;
 import org.junit.Assume;
@@ -46,7 +47,8 @@
   public void testMultiLevel() throws IOException {
     Assume.assumeTrue(ToolHelper.isLocalDevelopment());
 
-    LegacyToHumanSpecificationConverter converter = new LegacyToHumanSpecificationConverter();
+    LegacyToHumanSpecificationConverter converter =
+        new LegacyToHumanSpecificationConverter(Timing.empty());
 
     InternalOptions options = new InternalOptions();
 
@@ -57,7 +59,11 @@
                 StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()));
 
     MultiAPILevelHumanDesugaredLibrarySpecification humanSpec1 =
-        converter.convertAllAPILevels(spec, ToolHelper.getAndroidJar(31), options);
+        converter.convertAllAPILevels(
+            spec,
+            ToolHelper.getDesugarJDKLibs(),
+            ToolHelper.getAndroidJar(getRequiredCompilationAPILevel()),
+            options);
 
     Box<String> json = new Box<>();
     MultiAPILevelHumanDesugaredLibrarySpecificationJsonExporter.export(