Merge commit 'de30207755784daa2e1ededd0de58f26fbabec12' into dev-release
diff --git a/build.gradle b/build.gradle
index d157084..9981676 100644
--- a/build.gradle
+++ b/build.gradle
@@ -781,6 +781,7 @@
 
 def r8CreateTask(name, baseName, sources, includeSwissArmyKnife) {
     return tasks.create("r8Create${name}", Jar) {
+        entryCompression ZipEntryCompression.STORED
         dependsOn sources
         from consolidatedLicense.outputs.files
         from sources.collect { zipTree(it) }
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs.json b/src/library_desugar/jdk11/desugar_jdk_libs.json
index 6893b8f..238f3ee 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs.json
@@ -165,6 +165,16 @@
   ],
   "program_flags": [
     {
+      "api_level_below_or_equal": 32,
+      "api_level_greater_or_equal": 26,
+      "covariant_retarget_method": {
+        "java.time.chrono.IsoEra java.time.LocalDate#getEra()": "java.time.chrono.Era"
+      },
+      "amend_library_method": [
+        "public java.time.chrono.IsoEra java.time.LocalDate#getEra()"
+      ]
+    },
+    {
       "api_level_below_or_equal": 30,
       "retarget_method": {
         "java.time.Instant java.util.Calendar#toInstant()": "java.util.DesugarCalendar",
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_legacy.json b/src/library_desugar/jdk11/desugar_jdk_libs_legacy.json
index 730a294..b92af9f 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs_legacy.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs_legacy.json
@@ -1,14 +1,14 @@
 {
-  "configuration_format_version": 4,
+  "configuration_format_version": 5,
   "group_id" : "com.tools.android",
   "artifact_id" : "desugar_jdk_libs",
-  "version": "1.2.0-alpha01",
+  "version": "1.2.0",
   "required_compilation_api_level": 30,
   "synthesized_library_classes_package_prefix": "j$.",
   "support_all_callbacks_from_library": true,
   "common_flags": [
     {
-      "api_level_below_or_equal": 30,
+      "api_level_below_or_equal": 10000,
       "rewrite_prefix": {
         "java.time.": "j$.time.",
         "java.util.Desugar": "j$.util.Desugar"
@@ -37,20 +37,15 @@
       }
     },
     {
-      "api_level_below_or_equal": 28,
+      "api_level_below_or_equal": 23,
       "rewrite_prefix": {
-        "java.util.DoubleSummaryStatistics": "j$.util.DoubleSummaryStatistics",
-        "java.util.IntSummaryStatistics": "j$.util.IntSummaryStatistics",
-        "java.util.LongSummaryStatistics": "j$.util.LongSummaryStatistics",
-        "java.util.Optional": "j$.util.Optional",
-        "java.util.PrimitiveIterator": "j$.util.PrimitiveIterator",
-        "java.util.Spliterator": "j$.util.Spliterator",
-        "java.util.StringJoiner": "j$.util.StringJoiner",
-        "java.util.concurrent.ConcurrentHashMap": "j$.util.concurrent.ConcurrentHashMap",
-        "java.util.concurrent.ThreadLocalRandom": "j$.util.concurrent.ThreadLocalRandom",
-        "java.util.concurrent.atomic.DesugarAtomic": "j$.util.concurrent.atomic.DesugarAtomic",
-        "java.util.function.": "j$.util.function.",
-        "java.util.stream.": "j$.util.stream."
+        "java.util.concurrent.atomic.DesugarAtomic": "j$.util.concurrent.atomic.DesugarAtomic"
+      }
+    },
+    {
+      "api_level_below_or_equal": 23,
+      "rewrite_prefix": {
+        "java.util.function.": "j$.util.function."
       },
       "emulate_interface": {
         "java.lang.Iterable": "j$.lang.Iterable",
@@ -66,7 +61,22 @@
       },
       "dont_rewrite": [
         "java.util.Iterator#remove"
-      ],
+      ]
+    },
+    {
+      "api_level_below_or_equal": 10000,
+      "rewrite_prefix": {
+        "java.util.DoubleSummaryStatistics": "j$.util.DoubleSummaryStatistics",
+        "java.util.IntSummaryStatistics": "j$.util.IntSummaryStatistics",
+        "java.util.LongSummaryStatistics": "j$.util.LongSummaryStatistics",
+        "java.util.Optional": "j$.util.Optional",
+        "java.util.PrimitiveIterator": "j$.util.PrimitiveIterator",
+        "java.util.Spliterator": "j$.util.Spliterator",
+        "java.util.StringJoiner": "j$.util.StringJoiner",
+        "java.util.concurrent.ConcurrentHashMap": "j$.util.concurrent.ConcurrentHashMap",
+        "java.util.concurrent.ThreadLocalRandom": "j$.util.concurrent.ThreadLocalRandom",
+        "java.util.stream.": "j$.util.stream."
+      },
       "retarget_lib_member": {
         "java.util.Arrays#spliterator": "java.util.DesugarArrays",
         "java.util.Arrays#stream": "java.util.DesugarArrays",
@@ -137,7 +147,7 @@
   ],
   "program_flags": [
     {
-      "api_level_below_or_equal": 30,
+      "api_level_below_or_equal": 10000,
       "retarget_lib_member": {
         "java.util.TimeZone#getTimeZone": "java.util.DesugarTimeZone",
         "java.util.Calendar#toInstant": "java.util.DesugarCalendar",
@@ -167,9 +177,10 @@
   ],
   "library_flags": [
     {
-      "api_level_below_or_equal": 30,
+      "api_level_below_or_equal": 10000,
       "rewrite_prefix": {
         "j$.time.": "java.time.",
+        "java.lang.Desugar": "j$.lang.Desugar",
         "jdk.internal.": "j$.jdk.internal.",
         "sun.misc.Desugar": "j$.sun.misc.Desugar",
         "sun.security.action.": "j$.sun.security.action."
@@ -182,7 +193,7 @@
       }
     },
     {
-      "api_level_below_or_equal": 28,
+      "api_level_below_or_equal": 10000,
       "rewrite_prefix": {
         "java.util.AbstractList": "j$.util.AbstractList",
         "java.util.CollSer": "j$.util.CollSer",
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_path.json b/src/library_desugar/jdk11/desugar_jdk_libs_path.json
index a61df55..03ca930 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs_path.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs_path.json
@@ -268,6 +268,16 @@
   ],
   "program_flags": [
     {
+      "api_level_below_or_equal": 32,
+      "api_level_greater_or_equal": 26,
+      "covariant_retarget_method": {
+        "java.time.chrono.IsoEra java.time.LocalDate#getEra()": "java.time.chrono.Era"
+      },
+      "amend_library_method": [
+        "public java.time.chrono.IsoEra java.time.LocalDate#getEra()"
+      ]
+    },
+    {
       "api_level_below_or_equal": 30,
       "retarget_method": {
         "java.time.Instant java.util.Calendar#toInstant()": "java.util.DesugarCalendar",
diff --git a/src/main/java/com/android/tools/r8/CompilationMode.java b/src/main/java/com/android/tools/r8/CompilationMode.java
index fb02504..9288a35 100644
--- a/src/main/java/com/android/tools/r8/CompilationMode.java
+++ b/src/main/java/com/android/tools/r8/CompilationMode.java
@@ -9,5 +9,13 @@
   /** Preserves debugging information during compilation, eg, line-numbers and locals. */
   DEBUG,
   /** Strips debugging information that cannot affect stack traces. */
-  RELEASE
+  RELEASE;
+
+  public boolean isDebug() {
+    return this == DEBUG;
+  }
+
+  public boolean isRelease() {
+    return this == RELEASE;
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index 7cb5133..9393f4d 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -281,9 +281,8 @@
       Marker.checkCompatibleDesugaredLibrary(markers, options.reporter);
 
       InspectorImpl.runInspections(options.outputInspections, appView.appInfo().classes());
-      NamingLens namingLens = NamingLens.getIdentityLens();
-      namingLens = PrefixRewritingNamingLens.createPrefixRewritingNamingLens(appView, namingLens);
-      namingLens = RecordRewritingNamingLens.createRecordRewritingNamingLens(appView, namingLens);
+      appView.setNamingLens(PrefixRewritingNamingLens.createPrefixRewritingNamingLens(appView));
+      appView.setNamingLens(RecordRewritingNamingLens.createRecordRewritingNamingLens(appView));
 
       if (options.isGeneratingDex()
           && hasDexResources
@@ -294,17 +293,15 @@
         // without iterating again the IR. We fall-back to writing one app with rewriting and
         // merging it with the other app in rewriteNonDexInputs.
         timing.begin("Rewrite non-dex inputs");
-        DexApplication app =
-            rewriteNonDexInputs(
-                appView, inputApp, options, executor, timing, appView.appInfo().app(), namingLens);
+        DexApplication app = rewriteNonDexInputs(appView, inputApp, executor, timing);
         timing.end();
         appView.setAppInfo(
             new AppInfo(
                 appView.appInfo().getSyntheticItems().commit(app),
                 appView.appInfo().getMainDexInfo()));
-        namingLens = NamingLens.getIdentityLens();
+        appView.setNamingLens(NamingLens.getIdentityLens());
       } else if (options.isGeneratingDex() && hasDexResources) {
-        namingLens = NamingLens.getIdentityLens();
+        appView.setNamingLens(NamingLens.getIdentityLens());
       }
 
       // Since tracing is not lens aware, this needs to be done prior to synthetic finalization
@@ -322,21 +319,16 @@
 
       HorizontalClassMerger.createForD8ClassMerging(appView).runIfNecessary(executor, timing);
 
-      new GenericSignatureRewriter(appView, namingLens)
-          .runForD8(appView.appInfo().classes(), executor);
-      new KotlinMetadataRewriter(appView, namingLens).runForD8(executor);
+      new GenericSignatureRewriter(appView).runForD8(appView.appInfo().classes(), executor);
+      new KotlinMetadataRewriter(appView).runForD8(executor);
 
       if (options.isGeneratingClassFiles()) {
-        new CfApplicationWriter(appView, marker, namingLens)
-            .write(options.getClassFileConsumer(), inputApp);
+        new CfApplicationWriter(appView, marker).write(options.getClassFileConsumer(), inputApp);
       } else {
         if (options.apiModelingOptions().enableStubbingOfClasses) {
           new ApiReferenceStubber(appView).run(executor);
         }
-        new ApplicationWriter(
-                appView,
-                marker == null ? null : ImmutableList.copyOf(markers),
-                namingLens)
+        new ApplicationWriter(appView, marker == null ? null : ImmutableList.copyOf(markers))
             .write(executor, inputApp);
       }
       options.printWarnings();
@@ -357,13 +349,7 @@
   }
 
   private static DexApplication rewriteNonDexInputs(
-      AppView<AppInfo> appView,
-      AndroidApp inputApp,
-      InternalOptions options,
-      ExecutorService executor,
-      Timing timing,
-      DexApplication app,
-      NamingLens desugaringLens)
+      AppView<AppInfo> appView, AndroidApp inputApp, ExecutorService executor, Timing timing)
       throws IOException, ExecutionException {
     // TODO(b/154575955): Remove the naming lens in D8.
     appView
@@ -376,33 +362,33 @@
                     + " dex the class file inputs and dex merging only dex files."));
     List<DexProgramClass> dexProgramClasses = new ArrayList<>();
     List<DexProgramClass> nonDexProgramClasses = new ArrayList<>();
-    for (DexProgramClass aClass : app.classes()) {
+    for (DexProgramClass aClass : appView.appInfo().classes()) {
       if (aClass.originatesFromDexResource()) {
         dexProgramClasses.add(aClass);
       } else {
         nonDexProgramClasses.add(aClass);
       }
     }
-    DexApplication cfApp = app.builder().replaceProgramClasses(nonDexProgramClasses).build();
+    DexApplication cfApp =
+        appView.app().builder().replaceProgramClasses(nonDexProgramClasses).build();
     appView.setAppInfo(
         new AppInfo(
             appView.appInfo().getSyntheticItems().commit(cfApp),
             appView.appInfo().getMainDexInfo()));
     ConvertedCfFiles convertedCfFiles = new ConvertedCfFiles();
-    new GenericSignatureRewriter(appView, desugaringLens)
-        .run(appView.appInfo().classes(), executor);
-    new KotlinMetadataRewriter(appView, desugaringLens).runForD8(executor);
+    new GenericSignatureRewriter(appView).run(appView.appInfo().classes(), executor);
+    new KotlinMetadataRewriter(appView).runForD8(executor);
     new ApplicationWriter(
             appView,
             null,
-            desugaringLens,
             convertedCfFiles)
         .write(executor);
     AndroidApp.Builder builder = AndroidApp.builder(inputApp);
     builder.getProgramResourceProviders().clear();
     builder.addProgramResourceProvider(convertedCfFiles);
     AndroidApp newAndroidApp = builder.build();
-    DexApplication newApp = new ApplicationReader(newAndroidApp, options, timing).read(executor);
+    DexApplication newApp =
+        new ApplicationReader(newAndroidApp, appView.options(), timing).read(executor);
     DexApplication.Builder<?> finalDexApp = newApp.builder();
     for (DexProgramClass dexProgramClass : dexProgramClasses) {
       finalDexApp.addProgramClass(dexProgramClass);
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index c158fc8..1495071 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -92,6 +92,7 @@
     private boolean minimalMainDex = false;
     private boolean skipDump = false;
     private final List<ProguardConfigurationSource> mainDexRules = new ArrayList<>();
+    private boolean enableMissingLibraryApiModeling = false;
 
     private Builder() {
       this(new DefaultD8DiagnosticsHandler());
@@ -322,6 +323,18 @@
       return self();
     }
 
+    /**
+     * Enable experimental/pre-release support for modeling missing library APIs.
+     *
+     * <p>This allows enabling the feature while it is still default disabled by the compiler. Once
+     * the feature is default enabled, calling this method will have no affect.
+     */
+    @Deprecated
+    public Builder setEnableExperimentalMissingLibraryApiModeling(boolean enable) {
+      this.enableMissingLibraryApiModeling = enable;
+      return self();
+    }
+
     @Override
     void validate() {
       if (isPrintHelp()) {
@@ -411,6 +424,7 @@
           getDumpInputFlags(),
           getMapIdProvider(),
           proguardMapConsumer,
+          enableMissingLibraryApiModeling,
           factory);
     }
   }
@@ -426,6 +440,7 @@
   private final boolean minimalMainDex;
   private final ImmutableList<ProguardConfigurationRule> mainDexKeepRules;
   private final StringConsumer proguardMapConsumer;
+  private final boolean enableMissingLibraryApiModeling;
   private final DexItemFactory factory;
 
   public static Builder builder() {
@@ -500,6 +515,7 @@
       DumpInputFlags dumpInputFlags,
       MapIdProvider mapIdProvider,
       StringConsumer proguardMapConsumer,
+      boolean enableMissingLibraryApiModeling,
       DexItemFactory factory) {
     super(
         inputApp,
@@ -529,6 +545,7 @@
     this.minimalMainDex = minimalMainDex;
     this.mainDexKeepRules = mainDexKeepRules;
     this.proguardMapConsumer = proguardMapConsumer;
+    this.enableMissingLibraryApiModeling = enableMissingLibraryApiModeling;
     this.factory = factory;
   }
 
@@ -545,6 +562,7 @@
     minimalMainDex = false;
     mainDexKeepRules = null;
     proguardMapConsumer = null;
+    enableMissingLibraryApiModeling = false;
     factory = null;
   }
 
@@ -602,6 +620,11 @@
     internal.synthesizedClassPrefix = synthesizedClassPrefix;
     internal.desugaredLibraryKeepRuleConsumer = desugaredLibraryKeepRuleConsumer;
 
+    if (!enableMissingLibraryApiModeling) {
+      internal.apiModelingOptions().disableApiCallerIdentification();
+      internal.apiModelingOptions().disableMissingApiModeling();
+    }
+
     // Default is to remove all javac generated assertion code when generating dex.
     assert internal.assertionsConfiguration == null;
     internal.assertionsConfiguration =
diff --git a/src/main/java/com/android/tools/r8/DexFileMergerHelper.java b/src/main/java/com/android/tools/r8/DexFileMergerHelper.java
index f6149c8..b8163c7 100644
--- a/src/main/java/com/android/tools/r8/DexFileMergerHelper.java
+++ b/src/main/java/com/android/tools/r8/DexFileMergerHelper.java
@@ -13,7 +13,6 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.synthesis.SyntheticItems.GlobalSyntheticsStrategy;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.ExceptionUtils;
@@ -103,11 +102,7 @@
         List<Marker> markers = appView.dexItemFactory().extractMarkers();
 
         assert !options.hasMethodsFilter();
-        ApplicationWriter writer =
-            new ApplicationWriter(
-                appView,
-                markers,
-                NamingLens.getIdentityLens());
+        ApplicationWriter writer = new ApplicationWriter(appView, markers);
         writer.write(executor);
         options.printWarnings();
       } catch (ExecutionException e) {
diff --git a/src/main/java/com/android/tools/r8/DexSplitterHelper.java b/src/main/java/com/android/tools/r8/DexSplitterHelper.java
index b90b736..43b8e9a 100644
--- a/src/main/java/com/android/tools/r8/DexSplitterHelper.java
+++ b/src/main/java/com/android/tools/r8/DexSplitterHelper.java
@@ -16,7 +16,6 @@
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.LazyLoadedDexApplication;
 import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.shaking.MainDexInfo;
 import com.android.tools.r8.synthesis.SyntheticItems.GlobalSyntheticsStrategy;
 import com.android.tools.r8.utils.ExceptionUtils;
@@ -113,7 +112,6 @@
           new ApplicationWriter(
                   appView,
                   markers,
-                  NamingLens.getIdentityLens(),
                   consumer)
               .write(executor);
           options.printWarnings();
diff --git a/src/main/java/com/android/tools/r8/GenerateLintFiles.java b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
index 417fb63..27bdafd 100644
--- a/src/main/java/com/android/tools/r8/GenerateLintFiles.java
+++ b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
@@ -38,7 +38,6 @@
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
 import com.android.tools.r8.jar.CfApplicationWriter;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.synthesis.SyntheticItems.GlobalSyntheticsStrategy;
 import com.android.tools.r8.utils.AndroidApiLevel;
@@ -348,11 +347,7 @@
         AppView.createForD8(
             AppInfo.createInitialAppInfo(
                 builder.build(), GlobalSyntheticsStrategy.forNonSynthesizing()));
-    CfApplicationWriter writer =
-        new CfApplicationWriter(
-            appView,
-            options.getMarker(Tool.L8),
-            NamingLens.getIdentityLens());
+    CfApplicationWriter writer = new CfApplicationWriter(appView, options.getMarker(Tool.L8));
     ClassFileConsumer consumer =
         new ClassFileConsumer.ArchiveConsumer(
             lintFile(compilationApiLevel, minApiLevel, FileUtils.JAR_EXTENSION));
diff --git a/src/main/java/com/android/tools/r8/L8.java b/src/main/java/com/android/tools/r8/L8.java
index 8a8769a..f8d95ab 100644
--- a/src/main/java/com/android/tools/r8/L8.java
+++ b/src/main/java/com/android/tools/r8/L8.java
@@ -15,7 +15,6 @@
 import com.android.tools.r8.ir.desugar.TypeRewriter;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAmender;
 import com.android.tools.r8.jar.CfApplicationWriter;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.naming.PrefixRewritingNamingLens;
 import com.android.tools.r8.naming.signature.GenericSignatureRewriter;
 import com.android.tools.r8.origin.CommandLineOrigin;
@@ -143,10 +142,10 @@
 
       SyntheticFinalization.finalize(appView, executor);
 
-      NamingLens namingLens = PrefixRewritingNamingLens.createPrefixRewritingNamingLens(appView);
-      new GenericSignatureRewriter(appView, namingLens).run(appView.appInfo().classes(), executor);
+      appView.setNamingLens(PrefixRewritingNamingLens.createPrefixRewritingNamingLens(appView));
+      new GenericSignatureRewriter(appView).run(appView.appInfo().classes(), executor);
 
-      new CfApplicationWriter(appView, options.getMarker(Tool.L8), namingLens)
+      new CfApplicationWriter(appView, options.getMarker(Tool.L8))
           .write(options.getClassFileConsumer());
       options.printWarnings();
     } catch (ExecutionException e) {
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index 6c8f251..2b50253 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -213,6 +213,8 @@
 
     // Disable global optimizations.
     internal.disableGlobalOptimizations();
+    internal.apiModelingOptions().disableApiCallerIdentification();
+    internal.apiModelingOptions().disableMissingApiModeling();
 
     internal.setDumpInputFlags(getDumpInputFlags(), false);
     internal.dumpOptions = dumpOptions();
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 25a91e7..5d07a1c 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -63,7 +63,6 @@
 import com.android.tools.r8.kotlin.KotlinMetadataRewriter;
 import com.android.tools.r8.kotlin.KotlinMetadataUtils;
 import com.android.tools.r8.naming.Minifier;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.naming.PrefixRewritingNamingLens;
 import com.android.tools.r8.naming.ProguardMapMinifier;
 import com.android.tools.r8.naming.RecordRewritingNamingLens;
@@ -208,29 +207,24 @@
   }
 
   static void writeApplication(
-      ExecutorService executorService,
-      AppView<?> appView,
-      NamingLens namingLens,
-      InternalOptions options,
-      AndroidApp inputApp)
+      AppView<?> appView, AndroidApp inputApp, ExecutorService executorService)
       throws ExecutionException {
+    InternalOptions options = appView.options();
     InspectorImpl.runInspections(options.outputInspections, appView.appInfo().classes());
     try {
       Marker marker = options.getMarker(Tool.R8);
       assert marker != null;
       // Get the markers from the input which are different from the one created for this
       // compilation
-      Set<Marker> markers = new HashSet<>(options.itemFactory.extractMarkers());
+      Set<Marker> markers = new HashSet<>(appView.dexItemFactory().extractMarkers());
       markers.remove(marker);
       if (options.isGeneratingClassFiles()) {
-        new CfApplicationWriter(appView, marker, namingLens)
-            .write(options.getClassFileConsumer(), inputApp);
+        new CfApplicationWriter(appView, marker).write(options.getClassFileConsumer(), inputApp);
       } else {
         new ApplicationWriter(
                 appView,
                 // Ensure that the marker for this compilation is the first in the list.
-                ImmutableList.<Marker>builder().add(marker).addAll(markers).build(),
-                namingLens)
+                ImmutableList.<Marker>builder().add(marker).addAll(markers).build())
             .write(executorService, inputApp);
       }
     } catch (IOException e) {
@@ -431,7 +425,7 @@
               annotationRemoverBuilder
                   .build(appViewWithLiveness, removedClasses);
           annotationRemover.ensureValid().run(executorService);
-          new GenericSignatureRewriter(appView, NamingLens.getIdentityLens(), genericContextBuilder)
+          new GenericSignatureRewriter(appView, genericContextBuilder)
               .run(appView.appInfo().classes(), executorService);
 
           assert appView.checkForTesting(() -> allReferencesAssignedApiLevel(appViewWithLiveness));
@@ -650,8 +644,7 @@
             AnnotationRemover.builder(Mode.FINAL_TREE_SHAKING)
                 .build(appView.withLiveness(), removedClasses)
                 .run(executorService);
-            new GenericSignatureRewriter(
-                    appView, NamingLens.getIdentityLens(), genericContextBuilder)
+            new GenericSignatureRewriter(appView, genericContextBuilder)
                 .run(appView.appInfo().classes(), executorService);
             assert appView.checkForTesting(
                     () ->
@@ -761,19 +754,17 @@
                   : null);
 
       // Perform minification.
-      NamingLens namingLens;
       if (options.getProguardConfiguration().hasApplyMappingFile()) {
         timing.begin("apply-mapping");
-        namingLens = new ProguardMapMinifier(appView.withLiveness()).run(executorService, timing);
+        appView.setNamingLens(
+            new ProguardMapMinifier(appView.withLiveness()).run(executorService, timing));
         timing.end();
         // Clear the applymapping data
         appView.clearApplyMappingSeedMapper();
       } else if (options.isMinifying()) {
         timing.begin("Minification");
-        namingLens = new Minifier(appView.withLiveness()).run(executorService, timing);
+        appView.setNamingLens(new Minifier(appView.withLiveness()).run(executorService, timing));
         timing.end();
-      } else {
-        namingLens = NamingLens.getIdentityLens();
       }
 
       assert verifyMovedMethodsHaveOriginalMethodPosition(appView, getDirectApp(appView));
@@ -808,16 +799,16 @@
         options.syntheticProguardRulesConsumer.accept(synthesizedProguardRules);
       }
 
-      namingLens = PrefixRewritingNamingLens.createPrefixRewritingNamingLens(appView, namingLens);
-      namingLens = RecordRewritingNamingLens.createRecordRewritingNamingLens(appView, namingLens);
+      appView.setNamingLens(PrefixRewritingNamingLens.createPrefixRewritingNamingLens(appView));
+      appView.setNamingLens(RecordRewritingNamingLens.createRecordRewritingNamingLens(appView));
 
       new ApiReferenceStubber(appView).run(executorService);
 
       timing.begin("MinifyKotlinMetadata");
-      new KotlinMetadataRewriter(appView, namingLens).runForR8(executorService);
+      new KotlinMetadataRewriter(appView).runForR8(executorService);
       timing.end();
 
-      new GenericSignatureRewriter(appView, namingLens, genericContextBuilderBeforeFinalMerging)
+      new GenericSignatureRewriter(appView, genericContextBuilderBeforeFinalMerging)
           .run(appView.appInfo().classes(), executorService);
 
       assert appView.checkForTesting(
@@ -829,15 +820,10 @@
                           .isValid())
           : "Could not validate generic signatures";
 
-      new DesugaredLibraryKeepRuleGenerator(appView, namingLens).runIfNecessary(timing);
+      new DesugaredLibraryKeepRuleGenerator(appView).runIfNecessary(timing);
 
       // Generate the resulting application resources.
-      writeApplication(
-          executorService,
-          appView,
-          namingLens,
-          options,
-          inputApp);
+      writeApplication(appView, inputApp, executorService);
 
       assert appView.getDontWarnConfiguration().validate(options);
 
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 4e3e190..4e7ca32 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -114,6 +114,7 @@
     private final List<FeatureSplit> featureSplits = new ArrayList<>();
     private String synthesizedClassPrefix = "";
     private boolean skipDump = false;
+    private boolean enableMissingLibraryApiModeling = false;
 
     private boolean allowTestProguardOptions =
         System.getProperty("com.android.tools.r8.allowTestProguardOptions") != null;
@@ -431,6 +432,18 @@
       return self();
     }
 
+    /**
+     * Enable experimental/pre-release support for modeling missing library APIs.
+     *
+     * <p>This allows enabling the feature while it is still default disabled by the compiler. Once
+     * the feature is default enabled, calling this method will have no affect.
+     */
+    @Deprecated
+    public Builder setEnableExperimentalMissingLibraryApiModeling(boolean enable) {
+      this.enableMissingLibraryApiModeling = enable;
+      return self();
+    }
+
     @Override
     protected InternalProgramOutputPathConsumer createProgramOutputConsumer(
         Path path,
@@ -619,7 +632,8 @@
               getThreadCount(),
               getDumpInputFlags(),
               getMapIdProvider(),
-              getSourceFileProvider());
+              getSourceFileProvider(),
+              enableMissingLibraryApiModeling);
 
       if (inputDependencyGraphConsumer != null) {
         inputDependencyGraphConsumer.finished();
@@ -704,6 +718,7 @@
   private final FeatureSplitConfiguration featureSplitConfiguration;
   private final String synthesizedClassPrefix;
   private final boolean skipDump;
+  private final boolean enableMissingLibraryApiModeling;
 
   /** Get a new {@link R8Command.Builder}. */
   public static Builder builder() {
@@ -792,7 +807,8 @@
       int threadCount,
       DumpInputFlags dumpInputFlags,
       MapIdProvider mapIdProvider,
-      SourceFileProvider sourceFileProvider) {
+      SourceFileProvider sourceFileProvider,
+      boolean enableMissingLibraryApiModeling) {
     super(
         inputApp,
         mode,
@@ -831,6 +847,7 @@
     this.featureSplitConfiguration = featureSplitConfiguration;
     this.synthesizedClassPrefix = synthesizedClassPrefix;
     this.skipDump = skipDump;
+    this.enableMissingLibraryApiModeling = enableMissingLibraryApiModeling;
   }
 
   private R8Command(boolean printHelp, boolean printVersion) {
@@ -854,6 +871,7 @@
     featureSplitConfiguration = null;
     synthesizedClassPrefix = null;
     skipDump = false;
+    enableMissingLibraryApiModeling = false;
   }
 
   public DexItemFactory getDexItemFactory() {
@@ -960,6 +978,10 @@
 
     internal.outputInspections = InspectorImpl.wrapInspections(getOutputInspections());
 
+    if (!enableMissingLibraryApiModeling) {
+      internal.apiModelingOptions().disableMissingApiModeling();
+    }
+
     // Default is to remove all javac generated assertion code when generating dex.
     assert internal.assertionsConfiguration == null;
     AssertionsConfiguration.Builder builder = AssertionsConfiguration.builder(getReporter());
diff --git a/src/main/java/com/android/tools/r8/ResourceShrinker.java b/src/main/java/com/android/tools/r8/ResourceShrinker.java
index bf40d89..b5ab2b6 100644
--- a/src/main/java/com/android/tools/r8/ResourceShrinker.java
+++ b/src/main/java/com/android/tools/r8/ResourceShrinker.java
@@ -3,38 +3,38 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8;
 
-import com.android.tools.r8.code.Const;
-import com.android.tools.r8.code.Const16;
-import com.android.tools.r8.code.Const4;
-import com.android.tools.r8.code.ConstHigh16;
-import com.android.tools.r8.code.ConstString;
-import com.android.tools.r8.code.ConstStringJumbo;
-import com.android.tools.r8.code.ConstWide16;
-import com.android.tools.r8.code.ConstWide32;
-import com.android.tools.r8.code.FillArrayData;
-import com.android.tools.r8.code.FillArrayDataPayload;
-import com.android.tools.r8.code.Format35c;
-import com.android.tools.r8.code.Format3rc;
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.InvokeDirect;
-import com.android.tools.r8.code.InvokeDirectRange;
-import com.android.tools.r8.code.InvokeInterface;
-import com.android.tools.r8.code.InvokeInterfaceRange;
-import com.android.tools.r8.code.InvokeStatic;
-import com.android.tools.r8.code.InvokeStaticRange;
-import com.android.tools.r8.code.InvokeSuper;
-import com.android.tools.r8.code.InvokeSuperRange;
-import com.android.tools.r8.code.InvokeVirtual;
-import com.android.tools.r8.code.InvokeVirtualRange;
-import com.android.tools.r8.code.NewArray;
-import com.android.tools.r8.code.Sget;
-import com.android.tools.r8.code.SgetBoolean;
-import com.android.tools.r8.code.SgetByte;
-import com.android.tools.r8.code.SgetChar;
-import com.android.tools.r8.code.SgetObject;
-import com.android.tools.r8.code.SgetShort;
-import com.android.tools.r8.code.SgetWide;
 import com.android.tools.r8.dex.ApplicationReader;
+import com.android.tools.r8.dex.code.DexConst;
+import com.android.tools.r8.dex.code.DexConst16;
+import com.android.tools.r8.dex.code.DexConst4;
+import com.android.tools.r8.dex.code.DexConstHigh16;
+import com.android.tools.r8.dex.code.DexConstString;
+import com.android.tools.r8.dex.code.DexConstStringJumbo;
+import com.android.tools.r8.dex.code.DexConstWide16;
+import com.android.tools.r8.dex.code.DexConstWide32;
+import com.android.tools.r8.dex.code.DexFillArrayData;
+import com.android.tools.r8.dex.code.DexFillArrayDataPayload;
+import com.android.tools.r8.dex.code.DexFormat35c;
+import com.android.tools.r8.dex.code.DexFormat3rc;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexInvokeDirect;
+import com.android.tools.r8.dex.code.DexInvokeDirectRange;
+import com.android.tools.r8.dex.code.DexInvokeInterface;
+import com.android.tools.r8.dex.code.DexInvokeInterfaceRange;
+import com.android.tools.r8.dex.code.DexInvokeStatic;
+import com.android.tools.r8.dex.code.DexInvokeStaticRange;
+import com.android.tools.r8.dex.code.DexInvokeSuper;
+import com.android.tools.r8.dex.code.DexInvokeSuperRange;
+import com.android.tools.r8.dex.code.DexInvokeVirtual;
+import com.android.tools.r8.dex.code.DexInvokeVirtualRange;
+import com.android.tools.r8.dex.code.DexNewArray;
+import com.android.tools.r8.dex.code.DexSget;
+import com.android.tools.r8.dex.code.DexSgetBoolean;
+import com.android.tools.r8.dex.code.DexSgetByte;
+import com.android.tools.r8.dex.code.DexSgetChar;
+import com.android.tools.r8.dex.code.DexSgetObject;
+import com.android.tools.r8.dex.code.DexSgetShort;
+import com.android.tools.r8.dex.code.DexSgetWide;
 import com.android.tools.r8.graph.Code;
 import com.android.tools.r8.graph.DexAnnotation;
 import com.android.tools.r8.graph.DexAnnotationElement;
@@ -219,12 +219,12 @@
         final Set<Integer> methodIntArrayPayloadOffsets = Sets.newHashSet();
         // First we collect payloads, and then we process them because payload can be before the
         // fill-array-data instruction referencing it.
-        final List<FillArrayDataPayload> payloads = Lists.newArrayList();
+        final List<DexFillArrayDataPayload> payloads = Lists.newArrayList();
 
-        Instruction[] instructions = implementation.asDexCode().instructions;
+        DexInstruction[] instructions = implementation.asDexCode().instructions;
         int current = 0;
         while (current < instructions.length) {
-          Instruction instruction = instructions[current];
+          DexInstruction instruction = instructions[current];
           if (isIntConstInstruction(instruction)) {
             processIntConstInstruction(instruction);
           } else if (isStringConstInstruction(instruction)) {
@@ -235,15 +235,15 @@
             processInvokeInstruction(instruction);
           } else if (isInvokeRangeInstruction(instruction)) {
             processInvokeRangeInstruction(instruction);
-          } else if (instruction instanceof FillArrayData) {
+          } else if (instruction instanceof DexFillArrayData) {
             processFillArray(instructions, current, methodIntArrayPayloadOffsets);
-          } else if (instruction instanceof FillArrayDataPayload) {
-            payloads.add((FillArrayDataPayload) instruction);
+          } else if (instruction instanceof DexFillArrayDataPayload) {
+            payloads.add((DexFillArrayDataPayload) instruction);
           }
           current++;
         }
 
-        for (FillArrayDataPayload payload : payloads) {
+        for (DexFillArrayDataPayload payload : payloads) {
           if (isIntArrayPayload(payload, methodIntArrayPayloadOffsets)) {
             processIntArrayPayload(payload);
           }
@@ -272,8 +272,8 @@
               });
     }
 
-    private void processIntArrayPayload(Instruction instruction) {
-      FillArrayDataPayload payload = (FillArrayDataPayload) instruction;
+    private void processIntArrayPayload(DexInstruction instruction) {
+      DexFillArrayDataPayload payload = (DexFillArrayDataPayload) instruction;
 
       for (int i = 0; i < payload.data.length / 2; i++) {
         int intValue = payload.data[2 * i + 1] << 16 | payload.data[2 * i];
@@ -282,20 +282,20 @@
     }
 
     private boolean isIntArrayPayload(
-        Instruction instruction, Set<Integer> methodIntArrayPayloadOffsets) {
-      if (!(instruction instanceof FillArrayDataPayload)) {
+        DexInstruction instruction, Set<Integer> methodIntArrayPayloadOffsets) {
+      if (!(instruction instanceof DexFillArrayDataPayload)) {
         return false;
       }
 
-      FillArrayDataPayload payload = (FillArrayDataPayload) instruction;
+      DexFillArrayDataPayload payload = (DexFillArrayDataPayload) instruction;
       return methodIntArrayPayloadOffsets.contains(payload.getOffset());
     }
 
     private void processFillArray(
-        Instruction[] instructions, int current, Set<Integer> methodIntArrayPayloadOffsets) {
-      FillArrayData fillArrayData = (FillArrayData) instructions[current];
-      if (current > 0 && instructions[current - 1] instanceof NewArray) {
-        NewArray newArray = (NewArray) instructions[current - 1];
+        DexInstruction[] instructions, int current, Set<Integer> methodIntArrayPayloadOffsets) {
+      DexFillArrayData fillArrayData = (DexFillArrayData) instructions[current];
+      if (current > 0 && instructions[current - 1] instanceof DexNewArray) {
+        DexNewArray newArray = (DexNewArray) instructions[current - 1];
         if (!Objects.equals(newArray.getType().descriptor.toString(), "[I")) {
           return;
         }
@@ -334,17 +334,17 @@
       }
     }
 
-    private boolean isIntConstInstruction(Instruction instruction) {
+    private boolean isIntConstInstruction(DexInstruction instruction) {
       int opcode = instruction.getOpcode();
-      return opcode == Const4.OPCODE
-          || opcode == Const16.OPCODE
-          || opcode == Const.OPCODE
-          || opcode == ConstWide32.OPCODE
-          || opcode == ConstHigh16.OPCODE
-          || opcode == ConstWide16.OPCODE;
+      return opcode == DexConst4.OPCODE
+          || opcode == DexConst16.OPCODE
+          || opcode == DexConst.OPCODE
+          || opcode == DexConstWide32.OPCODE
+          || opcode == DexConstHigh16.OPCODE
+          || opcode == DexConstWide16.OPCODE;
     }
 
-    private void processIntConstInstruction(Instruction instruction) {
+    private void processIntConstInstruction(DexInstruction instruction) {
       assert isIntConstInstruction(instruction);
 
       int constantValue;
@@ -365,20 +365,20 @@
       callback.referencedInt(constantValue);
     }
 
-    private boolean isStringConstInstruction(Instruction instruction) {
+    private boolean isStringConstInstruction(DexInstruction instruction) {
       int opcode = instruction.getOpcode();
-      return opcode == ConstString.OPCODE || opcode == ConstStringJumbo.OPCODE;
+      return opcode == DexConstString.OPCODE || opcode == DexConstStringJumbo.OPCODE;
     }
 
-    private void processStringConstantInstruction(Instruction instruction) {
+    private void processStringConstantInstruction(DexInstruction instruction) {
       assert isStringConstInstruction(instruction);
 
       String constantValue;
-      if (instruction instanceof ConstString) {
-        ConstString constString = (ConstString) instruction;
+      if (instruction instanceof DexConstString) {
+        DexConstString constString = (DexConstString) instruction;
         constantValue = constString.getString().toString();
-      } else if (instruction instanceof ConstStringJumbo) {
-        ConstStringJumbo constStringJumbo = (ConstStringJumbo) instruction;
+      } else if (instruction instanceof DexConstStringJumbo) {
+        DexConstStringJumbo constStringJumbo = (DexConstStringJumbo) instruction;
         constantValue = constStringJumbo.getString().toString();
       } else {
         throw new AssertionError("Not a string constant instruction.");
@@ -387,41 +387,41 @@
       callback.referencedString(constantValue);
     }
 
-    private boolean isGetStatic(Instruction instruction) {
+    private boolean isGetStatic(DexInstruction instruction) {
       int opcode = instruction.getOpcode();
-      return opcode == Sget.OPCODE
-          || opcode == SgetBoolean.OPCODE
-          || opcode == SgetByte.OPCODE
-          || opcode == SgetChar.OPCODE
-          || opcode == SgetObject.OPCODE
-          || opcode == SgetShort.OPCODE
-          || opcode == SgetWide.OPCODE;
+      return opcode == DexSget.OPCODE
+          || opcode == DexSgetBoolean.OPCODE
+          || opcode == DexSgetByte.OPCODE
+          || opcode == DexSgetChar.OPCODE
+          || opcode == DexSgetObject.OPCODE
+          || opcode == DexSgetShort.OPCODE
+          || opcode == DexSgetWide.OPCODE;
     }
 
-    private void processGetStatic(Instruction instruction) {
+    private void processGetStatic(DexInstruction instruction) {
       assert isGetStatic(instruction);
 
       DexField field;
-      if (instruction instanceof Sget) {
-        Sget sget = (Sget) instruction;
+      if (instruction instanceof DexSget) {
+        DexSget sget = (DexSget) instruction;
         field = sget.getField();
-      } else if (instruction instanceof SgetBoolean) {
-        SgetBoolean sgetBoolean = (SgetBoolean) instruction;
+      } else if (instruction instanceof DexSgetBoolean) {
+        DexSgetBoolean sgetBoolean = (DexSgetBoolean) instruction;
         field = sgetBoolean.getField();
-      } else if (instruction instanceof SgetByte) {
-        SgetByte sgetByte = (SgetByte) instruction;
+      } else if (instruction instanceof DexSgetByte) {
+        DexSgetByte sgetByte = (DexSgetByte) instruction;
         field = sgetByte.getField();
-      } else if (instruction instanceof SgetChar) {
-        SgetChar sgetChar = (SgetChar) instruction;
+      } else if (instruction instanceof DexSgetChar) {
+        DexSgetChar sgetChar = (DexSgetChar) instruction;
         field = sgetChar.getField();
-      } else if (instruction instanceof SgetObject) {
-        SgetObject sgetObject = (SgetObject) instruction;
+      } else if (instruction instanceof DexSgetObject) {
+        DexSgetObject sgetObject = (DexSgetObject) instruction;
         field = sgetObject.getField();
-      } else if (instruction instanceof SgetShort) {
-        SgetShort sgetShort = (SgetShort) instruction;
+      } else if (instruction instanceof DexSgetShort) {
+        DexSgetShort sgetShort = (DexSgetShort) instruction;
         field = sgetShort.getField();
-      } else if (instruction instanceof SgetWide) {
-        SgetWide sgetWide = (SgetWide) instruction;
+      } else if (instruction instanceof DexSgetWide) {
+        DexSgetWide sgetWide = (DexSgetWide) instruction;
         field = sgetWide.getField();
       } else {
         throw new AssertionError("Not a get static instruction");
@@ -430,19 +430,19 @@
       callback.referencedStaticField(field.holder.getInternalName(), field.name.toString());
     }
 
-    private boolean isInvokeInstruction(Instruction instruction) {
+    private boolean isInvokeInstruction(DexInstruction instruction) {
       int opcode = instruction.getOpcode();
-      return opcode == InvokeVirtual.OPCODE
-          || opcode == InvokeSuper.OPCODE
-          || opcode == InvokeDirect.OPCODE
-          || opcode == InvokeStatic.OPCODE
-          || opcode == InvokeInterface.OPCODE;
+      return opcode == DexInvokeVirtual.OPCODE
+          || opcode == DexInvokeSuper.OPCODE
+          || opcode == DexInvokeDirect.OPCODE
+          || opcode == DexInvokeStatic.OPCODE
+          || opcode == DexInvokeInterface.OPCODE;
     }
 
-    private void processInvokeInstruction(Instruction instruction) {
+    private void processInvokeInstruction(DexInstruction instruction) {
       assert isInvokeInstruction(instruction);
 
-      Format35c ins35c = (Format35c) instruction;
+      DexFormat35c ins35c = (DexFormat35c) instruction;
       DexMethod method = (DexMethod) ins35c.BBBB;
 
       callback.referencedMethod(
@@ -451,19 +451,19 @@
           method.proto.toDescriptorString());
     }
 
-    private boolean isInvokeRangeInstruction(Instruction instruction) {
+    private boolean isInvokeRangeInstruction(DexInstruction instruction) {
       int opcode = instruction.getOpcode();
-      return opcode == InvokeVirtualRange.OPCODE
-          || opcode == InvokeSuperRange.OPCODE
-          || opcode == InvokeDirectRange.OPCODE
-          || opcode == InvokeStaticRange.OPCODE
-          || opcode == InvokeInterfaceRange.OPCODE;
+      return opcode == DexInvokeVirtualRange.OPCODE
+          || opcode == DexInvokeSuperRange.OPCODE
+          || opcode == DexInvokeDirectRange.OPCODE
+          || opcode == DexInvokeStaticRange.OPCODE
+          || opcode == DexInvokeInterfaceRange.OPCODE;
     }
 
-    private void processInvokeRangeInstruction(Instruction instruction) {
+    private void processInvokeRangeInstruction(DexInstruction instruction) {
       assert isInvokeRangeInstruction(instruction);
 
-      Format3rc ins3rc = (Format3rc) instruction;
+      DexFormat3rc ins3rc = (DexFormat3rc) instruction;
       DexMethod method = (DexMethod) ins3rc.BBBB;
 
       callback.referencedMethod(
diff --git a/src/main/java/com/android/tools/r8/androidapi/AndroidApiDataAccess.java b/src/main/java/com/android/tools/r8/androidapi/AndroidApiDataAccess.java
index 37acc4d..0539dcf 100644
--- a/src/main/java/com/android/tools/r8/androidapi/AndroidApiDataAccess.java
+++ b/src/main/java/com/android/tools/r8/androidapi/AndroidApiDataAccess.java
@@ -5,15 +5,29 @@
 package com.android.tools.r8.androidapi;
 
 import static com.android.tools.r8.lightir.ByteUtils.unsetBitAtIndex;
+import static com.android.tools.r8.utils.ZipUtils.getOffsetOfResourceInZip;
 
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.dex.CompatByteBuffer;
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.utils.ExceptionDiagnostic;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.StringDiagnostic;
 import com.google.common.io.ByteStreams;
 import com.google.common.primitives.Ints;
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.net.JarURLConnection;
 import java.net.URL;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
 import java.util.function.BiPredicate;
 
 /**
@@ -30,9 +44,13 @@
   private static final int PAYLOAD_OFFSET_WITH_LENGTH = 4 + 2;
   private static final byte ZERO_BYTE = (byte) 0;
 
+  public static boolean isApiDatabaseEntry(String entry) {
+    return RESOURCE_NAME.equals(entry);
+  }
+
   private static class PositionAndLength {
 
-    private static PositionAndLength EMPTY = new PositionAndLength(0, 0);
+    private static final PositionAndLength EMPTY = new PositionAndLength(0, 0);
 
     private final int position;
     private final int length;
@@ -46,7 +64,7 @@
       if (position == 0 && length == 0) {
         return EMPTY;
       }
-      if ((position < 0 && length != 0) || (position > 0 && length == 0)) {
+      if ((position < 0 && length > 0) || (position > 0 && length == 0)) {
         assert false : "Unexpected position and length";
         return EMPTY;
       }
@@ -70,6 +88,61 @@
     }
   }
 
+  public static AndroidApiDataAccess create(
+      InternalOptions options, DiagnosticsHandler diagnosticsHandler) {
+    URL resource = AndroidApiDataAccess.class.getClassLoader().getResource(RESOURCE_NAME);
+    if (resource == null) {
+      throw new CompilationError("Could not find the api database at " + RESOURCE_NAME);
+    }
+    if (options.apiModelingOptions().useMemoryMappedByteBuffer) {
+      try {
+        // The resource is encoded as protocol and a path, where we should have one of either:
+        // protocol: file, path: <path-to-file>
+        // protocol: jar, path: file:<path-to-jar>!/<resource-name-in-jar>
+        if (resource.getProtocol().equals("file")) {
+          return getDataAccessFromPathAndOffset(Paths.get(resource.toURI()), 0);
+        } else if (resource.getProtocol().equals("jar") && resource.getPath().startsWith("file:")) {
+          // The path is on form 'file:<path-to-jar>!/<resource-name-in-jar>
+          JarURLConnection jarUrl = (JarURLConnection) resource.openConnection();
+          File jarFile = new File(jarUrl.getJarFileURL().getFile());
+          String databaseEntry = jarUrl.getEntryName();
+          long offsetInJar = getOffsetOfResourceInZip(jarFile, databaseEntry);
+          if (offsetInJar > 0) {
+            return getDataAccessFromPathAndOffset(jarFile.toPath(), offsetInJar);
+          }
+        }
+        // On older DEX platforms creating a new byte channel may fail:
+        // Error: java.lang.NoSuchMethodError: No static method newByteChannel(Ljava/nio/file/Path;
+        // [Ljava/nio/file/OpenOption;)Ljava/nio/channels/SeekableByteChannel;
+        // in class Ljava/nio/file/Files
+      } catch (Exception | NoSuchMethodError e) {
+        diagnosticsHandler.warning(new ExceptionDiagnostic(e));
+      }
+      diagnosticsHandler.warning(
+          new StringDiagnostic(
+              "Unable to use a memory mapped byte buffer to access the api database. Falling back"
+                  + " to loading the database into program which requires more memory"));
+    }
+    try (InputStream apiInputStream =
+        AndroidApiDataAccess.class.getClassLoader().getResourceAsStream(RESOURCE_NAME)) {
+      if (apiInputStream == null) {
+        throw new CompilationError("Could not find the api database at: " + resource);
+      }
+      return new AndroidApiDataAccessInMemory(ByteStreams.toByteArray(apiInputStream));
+    } catch (IOException e) {
+      throw new CompilationError("Could not read the api database.", e);
+    }
+  }
+
+  private static AndroidApiDataAccessByteMapped getDataAccessFromPathAndOffset(
+      Path path, long offset) throws IOException {
+    FileChannel fileChannel = (FileChannel) Files.newByteChannel(path, StandardOpenOption.READ);
+    MappedByteBuffer mappedByteBuffer =
+        fileChannel.map(FileChannel.MapMode.READ_ONLY, offset, fileChannel.size() - offset);
+    // Ensure that we can run on JDK 8 by using the CompatByteBuffer.
+    return new AndroidApiDataAccessByteMapped(new CompatByteBuffer(mappedByteBuffer));
+  }
+
   public static int entrySizeInBitsForConstantPoolMap() {
     return ENTRY_SIZE_IN_BITS_FOR_CONSTANT_POOL_MAP;
   }
@@ -102,25 +175,44 @@
     return PAYLOAD_OFFSET_WITH_LENGTH;
   }
 
-  static int constantPoolOffset() {
+  /** The start of the constant pool */
+  public static int constantPoolOffset() {
     return 4;
   }
 
-  static int constantPoolHashMapOffset(int constantPoolSize) {
+  /** The start of the constant pool hash map. */
+  public static int constantPoolHashMapOffset(int constantPoolSize) {
     return (constantPoolSize * constantPoolEntrySize()) + constantPoolOffset();
   }
 
-  static int apiLevelHashMapOffset(int constantPoolSize) {
+  /** The start of the api level hash map. */
+  public static int apiLevelHashMapOffset(int constantPoolSize) {
     int constantPoolHashMapSize =
         (1 << entrySizeInBitsForConstantPoolMap()) * constantPoolMapEntrySize();
     return constantPoolHashMapOffset(constantPoolSize) + constantPoolHashMapSize;
   }
 
-  static int payloadOffset(int constantPoolSize) {
+  /** The start of the payload section. */
+  public static int payloadOffset(int constantPoolSize) {
     int apiLevelSize = (1 << entrySizeInBitsForApiLevelMap()) * apiLevelHashMapEntrySize();
     return apiLevelHashMapOffset(constantPoolSize) + apiLevelSize;
   }
 
+  /** The actual byte index of the constant pool index. */
+  public int constantPoolIndexOffset(int index) {
+    return constantPoolOffset() + (index * constantPoolEntrySize());
+  }
+
+  /** The actual byte index of the constant pool hash key. */
+  protected int constantPoolHashMapIndexOffset(int hash) {
+    return constantPoolHashMapOffset(getConstantPoolSize()) + (hash * constantPoolMapEntrySize());
+  }
+
+  /** The actual byte index of the api hash key. */
+  protected int apiLevelHashMapIndexOffset(int hash) {
+    return apiLevelHashMapOffset(getConstantPoolSize()) + (hash * apiLevelHashMapEntrySize());
+  }
+
   static int readIntFromOffset(byte[] data, int offset) {
     return Ints.fromBytes(data[offset], data[offset + 1], data[offset + 2], data[offset + 3]);
   }
@@ -133,11 +225,7 @@
 
   abstract int readConstantPoolSize();
 
-  abstract PositionAndLength getConstantPoolPayloadOffset(int index);
-
-  abstract PositionAndLength getConstantPoolHashMapPayloadOffset(int hash);
-
-  abstract PositionAndLength getApiLevelHashMapPayloadOffset(int hash);
+  abstract PositionAndLength readPositionAndLength(int offset);
 
   abstract boolean payloadHasConstantPoolValue(int offset, int length, byte[] value);
 
@@ -169,7 +257,7 @@
 
   public int getConstantPoolIndex(DexString string) {
     PositionAndLength constantPoolIndex =
-        getConstantPoolHashMapPayloadOffset(constantPoolHash(string));
+        readPositionAndLength(constantPoolHashMapIndexOffset(constantPoolHash(string)));
     if (constantPoolIndex.isEmpty()) {
       return -1;
     }
@@ -183,56 +271,108 @@
     } else {
       assert length > 0;
       return payloadContainsConstantPoolValue(
-          position, length, string.content, this::isConstantPoolEntry);
+          payloadOffset(getConstantPoolSize()) + position,
+          length,
+          string.content,
+          this::isConstantPoolEntry);
     }
     return -1;
   }
 
   public boolean isConstantPoolEntry(int index, byte[] value) {
-    PositionAndLength constantPoolPayloadOffset = getConstantPoolPayloadOffset(index);
+    PositionAndLength constantPoolPayloadOffset =
+        readPositionAndLength(constantPoolIndexOffset(index));
     if (constantPoolPayloadOffset.isEmpty()) {
       return false;
     }
+    if (value.length != constantPoolPayloadOffset.getLength()) {
+      return false;
+    }
     return payloadHasConstantPoolValue(
-        constantPoolPayloadOffset.getPosition(), constantPoolPayloadOffset.getLength(), value);
+        payloadOffset(getConstantPoolSize()) + constantPoolPayloadOffset.getPosition(),
+        constantPoolPayloadOffset.getLength(),
+        value);
   }
 
   public byte getApiLevelForReference(byte[] serialized, DexReference reference) {
     PositionAndLength apiLevelPayloadOffset =
-        getApiLevelHashMapPayloadOffset(apiLevelHash(reference));
+        readPositionAndLength(apiLevelHashMapIndexOffset(apiLevelHash(reference)));
     if (apiLevelPayloadOffset.isEmpty()) {
       return 0;
     }
     return readApiLevelForPayloadOffset(
-        apiLevelPayloadOffset.getPosition(), apiLevelPayloadOffset.getLength(), serialized);
+        payloadOffset(getConstantPoolSize()) + apiLevelPayloadOffset.getPosition(),
+        apiLevelPayloadOffset.getLength(),
+        serialized);
   }
 
-  public static byte findApiForReferenceHelper(byte[] data, int offset, int length, byte[] value) {
-    int index = offset;
-    while (index < offset + length) {
-      // Read size of entry
-      int lengthOfEntry = Ints.fromBytes(ZERO_BYTE, ZERO_BYTE, data[index], data[index + 1]);
-      int startIndex = index + 2;
-      int endIndex = startIndex + lengthOfEntry;
-      if (isSerializedDescriptor(value, data, startIndex, lengthOfEntry)) {
-        return data[endIndex];
-      }
-      index = endIndex + 1;
-    }
-    return 0;
-  }
+  public static class AndroidApiDataAccessByteMapped extends AndroidApiDataAccess {
 
-  protected static boolean isSerializedDescriptor(
-      byte[] serialized, byte[] candidate, int offset, int length) {
-    if (serialized.length != length) {
-      return false;
+    private final CompatByteBuffer mappedByteBuffer;
+
+    public AndroidApiDataAccessByteMapped(CompatByteBuffer mappedByteBuffer) {
+      this.mappedByteBuffer = mappedByteBuffer;
     }
-    for (int i = 0; i < length; i++) {
-      if (serialized[i] != candidate[i + offset]) {
-        return false;
+
+    @Override
+    int readConstantPoolSize() {
+      return mappedByteBuffer.getInt(0);
+    }
+
+    @Override
+    public PositionAndLength readPositionAndLength(int offset) {
+      return PositionAndLength.create(
+          mappedByteBuffer.getInt(offset), mappedByteBuffer.getShort(offset + 4));
+    }
+
+    @Override
+    boolean payloadHasConstantPoolValue(int offset, int length, byte[] value) {
+      assert length == value.length;
+      mappedByteBuffer.position(offset);
+      for (byte expected : value) {
+        if (expected != mappedByteBuffer.get()) {
+          return false;
+        }
       }
+      return true;
     }
-    return true;
+
+    @Override
+    int payloadContainsConstantPoolValue(
+        int offset, int length, byte[] value, BiPredicate<Integer, byte[]> predicate) {
+      for (int i = offset; i < offset + length; i += 2) {
+        // Do not use mappedByteBuffer.getShort() since that will add the sign.
+        int index =
+            Ints.fromBytes(
+                ZERO_BYTE, ZERO_BYTE, mappedByteBuffer.get(i), mappedByteBuffer.get(i + 1));
+        if (predicate.test(index, value)) {
+          return index;
+        }
+      }
+      return -1;
+    }
+
+    @Override
+    byte readApiLevelForPayloadOffset(int offset, int length, byte[] value) {
+      int currentOffset = offset;
+      while (currentOffset < offset + length) {
+        // Read the length
+        int lengthOfEntry =
+            Ints.fromBytes(
+                ZERO_BYTE,
+                ZERO_BYTE,
+                mappedByteBuffer.get(currentOffset),
+                mappedByteBuffer.get(currentOffset + 1));
+        int startPosition = currentOffset + 2;
+        if (value.length == lengthOfEntry
+            && payloadHasConstantPoolValue(startPosition, lengthOfEntry, value)) {
+          return mappedByteBuffer.get(startPosition + lengthOfEntry);
+        }
+        // Advance our current position + length of entry + api level.
+        currentOffset = startPosition + lengthOfEntry + 1;
+      }
+      return -1;
+    }
   }
 
   public static class AndroidApiDataAccessInMemory extends AndroidApiDataAccess {
@@ -243,62 +383,36 @@
       this.data = data;
     }
 
-    public static AndroidApiDataAccessInMemory create() {
-      byte[] data;
-      try (InputStream apiInputStream =
-          AndroidApiDataAccess.class.getClassLoader().getResourceAsStream(RESOURCE_NAME); ) {
-        if (apiInputStream == null) {
-          URL resource = AndroidApiDataAccess.class.getClassLoader().getResource(RESOURCE_NAME);
-          throw new CompilationError("Could not find the api database at: " + resource);
-        }
-        data = ByteStreams.toByteArray(apiInputStream);
-      } catch (IOException e) {
-        throw new CompilationError("Could not read the api database.", e);
-      }
-      return new AndroidApiDataAccessInMemory(data);
-    }
-
     @Override
     public int readConstantPoolSize() {
       return readIntFromOffset(data, 0);
     }
 
     @Override
-    PositionAndLength getConstantPoolPayloadOffset(int index) {
-      int offset = constantPoolOffset() + (index * constantPoolEntrySize());
-      return PositionAndLength.create(data, offset);
-    }
-
-    @Override
-    PositionAndLength getConstantPoolHashMapPayloadOffset(int hash) {
-      int offset =
-          constantPoolHashMapOffset(getConstantPoolSize()) + (hash * constantPoolMapEntrySize());
-      return PositionAndLength.create(data, offset);
-    }
-
-    @Override
-    PositionAndLength getApiLevelHashMapPayloadOffset(int hash) {
-      int offset =
-          apiLevelHashMapOffset(getConstantPoolSize()) + (hash * apiLevelHashMapEntrySize());
+    PositionAndLength readPositionAndLength(int offset) {
       return PositionAndLength.create(data, offset);
     }
 
     @Override
     boolean payloadHasConstantPoolValue(int offset, int length, byte[] value) {
-      return isSerializedDescriptor(
-          value, data, payloadOffset(getConstantPoolSize()) + offset, length);
+      if (value.length != length) {
+        return false;
+      }
+      for (int i = 0; i < length; i++) {
+        if (value[i] != data[i + offset]) {
+          return false;
+        }
+      }
+      return true;
     }
 
     @Override
     int payloadContainsConstantPoolValue(
         int offset, int length, byte[] value, BiPredicate<Integer, byte[]> predicate) {
-      int payloadOffset = payloadOffset(getConstantPoolSize());
-      int startInPayload = payloadOffset + offset;
-      int endInPayload = startInPayload + length;
-      if (data.length < endInPayload) {
+      if (data.length < length) {
         return -1;
       }
-      for (int i = startInPayload; i < endInPayload; i += 2) {
+      for (int i = offset; i < offset + length; i += 2) {
         int index = Ints.fromBytes(ZERO_BYTE, ZERO_BYTE, data[i], data[i + 1]);
         if (predicate.test(index, value)) {
           return index;
@@ -309,8 +423,18 @@
 
     @Override
     byte readApiLevelForPayloadOffset(int offset, int length, byte[] value) {
-      return findApiForReferenceHelper(
-          data, payloadOffset(getConstantPoolSize()) + offset, length, value);
+      int index = offset;
+      while (index < offset + length) {
+        // Read size of entry
+        int lengthOfEntry = Ints.fromBytes(ZERO_BYTE, ZERO_BYTE, data[index], data[index + 1]);
+        int startIndex = index + 2;
+        int endIndex = startIndex + lengthOfEntry;
+        if (payloadHasConstantPoolValue(startIndex, lengthOfEntry, value)) {
+          return data[endIndex];
+        }
+        index = endIndex + 1;
+      }
+      return 0;
     }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelHashingDatabaseImpl.java b/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelHashingDatabaseImpl.java
index 5e0a407..22d0c6d 100644
--- a/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelHashingDatabaseImpl.java
+++ b/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelHashingDatabaseImpl.java
@@ -7,13 +7,14 @@
 import static com.android.tools.r8.lightir.ByteUtils.isU2;
 import static com.android.tools.r8.utils.AndroidApiLevel.ANDROID_PLATFORM;
 
-import com.android.tools.r8.androidapi.AndroidApiDataAccess.AndroidApiDataAccessInMemory;
+import com.android.tools.r8.DiagnosticsHandler;
 import com.android.tools.r8.graph.DexField;
 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.InternalOptions;
 import com.android.tools.r8.utils.ThrowingFunction;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -126,13 +127,16 @@
 
   private final Map<DexReference, AndroidApiLevel> lookupCache = new ConcurrentHashMap<>();
   private final Map<DexString, Integer> constantPoolCache = new ConcurrentHashMap<>();
+  private final InternalOptions options;
+  private final DiagnosticsHandler diagnosticsHandler;
   private static volatile AndroidApiDataAccess dataAccess;
 
-  private static AndroidApiDataAccess getDataAccess() {
+  private static AndroidApiDataAccess getDataAccess(
+      InternalOptions options, DiagnosticsHandler diagnosticsHandler) {
     if (dataAccess == null) {
       synchronized (AndroidApiDataAccess.class) {
         if (dataAccess == null) {
-          dataAccess = AndroidApiDataAccessInMemory.create();
+          dataAccess = AndroidApiDataAccess.create(options, diagnosticsHandler);
         }
       }
     }
@@ -140,7 +144,11 @@
   }
 
   public AndroidApiLevelHashingDatabaseImpl(
-      List<AndroidApiForHashingReference> predefinedApiTypeLookup) {
+      List<AndroidApiForHashingReference> predefinedApiTypeLookup,
+      InternalOptions options,
+      DiagnosticsHandler diagnosticsHandler) {
+    this.options = options;
+    this.diagnosticsHandler = diagnosticsHandler;
     predefinedApiTypeLookup.forEach(
         predefinedApiReference -> {
           // Do not use computeIfAbsent since a return value of null implies the key should not be
@@ -169,7 +177,7 @@
 
   private int getConstantPoolId(DexString string) {
     return constantPoolCache.computeIfAbsent(
-        string, key -> getDataAccess().getConstantPoolIndex(string));
+        string, key -> getDataAccess(options, diagnosticsHandler).getConstantPoolIndex(string));
   }
 
   private AndroidApiLevel lookupApiLevel(DexReference reference) {
@@ -190,7 +198,8 @@
                 return ANDROID_PLATFORM;
               } else {
                 byte apiLevelForReference =
-                    getDataAccess().getApiLevelForReference(uniqueDescriptorForReference, ref);
+                    getDataAccess(options, diagnosticsHandler)
+                        .getApiLevelForReference(uniqueDescriptorForReference, ref);
                 return (apiLevelForReference <= 0)
                     ? ANDROID_PLATFORM
                     : AndroidApiLevel.getAndroidApiLevel(apiLevelForReference);
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 0e08965..b1b581b 100644
--- a/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java
+++ b/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java
@@ -30,7 +30,8 @@
     this.apiLevelCompute = apiLevelCompute;
     factory = appView.dexItemFactory();
     androidApiLevelDatabase =
-        new AndroidApiLevelHashingDatabaseImpl(predefinedApiTypeLookupForHashing);
+        new AndroidApiLevelHashingDatabaseImpl(
+            predefinedApiTypeLookupForHashing, appView.options(), appView.reporter());
   }
 
   public static AndroidApiReferenceLevelCache create(
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 f8ed446..6d8c09d 100644
--- a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
+++ b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
@@ -10,10 +10,10 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DefaultInstanceInitializerCode;
 import com.android.tools.r8.graph.DexClass;
 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.DexLibraryClass;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -29,9 +29,7 @@
 import com.android.tools.r8.utils.ThreadUtils;
 import com.android.tools.r8.utils.WorkList;
 import com.google.common.collect.Sets;
-import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
@@ -78,22 +76,22 @@
 
     @Override
     public void registerInstanceFieldRead(DexField field) {
-      checkReferenceToLibraryClass(field.type);
+      checkReferenceToLibraryClass(field);
     }
 
     @Override
     public void registerInstanceFieldWrite(DexField field) {
-      checkReferenceToLibraryClass(field.type);
+      checkReferenceToLibraryClass(field);
     }
 
     @Override
     public void registerStaticFieldRead(DexField field) {
-      checkReferenceToLibraryClass(field.type);
+      checkReferenceToLibraryClass(field);
     }
 
     @Override
     public void registerStaticFieldWrite(DexField field) {
-      checkReferenceToLibraryClass(field.type);
+      checkReferenceToLibraryClass(field);
     }
 
     @Override
@@ -104,17 +102,13 @@
     private void checkReferenceToLibraryClass(DexReference reference) {
       DexType rewrittenType = appView.graphLens().lookupType(reference.getContextType());
       findReferencedLibraryClasses(rewrittenType, getContext().getContextClass());
-      if (reference.isDexMethod()) {
-        findReferencedLibraryMethod(reference.asDexMethod(), getContext().getContextClass());
-      }
     }
   }
 
   private final AppView<?> appView;
   private final Map<DexLibraryClass, Set<ProgramDefinition>> referencingContexts =
       new ConcurrentHashMap<>();
-  private final Map<DexLibraryClass, Set<DexMethod>> libraryClassesToMock =
-      new ConcurrentHashMap<>();
+  private final Set<DexLibraryClass> libraryClassesToMock = Sets.newConcurrentHashSet();
   private final Set<DexType> seenTypes = Sets.newConcurrentHashSet();
   private final AndroidApiLevelCompute apiLevelCompute;
 
@@ -133,10 +127,9 @@
       return;
     }
     libraryClassesToMock.forEach(
-        (clazz, methods) ->
+        clazz ->
             mockMissingLibraryClass(
                 clazz,
-                methods,
                 ThrowExceptionCode.create(appView.dexItemFactory().noClassDefFoundErrorType)));
     // Commit the synthetic items.
     CommittedItems committedItems = appView.getSyntheticItems().commit(appView.appInfo().app());
@@ -171,37 +164,6 @@
         method -> method.registerCodeReferences(new ReferencesToApiLevelUseRegistry(method)));
   }
 
-  private void findReferencedLibraryMethod(DexMethod method, DexProgramClass context) {
-    DexType holderType = method.getHolderType();
-    if (!holderType.isClassType()) {
-      return;
-    }
-    DexType rewrittenType = appView.graphLens().lookupType(holderType);
-    DexClass clazz = appView.definitionFor(rewrittenType);
-    if (clazz == null || !clazz.isLibraryClass()) {
-      return;
-    }
-    ComputedApiLevel apiLevel =
-        apiLevelCompute.computeApiLevelForLibraryReference(method, ComputedApiLevel.unknown());
-    if (apiLevel.isGreaterThan(appView.computedMinApiLevel())) {
-      ComputedApiLevel holderApiLevel =
-          apiLevelCompute.computeApiLevelForLibraryReference(
-              rewrittenType, ComputedApiLevel.unknown());
-      if (holderApiLevel.isUnknownApiLevel()) {
-        // Do not mock methods or classes where the holder is unknown.
-        return;
-      }
-      if (holderApiLevel.isGreaterThan(appView.computedMinApiLevel())) {
-        libraryClassesToMock
-            .computeIfAbsent(clazz.asLibraryClass(), ignoreKey(Sets::newConcurrentHashSet))
-            .add(method);
-        referencingContexts
-            .computeIfAbsent(clazz.asLibraryClass(), ignoreKey(Sets::newConcurrentHashSet))
-            .add(context);
-      }
-    }
-  }
-
   private void findReferencedLibraryClasses(DexType type, DexProgramClass context) {
     if (!type.isClassType()) {
       return;
@@ -218,8 +180,7 @@
                 clazz.type, ComputedApiLevel.unknown());
         if (androidApiLevel.isGreaterThan(appView.computedMinApiLevel())
             && !androidApiLevel.isUnknownApiLevel()) {
-          libraryClassesToMock.computeIfAbsent(
-              clazz.asLibraryClass(), ignoreKey(Sets::newConcurrentHashSet));
+          libraryClassesToMock.add(clazz.asLibraryClass());
           referencingContexts
               .computeIfAbsent(clazz.asLibraryClass(), ignoreKey(Sets::newConcurrentHashSet))
               .add(context);
@@ -231,9 +192,9 @@
 
   private void mockMissingLibraryClass(
       DexLibraryClass libraryClass,
-      Set<DexMethod> methodsToStub,
       ThrowExceptionCode throwExceptionCode) {
-    if (libraryClass.getType() == appView.dexItemFactory().objectType
+    DexItemFactory factory = appView.dexItemFactory();
+    if (libraryClass.getType() == factory.objectType
         || libraryClass.getType().toDescriptorString().startsWith("Ljava/")) {
       return;
     }
@@ -260,9 +221,14 @@
               classBuilder
                   .setSuperType(libraryClass.getSuperType())
                   .setInterfaces(Arrays.asList(libraryClass.getInterfaces().values))
-                  .setVirtualMethods(
-                      buildLibraryMethodsForProgram(
-                          libraryClass, libraryClass.virtualMethods(), methodsToStub));
+                  // Add throwing static initializer
+                  .addMethod(
+                      methodBuilder ->
+                          methodBuilder
+                              .setName(factory.classConstructorMethodName)
+                              .setProto(factory.createProto(factory.voidType))
+                              .setAccessFlags(MethodAccessFlags.createForClassInitializer())
+                              .setCode(method -> throwExceptionCode));
               // Based on b/138781768#comment57 there is no significant reason to synthesize fields.
               if (libraryClass.isInterface()) {
                 classBuilder.setInterface();
@@ -270,60 +236,7 @@
               if (!libraryClass.isFinal()) {
                 classBuilder.unsetFinal();
               }
-              List<DexEncodedMethod> directMethods =
-                  (!libraryClass.isInterface()
-                          || appView.options().canUseDefaultAndStaticInterfaceMethods())
-                      ? buildLibraryMethodsForProgram(
-                          libraryClass, libraryClass.directMethods(), methodsToStub)
-                      : new ArrayList<>();
-              // Add throwing static initializer
-              directMethods.add(
-                  DexEncodedMethod.syntheticBuilder()
-                      .setMethod(
-                          appView.dexItemFactory().createClassInitializer(libraryClass.getType()))
-                      .setAccessFlags(MethodAccessFlags.createForClassInitializer())
-                      .setCode(throwExceptionCode)
-                      .build());
-              classBuilder.setDirectMethods(directMethods);
             },
             ignored -> {});
   }
-
-  private List<DexEncodedMethod> buildLibraryMethodsForProgram(
-      DexLibraryClass clazz, Iterable<DexEncodedMethod> methods, Set<DexMethod> methodsToMock) {
-    List<DexEncodedMethod> newMethods = new ArrayList<>();
-    methods.forEach(
-        method -> {
-          if (methodsToMock.contains(method.getReference())) {
-            DexEncodedMethod newMethod = buildLibraryMethodForProgram(clazz, method);
-            if (newMethod != null) {
-              newMethods.add(newMethod);
-            }
-          }
-        });
-    return newMethods;
-  }
-
-  private DexEncodedMethod buildLibraryMethodForProgram(
-      DexLibraryClass clazz, DexEncodedMethod method) {
-    assert !clazz.isInterface()
-        || !method.isStatic()
-        || appView.options().canUseDefaultAndStaticInterfaceMethods();
-    DexMethod newMethod = method.getReference().withHolder(clazz.type, appView.dexItemFactory());
-    DexEncodedMethod.Builder methodBuilder =
-        DexEncodedMethod.syntheticBuilder(method)
-            .setMethod(newMethod)
-            .modifyAccessFlags(MethodAccessFlags::setSynthetic);
-    if (method.isInstanceInitializer()) {
-      methodBuilder.setCode(DefaultInstanceInitializerCode.get());
-    } else if (method.isVirtualMethod() && clazz.isInterface()) {
-      methodBuilder.modifyAccessFlags(MethodAccessFlags::setAbstract);
-    } else if (method.isAbstract()) {
-      methodBuilder.modifyAccessFlags(MethodAccessFlags::setAbstract);
-    } else {
-      // To allow us not adding a trivial throwing code body we set the access flag as native.
-      methodBuilder.modifyAccessFlags(MethodAccessFlags::setNative);
-    }
-    return methodBuilder.build();
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/bisect/Bisect.java b/src/main/java/com/android/tools/r8/bisect/Bisect.java
index 4228cf4..c7547a8 100644
--- a/src/main/java/com/android/tools/r8/bisect/Bisect.java
+++ b/src/main/java/com/android/tools/r8/bisect/Bisect.java
@@ -14,7 +14,6 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.synthesis.SyntheticItems.GlobalSyntheticsStrategy;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.AndroidAppConsumers;
@@ -175,7 +174,7 @@
   }
 
   private DexApplication readApp(Path apk, InternalOptions options, ExecutorService executor)
-      throws IOException, ExecutionException {
+      throws IOException {
     AndroidApp app = AndroidApp.builder().addProgramFiles(apk).build();
     return new ApplicationReader(app, options, timing).read(executor);
   }
@@ -191,8 +190,7 @@
         new ApplicationWriter(
             AppView.createForD8(
                 AppInfo.createInitialAppInfo(app, GlobalSyntheticsStrategy.forNonSynthesizing())),
-            null,
-            NamingLens.getIdentityLens());
+            null);
     writer.write(executor);
     options.signalFinishedToConsumers();
     compatSink.build().writeToDirectory(output, OutputMode.DexIndexed);
diff --git a/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java b/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java
index 22fbe8e..9798222 100644
--- a/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java
+++ b/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java
@@ -536,24 +536,7 @@
     } else if (frameType.isUninitializedNew()) {
       return frameTypeType() + ".uninitializedNew(new " + cfType("CfLabel") + "())";
     } else if (frameType.isPrimitive()) {
-      if (frameType.isSingle()) {
-        if (frameType.isInt()) {
-          return frameTypeType() + ".intType()";
-        } else {
-          return frameTypeType()
-              + ".initialized("
-              + dexType(frameType.asSingleInitializedType().getInitializedType())
-              + ")";
-        }
-      } else {
-        assert frameType.isWide();
-        if (frameType.isDouble()) {
-          return frameTypeType() + ".doubleType()";
-        } else {
-          assert frameType.isLong();
-          return frameTypeType() + ".longType()";
-        }
-      }
+      return frameTypeType() + "." + frameType.asPrimitive().getTypeName() + "Type()";
     } else {
       assert frameType.isInitialized();
       if (frameType.isNullType()) {
diff --git a/src/main/java/com/android/tools/r8/cf/CfPrinter.java b/src/main/java/com/android/tools/r8/cf/CfPrinter.java
index 035e416..6030119 100644
--- a/src/main/java/com/android/tools/r8/cf/CfPrinter.java
+++ b/src/main/java/com/android/tools/r8/cf/CfPrinter.java
@@ -456,17 +456,7 @@
 
   private void print(FrameType type) {
     if (type.isPrimitive()) {
-      if (type.isInt()) {
-        builder.append("int");
-      } else if (type.isDouble()) {
-        builder.append("double");
-      } else if (type.isLong()) {
-        assert type.isLong();
-        builder.append("long");
-      } else {
-        assert type.isSingleInitialized();
-        appendType(type.asSingleInitializedType().getInitializedType());
-      }
+      builder.append(type.asPrimitive().getTypeName());
     } else if (type.isInitialized()) {
       appendType(type.asSingleInitializedType().getInitializedType());
     } else if (type.isUninitializedNew()) {
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java b/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
index bf9dc6b..993dd8e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
@@ -23,6 +23,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import org.objectweb.asm.MethodVisitor;
@@ -220,11 +221,14 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState state,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ..., value1, value2 →
     // ..., result
-    return state.popInitialized(appView, type).popInitialized(appView, type).push(appView, type);
+    return state
+        .popInitialized(appView, type)
+        .popInitialized(appView, type)
+        .push(appView, config, type);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
index e696048..8a39916 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
@@ -20,6 +20,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import org.objectweb.asm.MethodVisitor;
@@ -96,13 +97,13 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ..., arrayref →
     // ..., length
     return frame
         .popInitialized(appView, dexItemFactory.objectArrayType)
-        .push(dexItemFactory.intType);
+        .push(config, dexItemFactory.intType);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
index fbcad69..129219b 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
@@ -24,6 +24,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import org.objectweb.asm.MethodVisitor;
@@ -141,14 +142,14 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ..., arrayref, index →
     // ..., value
     return frame
         .popInitialized(appView, dexItemFactory.intType)
         .popInitialized(appView, dexItemFactory.objectArrayType)
-        .push(appView, type);
+        .push(appView, config, type);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
index 31ad222..965c413 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
@@ -23,6 +23,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import org.objectweb.asm.MethodVisitor;
@@ -133,8 +134,8 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ..., arrayref, index, value →
     // ...
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfAssignability.java b/src/main/java/com/android/tools/r8/cf/code/CfAssignability.java
index 184afb2..8335908 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfAssignability.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfAssignability.java
@@ -33,7 +33,7 @@
   // Based on https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.10.1.2.
   public static boolean isFrameTypeAssignable(
       SingleFrameType source, SingleFrameType target, AppView<?> appView) {
-    if (source == target || target.isOneWord()) {
+    if (source.equals(target) || target.isOneWord()) {
       return true;
     }
     if (source.isOneWord()) {
@@ -49,11 +49,21 @@
     }
     // TODO(b/168190267): Clean-up the lattice.
     DexItemFactory factory = appView.dexItemFactory();
+    if (target.isPrimitive()) {
+      return source.isPrimitive()
+          && source.asSinglePrimitive().hasIntVerificationType()
+          && target.asSinglePrimitive().hasIntVerificationType();
+    }
+    if (source.isPrimitive()) {
+      return false;
+    }
     if (target.isInitialized()) {
       if (source.isInitialized()) {
         // Both are instantiated types and we resort to primitive type/java type hierarchy checking.
         return isAssignable(
-            source.getInitializedType(factory), target.getInitializedType(factory), appView);
+            source.asSingleInitializedType().getInitializedType(),
+            target.asSingleInitializedType().getInitializedType(),
+            appView);
       }
       return target.asSingleInitializedType().getInitializedType() == factory.objectType;
     }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java b/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
index 323a253..6ad249b 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
@@ -23,6 +23,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import java.util.ListIterator;
@@ -145,11 +146,11 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ..., objectref →
     // ..., objectref
-    return frame.popInitialized(appView, dexItemFactory.objectType).push(type);
+    return frame.popInitialized(appView, dexItemFactory.objectType).push(config, type);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfCmp.java b/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
index 4a42ca3..5d3f7b9 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
@@ -25,6 +25,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import org.objectweb.asm.MethodVisitor;
@@ -145,14 +146,14 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ..., value1, value2 →
     // ..., result
     return frame
         .popInitialized(appView, type)
         .popInitialized(appView, type)
-        .push(dexItemFactory.intType);
+        .push(config, dexItemFactory.intType);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java b/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
index ff36775..43e8eee 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
@@ -23,6 +23,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import java.util.ListIterator;
@@ -152,11 +153,11 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ... →
     // ..., value
-    return frame.push(dexItemFactory.classType);
+    return frame.push(config, dexItemFactory.classType);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java b/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java
index 54c7820..da94a6ba 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java
@@ -31,6 +31,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import java.util.ListIterator;
@@ -239,11 +240,11 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ... →
     // ..., value
-    return frame.push(dexItemFactory.classType);
+    return frame.push(config, dexItemFactory.classType);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
index 50564e3..ad9f25e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
@@ -23,6 +23,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import java.util.ListIterator;
@@ -116,11 +117,11 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ... →
     // ..., value
-    return frame.push(dexItemFactory.methodHandleType);
+    return frame.push(config, dexItemFactory.methodHandleType);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
index b262ff9..dc1bee0 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
@@ -22,6 +22,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import java.util.ListIterator;
@@ -114,11 +115,11 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ... →
     // ..., value
-    return frame.push(dexItemFactory.methodTypeType);
+    return frame.push(config, dexItemFactory.methodTypeType);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java b/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
index e849e05..546fd6b 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
@@ -20,6 +20,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import org.objectweb.asm.MethodVisitor;
@@ -86,11 +87,11 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ... →
     // ..., value
-    return frame.push(DexItemFactory.nullValueType);
+    return frame.push(config, DexItemFactory.nullValueType);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java b/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
index 34f67c7..3277d2b 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
@@ -21,6 +21,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
@@ -244,12 +245,12 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ... →
     // ..., value
     assert type.isPrimitive();
-    return frame.push(appView, type);
+    return frame.push(appView, config, type);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstString.java b/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
index 4e4a325..e143829 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
@@ -20,6 +20,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import org.objectweb.asm.MethodVisitor;
@@ -117,11 +118,11 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ... →
     // ..., value
-    return frame.push(dexItemFactory.stringType);
+    return frame.push(config, dexItemFactory.stringType);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java b/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
index 8bccf77..374b722 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
@@ -24,6 +24,7 @@
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.naming.dexitembasedstring.NameComputationInfo;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import java.util.ListIterator;
@@ -136,11 +137,11 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ... →
     // ..., value
-    return frame.push(dexItemFactory.stringType);
+    return frame.push(config, dexItemFactory.stringType);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFrame.java b/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
index c40062c..fafcb67 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
@@ -6,6 +6,7 @@
 import static org.objectweb.asm.Opcodes.F_NEW;
 
 import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.cf.code.frame.PrimitiveFrameType;
 import com.android.tools.r8.cf.code.frame.SingleFrameType;
 import com.android.tools.r8.cf.code.frame.WideFrameType;
 import com.android.tools.r8.errors.Unimplemented;
@@ -29,6 +30,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.IntObjConsumer;
 import com.android.tools.r8.utils.collections.ImmutableDeque;
@@ -52,10 +54,26 @@
 
   public abstract static class FrameType {
 
+    public static BooleanFrameType booleanType() {
+      return BooleanFrameType.SINGLETON;
+    }
+
+    public static ByteFrameType byteType() {
+      return ByteFrameType.SINGLETON;
+    }
+
+    public static CharFrameType charType() {
+      return CharFrameType.SINGLETON;
+    }
+
     public static DoubleFrameType doubleType() {
       return DoubleFrameType.SINGLETON;
     }
 
+    public static FloatFrameType floatType() {
+      return FloatFrameType.SINGLETON;
+    }
+
     public static IntFrameType intType() {
       return IntFrameType.SINGLETON;
     }
@@ -64,12 +82,32 @@
       return LongFrameType.SINGLETON;
     }
 
+    public static ShortFrameType shortType() {
+      return ShortFrameType.SINGLETON;
+    }
+
     public static FrameType initialized(DexType type) {
       if (type.isPrimitiveType()) {
-        if (type.isWideType()) {
-          return type.isDoubleType() ? doubleType() : longType();
-        } else if (type.isIntType()) {
-          return intType();
+        char c = (char) type.getDescriptor().content[0];
+        switch (c) {
+          case 'Z':
+            return booleanType();
+          case 'B':
+            return byteType();
+          case 'C':
+            return charType();
+          case 'D':
+            return doubleType();
+          case 'F':
+            return floatType();
+          case 'I':
+            return intType();
+          case 'J':
+            return longType();
+          case 'S':
+            return shortType();
+          default:
+            throw new Unreachable("Unexpected primitive type: " + type.getTypeName());
         }
       }
       return new SingleInitializedType(type);
@@ -97,10 +135,26 @@
 
     abstract Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens);
 
+    public boolean isBoolean() {
+      return false;
+    }
+
+    public boolean isByte() {
+      return false;
+    }
+
+    public boolean isChar() {
+      return false;
+    }
+
     public boolean isDouble() {
       return false;
     }
 
+    public boolean isFloat() {
+      return false;
+    }
+
     public boolean isInt() {
       return false;
     }
@@ -109,6 +163,10 @@
       return false;
     }
 
+    public boolean isShort() {
+      return false;
+    }
+
     public boolean isNullType() {
       return false;
     }
@@ -117,7 +175,7 @@
       return false;
     }
 
-    public DexType getObjectType(ProgramMethod context) {
+    public DexType getObjectType(DexType context) {
       assert false : "Unexpected use of getObjectType() for non-object FrameType";
       return null;
     }
@@ -126,6 +184,10 @@
       return false;
     }
 
+    public PrimitiveFrameType asPrimitive() {
+      return null;
+    }
+
     public final boolean isSingle() {
       return !isWide();
     }
@@ -134,6 +196,10 @@
       return null;
     }
 
+    public SinglePrimitiveFrameType asSinglePrimitive() {
+      return null;
+    }
+
     public SingleInitializedType asSingleInitializedType() {
       return null;
     }
@@ -146,6 +212,11 @@
       return null;
     }
 
+    public int getWidth() {
+      assert isSingle();
+      return 1;
+    }
+
     public boolean isUninitializedNew() {
       return false;
     }
@@ -166,10 +237,6 @@
       return false;
     }
 
-    public boolean isSingleInitialized() {
-      return false;
-    }
-
     public DexType getInitializedType(DexItemFactory dexItemFactory) {
       return null;
     }
@@ -283,26 +350,181 @@
     return CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other);
   }
 
-  public abstract static class SinglePrimitiveType extends SingletonFrameType
-      implements SingleFrameType {
+  public abstract static class SinglePrimitiveFrameType extends SingletonFrameType
+      implements PrimitiveFrameType, SingleFrameType {
+
+    public boolean hasIntVerificationType() {
+      return false;
+    }
 
     @Override
-    public boolean isInitialized() {
+    public final boolean isInitialized() {
       return true;
     }
 
     @Override
-    public boolean isPrimitive() {
+    public final boolean isPrimitive() {
       return true;
     }
 
     @Override
-    public SingleFrameType asSingle() {
+    public PrimitiveFrameType asPrimitive() {
       return this;
     }
+
+    @Override
+    public final SingleFrameType asSingle() {
+      return this;
+    }
+
+    @Override
+    public final SinglePrimitiveFrameType asSinglePrimitive() {
+      return this;
+    }
+
+    @Override
+    public final SingleFrameType join(SingleFrameType frameType) {
+      if (this == frameType) {
+        return this;
+      }
+      if (hasIntVerificationType()
+          && frameType.isPrimitive()
+          && frameType.asSinglePrimitive().hasIntVerificationType()) {
+        return intType();
+      }
+      return oneWord();
+    }
+
+    @Override
+    public final String toString() {
+      return getTypeName();
+    }
   }
 
-  public static class IntFrameType extends SinglePrimitiveType {
+  public static class BooleanFrameType extends SinglePrimitiveFrameType {
+
+    private static final BooleanFrameType SINGLETON = new BooleanFrameType();
+
+    private BooleanFrameType() {}
+
+    @Override
+    public DexType getInitializedType(DexItemFactory dexItemFactory) {
+      return dexItemFactory.booleanType;
+    }
+
+    @Override
+    public String getTypeName() {
+      return "boolean";
+    }
+
+    @Override
+    Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+      throw new Unreachable("Unexpected value type: " + this);
+    }
+
+    @Override
+    public boolean hasIntVerificationType() {
+      return true;
+    }
+
+    @Override
+    public boolean isBoolean() {
+      return true;
+    }
+  }
+
+  public static class ByteFrameType extends SinglePrimitiveFrameType {
+
+    private static final ByteFrameType SINGLETON = new ByteFrameType();
+
+    private ByteFrameType() {}
+
+    @Override
+    public DexType getInitializedType(DexItemFactory dexItemFactory) {
+      return dexItemFactory.byteType;
+    }
+
+    @Override
+    public String getTypeName() {
+      return "byte";
+    }
+
+    @Override
+    Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+      throw new Unreachable("Unexpected value type: " + this);
+    }
+
+    @Override
+    public boolean hasIntVerificationType() {
+      return true;
+    }
+
+    @Override
+    public boolean isByte() {
+      return true;
+    }
+  }
+
+  public static class CharFrameType extends SinglePrimitiveFrameType {
+
+    private static final CharFrameType SINGLETON = new CharFrameType();
+
+    private CharFrameType() {}
+
+    @Override
+    public DexType getInitializedType(DexItemFactory dexItemFactory) {
+      return dexItemFactory.charType;
+    }
+
+    @Override
+    public String getTypeName() {
+      return "char";
+    }
+
+    @Override
+    Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+      throw new Unreachable("Unexpected value type: " + this);
+    }
+
+    @Override
+    public boolean hasIntVerificationType() {
+      return true;
+    }
+
+    @Override
+    public boolean isChar() {
+      return true;
+    }
+  }
+
+  public static class FloatFrameType extends SinglePrimitiveFrameType {
+
+    private static final FloatFrameType SINGLETON = new FloatFrameType();
+
+    private FloatFrameType() {}
+
+    @Override
+    public DexType getInitializedType(DexItemFactory dexItemFactory) {
+      return dexItemFactory.floatType;
+    }
+
+    @Override
+    public String getTypeName() {
+      return "float";
+    }
+
+    @Override
+    Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+      return Opcodes.FLOAT;
+    }
+
+    @Override
+    public boolean isFloat() {
+      return true;
+    }
+  }
+
+  public static class IntFrameType extends SinglePrimitiveFrameType {
 
     private static final IntFrameType SINGLETON = new IntFrameType();
 
@@ -314,8 +536,8 @@
     }
 
     @Override
-    public boolean isInt() {
-      return true;
+    public String getTypeName() {
+      return "int";
     }
 
     @Override
@@ -324,23 +546,45 @@
     }
 
     @Override
-    public SingleFrameType join(SingleFrameType frameType) {
-      if (this == frameType) {
-        return this;
-      }
-      if (frameType.isOneWord() || frameType.isUninitializedObject()) {
-        return oneWord();
-      }
-      assert frameType.isInitialized();
-      return CfAssignability.hasIntVerificationType(
-              frameType.asSingleInitializedType().getInitializedType())
-          ? this
-          : oneWord();
+    public boolean hasIntVerificationType() {
+      return true;
     }
 
     @Override
-    public String toString() {
-      return "int";
+    public boolean isInt() {
+      return true;
+    }
+  }
+
+  public static class ShortFrameType extends SinglePrimitiveFrameType {
+
+    private static final ShortFrameType SINGLETON = new ShortFrameType();
+
+    private ShortFrameType() {}
+
+    @Override
+    public DexType getInitializedType(DexItemFactory dexItemFactory) {
+      return dexItemFactory.shortType;
+    }
+
+    @Override
+    public String getTypeName() {
+      return "short";
+    }
+
+    @Override
+    Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+      throw new Unreachable("Unexpected value type: " + this);
+    }
+
+    @Override
+    public boolean hasIntVerificationType() {
+      return true;
+    }
+
+    @Override
+    public boolean isShort() {
+      return true;
     }
   }
 
@@ -350,7 +594,7 @@
 
     private SingleInitializedType(DexType type) {
       assert type != null;
-      assert !type.isIntType();
+      assert type.isReferenceType();
       this.type = type;
     }
 
@@ -364,26 +608,11 @@
       if (equals(frameType)) {
         return this;
       }
-      if (frameType.isOneWord() || frameType.isUninitializedObject()) {
+      if (frameType.isOneWord() || frameType.isPrimitive() || frameType.isUninitializedObject()) {
         return oneWord();
       }
-      assert frameType.isInitialized();
-      if (frameType.isPrimitive()) {
-        if (frameType.isInt()) {
-          return CfAssignability.hasIntVerificationType(type) ? frameType : oneWord();
-        }
-        // The rest of the primitives are still represented using SingleInitializedType.
-        DexType otherType = frameType.asSingleInitializedType().getInitializedType();
-        return CfAssignability.hasIntVerificationType(type)
-                && CfAssignability.hasIntVerificationType(otherType)
-            ? intType()
-            : oneWord();
-      }
       DexType otherType = frameType.asSingleInitializedType().getInitializedType();
       assert type != otherType;
-      if (type.isPrimitiveType()) {
-        return oneWord();
-      }
       assert type.isReferenceType();
       if (isNullType()) {
         return otherType.isReferenceType() ? frameType : oneWord();
@@ -456,16 +685,6 @@
       return true;
     }
 
-    @Override
-    public boolean isPrimitive() {
-      return type.isPrimitiveType();
-    }
-
-    @Override
-    public boolean isSingleInitialized() {
-      return true;
-    }
-
     public DexType getInitializedType() {
       return type;
     }
@@ -486,14 +705,14 @@
     }
 
     @Override
-    public DexType getObjectType(ProgramMethod context) {
+    public DexType getObjectType(DexType context) {
       assert isObject() : "Unexpected use of getObjectType() for non-object FrameType";
       return type;
     }
   }
 
-  public abstract static class WideInitializedType extends SingletonFrameType
-      implements WideFrameType {
+  public abstract static class WidePrimitiveFrameType extends SingletonFrameType
+      implements PrimitiveFrameType, WideFrameType {
 
     @Override
     public boolean isInitialized() {
@@ -506,6 +725,11 @@
     }
 
     @Override
+    public PrimitiveFrameType asPrimitive() {
+      return this;
+    }
+
+    @Override
     public boolean isWide() {
       return true;
     }
@@ -516,12 +740,22 @@
     }
 
     @Override
+    public int getWidth() {
+      return 2;
+    }
+
+    @Override
     public WideFrameType join(WideFrameType frameType) {
       return this == frameType ? this : twoWord();
     }
+
+    @Override
+    public final String toString() {
+      return getTypeName();
+    }
   }
 
-  private static class DoubleFrameType extends WideInitializedType {
+  public static class DoubleFrameType extends WidePrimitiveFrameType {
 
     private static final DoubleFrameType SINGLETON = new DoubleFrameType();
 
@@ -538,17 +772,17 @@
     }
 
     @Override
-    Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
-      return Opcodes.DOUBLE;
+    public String getTypeName() {
+      return "double";
     }
 
     @Override
-    public String toString() {
-      return "double";
+    Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+      return Opcodes.DOUBLE;
     }
   }
 
-  public static class LongFrameType extends WideInitializedType {
+  public static class LongFrameType extends WidePrimitiveFrameType {
 
     private static final LongFrameType SINGLETON = new LongFrameType();
 
@@ -565,13 +799,13 @@
     }
 
     @Override
-    Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
-      return Opcodes.LONG;
+    public String getTypeName() {
+      return "long";
     }
 
     @Override
-    public String toString() {
-      return "long";
+    Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+      return Opcodes.LONG;
     }
   }
 
@@ -628,7 +862,7 @@
     }
 
     @Override
-    public DexType getObjectType(ProgramMethod context) {
+    public DexType getObjectType(DexType context) {
       return type;
     }
 
@@ -688,8 +922,8 @@
     }
 
     @Override
-    public DexType getObjectType(ProgramMethod context) {
-      return context.getHolderType();
+    public DexType getObjectType(DexType context) {
+      return context;
     }
 
     @Override
@@ -767,6 +1001,11 @@
     }
 
     @Override
+    public int getWidth() {
+      return 2;
+    }
+
+    @Override
     public WideFrameType join(WideFrameType frameType) {
       // The join of wide with one of {double, long, wide} is wide.
       return this;
@@ -843,10 +1082,20 @@
     return locals;
   }
 
+  public Int2ObjectAVLTreeMap<FrameType> getMutableLocals() {
+    assert locals instanceof Int2ObjectAVLTreeMap<?>;
+    return (Int2ObjectAVLTreeMap<FrameType>) locals;
+  }
+
   public Deque<FrameType> getStack() {
     return stack;
   }
 
+  public ArrayDeque<FrameType> getMutableStack() {
+    assert stack instanceof ArrayDeque<?>;
+    return (ArrayDeque<FrameType>) stack;
+  }
+
   @Override
   public boolean equals(Object obj) {
     if (this == obj) {
@@ -898,7 +1147,7 @@
   public int computeStackSize() {
     int size = 0;
     for (FrameType frameType : stack) {
-      size += frameType.isWide() ? 2 : 1;
+      size += frameType.getWidth();
     }
     return size;
   }
@@ -989,8 +1238,8 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     return frame.check(appView, this);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfGoto.java b/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
index 10a85b9..490de77 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
@@ -19,6 +19,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.TraversalContinuation;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
@@ -119,8 +120,8 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     return frame;
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIf.java b/src/main/java/com/android/tools/r8/cf/code/CfIf.java
index 8388a88..78acd72 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfIf.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfIf.java
@@ -19,6 +19,7 @@
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.TraversalContinuation;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
@@ -117,8 +118,8 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ..., value →
     // ...
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java b/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java
index 7c30583..96f5832 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java
@@ -20,6 +20,7 @@
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.TraversalContinuation;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
@@ -118,8 +119,8 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ..., value1, value2 →
     // ...
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIinc.java b/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
index 5a121bd..8135aa9 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
@@ -21,6 +21,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.FunctionUtils;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
@@ -109,8 +110,8 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     return frame.readLocal(appView, getLocalIndex(), ValueType.INT, FunctionUtils::getFirst);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java b/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
index a168090..fe8f36e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
@@ -23,6 +23,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import java.util.ListIterator;
@@ -129,11 +130,11 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ..., →
     // ..., value
-    return frame.push(dexItemFactory.intType);
+    return frame.push(config, dexItemFactory.intType);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldRead.java b/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldRead.java
index c461c07..1eb4b5d 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldRead.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldRead.java
@@ -4,7 +4,7 @@
 
 package com.android.tools.r8.cf.code;
 
-import com.android.tools.r8.code.CfOrDexInstanceFieldRead;
+import com.android.tools.r8.dex.code.CfOrDexInstanceFieldRead;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.DexClassAndMethod;
@@ -19,6 +19,7 @@
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import java.util.ListIterator;
 import org.objectweb.asm.Opcodes;
@@ -80,11 +81,13 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ..., objectref →
     // ..., value
-    return frame.popInitialized(appView, getField().getHolderType()).push(getField().getType());
+    return frame
+        .popInitialized(appView, getField().getHolderType())
+        .push(config, getField().getType());
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldWrite.java b/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldWrite.java
index ea0d0f8..b7bf3ec 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldWrite.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldWrite.java
@@ -4,8 +4,10 @@
 
 package com.android.tools.r8.cf.code;
 
+import static com.android.tools.r8.optimize.interfaces.analysis.ErroneousCfFrameState.formatActual;
 import static com.android.tools.r8.utils.BiPredicateUtils.or;
 
+import com.android.tools.r8.cf.code.CfFrame.FrameType;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.DexClassAndMethod;
@@ -20,7 +22,9 @@
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
+import com.android.tools.r8.optimize.interfaces.analysis.ErroneousCfFrameState;
 import java.util.ListIterator;
 import org.objectweb.asm.Opcodes;
 
@@ -83,8 +87,8 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ..., objectref, value →
     // ...
@@ -93,7 +97,15 @@
         .popObject(
             appView,
             getField().getHolderType(),
-            context,
-            (state, head) -> head.isUninitializedNew() ? CfFrameState.error() : state);
+            config,
+            (state, head) -> head.isUninitializedNew() ? error(head) : state);
+  }
+
+  private ErroneousCfFrameState error(FrameType objectType) {
+    return CfFrameState.error(
+        "Frame type "
+            + formatActual(objectType)
+            + " is not assignable to "
+            + getField().getHolderType().getTypeName());
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java b/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
index 53f9904..e42e7e3 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
@@ -22,6 +22,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import java.util.ListIterator;
@@ -139,11 +140,13 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ..., objectref →
     // ..., result
-    return frame.popInitialized(appView, dexItemFactory.objectType).push(dexItemFactory.intType);
+    return frame
+        .popInitialized(appView, dexItemFactory.objectType)
+        .push(config, dexItemFactory.intType);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
index 6599e60..dc1f4de 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
@@ -4,8 +4,8 @@
 package com.android.tools.r8.cf.code;
 
 import com.android.tools.r8.cf.CfPrinter;
-import com.android.tools.r8.code.CfOrDexInstruction;
-import com.android.tools.r8.code.Instruction;
+import com.android.tools.r8.dex.code.CfOrDexInstruction;
+import com.android.tools.r8.dex.code.DexInstruction;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
@@ -25,6 +25,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.TraversalContinuation;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
@@ -127,7 +128,12 @@
       CT initialValue) {
     // The method is overridden in each jump instruction.
     assert !isJump();
-    return fn.apply(fallthroughInstruction, initialValue);
+    if (fallthroughInstruction != null) {
+      return fn.apply(fallthroughInstruction, initialValue);
+    }
+    // There may be a label after the last return.
+    assert isLabel();
+    return TraversalContinuation.doContinue(initialValue);
   }
 
   @Override
@@ -141,7 +147,7 @@
   }
 
   @Override
-  public Instruction asDexInstruction() {
+  public DexInstruction asDexInstruction() {
     return null;
   }
 
@@ -355,5 +361,8 @@
       DexItemFactory dexItemFactory);
 
   public abstract CfFrameState evaluate(
-      CfFrameState frame, ProgramMethod context, AppView<?> appView, DexItemFactory dexItemFactory);
+      CfFrameState frame,
+      AppView<?> appView,
+      CfAnalysisConfig config,
+      DexItemFactory dexItemFactory);
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
index c972e4e..bbaf8b5 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
@@ -32,6 +32,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
@@ -341,8 +342,8 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ..., objectref, [arg1, [arg2 ...]] →
     // ... [ returnType ]
@@ -352,14 +353,14 @@
     frame = frame.popInitialized(appView, method.getParameters().getBacking());
     if (opcode != Opcodes.INVOKESTATIC) {
       frame =
-          opcode == Opcodes.INVOKESPECIAL && context.getDefinition().isInstanceInitializer()
-              ? frame.popAndInitialize(appView, method, context)
+          opcode == Opcodes.INVOKESPECIAL && method.isInstanceInitializer(dexItemFactory)
+              ? frame.popAndInitialize(appView, method, config)
               : frame.popInitialized(appView, method.getHolderType());
     }
     if (method.getReturnType().isVoidType()) {
       return frame;
     }
-    return frame.push(method.getReturnType());
+    return frame.push(config, method.getReturnType());
   }
 
   private Type computeInvokeTypeForInvokeSpecial(
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java b/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
index 121c288..dc81cfc 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
@@ -28,6 +28,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import java.util.ArrayList;
@@ -183,8 +184,8 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ..., [arg1, [arg2 ...]] →
     // ...
@@ -193,6 +194,6 @@
     if (returnType.isVoidType()) {
       return frame;
     }
-    return frame.push(returnType);
+    return frame.push(config, returnType);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java b/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
index ab730fb..f132e94 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
@@ -21,6 +21,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import org.objectweb.asm.MethodVisitor;
@@ -97,10 +98,10 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
-    return CfFrameState.error();
+    return CfFrameState.error("Unexpected JSR/RET instruction");
   }
 
   public int getLocal() {
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLabel.java b/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
index 0e1ee11..7705bce 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
@@ -19,6 +19,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import org.objectweb.asm.Label;
@@ -107,8 +108,8 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     return frame;
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLoad.java b/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
index 225ad07..22e8e44 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
@@ -22,6 +22,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import org.objectweb.asm.MethodVisitor;
@@ -144,11 +145,12 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ... →
     // ..., objectref
-    return frame.readLocal(appView, getLocalIndex(), type, CfFrameState::push);
+    return frame.readLocal(
+        appView, getLocalIndex(), type, (state, frameType) -> state.push(config, frameType));
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java b/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
index 3cf6f34..18bf0d3 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
@@ -23,6 +23,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import org.objectweb.asm.MethodVisitor;
@@ -202,8 +203,8 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ..., value1, value2 →
     // ..., result
@@ -221,6 +222,6 @@
     return frame
         .popInitialized(appView, value2Type)
         .popInitialized(appView, value1Type)
-        .push(appView, value1Type);
+        .push(appView, config, value1Type);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java b/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
index f860f58..9b6e582 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
@@ -22,6 +22,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import org.objectweb.asm.MethodVisitor;
@@ -108,8 +109,8 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ..., objectref →
     // ...
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java b/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
index a69ff20..0d48a12 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
@@ -22,6 +22,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
@@ -145,14 +146,14 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ..., count1, [count2, ...] →
     // ..., arrayref
     for (int i = 0; i < dimensions; i++) {
       frame = frame.popInitialized(appView, dexItemFactory.intType);
     }
-    return frame.push(type);
+    return frame.push(config, type);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNeg.java b/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
index c25b0ff..5150a97 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
@@ -23,6 +23,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import org.objectweb.asm.MethodVisitor;
@@ -134,11 +135,11 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ..., value →
     // ..., result
-    return frame.popInitialized(appView, type).push(appView, type);
+    return frame.popInitialized(appView, type).push(appView, config, type);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNew.java b/src/main/java/com/android/tools/r8/cf/code/CfNew.java
index bcfae83..94fbd54 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNew.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNew.java
@@ -23,6 +23,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import java.util.ListIterator;
@@ -145,11 +146,11 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ... →
     // ..., objectref
-    return frame.push(FrameType.uninitializedNew(getLabel(), type));
+    return frame.push(config, FrameType.uninitializedNew(getLabel(), type));
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java b/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
index 261db2e..6d176fa 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
@@ -24,6 +24,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
@@ -178,11 +179,11 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ..., count →
     // ..., arrayref
-    return frame.popInitialized(appView, dexItemFactory.intType).push(type);
+    return frame.popInitialized(appView, dexItemFactory.intType).push(config, type);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java b/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java
index 73d04d1..7814564 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java
@@ -24,6 +24,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import java.util.ListIterator;
@@ -131,11 +132,11 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ... →
     // ..., objectref
-    return frame.push(type);
+    return frame.push(config, type);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNop.java b/src/main/java/com/android/tools/r8/cf/code/CfNop.java
index 7bc083c..db3ea6a 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNop.java
@@ -19,6 +19,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import org.objectweb.asm.MethodVisitor;
@@ -88,8 +89,8 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     return frame;
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java b/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
index ee83adb..f302df8 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
@@ -23,6 +23,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import org.objectweb.asm.MethodVisitor;
@@ -206,11 +207,11 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ..., value →
     // ..., result
-    return frame.popInitialized(appView, from).push(appView, to);
+    return frame.popInitialized(appView, from).push(appView, config, to);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfPosition.java b/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
index 42ebf38..1df0826 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
@@ -20,6 +20,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import org.objectweb.asm.MethodVisitor;
@@ -121,8 +122,8 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     return frame;
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java b/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java
index ba04a1c..2d2456e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java
@@ -23,6 +23,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
@@ -124,12 +125,12 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     for (DexField ignored : fields) {
       frame = frame.popInitialized(appView, dexItemFactory.objectType);
     }
-    return frame.push(dexItemFactory.objectArrayType);
+    return frame.push(config, dexItemFactory.objectArrayType);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfReturn.java b/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
index be09285..6c007cc 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
@@ -22,6 +22,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.TraversalContinuation;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
@@ -131,10 +132,10 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
-    assert !context.getReturnType().isVoidType();
-    return frame.popInitialized(appView, context.getReturnType()).clear();
+    assert !config.getCurrentContext().getReturnType().isVoidType();
+    return frame.popInitialized(appView, config.getCurrentContext().getReturnType()).clear();
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java b/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
index 0572c8b..e21e6c7 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
@@ -19,6 +19,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.TraversalContinuation;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
@@ -103,8 +104,8 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     return frame.clear();
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
index e27498e..345cc84 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
@@ -24,6 +24,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.FunctionUtils;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
@@ -510,8 +511,8 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     switch (opcode) {
       case Pop:
@@ -532,13 +533,13 @@
       case Dup:
         // ..., value →
         // ..., value, value
-        return frame.popSingle((state, single) -> state.push(single, single));
+        return frame.popSingle((state, single) -> state.push(config, single, single));
       case DupX1:
         {
           // ..., value2, value1 →
           // ..., value1, value2, value1
           return frame.popSingles(
-              (state, single2, single1) -> state.push(single1, single2, single1));
+              (state, single2, single1) -> state.push(config, single1, single2, single1));
         }
       case DupX2:
         {
@@ -550,8 +551,9 @@
           return frame.popSingle(
               (state1, single1) ->
                   state1.popSingleSingleOrWide(
-                      (state2, single3, single2) -> state2.push(single1, single3, single2, single1),
-                      (state2, wide2) -> state2.push(single1, wide2, single1)));
+                      (state2, single3, single2) ->
+                          state2.push(config, single1, single3, single2, single1),
+                      (state2, wide2) -> state2.push(config, single1, wide2, single1)));
         }
       case Dup2:
         {
@@ -561,8 +563,8 @@
           // ..., value →
           // ..., value, value
           return frame.popSingleSingleOrWide(
-              (state, single2, single1) -> state.push(single2, single1, single2, single1),
-              (state, wide) -> state.push(wide, wide));
+              (state, single2, single1) -> state.push(config, single2, single1, single2, single1),
+              (state, wide) -> state.push(config, wide, wide));
         }
       case Dup2X1:
         {
@@ -575,9 +577,10 @@
               (state1, single2, single1) ->
                   state1.popSingle(
                       (state2, single3) ->
-                          state2.push(single2, single1, single3, single2, single1)),
+                          state2.push(config, single2, single1, single3, single2, single1)),
               (state1, wide1) ->
-                  state1.popSingle((state2, single2) -> state2.push(wide1, single2, wide1)));
+                  state1.popSingle(
+                      (state2, single2) -> state2.push(config, wide1, single2, wide1)));
         }
       case Dup2X2:
         {
@@ -597,18 +600,21 @@
               (state1, single2, single1) ->
                   state1.popSingleSingleOrWide(
                       (state2, single4, single3) ->
-                          state2.push(single2, single1, single4, single3, single2, single1),
-                      (state2, wide3) -> state2.push(single2, single1, wide3, single2, single1)),
+                          state2.push(config, single2, single1, single4, single3, single2, single1),
+                      (state2, wide3) ->
+                          state2.push(config, single2, single1, wide3, single2, single1)),
               (state1, wide1) ->
                   state1.popSingleSingleOrWide(
-                      (state2, single3, single2) -> state2.push(wide1, single3, single2, wide1),
-                      (state2, wide2) -> state2.push(wide1, wide2, wide1)));
+                      (state2, single3, single2) ->
+                          state2.push(config, wide1, single3, single2, wide1),
+                      (state2, wide2) -> state2.push(config, wide1, wide2, wide1)));
         }
       case Swap:
         {
           // ..., value2, value1 →
           // ..., value1, value2
-          return frame.popSingles((state, single2, single1) -> state.push(single1, single2));
+          return frame.popSingles(
+              (state, single2, single1) -> state.push(config, single1, single2));
         }
       default:
         throw new Unreachable("Invalid opcode for CfStackInstruction");
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldRead.java b/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldRead.java
index 3950a9c..e0d1ab1 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldRead.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldRead.java
@@ -4,7 +4,7 @@
 
 package com.android.tools.r8.cf.code;
 
-import com.android.tools.r8.code.CfOrDexStaticFieldRead;
+import com.android.tools.r8.dex.code.CfOrDexStaticFieldRead;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.DexClassAndMethod;
@@ -18,6 +18,7 @@
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import java.util.ListIterator;
 import org.objectweb.asm.Opcodes;
@@ -83,11 +84,11 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ..., →
     // ..., value
-    return frame.push(getField().getType());
+    return frame.push(config, getField().getType());
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldWrite.java b/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldWrite.java
index 3c64e6a..dc25d3f 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldWrite.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldWrite.java
@@ -18,6 +18,7 @@
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import java.util.ListIterator;
 import org.objectweb.asm.Opcodes;
@@ -79,8 +80,8 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ..., value →
     // ...
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStore.java b/src/main/java/com/android/tools/r8/cf/code/CfStore.java
index 2d1bf34..e5406bb 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStore.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStore.java
@@ -25,6 +25,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import org.objectweb.asm.MethodVisitor;
@@ -177,19 +178,20 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ..., ref →
     // ...
     if (type.isObject()) {
-      return frame.popObject((state, head) -> state.storeLocal(getLocalIndex(), head));
+      return frame.popObject((state, head) -> state.storeLocal(getLocalIndex(), head, config));
     } else {
       assert type.isPrimitive();
       return frame.popInitialized(
           appView,
           type,
-          (state, head) -> state.storeLocal(getLocalIndex(), type.toPrimitiveType(), appView));
+          (state, head) ->
+              state.storeLocal(getLocalIndex(), type.toPrimitiveType(), appView, config));
     }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java b/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
index 695bd9c..44bb2c9 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
@@ -21,6 +21,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.TraversalContinuation;
 import com.android.tools.r8.utils.TraversalUtils;
@@ -184,8 +185,8 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ..., index/key →
     // ...
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfThrow.java b/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
index ef2ab8b..126c0ad 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
@@ -20,6 +20,7 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
 import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
 import com.android.tools.r8.utils.TraversalContinuation;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
@@ -114,8 +115,8 @@
   @Override
   public CfFrameState evaluate(
       CfFrameState frame,
-      ProgramMethod context,
       AppView<?> appView,
+      CfAnalysisConfig config,
       DexItemFactory dexItemFactory) {
     // ..., objectref →
     // objectref
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/PrimitiveFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/PrimitiveFrameType.java
new file mode 100644
index 0000000..2db1925
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/PrimitiveFrameType.java
@@ -0,0 +1,10 @@
+// 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.cf.code.frame;
+
+public interface PrimitiveFrameType {
+
+  String getTypeName();
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/SingleFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/SingleFrameType.java
index 1723418..ce215b6 100644
--- a/src/main/java/com/android/tools/r8/cf/code/frame/SingleFrameType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/SingleFrameType.java
@@ -6,6 +6,7 @@
 
 import com.android.tools.r8.cf.code.CfFrame.FrameType;
 import com.android.tools.r8.cf.code.CfFrame.SingleInitializedType;
+import com.android.tools.r8.cf.code.CfFrame.SinglePrimitiveFrameType;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
 
@@ -27,6 +28,8 @@
 
   boolean isPrimitive();
 
+  SinglePrimitiveFrameType asSinglePrimitive();
+
   boolean isUninitializedNew();
 
   DexType getUninitializedNewType();
diff --git a/src/main/java/com/android/tools/r8/code/BaseInstructionFactory.java b/src/main/java/com/android/tools/r8/code/BaseInstructionFactory.java
deleted file mode 100644
index 4e15eb9..0000000
--- a/src/main/java/com/android/tools/r8/code/BaseInstructionFactory.java
+++ /dev/null
@@ -1,465 +0,0 @@
-// Copyright (c) 2016, 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.code;
-
-import com.android.tools.r8.graph.OffsetToObjectMapping;
-
-abstract class BaseInstructionFactory {
-
-  static Instruction create(int high, int opcode, BytecodeStream stream,
-      OffsetToObjectMapping mapping) {
-    switch (opcode) {
-      case 0x0:
-        return Nop.create(high, stream);
-      case Move.OPCODE:
-        return new Move(high, stream);
-      case MoveFrom16.OPCODE:
-        return new MoveFrom16(high, stream);
-      case Move16.OPCODE:
-        return new Move16(high, stream);
-      case MoveWide.OPCODE:
-        return new MoveWide(high, stream);
-      case MoveWideFrom16.OPCODE:
-        return new MoveWideFrom16(high, stream);
-      case MoveWide16.OPCODE:
-        return new MoveWide16(high, stream);
-      case MoveObject.OPCODE:
-        return new MoveObject(high, stream);
-      case MoveObjectFrom16.OPCODE:
-        return new MoveObjectFrom16(high, stream);
-      case MoveObject16.OPCODE:
-        return new MoveObject16(high, stream);
-      case MoveResult.OPCODE:
-        return new MoveResult(high, stream);
-      case MoveResultWide.OPCODE:
-        return new MoveResultWide(high, stream);
-      case MoveResultObject.OPCODE:
-        return new MoveResultObject(high, stream);
-      case MoveException.OPCODE:
-        return new MoveException(high, stream);
-      case ReturnVoid.OPCODE:
-        return new ReturnVoid(high, stream);
-      case Return.OPCODE:
-        return new Return(high, stream);
-      case ReturnWide.OPCODE:
-        return new ReturnWide(high, stream);
-      case ReturnObject.OPCODE:
-        return new ReturnObject(high, stream);
-      case Const4.OPCODE:
-        return new Const4(high, stream);
-      case Const16.OPCODE:
-        return new Const16(high, stream);
-      case Const.OPCODE:
-        return new Const(high, stream);
-      case ConstHigh16.OPCODE:
-        return new ConstHigh16(high, stream);
-      case ConstWide16.OPCODE:
-        return new ConstWide16(high, stream);
-      case ConstWide32.OPCODE:
-        return new ConstWide32(high, stream);
-      case ConstWide.OPCODE:
-        return new ConstWide(high, stream);
-      case ConstWideHigh16.OPCODE:
-        return new ConstWideHigh16(high, stream);
-      case ConstString.OPCODE:
-        return new ConstString(high, stream, mapping);
-      case ConstStringJumbo.OPCODE:
-        return new ConstStringJumbo(high, stream, mapping);
-      case ConstClass.OPCODE:
-        return new ConstClass(high, stream, mapping);
-      case MonitorEnter.OPCODE:
-        return new MonitorEnter(high, stream);
-      case MonitorExit.OPCODE:
-        return new MonitorExit(high, stream);
-      case CheckCast.OPCODE:
-        return new CheckCast(high, stream, mapping);
-      case InstanceOf.OPCODE:
-        return new InstanceOf(high, stream, mapping);
-      case ArrayLength.OPCODE:
-        return new ArrayLength(high, stream);
-      case NewInstance.OPCODE:
-        return new NewInstance(high, stream, mapping);
-      case NewArray.OPCODE:
-        return new NewArray(high, stream, mapping);
-      case FilledNewArray.OPCODE:
-        return new FilledNewArray(high, stream, mapping);
-      case FilledNewArrayRange.OPCODE:
-        return new FilledNewArrayRange(high, stream, mapping);
-      case FillArrayData.OPCODE:
-        return new FillArrayData(high, stream);
-      case Throw.OPCODE:
-        return new Throw(high, stream);
-      case Goto.OPCODE:
-        return new Goto(high, stream);
-      case Goto16.OPCODE:
-        return new Goto16(high, stream);
-      case Goto32.OPCODE:
-        return new Goto32(high, stream);
-      case PackedSwitch.OPCODE:
-        return new PackedSwitch(high, stream);
-      case SparseSwitch.OPCODE:
-        return new SparseSwitch(high, stream);
-      case CmplFloat.OPCODE:
-        return new CmplFloat(high, stream);
-      case CmpgFloat.OPCODE:
-        return new CmpgFloat(high, stream);
-      case CmplDouble.OPCODE:
-        return new CmplDouble(high, stream);
-      case CmpgDouble.OPCODE:
-        return new CmpgDouble(high, stream);
-      case CmpLong.OPCODE:
-        return new CmpLong(high, stream);
-      case IfEq.OPCODE:
-        return new IfEq(high, stream);
-      case IfNe.OPCODE:
-        return new IfNe(high, stream);
-      case IfLt.OPCODE:
-        return new IfLt(high, stream);
-      case IfGe.OPCODE:
-        return new IfGe(high, stream);
-      case IfGt.OPCODE:
-        return new IfGt(high, stream);
-      case IfLe.OPCODE:
-        return new IfLe(high, stream);
-      case IfEqz.OPCODE:
-        return new IfEqz(high, stream);
-      case IfNez.OPCODE:
-        return new IfNez(high, stream);
-      case IfLtz.OPCODE:
-        return new IfLtz(high, stream);
-      case IfGez.OPCODE:
-        return new IfGez(high, stream);
-      case IfGtz.OPCODE:
-        return new IfGtz(high, stream);
-      case IfLez.OPCODE:
-        return new IfLez(high, stream);
-      case Aget.OPCODE:
-        return new Aget(high, stream);
-      case AgetWide.OPCODE:
-        return new AgetWide(high, stream);
-      case AgetObject.OPCODE:
-        return new AgetObject(high, stream);
-      case AgetBoolean.OPCODE:
-        return new AgetBoolean(high, stream);
-      case AgetByte.OPCODE:
-        return new AgetByte(high, stream);
-      case AgetChar.OPCODE:
-        return new AgetChar(high, stream);
-      case AgetShort.OPCODE:
-        return new AgetShort(high, stream);
-      case Aput.OPCODE:
-        return new Aput(high, stream);
-      case AputWide.OPCODE:
-        return new AputWide(high, stream);
-      case AputObject.OPCODE:
-        return new AputObject(high, stream);
-      case AputBoolean.OPCODE:
-        return new AputBoolean(high, stream);
-      case AputByte.OPCODE:
-        return new AputByte(high, stream);
-      case AputChar.OPCODE:
-        return new AputChar(high, stream);
-      case AputShort.OPCODE:
-        return new AputShort(high, stream);
-      case Iget.OPCODE:
-        return new Iget(high, stream, mapping);
-      case IgetWide.OPCODE:
-        return new IgetWide(high, stream, mapping);
-      case IgetObject.OPCODE:
-        return new IgetObject(high, stream, mapping);
-      case IgetBoolean.OPCODE:
-        return new IgetBoolean(high, stream, mapping);
-      case IgetByte.OPCODE:
-        return new IgetByte(high, stream, mapping);
-      case IgetChar.OPCODE:
-        return new IgetChar(high, stream, mapping);
-      case IgetShort.OPCODE:
-        return new IgetShort(high, stream, mapping);
-      case Iput.OPCODE:
-        return new Iput(high, stream, mapping);
-      case IputWide.OPCODE:
-        return new IputWide(high, stream, mapping);
-      case IputObject.OPCODE:
-        return new IputObject(high, stream, mapping);
-      case IputBoolean.OPCODE:
-        return new IputBoolean(high, stream, mapping);
-      case IputByte.OPCODE:
-        return new IputByte(high, stream, mapping);
-      case IputChar.OPCODE:
-        return new IputChar(high, stream, mapping);
-      case IputShort.OPCODE:
-        return new IputShort(high, stream, mapping);
-      case Sget.OPCODE:
-        return new Sget(high, stream, mapping);
-      case SgetWide.OPCODE:
-        return new SgetWide(high, stream, mapping);
-      case SgetObject.OPCODE:
-        return new SgetObject(high, stream, mapping);
-      case SgetBoolean.OPCODE:
-        return new SgetBoolean(high, stream, mapping);
-      case SgetByte.OPCODE:
-        return new SgetByte(high, stream, mapping);
-      case SgetChar.OPCODE:
-        return new SgetChar(high, stream, mapping);
-      case SgetShort.OPCODE:
-        return new SgetShort(high, stream, mapping);
-      case Sput.OPCODE:
-        return new Sput(high, stream, mapping);
-      case SputWide.OPCODE:
-        return new SputWide(high, stream, mapping);
-      case SputObject.OPCODE:
-        return new SputObject(high, stream, mapping);
-      case SputBoolean.OPCODE:
-        return new SputBoolean(high, stream, mapping);
-      case SputByte.OPCODE:
-        return new SputByte(high, stream, mapping);
-      case SputChar.OPCODE:
-        return new SputChar(high, stream, mapping);
-      case SputShort.OPCODE:
-        return new SputShort(high, stream, mapping);
-      case InvokeVirtual.OPCODE:
-        return new InvokeVirtual(high, stream, mapping);
-      case InvokeSuper.OPCODE:
-        return new InvokeSuper(high, stream, mapping);
-      case InvokeDirect.OPCODE:
-        return new InvokeDirect(high, stream, mapping);
-      case InvokeStatic.OPCODE:
-        return new InvokeStatic(high, stream, mapping);
-      case InvokeInterface.OPCODE:
-        return new InvokeInterface(high, stream, mapping);
-      case InvokeVirtualRange.OPCODE:
-        return new InvokeVirtualRange(high, stream, mapping);
-      case InvokeSuperRange.OPCODE:
-        return new InvokeSuperRange(high, stream, mapping);
-      case InvokeDirectRange.OPCODE:
-        return new InvokeDirectRange(high, stream, mapping);
-      case InvokeStaticRange.OPCODE:
-        return new InvokeStaticRange(high, stream, mapping);
-      case InvokeInterfaceRange.OPCODE:
-        return new InvokeInterfaceRange(high, stream, mapping);
-      case NegInt.OPCODE:
-        return new NegInt(high, stream);
-      case NotInt.OPCODE:
-        return new NotInt(high, stream);
-      case NegLong.OPCODE:
-        return new NegLong(high, stream);
-      case NotLong.OPCODE:
-        return new NotLong(high, stream);
-      case NegFloat.OPCODE:
-        return new NegFloat(high, stream);
-      case NegDouble.OPCODE:
-        return new NegDouble(high, stream);
-      case IntToLong.OPCODE:
-        return new IntToLong(high, stream);
-      case IntToFloat.OPCODE:
-        return new IntToFloat(high, stream);
-      case IntToDouble.OPCODE:
-        return new IntToDouble(high, stream);
-      case LongToInt.OPCODE:
-        return new LongToInt(high, stream);
-      case LongToFloat.OPCODE:
-        return new LongToFloat(high, stream);
-      case LongToDouble.OPCODE:
-        return new LongToDouble(high, stream);
-      case FloatToInt.OPCODE:
-        return new FloatToInt(high, stream);
-      case FloatToLong.OPCODE:
-        return new FloatToLong(high, stream);
-      case FloatToDouble.OPCODE:
-        return new FloatToDouble(high, stream);
-      case DoubleToInt.OPCODE:
-        return new DoubleToInt(high, stream);
-      case DoubleToLong.OPCODE:
-        return new DoubleToLong(high, stream);
-      case DoubleToFloat.OPCODE:
-        return new DoubleToFloat(high, stream);
-      case IntToByte.OPCODE:
-        return new IntToByte(high, stream);
-      case IntToChar.OPCODE:
-        return new IntToChar(high, stream);
-      case IntToShort.OPCODE:
-        return new IntToShort(high, stream);
-      case AddInt.OPCODE:
-        return new AddInt(high, stream);
-      case SubInt.OPCODE:
-        return new SubInt(high, stream);
-      case MulInt.OPCODE:
-        return new MulInt(high, stream);
-      case DivInt.OPCODE:
-        return new DivInt(high, stream);
-      case RemInt.OPCODE:
-        return new RemInt(high, stream);
-      case AndInt.OPCODE:
-        return new AndInt(high, stream);
-      case OrInt.OPCODE:
-        return new OrInt(high, stream);
-      case XorInt.OPCODE:
-        return new XorInt(high, stream);
-      case ShlInt.OPCODE:
-        return new ShlInt(high, stream);
-      case ShrInt.OPCODE:
-        return new ShrInt(high, stream);
-      case UshrInt.OPCODE:
-        return new UshrInt(high, stream);
-      case AddLong.OPCODE:
-        return new AddLong(high, stream);
-      case SubLong.OPCODE:
-        return new SubLong(high, stream);
-      case MulLong.OPCODE:
-        return new MulLong(high, stream);
-      case DivLong.OPCODE:
-        return new DivLong(high, stream);
-      case RemLong.OPCODE:
-        return new RemLong(high, stream);
-      case AndLong.OPCODE:
-        return new AndLong(high, stream);
-      case OrLong.OPCODE:
-        return new OrLong(high, stream);
-      case XorLong.OPCODE:
-        return new XorLong(high, stream);
-      case ShlLong.OPCODE:
-        return new ShlLong(high, stream);
-      case ShrLong.OPCODE:
-        return new ShrLong(high, stream);
-      case UshrLong.OPCODE:
-        return new UshrLong(high, stream);
-      case AddFloat.OPCODE:
-        return new AddFloat(high, stream);
-      case SubFloat.OPCODE:
-        return new SubFloat(high, stream);
-      case MulFloat.OPCODE:
-        return new MulFloat(high, stream);
-      case DivFloat.OPCODE:
-        return new DivFloat(high, stream);
-      case RemFloat.OPCODE:
-        return new RemFloat(high, stream);
-      case AddDouble.OPCODE:
-        return new AddDouble(high, stream);
-      case SubDouble.OPCODE:
-        return new SubDouble(high, stream);
-      case MulDouble.OPCODE:
-        return new MulDouble(high, stream);
-      case DivDouble.OPCODE:
-        return new DivDouble(high, stream);
-      case RemDouble.OPCODE:
-        return new RemDouble(high, stream);
-      case AddInt2Addr.OPCODE:
-        return new AddInt2Addr(high, stream);
-      case SubInt2Addr.OPCODE:
-        return new SubInt2Addr(high, stream);
-      case MulInt2Addr.OPCODE:
-        return new MulInt2Addr(high, stream);
-      case DivInt2Addr.OPCODE:
-        return new DivInt2Addr(high, stream);
-      case RemInt2Addr.OPCODE:
-        return new RemInt2Addr(high, stream);
-      case AndInt2Addr.OPCODE:
-        return new AndInt2Addr(high, stream);
-      case OrInt2Addr.OPCODE:
-        return new OrInt2Addr(high, stream);
-      case XorInt2Addr.OPCODE:
-        return new XorInt2Addr(high, stream);
-      case ShlInt2Addr.OPCODE:
-        return new ShlInt2Addr(high, stream);
-      case ShrInt2Addr.OPCODE:
-        return new ShrInt2Addr(high, stream);
-      case UshrInt2Addr.OPCODE:
-        return new UshrInt2Addr(high, stream);
-      case AddLong2Addr.OPCODE:
-        return new AddLong2Addr(high, stream);
-      case SubLong2Addr.OPCODE:
-        return new SubLong2Addr(high, stream);
-      case MulLong2Addr.OPCODE:
-        return new MulLong2Addr(high, stream);
-      case DivLong2Addr.OPCODE:
-        return new DivLong2Addr(high, stream);
-      case RemLong2Addr.OPCODE:
-        return new RemLong2Addr(high, stream);
-      case AndLong2Addr.OPCODE:
-        return new AndLong2Addr(high, stream);
-      case OrLong2Addr.OPCODE:
-        return new OrLong2Addr(high, stream);
-      case XorLong2Addr.OPCODE:
-        return new XorLong2Addr(high, stream);
-      case ShlLong2Addr.OPCODE:
-        return new ShlLong2Addr(high, stream);
-      case ShrLong2Addr.OPCODE:
-        return new ShrLong2Addr(high, stream);
-      case UshrLong2Addr.OPCODE:
-        return new UshrLong2Addr(high, stream);
-      case AddFloat2Addr.OPCODE:
-        return new AddFloat2Addr(high, stream);
-      case SubFloat2Addr.OPCODE:
-        return new SubFloat2Addr(high, stream);
-      case MulFloat2Addr.OPCODE:
-        return new MulFloat2Addr(high, stream);
-      case DivFloat2Addr.OPCODE:
-        return new DivFloat2Addr(high, stream);
-      case RemFloat2Addr.OPCODE:
-        return new RemFloat2Addr(high, stream);
-      case AddDouble2Addr.OPCODE:
-        return new AddDouble2Addr(high, stream);
-      case SubDouble2Addr.OPCODE:
-        return new SubDouble2Addr(high, stream);
-      case MulDouble2Addr.OPCODE:
-        return new MulDouble2Addr(high, stream);
-      case DivDouble2Addr.OPCODE:
-        return new DivDouble2Addr(high, stream);
-      case RemDouble2Addr.OPCODE:
-        return new RemDouble2Addr(high, stream);
-      case AddIntLit16.OPCODE:
-        return new AddIntLit16(high, stream);
-      case RsubInt.OPCODE:
-        return new RsubInt(high, stream);
-      case MulIntLit16.OPCODE:
-        return new MulIntLit16(high, stream);
-      case DivIntLit16.OPCODE:
-        return new DivIntLit16(high, stream);
-      case RemIntLit16.OPCODE:
-        return new RemIntLit16(high, stream);
-      case AndIntLit16.OPCODE:
-        return new AndIntLit16(high, stream);
-      case OrIntLit16.OPCODE:
-        return new OrIntLit16(high, stream);
-      case XorIntLit16.OPCODE:
-        return new XorIntLit16(high, stream);
-      case AddIntLit8.OPCODE:
-        return new AddIntLit8(high, stream);
-      case RsubIntLit8.OPCODE:
-        return new RsubIntLit8(high, stream);
-      case MulIntLit8.OPCODE:
-        return new MulIntLit8(high, stream);
-      case DivIntLit8.OPCODE:
-        return new DivIntLit8(high, stream);
-      case RemIntLit8.OPCODE:
-        return new RemIntLit8(high, stream);
-      case AndIntLit8.OPCODE:
-        return new AndIntLit8(high, stream);
-      case OrIntLit8.OPCODE:
-        return new OrIntLit8(high, stream);
-      case XorIntLit8.OPCODE:
-        return new XorIntLit8(high, stream);
-      case ShlIntLit8.OPCODE:
-        return new ShlIntLit8(high, stream);
-      case ShrIntLit8.OPCODE:
-        return new ShrIntLit8(high, stream);
-      case UshrIntLit8.OPCODE:
-        return new UshrIntLit8(high, stream);
-      case InvokePolymorphic.OPCODE:
-        return new InvokePolymorphic(high, stream, mapping);
-      case InvokePolymorphicRange.OPCODE:
-        return new InvokePolymorphicRange(high, stream, mapping);
-      case InvokeCustom.OPCODE:
-        return new InvokeCustom(high, stream, mapping);
-      case InvokeCustomRange.OPCODE:
-        return new InvokeCustomRange(high, stream, mapping);
-      case ConstMethodHandle.OPCODE:
-        return new ConstMethodHandle(high, stream, mapping);
-      case ConstMethodType.OPCODE:
-        return new ConstMethodType(high, stream, mapping);
-      default:
-        throw new IllegalArgumentException("Illegal Opcode: 0x" + Integer.toString(opcode, 16));
-    }
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/debuginfo/DebugRepresentation.java b/src/main/java/com/android/tools/r8/debuginfo/DebugRepresentation.java
index 173ddd1..e9b23e7 100644
--- a/src/main/java/com/android/tools/r8/debuginfo/DebugRepresentation.java
+++ b/src/main/java/com/android/tools/r8/debuginfo/DebugRepresentation.java
@@ -3,17 +3,16 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.debuginfo;
 
-import com.android.tools.r8.code.Instruction;
 import com.android.tools.r8.dex.VirtualFile;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.graph.DexDebugInfo;
 import com.android.tools.r8.graph.DexDebugInfo.PcBasedDebugInfo;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.LebUtils;
 import com.android.tools.r8.utils.LineNumberOptimizer;
@@ -69,8 +68,8 @@
     this.paramToInfo = paramToInfo;
   }
 
-  public static void computeForFile(
-      VirtualFile file, GraphLens graphLens, NamingLens namingLens, InternalOptions options) {
+  public static void computeForFile(AppView<?> appView, VirtualFile file) {
+    InternalOptions options = appView.options();
     if (!options.canUseDexPc2PcAsDebugInformation()
         || options.canUseNativeDexPcInsteadOfDebugInfo()
         || options.testing.forcePcBasedEncoding) {
@@ -81,7 +80,7 @@
     Int2ReferenceMap<CostSummary> paramCountToCosts = new Int2ReferenceOpenHashMap<>();
     for (DexProgramClass clazz : file.classes()) {
       IdentityHashMap<DexString, List<ProgramMethod>> overloads =
-          LineNumberOptimizer.groupMethodsByRenamedName(graphLens, namingLens, clazz);
+          LineNumberOptimizer.groupMethodsByRenamedName(appView, clazz);
       for (List<ProgramMethod> methods : overloads.values()) {
         if (methods.size() != 1) {
           // Never use PC info for overloaded methods. They need distinct lines to disambiguate.
@@ -94,7 +93,7 @@
         }
         DexCode code = definition.getCode().asDexCode();
         DexDebugInfo debugInfo = code.getDebugInfo();
-        Instruction lastInstruction = getLastExecutableInstruction(code);
+        DexInstruction lastInstruction = getLastExecutableInstruction(code);
         if (lastInstruction == null) {
           continue;
         }
@@ -120,7 +119,7 @@
     if (conversionInfo.cutoff < 0) {
       return false;
     }
-    Instruction lastInstruction = getLastExecutableInstruction(code);
+    DexInstruction lastInstruction = getLastExecutableInstruction(code);
     if (lastInstruction == null) {
       return false;
     }
@@ -264,9 +263,9 @@
     }
   }
 
-  private static Instruction getLastExecutableInstruction(DexCode code) {
-    Instruction lastInstruction = null;
-    for (Instruction instruction : code.instructions) {
+  private static DexInstruction getLastExecutableInstruction(DexCode code) {
+    DexInstruction lastInstruction = null;
+    for (DexInstruction instruction : code.instructions) {
       if (!instruction.isPayload()) {
         lastInstruction = instruction;
       }
diff --git a/src/main/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryKeepRuleGenerator.java b/src/main/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryKeepRuleGenerator.java
index eaec5a0..8dc8979 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
@@ -44,13 +44,10 @@
 public class DesugaredLibraryKeepRuleGenerator {
 
   private final AppView<AppInfoWithClassHierarchy> appView;
-  private final NamingLens namingLens;
   private final InternalOptions options;
 
-  public DesugaredLibraryKeepRuleGenerator(
-      AppView<AppInfoWithClassHierarchy> appView, NamingLens namingLens) {
+  public DesugaredLibraryKeepRuleGenerator(AppView<AppInfoWithClassHierarchy> appView) {
     this.appView = appView;
-    this.namingLens = namingLens;
     this.options = appView.options();
   }
 
@@ -68,7 +65,7 @@
         || !options.testing.enableExperimentalDesugaredLibraryKeepRuleGenerator) {
       return false;
     }
-    return namingLens.hasPrefixRewritingLogic()
+    return appView.getNamingLens().hasPrefixRewritingLogic()
         || options.machineDesugaredLibrarySpecification.hasEmulatedInterfaces();
   }
 
@@ -83,6 +80,7 @@
     byte[] synthesizedLibraryClassesPackageDescriptorPrefix =
         DexString.encodeToMutf8(
             "L" + desugaredLibrarySpecification.getSynthesizedLibraryClassesPackagePrefix());
+    NamingLens namingLens = appView.getNamingLens();
     return type ->
         namingLens.prefixRewrittenType(type) != null
             || desugaredLibrarySpecification.isEmulatedInterfaceRewrittenType(type)
@@ -91,7 +89,7 @@
   }
 
   private KeepRuleGenerator createTraceReferencesConsumer() {
-    return new KeepRuleGenerator(appView, namingLens);
+    return new KeepRuleGenerator(appView);
   }
 
   private static class KeepRuleGenerator extends TraceReferencesConsumer.ForwardingConsumer {
@@ -111,14 +109,13 @@
     // ArrayReference to DexType, nor conversions from (formal types, return type) to DexProto.
     private final Map<TypeReference, DexType> typeConversionCache = new ConcurrentHashMap<>();
 
-    private KeepRuleGenerator(
-        AppView<? extends AppInfoWithClassHierarchy> appView, NamingLens namingLens) {
+    private KeepRuleGenerator(AppView<? extends AppInfoWithClassHierarchy> appView) {
       super(
           TraceReferencesKeepRules.builder()
               .setOutputConsumer(appView.options().desugaredLibraryKeepRuleConsumer)
               .build());
       this.factory = appView.dexItemFactory();
-      this.namingLens = namingLens;
+      this.namingLens = appView.getNamingLens();
     }
 
     @Override
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
index cc04d01..d2cff23 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -83,7 +83,6 @@
 public class ApplicationWriter {
 
   public final AppView<?> appView;
-  public final NamingLens namingLens;
   public final InternalOptions options;
   private final CodeToKeep desugaredLibraryCodeToKeep;
   private final Predicate<DexType> isTypeMissing;
@@ -151,38 +150,42 @@
     }
 
     @Override
-    public boolean setAnnotationsDirectoryForClass(DexProgramClass clazz,
-        DexAnnotationDirectory annotationDirectory) {
-      return true;
+    public void setAnnotationsDirectoryForClass(
+        DexProgramClass clazz, DexAnnotationDirectory annotationDirectory) {
+      // Intentionally empty.
+    }
+
+    @Override
+    public void setStaticFieldValuesForClass(
+        DexProgramClass clazz, DexEncodedArray staticFieldValues) {
+      add(staticFieldValues);
     }
   }
 
-  public ApplicationWriter(
-      AppView<?> appView,
-      List<Marker> markers,
-      NamingLens namingLens) {
+  public ApplicationWriter(AppView<?> appView, List<Marker> markers) {
     this(
         appView,
         markers,
-        namingLens,
         null);
   }
 
   public ApplicationWriter(
       AppView<?> appView,
       List<Marker> markers,
-      NamingLens namingLens,
       DexIndexedConsumer consumer) {
     this.appView = appView;
     this.options = appView.options();
-    this.desugaredLibraryCodeToKeep = CodeToKeep.createCodeToKeep(options, namingLens);
+    this.desugaredLibraryCodeToKeep = CodeToKeep.createCodeToKeep(appView);
     this.markers = markers;
-    this.namingLens = namingLens;
     this.programConsumer = consumer;
     this.isTypeMissing =
         PredicateUtils.isNull(appView.appInfo()::definitionForWithoutExistenceAssert);
   }
 
+  private NamingLens getNamingLens() {
+    return appView.getNamingLens();
+  }
+
   private List<VirtualFile> distribute(ExecutorService executorService)
       throws ExecutionException, IOException {
     Collection<DexProgramClass> classes = appView.appInfo().classes();
@@ -242,12 +245,12 @@
     Collection<DexProgramClass> classes = appView.appInfo().classes();
     Reference2LongMap<DexString> inputChecksums = new Reference2LongOpenHashMap<>(classes.size());
     for (DexProgramClass clazz : classes) {
-      inputChecksums.put(namingLens.lookupDescriptor(clazz.getType()), clazz.getChecksum());
+      inputChecksums.put(getNamingLens().lookupDescriptor(clazz.getType()), clazz.getChecksum());
     }
     for (VirtualFile file : files) {
       ClassesChecksum toWrite = new ClassesChecksum();
       for (DexProgramClass clazz : file.classes()) {
-        DexString desc = namingLens.lookupDescriptor(clazz.type);
+        DexString desc = getNamingLens().lookupDescriptor(clazz.type);
         toWrite.addChecksum(desc.toString(), inputChecksums.getLong(desc));
       }
       file.injectString(appView.dexItemFactory().createString(toWrite.toJsonString()));
@@ -307,7 +310,7 @@
 
       // TODO(b/151313617): Sorting annotations mutates elements so run single threaded on main.
       timing.begin("Sort Annotations");
-      SortAnnotations sortAnnotations = new SortAnnotations(namingLens);
+      SortAnnotations sortAnnotations = new SortAnnotations(getNamingLens());
       appView.appInfo().classes().forEach((clazz) -> clazz.addDependencies(sortAnnotations));
       timing.end();
 
@@ -322,8 +325,7 @@
                   Timing fileTiming = Timing.create("VirtualFile " + virtualFile.getId(), options);
                   computeOffsetMappingAndRewriteJumboStrings(
                       virtualFile, lazyDexStrings, fileTiming);
-                  DebugRepresentation.computeForFile(
-                      virtualFile, appView.graphLens(), namingLens, options);
+                  DebugRepresentation.computeForFile(appView, virtualFile);
                   fileTiming.end();
                   return fileTiming;
                 },
@@ -332,15 +334,14 @@
         merger.end();
       }
 
-
-      // Now code offsets are fixed, compute the mapping file content.
+      // Now that the instruction offsets in each code object are fixed, compute the mapping file
+      // content.
       if (willComputeProguardMap()) {
         // TODO(b/220999985): Refactor line number optimization to be per file and thread it above.
         DebugRepresentationPredicate representation =
             DebugRepresentation.fromFiles(virtualFiles, options);
         delayedProguardMapId.set(
-            runAndWriteMap(
-                inputApp, appView, namingLens, timing, originalSourceFiles, representation));
+            runAndWriteMap(inputApp, appView, timing, originalSourceFiles, representation));
       }
 
       // With the mapping id/hash known, it is safe to compute the remaining dex strings.
@@ -368,7 +369,7 @@
         merger.add(timings);
         merger.end();
         if (globalsSyntheticsConsumer != null) {
-          globalsSyntheticsConsumer.finished(appView, namingLens);
+          globalsSyntheticsConsumer.finished(appView);
         }
       }
 
@@ -380,7 +381,7 @@
       // Fail if there are pending errors, e.g., the program consumers may have reported errors.
       options.reporter.failIfPendingErrors();
       // Supply info to all additional resource consumers.
-      supplyAdditionalConsumers(appView.appInfo().app(), appView, namingLens, options);
+      supplyAdditionalConsumers(appView);
     } finally {
       timing.end();
     }
@@ -484,7 +485,7 @@
       return;
     }
     timing.begin("Compute object offset mapping");
-    virtualFile.computeMapping(appView, namingLens, lazyDexStrings.size(), timing);
+    virtualFile.computeMapping(appView, lazyDexStrings.size(), timing);
     timing.end();
     timing.begin("Rewrite jumbo strings");
     rewriteCodeWithJumboStrings(
@@ -528,7 +529,7 @@
     timing.end();
 
     timing.begin("Write bytes");
-    ByteBufferResult result = writeDexFile(objectMapping, byteBufferProvider, timing);
+    ByteBufferResult result = writeDexFile(objectMapping, byteBufferProvider, virtualFile, timing);
     ByteDataView data =
         new ByteDataView(result.buffer.array(), result.buffer.arrayOffset(), result.length);
     timing.end();
@@ -550,11 +551,8 @@
     byteBufferProvider.releaseByteBuffer(result.buffer.asByteBuffer());
   }
 
-  public static void supplyAdditionalConsumers(
-      DexApplication application,
-      AppView<?> appView,
-      NamingLens namingLens,
-      InternalOptions options) {
+  public static void supplyAdditionalConsumers(AppView<?> appView) {
+    InternalOptions options = appView.options();
     if (options.configurationConsumer != null) {
       ExceptionUtils.withConsumeResourceHandler(
           options.reporter, options.configurationConsumer,
@@ -563,22 +561,22 @@
     }
     if (options.mainDexListConsumer != null) {
       ExceptionUtils.withConsumeResourceHandler(
-          options.reporter, options.mainDexListConsumer, writeMainDexList(appView, namingLens));
+          options.reporter, options.mainDexListConsumer, writeMainDexList(appView));
       ExceptionUtils.withFinishedResourceHandler(options.reporter, options.mainDexListConsumer);
     }
 
     DataResourceConsumer dataResourceConsumer = options.dataResourceConsumer;
     if (dataResourceConsumer != null) {
-      ImmutableList<DataResourceProvider> dataResourceProviders = application.dataResourceProviders;
-      ResourceAdapter resourceAdapter =
-          new ResourceAdapter(appView, application.dexItemFactory, namingLens, options);
-
+      ImmutableList<DataResourceProvider> dataResourceProviders =
+          appView.app().dataResourceProviders;
+      ResourceAdapter resourceAdapter = new ResourceAdapter(appView);
       adaptAndPassDataResources(
           options, dataResourceConsumer, dataResourceProviders, resourceAdapter);
 
       // Write the META-INF/services resources. Sort on service names and keep the order from
       // the input for the implementation lines for deterministic output.
       if (!appView.appServices().isEmpty()) {
+        NamingLens namingLens = appView.getNamingLens();
         appView
             .appServices()
             .visit(
@@ -605,8 +603,7 @@
     if (options.featureSplitConfiguration != null) {
       for (DataResourceProvidersAndConsumer entry :
           options.featureSplitConfiguration.getDataResourceProvidersAndConsumers()) {
-        ResourceAdapter resourceAdapter =
-            new ResourceAdapter(appView, application.dexItemFactory, namingLens, options);
+        ResourceAdapter resourceAdapter = new ResourceAdapter(appView);
         adaptAndPassDataResources(
             options, entry.getConsumer(), entry.getProviders(), resourceAdapter);
       }
@@ -704,7 +701,7 @@
           } else {
             annotations.add(
                 DexAnnotation.createInnerClassAnnotation(
-                    namingLens.lookupInnerName(innerClass, options),
+                    getNamingLens().lookupInnerName(innerClass, options),
                     innerClass.getAccess(),
                     options.itemFactory));
             if (innerClass.getOuter() != null && innerClass.isNamed()) {
@@ -726,7 +723,7 @@
     if (clazz.getClassSignature().hasSignature()) {
       annotations.add(
           DexAnnotation.createSignatureAnnotation(
-              clazz.getClassSignature().toRenamedString(namingLens, isTypeMissing),
+              clazz.getClassSignature().toRenamedString(getNamingLens(), isTypeMissing),
               options.itemFactory));
     }
 
@@ -756,7 +753,7 @@
             ArrayUtils.appendSingleElement(
                 field.annotations().annotations,
                 DexAnnotation.createSignatureAnnotation(
-                    field.getGenericSignature().toRenamedString(namingLens, isTypeMissing),
+                    field.getGenericSignature().toRenamedString(getNamingLens(), isTypeMissing),
                     options.itemFactory))));
     field.clearGenericSignature();
   }
@@ -771,7 +768,7 @@
             ArrayUtils.appendSingleElement(
                 method.annotations().annotations,
                 DexAnnotation.createSignatureAnnotation(
-                    method.getGenericSignature().toRenamedString(namingLens, isTypeMissing),
+                    method.getGenericSignature().toRenamedString(getNamingLens(), isTypeMissing),
                     options.itemFactory))));
     method.clearGenericSignature();
   }
@@ -827,15 +824,12 @@
   }
 
   private ByteBufferResult writeDexFile(
-      ObjectToOffsetMapping objectMapping, ByteBufferProvider provider, Timing timing) {
+      ObjectToOffsetMapping objectMapping,
+      ByteBufferProvider provider,
+      VirtualFile virtualFile,
+      Timing timing) {
     FileWriter fileWriter =
-        new FileWriter(
-            provider,
-            objectMapping,
-            appView.appInfo(),
-            options,
-            namingLens,
-            desugaredLibraryCodeToKeep);
+        new FileWriter(appView, provider, objectMapping, desugaredLibraryCodeToKeep, virtualFile);
     // Collect the non-fixed sections.
     timing.time("collect", fileWriter::collect);
     // Generate and write the bytes.
@@ -847,7 +841,7 @@
         .replace('.', '/') + ".class";
   }
 
-  private static String writeMainDexList(AppView<?> appView, NamingLens namingLens) {
+  private static String writeMainDexList(AppView<?> appView) {
     // TODO(b/178231294): Clean up by streaming directly to the consumer.
     MainDexInfo mainDexInfo = appView.appInfo().getMainDexInfo();
     StringBuilder builder = new StringBuilder();
@@ -855,7 +849,7 @@
     mainDexInfo.forEach(list::add);
     list.sort(DexType::compareTo);
     list.forEach(
-        type -> builder.append(mapMainDexListName(type, namingLens)).append('\n'));
+        type -> builder.append(mapMainDexListName(type, appView.getNamingLens())).append('\n'));
     return builder.toString();
   }
 
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 6b77d5b..5a0ec34 100644
--- a/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
+++ b/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.dex;
 
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -24,7 +25,9 @@
 
 public abstract class CodeToKeep {
 
-  static CodeToKeep createCodeToKeep(InternalOptions options, NamingLens namingLens) {
+  static CodeToKeep createCodeToKeep(AppView<?> appView) {
+    InternalOptions options = appView.options();
+    NamingLens namingLens = appView.getNamingLens();
     if ((!namingLens.hasPrefixRewritingLogic()
             && options.machineDesugaredLibrarySpecification.getMaintainType().isEmpty()
             && !options.machineDesugaredLibrarySpecification.hasEmulatedInterfaces())
@@ -32,7 +35,7 @@
         || options.testing.enableExperimentalDesugaredLibraryKeepRuleGenerator) {
       return new NopCodeToKeep();
     }
-    return new DesugaredLibraryCodeToKeep(namingLens, options);
+    return new DesugaredLibraryCodeToKeep(appView);
   }
 
   public abstract void recordMethod(DexMethod method);
@@ -58,17 +61,16 @@
       boolean all = false;
     }
 
-    private final NamingLens namingLens;
+    private final AppView<?> appView;
     private final Map<DexType, KeepStruct> toKeep = new ConcurrentHashMap<>();
-    private final InternalOptions options;
 
-    public DesugaredLibraryCodeToKeep(NamingLens namingLens, InternalOptions options) {
-      this.namingLens = namingLens;
-      this.options = options;
+    public DesugaredLibraryCodeToKeep(AppView<?> appView) {
+      this.appView = appView;
     }
 
     private boolean shouldKeep(DexType givenType) {
-      if (namingLens.prefixRewrittenType(givenType) != null
+      InternalOptions options = appView.options();
+      if (appView.getNamingLens().prefixRewrittenType(givenType) != null
           || options.machineDesugaredLibrarySpecification.isCustomConversionRewrittenType(givenType)
           || options.machineDesugaredLibrarySpecification.isEmulatedInterfaceRewrittenType(
               givenType)
@@ -84,14 +86,14 @@
       DexType type =
           InterfaceDesugaringSyntheticHelper.isCompanionClassType(givenType)
               ? InterfaceDesugaringSyntheticHelper.getInterfaceClassType(
-                  givenType, options.dexItemFactory())
+                  givenType, appView.dexItemFactory())
               : givenType;
       return options.machineDesugaredLibrarySpecification.getMaintainType().contains(type);
     }
 
     @Override
     public void recordMethod(DexMethod method) {
-      DexType baseType = method.holder.toBaseType(options.dexItemFactory());
+      DexType baseType = method.holder.toBaseType(appView.dexItemFactory());
       if (shouldKeep(baseType)) {
         keepClass(baseType);
         if (!method.holder.isArrayType()) {
@@ -110,7 +112,7 @@
 
     @Override
     public void recordField(DexField field) {
-      DexType baseType = field.holder.toBaseType(options.dexItemFactory());
+      DexType baseType = field.holder.toBaseType(appView.dexItemFactory());
       if (shouldKeep(baseType)) {
         keepClass(baseType);
         if (!field.holder.isArrayType()) {
@@ -146,7 +148,7 @@
     }
 
     private void keepClass(DexType type) {
-      DexType baseType = type.lookupBaseType(options.itemFactory);
+      DexType baseType = type.lookupBaseType(appView.dexItemFactory());
       toKeep.putIfAbsent(baseType, new KeepStruct());
     }
 
@@ -156,7 +158,7 @@
     }
 
     private String convertType(DexType type) {
-      DexString rewriteType = namingLens.prefixRewrittenType(type);
+      DexString rewriteType = appView.getNamingLens().prefixRewrittenType(type);
       DexString descriptor = rewriteType != null ? rewriteType : type.descriptor;
       return DescriptorUtils.descriptorToJavaType(descriptor.toString());
     }
@@ -166,13 +168,6 @@
       // TODO(b/134734081): Stream the consumer instead of building the String.
       StringBuilder sb = new StringBuilder();
       String cr = System.lineSeparator();
-      Comparator<DexReference> comparator =
-          new Comparator<DexReference>() {
-            @Override
-            public int compare(DexReference o1, DexReference o2) {
-              return o1.compareTo(o2);
-            }
-          };
       for (DexType type : CollectionUtils.sort(toKeep.keySet(), getComparator())) {
         KeepStruct keepStruct = toKeep.get(type);
         sb.append("-keep class ").append(convertType(type));
@@ -214,12 +209,7 @@
     }
 
     private static <T extends DexReference> Comparator<T> getComparator() {
-      return new Comparator<T>() {
-        @Override
-        public int compare(T o1, T o2) {
-          return o1.compareTo(o2);
-        }
-      };
+      return DexReference::compareTo;
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/dex/CompatByteBuffer.java b/src/main/java/com/android/tools/r8/dex/CompatByteBuffer.java
index 6e32c6e..0d36470 100644
--- a/src/main/java/com/android/tools/r8/dex/CompatByteBuffer.java
+++ b/src/main/java/com/android/tools/r8/dex/CompatByteBuffer.java
@@ -117,6 +117,10 @@
     return asByteBuffer().getShort();
   }
 
+  public short getShort(int offset) {
+    return asByteBuffer().getShort(offset);
+  }
+
   public void put(byte aByte) {
     asByteBuffer().put(aByte);
   }
diff --git a/src/main/java/com/android/tools/r8/dex/DefaultMixedSectionLayoutStrategy.java b/src/main/java/com/android/tools/r8/dex/DefaultMixedSectionLayoutStrategy.java
new file mode 100644
index 0000000..dee0f55
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/dex/DefaultMixedSectionLayoutStrategy.java
@@ -0,0 +1,118 @@
+// 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.dex;
+
+import com.android.tools.r8.dex.FileWriter.MixedSectionOffsets;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexAnnotation;
+import com.android.tools.r8.graph.DexAnnotationDirectory;
+import com.android.tools.r8.graph.DexAnnotationSet;
+import com.android.tools.r8.graph.DexEncodedArray;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexTypeList;
+import com.android.tools.r8.graph.DexWritableCode;
+import com.android.tools.r8.graph.ParameterAnnotationsList;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.naming.MemberNaming.MethodSignature;
+import com.android.tools.r8.naming.MemberNaming.Signature;
+import com.android.tools.r8.utils.collections.ProgramMethodMap;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.List;
+
+public class DefaultMixedSectionLayoutStrategy extends MixedSectionLayoutStrategy {
+
+  final AppView<?> appView;
+  final MixedSectionOffsets mixedSectionOffsets;
+
+  public DefaultMixedSectionLayoutStrategy(
+      AppView<?> appView, MixedSectionOffsets mixedSectionOffsets) {
+    this.appView = appView;
+    this.mixedSectionOffsets = mixedSectionOffsets;
+  }
+
+  @Override
+  public Collection<DexAnnotation> getAnnotationLayout() {
+    return mixedSectionOffsets.getAnnotations();
+  }
+
+  @Override
+  public Collection<DexAnnotationDirectory> getAnnotationDirectoryLayout() {
+    return mixedSectionOffsets.getAnnotationDirectories();
+  }
+
+  @Override
+  public Collection<DexAnnotationSet> getAnnotationSetLayout() {
+    return mixedSectionOffsets.getAnnotationSets();
+  }
+
+  @Override
+  public Collection<ParameterAnnotationsList> getAnnotationSetRefListLayout() {
+    return mixedSectionOffsets.getAnnotationSetRefLists();
+  }
+
+  @Override
+  public Collection<DexProgramClass> getClassDataLayout() {
+    return mixedSectionOffsets.getClassesWithData();
+  }
+
+  @Override
+  public Collection<ProgramMethod> getCodeLayout() {
+    return getCodeLayoutForClasses(mixedSectionOffsets.getClassesWithData());
+  }
+
+  final Collection<ProgramMethod> getCodeLayoutForClasses(Collection<DexProgramClass> classes) {
+    ProgramMethodMap<String> codeToSignatureMap = ProgramMethodMap.create();
+    List<ProgramMethod> codesSorted = new ArrayList<>();
+    for (DexProgramClass clazz : classes) {
+      clazz.forEachProgramMethodMatching(
+          DexEncodedMethod::hasCode,
+          method -> {
+            DexWritableCode code = method.getDefinition().getDexWritableCodeOrNull();
+            assert code != null || method.getDefinition().shouldNotHaveCode();
+            if (code != null) {
+              codesSorted.add(method);
+              codeToSignatureMap.put(
+                  method, getKeyForDexCodeSorting(method, appView.app().getProguardMap()));
+            }
+          });
+    }
+    codesSorted.sort(Comparator.comparing(codeToSignatureMap::get));
+    return codesSorted;
+  }
+
+  private static String getKeyForDexCodeSorting(ProgramMethod method, ClassNameMapper proguardMap) {
+    // TODO(b/173999869): Could this instead compute sorting using dex items?
+    Signature signature;
+    String originalClassName;
+    if (proguardMap != null) {
+      signature = proguardMap.originalSignatureOf(method.getReference());
+      originalClassName = proguardMap.originalNameOf(method.getHolderType());
+    } else {
+      signature = MethodSignature.fromDexMethod(method.getReference());
+      originalClassName = method.getHolderType().toSourceString();
+    }
+    return originalClassName + signature;
+  }
+
+  @Override
+  public Collection<DexEncodedArray> getEncodedArrayLayout() {
+    return mixedSectionOffsets.getEncodedArrays();
+  }
+
+  @Override
+  public Collection<DexString> getStringDataLayout() {
+    return mixedSectionOffsets.getStringData();
+  }
+
+  @Override
+  public Collection<DexTypeList> getTypeListLayout() {
+    return mixedSectionOffsets.getTypeLists();
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/dex/DexParser.java b/src/main/java/com/android/tools/r8/dex/DexParser.java
index 7a3ccf5..8705bb4 100644
--- a/src/main/java/com/android/tools/r8/dex/DexParser.java
+++ b/src/main/java/com/android/tools/r8/dex/DexParser.java
@@ -9,8 +9,8 @@
 import static com.android.tools.r8.utils.EncodedValueUtils.parseUnsigned;
 
 import com.android.tools.r8.ProgramResource.Kind;
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.InstructionFactory;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexInstructionFactory;
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.graph.ApplicationReaderMap;
 import com.android.tools.r8.graph.ClassAccessFlags;
@@ -167,7 +167,7 @@
       dexReader.position(offset);
       dexReader.align(4);
       DexCode code = parseCodeItem();
-      codes.put(offset, code);  // Update the file local offset to code mapping.
+      codes.put(offset, code); // Update the file local offset to code mapping.
       dexReader.position(currentPos);
     }
   }
@@ -297,7 +297,7 @@
           DexMethodHandle value =
               indexedItems.getMethodHandle((int) parseUnsigned(dexReader, size));
           return new DexValue.DexValueMethodHandle(value);
-      }
+        }
       default:
         throw new IndexOutOfBoundsException();
     }
@@ -306,9 +306,10 @@
   private void checkName(DexString name) {
     if (!options.itemFactory.getSkipNameValidationForTesting()
         && !name.isValidSimpleName(options.getMinApiLevel())) {
-      throw new CompilationError("Space characters in SimpleName '"
-        + name.toASCIIString()
-        + "' are not allowed prior to DEX version 040");
+      throw new CompilationError(
+          "Space characters in SimpleName '"
+              + name.toASCIIString()
+              + "' are not allowed prior to DEX version 040");
     }
   }
 
@@ -333,7 +334,6 @@
     return values;
   }
 
-
   private DexEncodedArray parseEncodedArray() {
     return new DexEncodedArray(parseEncodedArrayValues());
   }
@@ -415,10 +415,11 @@
     DexParameterAnnotation[] result = new DexParameterAnnotation[size];
     for (int i = 0; i < size; i++) {
       DexMethod method = indexedItems.getMethod(methodIndices[i]);
-      result[i] = new DexParameterAnnotation(
-          method,
-          annotationSetRefListAt(annotationOffsets[i])
-              .withParameterCount(method.proto.parameters.size()));
+      result[i] =
+          new DexParameterAnnotation(
+              method,
+              annotationSetRefListAt(annotationOffsets[i])
+                  .withParameterCount(method.proto.parameters.size()));
     }
     dexReader.position(saved);
     return result;
@@ -433,11 +434,11 @@
 
   private <S> Object cacheAt(int offset, Supplier<S> function) {
     if (offset == 0) {
-      return null;  // return null for offset zero.
+      return null; // return null for offset zero.
     }
     Object result = offsetMap.get(offset);
     if (result != null) {
-      return result;  // return the cached result.
+      return result; // return the cached result.
     }
     // Cache is empty so parse the structure.
     dexReader.position(offset);
@@ -484,8 +485,7 @@
     }
     DexType dupType = DexAnnotationSet.findDuplicateEntryType(result);
     if (dupType != null) {
-      throw new CompilationError(
-          "Multiple annotations of type `" + dupType.toSourceString() + "`");
+      throw new CompilationError("Multiple annotations of type `" + dupType.toSourceString() + "`");
     }
     return DexAnnotationSet.create(result);
   }
@@ -500,8 +500,8 @@
   }
 
   private AnnotationsDirectory annotationsDirectoryAt(int offset) {
-    return (AnnotationsDirectory) cacheAt(offset, this::parseAnnotationsDirectory,
-        AnnotationsDirectory::empty);
+    return (AnnotationsDirectory)
+        cacheAt(offset, this::parseAnnotationsDirectory, AnnotationsDirectory::empty);
   }
 
   private AnnotationsDirectory parseAnnotationsDirectory() {
@@ -513,10 +513,7 @@
     final DexMethodAnnotation[] methods = parseMethodAnnotations(methodsSize);
     final DexParameterAnnotation[] parameters = parseParameterAnnotations(parametersSize);
     return new AnnotationsDirectory(
-        annotationSetAt(classAnnotationsOff),
-        fields,
-        methods,
-        parameters);
+        annotationSetAt(classAnnotationsOff), fields, methods, parameters);
   }
 
   private DexDebugInfo debugInfoAt(int offset) {
@@ -548,72 +545,82 @@
           events.add(dexItemFactory.createAdvanceLine(dexReader.getSleb128()));
           isPcBasedDebugInfo = false;
           break;
-        case Constants.DBG_START_LOCAL: {
-          int registerNum = dexReader.getUleb128();
-          int nameIdx = dexReader.getUleb128p1();
-          int typeIdx = dexReader.getUleb128p1();
-          events.add(new DexDebugEvent.StartLocal(
-              registerNum,
-              nameIdx == NO_INDEX ? null : indexedItems.getString(nameIdx),
-              typeIdx == NO_INDEX ? null : indexedItems.getType(typeIdx),
-              null));
-          isPcBasedDebugInfo = false;
-          break;
-        }
-        case Constants.DBG_START_LOCAL_EXTENDED: {
-          int registerNum = dexReader.getUleb128();
-          int nameIdx = dexReader.getUleb128p1();
-          int typeIdx = dexReader.getUleb128p1();
-          int sigIdx = dexReader.getUleb128p1();
-          events.add(new DexDebugEvent.StartLocal(
-              registerNum,
-              nameIdx == NO_INDEX ? null : indexedItems.getString(nameIdx),
-              typeIdx == NO_INDEX ? null : indexedItems.getType(typeIdx),
-              sigIdx == NO_INDEX ? null : indexedItems.getString(sigIdx)));
-          isPcBasedDebugInfo = false;
-          break;
-        }
-        case Constants.DBG_END_LOCAL: {
-          events.add(dexItemFactory.createEndLocal(dexReader.getUleb128()));
-          isPcBasedDebugInfo = false;
-          break;
-        }
-        case Constants.DBG_RESTART_LOCAL: {
-          events.add(dexItemFactory.createRestartLocal(dexReader.getUleb128()));
-          isPcBasedDebugInfo = false;
-          break;
-        }
-        case Constants.DBG_SET_PROLOGUE_END: {
-          events.add(dexItemFactory.createSetPrologueEnd());
-          isPcBasedDebugInfo = false;
-          break;
-        }
-        case Constants.DBG_SET_EPILOGUE_BEGIN: {
-          events.add(dexItemFactory.createSetEpilogueBegin());
-          isPcBasedDebugInfo = false;
-          break;
-        }
-        case Constants.DBG_SET_FILE: {
-          int nameIdx = dexReader.getUleb128p1();
-          DexString sourceFile = nameIdx == NO_INDEX ? null : indexedItems.getString(nameIdx);
-          if (options.readDebugSetFileEvent) {
-            events.add(dexItemFactory.createSetFile(sourceFile));
+        case Constants.DBG_START_LOCAL:
+          {
+            int registerNum = dexReader.getUleb128();
+            int nameIdx = dexReader.getUleb128p1();
+            int typeIdx = dexReader.getUleb128p1();
+            events.add(
+                new DexDebugEvent.StartLocal(
+                    registerNum,
+                    nameIdx == NO_INDEX ? null : indexedItems.getString(nameIdx),
+                    typeIdx == NO_INDEX ? null : indexedItems.getType(typeIdx),
+                    null));
+            isPcBasedDebugInfo = false;
+            break;
           }
-          isPcBasedDebugInfo = false;
-          break;
-        }
-        default: {
-          assert head >= 0x0a && head <= 0xff;
-          Default event = dexItemFactory.createDefault(head);
-          events.add(event);
-          if (isPcBasedDebugInfo) {
-            if (events.size() == 1) {
-              isPcBasedDebugInfo = event.equals(dexItemFactory.zeroChangeDefaultEvent);
-            } else {
-              isPcBasedDebugInfo = event.equals(dexItemFactory.oneChangeDefaultEvent);
+        case Constants.DBG_START_LOCAL_EXTENDED:
+          {
+            int registerNum = dexReader.getUleb128();
+            int nameIdx = dexReader.getUleb128p1();
+            int typeIdx = dexReader.getUleb128p1();
+            int sigIdx = dexReader.getUleb128p1();
+            events.add(
+                new DexDebugEvent.StartLocal(
+                    registerNum,
+                    nameIdx == NO_INDEX ? null : indexedItems.getString(nameIdx),
+                    typeIdx == NO_INDEX ? null : indexedItems.getType(typeIdx),
+                    sigIdx == NO_INDEX ? null : indexedItems.getString(sigIdx)));
+            isPcBasedDebugInfo = false;
+            break;
+          }
+        case Constants.DBG_END_LOCAL:
+          {
+            events.add(dexItemFactory.createEndLocal(dexReader.getUleb128()));
+            isPcBasedDebugInfo = false;
+            break;
+          }
+        case Constants.DBG_RESTART_LOCAL:
+          {
+            events.add(dexItemFactory.createRestartLocal(dexReader.getUleb128()));
+            isPcBasedDebugInfo = false;
+            break;
+          }
+        case Constants.DBG_SET_PROLOGUE_END:
+          {
+            events.add(dexItemFactory.createSetPrologueEnd());
+            isPcBasedDebugInfo = false;
+            break;
+          }
+        case Constants.DBG_SET_EPILOGUE_BEGIN:
+          {
+            events.add(dexItemFactory.createSetEpilogueBegin());
+            isPcBasedDebugInfo = false;
+            break;
+          }
+        case Constants.DBG_SET_FILE:
+          {
+            int nameIdx = dexReader.getUleb128p1();
+            DexString sourceFile = nameIdx == NO_INDEX ? null : indexedItems.getString(nameIdx);
+            if (options.readDebugSetFileEvent) {
+              events.add(dexItemFactory.createSetFile(sourceFile));
+            }
+            isPcBasedDebugInfo = false;
+            break;
+          }
+        default:
+          {
+            assert head >= 0x0a && head <= 0xff;
+            Default event = dexItemFactory.createDefault(head);
+            events.add(event);
+            if (isPcBasedDebugInfo) {
+              if (events.size() == 1) {
+                isPcBasedDebugInfo = event.equals(dexItemFactory.zeroChangeDefaultEvent);
+              } else {
+                isPcBasedDebugInfo = event.equals(dexItemFactory.oneChangeDefaultEvent);
+              }
             }
           }
-        }
       }
     }
     return isPcBasedDebugInfo
@@ -650,8 +657,8 @@
     }
   }
 
-  private DexEncodedField[] readFields(int size, DexFieldAnnotation[] annotations,
-      DexValue[] staticValues) {
+  private DexEncodedField[] readFields(
+      int size, DexFieldAnnotation[] annotations, DexValue[] staticValues) {
     DexEncodedField[] fields = new DexEncodedField[size];
     int fieldIndex = 0;
     MemberAnnotationIterator<DexField, DexAnnotationSet> annotationIterator =
@@ -784,8 +791,9 @@
       // Check if constraints from
       // https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.1 are met.
       if (!flags.areValid(Constants.CORRESPONDING_CLASS_FILE_VERSION, false)) {
-        throw new CompilationError("Class " + type.toSourceString()
-            + " has illegal access flags. Found: " + flags, origin);
+        throw new CompilationError(
+            "Class " + type.toSourceString() + " has illegal access flags. Found: " + flags,
+            origin);
       }
       DexEncodedField[] staticFields = DexEncodedField.EMPTY_ARRAY;
       DexEncodedField[] instanceFields = DexEncodedField.EMPTY_ARRAY;
@@ -811,8 +819,11 @@
         int directMethodsSize = dexReader.getUleb128();
         int virtualMethodsSize = dexReader.getUleb128();
 
-        staticFields = readFields(staticFieldsSize, annotationsDirectory.fields,
-            staticValues != null ? staticValues.values : null);
+        staticFields =
+            readFields(
+                staticFieldsSize,
+                annotationsDirectory.fields,
+                staticValues != null ? staticValues.values : null);
         instanceFields = readFields(instanceFieldsSize, annotationsDirectory.fields, null);
         directMethods =
             readMethods(
@@ -857,7 +868,7 @@
               dexItemFactory.getSkipNameValidationForTesting(),
               checksumSupplier,
               null);
-      classCollection.accept(clazz);  // Update the application object.
+      classCollection.accept(clazz); // Update the application object.
     }
   }
 
@@ -913,8 +924,13 @@
       for (int i = 0; i < result.length; i++) {
         DexSection dexSection = result[i];
         int nextOffset = i < result.length - 1 ? result[i + 1].offset : dexSection.offset;
-        Log.debug(this.getClass(), "Read section 0x%04x @ 0x%08x #items %08d size 0x%08x.",
-            dexSection.type, dexSection.offset, dexSection.length, nextOffset - dexSection.offset);
+        Log.debug(
+            this.getClass(),
+            "Read section 0x%04x @ 0x%08x #items %08d size 0x%08x.",
+            dexSection.type,
+            dexSection.offset,
+            dexSection.length,
+            nextOffset - dexSection.offset);
       }
     }
     for (int i = 0; i < mapSize - 1; i++) {
@@ -940,7 +956,7 @@
         code[i] = dexReader.getShort();
       }
       if (insnsSize % 2 != 0) {
-        dexReader.getUshort();  // Skip padding ushort
+        dexReader.getUshort(); // Skip padding ushort
       }
       if (triesSize > 0) {
         Int2IntArrayMap handlerMap = new Int2IntArrayMap();
@@ -987,20 +1003,20 @@
     int saved = dexReader.position();
     DexDebugInfo debugInfo = debugInfoAt(debugInfoOff);
     dexReader.position(saved);
-    InstructionFactory factory = new InstructionFactory();
-    Instruction[] instructions =
+    DexInstructionFactory factory = new DexInstructionFactory();
+    DexInstruction[] instructions =
         factory.readSequenceFrom(ShortBuffer.wrap(code), 0, code.length, indexedItems);
     return new DexCode(registerSize, insSize, outsSize, instructions, tries, handlers, debugInfo);
   }
 
   void populateIndexTables() {
     // Populate structures that are already sorted upon read.
-    populateStrings();  // Depends on nothing.
+    populateStrings(); // Depends on nothing.
     populateChecksums(); // Depends on Strings.
-    populateTypes();  // Depends on Strings.
-    populateFields();  // Depends on Types, and Strings.
-    populateProtos();  // Depends on Types and Strings.
-    populateMethods();  // Depends on Protos, Types, and Strings.
+    populateTypes(); // Depends on Strings.
+    populateFields(); // Depends on Types, and Strings.
+    populateProtos(); // Depends on Types and Strings.
+    populateMethods(); // Depends on Protos, Types, and Strings.
     populateMethodHandles(); // Depends on Methods and Fields
     populateCallSites(); // Depends on MethodHandles
   }
@@ -1176,9 +1192,8 @@
    * From https://source.android.com/devices/tech/dalvik/dex-format#file-layout:
    *
    * <p>This list must be sorted, where the defining type (by type_id index) is the major order,
-   * method name (by string_id index) is the intermediate order, and method prototype
-   * (by proto_id index) is the minor order. The list must not contain any duplicate entries.
-   *
+   * method name (by string_id index) is the intermediate order, and method prototype (by proto_id
+   * index) is the minor order. The list must not contain any duplicate entries.
    */
   private boolean verifyOrderOfMethodIds(DexSection dexSection) {
     if (dexSection.length >= 2) {
@@ -1288,18 +1303,20 @@
       case INSTANCE_GET:
       case INSTANCE_PUT:
       case STATIC_GET:
-      case STATIC_PUT: {
-        fieldOrMethod = indexedItems.getField(indexFieldOrMethod);
-        break;
-      }
+      case STATIC_PUT:
+        {
+          fieldOrMethod = indexedItems.getField(indexFieldOrMethod);
+          break;
+        }
       case INVOKE_CONSTRUCTOR:
       case INVOKE_DIRECT:
       case INVOKE_INTERFACE:
       case INVOKE_INSTANCE:
-      case INVOKE_STATIC: {
-        fieldOrMethod = indexedItems.getMethod(indexFieldOrMethod);
-        break;
-      }
+      case INVOKE_STATIC:
+        {
+          fieldOrMethod = indexedItems.getMethod(indexFieldOrMethod);
+          break;
+        }
       default:
         throw new AssertionError("Method handle type unsupported in a dex file.");
     }
@@ -1367,15 +1384,15 @@
     private static final DexParameterAnnotation[] NO_PARAMETER_ANNOTATIONS =
         new DexParameterAnnotation[0];
 
-    private static final DexFieldAnnotation[] NO_FIELD_ANNOTATIONS =
-        new DexFieldAnnotation[0];
+    private static final DexFieldAnnotation[] NO_FIELD_ANNOTATIONS = new DexFieldAnnotation[0];
 
-    private static final DexMethodAnnotation[] NO_METHOD_ANNOTATIONS =
-        new DexMethodAnnotation[0];
+    private static final DexMethodAnnotation[] NO_METHOD_ANNOTATIONS = new DexMethodAnnotation[0];
 
     private static final AnnotationsDirectory THE_EMPTY_ANNOTATIONS_DIRECTORY =
-        new AnnotationsDirectory(DexAnnotationSet.empty(),
-            NO_FIELD_ANNOTATIONS, new DexMethodAnnotation[0],
+        new AnnotationsDirectory(
+            DexAnnotationSet.empty(),
+            NO_FIELD_ANNOTATIONS,
+            new DexMethodAnnotation[0],
             NO_PARAMETER_ANNOTATIONS);
 
     public final DexAnnotationSet clazz;
@@ -1383,7 +1400,8 @@
     public final DexMethodAnnotation[] methods;
     public final DexParameterAnnotation[] parameters;
 
-    AnnotationsDirectory(DexAnnotationSet clazz,
+    AnnotationsDirectory(
+        DexAnnotationSet clazz,
         DexFieldAnnotation[] fields,
         DexMethodAnnotation[] methods,
         DexParameterAnnotation[] parameters) {
diff --git a/src/main/java/com/android/tools/r8/dex/FileWriter.java b/src/main/java/com/android/tools/r8/dex/FileWriter.java
index ebf21c6..2c9ca25 100644
--- a/src/main/java/com/android/tools/r8/dex/FileWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/FileWriter.java
@@ -11,14 +11,12 @@
 import com.android.tools.r8.errors.InvokeCustomDiagnostic;
 import com.android.tools.r8.errors.PrivateInterfaceMethodDiagnostic;
 import com.android.tools.r8.errors.StaticInterfaceMethodDiagnostic;
-import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexAnnotation;
 import com.android.tools.r8.graph.DexAnnotationDirectory;
 import com.android.tools.r8.graph.DexAnnotationElement;
 import com.android.tools.r8.graph.DexAnnotationSet;
-import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexCallSite;
-import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexCode.Try;
 import com.android.tools.r8.graph.DexCode.TryHandler;
 import com.android.tools.r8.graph.DexCode.TryHandler.TypeAddrPair;
@@ -46,12 +44,8 @@
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ParameterAnnotationsList;
 import com.android.tools.r8.graph.ProgramClassVisitor;
-import com.android.tools.r8.graph.ProgramDexCode;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.logging.Log;
-import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.naming.MemberNaming.MethodSignature;
-import com.android.tools.r8.naming.MemberNaming.Signature;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.position.MethodPosition;
 import com.android.tools.r8.synthesis.SyntheticNaming;
@@ -70,8 +64,6 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.IdentityHashMap;
 import java.util.List;
@@ -96,31 +88,33 @@
     }
   }
 
-  private final ObjectToOffsetMapping mapping;
-  private final DexApplication application;
-  private final InternalOptions options;
+  private final AppView<?> appView;
   private final GraphLens graphLens;
-  private final NamingLens namingLens;
+  private final ObjectToOffsetMapping mapping;
+  private final InternalOptions options;
   private final DexOutputBuffer dest;
   private final MixedSectionOffsets mixedSectionOffsets;
   private final CodeToKeep desugaredLibraryCodeToKeep;
-  private final Map<DexProgramClass, DexEncodedArray> staticFieldValues = new IdentityHashMap<>();
+  private final VirtualFile virtualFile;
 
   public FileWriter(
+      AppView<?> appView,
       ByteBufferProvider provider,
       ObjectToOffsetMapping mapping,
-      AppInfo appInfo,
-      InternalOptions options,
-      NamingLens namingLens,
-      CodeToKeep desugaredLibraryCodeToKeep) {
+      CodeToKeep desugaredLibraryCodeToKeep,
+      VirtualFile virtualFile) {
+    this.appView = appView;
+    this.graphLens = appView.graphLens();
     this.mapping = mapping;
-    this.application = appInfo.app();
-    this.options = options;
-    this.graphLens = mapping.getGraphLens();
-    this.namingLens = namingLens;
+    this.options = appView.options();
     this.dest = new DexOutputBuffer(provider);
     this.mixedSectionOffsets = new MixedSectionOffsets(options);
     this.desugaredLibraryCodeToKeep = desugaredLibraryCodeToKeep;
+    this.virtualFile = virtualFile;
+  }
+
+  private NamingLens getNamingLens() {
+    return appView.getNamingLens();
   }
 
   public static void writeEncodedAnnotation(
@@ -140,20 +134,19 @@
 
   public FileWriter collect() {
     // Use the class array from the mapping, as it has a deterministic iteration order.
-    new ProgramClassDependencyCollector(application, mapping.getClasses())
-        .run(mapping.getClasses());
+    new ProgramClassDependencyCollector(appView, mapping.getClasses()).run(mapping.getClasses());
 
     // Add the static values for all fields now that we have committed to their sorting.
     mixedSectionOffsets.getClassesWithData().forEach(this::addStaticFieldValues);
 
-    // String data is not tracked by the MixedSectionCollection.new AppInfo(application, null)
+    // String data is not tracked by the MixedSectionCollection.
     assert mixedSectionOffsets.stringData.size() == 0;
     for (DexString string : mapping.getStrings()) {
       mixedSectionOffsets.add(string);
     }
     // Neither are the typelists in protos...
     for (DexProto proto : mapping.getProtos()) {
-      mixedSectionOffsets.add(proto.parameters);
+      mixedSectionOffsets.add(proto.getParameters());
     }
 
     DexItem.collectAll(mixedSectionOffsets, mapping.getCallSites());
@@ -174,7 +167,9 @@
     layout.setCodesOffset(layout.dataSectionOffset);
 
     // Sort the codes first, as their order might impact size due to alignment constraints.
-    List<ProgramDexCode> codes = sortDexCodesByClassName();
+    MixedSectionLayoutStrategy mixedSectionLayoutStrategy =
+        MixedSectionLayoutStrategy.create(appView, mixedSectionOffsets, virtualFile);
+    Collection<ProgramMethod> codes = mixedSectionLayoutStrategy.getCodeLayout();
 
     // Output the debug_info_items first, as they have no dependencies.
     dest.moveTo(layout.getCodesOffset() + sizeOfCodeItems(codes));
@@ -184,10 +179,11 @@
       // Ensure deterministic ordering of debug info by sorting consistent with the code objects.
       layout.setDebugInfosOffset(dest.align(1));
       Set<DexDebugInfoForWriting> seen = new HashSet<>(mixedSectionOffsets.getDebugInfos().size());
-      for (ProgramDexCode code : codes) {
-        DexDebugInfoForWriting info = code.getCode().getDebugInfoForWriting();
+      for (ProgramMethod method : codes) {
+        DexDebugInfoForWriting info =
+            method.getDefinition().getCode().asDexWritableCode().getDebugInfoForWriting();
         if (info != null && seen.add(info)) {
-          writeDebugItem(info, graphLens);
+          writeDebugItem(info);
         }
       }
     }
@@ -203,21 +199,41 @@
 
     // Now the type lists and rest.
     dest.moveTo(layout.getTypeListsOffset());
-    writeItems(mixedSectionOffsets.getTypeLists(), layout::alreadySetOffset, this::writeTypeList);
-    writeItems(mixedSectionOffsets.getStringData(), layout::setStringDataOffsets,
+    writeItems(
+        mixedSectionLayoutStrategy.getTypeListLayout(),
+        layout::alreadySetOffset,
+        this::writeTypeList);
+    writeItems(
+        mixedSectionLayoutStrategy.getStringDataLayout(),
+        layout::setStringDataOffsets,
         this::writeStringData);
-    writeItems(mixedSectionOffsets.getAnnotations(), layout::setAnnotationsOffset,
+    writeItems(
+        mixedSectionLayoutStrategy.getAnnotationLayout(),
+        layout::setAnnotationsOffset,
         this::writeAnnotation);
-    writeItems(mixedSectionOffsets.getClassesWithData(), layout::setClassDataOffset,
+    writeItems(
+        mixedSectionLayoutStrategy.getClassDataLayout(),
+        layout::setClassDataOffset,
         this::writeClassData);
-    writeItems(mixedSectionOffsets.getEncodedArrays(), layout::setEncodedArrarysOffset,
+    writeItems(
+        mixedSectionLayoutStrategy.getEncodedArrayLayout(),
+        layout::setEncodedArraysOffset,
         this::writeEncodedArray);
-    writeItems(mixedSectionOffsets.getAnnotationSets(), layout::setAnnotationSetsOffset,
-        this::writeAnnotationSet, 4);
-    writeItems(mixedSectionOffsets.getAnnotationSetRefLists(),
-        layout::setAnnotationSetRefListsOffset, this::writeAnnotationSetRefList, 4);
-    writeItems(mixedSectionOffsets.getAnnotationDirectories(),
-        layout::setAnnotationDirectoriesOffset, this::writeAnnotationDirectory, 4);
+    writeItems(
+        mixedSectionLayoutStrategy.getAnnotationSetLayout(),
+        layout::setAnnotationSetsOffset,
+        this::writeAnnotationSet,
+        4);
+    writeItems(
+        mixedSectionLayoutStrategy.getAnnotationSetRefListLayout(),
+        layout::setAnnotationSetRefListsOffset,
+        this::writeAnnotationSetRefList,
+        4);
+    writeItems(
+        mixedSectionLayoutStrategy.getAnnotationDirectoryLayout(),
+        layout::setAnnotationDirectoriesOffset,
+        this::writeAnnotationDirectory,
+        4);
 
     // Add the map at the end
     layout.setMapOffset(dest.align(4));
@@ -265,7 +281,7 @@
   //     static methods, as well as public non-abstract (default)
   //     and private instance methods.
   private void checkInterfaceMethod(DexEncodedMethod method) {
-    if (application.dexItemFactory.isClassConstructor(method.getReference())) {
+    if (appView.dexItemFactory().isClassConstructor(method.getReference())) {
       return; // Class constructor is always OK.
     }
     if (method.accessFlags.isStatic()) {
@@ -304,7 +320,7 @@
   }
 
   private boolean verifyNames() {
-    if (options.itemFactory.getSkipNameValidationForTesting()) {
+    if (appView.dexItemFactory().getSkipNameValidationForTesting()) {
       return true;
     }
 
@@ -325,40 +341,6 @@
     return true;
   }
 
-  private List<ProgramDexCode> sortDexCodesByClassName() {
-    Map<ProgramDexCode, String> codeToSignatureMap = new IdentityHashMap<>();
-    List<ProgramDexCode> codesSorted = new ArrayList<>();
-    for (DexProgramClass clazz : mapping.getClasses()) {
-      clazz.forEachProgramMethod(
-          method -> {
-            DexWritableCode code = method.getDefinition().getDexWritableCodeOrNull();
-            assert code != null || method.getDefinition().shouldNotHaveCode();
-            if (code != null) {
-              ProgramDexCode programCode = new ProgramDexCode(code, method);
-              codesSorted.add(programCode);
-              codeToSignatureMap.put(
-                  programCode, getKeyForDexCodeSorting(method, application.getProguardMap()));
-            }
-          });
-    }
-    codesSorted.sort(Comparator.comparing(codeToSignatureMap::get));
-    return codesSorted;
-  }
-
-  private static String getKeyForDexCodeSorting(ProgramMethod method, ClassNameMapper proguardMap) {
-    // TODO(b/173999869): Could this instead compute sorting using dex items?
-    Signature signature;
-    String originalClassName;
-    if (proguardMap != null) {
-      signature = proguardMap.originalSignatureOf(method.getReference());
-      originalClassName = proguardMap.originalNameOf(method.getHolderType());
-    } else {
-      signature = MethodSignature.fromDexMethod(method.getReference());
-      originalClassName = method.getHolderType().toSourceString();
-    }
-    return originalClassName + signature;
-  }
-
   private <T extends IndexedDexItem> void writeFixedSectionItems(
       Collection<T> items, int offset, Consumer<T> writer) {
     assert dest.position() == offset;
@@ -390,11 +372,11 @@
     }
   }
 
-  private int sizeOfCodeItems(Iterable<ProgramDexCode> codes) {
+  private int sizeOfCodeItems(Iterable<ProgramMethod> methods) {
     int size = 0;
-    for (ProgramDexCode code : codes) {
+    for (ProgramMethod method : methods) {
       size = alignSize(4, size);
-      size += sizeOfCodeItem(code.getCode());
+      size += sizeOfCodeItem(method.getDefinition().getCode().asDexWritableCode());
     }
     return size;
   }
@@ -431,7 +413,7 @@
   }
 
   private void writeTypeItem(DexType type) {
-    DexString descriptor = namingLens.lookupDescriptor(type);
+    DexString descriptor = getNamingLens().lookupDescriptor(type);
     dest.putInt(mapping.getOffsetFor(descriptor));
   }
 
@@ -448,7 +430,7 @@
     int typeIdx = mapping.getOffsetFor(field.type);
     assert (typeIdx & 0xFFFF) == typeIdx;
     dest.putShort((short) typeIdx);
-    DexString name = namingLens.lookupName(field);
+    DexString name = getNamingLens().lookupName(field);
     dest.putInt(mapping.getOffsetFor(name));
   }
 
@@ -459,13 +441,12 @@
     int protoIdx = mapping.getOffsetFor(method.proto);
     assert (protoIdx & 0xFFFF) == protoIdx;
     dest.putShort((short) protoIdx);
-    DexString name = namingLens.lookupName(method);
+    DexString name = getNamingLens().lookupName(method);
     dest.putInt(mapping.getOffsetFor(name));
   }
 
   private void writeClassDefItem(DexProgramClass clazz) {
     desugaredLibraryCodeToKeep.recordHierarchyOf(clazz);
-
     dest.putInt(mapping.getOffsetFor(clazz.type));
     dest.putInt(clazz.accessFlags.getAsDexAccessFlags());
     dest.putInt(
@@ -476,19 +457,20 @@
     dest.putInt(mixedSectionOffsets.getOffsetForAnnotationsDirectory(clazz));
     dest.putInt(
         clazz.hasMethodsOrFields() ? mixedSectionOffsets.getOffsetFor(clazz) : Constants.NO_OFFSET);
-    dest.putInt(mixedSectionOffsets.getOffsetFor(staticFieldValues.get(clazz)));
+    dest.putInt(
+        mixedSectionOffsets.getOffsetFor(mixedSectionOffsets.getStaticFieldValuesForClass(clazz)));
   }
 
-  private void writeDebugItem(DexDebugInfoForWriting debugInfo, GraphLens graphLens) {
+  private void writeDebugItem(DexDebugInfoForWriting debugInfo) {
     mixedSectionOffsets.setOffsetFor(debugInfo, dest.position());
     dest.putBytes(new DebugBytecodeWriter(debugInfo, mapping, graphLens).generate());
   }
 
-  private void writeCodeItem(ProgramDexCode code) {
-    writeCodeItem(code.getCode(), code.getMethod());
+  private void writeCodeItem(ProgramMethod method) {
+    writeCodeItem(method, method.getDefinition().getCode().asDexWritableCode());
   }
 
-  private void writeCodeItem(DexWritableCode code, ProgramMethod method) {
+  private void writeCodeItem(ProgramMethod method, DexWritableCode code) {
     mixedSectionOffsets.setOffsetFor(method.getDefinition(), code, dest.align(4));
     // Fixed size header information.
     dest.putShort((short) code.getRegisterSize(method));
@@ -630,7 +612,7 @@
             a.getReference().acceptCompareTo(b.getReference(), mapping.getCompareToVisitor()));
     int currentOffset = 0;
     for (DexEncodedField field : fields) {
-      assert field.validateDexValue(application.dexItemFactory);
+      assert field.validateDexValue(appView.dexItemFactory());
       int nextOffset = mapping.getOffsetFor(field.getReference());
       assert nextOffset - currentOffset >= 0;
       dest.putUleb128(nextOffset - currentOffset);
@@ -683,10 +665,9 @@
     // We have collected the individual components of this array due to the data stored in
     // DexEncodedField#staticValues. However, we have to collect the DexEncodedArray itself
     // here.
-    DexEncodedArray staticValues = clazz.computeStaticValuesArray(namingLens);
+    DexEncodedArray staticValues = clazz.computeStaticValuesArray(getNamingLens());
     if (staticValues != null) {
-      staticFieldValues.put(clazz, staticValues);
-      mixedSectionOffsets.add(staticValues);
+      mixedSectionOffsets.setStaticFieldValuesForClass(clazz, staticValues);
     }
   }
 
@@ -780,8 +761,11 @@
         mixedSectionOffsets.getAnnotations().size());
     size += writeMapItem(Constants.TYPE_CLASS_DATA_ITEM, layout.getClassDataOffset(),
         mixedSectionOffsets.getClassesWithData().size());
-    size += writeMapItem(Constants.TYPE_ENCODED_ARRAY_ITEM, layout.getEncodedArrarysOffset(),
-        mixedSectionOffsets.getEncodedArrays().size());
+    size +=
+        writeMapItem(
+            Constants.TYPE_ENCODED_ARRAY_ITEM,
+            layout.getEncodedArraysOffset(),
+            mixedSectionOffsets.getEncodedArrays().size());
     size += writeMapItem(Constants.TYPE_ANNOTATION_SET_ITEM, layout.getAnnotationSetsOffset(),
         mixedSectionOffsets.getAnnotationSets().size());
     size += writeMapItem(Constants.TYPE_ANNOTATION_SET_REF_LIST,
@@ -885,12 +869,19 @@
     private int annotationSetRefListsOffset = NOT_SET; // aligned
     private int annotationDirectoriesOffset = NOT_SET; // aligned
     private int classDataOffset = NOT_SET;
-    private int encodedArrarysOffset = NOT_SET;
+    private int encodedArraysOffset = NOT_SET;
     private int mapOffset = NOT_SET;
     private int endOfFile = NOT_SET;
 
-    private Layout(int stringIdsOffset, int typeIdsOffset, int protoIdsOffset, int fieldIdsOffset,
-        int methodIdsOffset, int classDefsOffset, int callSiteIdsOffset, int methodHandleIdsOffset,
+    private Layout(
+        int stringIdsOffset,
+        int typeIdsOffset,
+        int protoIdsOffset,
+        int fieldIdsOffset,
+        int methodIdsOffset,
+        int classDefsOffset,
+        int callSiteIdsOffset,
+        int methodHandleIdsOffset,
         int dataSectionOffset) {
       this.stringIdsOffset = stringIdsOffset;
       this.typeIdsOffset = typeIdsOffset;
@@ -1029,14 +1020,14 @@
       this.classDataOffset = classDataOffset;
     }
 
-    public int getEncodedArrarysOffset() {
-      assert isValidOffset(encodedArrarysOffset, false);
-      return encodedArrarysOffset;
+    public int getEncodedArraysOffset() {
+      assert isValidOffset(encodedArraysOffset, false);
+      return encodedArraysOffset;
     }
 
-    public void setEncodedArrarysOffset(int encodedArrarysOffset) {
-      assert this.encodedArrarysOffset == NOT_SET;
-      this.encodedArrarysOffset = encodedArrarysOffset;
+    public void setEncodedArraysOffset(int encodedArraysOffset) {
+      assert this.encodedArraysOffset == NOT_SET;
+      this.encodedArraysOffset = encodedArraysOffset;
     }
 
     public int getMapOffset() {
@@ -1063,7 +1054,7 @@
    * These offsets are then used to resolve cross-references between items from different sections
    * into a file offset.
    */
-  private static class MixedSectionOffsets extends MixedSectionCollection {
+  static class MixedSectionOffsets extends MixedSectionCollection {
 
     private static final int NOT_SET = -1;
     private static final int NOT_KNOWN = -2;
@@ -1078,12 +1069,14 @@
         = createObject2IntMap();
     private final Object2IntMap<DexAnnotationDirectory> annotationDirectories
         = createObject2IntMap();
-    private final Object2IntMap<DexProgramClass> classesWithData = createObject2IntMap();
+    private final Reference2IntMap<DexProgramClass> classesWithData = createReference2IntMap();
     private final Object2IntMap<DexEncodedArray> encodedArrays = createObject2IntMap();
-    private final Map<DexProgramClass, DexAnnotationDirectory> clazzToAnnotationDirectory
-        = new HashMap<>();
+    private final Map<DexProgramClass, DexAnnotationDirectory> classToAnnotationDirectory =
+        new IdentityHashMap<>();
+    private final Map<DexProgramClass, DexEncodedArray> classToStaticFieldValues =
+        new IdentityHashMap<>();
 
-    private final AndroidApiLevel minApiLevel;
+    private final InternalOptions options;
 
     private static <T> Object2IntMap<T> createObject2IntMap() {
       Object2IntMap<T> result = new Object2IntLinkedOpenHashMap<>();
@@ -1098,7 +1091,7 @@
     }
 
     private MixedSectionOffsets(InternalOptions options) {
-      this.minApiLevel = options.getMinApiLevel();
+      this.options = options;
     }
 
     private <T> boolean add(Object2IntMap<T> map, T item) {
@@ -1129,9 +1122,7 @@
 
     @Override
     public boolean add(DexAnnotationSet annotationSet) {
-      // Until we fully drop support for API levels < 17, we have to emit an empty annotation set to
-      // work around a DALVIK bug. See b/36951668.
-      if ((minApiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.J_MR1)) && annotationSet.isEmpty()) {
+      if (!options.canHaveDalvikEmptyAnnotationSetBug() && annotationSet.isEmpty()) {
         return false;
       }
       return add(annotationSets, annotationSet);
@@ -1174,11 +1165,19 @@
     }
 
     @Override
-    public boolean setAnnotationsDirectoryForClass(DexProgramClass clazz,
-        DexAnnotationDirectory annotationDirectory) {
-      DexAnnotationDirectory previous = clazzToAnnotationDirectory.put(clazz, annotationDirectory);
+    public void setAnnotationsDirectoryForClass(
+        DexProgramClass clazz, DexAnnotationDirectory annotationDirectory) {
+      DexAnnotationDirectory previous = classToAnnotationDirectory.put(clazz, annotationDirectory);
       assert previous == null;
-      return add(annotationDirectories, annotationDirectory);
+      add(annotationDirectories, annotationDirectory);
+    }
+
+    @Override
+    public void setStaticFieldValuesForClass(
+        DexProgramClass clazz, DexEncodedArray staticFieldValues) {
+      DexEncodedArray previous = classToStaticFieldValues.put(clazz, staticFieldValues);
+      assert previous == null;
+      add(staticFieldValues);
     }
 
     public boolean add(DexString string) {
@@ -1266,12 +1265,11 @@
       return lookup(debugInfo, debugInfos);
     }
 
-
     public int getOffsetForAnnotationsDirectory(DexProgramClass clazz) {
       if (!clazz.hasClassOrMemberAnnotations()) {
         return Constants.NO_OFFSET;
       }
-      int offset = annotationDirectories.getInt(clazzToAnnotationDirectory.get(clazz));
+      int offset = annotationDirectories.getInt(getAnnotationDirectoryForClass(clazz));
       assert offset != NOT_KNOWN;
       return offset;
     }
@@ -1281,9 +1279,7 @@
     }
 
     public int getOffsetFor(DexAnnotationSet annotationSet) {
-      // Until we fully drop support for API levels < 17, we have to emit an empty annotation set to
-      // work around a DALVIK bug. See b/36951668.
-      if ((minApiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.J_MR1)) && annotationSet.isEmpty()) {
+      if (!options.canHaveDalvikEmptyAnnotationSetBug() && annotationSet.isEmpty()) {
         return 0;
       }
       return lookup(annotationSet, annotationSets);
@@ -1332,9 +1328,7 @@
     }
 
     void setOffsetFor(DexAnnotationSet annotationSet, int offset) {
-      // Until we fully drop support for API levels < 17, we have to emit an empty annotation set to
-      // work around a DALVIK bug. See b/36951668.
-      assert (minApiLevel.isLessThan(AndroidApiLevel.J_MR1)) || !annotationSet.isEmpty();
+      assert options.canHaveDalvikEmptyAnnotationSetBug() || !annotationSet.isEmpty();
       setOffsetFor(annotationSet, offset, annotationSets);
     }
 
@@ -1354,29 +1348,31 @@
       assert offset != 0 && !annotationSetRefList.isEmpty();
       setOffsetFor(annotationSetRefList, offset, annotationSetRefLists);
     }
+
+    DexAnnotationDirectory getAnnotationDirectoryForClass(DexProgramClass clazz) {
+      return classToAnnotationDirectory.get(clazz);
+    }
+
+    DexEncodedArray getStaticFieldValuesForClass(DexProgramClass clazz) {
+      return classToStaticFieldValues.get(clazz);
+    }
   }
 
   private class ProgramClassDependencyCollector extends ProgramClassVisitor {
 
-    private final Set<DexClass> includedClasses = Sets.newIdentityHashSet();
+    private final Set<DexProgramClass> includedClasses = Sets.newIdentityHashSet();
 
-    ProgramClassDependencyCollector(DexApplication application, DexProgramClass[] includedClasses) {
-      super(application);
+    ProgramClassDependencyCollector(AppView<?> appView, DexProgramClass[] includedClasses) {
+      super(appView);
       Collections.addAll(this.includedClasses, includedClasses);
     }
 
     @Override
-    public void visit(DexType type) {
-      // Intentionally left empty.
-    }
-
-    @Override
-    public void visit(DexClass clazz) {
+    public void visit(DexProgramClass clazz) {
       // Only visit classes that are part of the current file.
-      if (!includedClasses.contains(clazz)) {
-        return;
+      if (includedClasses.contains(clazz)) {
+        clazz.addDependencies(mixedSectionOffsets);
       }
-      clazz.addDependencies(mixedSectionOffsets);
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/dex/IndexedItemCollection.java b/src/main/java/com/android/tools/r8/dex/IndexedItemCollection.java
index 1de1144..393439d 100644
--- a/src/main/java/com/android/tools/r8/dex/IndexedItemCollection.java
+++ b/src/main/java/com/android/tools/r8/dex/IndexedItemCollection.java
@@ -12,9 +12,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.graph.GraphLens;
 import com.android.tools.r8.graph.IndexedDexItem;
-import com.android.tools.r8.graph.InitClassLens;
 
 /**
  * Common interface for constant pools.
@@ -100,24 +98,4 @@
    * @return true if the method handle was not in the pool before.
    */
   boolean addMethodHandle(DexMethodHandle methodHandle);
-
-  default GraphLens getGraphLens() {
-    return GraphLens.getIdentityLens();
-  }
-
-  default InitClassLens getInitClassLens() {
-    return InitClassLens.getThrowingInstance();
-  }
-
-  default DexString getRenamedName(DexMethod method) {
-    return method.name;
-  }
-
-  default DexString getRenamedName(DexField field) {
-    return field.name;
-  }
-
-  default DexString getRenamedDescriptor(DexType type) {
-    return type.descriptor;
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/dex/InheritanceClassInDexDistributor.java b/src/main/java/com/android/tools/r8/dex/InheritanceClassInDexDistributor.java
index 9978311..c78eaac 100644
--- a/src/main/java/com/android/tools/r8/dex/InheritanceClassInDexDistributor.java
+++ b/src/main/java/com/android/tools/r8/dex/InheritanceClassInDexDistributor.java
@@ -10,7 +10,6 @@
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.utils.IntBox;
 import com.android.tools.r8.utils.ThreadUtils;
 import com.google.common.collect.Maps;
@@ -70,7 +69,7 @@
 
     public void updateNumbersOfIds() {
       // Use a temporary VirtualFile to evaluate the number of ids in the group.
-      VirtualFile virtualFile = new VirtualFile(0, appView, namingLens);
+      VirtualFile virtualFile = new VirtualFile(0, appView);
       // Note: sort not needed.
       for (DexProgramClass clazz : members) {
         virtualFile.addClass(clazz);
@@ -286,7 +285,6 @@
   private final Set<DexProgramClass> classes;
   private final AppView<?> appView;
   private final IntBox nextFileId;
-  private final NamingLens namingLens;
   private final DirectSubClassesInfo directSubClasses;
 
   public InheritanceClassInDexDistributor(
@@ -295,7 +293,6 @@
       List<VirtualFile> filesForDistribution,
       Set<DexProgramClass> classes,
       IntBox nextFileId,
-      NamingLens namingLens,
       AppView<?> appView,
       ExecutorService executorService) {
     this.mainDex = mainDex;
@@ -303,7 +300,6 @@
     this.filesForDistribution = filesForDistribution;
     this.classes = classes;
     this.nextFileId = nextFileId;
-    this.namingLens = namingLens;
     this.appView = appView;
     this.executorService = executorService;
 
@@ -320,7 +316,7 @@
     // Allocate member of groups depending on
     // the main dex members
     VirtualFileCycler cycler =
-        new VirtualFileCycler(files, filesForDistribution, appView, namingLens, nextFileId);
+        new VirtualFileCycler(files, filesForDistribution, appView, nextFileId);
     for (Iterator<ClassGroup> iter = remainingInheritanceGroups.iterator(); iter.hasNext();) {
       ClassGroup group = iter.next();
       if (group.dependsOnMainDexClasses) {
diff --git a/src/main/java/com/android/tools/r8/dex/JumboStringRewriter.java b/src/main/java/com/android/tools/r8/dex/JumboStringRewriter.java
index fc3784f..785158d 100644
--- a/src/main/java/com/android/tools/r8/dex/JumboStringRewriter.java
+++ b/src/main/java/com/android/tools/r8/dex/JumboStringRewriter.java
@@ -6,29 +6,29 @@
 import static com.android.tools.r8.graph.DexCode.TryHandler.NO_HANDLER;
 import static com.android.tools.r8.graph.DexDebugEventBuilder.addDefaultEventWithAdvancePcIfNecessary;
 
-import com.android.tools.r8.code.ConstString;
-import com.android.tools.r8.code.ConstStringJumbo;
-import com.android.tools.r8.code.Format21t;
-import com.android.tools.r8.code.Format22t;
-import com.android.tools.r8.code.Format31t;
-import com.android.tools.r8.code.Goto;
-import com.android.tools.r8.code.Goto16;
-import com.android.tools.r8.code.Goto32;
-import com.android.tools.r8.code.IfEq;
-import com.android.tools.r8.code.IfEqz;
-import com.android.tools.r8.code.IfGe;
-import com.android.tools.r8.code.IfGez;
-import com.android.tools.r8.code.IfGt;
-import com.android.tools.r8.code.IfGtz;
-import com.android.tools.r8.code.IfLe;
-import com.android.tools.r8.code.IfLez;
-import com.android.tools.r8.code.IfLt;
-import com.android.tools.r8.code.IfLtz;
-import com.android.tools.r8.code.IfNe;
-import com.android.tools.r8.code.IfNez;
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.Nop;
-import com.android.tools.r8.code.SwitchPayload;
+import com.android.tools.r8.dex.code.DexConstString;
+import com.android.tools.r8.dex.code.DexConstStringJumbo;
+import com.android.tools.r8.dex.code.DexFormat21t;
+import com.android.tools.r8.dex.code.DexFormat22t;
+import com.android.tools.r8.dex.code.DexFormat31t;
+import com.android.tools.r8.dex.code.DexGoto;
+import com.android.tools.r8.dex.code.DexGoto16;
+import com.android.tools.r8.dex.code.DexGoto32;
+import com.android.tools.r8.dex.code.DexIfEq;
+import com.android.tools.r8.dex.code.DexIfEqz;
+import com.android.tools.r8.dex.code.DexIfGe;
+import com.android.tools.r8.dex.code.DexIfGez;
+import com.android.tools.r8.dex.code.DexIfGt;
+import com.android.tools.r8.dex.code.DexIfGtz;
+import com.android.tools.r8.dex.code.DexIfLe;
+import com.android.tools.r8.dex.code.DexIfLez;
+import com.android.tools.r8.dex.code.DexIfLt;
+import com.android.tools.r8.dex.code.DexIfLtz;
+import com.android.tools.r8.dex.code.DexIfNe;
+import com.android.tools.r8.dex.code.DexIfNez;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexNop;
+import com.android.tools.r8.dex.code.DexSwitchPayload;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.graph.DexCode.Try;
 import com.android.tools.r8.graph.DexCode.TryHandler;
@@ -57,11 +57,11 @@
 public class JumboStringRewriter {
 
   private static class TryTargets {
-    private Instruction start;
-    private Instruction end;
+    private DexInstruction start;
+    private DexInstruction end;
     private final boolean endsAfterLastInstruction;
 
-    TryTargets(Instruction start, Instruction end, boolean endsAfterLastInstruction) {
+    TryTargets(DexInstruction start, DexInstruction end, boolean endsAfterLastInstruction) {
       assert start != null;
       assert end != null;
       this.start = start;
@@ -69,7 +69,7 @@
       this.endsAfterLastInstruction = endsAfterLastInstruction;
     }
 
-    void replaceTarget(Instruction target, Instruction newTarget) {
+    void replaceTarget(DexInstruction target, DexInstruction newTarget) {
       if (start == target) {
         start = newTarget;
       }
@@ -93,14 +93,16 @@
   private final DexEncodedMethod method;
   private final DexString firstJumboString;
   private final DexItemFactory factory;
-  private final Map<Instruction, List<Instruction>> instructionTargets = new IdentityHashMap<>();
+  private final Map<DexInstruction, List<DexInstruction>> instructionTargets =
+      new IdentityHashMap<>();
   private EventBasedDebugInfo debugEventBasedInfo = null;
-  private final Int2ReferenceMap<Instruction> debugEventTargets = new Int2ReferenceOpenHashMap<>();
-  private final Map<Instruction, Instruction> payloadToSwitch = new IdentityHashMap<>();
+  private final Int2ReferenceMap<DexInstruction> debugEventTargets =
+      new Int2ReferenceOpenHashMap<>();
+  private final Map<DexInstruction, DexInstruction> payloadToSwitch = new IdentityHashMap<>();
   private final Map<Try, TryTargets> tryTargets = new IdentityHashMap<>();
-  private final Int2ReferenceMap<Instruction> tryRangeStartAndEndTargets
-      = new Int2ReferenceOpenHashMap<>();
-  private final Map<TryHandler, List<Instruction>> handlerTargets = new IdentityHashMap<>();
+  private final Int2ReferenceMap<DexInstruction> tryRangeStartAndEndTargets =
+      new Int2ReferenceOpenHashMap<>();
+  private final Map<TryHandler, List<DexInstruction>> handlerTargets = new IdentityHashMap<>();
 
   public JumboStringRewriter(
       DexEncodedMethod method, DexString firstJumboString, DexItemFactory factory) {
@@ -114,7 +116,7 @@
     // instructions to the actual instruction referenced.
     recordTargets();
     // Expand the code by rewriting jumbo strings and branching instructions.
-    List<Instruction> newInstructions = expandCode();
+    List<DexInstruction> newInstructions = expandCode();
     // Commit to the new instruction offsets and update instructions, try-catch structures
     // and debug info with the new offsets.
     rewriteInstructionOffsets(newInstructions);
@@ -128,7 +130,7 @@
             oldCode.registerSize,
             oldCode.incomingRegisterSize,
             oldCode.outgoingRegisterSize,
-            newInstructions.toArray(Instruction.EMPTY_ARRAY),
+            newInstructions.toArray(DexInstruction.EMPTY_ARRAY),
             newTries,
             newHandlers,
             newDebugInfo);
@@ -138,44 +140,44 @@
     return newCode;
   }
 
-  private void rewriteInstructionOffsets(List<Instruction> instructions) {
-    for (Instruction instruction : instructions) {
-      if (instruction instanceof Format22t) {  // IfEq, IfGe, IfGt, IfLe, IfLt, IfNe
-        Format22t condition = (Format22t) instruction;
+  private void rewriteInstructionOffsets(List<DexInstruction> instructions) {
+    for (DexInstruction instruction : instructions) {
+      if (instruction instanceof DexFormat22t) { // IfEq, IfGe, IfGt, IfLe, IfLt, IfNe
+        DexFormat22t condition = (DexFormat22t) instruction;
         int offset = instructionTargets.get(condition).get(0).getOffset() - instruction.getOffset();
         assert Short.MIN_VALUE <= offset && offset <= Short.MAX_VALUE;
         condition.CCCC = (short) offset;
-      } else if (instruction instanceof Format21t) {  // IfEqz, IfGez, IfGtz, IfLez, IfLtz, IfNez
-        Format21t condition = (Format21t) instruction;
+      } else if (instruction instanceof DexFormat21t) { // IfEqz, IfGez, IfGtz, IfLez, IfLtz, IfNez
+        DexFormat21t condition = (DexFormat21t) instruction;
         int offset = instructionTargets.get(condition).get(0).getOffset() - instruction.getOffset();
         assert Short.MIN_VALUE <= offset && offset <= Short.MAX_VALUE;
         condition.BBBB = (short) offset;
-      } else if (instruction instanceof Goto) {
-        Goto jump = (Goto) instruction;
+      } else if (instruction instanceof DexGoto) {
+        DexGoto jump = (DexGoto) instruction;
         int offset = instructionTargets.get(jump).get(0).getOffset() - instruction.getOffset();
         assert Byte.MIN_VALUE <= offset && offset <= Byte.MAX_VALUE;
         jump.AA = (byte) offset;
-      } else if (instruction instanceof Goto16) {
-        Goto16 jump = (Goto16) instruction;
+      } else if (instruction instanceof DexGoto16) {
+        DexGoto16 jump = (DexGoto16) instruction;
         int offset = instructionTargets.get(jump).get(0).getOffset() - instruction.getOffset();
         assert Short.MIN_VALUE <= offset && offset <= Short.MAX_VALUE;
         jump.AAAA = (short) offset;
-      } else if (instruction instanceof Goto32) {
-        Goto32 jump = (Goto32) instruction;
+      } else if (instruction instanceof DexGoto32) {
+        DexGoto32 jump = (DexGoto32) instruction;
         int offset = instructionTargets.get(jump).get(0).getOffset() - instruction.getOffset();
         jump.AAAAAAAA = offset;
-      } else if (instruction.hasPayload()) {  // FillArrayData, SparseSwitch, PackedSwitch
-        Format31t payloadUser = (Format31t) instruction;
+      } else if (instruction.hasPayload()) { // FillArrayData, SparseSwitch, PackedSwitch
+        DexFormat31t payloadUser = (DexFormat31t) instruction;
         int offset =
             instructionTargets.get(payloadUser).get(0).getOffset() - instruction.getOffset();
         payloadUser.setPayloadOffset(offset);
-      } else if (instruction instanceof SwitchPayload) {
-        SwitchPayload payload = (SwitchPayload) instruction;
-        Instruction switchInstruction = payloadToSwitch.get(payload);
-        List<Instruction> switchTargets = instructionTargets.get(payload);
+      } else if (instruction instanceof DexSwitchPayload) {
+        DexSwitchPayload payload = (DexSwitchPayload) instruction;
+        DexInstruction switchInstruction = payloadToSwitch.get(payload);
+        List<DexInstruction> switchTargets = instructionTargets.get(payload);
         int[] targets = payload.switchTargetOffsets();
         for (int i = 0; i < switchTargets.size(); i++) {
-          Instruction target = switchTargets.get(i);
+          DexInstruction target = switchTargets.get(i);
           targets[i] = target.getOffset() - switchInstruction.getOffset();
         }
       }
@@ -199,8 +201,8 @@
     TryHandler[] result = new TryHandler[code.handlers.length];
     for (int i = 0; i < code.handlers.length; i++) {
       TryHandler handler = code.handlers[i];
-      List<Instruction> targets = handlerTargets.get(handler);
-      Iterator<Instruction> it = targets.iterator();
+      List<DexInstruction> targets = handlerTargets.get(handler);
+      Iterator<DexInstruction> it = targets.iterator();
       int catchAllAddr = NO_HANDLER;
       if (handler.catchAllAddr != NO_HANDLER) {
         catchAllAddr = it.next().getOffset();
@@ -226,14 +228,14 @@
         if (event instanceof AdvancePC) {
           AdvancePC advance = (AdvancePC) event;
           lastOriginalOffset += advance.delta;
-          Instruction target = debugEventTargets.get(lastOriginalOffset);
+          DexInstruction target = debugEventTargets.get(lastOriginalOffset);
           int pcDelta = target.getOffset() - lastNewOffset;
           events.add(factory.createAdvancePC(pcDelta));
           lastNewOffset = target.getOffset();
         } else if (event instanceof Default) {
           Default defaultEvent = (Default) event;
           lastOriginalOffset += defaultEvent.getPCDelta();
-          Instruction target = debugEventTargets.get(lastOriginalOffset);
+          DexInstruction target = debugEventTargets.get(lastOriginalOffset);
           int lineDelta = defaultEvent.getLineDelta();
           int pcDelta = target.getOffset() - lastNewOffset;
           addDefaultEventWithAdvancePcIfNecessary(lineDelta, pcDelta, events, factory);
@@ -250,116 +252,116 @@
     return code.getDebugInfo();
   }
 
-  private List<Instruction> expandCode() {
-    LinkedList<Instruction> instructions = new LinkedList<>();
+  private List<DexInstruction> expandCode() {
+    LinkedList<DexInstruction> instructions = new LinkedList<>();
     Collections.addAll(instructions, method.getCode().asDexCode().instructions);
     int offsetDelta;
     do {
-      ListIterator<Instruction> it = instructions.listIterator();
+      ListIterator<DexInstruction> it = instructions.listIterator();
       offsetDelta = 0;
       while (it.hasNext()) {
-        Instruction instruction = it.next();
+        DexInstruction instruction = it.next();
         int orignalOffset = instruction.getOffset();
         instruction.setOffset(orignalOffset + offsetDelta);
-        if (instruction instanceof ConstString) {
-          ConstString string = (ConstString) instruction;
+        if (instruction instanceof DexConstString) {
+          DexConstString string = (DexConstString) instruction;
           if (string.getString().compareTo(firstJumboString) >= 0) {
-            ConstStringJumbo jumboString = new ConstStringJumbo(string.AA, string.getString());
+            DexConstStringJumbo jumboString =
+                new DexConstStringJumbo(string.AA, string.getString());
             jumboString.setOffset(string.getOffset());
             offsetDelta++;
             it.set(jumboString);
             replaceTarget(instruction, jumboString);
           }
-        } else if (instruction instanceof Format22t) {  // IfEq, IfGe, IfGt, IfLe, IfLt, IfNe
-          Format22t condition = (Format22t) instruction;
+        } else if (instruction instanceof DexFormat22t) { // IfEq, IfGe, IfGt, IfLe, IfLt, IfNe
+          DexFormat22t condition = (DexFormat22t) instruction;
           int offset =
               instructionTargets.get(condition).get(0).getOffset() - instruction.getOffset();
           if (Short.MIN_VALUE > offset || offset > Short.MAX_VALUE) {
-            Format22t newCondition = null;
+            DexFormat22t newCondition = null;
             switch (condition.getType().inverted()) {
               case EQ:
-                newCondition = new IfEq(condition.A, condition.B, 0);
+                newCondition = new DexIfEq(condition.A, condition.B, 0);
                 break;
               case GE:
-                newCondition = new IfGe(condition.A, condition.B, 0);
+                newCondition = new DexIfGe(condition.A, condition.B, 0);
                 break;
               case GT:
-                newCondition = new IfGt(condition.A, condition.B, 0);
+                newCondition = new DexIfGt(condition.A, condition.B, 0);
                 break;
               case LE:
-                newCondition = new IfLe(condition.A, condition.B, 0);
+                newCondition = new DexIfLe(condition.A, condition.B, 0);
                 break;
               case LT:
-                newCondition = new IfLt(condition.A, condition.B, 0);
+                newCondition = new DexIfLt(condition.A, condition.B, 0);
                 break;
               case NE:
-                newCondition = new IfNe(condition.A, condition.B, 0);
+                newCondition = new DexIfNe(condition.A, condition.B, 0);
                 break;
             }
             offsetDelta = rewriteIfToIfAndGoto(offsetDelta, it, condition, newCondition);
           }
-        } else if (instruction instanceof Format21t) {  // IfEqz, IfGez, IfGtz, IfLez, IfLtz, IfNez
-          Format21t condition = (Format21t) instruction;
+        } else if (instruction
+            instanceof DexFormat21t) { // IfEqz, IfGez, IfGtz, IfLez, IfLtz, IfNez
+          DexFormat21t condition = (DexFormat21t) instruction;
           int offset =
               instructionTargets.get(condition).get(0).getOffset() - instruction.getOffset();
           if (Short.MIN_VALUE > offset || offset > Short.MAX_VALUE) {
-            Format21t newCondition = null;
+            DexFormat21t newCondition = null;
             switch (condition.getType().inverted()) {
               case EQ:
-                newCondition = new IfEqz(condition.AA, 0);
+                newCondition = new DexIfEqz(condition.AA, 0);
                 break;
               case GE:
-                newCondition = new IfGez(condition.AA, 0);
+                newCondition = new DexIfGez(condition.AA, 0);
                 break;
               case GT:
-                newCondition = new IfGtz(condition.AA, 0);
+                newCondition = new DexIfGtz(condition.AA, 0);
                 break;
               case LE:
-                newCondition = new IfLez(condition.AA, 0);
+                newCondition = new DexIfLez(condition.AA, 0);
                 break;
               case LT:
-                newCondition = new IfLtz(condition.AA, 0);
+                newCondition = new DexIfLtz(condition.AA, 0);
                 break;
               case NE:
-                newCondition = new IfNez(condition.AA, 0);
+                newCondition = new DexIfNez(condition.AA, 0);
                 break;
             }
             offsetDelta = rewriteIfToIfAndGoto(offsetDelta, it, condition, newCondition);
           }
-        } else if (instruction instanceof Goto) {
-          Goto jump = (Goto) instruction;
-          int offset =
-              instructionTargets.get(jump).get(0).getOffset() - instruction.getOffset();
+        } else if (instruction instanceof DexGoto) {
+          DexGoto jump = (DexGoto) instruction;
+          int offset = instructionTargets.get(jump).get(0).getOffset() - instruction.getOffset();
           if (Byte.MIN_VALUE > offset || offset > Byte.MAX_VALUE) {
-            Instruction newJump;
+            DexInstruction newJump;
             if (Short.MIN_VALUE > offset || offset > Short.MAX_VALUE) {
-              newJump = new Goto32(offset);
+              newJump = new DexGoto32(offset);
             } else {
-              newJump = new Goto16(offset);
+              newJump = new DexGoto16(offset);
             }
             newJump.setOffset(jump.getOffset());
             it.set(newJump);
             offsetDelta += (newJump.getSize() - jump.getSize());
             replaceTarget(jump, newJump);
-            List<Instruction> targets = instructionTargets.remove(jump);
+            List<DexInstruction> targets = instructionTargets.remove(jump);
             instructionTargets.put(newJump, targets);
           }
-        } else if (instruction instanceof Goto16) {
-          Goto16 jump = (Goto16) instruction;
-          int offset =
-              instructionTargets.get(jump).get(0).getOffset() - instruction.getOffset();
+        } else if (instruction instanceof DexGoto16) {
+          DexGoto16 jump = (DexGoto16) instruction;
+          int offset = instructionTargets.get(jump).get(0).getOffset() - instruction.getOffset();
           if (Short.MIN_VALUE > offset || offset > Short.MAX_VALUE) {
-            Instruction newJump = new Goto32(offset);
+            DexInstruction newJump = new DexGoto32(offset);
             newJump.setOffset(jump.getOffset());
             it.set(newJump);
             offsetDelta += (newJump.getSize() - jump.getSize());
             replaceTarget(jump, newJump);
-            List<Instruction> targets = instructionTargets.remove(jump);
+            List<DexInstruction> targets = instructionTargets.remove(jump);
             instructionTargets.put(newJump, targets);
           }
-        } else if (instruction instanceof Goto32) {
+        } else if (instruction instanceof DexGoto32) {
           // Instruction big enough for any offset.
-        } else if (instruction.hasPayload()) {  // FillArrayData, SparseSwitch, PackedSwitch
+        } else if (instruction.hasPayload()) { // FillArrayData, SparseSwitch, PackedSwitch
           // Instruction big enough for any offset.
         } else if (instruction.isPayload()) {
           // Payload instructions must be 4 byte aligned (instructions are 2 bytes).
@@ -368,7 +370,7 @@
             // Check if the previous instruction was a simple nop. If that is the case, remove it
             // to make the alignment instead of adding another one. Only allow removal if this
             // instruction is not targeted by anything. See b/78072750.
-            Instruction instructionBeforePayload = it.hasPrevious() ? it.previous() : null;
+            DexInstruction instructionBeforePayload = it.hasPrevious() ? it.previous() : null;
             if (instructionBeforePayload != null
                 && instructionBeforePayload.isSimpleNop()
                 && debugEventTargets.get(orignalOffset) == null
@@ -379,7 +381,7 @@
               if (instructionBeforePayload != null) {
                 it.next();
               }
-              Nop nop = new Nop();
+              DexNop nop = new DexNop();
               nop.setOffset(instruction.getOffset());
               it.add(nop);
               offsetDelta++;
@@ -396,11 +398,11 @@
 
   private int rewriteIfToIfAndGoto(
       int offsetDelta,
-      ListIterator<Instruction> it,
-      Instruction condition,
-      Instruction newCondition) {
+      ListIterator<DexInstruction> it,
+      DexInstruction condition,
+      DexInstruction newCondition) {
     int jumpOffset = condition.getOffset() + condition.getSize();
-    Goto32 jump = new Goto32(0);
+    DexGoto32 jump = new DexGoto32(0);
     jump.setOffset(jumpOffset);
     newCondition.setOffset(condition.getOffset());
     it.set(newCondition);
@@ -408,17 +410,17 @@
     it.add(jump);
     offsetDelta += jump.getSize();
     instructionTargets.put(jump, instructionTargets.remove(condition));
-    Instruction fallthroughInstruction = it.next();
+    DexInstruction fallthroughInstruction = it.next();
     instructionTargets.put(newCondition, Lists.newArrayList(fallthroughInstruction));
     it.previous();
     return offsetDelta;
   }
 
-  private void replaceTarget(Instruction target, Instruction newTarget) {
-    for (List<Instruction> instructions : instructionTargets.values()) {
+  private void replaceTarget(DexInstruction target, DexInstruction newTarget) {
+    for (List<DexInstruction> instructions : instructionTargets.values()) {
       instructions.replaceAll((i) -> i == target ? newTarget : i);
     }
-    for (Int2ReferenceMap.Entry<Instruction> entry : debugEventTargets.int2ReferenceEntrySet()) {
+    for (Int2ReferenceMap.Entry<DexInstruction> entry : debugEventTargets.int2ReferenceEntrySet()) {
       if (entry.getValue() == target) {
         entry.setValue(newTarget);
       }
@@ -426,52 +428,53 @@
     for (Entry<Try, TryTargets> entry : tryTargets.entrySet()) {
       entry.getValue().replaceTarget(target, newTarget);
     }
-    for (List<Instruction> instructions : handlerTargets.values()) {
+    for (List<DexInstruction> instructions : handlerTargets.values()) {
       instructions.replaceAll((i) -> i == target ? newTarget : i);
     }
   }
 
-  private void recordInstructionTargets(Int2ReferenceMap<Instruction> offsetToInstruction) {
-    Instruction[] instructions = method.getCode().asDexCode().instructions;
-    for (Instruction instruction : instructions) {
-      if (instruction instanceof Format22t) {  // IfEq, IfGe, IfGt, IfLe, IfLt, IfNe
-        Format22t condition = (Format22t) instruction;
-        Instruction target = offsetToInstruction.get(condition.getOffset() + condition.CCCC);
+  private void recordInstructionTargets(Int2ReferenceMap<DexInstruction> offsetToInstruction) {
+    DexInstruction[] instructions = method.getCode().asDexCode().instructions;
+    for (DexInstruction instruction : instructions) {
+      if (instruction instanceof DexFormat22t) { // IfEq, IfGe, IfGt, IfLe, IfLt, IfNe
+        DexFormat22t condition = (DexFormat22t) instruction;
+        DexInstruction target = offsetToInstruction.get(condition.getOffset() + condition.CCCC);
         assert target != null;
         instructionTargets.put(instruction, Lists.newArrayList(target));
-      } else if (instruction instanceof Format21t) {  // IfEqz, IfGez, IfGtz, IfLez, IfLtz, IfNez
-        Format21t condition = (Format21t) instruction;
-        Instruction target = offsetToInstruction.get(condition.getOffset() + condition.BBBB);
+      } else if (instruction instanceof DexFormat21t) { // IfEqz, IfGez, IfGtz, IfLez, IfLtz, IfNez
+        DexFormat21t condition = (DexFormat21t) instruction;
+        DexInstruction target = offsetToInstruction.get(condition.getOffset() + condition.BBBB);
         assert target != null;
         instructionTargets.put(instruction, Lists.newArrayList(target));
-      } else if (instruction instanceof Goto) {
-        Goto jump = (Goto) instruction;
-        Instruction target = offsetToInstruction.get(jump.getOffset() + jump.AA);
+      } else if (instruction instanceof DexGoto) {
+        DexGoto jump = (DexGoto) instruction;
+        DexInstruction target = offsetToInstruction.get(jump.getOffset() + jump.AA);
         assert target != null;
         instructionTargets.put(instruction, Lists.newArrayList(target));
-      } else if (instruction instanceof Goto16) {
-        Goto16 jump = (Goto16) instruction;
-        Instruction target = offsetToInstruction.get(jump.getOffset() + jump.AAAA);
+      } else if (instruction instanceof DexGoto16) {
+        DexGoto16 jump = (DexGoto16) instruction;
+        DexInstruction target = offsetToInstruction.get(jump.getOffset() + jump.AAAA);
         assert target != null;
         instructionTargets.put(instruction, Lists.newArrayList(target));
-      } else if (instruction instanceof Goto32) {
-        Goto32 jump = (Goto32) instruction;
-        Instruction target = offsetToInstruction.get(jump.getOffset() + jump.AAAAAAAA);
+      } else if (instruction instanceof DexGoto32) {
+        DexGoto32 jump = (DexGoto32) instruction;
+        DexInstruction target = offsetToInstruction.get(jump.getOffset() + jump.AAAAAAAA);
         assert target != null;
         instructionTargets.put(instruction, Lists.newArrayList(target));
-      } else if (instruction.hasPayload()) {  // FillArrayData, SparseSwitch, PackedSwitch
-        Format31t offsetInstruction = (Format31t) instruction;
-        Instruction target = offsetToInstruction.get(
-            offsetInstruction.getOffset() + offsetInstruction.getPayloadOffset());
+      } else if (instruction.hasPayload()) { // FillArrayData, SparseSwitch, PackedSwitch
+        DexFormat31t offsetInstruction = (DexFormat31t) instruction;
+        DexInstruction target =
+            offsetToInstruction.get(
+                offsetInstruction.getOffset() + offsetInstruction.getPayloadOffset());
         assert target != null;
         instructionTargets.put(instruction, Lists.newArrayList(target));
-      } else if (instruction instanceof SwitchPayload) {
-        SwitchPayload payload = (SwitchPayload) instruction;
+      } else if (instruction instanceof DexSwitchPayload) {
+        DexSwitchPayload payload = (DexSwitchPayload) instruction;
         int[] targetOffsets = payload.switchTargetOffsets();
         int switchOffset = payloadToSwitch.get(instruction).getOffset();
-        List<Instruction> targets = new ArrayList<>();
+        List<DexInstruction> targets = new ArrayList<>();
         for (int i = 0; i < targetOffsets.length; i++) {
-          Instruction target = offsetToInstruction.get(switchOffset + targetOffsets[i]);
+          DexInstruction target = offsetToInstruction.get(switchOffset + targetOffsets[i]);
           assert target != null;
           targets.add(target);
         }
@@ -480,7 +483,7 @@
     }
   }
 
-  private void recordDebugEventTargets(Int2ReferenceMap<Instruction> offsetToInstruction) {
+  private void recordDebugEventTargets(Int2ReferenceMap<DexInstruction> offsetToInstruction) {
     // TODO(b/213411850): Merging pc based D8 builds will map out of PC for any jumbo processed
     //  method. Instead we should rather retain the PC encoding by bumping the max-pc and recording
     //  the line number translation. We actually need to do so to support merging with native PC
@@ -496,13 +499,13 @@
       if (event instanceof AdvancePC) {
         AdvancePC advance = (AdvancePC) event;
         address += advance.delta;
-        Instruction target = offsetToInstruction.get(address);
+        DexInstruction target = offsetToInstruction.get(address);
         assert target != null;
         debugEventTargets.put(address, target);
       } else if (event instanceof Default) {
         Default defaultEvent = (Default) event;
         address += defaultEvent.getPCDelta();
-        Instruction target = offsetToInstruction.get(address);
+        DexInstruction target = offsetToInstruction.get(address);
         assert target != null;
         debugEventTargets.put(address, target);
       }
@@ -510,12 +513,11 @@
   }
 
   private void recordTryAndHandlerTargets(
-      Int2ReferenceMap<Instruction> offsetToInstruction,
-      Instruction lastInstruction) {
+      Int2ReferenceMap<DexInstruction> offsetToInstruction, DexInstruction lastInstruction) {
     DexCode code = method.getCode().asDexCode();
     for (Try theTry : code.tries) {
-      Instruction start = offsetToInstruction.get(theTry.startAddress);
-      Instruction end = null;
+      DexInstruction start = offsetToInstruction.get(theTry.startAddress);
+      DexInstruction end = null;
       int endAddress = theTry.startAddress + theTry.instructionCount;
       TryTargets targets;
       if (endAddress > lastInstruction.getOffset()) {
@@ -532,14 +534,14 @@
       tryRangeStartAndEndTargets.put(end.getOffset(), end);
     }
     for (TryHandler handler : code.handlers) {
-      List<Instruction> targets = new ArrayList<>();
+      List<DexInstruction> targets = new ArrayList<>();
       if (handler.catchAllAddr != NO_HANDLER) {
-        Instruction target = offsetToInstruction.get(handler.catchAllAddr);
+        DexInstruction target = offsetToInstruction.get(handler.catchAllAddr);
         assert target != null;
         targets.add(target);
       }
       for (TypeAddrPair pair : handler.pairs) {
-        Instruction target = offsetToInstruction.get(pair.addr);
+        DexInstruction target = offsetToInstruction.get(pair.addr);
         assert target != null;
         targets.add(target);
       }
@@ -548,19 +550,19 @@
   }
 
   private void recordTargets() {
-    Int2ReferenceMap<Instruction> offsetToInstruction = new Int2ReferenceOpenHashMap<>();
-    Instruction[] instructions = method.getCode().asDexCode().instructions;
+    Int2ReferenceMap<DexInstruction> offsetToInstruction = new Int2ReferenceOpenHashMap<>();
+    DexInstruction[] instructions = method.getCode().asDexCode().instructions;
     boolean containsPayloads = false;
-    for (Instruction instruction : instructions) {
+    for (DexInstruction instruction : instructions) {
       offsetToInstruction.put(instruction.getOffset(), instruction);
-      if (instruction.hasPayload()) {  // FillArrayData, SparseSwitch, PackedSwitch
+      if (instruction.hasPayload()) { // FillArrayData, SparseSwitch, PackedSwitch
         containsPayloads = true;
       }
     }
     if (containsPayloads) {
-      for (Instruction instruction : instructions) {
-        if (instruction.hasPayload()) {  // FillArrayData, SparseSwitch, PackedSwitch
-          Instruction payload =
+      for (DexInstruction instruction : instructions) {
+        if (instruction.hasPayload()) { // FillArrayData, SparseSwitch, PackedSwitch
+          DexInstruction payload =
               offsetToInstruction.get(instruction.getOffset() + instruction.getPayloadOffset());
           assert payload != null;
           payloadToSwitch.put(payload, instruction);
@@ -569,7 +571,7 @@
     }
     recordInstructionTargets(offsetToInstruction);
     recordDebugEventTargets(offsetToInstruction);
-    Instruction lastInstruction = instructions[instructions.length - 1];
+    DexInstruction lastInstruction = instructions[instructions.length - 1];
     recordTryAndHandlerTargets(offsetToInstruction, lastInstruction);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/dex/MixedSectionCollection.java b/src/main/java/com/android/tools/r8/dex/MixedSectionCollection.java
index f0c4c06..d80b036 100644
--- a/src/main/java/com/android/tools/r8/dex/MixedSectionCollection.java
+++ b/src/main/java/com/android/tools/r8/dex/MixedSectionCollection.java
@@ -110,10 +110,16 @@
   /**
    * Adds the given annotation directory to the collection.
    *
-   * Add a dependency between the clazz and the annotation directory.
-   *
-   * @return true if the item was not added before
+   * <p>Adds a dependency between the clazz and the annotation directory.
    */
-  public abstract boolean setAnnotationsDirectoryForClass(DexProgramClass clazz,
-      DexAnnotationDirectory annotationDirectory);
+  public abstract void setAnnotationsDirectoryForClass(
+      DexProgramClass clazz, DexAnnotationDirectory annotationDirectory);
+
+  /**
+   * Adds the given static field values array to the collection.
+   *
+   * <p>Adds a dependency between the clazz and the static field values array.
+   */
+  public abstract void setStaticFieldValuesForClass(
+      DexProgramClass clazz, DexEncodedArray staticFieldValues);
 }
diff --git a/src/main/java/com/android/tools/r8/dex/MixedSectionLayoutStrategy.java b/src/main/java/com/android/tools/r8/dex/MixedSectionLayoutStrategy.java
new file mode 100644
index 0000000..5454b0f
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/dex/MixedSectionLayoutStrategy.java
@@ -0,0 +1,56 @@
+// 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.dex;
+
+import com.android.tools.r8.dex.FileWriter.MixedSectionOffsets;
+import com.android.tools.r8.experimental.startup.StartupOrder;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexAnnotation;
+import com.android.tools.r8.graph.DexAnnotationDirectory;
+import com.android.tools.r8.graph.DexAnnotationSet;
+import com.android.tools.r8.graph.DexEncodedArray;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexTypeList;
+import com.android.tools.r8.graph.ParameterAnnotationsList;
+import com.android.tools.r8.graph.ProgramMethod;
+import java.util.Collection;
+
+public abstract class MixedSectionLayoutStrategy {
+
+  public static MixedSectionLayoutStrategy create(
+      AppView<?> appView, MixedSectionOffsets mixedSectionOffsets, VirtualFile virtualFile) {
+    StartupOrder startupOrderForWriting =
+        virtualFile.getId() == 0 && appView.hasClassHierarchy()
+            ? appView
+                .appInfoWithClassHierarchy()
+                .getStartupOrder()
+                .toStartupOrderForWriting(appView)
+            : StartupOrder.empty();
+    if (startupOrderForWriting.isEmpty()) {
+      return new DefaultMixedSectionLayoutStrategy(appView, mixedSectionOffsets);
+    }
+    return new StartupMixedSectionLayoutStrategy(
+        appView, mixedSectionOffsets, startupOrderForWriting, virtualFile);
+  }
+
+  public abstract Collection<DexAnnotation> getAnnotationLayout();
+
+  public abstract Collection<DexAnnotationDirectory> getAnnotationDirectoryLayout();
+
+  public abstract Collection<DexAnnotationSet> getAnnotationSetLayout();
+
+  public abstract Collection<ParameterAnnotationsList> getAnnotationSetRefListLayout();
+
+  public abstract Collection<DexProgramClass> getClassDataLayout();
+
+  public abstract Collection<ProgramMethod> getCodeLayout();
+
+  public abstract Collection<DexEncodedArray> getEncodedArrayLayout();
+
+  public abstract Collection<DexString> getStringDataLayout();
+
+  public abstract Collection<DexTypeList> getTypeListLayout();
+}
diff --git a/src/main/java/com/android/tools/r8/dex/ResourceAdapter.java b/src/main/java/com/android/tools/r8/dex/ResourceAdapter.java
index eaf736d..e249186 100644
--- a/src/main/java/com/android/tools/r8/dex/ResourceAdapter.java
+++ b/src/main/java/com/android/tools/r8/dex/ResourceAdapter.java
@@ -37,16 +37,12 @@
   private final NamingLens namingLens;
   private final InternalOptions options;
 
-  public ResourceAdapter(
-      AppView<?> appView,
-      DexItemFactory dexItemFactory,
-      NamingLens namingLens,
-      InternalOptions options) {
+  public ResourceAdapter(AppView<?> appView) {
     this.appView = appView;
-    this.dexItemFactory = dexItemFactory;
+    this.dexItemFactory = appView.dexItemFactory();
     this.graphLens = appView.graphLens();
-    this.namingLens = namingLens;
-    this.options = options;
+    this.namingLens = appView.getNamingLens();
+    this.options = appView.options();
   }
 
   public DataEntryResource adaptIfNeeded(DataEntryResource file) {
diff --git a/src/main/java/com/android/tools/r8/dex/StartupMixedSectionLayoutStrategy.java b/src/main/java/com/android/tools/r8/dex/StartupMixedSectionLayoutStrategy.java
new file mode 100644
index 0000000..b5ccc6b
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/dex/StartupMixedSectionLayoutStrategy.java
@@ -0,0 +1,226 @@
+// 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.dex;
+
+import com.android.tools.r8.dex.FileWriter.MixedSectionOffsets;
+import com.android.tools.r8.experimental.startup.StartupOrder;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexAnnotation;
+import com.android.tools.r8.graph.DexAnnotationDirectory;
+import com.android.tools.r8.graph.DexAnnotationSet;
+import com.android.tools.r8.graph.DexCallSite;
+import com.android.tools.r8.graph.DexEncodedArray;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexMethodHandle;
+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.DexTypeList;
+import com.android.tools.r8.graph.ParameterAnnotationsList;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import com.android.tools.r8.utils.MapUtils;
+import com.android.tools.r8.utils.collections.LinkedProgramMethodSet;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
+import java.util.Collection;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class StartupMixedSectionLayoutStrategy extends DefaultMixedSectionLayoutStrategy {
+
+  private final StartupOrder startupOrderForWriting;
+
+  private final LinkedHashSet<DexAnnotation> annotationLayout;
+  private final LinkedHashSet<DexAnnotationDirectory> annotationDirectoryLayout;
+  private final LinkedHashSet<DexAnnotationSet> annotationSetLayout;
+  private final LinkedHashSet<ParameterAnnotationsList> annotationSetRefListLayout;
+  private final LinkedHashSet<DexProgramClass> classDataLayout;
+  private final LinkedProgramMethodSet codeLayout;
+  private final LinkedHashSet<DexEncodedArray> encodedArrayLayout;
+  private final LinkedHashSet<DexString> stringDataLayout;
+  private final LinkedHashSet<DexTypeList> typeListLayout;
+
+  public StartupMixedSectionLayoutStrategy(
+      AppView<?> appView,
+      MixedSectionOffsets mixedSectionOffsets,
+      StartupOrder startupOrderForWriting,
+      VirtualFile virtualFile) {
+    super(appView, mixedSectionOffsets);
+    this.startupOrderForWriting = startupOrderForWriting;
+
+    // Initialize startup layouts.
+    this.annotationLayout = new LinkedHashSet<>(mixedSectionOffsets.getAnnotations().size());
+    this.annotationDirectoryLayout =
+        new LinkedHashSet<>(mixedSectionOffsets.getAnnotationDirectories().size());
+    this.annotationSetLayout = new LinkedHashSet<>(mixedSectionOffsets.getAnnotationSets().size());
+    this.annotationSetRefListLayout =
+        new LinkedHashSet<>(mixedSectionOffsets.getAnnotationSetRefLists().size());
+    this.classDataLayout = new LinkedHashSet<>(mixedSectionOffsets.getClassesWithData().size());
+    this.codeLayout = ProgramMethodSet.createLinked(mixedSectionOffsets.getCodes().size());
+    this.encodedArrayLayout = new LinkedHashSet<>(mixedSectionOffsets.getEncodedArrays().size());
+    this.stringDataLayout = new LinkedHashSet<>(mixedSectionOffsets.getStringData().size());
+    this.typeListLayout = new LinkedHashSet<>(mixedSectionOffsets.getTypeLists().size());
+
+    // Add startup items to startup layouts.
+    collectStartupItems(virtualFile);
+  }
+
+  private void collectStartupItems(VirtualFile virtualFile) {
+    Map<DexType, DexProgramClass> virtualFileDefinitions =
+        MapUtils.newIdentityHashMap(
+            builder ->
+                virtualFile.classes().forEach(clazz -> builder.accept(clazz.getType(), clazz)),
+            virtualFile.classes().size());
+    LensCodeRewriterUtils rewriter = new LensCodeRewriterUtils(appView, true);
+    StartupIndexedItemCollection indexedItemCollection = new StartupIndexedItemCollection();
+    for (DexType startupClass : startupOrderForWriting.getClasses()) {
+      DexProgramClass definition = virtualFileDefinitions.get(startupClass);
+      if (definition != null) {
+        definition.collectIndexedItems(appView, indexedItemCollection, rewriter);
+      }
+    }
+  }
+
+  private static <T> Collection<T> amendStartupLayout(
+      Collection<T> startupLayout, Collection<T> defaultLayout) {
+    startupLayout.addAll(defaultLayout);
+    return startupLayout;
+  }
+
+  @Override
+  public Collection<DexAnnotation> getAnnotationLayout() {
+    return amendStartupLayout(annotationLayout, super.getAnnotationLayout());
+  }
+
+  @Override
+  public Collection<DexAnnotationDirectory> getAnnotationDirectoryLayout() {
+    return amendStartupLayout(annotationDirectoryLayout, super.getAnnotationDirectoryLayout());
+  }
+
+  @Override
+  public Collection<DexAnnotationSet> getAnnotationSetLayout() {
+    return amendStartupLayout(annotationSetLayout, super.getAnnotationSetLayout());
+  }
+
+  @Override
+  public Collection<ParameterAnnotationsList> getAnnotationSetRefListLayout() {
+    return amendStartupLayout(annotationSetRefListLayout, super.getAnnotationSetRefListLayout());
+  }
+
+  @Override
+  public Collection<DexProgramClass> getClassDataLayout() {
+    return amendStartupLayout(classDataLayout, super.getClassDataLayout());
+  }
+
+  @Override
+  public Collection<ProgramMethod> getCodeLayout() {
+    Set<DexProgramClass> nonStartupClasses =
+        new LinkedHashSet<>(mixedSectionOffsets.getClassesWithData());
+    nonStartupClasses.removeIf(clazz -> startupOrderForWriting.contains(clazz.getType()));
+    return amendStartupLayout(codeLayout, super.getCodeLayoutForClasses(nonStartupClasses));
+  }
+
+  @Override
+  public Collection<DexEncodedArray> getEncodedArrayLayout() {
+    return amendStartupLayout(encodedArrayLayout, super.getEncodedArrayLayout());
+  }
+
+  @Override
+  public Collection<DexString> getStringDataLayout() {
+    return amendStartupLayout(stringDataLayout, super.getStringDataLayout());
+  }
+
+  @Override
+  public Collection<DexTypeList> getTypeListLayout() {
+    return amendStartupLayout(typeListLayout, super.getTypeListLayout());
+  }
+
+  private class StartupIndexedItemCollection implements IndexedItemCollection {
+
+    private void addAnnotation(DexAnnotation annotation) {
+      annotationLayout.add(annotation);
+    }
+
+    private void addAnnotationSet(DexAnnotationSet annotationSet) {
+      if (appView.options().canHaveDalvikEmptyAnnotationSetBug() || !annotationSet.isEmpty()) {
+        annotationSetLayout.add(annotationSet);
+      }
+    }
+
+    private void addAnnotationSetRefList(ParameterAnnotationsList annotationSetRefList) {
+      if (!annotationSetRefList.isEmpty()) {
+        annotationSetRefListLayout.add(annotationSetRefList);
+      }
+    }
+
+    @Override
+    public boolean addClass(DexProgramClass clazz) {
+      if (clazz.hasMethodsOrFields()) {
+        classDataLayout.add(clazz);
+      }
+      addTypeList(clazz.getInterfaces());
+      clazz.forEachProgramMethodMatching(DexEncodedMethod::hasCode, codeLayout::add);
+      DexAnnotationDirectory annotationDirectory =
+          mixedSectionOffsets.getAnnotationDirectoryForClass(clazz);
+      if (annotationDirectory != null) {
+        annotationDirectoryLayout.add(annotationDirectory);
+        annotationDirectory.visitAnnotations(
+            this::addAnnotation, this::addAnnotationSet, this::addAnnotationSetRefList);
+      }
+      DexEncodedArray staticFieldValues = mixedSectionOffsets.getStaticFieldValuesForClass(clazz);
+      if (staticFieldValues != null) {
+        encodedArrayLayout.add(staticFieldValues);
+      }
+      return true;
+    }
+
+    @Override
+    public boolean addField(DexField field) {
+      return true;
+    }
+
+    @Override
+    public boolean addMethod(DexMethod method) {
+      return true;
+    }
+
+    @Override
+    public boolean addString(DexString string) {
+      return stringDataLayout.add(string);
+    }
+
+    @Override
+    public boolean addProto(DexProto proto) {
+      addTypeList(proto.getParameters());
+      return true;
+    }
+
+    @Override
+    public boolean addType(DexType type) {
+      return true;
+    }
+
+    private void addTypeList(DexTypeList typeList) {
+      if (!typeList.isEmpty()) {
+        typeListLayout.add(typeList);
+      }
+    }
+
+    @Override
+    public boolean addCallSite(DexCallSite callSite) {
+      encodedArrayLayout.add(callSite.getEncodedArray());
+      return true;
+    }
+
+    @Override
+    public boolean addMethodHandle(DexMethodHandle methodHandle) {
+      return true;
+    }
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/dex/VirtualFile.java b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
index d5995f4..80b9a6c 100644
--- a/src/main/java/com/android/tools/r8/dex/VirtualFile.java
+++ b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
@@ -79,38 +79,32 @@
   private final DexProgramClass primaryClass;
   private DebugRepresentation debugRepresentation;
 
-  VirtualFile(
-      int id,
-      AppView<?> appView,
-      NamingLens namingLens) {
-    this(id, appView, namingLens, null, null);
+  VirtualFile(int id, AppView<?> appView) {
+    this(id, appView, null, null);
   }
 
   VirtualFile(
       int id,
       AppView<?> appView,
-      NamingLens namingLens,
       FeatureSplit featureSplit) {
-    this(id, appView, namingLens, null, featureSplit);
+    this(id, appView, null, featureSplit);
   }
 
   private VirtualFile(
       int id,
       AppView<?> appView,
-      NamingLens namingLens,
       DexProgramClass primaryClass) {
-    this(id, appView, namingLens, primaryClass, null);
+    this(id, appView, primaryClass, null);
   }
 
   private VirtualFile(
       int id,
       AppView<?> appView,
-      NamingLens namingLens,
       DexProgramClass primaryClass,
       FeatureSplit featureSplit) {
     this.id = id;
-    this.indexedItems = new VirtualFileIndexedItemCollection(appView, namingLens);
-    this.transaction = new IndexedItemTransaction(indexedItems, appView, namingLens);
+    this.indexedItems = new VirtualFileIndexedItemCollection(appView);
+    this.transaction = new IndexedItemTransaction(indexedItems, appView);
     this.primaryClass = primaryClass;
     this.featureSplit = featureSplit;
   }
@@ -199,7 +193,6 @@
 
   public void computeMapping(
       AppView<?> appView,
-      NamingLens namingLens,
       int lazyDexStringsCount,
       Timing timing) {
     assert transaction.isEmpty();
@@ -207,7 +200,6 @@
     objectMapping =
         new ObjectToOffsetMapping(
             appView,
-            namingLens,
             transaction.rewriter,
             indexedItems.classes,
             indexedItems.protos,
@@ -326,8 +318,7 @@
         //  duplicated.
         if (!combineSyntheticClassesWithPrimaryClass
             || !appView.getSyntheticItems().isSyntheticClass(clazz)) {
-          VirtualFile file =
-              new VirtualFile(virtualFiles.size(), appView, writer.namingLens, clazz);
+          VirtualFile file = new VirtualFile(virtualFiles.size(), appView, clazz);
           virtualFiles.add(file);
           file.addClass(clazz);
           files.put(clazz, file);
@@ -365,7 +356,7 @@
       this.classes = SetUtils.newIdentityHashSet(classes);
 
       // Create the primary dex file. The distribution will add more if needed.
-      mainDexFile = new VirtualFile(0, appView, writer.namingLens);
+      mainDexFile = new VirtualFile(0, appView);
       assert virtualFiles.isEmpty();
       virtualFiles.add(mainDexFile);
       addMarkers(mainDexFile);
@@ -446,7 +437,6 @@
             new VirtualFile(
                 nextFileId.getAndIncrement(),
                 appView,
-                writer.namingLens,
                 featureSplitSetEntry.getKey());
         virtualFiles.add(featureFile);
         addMarkers(featureFile);
@@ -458,8 +448,7 @@
                 appView,
                 featureSplitSetEntry.getValue(),
                 originalNames,
-                nextFileId,
-                writer.namingLens)
+                nextFileId)
             .run();
       }
     }
@@ -510,19 +499,12 @@
                 filesForDistribution,
                 classes,
                 nextFileId,
-                writer.namingLens,
                 appView,
                 executorService)
             .distribute();
       } else {
         new PackageSplitPopulator(
-                virtualFiles,
-                filesForDistribution,
-                appView,
-                classes,
-                originalNames,
-                nextFileId,
-                writer.namingLens)
+                virtualFiles, filesForDistribution, appView, classes, originalNames, nextFileId)
             .run();
       }
       addFeatureSplitFiles(featureSplitClasses);
@@ -573,10 +555,10 @@
     private final Set<DexCallSite> callSites = Sets.newIdentityHashSet();
     private final Set<DexMethodHandle> methodHandles = Sets.newIdentityHashSet();
 
-    public VirtualFileIndexedItemCollection(AppView<?> appView, NamingLens namingLens) {
+    public VirtualFileIndexedItemCollection(AppView<?> appView) {
       this.graphLens = appView.graphLens();
       this.initClassLens = appView.initClassLens();
-      this.namingLens = namingLens;
+      this.namingLens = appView.getNamingLens();
     }
 
     @Override
@@ -627,45 +609,12 @@
     int getNumberOfFields() {
       return fields.size();
     }
-
-    int getNumberOfStrings() {
-      return strings.size();
-    }
-
-    @Override
-    public GraphLens getGraphLens() {
-      return graphLens;
-    }
-
-    @Override
-    public InitClassLens getInitClassLens() {
-      return initClassLens;
-    }
-
-    @Override
-    public DexString getRenamedDescriptor(DexType type) {
-      return namingLens.lookupDescriptor(type);
-    }
-
-    @Override
-    public DexString getRenamedName(DexMethod method) {
-      DexMethod mappedMethod = graphLens.lookupMethod(method);
-      assert namingLens.verifyRenamingConsistentWithResolution(mappedMethod);
-      return namingLens.lookupName(mappedMethod);
-    }
-
-    @Override
-    public DexString getRenamedName(DexField field) {
-      return namingLens.lookupName(graphLens.lookupField(field));
-    }
   }
 
   public static class IndexedItemTransaction implements IndexedItemCollection {
 
     private final AppView<?> appView;
     private final VirtualFileIndexedItemCollection base;
-    private final InitClassLens initClassLens;
-    private final NamingLens namingLens;
     private final LensCodeRewriterUtils rewriter;
 
     private final Set<DexProgramClass> classes = new LinkedHashSet<>();
@@ -677,17 +626,16 @@
     private final Set<DexCallSite> callSites = new LinkedHashSet<>();
     private final Set<DexMethodHandle> methodHandles = new LinkedHashSet<>();
 
-    private IndexedItemTransaction(
-        VirtualFileIndexedItemCollection base,
-        AppView<?> appView,
-        NamingLens namingLens) {
+    private IndexedItemTransaction(VirtualFileIndexedItemCollection base, AppView<?> appView) {
       this.appView = appView;
       this.base = base;
-      this.initClassLens = appView.initClassLens();
-      this.namingLens = namingLens;
       this.rewriter = new LensCodeRewriterUtils(appView, true);
     }
 
+    private NamingLens getNamingLens() {
+      return appView.getNamingLens();
+    }
+
     private <T extends DexItem> boolean maybeInsert(T item, Set<T> set, Set<T> baseSet) {
       if (baseSet.contains(item) || set.contains(item)) {
         return false;
@@ -697,7 +645,7 @@
     }
 
     void addClassAndDependencies(DexProgramClass clazz) {
-      clazz.collectIndexedItems(this, getGraphLens(), rewriter);
+      clazz.collectIndexedItems(appView, this, rewriter);
     }
 
     @Override
@@ -741,32 +689,6 @@
       return maybeInsert(methodHandle, methodHandles, base.methodHandles);
     }
 
-    @Override
-    public GraphLens getGraphLens() {
-      return appView.graphLens();
-    }
-
-    @Override
-    public InitClassLens getInitClassLens() {
-      return initClassLens;
-    }
-
-    @Override
-    public DexString getRenamedDescriptor(DexType type) {
-      return namingLens.lookupDescriptor(type);
-    }
-
-    @Override
-    public DexString getRenamedName(DexMethod method) {
-      assert namingLens.verifyRenamingConsistentWithResolution(method);
-      return namingLens.lookupName(method);
-    }
-
-    @Override
-    public DexString getRenamedName(DexField field) {
-      return namingLens.lookupName(field);
-    }
-
     int getNumberOfMethods() {
       return methods.size() + base.getNumberOfMethods();
     }
@@ -830,7 +752,6 @@
     private final List<VirtualFile> files;
     private final List<VirtualFile> filesForDistribution;
     private final AppView<?> appView;
-    private final NamingLens namingLens;
 
     private final IntBox nextFileId;
     private Iterator<VirtualFile> allFilesCyclic;
@@ -841,12 +762,10 @@
         List<VirtualFile> files,
         List<VirtualFile> filesForDistribution,
         AppView<?> appView,
-        NamingLens namingLens,
         IntBox nextFileId) {
       this.files = files;
       this.filesForDistribution = new ArrayList<>(filesForDistribution);
       this.appView = appView;
-      this.namingLens = namingLens;
       this.nextFileId = nextFileId;
 
       if (filesForDistribution.size() > 0) {
@@ -917,8 +836,7 @@
     }
 
     private VirtualFile internalAddFile() {
-      VirtualFile newFile =
-          new VirtualFile(nextFileId.getAndIncrement(), appView, namingLens, featureSplit);
+      VirtualFile newFile = new VirtualFile(nextFileId.getAndIncrement(), appView, featureSplit);
       files.add(newFile);
       filesForDistribution.add(newFile);
       return newFile;
@@ -1061,14 +979,12 @@
         AppView<?> appView,
         Collection<DexProgramClass> classes,
         Map<DexProgramClass, String> originalNames,
-        IntBox nextFileId,
-        NamingLens namingLens) {
+        IntBox nextFileId) {
       this.classPartioning = PackageSplitClassPartioning.create(classes, appView, originalNames);
       this.originalNames = originalNames;
       this.dexItemFactory = appView.dexItemFactory();
       this.options = appView.options();
-      this.cycler =
-          new VirtualFileCycler(files, filesForDistribution, appView, namingLens, nextFileId);
+      this.cycler = new VirtualFileCycler(files, filesForDistribution, appView, nextFileId);
     }
 
     static boolean coveredByPrefix(String originalName, String currentPrefix) {
diff --git a/src/main/java/com/android/tools/r8/code/BytecodeStream.java b/src/main/java/com/android/tools/r8/dex/code/BytecodeStream.java
similarity index 87%
rename from src/main/java/com/android/tools/r8/code/BytecodeStream.java
rename to src/main/java/com/android/tools/r8/dex/code/BytecodeStream.java
index e928c3e..da1e31a 100644
--- a/src/main/java/com/android/tools/r8/code/BytecodeStream.java
+++ b/src/main/java/com/android/tools/r8/dex/code/BytecodeStream.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 public interface BytecodeStream {
 
@@ -23,7 +23,7 @@
    * Returns the next byte value from the stream, i.e., the high value of the next short followed by
    * the low value.
    *
-   * Both bytes need to be consumed before the next call to {@link #nextShort()}.
+   * <p>Both bytes need to be consumed before the next call to {@link #nextShort()}.
    *
    * @return next byte value in the stream.
    */
diff --git a/src/main/java/com/android/tools/r8/code/CfOrDexInstanceFieldRead.java b/src/main/java/com/android/tools/r8/dex/code/CfOrDexInstanceFieldRead.java
similarity index 89%
rename from src/main/java/com/android/tools/r8/code/CfOrDexInstanceFieldRead.java
rename to src/main/java/com/android/tools/r8/dex/code/CfOrDexInstanceFieldRead.java
index 3d560fc..4d4d9bc 100644
--- a/src/main/java/com/android/tools/r8/code/CfOrDexInstanceFieldRead.java
+++ b/src/main/java/com/android/tools/r8/dex/code/CfOrDexInstanceFieldRead.java
@@ -2,7 +2,7 @@
 // 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexField;
 
diff --git a/src/main/java/com/android/tools/r8/code/CfOrDexInstruction.java b/src/main/java/com/android/tools/r8/dex/code/CfOrDexInstruction.java
similarity index 83%
rename from src/main/java/com/android/tools/r8/code/CfOrDexInstruction.java
rename to src/main/java/com/android/tools/r8/dex/code/CfOrDexInstruction.java
index e8ac111..7bd1e7a 100644
--- a/src/main/java/com/android/tools/r8/code/CfOrDexInstruction.java
+++ b/src/main/java/com/android/tools/r8/dex/code/CfOrDexInstruction.java
@@ -2,7 +2,7 @@
 // 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.cf.code.CfInstruction;
 
@@ -12,5 +12,5 @@
 
   boolean isCfInstruction();
 
-  Instruction asDexInstruction();
+  DexInstruction asDexInstruction();
 }
diff --git a/src/main/java/com/android/tools/r8/code/CfOrDexStaticFieldRead.java b/src/main/java/com/android/tools/r8/dex/code/CfOrDexStaticFieldRead.java
similarity index 89%
rename from src/main/java/com/android/tools/r8/code/CfOrDexStaticFieldRead.java
rename to src/main/java/com/android/tools/r8/dex/code/CfOrDexStaticFieldRead.java
index 121023a..513543c 100644
--- a/src/main/java/com/android/tools/r8/code/CfOrDexStaticFieldRead.java
+++ b/src/main/java/com/android/tools/r8/dex/code/CfOrDexStaticFieldRead.java
@@ -2,7 +2,7 @@
 // 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexField;
 
diff --git a/src/main/java/com/android/tools/r8/code/AddDouble.java b/src/main/java/com/android/tools/r8/dex/code/DexAddDouble.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/AddDouble.java
rename to src/main/java/com/android/tools/r8/dex/code/DexAddDouble.java
index ce962e2..d78dcbd 100644
--- a/src/main/java/com/android/tools/r8/code/AddDouble.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexAddDouble.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class AddDouble extends Format23x {
+
+public class DexAddDouble extends DexFormat23x {
 
   public static final int OPCODE = 0xab;
   public static final String NAME = "AddDouble";
   public static final String SMALI_NAME = "add-double";
 
-  AddDouble(int high, BytecodeStream stream) {
+  DexAddDouble(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public AddDouble(int dest, int left, int right) {
+  public DexAddDouble(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/AddDouble2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexAddDouble2Addr.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/AddDouble2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexAddDouble2Addr.java
index a5a907b..c641b5f 100644
--- a/src/main/java/com/android/tools/r8/code/AddDouble2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexAddDouble2Addr.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class AddDouble2Addr extends Format12x {
+
+public class DexAddDouble2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xcb;
   public static final String NAME = "AddDouble2Addr";
   public static final String SMALI_NAME = "add-double/2addr";
 
-  AddDouble2Addr(int high, BytecodeStream stream) {
+  DexAddDouble2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public AddDouble2Addr(int left, int right) {
+  public DexAddDouble2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/AddFloat.java b/src/main/java/com/android/tools/r8/dex/code/DexAddFloat.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/AddFloat.java
rename to src/main/java/com/android/tools/r8/dex/code/DexAddFloat.java
index 2d255ea..e745b30 100644
--- a/src/main/java/com/android/tools/r8/code/AddFloat.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexAddFloat.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class AddFloat extends Format23x {
+public class DexAddFloat extends DexFormat23x {
 
   public static final int OPCODE = 0xa6;
   public static final String NAME = "AddFloat";
   public static final String SMALI_NAME = "add-float";
 
-  AddFloat(int high, BytecodeStream stream) {
+  DexAddFloat(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public AddFloat(int dest, int left, int right) {
+  public DexAddFloat(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/AddFloat2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexAddFloat2Addr.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/AddFloat2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexAddFloat2Addr.java
index 0fb4691..e232cae 100644
--- a/src/main/java/com/android/tools/r8/code/AddFloat2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexAddFloat2Addr.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class AddFloat2Addr extends Format12x {
+public class DexAddFloat2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xc6;
   public static final String NAME = "AddFloat2Addr";
   public static final String SMALI_NAME = "add-float/2addr";
 
-  AddFloat2Addr(int high, BytecodeStream stream) {
+  DexAddFloat2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public AddFloat2Addr(int left, int right) {
+  public DexAddFloat2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/AddInt.java b/src/main/java/com/android/tools/r8/dex/code/DexAddInt.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/AddInt.java
rename to src/main/java/com/android/tools/r8/dex/code/DexAddInt.java
index ba05bbf..b9e3d75 100644
--- a/src/main/java/com/android/tools/r8/code/AddInt.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexAddInt.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class AddInt extends Format23x {
+public class DexAddInt extends DexFormat23x {
 
   public static final int OPCODE = 0x90;
   public static final String NAME = "AddInt";
   public static final String SMALI_NAME = "add-int";
 
-  AddInt(int high, BytecodeStream stream) {
+  DexAddInt(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public AddInt(int dest, int left, int right) {
+  public DexAddInt(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/AddInt2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexAddInt2Addr.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/AddInt2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexAddInt2Addr.java
index 1d50caf..cc38583 100644
--- a/src/main/java/com/android/tools/r8/code/AddInt2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexAddInt2Addr.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class AddInt2Addr extends Format12x {
+public class DexAddInt2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xb0;
   public static final String NAME = "AddInt2Addr";
   public static final String SMALI_NAME = "add-int/2addr";
 
-  AddInt2Addr(int high, BytecodeStream stream) {
+  DexAddInt2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public AddInt2Addr(int left, int right) {
+  public DexAddInt2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/AddIntLit16.java b/src/main/java/com/android/tools/r8/dex/code/DexAddIntLit16.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/AddIntLit16.java
rename to src/main/java/com/android/tools/r8/dex/code/DexAddIntLit16.java
index c05f238..07e6e6a 100644
--- a/src/main/java/com/android/tools/r8/code/AddIntLit16.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexAddIntLit16.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class AddIntLit16 extends Format22s {
+public class DexAddIntLit16 extends DexFormat22s {
 
   public static final int OPCODE = 0xd0;
   public static final String NAME = "AddIntLit16";
   public static final String SMALI_NAME = "add-int/lit16";
 
-  AddIntLit16(int high, BytecodeStream stream) {
+  DexAddIntLit16(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public AddIntLit16(int dest, int register, int constant) {
+  public DexAddIntLit16(int dest, int register, int constant) {
     super(dest, register, constant);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/AddIntLit8.java b/src/main/java/com/android/tools/r8/dex/code/DexAddIntLit8.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/AddIntLit8.java
rename to src/main/java/com/android/tools/r8/dex/code/DexAddIntLit8.java
index 8715c06..8093253 100644
--- a/src/main/java/com/android/tools/r8/code/AddIntLit8.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexAddIntLit8.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class AddIntLit8 extends Format22b {
+public class DexAddIntLit8 extends DexFormat22b {
 
   public static final int OPCODE = 0xd8;
   public static final String NAME = "AddIntLit8";
   public static final String SMALI_NAME = "add-int/lit8";
 
-  AddIntLit8(int high, BytecodeStream stream) {
+  DexAddIntLit8(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public AddIntLit8(int dest, int register, int constant) {
+  public DexAddIntLit8(int dest, int register, int constant) {
     super(dest, register, constant);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/AddLong.java b/src/main/java/com/android/tools/r8/dex/code/DexAddLong.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/AddLong.java
rename to src/main/java/com/android/tools/r8/dex/code/DexAddLong.java
index f3a6e3f..dbb0094 100644
--- a/src/main/java/com/android/tools/r8/code/AddLong.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexAddLong.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class AddLong extends Format23x {
+
+public class DexAddLong extends DexFormat23x {
 
   public static final int OPCODE = 0x9b;
   public static final String NAME = "AddLong";
   public static final String SMALI_NAME = "add-long";
 
-  AddLong(int high, BytecodeStream stream) {
+  DexAddLong(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public AddLong(int dest, int left, int right) {
+  public DexAddLong(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/AddLong2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexAddLong2Addr.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/AddLong2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexAddLong2Addr.java
index 72cb8e6..0d93f58 100644
--- a/src/main/java/com/android/tools/r8/code/AddLong2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexAddLong2Addr.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class AddLong2Addr extends Format12x {
+
+public class DexAddLong2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xbb;
   public static final String NAME = "AddLong2Addr";
   public static final String SMALI_NAME = "add-long/2addr";
 
-  AddLong2Addr(int high, BytecodeStream stream) {
+  DexAddLong2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public AddLong2Addr(int left, int right) {
+  public DexAddLong2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/Aget.java b/src/main/java/com/android/tools/r8/dex/code/DexAget.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/Aget.java
rename to src/main/java/com/android/tools/r8/dex/code/DexAget.java
index 063df5e..71f365b 100644
--- a/src/main/java/com/android/tools/r8/code/Aget.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexAget.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.MemberType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class Aget extends Format23x {
+public class DexAget extends DexFormat23x {
 
   public static final int OPCODE = 0x44;
   public static final String NAME = "Aget";
   public static final String SMALI_NAME = "aget";
 
-  /*package*/ Aget(int high, BytecodeStream stream) {
+  /*package*/ DexAget(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public Aget(int AA, int BB, int CC) {
+  public DexAget(int AA, int BB, int CC) {
     super(AA, BB, CC);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/AgetBoolean.java b/src/main/java/com/android/tools/r8/dex/code/DexAgetBoolean.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/AgetBoolean.java
rename to src/main/java/com/android/tools/r8/dex/code/DexAgetBoolean.java
index fc05007..e969298 100644
--- a/src/main/java/com/android/tools/r8/code/AgetBoolean.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexAgetBoolean.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.MemberType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class AgetBoolean extends Format23x {
+public class DexAgetBoolean extends DexFormat23x {
 
   public static final int OPCODE = 0x47;
   public static final String NAME = "AgetBoolean";
   public static final String SMALI_NAME = "aget-boolean";
 
-  AgetBoolean(int high, BytecodeStream stream) {
+  DexAgetBoolean(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public AgetBoolean(int AA, int BB, int CC) {
+  public DexAgetBoolean(int AA, int BB, int CC) {
     super(AA, BB, CC);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/AgetByte.java b/src/main/java/com/android/tools/r8/dex/code/DexAgetByte.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/AgetByte.java
rename to src/main/java/com/android/tools/r8/dex/code/DexAgetByte.java
index f7bc165..addb35e 100644
--- a/src/main/java/com/android/tools/r8/code/AgetByte.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexAgetByte.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.MemberType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class AgetByte extends Format23x {
+public class DexAgetByte extends DexFormat23x {
 
   public static final int OPCODE = 0x48;
   public static final String NAME = "AgetByte";
   public static final String SMALI_NAME = "aget-byte";
 
-  /*package*/ AgetByte(int high, BytecodeStream stream) {
+  /*package*/ DexAgetByte(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public AgetByte(int AA, int BB, int CC) {
+  public DexAgetByte(int AA, int BB, int CC) {
     super(AA, BB, CC);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/AgetChar.java b/src/main/java/com/android/tools/r8/dex/code/DexAgetChar.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/AgetChar.java
rename to src/main/java/com/android/tools/r8/dex/code/DexAgetChar.java
index fc7804e..ed8ac21 100644
--- a/src/main/java/com/android/tools/r8/code/AgetChar.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexAgetChar.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.MemberType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class AgetChar extends Format23x {
+public class DexAgetChar extends DexFormat23x {
 
   public static final int OPCODE = 0x49;
   public static final String NAME = "AgetChar";
   public static final String SMALI_NAME = "aget-char";
 
-  /*package*/ AgetChar(int high, BytecodeStream stream) {
+  /*package*/ DexAgetChar(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public AgetChar(int AA, int BB, int CC) {
+  public DexAgetChar(int AA, int BB, int CC) {
     super(AA, BB, CC);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/AgetObject.java b/src/main/java/com/android/tools/r8/dex/code/DexAgetObject.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/AgetObject.java
rename to src/main/java/com/android/tools/r8/dex/code/DexAgetObject.java
index 1574602..8cbedda 100644
--- a/src/main/java/com/android/tools/r8/code/AgetObject.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexAgetObject.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.MemberType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class AgetObject extends Format23x {
+
+public class DexAgetObject extends DexFormat23x {
 
   public static final int OPCODE = 0x46;
   public static final String NAME = "AgetObject";
   public static final String SMALI_NAME = "aget-object";
 
-  AgetObject(int high, BytecodeStream stream) {
+  DexAgetObject(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public AgetObject(int AA, int BB, int CC) {
+  public DexAgetObject(int AA, int BB, int CC) {
     super(AA, BB, CC);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/AgetShort.java b/src/main/java/com/android/tools/r8/dex/code/DexAgetShort.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/AgetShort.java
rename to src/main/java/com/android/tools/r8/dex/code/DexAgetShort.java
index d7fb45a..fd887b1 100644
--- a/src/main/java/com/android/tools/r8/code/AgetShort.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexAgetShort.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.MemberType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class AgetShort extends Format23x {
+public class DexAgetShort extends DexFormat23x {
 
   public static final int OPCODE = 0x4a;
   public static final String NAME = "AgetShort";
   public static final String SMALI_NAME = "aget-short";
 
-  AgetShort(int high, BytecodeStream stream) {
+  DexAgetShort(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public AgetShort(int AA, int BB, int CC) {
+  public DexAgetShort(int AA, int BB, int CC) {
     super(AA, BB, CC);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/AgetWide.java b/src/main/java/com/android/tools/r8/dex/code/DexAgetWide.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/AgetWide.java
rename to src/main/java/com/android/tools/r8/dex/code/DexAgetWide.java
index 64c645d..59a0923 100644
--- a/src/main/java/com/android/tools/r8/code/AgetWide.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexAgetWide.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.MemberType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class AgetWide extends Format23x {
+public class DexAgetWide extends DexFormat23x {
 
   public static final int OPCODE = 0x45;
   public static final String NAME = "AgetWide";
   public static final String SMALI_NAME = "aget-wide";
 
-  /*package*/ AgetWide(int high, BytecodeStream stream) {
+  /*package*/ DexAgetWide(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public AgetWide(int AA, int BB, int CC) {
+  public DexAgetWide(int AA, int BB, int CC) {
     super(AA, BB, CC);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/AndInt.java b/src/main/java/com/android/tools/r8/dex/code/DexAndInt.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/AndInt.java
rename to src/main/java/com/android/tools/r8/dex/code/DexAndInt.java
index 532e657..7050380 100644
--- a/src/main/java/com/android/tools/r8/code/AndInt.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexAndInt.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class AndInt extends Format23x {
+public class DexAndInt extends DexFormat23x {
 
   public static final int OPCODE = 0x95;
   public static final String NAME = "AndInt";
   public static final String SMALI_NAME = "and-int";
 
-  AndInt(int high, BytecodeStream stream) {
+  DexAndInt(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public AndInt(int dest, int left, int right) {
+  public DexAndInt(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/AndInt2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexAndInt2Addr.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/AndInt2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexAndInt2Addr.java
index ad29884..8eba630 100644
--- a/src/main/java/com/android/tools/r8/code/AndInt2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexAndInt2Addr.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class AndInt2Addr extends Format12x {
+public class DexAndInt2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xb5;
   public static final String NAME = "AndInt2Addr";
   public static final String SMALI_NAME = "and-int/2addr";
 
-  AndInt2Addr(int high, BytecodeStream stream) {
+  DexAndInt2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public AndInt2Addr(int left, int right) {
+  public DexAndInt2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/AndIntLit16.java b/src/main/java/com/android/tools/r8/dex/code/DexAndIntLit16.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/AndIntLit16.java
rename to src/main/java/com/android/tools/r8/dex/code/DexAndIntLit16.java
index 8dc59d5..fd68e93 100644
--- a/src/main/java/com/android/tools/r8/code/AndIntLit16.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexAndIntLit16.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class AndIntLit16 extends Format22s {
+public class DexAndIntLit16 extends DexFormat22s {
 
   public static final int OPCODE = 0xd5;
   public static final String NAME = "AndIntLit16";
   public static final String SMALI_NAME = "and-int/lit16";
 
-  AndIntLit16(int high, BytecodeStream stream) {
+  DexAndIntLit16(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public AndIntLit16(int dest, int left, int constant) {
+  public DexAndIntLit16(int dest, int left, int constant) {
     super(dest, left, constant);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/AndIntLit8.java b/src/main/java/com/android/tools/r8/dex/code/DexAndIntLit8.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/AndIntLit8.java
rename to src/main/java/com/android/tools/r8/dex/code/DexAndIntLit8.java
index a347b70..18778c6 100644
--- a/src/main/java/com/android/tools/r8/code/AndIntLit8.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexAndIntLit8.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class AndIntLit8 extends Format22b {
+
+public class DexAndIntLit8 extends DexFormat22b {
 
   public static final int OPCODE = 0xdd;
   public static final String NAME = "AndIntLit8";
   public static final String SMALI_NAME = "and-int/lit8";
 
-  AndIntLit8(int high, BytecodeStream stream) {
+  DexAndIntLit8(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public AndIntLit8(int dest, int left, int constant) {
+  public DexAndIntLit8(int dest, int left, int constant) {
     super(dest, left, constant);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/AndLong.java b/src/main/java/com/android/tools/r8/dex/code/DexAndLong.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/AndLong.java
rename to src/main/java/com/android/tools/r8/dex/code/DexAndLong.java
index 0bc3eaa..5458217 100644
--- a/src/main/java/com/android/tools/r8/code/AndLong.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexAndLong.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class AndLong extends Format23x {
+public class DexAndLong extends DexFormat23x {
 
   public static final int OPCODE = 0xA0;
   public static final String NAME = "AndLong";
   public static final String SMALI_NAME = "and-long";
 
-  AndLong(int high, BytecodeStream stream) {
+  DexAndLong(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public AndLong(int dest, int left, int right) {
+  public DexAndLong(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/AndLong2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexAndLong2Addr.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/AndLong2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexAndLong2Addr.java
index 276a814..73babe5 100644
--- a/src/main/java/com/android/tools/r8/code/AndLong2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexAndLong2Addr.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class AndLong2Addr extends Format12x {
+
+public class DexAndLong2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xc0;
   public static final String NAME = "AndLong2Addr";
   public static final String SMALI_NAME = "and-long/2addr";
 
-  AndLong2Addr(int high, BytecodeStream stream) {
+  DexAndLong2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public AndLong2Addr(int left, int right) {
+  public DexAndLong2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/Aput.java b/src/main/java/com/android/tools/r8/dex/code/DexAput.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/Aput.java
rename to src/main/java/com/android/tools/r8/dex/code/DexAput.java
index 65e0721..c5b1e1a 100644
--- a/src/main/java/com/android/tools/r8/code/Aput.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexAput.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.MemberType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class Aput extends Format23x {
+public class DexAput extends DexFormat23x {
 
   public static final int OPCODE = 0x4b;
   public static final String NAME = "Aput";
   public static final String SMALI_NAME = "aput";
 
-  /*package*/ Aput(int high, BytecodeStream stream) {
+  /*package*/ DexAput(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public Aput(int AA, int BB, int CC) {
+  public DexAput(int AA, int BB, int CC) {
     super(AA, BB, CC);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/AputBoolean.java b/src/main/java/com/android/tools/r8/dex/code/DexAputBoolean.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/AputBoolean.java
rename to src/main/java/com/android/tools/r8/dex/code/DexAputBoolean.java
index ac64012..78d70a2 100644
--- a/src/main/java/com/android/tools/r8/code/AputBoolean.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexAputBoolean.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.MemberType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class AputBoolean extends Format23x {
+public class DexAputBoolean extends DexFormat23x {
 
   public static final int OPCODE = 0x4e;
   public static final String NAME = "AputBoolean";
   public static final String SMALI_NAME = "aput-boolean";
 
-  /*package*/ AputBoolean(int high, BytecodeStream stream) {
+  /*package*/ DexAputBoolean(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public AputBoolean(int AA, int BB, int CC) {
+  public DexAputBoolean(int AA, int BB, int CC) {
     super(AA, BB, CC);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/AputByte.java b/src/main/java/com/android/tools/r8/dex/code/DexAputByte.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/AputByte.java
rename to src/main/java/com/android/tools/r8/dex/code/DexAputByte.java
index 1d439c6..04def29 100644
--- a/src/main/java/com/android/tools/r8/code/AputByte.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexAputByte.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.MemberType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class AputByte extends Format23x {
+public class DexAputByte extends DexFormat23x {
 
   public static final int OPCODE = 0x4f;
   public static final String NAME = "AputByte";
   public static final String SMALI_NAME = "aput-byte";
 
-  /*package*/ AputByte(int high, BytecodeStream stream) {
+  /*package*/ DexAputByte(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public AputByte(int AA, int BB, int CC) {
+  public DexAputByte(int AA, int BB, int CC) {
     super(AA, BB, CC);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/AputChar.java b/src/main/java/com/android/tools/r8/dex/code/DexAputChar.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/AputChar.java
rename to src/main/java/com/android/tools/r8/dex/code/DexAputChar.java
index 14e408c..0f66bfa 100644
--- a/src/main/java/com/android/tools/r8/code/AputChar.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexAputChar.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.MemberType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class AputChar extends Format23x {
+public class DexAputChar extends DexFormat23x {
 
   public static final int OPCODE = 0x50;
   public static final String NAME = "AputChar";
   public static final String SMALI_NAME = "aput-char";
 
-  /*package*/ AputChar(int high, BytecodeStream stream) {
+  /*package*/ DexAputChar(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public AputChar(int AA, int BB, int CC) {
+  public DexAputChar(int AA, int BB, int CC) {
     super(AA, BB, CC);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/AputObject.java b/src/main/java/com/android/tools/r8/dex/code/DexAputObject.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/AputObject.java
rename to src/main/java/com/android/tools/r8/dex/code/DexAputObject.java
index bcfea78..3012172 100644
--- a/src/main/java/com/android/tools/r8/code/AputObject.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexAputObject.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.MemberType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class AputObject extends Format23x {
+public class DexAputObject extends DexFormat23x {
 
   public static final int OPCODE = 0x4d;
   public static final String NAME = "AputObject";
   public static final String SMALI_NAME = "aput-object";
 
-  /*package*/ AputObject(int high, BytecodeStream stream) {
+  /*package*/ DexAputObject(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public AputObject(int AA, int BB, int CC) {
+  public DexAputObject(int AA, int BB, int CC) {
     super(AA, BB, CC);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/AputShort.java b/src/main/java/com/android/tools/r8/dex/code/DexAputShort.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/AputShort.java
rename to src/main/java/com/android/tools/r8/dex/code/DexAputShort.java
index daf9b4a..6a3173e 100644
--- a/src/main/java/com/android/tools/r8/code/AputShort.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexAputShort.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.MemberType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class AputShort extends Format23x {
+public class DexAputShort extends DexFormat23x {
 
   public static final int OPCODE = 0x51;
   public static final String NAME = "AputShort";
   public static final String SMALI_NAME = "aput-short";
 
-  /*package*/ AputShort(int high, BytecodeStream stream) {
+  /*package*/ DexAputShort(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public AputShort(int AA, int BB, int CC) {
+  public DexAputShort(int AA, int BB, int CC) {
     super(AA, BB, CC);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/AputWide.java b/src/main/java/com/android/tools/r8/dex/code/DexAputWide.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/AputWide.java
rename to src/main/java/com/android/tools/r8/dex/code/DexAputWide.java
index 286dfff..adf0e40 100644
--- a/src/main/java/com/android/tools/r8/code/AputWide.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexAputWide.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.MemberType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class AputWide extends Format23x {
+public class DexAputWide extends DexFormat23x {
 
   public static final int OPCODE = 0x4c;
   public static final String NAME = "AputWide";
   public static final String SMALI_NAME = "aput-wide";
 
-  /*package*/ AputWide(int high, BytecodeStream stream) {
+  /*package*/ DexAputWide(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public AputWide(int AA, int BB, int CC) {
+  public DexAputWide(int AA, int BB, int CC) {
     super(AA, BB, CC);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/ArrayLength.java b/src/main/java/com/android/tools/r8/dex/code/DexArrayLength.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/ArrayLength.java
rename to src/main/java/com/android/tools/r8/dex/code/DexArrayLength.java
index 156df49..543ab01 100644
--- a/src/main/java/com/android/tools/r8/code/ArrayLength.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexArrayLength.java
@@ -1,21 +1,21 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class ArrayLength extends Format12x {
+public class DexArrayLength extends DexFormat12x {
 
   public static final int OPCODE = 0x21;
   public static final String NAME = "ArrayLength";
   public static final String SMALI_NAME = "array-length";
 
-  ArrayLength(int high, BytecodeStream stream) {
+  DexArrayLength(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public ArrayLength(int dest, int array) {
+  public DexArrayLength(int dest, int array) {
     super(dest, array);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/Base1Format.java b/src/main/java/com/android/tools/r8/dex/code/DexBase1Format.java
similarity index 64%
rename from src/main/java/com/android/tools/r8/code/Base1Format.java
rename to src/main/java/com/android/tools/r8/dex/code/DexBase1Format.java
index 09c4bc8..eaea826 100644
--- a/src/main/java/com/android/tools/r8/code/Base1Format.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexBase1Format.java
@@ -1,17 +1,17 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
-public abstract class Base1Format extends Instruction {
+public abstract class DexBase1Format extends DexInstruction {
 
   public static final int SIZE = 1;
 
-  public Base1Format(BytecodeStream stream) {
+  public DexBase1Format(BytecodeStream stream) {
     super(stream);
   }
 
-  protected Base1Format() {}
+  protected DexBase1Format() {}
 
   @Override
   public int getSize() {
diff --git a/src/main/java/com/android/tools/r8/code/Base2Format.java b/src/main/java/com/android/tools/r8/dex/code/DexBase2Format.java
similarity index 64%
rename from src/main/java/com/android/tools/r8/code/Base2Format.java
rename to src/main/java/com/android/tools/r8/dex/code/DexBase2Format.java
index 7d8e51e..abc2ee2 100644
--- a/src/main/java/com/android/tools/r8/code/Base2Format.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexBase2Format.java
@@ -1,15 +1,15 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
-public abstract class Base2Format extends Instruction {
+public abstract class DexBase2Format extends DexInstruction {
 
   public static final int SIZE = 2;
 
-  protected Base2Format() {}
+  protected DexBase2Format() {}
 
-  public Base2Format(BytecodeStream stream) {
+  public DexBase2Format(BytecodeStream stream) {
     super(stream);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/Base3Format.java b/src/main/java/com/android/tools/r8/dex/code/DexBase3Format.java
similarity index 64%
rename from src/main/java/com/android/tools/r8/code/Base3Format.java
rename to src/main/java/com/android/tools/r8/dex/code/DexBase3Format.java
index 62d6824..e78d48d 100644
--- a/src/main/java/com/android/tools/r8/code/Base3Format.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexBase3Format.java
@@ -1,15 +1,15 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
-public abstract class Base3Format extends Instruction {
+public abstract class DexBase3Format extends DexInstruction {
 
   public static final int SIZE = 3;
 
-  protected Base3Format() {}
+  protected DexBase3Format() {}
 
-  public Base3Format(BytecodeStream stream) {
+  public DexBase3Format(BytecodeStream stream) {
     super(stream);
   }
 
@@ -17,4 +17,4 @@
   public int getSize() {
     return SIZE;
   }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/android/tools/r8/code/Base4Format.java b/src/main/java/com/android/tools/r8/dex/code/DexBase4Format.java
similarity index 64%
rename from src/main/java/com/android/tools/r8/code/Base4Format.java
rename to src/main/java/com/android/tools/r8/dex/code/DexBase4Format.java
index a08411f..ea206fe 100644
--- a/src/main/java/com/android/tools/r8/code/Base4Format.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexBase4Format.java
@@ -1,15 +1,15 @@
 // Copyright (c) 2017, 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.code;
+package com.android.tools.r8.dex.code;
 
-public abstract class Base4Format extends Instruction {
+public abstract class DexBase4Format extends DexInstruction {
 
   public static final int SIZE = 4;
 
-  protected Base4Format() {}
+  protected DexBase4Format() {}
 
-  public Base4Format(BytecodeStream stream) {
+  public DexBase4Format(BytecodeStream stream) {
     super(stream);
   }
 
@@ -17,4 +17,4 @@
   public int getSize() {
     return SIZE;
   }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/android/tools/r8/code/Base5Format.java b/src/main/java/com/android/tools/r8/dex/code/DexBase5Format.java
similarity index 64%
rename from src/main/java/com/android/tools/r8/code/Base5Format.java
rename to src/main/java/com/android/tools/r8/dex/code/DexBase5Format.java
index 093e932..207129d 100644
--- a/src/main/java/com/android/tools/r8/code/Base5Format.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexBase5Format.java
@@ -1,15 +1,15 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
-public abstract class Base5Format extends Instruction {
+public abstract class DexBase5Format extends DexInstruction {
 
   public static final int SIZE = 5;
 
-  protected Base5Format() {}
+  protected DexBase5Format() {}
 
-  public Base5Format(BytecodeStream stream) {
+  public DexBase5Format(BytecodeStream stream) {
     super(stream);
   }
 
@@ -17,4 +17,4 @@
   public int getSize() {
     return SIZE;
   }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexBaseInstructionFactory.java b/src/main/java/com/android/tools/r8/dex/code/DexBaseInstructionFactory.java
new file mode 100644
index 0000000..fdd4b40
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/dex/code/DexBaseInstructionFactory.java
@@ -0,0 +1,465 @@
+// Copyright (c) 2016, 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.dex.code;
+
+import com.android.tools.r8.graph.OffsetToObjectMapping;
+
+abstract class DexBaseInstructionFactory {
+
+  static DexInstruction create(
+      int high, int opcode, BytecodeStream stream, OffsetToObjectMapping mapping) {
+    switch (opcode) {
+      case 0x0:
+        return DexNop.create(high, stream);
+      case DexMove.OPCODE:
+        return new DexMove(high, stream);
+      case DexMoveFrom16.OPCODE:
+        return new DexMoveFrom16(high, stream);
+      case DexMove16.OPCODE:
+        return new DexMove16(high, stream);
+      case DexMoveWide.OPCODE:
+        return new DexMoveWide(high, stream);
+      case DexMoveWideFrom16.OPCODE:
+        return new DexMoveWideFrom16(high, stream);
+      case DexMoveWide16.OPCODE:
+        return new DexMoveWide16(high, stream);
+      case DexMoveObject.OPCODE:
+        return new DexMoveObject(high, stream);
+      case DexMoveObjectFrom16.OPCODE:
+        return new DexMoveObjectFrom16(high, stream);
+      case DexMoveObject16.OPCODE:
+        return new DexMoveObject16(high, stream);
+      case DexMoveResult.OPCODE:
+        return new DexMoveResult(high, stream);
+      case DexMoveResultWide.OPCODE:
+        return new DexMoveResultWide(high, stream);
+      case DexMoveResultObject.OPCODE:
+        return new DexMoveResultObject(high, stream);
+      case DexMoveException.OPCODE:
+        return new DexMoveException(high, stream);
+      case DexReturnVoid.OPCODE:
+        return new DexReturnVoid(high, stream);
+      case DexReturn.OPCODE:
+        return new DexReturn(high, stream);
+      case DexReturnWide.OPCODE:
+        return new DexReturnWide(high, stream);
+      case DexReturnObject.OPCODE:
+        return new DexReturnObject(high, stream);
+      case DexConst4.OPCODE:
+        return new DexConst4(high, stream);
+      case DexConst16.OPCODE:
+        return new DexConst16(high, stream);
+      case DexConst.OPCODE:
+        return new DexConst(high, stream);
+      case DexConstHigh16.OPCODE:
+        return new DexConstHigh16(high, stream);
+      case DexConstWide16.OPCODE:
+        return new DexConstWide16(high, stream);
+      case DexConstWide32.OPCODE:
+        return new DexConstWide32(high, stream);
+      case DexConstWide.OPCODE:
+        return new DexConstWide(high, stream);
+      case DexConstWideHigh16.OPCODE:
+        return new DexConstWideHigh16(high, stream);
+      case DexConstString.OPCODE:
+        return new DexConstString(high, stream, mapping);
+      case DexConstStringJumbo.OPCODE:
+        return new DexConstStringJumbo(high, stream, mapping);
+      case DexConstClass.OPCODE:
+        return new DexConstClass(high, stream, mapping);
+      case DexMonitorEnter.OPCODE:
+        return new DexMonitorEnter(high, stream);
+      case DexMonitorExit.OPCODE:
+        return new DexMonitorExit(high, stream);
+      case DexCheckCast.OPCODE:
+        return new DexCheckCast(high, stream, mapping);
+      case DexInstanceOf.OPCODE:
+        return new DexInstanceOf(high, stream, mapping);
+      case DexArrayLength.OPCODE:
+        return new DexArrayLength(high, stream);
+      case DexNewInstance.OPCODE:
+        return new DexNewInstance(high, stream, mapping);
+      case DexNewArray.OPCODE:
+        return new DexNewArray(high, stream, mapping);
+      case DexFilledNewArray.OPCODE:
+        return new DexFilledNewArray(high, stream, mapping);
+      case DexFilledNewArrayRange.OPCODE:
+        return new DexFilledNewArrayRange(high, stream, mapping);
+      case DexFillArrayData.OPCODE:
+        return new DexFillArrayData(high, stream);
+      case DexThrow.OPCODE:
+        return new DexThrow(high, stream);
+      case DexGoto.OPCODE:
+        return new DexGoto(high, stream);
+      case DexGoto16.OPCODE:
+        return new DexGoto16(high, stream);
+      case DexGoto32.OPCODE:
+        return new DexGoto32(high, stream);
+      case DexPackedSwitch.OPCODE:
+        return new DexPackedSwitch(high, stream);
+      case DexSparseSwitch.OPCODE:
+        return new DexSparseSwitch(high, stream);
+      case DexCmplFloat.OPCODE:
+        return new DexCmplFloat(high, stream);
+      case DexCmpgFloat.OPCODE:
+        return new DexCmpgFloat(high, stream);
+      case DexCmplDouble.OPCODE:
+        return new DexCmplDouble(high, stream);
+      case DexCmpgDouble.OPCODE:
+        return new DexCmpgDouble(high, stream);
+      case DexCmpLong.OPCODE:
+        return new DexCmpLong(high, stream);
+      case DexIfEq.OPCODE:
+        return new DexIfEq(high, stream);
+      case DexIfNe.OPCODE:
+        return new DexIfNe(high, stream);
+      case DexIfLt.OPCODE:
+        return new DexIfLt(high, stream);
+      case DexIfGe.OPCODE:
+        return new DexIfGe(high, stream);
+      case DexIfGt.OPCODE:
+        return new DexIfGt(high, stream);
+      case DexIfLe.OPCODE:
+        return new DexIfLe(high, stream);
+      case DexIfEqz.OPCODE:
+        return new DexIfEqz(high, stream);
+      case DexIfNez.OPCODE:
+        return new DexIfNez(high, stream);
+      case DexIfLtz.OPCODE:
+        return new DexIfLtz(high, stream);
+      case DexIfGez.OPCODE:
+        return new DexIfGez(high, stream);
+      case DexIfGtz.OPCODE:
+        return new DexIfGtz(high, stream);
+      case DexIfLez.OPCODE:
+        return new DexIfLez(high, stream);
+      case DexAget.OPCODE:
+        return new DexAget(high, stream);
+      case DexAgetWide.OPCODE:
+        return new DexAgetWide(high, stream);
+      case DexAgetObject.OPCODE:
+        return new DexAgetObject(high, stream);
+      case DexAgetBoolean.OPCODE:
+        return new DexAgetBoolean(high, stream);
+      case DexAgetByte.OPCODE:
+        return new DexAgetByte(high, stream);
+      case DexAgetChar.OPCODE:
+        return new DexAgetChar(high, stream);
+      case DexAgetShort.OPCODE:
+        return new DexAgetShort(high, stream);
+      case DexAput.OPCODE:
+        return new DexAput(high, stream);
+      case DexAputWide.OPCODE:
+        return new DexAputWide(high, stream);
+      case DexAputObject.OPCODE:
+        return new DexAputObject(high, stream);
+      case DexAputBoolean.OPCODE:
+        return new DexAputBoolean(high, stream);
+      case DexAputByte.OPCODE:
+        return new DexAputByte(high, stream);
+      case DexAputChar.OPCODE:
+        return new DexAputChar(high, stream);
+      case DexAputShort.OPCODE:
+        return new DexAputShort(high, stream);
+      case DexIget.OPCODE:
+        return new DexIget(high, stream, mapping);
+      case DexIgetWide.OPCODE:
+        return new DexIgetWide(high, stream, mapping);
+      case DexIgetObject.OPCODE:
+        return new DexIgetObject(high, stream, mapping);
+      case DexIgetBoolean.OPCODE:
+        return new DexIgetBoolean(high, stream, mapping);
+      case DexIgetByte.OPCODE:
+        return new DexIgetByte(high, stream, mapping);
+      case DexIgetChar.OPCODE:
+        return new DexIgetChar(high, stream, mapping);
+      case DexIgetShort.OPCODE:
+        return new DexIgetShort(high, stream, mapping);
+      case DexIput.OPCODE:
+        return new DexIput(high, stream, mapping);
+      case DexIputWide.OPCODE:
+        return new DexIputWide(high, stream, mapping);
+      case DexIputObject.OPCODE:
+        return new DexIputObject(high, stream, mapping);
+      case DexIputBoolean.OPCODE:
+        return new DexIputBoolean(high, stream, mapping);
+      case DexIputByte.OPCODE:
+        return new DexIputByte(high, stream, mapping);
+      case DexIputChar.OPCODE:
+        return new DexIputChar(high, stream, mapping);
+      case DexIputShort.OPCODE:
+        return new DexIputShort(high, stream, mapping);
+      case DexSget.OPCODE:
+        return new DexSget(high, stream, mapping);
+      case DexSgetWide.OPCODE:
+        return new DexSgetWide(high, stream, mapping);
+      case DexSgetObject.OPCODE:
+        return new DexSgetObject(high, stream, mapping);
+      case DexSgetBoolean.OPCODE:
+        return new DexSgetBoolean(high, stream, mapping);
+      case DexSgetByte.OPCODE:
+        return new DexSgetByte(high, stream, mapping);
+      case DexSgetChar.OPCODE:
+        return new DexSgetChar(high, stream, mapping);
+      case DexSgetShort.OPCODE:
+        return new DexSgetShort(high, stream, mapping);
+      case DexSput.OPCODE:
+        return new DexSput(high, stream, mapping);
+      case DexSputWide.OPCODE:
+        return new DexSputWide(high, stream, mapping);
+      case DexSputObject.OPCODE:
+        return new DexSputObject(high, stream, mapping);
+      case DexSputBoolean.OPCODE:
+        return new DexSputBoolean(high, stream, mapping);
+      case DexSputByte.OPCODE:
+        return new DexSputByte(high, stream, mapping);
+      case DexSputChar.OPCODE:
+        return new DexSputChar(high, stream, mapping);
+      case DexSputShort.OPCODE:
+        return new DexSputShort(high, stream, mapping);
+      case DexInvokeVirtual.OPCODE:
+        return new DexInvokeVirtual(high, stream, mapping);
+      case DexInvokeSuper.OPCODE:
+        return new DexInvokeSuper(high, stream, mapping);
+      case DexInvokeDirect.OPCODE:
+        return new DexInvokeDirect(high, stream, mapping);
+      case DexInvokeStatic.OPCODE:
+        return new DexInvokeStatic(high, stream, mapping);
+      case DexInvokeInterface.OPCODE:
+        return new DexInvokeInterface(high, stream, mapping);
+      case DexInvokeVirtualRange.OPCODE:
+        return new DexInvokeVirtualRange(high, stream, mapping);
+      case DexInvokeSuperRange.OPCODE:
+        return new DexInvokeSuperRange(high, stream, mapping);
+      case DexInvokeDirectRange.OPCODE:
+        return new DexInvokeDirectRange(high, stream, mapping);
+      case DexInvokeStaticRange.OPCODE:
+        return new DexInvokeStaticRange(high, stream, mapping);
+      case DexInvokeInterfaceRange.OPCODE:
+        return new DexInvokeInterfaceRange(high, stream, mapping);
+      case DexNegInt.OPCODE:
+        return new DexNegInt(high, stream);
+      case DexNotInt.OPCODE:
+        return new DexNotInt(high, stream);
+      case DexNegLong.OPCODE:
+        return new DexNegLong(high, stream);
+      case DexNotLong.OPCODE:
+        return new DexNotLong(high, stream);
+      case DexNegFloat.OPCODE:
+        return new DexNegFloat(high, stream);
+      case DexNegDouble.OPCODE:
+        return new DexNegDouble(high, stream);
+      case DexIntToLong.OPCODE:
+        return new DexIntToLong(high, stream);
+      case DexIntToFloat.OPCODE:
+        return new DexIntToFloat(high, stream);
+      case DexIntToDouble.OPCODE:
+        return new DexIntToDouble(high, stream);
+      case DexLongToInt.OPCODE:
+        return new DexLongToInt(high, stream);
+      case DexLongToFloat.OPCODE:
+        return new DexLongToFloat(high, stream);
+      case DexLongToDouble.OPCODE:
+        return new DexLongToDouble(high, stream);
+      case DexFloatToInt.OPCODE:
+        return new DexFloatToInt(high, stream);
+      case DexFloatToLong.OPCODE:
+        return new DexFloatToLong(high, stream);
+      case DexFloatToDouble.OPCODE:
+        return new DexFloatToDouble(high, stream);
+      case DexDoubleToInt.OPCODE:
+        return new DexDoubleToInt(high, stream);
+      case DexDoubleToLong.OPCODE:
+        return new DexDoubleToLong(high, stream);
+      case DexDoubleToFloat.OPCODE:
+        return new DexDoubleToFloat(high, stream);
+      case DexIntToByte.OPCODE:
+        return new DexIntToByte(high, stream);
+      case DexIntToChar.OPCODE:
+        return new DexIntToChar(high, stream);
+      case DexIntToShort.OPCODE:
+        return new DexIntToShort(high, stream);
+      case DexAddInt.OPCODE:
+        return new DexAddInt(high, stream);
+      case DexSubInt.OPCODE:
+        return new DexSubInt(high, stream);
+      case DexMulInt.OPCODE:
+        return new DexMulInt(high, stream);
+      case DexDivInt.OPCODE:
+        return new DexDivInt(high, stream);
+      case DexRemInt.OPCODE:
+        return new DexRemInt(high, stream);
+      case DexAndInt.OPCODE:
+        return new DexAndInt(high, stream);
+      case DexOrInt.OPCODE:
+        return new DexOrInt(high, stream);
+      case DexXorInt.OPCODE:
+        return new DexXorInt(high, stream);
+      case DexShlInt.OPCODE:
+        return new DexShlInt(high, stream);
+      case DexShrInt.OPCODE:
+        return new DexShrInt(high, stream);
+      case DexUshrInt.OPCODE:
+        return new DexUshrInt(high, stream);
+      case DexAddLong.OPCODE:
+        return new DexAddLong(high, stream);
+      case DexSubLong.OPCODE:
+        return new DexSubLong(high, stream);
+      case DexMulLong.OPCODE:
+        return new DexMulLong(high, stream);
+      case DexDivLong.OPCODE:
+        return new DexDivLong(high, stream);
+      case DexRemLong.OPCODE:
+        return new DexRemLong(high, stream);
+      case DexAndLong.OPCODE:
+        return new DexAndLong(high, stream);
+      case DexOrLong.OPCODE:
+        return new DexOrLong(high, stream);
+      case DexXorLong.OPCODE:
+        return new DexXorLong(high, stream);
+      case DexShlLong.OPCODE:
+        return new DexShlLong(high, stream);
+      case DexShrLong.OPCODE:
+        return new DexShrLong(high, stream);
+      case DexUshrLong.OPCODE:
+        return new DexUshrLong(high, stream);
+      case DexAddFloat.OPCODE:
+        return new DexAddFloat(high, stream);
+      case DexSubFloat.OPCODE:
+        return new DexSubFloat(high, stream);
+      case DexMulFloat.OPCODE:
+        return new DexMulFloat(high, stream);
+      case DexDivFloat.OPCODE:
+        return new DexDivFloat(high, stream);
+      case DexRemFloat.OPCODE:
+        return new DexRemFloat(high, stream);
+      case DexAddDouble.OPCODE:
+        return new DexAddDouble(high, stream);
+      case DexSubDouble.OPCODE:
+        return new DexSubDouble(high, stream);
+      case DexMulDouble.OPCODE:
+        return new DexMulDouble(high, stream);
+      case DexDivDouble.OPCODE:
+        return new DexDivDouble(high, stream);
+      case DexRemDouble.OPCODE:
+        return new DexRemDouble(high, stream);
+      case DexAddInt2Addr.OPCODE:
+        return new DexAddInt2Addr(high, stream);
+      case DexSubInt2Addr.OPCODE:
+        return new DexSubInt2Addr(high, stream);
+      case DexMulInt2Addr.OPCODE:
+        return new DexMulInt2Addr(high, stream);
+      case DexDivInt2Addr.OPCODE:
+        return new DexDivInt2Addr(high, stream);
+      case DexRemInt2Addr.OPCODE:
+        return new DexRemInt2Addr(high, stream);
+      case DexAndInt2Addr.OPCODE:
+        return new DexAndInt2Addr(high, stream);
+      case DexOrInt2Addr.OPCODE:
+        return new DexOrInt2Addr(high, stream);
+      case DexXorInt2Addr.OPCODE:
+        return new DexXorInt2Addr(high, stream);
+      case DexShlInt2Addr.OPCODE:
+        return new DexShlInt2Addr(high, stream);
+      case DexShrInt2Addr.OPCODE:
+        return new DexShrInt2Addr(high, stream);
+      case DexUshrInt2Addr.OPCODE:
+        return new DexUshrInt2Addr(high, stream);
+      case DexAddLong2Addr.OPCODE:
+        return new DexAddLong2Addr(high, stream);
+      case DexSubLong2Addr.OPCODE:
+        return new DexSubLong2Addr(high, stream);
+      case DexMulLong2Addr.OPCODE:
+        return new DexMulLong2Addr(high, stream);
+      case DexDivLong2Addr.OPCODE:
+        return new DexDivLong2Addr(high, stream);
+      case DexRemLong2Addr.OPCODE:
+        return new DexRemLong2Addr(high, stream);
+      case DexAndLong2Addr.OPCODE:
+        return new DexAndLong2Addr(high, stream);
+      case DexOrLong2Addr.OPCODE:
+        return new DexOrLong2Addr(high, stream);
+      case DexXorLong2Addr.OPCODE:
+        return new DexXorLong2Addr(high, stream);
+      case DexShlLong2Addr.OPCODE:
+        return new DexShlLong2Addr(high, stream);
+      case DexShrLong2Addr.OPCODE:
+        return new DexShrLong2Addr(high, stream);
+      case DexUshrLong2Addr.OPCODE:
+        return new DexUshrLong2Addr(high, stream);
+      case DexAddFloat2Addr.OPCODE:
+        return new DexAddFloat2Addr(high, stream);
+      case DexSubFloat2Addr.OPCODE:
+        return new DexSubFloat2Addr(high, stream);
+      case DexMulFloat2Addr.OPCODE:
+        return new DexMulFloat2Addr(high, stream);
+      case DexDivFloat2Addr.OPCODE:
+        return new DexDivFloat2Addr(high, stream);
+      case DexRemFloat2Addr.OPCODE:
+        return new DexRemFloat2Addr(high, stream);
+      case DexAddDouble2Addr.OPCODE:
+        return new DexAddDouble2Addr(high, stream);
+      case DexSubDouble2Addr.OPCODE:
+        return new DexSubDouble2Addr(high, stream);
+      case DexMulDouble2Addr.OPCODE:
+        return new DexMulDouble2Addr(high, stream);
+      case DexDivDouble2Addr.OPCODE:
+        return new DexDivDouble2Addr(high, stream);
+      case DexRemDouble2Addr.OPCODE:
+        return new DexRemDouble2Addr(high, stream);
+      case DexAddIntLit16.OPCODE:
+        return new DexAddIntLit16(high, stream);
+      case DexRsubInt.OPCODE:
+        return new DexRsubInt(high, stream);
+      case DexMulIntLit16.OPCODE:
+        return new DexMulIntLit16(high, stream);
+      case DexDivIntLit16.OPCODE:
+        return new DexDivIntLit16(high, stream);
+      case DexRemIntLit16.OPCODE:
+        return new DexRemIntLit16(high, stream);
+      case DexAndIntLit16.OPCODE:
+        return new DexAndIntLit16(high, stream);
+      case DexOrIntLit16.OPCODE:
+        return new DexOrIntLit16(high, stream);
+      case DexXorIntLit16.OPCODE:
+        return new DexXorIntLit16(high, stream);
+      case DexAddIntLit8.OPCODE:
+        return new DexAddIntLit8(high, stream);
+      case DexRsubIntLit8.OPCODE:
+        return new DexRsubIntLit8(high, stream);
+      case DexMulIntLit8.OPCODE:
+        return new DexMulIntLit8(high, stream);
+      case DexDivIntLit8.OPCODE:
+        return new DexDivIntLit8(high, stream);
+      case DexRemIntLit8.OPCODE:
+        return new DexRemIntLit8(high, stream);
+      case DexAndIntLit8.OPCODE:
+        return new DexAndIntLit8(high, stream);
+      case DexOrIntLit8.OPCODE:
+        return new DexOrIntLit8(high, stream);
+      case DexXorIntLit8.OPCODE:
+        return new DexXorIntLit8(high, stream);
+      case DexShlIntLit8.OPCODE:
+        return new DexShlIntLit8(high, stream);
+      case DexShrIntLit8.OPCODE:
+        return new DexShrIntLit8(high, stream);
+      case DexUshrIntLit8.OPCODE:
+        return new DexUshrIntLit8(high, stream);
+      case DexInvokePolymorphic.OPCODE:
+        return new DexInvokePolymorphic(high, stream, mapping);
+      case DexInvokePolymorphicRange.OPCODE:
+        return new DexInvokePolymorphicRange(high, stream, mapping);
+      case DexInvokeCustom.OPCODE:
+        return new DexInvokeCustom(high, stream, mapping);
+      case DexInvokeCustomRange.OPCODE:
+        return new DexInvokeCustomRange(high, stream, mapping);
+      case DexConstMethodHandle.OPCODE:
+        return new DexConstMethodHandle(high, stream, mapping);
+      case DexConstMethodType.OPCODE:
+        return new DexConstMethodType(high, stream, mapping);
+      default:
+        throw new IllegalArgumentException("Illegal Opcode: 0x" + Integer.toString(opcode, 16));
+    }
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/code/CheckCast.java b/src/main/java/com/android/tools/r8/dex/code/DexCheckCast.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/CheckCast.java
rename to src/main/java/com/android/tools/r8/dex/code/DexCheckCast.java
index 74a5f91..650655a 100644
--- a/src/main/java/com/android/tools/r8/code/CheckCast.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexCheckCast.java
@@ -1,9 +1,10 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
@@ -15,7 +16,7 @@
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
-public class CheckCast extends Format21c<DexType> {
+public class DexCheckCast extends DexFormat21c<DexType> {
 
   public static final int OPCODE = 0x1f;
   public static final String NAME = "CheckCast";
@@ -23,12 +24,12 @@
 
   private final boolean ignoreCompatRules;
 
-  CheckCast(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexCheckCast(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getTypeMap());
     this.ignoreCompatRules = false;
   }
 
-  public CheckCast(int valueRegister, DexType type, boolean ignoreCompatRules) {
+  public DexCheckCast(int valueRegister, DexType type, boolean ignoreCompatRules) {
     super(valueRegister, type);
     this.ignoreCompatRules = ignoreCompatRules;
   }
@@ -49,7 +50,7 @@
   }
 
   @Override
-  void internalSubSpecify(StructuralSpecification<Format21c<DexType>, ?> spec) {
+  void internalSubSpecify(StructuralSpecification<DexFormat21c<DexType>, ?> spec) {
     spec.withItem(i -> i.BBBB);
   }
 
@@ -60,12 +61,12 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
-    DexType rewritten = graphLens.lookupType(getType());
-    rewritten.collectIndexedItems(indexedItems);
+    DexType rewritten = appView.graphLens().lookupType(getType());
+    rewritten.collectIndexedItems(appView, indexedItems);
   }
 
   @Override
@@ -81,7 +82,7 @@
   }
 
   @Override
-  public CheckCast asCheckCast() {
+  public DexCheckCast asCheckCast() {
     return this;
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/CmpLong.java b/src/main/java/com/android/tools/r8/dex/code/DexCmpLong.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/CmpLong.java
rename to src/main/java/com/android/tools/r8/dex/code/DexCmpLong.java
index 38f1bc9..57f1807 100644
--- a/src/main/java/com/android/tools/r8/code/CmpLong.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexCmpLong.java
@@ -1,23 +1,23 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.Cmp.Bias;
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class CmpLong extends Format23x {
+public class DexCmpLong extends DexFormat23x {
 
   public static final int OPCODE = 0x31;
   public static final String NAME = "CmpLong";
   public static final String SMALI_NAME = "cmp-long";
 
-  CmpLong(int high, BytecodeStream stream) {
+  DexCmpLong(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public CmpLong(int dest, int left, int right) {
+  public DexCmpLong(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/CmpgDouble.java b/src/main/java/com/android/tools/r8/dex/code/DexCmpgDouble.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/CmpgDouble.java
rename to src/main/java/com/android/tools/r8/dex/code/DexCmpgDouble.java
index f4cfef4..4414ec7 100644
--- a/src/main/java/com/android/tools/r8/code/CmpgDouble.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexCmpgDouble.java
@@ -1,23 +1,23 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.Cmp.Bias;
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class CmpgDouble extends Format23x {
+public class DexCmpgDouble extends DexFormat23x {
 
   public static final int OPCODE = 0x30;
   public static final String NAME = "CmpgDouble";
   public static final String SMALI_NAME = "cmpg-double";
 
-  CmpgDouble(int high, BytecodeStream stream) {
+  DexCmpgDouble(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public CmpgDouble(int dest, int left, int right) {
+  public DexCmpgDouble(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/CmpgFloat.java b/src/main/java/com/android/tools/r8/dex/code/DexCmpgFloat.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/CmpgFloat.java
rename to src/main/java/com/android/tools/r8/dex/code/DexCmpgFloat.java
index 299e2fe..ac387ed 100644
--- a/src/main/java/com/android/tools/r8/code/CmpgFloat.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexCmpgFloat.java
@@ -1,23 +1,23 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.Cmp.Bias;
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class CmpgFloat extends Format23x {
+public class DexCmpgFloat extends DexFormat23x {
 
   public static final int OPCODE = 0x2e;
   public static final String NAME = "CmpgFloat";
   public static final String SMALI_NAME = "cmpg-float";
 
-  CmpgFloat(int high, BytecodeStream stream) {
+  DexCmpgFloat(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public CmpgFloat(int dest, int left, int right) {
+  public DexCmpgFloat(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/CmplDouble.java b/src/main/java/com/android/tools/r8/dex/code/DexCmplDouble.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/CmplDouble.java
rename to src/main/java/com/android/tools/r8/dex/code/DexCmplDouble.java
index a65ef74..b28bf82 100644
--- a/src/main/java/com/android/tools/r8/code/CmplDouble.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexCmplDouble.java
@@ -1,23 +1,23 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.Cmp.Bias;
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class CmplDouble extends Format23x {
+public class DexCmplDouble extends DexFormat23x {
 
   public static final int OPCODE = 0x2f;
   public static final String NAME = "CmplDouble";
   public static final String SMALI_NAME = "cmpl-double";
 
-  CmplDouble(int high, BytecodeStream stream) {
+  DexCmplDouble(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public CmplDouble(int dest, int left, int right) {
+  public DexCmplDouble(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/CmplFloat.java b/src/main/java/com/android/tools/r8/dex/code/DexCmplFloat.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/CmplFloat.java
rename to src/main/java/com/android/tools/r8/dex/code/DexCmplFloat.java
index 892d0de..76becd7 100644
--- a/src/main/java/com/android/tools/r8/code/CmplFloat.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexCmplFloat.java
@@ -1,23 +1,23 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.Cmp.Bias;
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class CmplFloat extends Format23x {
+public class DexCmplFloat extends DexFormat23x {
 
   public static final int OPCODE = 0x2d;
   public static final String NAME = "CmplFloat";
   public static final String SMALI_NAME = "cmpl-float";
 
-  CmplFloat(int high, BytecodeStream stream) {
+  DexCmplFloat(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public CmplFloat(int dest, int left, int right) {
+  public DexCmplFloat(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/DexCompareHelper.java b/src/main/java/com/android/tools/r8/dex/code/DexCompareHelper.java
similarity index 91%
rename from src/main/java/com/android/tools/r8/code/DexCompareHelper.java
rename to src/main/java/com/android/tools/r8/dex/code/DexCompareHelper.java
index 130e69b..93c2501 100644
--- a/src/main/java/com/android/tools/r8/code/DexCompareHelper.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexCompareHelper.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2020, 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.code;
+package com.android.tools.r8.dex.code;
 
 public class DexCompareHelper {
 
@@ -22,7 +22,7 @@
 
   // Helper to signal that the concrete instruction is uniquely determined by its ID/opcode.
   public static int compareIdUniquelyDeterminesEquality(
-      Instruction instruction1, Instruction instruction2) {
+      DexInstruction instruction1, DexInstruction instruction2) {
     assert instruction1.getClass() == instruction2.getClass();
     assert instruction1.getCompareToId() == instruction2.getCompareToId();
     assert instruction1.toString().equals(instruction2.toString());
diff --git a/src/main/java/com/android/tools/r8/code/Const.java b/src/main/java/com/android/tools/r8/dex/code/DexConst.java
similarity index 74%
rename from src/main/java/com/android/tools/r8/code/Const.java
rename to src/main/java/com/android/tools/r8/dex/code/DexConst.java
index 498f747..33fdff4 100644
--- a/src/main/java/com/android/tools/r8/code/Const.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexConst.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.code.SingleConstant;
@@ -9,17 +9,17 @@
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.StringUtils;
 
-public class Const extends Format31i implements SingleConstant {
+public class DexConst extends DexFormat31i implements SingleConstant {
 
   public static final int OPCODE = 0x14;
   public static final String NAME = "Const";
   public static final String SMALI_NAME = "const";
 
-  Const(int high, BytecodeStream stream) {
+  DexConst(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public Const(int register, int constant) {
+  public DexConst(int register, int constant) {
     super(register, constant);
   }
 
@@ -45,14 +45,14 @@
 
   @Override
   public String toString(ClassNameMapper naming) {
-    return formatString("v" + AA + ", " + StringUtils.hexString(decodedValue(), 8) +
-        " (" + decodedValue() + ")");
+    return formatString(
+        "v" + AA + ", " + StringUtils.hexString(decodedValue(), 8) + " (" + decodedValue() + ")");
   }
 
   @Override
   public String toSmaliString(ClassNameMapper naming) {
-    return formatSmaliString("v" + AA + ", " + StringUtils.hexString(decodedValue(), 8) +
-        "  # " + decodedValue());
+    return formatSmaliString(
+        "v" + AA + ", " + StringUtils.hexString(decodedValue(), 8) + "  # " + decodedValue());
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/Const16.java b/src/main/java/com/android/tools/r8/dex/code/DexConst16.java
similarity index 78%
rename from src/main/java/com/android/tools/r8/code/Const16.java
rename to src/main/java/com/android/tools/r8/dex/code/DexConst16.java
index 9d69f25..1188df2 100644
--- a/src/main/java/com/android/tools/r8/code/Const16.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexConst16.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.code.SingleConstant;
@@ -9,17 +9,17 @@
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.StringUtils;
 
-public class Const16 extends Format21s implements SingleConstant {
+public class DexConst16 extends DexFormat21s implements SingleConstant {
 
   public static final int OPCODE = 0x13;
   public static final String NAME = "Const16";
   public static final String SMALI_NAME = "const/16";
 
-  /*package*/ Const16(int high, BytecodeStream stream) {
+  /*package*/ DexConst16(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public Const16(int dest, int constant) {
+  public DexConst16(int dest, int constant) {
     super(dest, constant);
   }
 
@@ -45,8 +45,8 @@
 
   @Override
   public String toString(ClassNameMapper naming) {
-    return formatString("v" + AA + ", " + StringUtils.hexString(decodedValue(), 4) +
-        " (" + decodedValue() + ")");
+    return formatString(
+        "v" + AA + ", " + StringUtils.hexString(decodedValue(), 4) + " (" + decodedValue() + ")");
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/Const4.java b/src/main/java/com/android/tools/r8/dex/code/DexConst4.java
similarity index 74%
rename from src/main/java/com/android/tools/r8/code/Const4.java
rename to src/main/java/com/android/tools/r8/dex/code/DexConst4.java
index b9fd59c..09ecd15 100644
--- a/src/main/java/com/android/tools/r8/code/Const4.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexConst4.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.code.SingleConstant;
@@ -9,17 +9,17 @@
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.StringUtils;
 
-public class Const4 extends Format11n implements SingleConstant {
+public class DexConst4 extends DexFormat11n implements SingleConstant {
 
   public static final int OPCODE = 0x12;
   public static final String NAME = "Const4";
   public static final String SMALI_NAME = "const/4";
 
-  Const4(int high, BytecodeStream stream) {
+  DexConst4(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public Const4(int dest, int constant) {
+  public DexConst4(int dest, int constant) {
     super(dest, constant);
   }
 
@@ -45,14 +45,14 @@
 
   @Override
   public String toString(ClassNameMapper naming) {
-    return formatString("v" + A + ", " + StringUtils.hexString(decodedValue(), 1) +
-        " (" + decodedValue() + ")");
+    return formatString(
+        "v" + A + ", " + StringUtils.hexString(decodedValue(), 1) + " (" + decodedValue() + ")");
   }
 
   @Override
   public String toSmaliString(ClassNameMapper naming) {
-    return formatSmaliString("v" + A + ", " + StringUtils.hexString(decodedValue(), 2) +
-        "  # " + decodedValue());
+    return formatSmaliString(
+        "v" + A + ", " + StringUtils.hexString(decodedValue(), 2) + "  # " + decodedValue());
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/ConstClass.java b/src/main/java/com/android/tools/r8/dex/code/DexConstClass.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/ConstClass.java
rename to src/main/java/com/android/tools/r8/dex/code/DexConstClass.java
index 88b35e1..bc476c1 100644
--- a/src/main/java/com/android/tools/r8/code/ConstClass.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexConstClass.java
@@ -1,9 +1,10 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
@@ -15,7 +16,7 @@
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
-public class ConstClass extends Format21c<DexType> {
+public class DexConstClass extends DexFormat21c<DexType> {
 
   public static final int OPCODE = 0x1c;
   public static final String NAME = "ConstClass";
@@ -23,18 +24,18 @@
 
   private final boolean ignoreCompatRules;
 
-  ConstClass(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexConstClass(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getTypeMap());
     this.ignoreCompatRules = false;
   }
 
-  public ConstClass(int dest, DexType type, boolean ignoreCompatRules) {
+  public DexConstClass(int dest, DexType type, boolean ignoreCompatRules) {
     super(dest, type);
     this.ignoreCompatRules = ignoreCompatRules;
   }
 
   @Override
-  void internalSubSpecify(StructuralSpecification<Format21c<DexType>, ?> spec) {
+  void internalSubSpecify(StructuralSpecification<DexFormat21c<DexType>, ?> spec) {
     spec.withItem(i -> i.BBBB);
   }
 
@@ -60,12 +61,12 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
-    DexType rewritten = graphLens.lookupType(getType());
-    rewritten.collectIndexedItems(indexedItems);
+    DexType rewritten = appView.graphLens().lookupType(getType());
+    rewritten.collectIndexedItems(appView, indexedItems);
   }
 
   @Override
@@ -100,7 +101,7 @@
   }
 
   @Override
-  public ConstClass asConstClass() {
+  public DexConstClass asConstClass() {
     return this;
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/ConstHigh16.java b/src/main/java/com/android/tools/r8/dex/code/DexConstHigh16.java
similarity index 72%
rename from src/main/java/com/android/tools/r8/code/ConstHigh16.java
rename to src/main/java/com/android/tools/r8/dex/code/DexConstHigh16.java
index b16e45d..2e732ed 100644
--- a/src/main/java/com/android/tools/r8/code/ConstHigh16.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexConstHigh16.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.code.SingleConstant;
@@ -9,17 +9,17 @@
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.StringUtils;
 
-public class ConstHigh16 extends Format21h implements SingleConstant {
+public class DexConstHigh16 extends DexFormat21h implements SingleConstant {
 
   public static final int OPCODE = 0x15;
   public static final String NAME = "ConstHigh16";
   public static final String SMALI_NAME = "const/high16";
 
-  /*package*/ ConstHigh16(int high, BytecodeStream stream) {
+  /*package*/ DexConstHigh16(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public ConstHigh16(int register, int constantHighBits) {
+  public DexConstHigh16(int register, int constantHighBits) {
     super(register, constantHighBits);
   }
 
@@ -45,14 +45,14 @@
 
   @Override
   public String toString(ClassNameMapper naming) {
-    return formatString("v" + AA + ", " + StringUtils.hexString(decodedValue(), 8) +
-        " (" + decodedValue() + ")");
+    return formatString(
+        "v" + AA + ", " + StringUtils.hexString(decodedValue(), 8) + " (" + decodedValue() + ")");
   }
 
   @Override
   public String toSmaliString(ClassNameMapper naming) {
-    return formatSmaliString("v" + AA + ", " + StringUtils.hexString(decodedValue(), 8) +
-        "  # " + decodedValue());
+    return formatSmaliString(
+        "v" + AA + ", " + StringUtils.hexString(decodedValue(), 8) + "  # " + decodedValue());
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/ConstMethodHandle.java b/src/main/java/com/android/tools/r8/dex/code/DexConstMethodHandle.java
similarity index 86%
rename from src/main/java/com/android/tools/r8/code/ConstMethodHandle.java
rename to src/main/java/com/android/tools/r8/dex/code/DexConstMethodHandle.java
index 0df963f..87964c8 100644
--- a/src/main/java/com/android/tools/r8/code/ConstMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexConstMethodHandle.java
@@ -1,10 +1,11 @@
 // Copyright (c) 2017, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.errors.InternalCompilerError;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethodHandle;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
@@ -18,17 +19,17 @@
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
-public class ConstMethodHandle extends Format21c<DexMethodHandle> {
+public class DexConstMethodHandle extends DexFormat21c<DexMethodHandle> {
 
   public static final int OPCODE = 0xfe;
   public static final String NAME = "ConstMethodHandle";
   public static final String SMALI_NAME = "const-method-handle";
 
-  ConstMethodHandle(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexConstMethodHandle(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getMethodHandleMap());
   }
 
-  public ConstMethodHandle(int register, DexMethodHandle methodHandle) {
+  public DexConstMethodHandle(int register, DexMethodHandle methodHandle) {
     super(register, methodHandle);
   }
 
@@ -52,7 +53,7 @@
   }
 
   @Override
-  void internalSubSpecify(StructuralSpecification<Format21c<DexMethodHandle>, ?> spec) {
+  void internalSubSpecify(StructuralSpecification<DexFormat21c<DexMethodHandle>, ?> spec) {
     spec.withItem(i -> i.BBBB);
   }
 
@@ -92,14 +93,14 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     DexMethodHandle rewritten =
         rewriter.rewriteDexMethodHandle(
             getMethodHandle(), MethodHandleUse.NOT_ARGUMENT_TO_LAMBDA_METAFACTORY, context);
-    rewritten.collectIndexedItems(indexedItems);
+    rewritten.collectIndexedItems(appView, indexedItems);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/ConstMethodType.java b/src/main/java/com/android/tools/r8/dex/code/DexConstMethodType.java
similarity index 85%
rename from src/main/java/com/android/tools/r8/code/ConstMethodType.java
rename to src/main/java/com/android/tools/r8/dex/code/DexConstMethodType.java
index 478d3b5..68f49fb 100644
--- a/src/main/java/com/android/tools/r8/code/ConstMethodType.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexConstMethodType.java
@@ -1,10 +1,11 @@
 // Copyright (c) 2017, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.errors.InternalCompilerError;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
@@ -17,17 +18,17 @@
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
-public class ConstMethodType extends Format21c<DexProto> {
+public class DexConstMethodType extends DexFormat21c<DexProto> {
 
   public static final int OPCODE = 0xff;
   public static final String NAME = "ConstMethodType";
   public static final String SMALI_NAME = "const-method-type";
 
-  ConstMethodType(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexConstMethodType(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getProtosMap());
   }
 
-  public ConstMethodType(int register, DexProto methodType) {
+  public DexConstMethodType(int register, DexProto methodType) {
     super(register, methodType);
   }
 
@@ -51,7 +52,7 @@
   }
 
   @Override
-  void internalSubSpecify(StructuralSpecification<Format21c<DexProto>, ?> spec) {
+  void internalSubSpecify(StructuralSpecification<DexFormat21c<DexProto>, ?> spec) {
     spec.withItem(i -> i.BBBB);
   }
 
@@ -88,12 +89,12 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     DexProto rewritten = rewriter.rewriteProto(getMethodType());
-    rewritten.collectIndexedItems(indexedItems);
+    rewritten.collectIndexedItems(appView, indexedItems);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/ConstString.java b/src/main/java/com/android/tools/r8/dex/code/DexConstString.java
similarity index 85%
rename from src/main/java/com/android/tools/r8/code/ConstString.java
rename to src/main/java/com/android/tools/r8/dex/code/DexConstString.java
index 5fd55e4..0117785 100644
--- a/src/main/java/com/android/tools/r8/code/ConstString.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexConstString.java
@@ -1,10 +1,11 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.errors.InternalCompilerError;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
@@ -16,17 +17,17 @@
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
-public class ConstString extends Format21c<DexString> {
+public class DexConstString extends DexFormat21c<DexString> {
 
   public static final int OPCODE = 0x1a;
   public static final String NAME = "ConstString";
   public static final String SMALI_NAME = "const-string";
 
-  ConstString(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexConstString(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getStringMap());
   }
 
-  public ConstString(int register, DexString string) {
+  public DexConstString(int register, DexString string) {
     super(register, string);
   }
 
@@ -35,15 +36,15 @@
   }
 
   @Override
-  void internalSubSpecify(StructuralSpecification<Format21c<DexString>, ?> spec) {
+  void internalSubSpecify(StructuralSpecification<DexFormat21c<DexString>, ?> spec) {
     spec.withItem(i -> i.BBBB);
   }
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     getString().collectIndexedItems(indexedItems);
   }
@@ -64,7 +65,7 @@
   }
 
   @Override
-  public ConstString asConstString() {
+  public DexConstString asConstString() {
     return this;
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/ConstStringJumbo.java b/src/main/java/com/android/tools/r8/dex/code/DexConstStringJumbo.java
similarity index 83%
rename from src/main/java/com/android/tools/r8/code/ConstStringJumbo.java
rename to src/main/java/com/android/tools/r8/dex/code/DexConstStringJumbo.java
index b24f86f..725ef8a 100644
--- a/src/main/java/com/android/tools/r8/code/ConstStringJumbo.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexConstStringJumbo.java
@@ -1,24 +1,24 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.naming.ClassNameMapper;
 
-public class ConstStringJumbo extends Format31c {
+public class DexConstStringJumbo extends DexFormat31c {
 
   public static final int OPCODE = 0x1b;
   public static final String NAME = "ConstStringJumbo";
   public static final String SMALI_NAME = "const-string/jumbo";
 
-  ConstStringJumbo(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexConstStringJumbo(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getStringMap());
   }
 
-  public ConstStringJumbo(int register, DexString string) {
+  public DexConstStringJumbo(int register, DexString string) {
     super(register, string);
   }
 
@@ -42,7 +42,7 @@
   }
 
   @Override
-  public ConstStringJumbo asConstStringJumbo() {
+  public DexConstStringJumbo asConstStringJumbo() {
     return this;
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/ConstWide.java b/src/main/java/com/android/tools/r8/dex/code/DexConstWide.java
similarity index 72%
rename from src/main/java/com/android/tools/r8/code/ConstWide.java
rename to src/main/java/com/android/tools/r8/dex/code/DexConstWide.java
index dd2e6e6..6fbd6f2 100644
--- a/src/main/java/com/android/tools/r8/code/ConstWide.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexConstWide.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.code.WideConstant;
@@ -9,17 +9,17 @@
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.StringUtils;
 
-public class ConstWide extends Format51l implements WideConstant {
+public class DexConstWide extends DexFormat51l implements WideConstant {
 
   public static final int OPCODE = 0x18;
   public static final String NAME = "ConstWide";
   public static final String SMALI_NAME = "const-wide";
 
-  ConstWide(int high, BytecodeStream stream) {
+  DexConstWide(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public ConstWide(int dest, long constant) {
+  public DexConstWide(int dest, long constant) {
     super(dest, constant);
   }
 
@@ -45,14 +45,14 @@
 
   @Override
   public String toString(ClassNameMapper naming) {
-    return formatString("v" + AA + ", " + StringUtils.hexString(decodedValue(), 16) +
-        " (" + decodedValue() + ")");
+    return formatString(
+        "v" + AA + ", " + StringUtils.hexString(decodedValue(), 16) + " (" + decodedValue() + ")");
   }
 
   @Override
   public String toSmaliString(ClassNameMapper naming) {
-    return formatSmaliString("v" + AA + ", " + StringUtils.hexString(decodedValue(), 16) +
-        "L  # " + decodedValue());
+    return formatSmaliString(
+        "v" + AA + ", " + StringUtils.hexString(decodedValue(), 16) + "L  # " + decodedValue());
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/ConstWide16.java b/src/main/java/com/android/tools/r8/dex/code/DexConstWide16.java
similarity index 79%
rename from src/main/java/com/android/tools/r8/code/ConstWide16.java
rename to src/main/java/com/android/tools/r8/dex/code/DexConstWide16.java
index 99c1810..e30b886 100644
--- a/src/main/java/com/android/tools/r8/code/ConstWide16.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexConstWide16.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.code.WideConstant;
@@ -9,17 +9,17 @@
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.StringUtils;
 
-public class ConstWide16 extends Format21s implements WideConstant {
+public class DexConstWide16 extends DexFormat21s implements WideConstant {
 
   public static final int OPCODE = 0x16;
   public static final String NAME = "ConstWide16";
   public static final String SMALI_NAME = "const-wide/16";
 
-  ConstWide16(int high, BytecodeStream stream) {
+  DexConstWide16(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public ConstWide16(int dest, int constant) {
+  public DexConstWide16(int dest, int constant) {
     super(dest, constant);
   }
 
@@ -45,8 +45,8 @@
 
   @Override
   public String toString(ClassNameMapper naming) {
-    return formatString("v" + AA + ", " + StringUtils.hexString(decodedValue(), 16) +
-        " (" + decodedValue() + ")");
+    return formatString(
+        "v" + AA + ", " + StringUtils.hexString(decodedValue(), 16) + " (" + decodedValue() + ")");
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/ConstWide32.java b/src/main/java/com/android/tools/r8/dex/code/DexConstWide32.java
similarity index 79%
rename from src/main/java/com/android/tools/r8/code/ConstWide32.java
rename to src/main/java/com/android/tools/r8/dex/code/DexConstWide32.java
index 1e2c274..b315cb9 100644
--- a/src/main/java/com/android/tools/r8/code/ConstWide32.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexConstWide32.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.code.WideConstant;
@@ -9,17 +9,17 @@
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.StringUtils;
 
-public class ConstWide32 extends Format31i implements WideConstant {
+public class DexConstWide32 extends DexFormat31i implements WideConstant {
 
   public static final int OPCODE = 0x17;
   public static final String NAME = "ConstWide32";
   public static final String SMALI_NAME = "const-wide/32";
 
-  ConstWide32(int high, BytecodeStream stream) {
+  DexConstWide32(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public ConstWide32(int dest, int constant) {
+  public DexConstWide32(int dest, int constant) {
     super(dest, constant);
   }
 
@@ -45,8 +45,8 @@
 
   @Override
   public String toString(ClassNameMapper naming) {
-    return formatString("v" + AA + ", " + StringUtils.hexString(decodedValue(), 16) +
-        " (" + decodedValue() + ")");
+    return formatString(
+        "v" + AA + ", " + StringUtils.hexString(decodedValue(), 16) + " (" + decodedValue() + ")");
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/ConstWideHigh16.java b/src/main/java/com/android/tools/r8/dex/code/DexConstWideHigh16.java
similarity index 71%
rename from src/main/java/com/android/tools/r8/code/ConstWideHigh16.java
rename to src/main/java/com/android/tools/r8/dex/code/DexConstWideHigh16.java
index 26d5ea0..0eeca93 100644
--- a/src/main/java/com/android/tools/r8/code/ConstWideHigh16.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexConstWideHigh16.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.code.WideConstant;
@@ -9,17 +9,17 @@
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.StringUtils;
 
-public class ConstWideHigh16 extends Format21h implements WideConstant {
+public class DexConstWideHigh16 extends DexFormat21h implements WideConstant {
 
   public static final int OPCODE = 0x19;
   public static final String NAME = "ConstWideHigh16";
   public static final String SMALI_NAME = "const-wide/high16";
 
-  ConstWideHigh16(int high, BytecodeStream stream) {
+  DexConstWideHigh16(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public ConstWideHigh16(int dest, int constantHighBits) {
+  public DexConstWideHigh16(int dest, int constantHighBits) {
     super(dest, constantHighBits);
   }
 
@@ -45,14 +45,14 @@
 
   @Override
   public String toString(ClassNameMapper naming) {
-    return formatString("v" + AA + ", " + StringUtils.hexString(decodedValue(), 16) +
-        " (" + decodedValue() + ")");
+    return formatString(
+        "v" + AA + ", " + StringUtils.hexString(decodedValue(), 16) + " (" + decodedValue() + ")");
   }
 
   @Override
   public String toSmaliString(ClassNameMapper naming) {
-    return formatSmaliString("v" + AA + ", " + StringUtils.hexString(decodedValue(), 16) +
-        "L  # " + decodedValue());
+    return formatSmaliString(
+        "v" + AA + ", " + StringUtils.hexString(decodedValue(), 16) + "L  # " + decodedValue());
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/DivDouble.java b/src/main/java/com/android/tools/r8/dex/code/DexDivDouble.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/DivDouble.java
rename to src/main/java/com/android/tools/r8/dex/code/DexDivDouble.java
index 1be9ee9..19ad41f 100644
--- a/src/main/java/com/android/tools/r8/code/DivDouble.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexDivDouble.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class DivDouble extends Format23x {
+
+public class DexDivDouble extends DexFormat23x {
 
   public static final int OPCODE = 0xae;
   public static final String NAME = "DivDouble";
   public static final String SMALI_NAME = "div-double";
 
-  DivDouble(int high, BytecodeStream stream) {
+  DexDivDouble(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public DivDouble(int dest, int left, int right) {
+  public DexDivDouble(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/DivDouble2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexDivDouble2Addr.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/DivDouble2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexDivDouble2Addr.java
index a8070d2..9481f04 100644
--- a/src/main/java/com/android/tools/r8/code/DivDouble2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexDivDouble2Addr.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class DivDouble2Addr extends Format12x {
+public class DexDivDouble2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xce;
   public static final String NAME = "DivDouble2Addr";
   public static final String SMALI_NAME = "div-double/2addr";
 
-  DivDouble2Addr(int high, BytecodeStream stream) {
+  DexDivDouble2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public DivDouble2Addr(int left, int right) {
+  public DexDivDouble2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/DivFloat.java b/src/main/java/com/android/tools/r8/dex/code/DexDivFloat.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/DivFloat.java
rename to src/main/java/com/android/tools/r8/dex/code/DexDivFloat.java
index 4069d40..2791142 100644
--- a/src/main/java/com/android/tools/r8/code/DivFloat.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexDivFloat.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class DivFloat extends Format23x {
+
+public class DexDivFloat extends DexFormat23x {
 
   public static final int OPCODE = 0xa9;
   public static final String NAME = "DivFloat";
   public static final String SMALI_NAME = "div-float";
 
-  DivFloat(int high, BytecodeStream stream) {
+  DexDivFloat(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public DivFloat(int dest, int left, int right) {
+  public DexDivFloat(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/DivFloat2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexDivFloat2Addr.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/DivFloat2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexDivFloat2Addr.java
index a51af26..56fb846 100644
--- a/src/main/java/com/android/tools/r8/code/DivFloat2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexDivFloat2Addr.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class DivFloat2Addr extends Format12x {
+public class DexDivFloat2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xc9;
   public static final String NAME = "DivFloat2Addr";
   public static final String SMALI_NAME = "div-float/2addr";
 
-  DivFloat2Addr(int high, BytecodeStream stream) {
+  DexDivFloat2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public DivFloat2Addr(int left, int right) {
+  public DexDivFloat2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/DivInt.java b/src/main/java/com/android/tools/r8/dex/code/DexDivInt.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/DivInt.java
rename to src/main/java/com/android/tools/r8/dex/code/DexDivInt.java
index 90e1459..7f5dc8a 100644
--- a/src/main/java/com/android/tools/r8/code/DivInt.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexDivInt.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class DivInt extends Format23x {
+public class DexDivInt extends DexFormat23x {
 
   public static final int OPCODE = 0x93;
   public static final String NAME = "DivInt";
   public static final String SMALI_NAME = "div-int";
 
-  /*package*/ DivInt(int high, BytecodeStream stream) {
+  /*package*/ DexDivInt(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public DivInt(int dest, int left, int right) {
+  public DexDivInt(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/DivInt2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexDivInt2Addr.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/DivInt2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexDivInt2Addr.java
index a92d24f..f321ff2 100644
--- a/src/main/java/com/android/tools/r8/code/DivInt2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexDivInt2Addr.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class DivInt2Addr extends Format12x {
+public class DexDivInt2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xb3;
   public static final String NAME = "DivInt2Addr";
   public static final String SMALI_NAME = "div-int/2addr";
 
-  /*package*/ DivInt2Addr(int high, BytecodeStream stream) {
+  /*package*/ DexDivInt2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public DivInt2Addr(int left, int right) {
+  public DexDivInt2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/DivIntLit16.java b/src/main/java/com/android/tools/r8/dex/code/DexDivIntLit16.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/DivIntLit16.java
rename to src/main/java/com/android/tools/r8/dex/code/DexDivIntLit16.java
index 1a62f6e..10931d3 100644
--- a/src/main/java/com/android/tools/r8/code/DivIntLit16.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexDivIntLit16.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class DivIntLit16 extends Format22s {
+
+public class DexDivIntLit16 extends DexFormat22s {
 
   public static final int OPCODE = 0xd3;
   public static final String NAME = "DivIntLit16";
   public static final String SMALI_NAME = "div-int/lit16";
 
-  /*package*/ DivIntLit16(int high, BytecodeStream stream) {
+  /*package*/ DexDivIntLit16(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public DivIntLit16(int dest, int register, int constant) {
+  public DexDivIntLit16(int dest, int register, int constant) {
     super(dest, register, constant);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/DivIntLit8.java b/src/main/java/com/android/tools/r8/dex/code/DexDivIntLit8.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/DivIntLit8.java
rename to src/main/java/com/android/tools/r8/dex/code/DexDivIntLit8.java
index 31fd0e60..0626aa4 100644
--- a/src/main/java/com/android/tools/r8/code/DivIntLit8.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexDivIntLit8.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class DivIntLit8 extends Format22b {
+public class DexDivIntLit8 extends DexFormat22b {
 
   public static final int OPCODE = 0xdb;
   public static final String NAME = "DivIntLit8";
   public static final String SMALI_NAME = "div-int/lit8";
 
-  DivIntLit8(int high, BytecodeStream stream) {
+  DexDivIntLit8(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public DivIntLit8(int dest, int left, int constant) {
+  public DexDivIntLit8(int dest, int left, int constant) {
     super(dest, left, constant);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/DivLong.java b/src/main/java/com/android/tools/r8/dex/code/DexDivLong.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/DivLong.java
rename to src/main/java/com/android/tools/r8/dex/code/DexDivLong.java
index 271dd04..260be18 100644
--- a/src/main/java/com/android/tools/r8/code/DivLong.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexDivLong.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class DivLong extends Format23x {
+
+public class DexDivLong extends DexFormat23x {
 
   public static final int OPCODE = 0x9e;
   public static final String NAME = "DivLong";
   public static final String SMALI_NAME = "div-long";
 
-  DivLong(int high, BytecodeStream stream) {
+  DexDivLong(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public DivLong(int dest, int left, int right) {
+  public DexDivLong(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/DivLong2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexDivLong2Addr.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/DivLong2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexDivLong2Addr.java
index 40f0946..b36326d 100644
--- a/src/main/java/com/android/tools/r8/code/DivLong2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexDivLong2Addr.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class DivLong2Addr extends Format12x {
+public class DexDivLong2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xbe;
   public static final String NAME = "DivLong2Addr";
   public static final String SMALI_NAME = "div-long/2addr";
 
-  DivLong2Addr(int high, BytecodeStream stream) {
+  DexDivLong2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public DivLong2Addr(int left, int right) {
+  public DexDivLong2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/DoubleToFloat.java b/src/main/java/com/android/tools/r8/dex/code/DexDoubleToFloat.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/DoubleToFloat.java
rename to src/main/java/com/android/tools/r8/dex/code/DexDoubleToFloat.java
index 07b8ab6..008c565 100644
--- a/src/main/java/com/android/tools/r8/code/DoubleToFloat.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexDoubleToFloat.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class DoubleToFloat extends Format12x {
+public class DexDoubleToFloat extends DexFormat12x {
 
   public static final int OPCODE = 0x8c;
   public static final String NAME = "DoubleToFloat";
   public static final String SMALI_NAME = "double-to-float";
 
-  DoubleToFloat(int high, BytecodeStream stream) {
+  DexDoubleToFloat(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public DoubleToFloat(int dest, int source) {
+  public DexDoubleToFloat(int dest, int source) {
     super(dest, source);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/DoubleToInt.java b/src/main/java/com/android/tools/r8/dex/code/DexDoubleToInt.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/DoubleToInt.java
rename to src/main/java/com/android/tools/r8/dex/code/DexDoubleToInt.java
index 6d8f506..99debd4 100644
--- a/src/main/java/com/android/tools/r8/code/DoubleToInt.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexDoubleToInt.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class DoubleToInt extends Format12x {
+
+public class DexDoubleToInt extends DexFormat12x {
 
   public static final int OPCODE = 0x8a;
   public static final String NAME = "DoubleToInt";
   public static final String SMALI_NAME = "doubleto-int";
 
-  DoubleToInt(int high, BytecodeStream stream) {
+  DexDoubleToInt(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public DoubleToInt(int dest, int source) {
+  public DexDoubleToInt(int dest, int source) {
     super(dest, source);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/DoubleToLong.java b/src/main/java/com/android/tools/r8/dex/code/DexDoubleToLong.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/DoubleToLong.java
rename to src/main/java/com/android/tools/r8/dex/code/DexDoubleToLong.java
index d9fa0c5..0ea8942 100644
--- a/src/main/java/com/android/tools/r8/code/DoubleToLong.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexDoubleToLong.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class DoubleToLong extends Format12x {
+
+public class DexDoubleToLong extends DexFormat12x {
 
   public static final int OPCODE = 0x8b;
   public static final String NAME = "DoubleToLong";
   public static final String SMALI_NAME = "double-to-long";
 
-  DoubleToLong(int high, BytecodeStream stream) {
+  DexDoubleToLong(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public DoubleToLong(int dest, int source) {
+  public DexDoubleToLong(int dest, int source) {
     super(dest, source);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/FillArrayData.java b/src/main/java/com/android/tools/r8/dex/code/DexFillArrayData.java
similarity index 85%
rename from src/main/java/com/android/tools/r8/code/FillArrayData.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFillArrayData.java
index a49a31d..de478d7 100644
--- a/src/main/java/com/android/tools/r8/code/FillArrayData.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFillArrayData.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.naming.ClassNameMapper;
 
-public class FillArrayData extends Format31t {
+public class DexFillArrayData extends DexFormat31t {
 
   public static final int OPCODE = 0x26;
   public static final String NAME = "FillArrayData";
   public static final String SMALI_NAME = "fill-array-data";
 
-  FillArrayData(int high, BytecodeStream stream) {
+  DexFillArrayData(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public FillArrayData(int value) {
+  public DexFillArrayData(int value) {
     super(value, -1);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/FillArrayDataPayload.java b/src/main/java/com/android/tools/r8/dex/code/DexFillArrayDataPayload.java
similarity index 85%
rename from src/main/java/com/android/tools/r8/code/FillArrayDataPayload.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFillArrayDataPayload.java
index cab0270..11b34be 100644
--- a/src/main/java/com/android/tools/r8/code/FillArrayDataPayload.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFillArrayDataPayload.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
@@ -15,17 +15,17 @@
 import java.nio.ShortBuffer;
 import java.util.Arrays;
 
-public class FillArrayDataPayload extends Nop {
+public class DexFillArrayDataPayload extends DexNop {
 
   public final int element_width;
   public final long size;
   public final short[] data;
 
-  private static void specify(StructuralSpecification<FillArrayDataPayload, ?> spec) {
+  private static void specify(StructuralSpecification<DexFillArrayDataPayload, ?> spec) {
     spec.withInt(i -> i.element_width).withLong(i -> i.size).withShortArray(i -> i.data);
   }
 
-  FillArrayDataPayload(int high, BytecodeStream stream) {
+  DexFillArrayDataPayload(int high, BytecodeStream stream) {
     super(high, stream);
     element_width = read16BitValue(stream);
     size = read32BitValue(stream);
@@ -39,7 +39,7 @@
     }
   }
 
-  public FillArrayDataPayload(int element_width, long size, short[] data) {
+  public DexFillArrayDataPayload(int element_width, long size, short[] data) {
     this.element_width = element_width;
     this.size = size;
     this.data = data;
@@ -57,7 +57,7 @@
       GraphLens graphLens,
       ObjectToOffsetMapping mapping,
       LensCodeRewriterUtils rewriter) {
-    writeFirst(3, dest);  // Pseudo-opcode = 0x0300
+    writeFirst(3, dest); // Pseudo-opcode = 0x0300
     write16BitValue(element_width, dest);
     write32BitValue(size, dest);
     for (short datum : data) {
@@ -66,8 +66,8 @@
   }
 
   @Override
-  final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
-    return visitor.visit(this, (FillArrayDataPayload) other, FillArrayDataPayload::specify);
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
+    return visitor.visit(this, (DexFillArrayDataPayload) other, DexFillArrayDataPayload::specify);
   }
 
   @Override
@@ -86,8 +86,12 @@
 
   @Override
   public String toString(ClassNameMapper naming) {
-    return super.toString(naming) + "[FillArrayPayload], " +
-        "width: " + element_width + ", size:  " + size;
+    return super.toString(naming)
+        + "[FillArrayPayload], "
+        + "width: "
+        + element_width
+        + ", size:  "
+        + size;
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/FilledNewArray.java b/src/main/java/com/android/tools/r8/dex/code/DexFilledNewArray.java
similarity index 77%
rename from src/main/java/com/android/tools/r8/code/FilledNewArray.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFilledNewArray.java
index 5198876..ab52b2b 100644
--- a/src/main/java/com/android/tools/r8/code/FilledNewArray.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFilledNewArray.java
@@ -1,9 +1,10 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
@@ -13,17 +14,17 @@
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import java.nio.ShortBuffer;
 
-public class FilledNewArray extends Format35c<DexType> {
+public class DexFilledNewArray extends DexFormat35c<DexType> {
 
   public static final int OPCODE = 0x24;
   public static final String NAME = "FilledNewArray";
   public static final String SMALI_NAME = "filled-new-array";
 
-  FilledNewArray(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexFilledNewArray(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getTypeMap());
   }
 
-  public FilledNewArray(int size, DexType type, int v0, int v1, int v2, int v3, int v4) {
+  public DexFilledNewArray(int size, DexType type, int v0, int v1, int v2, int v3, int v4) {
     super(size, type, v0, v1, v2, v3, v4);
   }
 
@@ -44,12 +45,12 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
-    DexType rewritten = graphLens.lookupType(getType());
-    rewritten.collectIndexedItems(indexedItems);
+    DexType rewritten = appView.graphLens().lookupType(getType());
+    rewritten.collectIndexedItems(appView, indexedItems);
   }
 
   public DexType getType() {
@@ -58,7 +59,7 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addInvokeNewArray(getType(), A, new int[]{C, D, E, F, G});
+    builder.addInvokeNewArray(getType(), A, new int[] {C, D, E, F, G});
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/FilledNewArrayRange.java b/src/main/java/com/android/tools/r8/dex/code/DexFilledNewArrayRange.java
similarity index 79%
rename from src/main/java/com/android/tools/r8/code/FilledNewArrayRange.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFilledNewArrayRange.java
index de651f5..5e473dc 100644
--- a/src/main/java/com/android/tools/r8/code/FilledNewArrayRange.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFilledNewArrayRange.java
@@ -1,9 +1,10 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
@@ -13,17 +14,17 @@
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import java.nio.ShortBuffer;
 
-public class FilledNewArrayRange extends Format3rc<DexType> {
+public class DexFilledNewArrayRange extends DexFormat3rc<DexType> {
 
   public static final int OPCODE = 0x25;
   public static final String NAME = "FilledNewArrayRange";
   public static final String SMALI_NAME = "filled-new-array/range";
 
-  FilledNewArrayRange(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexFilledNewArrayRange(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getTypeMap());
   }
 
-  public FilledNewArrayRange(int firstContentRegister, int size, DexType type) {
+  public DexFilledNewArrayRange(int firstContentRegister, int size, DexType type) {
     super(firstContentRegister, size, type);
   }
 
@@ -44,12 +45,12 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
-    DexType rewritten = graphLens.lookupType(getType());
-    rewritten.collectIndexedItems(indexedItems);
+    DexType rewritten = appView.graphLens().lookupType(getType());
+    rewritten.collectIndexedItems(appView, indexedItems);
   }
 
   public DexType getType() {
diff --git a/src/main/java/com/android/tools/r8/code/FloatToDouble.java b/src/main/java/com/android/tools/r8/dex/code/DexFloatToDouble.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/FloatToDouble.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFloatToDouble.java
index 5b11258..8536b7e 100644
--- a/src/main/java/com/android/tools/r8/code/FloatToDouble.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFloatToDouble.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class FloatToDouble extends Format12x {
+public class DexFloatToDouble extends DexFormat12x {
 
   public static final int OPCODE = 0x89;
   public static final String NAME = "FloatToDouble";
   public static final String SMALI_NAME = "float-to-double";
 
-  FloatToDouble(int high, BytecodeStream stream) {
+  DexFloatToDouble(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public FloatToDouble(int dest, int source) {
+  public DexFloatToDouble(int dest, int source) {
     super(dest, source);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/FloatToInt.java b/src/main/java/com/android/tools/r8/dex/code/DexFloatToInt.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/FloatToInt.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFloatToInt.java
index d0d706f..cf95583 100644
--- a/src/main/java/com/android/tools/r8/code/FloatToInt.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFloatToInt.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class FloatToInt extends Format12x {
+public class DexFloatToInt extends DexFormat12x {
 
   public static final int OPCODE = 0x87;
   public static final String NAME = "FloatToInt";
   public static final String SMALI_NAME = "float-to-int";
 
-  FloatToInt(int high, BytecodeStream stream) {
+  DexFloatToInt(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public FloatToInt(int dest, int source) {
+  public DexFloatToInt(int dest, int source) {
     super(dest, source);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/FloatToLong.java b/src/main/java/com/android/tools/r8/dex/code/DexFloatToLong.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/FloatToLong.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFloatToLong.java
index 82346b0..3c7d3b4 100644
--- a/src/main/java/com/android/tools/r8/code/FloatToLong.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFloatToLong.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class FloatToLong extends Format12x {
+
+public class DexFloatToLong extends DexFormat12x {
 
   public static final int OPCODE = 0x88;
   public static final String NAME = "FloatToLong";
   public static final String SMALI_NAME = "float-to-long";
 
-  FloatToLong(int high, BytecodeStream stream) {
+  DexFloatToLong(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public FloatToLong(int dest, int source) {
+  public DexFloatToLong(int dest, int source) {
     super(dest, source);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/Format10t.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat10t.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/Format10t.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFormat10t.java
index 9b2b11c..5ccccb9 100644
--- a/src/main/java/com/android/tools/r8/code/Format10t.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat10t.java
@@ -1,9 +1,10 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -12,18 +13,18 @@
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import java.nio.ShortBuffer;
 
-abstract class Format10t extends Base1Format {
+abstract class DexFormat10t extends DexBase1Format {
 
   public /* offset */ byte AA;
 
   // +AA | op
-  Format10t(int high, BytecodeStream stream) {
+  DexFormat10t(int high, BytecodeStream stream) {
     super(stream);
     // AA is an offset, so convert to signed.
     AA = (byte) high;
   }
 
-  protected Format10t(int AA) {
+  protected DexFormat10t(int AA) {
     assert Byte.MIN_VALUE <= AA && AA <= Byte.MAX_VALUE;
     this.AA = (byte) AA;
   }
@@ -44,8 +45,8 @@
   }
 
   @Override
-  final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
-    return visitor.visitInt(AA, ((Format10t) other).AA);
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
+    return visitor.visitInt(AA, ((DexFormat10t) other).AA);
   }
 
   @Override
@@ -60,9 +61,9 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     // No references.
   }
diff --git a/src/main/java/com/android/tools/r8/code/Format10x.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat10x.java
similarity index 83%
rename from src/main/java/com/android/tools/r8/code/Format10x.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFormat10x.java
index bc8feed..3cb41fb 100644
--- a/src/main/java/com/android/tools/r8/code/Format10x.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat10x.java
@@ -1,9 +1,10 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -11,16 +12,15 @@
 import com.android.tools.r8.naming.ClassNameMapper;
 import java.nio.ShortBuffer;
 
-abstract class Format10x extends Base1Format {
+abstract class DexFormat10x extends DexBase1Format {
 
   // øø | op
-  Format10x(int high, BytecodeStream stream) {
+  DexFormat10x(int high, BytecodeStream stream) {
     // Intentionally left empty.
     super(stream);
   }
 
-  protected Format10x() {
-  }
+  protected DexFormat10x() {}
 
   @Override
   public void write(
@@ -44,9 +44,9 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     // No references.
   }
diff --git a/src/main/java/com/android/tools/r8/code/Format11n.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat11n.java
similarity index 78%
rename from src/main/java/com/android/tools/r8/code/Format11n.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFormat11n.java
index 27c0d27..20bec92 100644
--- a/src/main/java/com/android/tools/r8/code/Format11n.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat11n.java
@@ -1,10 +1,11 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -14,16 +15,16 @@
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
-abstract class Format11n extends Base1Format {
+abstract class DexFormat11n extends DexBase1Format {
 
   public final byte A, B;
 
-  private static void specify(StructuralSpecification<Format11n, ?> spec) {
+  private static void specify(StructuralSpecification<DexFormat11n, ?> spec) {
     spec.withInt(i -> i.A).withInt(i -> i.B);
   }
 
   // #+B | vA | op
-  /*package*/ Format11n(int high, BytecodeStream stream) {
+  /*package*/ DexFormat11n(int high, BytecodeStream stream) {
     super(stream);
     A = (byte) (high & 0xf);
     // Sign extend 4bit value.
@@ -35,7 +36,7 @@
     }
   }
 
-  /*package*/ Format11n(int A, int B) {
+  /*package*/ DexFormat11n(int A, int B) {
     assert 0 <= A && A <= Constants.U4BIT_MAX;
     assert Constants.S4BIT_MIN <= B && B <= Constants.S4BIT_MAX;
     this.A = (byte) A;
@@ -58,8 +59,8 @@
   }
 
   @Override
-  final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
-    return visitor.visit(this, (Format11n) other, Format11n::specify);
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
+    return visitor.visit(this, (DexFormat11n) other, DexFormat11n::specify);
   }
 
   @Override
@@ -69,9 +70,9 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     // No references.
   }
diff --git a/src/main/java/com/android/tools/r8/code/Format11x.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat11x.java
similarity index 79%
rename from src/main/java/com/android/tools/r8/code/Format11x.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFormat11x.java
index 3cc3b73..46d615b 100644
--- a/src/main/java/com/android/tools/r8/code/Format11x.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat11x.java
@@ -1,10 +1,11 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -13,17 +14,17 @@
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import java.nio.ShortBuffer;
 
-abstract class Format11x extends Base1Format {
+abstract class DexFormat11x extends DexBase1Format {
 
   public final short AA;
 
   // vAA | op
-  Format11x(int high, BytecodeStream stream) {
+  DexFormat11x(int high, BytecodeStream stream) {
     super(stream);
     AA = (short) high;
   }
 
-  protected Format11x(int AA) {
+  protected DexFormat11x(int AA) {
     assert 0 <= AA && AA <= Constants.U8BIT_MAX;
     this.AA = (short) AA;
   }
@@ -44,8 +45,8 @@
   }
 
   @Override
-  final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
-    return visitor.visitInt(AA, ((Format11x) other).AA);
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
+    return visitor.visitInt(AA, ((DexFormat11x) other).AA);
   }
 
   @Override
@@ -60,9 +61,9 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     // No references.
   }
diff --git a/src/main/java/com/android/tools/r8/code/Format12x.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat12x.java
similarity index 78%
rename from src/main/java/com/android/tools/r8/code/Format12x.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFormat12x.java
index f3b80aa..29c2224 100644
--- a/src/main/java/com/android/tools/r8/code/Format12x.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat12x.java
@@ -1,10 +1,11 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -14,22 +15,22 @@
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
-abstract class Format12x extends Base1Format {
+abstract class DexFormat12x extends DexBase1Format {
 
   public final byte A, B;
 
-  private static void specify(StructuralSpecification<Format12x, ?> spec) {
+  private static void specify(StructuralSpecification<DexFormat12x, ?> spec) {
     spec.withInt(i -> i.A).withInt(i -> i.B);
   }
 
   // vB | vA | op
-  Format12x(int high, BytecodeStream stream) {
+  DexFormat12x(int high, BytecodeStream stream) {
     super(stream);
     A = (byte) (high & 0xF);
     B = (byte) ((high >> 4) & 0xF);
   }
 
-  Format12x(int A, int B) {
+  DexFormat12x(int A, int B) {
     assert 0 <= A && A <= Constants.U4BIT_MAX;
     assert 0 <= B && B <= Constants.U4BIT_MAX;
     this.A = (byte) A;
@@ -52,11 +53,10 @@
   }
 
   @Override
-  final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
-    return visitor.visit(this, (Format12x) other, Format12x::specify);
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
+    return visitor.visit(this, (DexFormat12x) other, DexFormat12x::specify);
   }
 
-
   @Override
   public String toString(ClassNameMapper naming) {
     return formatString("v" + A + ", v" + B);
@@ -69,9 +69,9 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     // No references.
   }
diff --git a/src/main/java/com/android/tools/r8/code/Format20t.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat20t.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/Format20t.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFormat20t.java
index c9cd18b..c63962f 100644
--- a/src/main/java/com/android/tools/r8/code/Format20t.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat20t.java
@@ -1,9 +1,10 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -12,17 +13,17 @@
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import java.nio.ShortBuffer;
 
-abstract class Format20t extends Base2Format {
+abstract class DexFormat20t extends DexBase2Format {
 
   public /* offset */ short AAAA;
 
   // øø | op | +AAAA
-  Format20t(int high, BytecodeStream stream) {
+  DexFormat20t(int high, BytecodeStream stream) {
     super(stream);
     AAAA = readSigned16BitValue(stream);
   }
 
-  protected Format20t(int AAAA) {
+  protected DexFormat20t(int AAAA) {
     assert Short.MIN_VALUE <= AAAA && AAAA <= Short.MAX_VALUE;
     this.AAAA = (short) AAAA;
   }
@@ -44,8 +45,8 @@
   }
 
   @Override
-  final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
-    return visitor.visitInt(AAAA, ((Format20t) other).AAAA);
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
+    return visitor.visitInt(AAAA, ((DexFormat20t) other).AAAA);
   }
 
   @Override
@@ -60,9 +61,9 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     // No references.
   }
diff --git a/src/main/java/com/android/tools/r8/code/Format21c.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat21c.java
similarity index 73%
rename from src/main/java/com/android/tools/r8/code/Format21c.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFormat21c.java
index 9416be7..d942119 100644
--- a/src/main/java/com/android/tools/r8/code/Format21c.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat21c.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.graph.IndexedDexItem;
@@ -10,19 +10,19 @@
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.util.function.BiPredicate;
 
-abstract class Format21c<T extends IndexedDexItem> extends Base2Format {
+abstract class DexFormat21c<T extends IndexedDexItem> extends DexBase2Format {
 
   public final short AA;
   public T BBBB;
 
   // AA | op | [type|field|string]@BBBB
-  Format21c(int high, BytecodeStream stream, T[] map) {
+  DexFormat21c(int high, BytecodeStream stream, T[] map) {
     super(stream);
     AA = (short) high;
     BBBB = map[read16BitValue(stream)];
   }
 
-  protected Format21c(int AA, T BBBB) {
+  protected DexFormat21c(int AA, T BBBB) {
     assert 0 <= AA && AA <= Constants.U8BIT_MAX;
     this.AA = (short) AA;
     this.BBBB = BBBB;
@@ -35,14 +35,14 @@
 
   @SuppressWarnings("unchecked")
   @Override
-  final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
     return visitor.visit(
         this,
-        (Format21c<T>) other,
+        (DexFormat21c<T>) other,
         spec -> spec.withInt(i -> i.AA).withSpec(this::internalSubSpecify));
   }
 
-  abstract void internalSubSpecify(StructuralSpecification<Format21c<T>, ?> spec);
+  abstract void internalSubSpecify(StructuralSpecification<DexFormat21c<T>, ?> spec);
 
   @Override
   public String toString(ClassNameMapper naming) {
@@ -57,11 +57,12 @@
   }
 
   @Override
-  public boolean equals(Instruction other, BiPredicate<IndexedDexItem, IndexedDexItem> equality) {
+  public boolean equals(
+      DexInstruction other, BiPredicate<IndexedDexItem, IndexedDexItem> equality) {
     if (other == null || this.getClass() != other.getClass()) {
       return false;
     }
-    Format21c<?> o = (Format21c<?>) other;
+    DexFormat21c<?> o = (DexFormat21c<?>) other;
     return o.AA == AA && equality.test(BBBB, o.BBBB);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/code/Format21h.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat21h.java
similarity index 76%
rename from src/main/java/com/android/tools/r8/code/Format21h.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFormat21h.java
index 36b9174..ae07163 100644
--- a/src/main/java/com/android/tools/r8/code/Format21h.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat21h.java
@@ -1,10 +1,11 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -13,23 +14,23 @@
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
-abstract class Format21h extends Base2Format {
+abstract class DexFormat21h extends DexBase2Format {
 
   public final short AA;
   public final char BBBB;
 
-  private static void specify(StructuralSpecification<Format21h, ?> spec) {
+  private static void specify(StructuralSpecification<DexFormat21h, ?> spec) {
     spec.withInt(i -> i.AA).withInt(i -> i.BBBB);
   }
 
   // AA | op | BBBB0000[00000000]
-  /*package*/ Format21h(int high, BytecodeStream stream) {
+  /*package*/ DexFormat21h(int high, BytecodeStream stream) {
     super(stream);
     AA = (short) high;
     BBBB = read16BitValue(stream);
   }
 
-  /*package*/ Format21h(int AA, int BBBB) {
+  /*package*/ DexFormat21h(int AA, int BBBB) {
     assert 0 <= AA && AA <= Constants.U8BIT_MAX;
     assert 0 <= BBBB && BBBB <= Constants.U16BIT_MAX;
     this.AA = (short) AA;
@@ -53,15 +54,15 @@
   }
 
   @Override
-  final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
-    return visitor.visit(this, (Format21h) other, Format21h::specify);
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
+    return visitor.visit(this, (DexFormat21h) other, DexFormat21h::specify);
   }
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     // No references.
   }
diff --git a/src/main/java/com/android/tools/r8/code/Format21s.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat21s.java
similarity index 79%
rename from src/main/java/com/android/tools/r8/code/Format21s.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFormat21s.java
index 550fdd4..1194963 100644
--- a/src/main/java/com/android/tools/r8/code/Format21s.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat21s.java
@@ -1,10 +1,11 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -15,23 +16,23 @@
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
-abstract class Format21s extends Base2Format {
+abstract class DexFormat21s extends DexBase2Format {
 
   public final short AA;
   public final short BBBB;
 
-  private static void specify(StructuralSpecification<Format21s, ?> spec) {
+  private static void specify(StructuralSpecification<DexFormat21s, ?> spec) {
     spec.withInt(i -> i.AA).withInt(i -> i.BBBB);
   }
 
   // AA | op | #+BBBB
-  /*package*/ Format21s(int high, BytecodeStream stream) {
+  /*package*/ DexFormat21s(int high, BytecodeStream stream) {
     super(stream);
     AA = (short) high;
     BBBB = readSigned16BitValue(stream);
   }
 
-  /*package*/ Format21s(int AA, int BBBB) {
+  /*package*/ DexFormat21s(int AA, int BBBB) {
     assert Short.MIN_VALUE <= BBBB && BBBB <= Short.MAX_VALUE;
     assert 0 <= AA && AA <= Constants.U8BIT_MAX;
     this.AA = (short) AA;
@@ -55,8 +56,8 @@
   }
 
   @Override
-  final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
-    return visitor.visit(this, (Format21s) other, Format21s::specify);
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
+    return visitor.visit(this, (DexFormat21s) other, DexFormat21s::specify);
   }
 
   @Override
@@ -71,9 +72,9 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     // No references.
   }
diff --git a/src/main/java/com/android/tools/r8/code/Format21t.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat21t.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/Format21t.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFormat21t.java
index bde930d..21061c3 100644
--- a/src/main/java/com/android/tools/r8/code/Format21t.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat21t.java
@@ -1,10 +1,11 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -17,23 +18,23 @@
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
-public abstract class Format21t extends Base2Format {
+public abstract class DexFormat21t extends DexBase2Format {
 
   public final short AA;
   public /* offset */ short BBBB;
 
-  private static void specify(StructuralSpecification<Format21t, ?> spec) {
+  private static void specify(StructuralSpecification<DexFormat21t, ?> spec) {
     spec.withInt(i -> i.AA).withInt(i -> i.BBBB);
   }
 
   // AA | op | +BBBB
-  Format21t(int high, BytecodeStream stream) {
+  DexFormat21t(int high, BytecodeStream stream) {
     super(stream);
     AA = (short) high;
     BBBB = readSigned16BitValue(stream);
   }
 
-  Format21t(int register, int offset) {
+  DexFormat21t(int register, int offset) {
     assert Short.MIN_VALUE <= offset && offset <= Short.MAX_VALUE;
     assert 0 <= register && register <= Constants.U8BIT_MAX;
     AA = (short) register;
@@ -57,8 +58,8 @@
   }
 
   @Override
-  final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
-    return visitor.visit(this, (Format21t) other, Format21t::specify);
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
+    return visitor.visit(this, (DexFormat21t) other, DexFormat21t::specify);
   }
 
   public abstract Type getType();
@@ -67,7 +68,7 @@
 
   @Override
   public int[] getTargets() {
-    return new int[]{BBBB, getSize()};
+    return new int[] {BBBB, getSize()};
   }
 
   @Override
@@ -89,9 +90,9 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     // No references.
   }
diff --git a/src/main/java/com/android/tools/r8/code/Format22b.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat22b.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/Format22b.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFormat22b.java
index 6f79b50..5f3213e 100644
--- a/src/main/java/com/android/tools/r8/code/Format22b.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat22b.java
@@ -1,10 +1,11 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -15,25 +16,25 @@
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
-public abstract class Format22b extends Base2Format {
+public abstract class DexFormat22b extends DexBase2Format {
 
   public final short AA;
   public final short BB;
   public final byte CC;
 
-  private static void specify(StructuralSpecification<Format22b, ?> spec) {
+  private static void specify(StructuralSpecification<DexFormat22b, ?> spec) {
     spec.withInt(i -> i.AA).withInt(i -> i.BB).withInt(i -> i.CC);
   }
 
   // vAA | op | #+CC | VBB
-  /*package*/ Format22b(int high, BytecodeStream stream) {
+  /*package*/ DexFormat22b(int high, BytecodeStream stream) {
     super(stream);
     AA = (short) high;
     CC = readSigned8BitValue(stream);
     BB = read8BitValue(stream);
   }
 
-  /*package*/ Format22b(int AA, int BB, int CC) {
+  /*package*/ DexFormat22b(int AA, int BB, int CC) {
     assert 0 <= AA && AA <= Constants.U8BIT_MAX;
     assert 0 <= BB && BB <= Constants.U8BIT_MAX;
     assert Byte.MIN_VALUE <= CC && CC <= Byte.MAX_VALUE;
@@ -59,8 +60,8 @@
   }
 
   @Override
-  final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
-    return visitor.visit(this, (Format22b) other, Format22b::specify);
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
+    return visitor.visit(this, (DexFormat22b) other, DexFormat22b::specify);
   }
 
   @Override
@@ -76,9 +77,9 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     // No references.
   }
diff --git a/src/main/java/com/android/tools/r8/code/Format22c.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat22c.java
similarity index 71%
rename from src/main/java/com/android/tools/r8/code/Format22c.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFormat22c.java
index 536ec65..d406aad 100644
--- a/src/main/java/com/android/tools/r8/code/Format22c.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat22c.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.graph.DexReference;
@@ -11,25 +11,26 @@
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.util.function.BiPredicate;
 
-public abstract class Format22c<T extends DexReference> extends Base2Format {
+public abstract class DexFormat22c<T extends DexReference> extends DexBase2Format {
 
   public final byte A;
   public final byte B;
   public T CCCC;
 
-  private static void specify(StructuralSpecification<Format22c<? extends DexReference>, ?> spec) {
+  private static void specify(
+      StructuralSpecification<DexFormat22c<? extends DexReference>, ?> spec) {
     spec.withInt(i -> i.A).withInt(i -> i.B).withDexReference(i -> i.CCCC);
   }
 
   // vB | vA | op | [type|field]@CCCC
-  /*package*/ Format22c(int high, BytecodeStream stream, T[] map) {
+  /*package*/ DexFormat22c(int high, BytecodeStream stream, T[] map) {
     super(stream);
     A = (byte) (high & 0xf);
     B = (byte) ((high >> 4) & 0xf);
     CCCC = map[read16BitValue(stream)];
   }
 
-  /*package*/ Format22c(int A, int B, T CCCC) {
+  /*package*/ DexFormat22c(int A, int B, T CCCC) {
     assert 0 <= A && A <= Constants.U4BIT_MAX;
     assert 0 <= B && B <= Constants.U4BIT_MAX;
     this.A = (byte) A;
@@ -43,8 +44,8 @@
   }
 
   @Override
-  final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
-    return visitor.visit(this, (Format22c<? extends DexReference>) other, Format22c::specify);
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
+    return visitor.visit(this, (DexFormat22c<? extends DexReference>) other, DexFormat22c::specify);
   }
 
   @Override
@@ -60,11 +61,12 @@
   }
 
   @Override
-  public boolean equals(Instruction other, BiPredicate<IndexedDexItem, IndexedDexItem> equality) {
+  public boolean equals(
+      DexInstruction other, BiPredicate<IndexedDexItem, IndexedDexItem> equality) {
     if (other == null || this.getClass() != other.getClass()) {
       return false;
     }
-    Format22c<?> o = (Format22c<?>) other;
+    DexFormat22c<?> o = (DexFormat22c<?>) other;
     return o.A == A && o.B == B && equality.test(CCCC, o.CCCC);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/code/Format22s.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat22s.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/Format22s.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFormat22s.java
index efa14d2..84921eb 100644
--- a/src/main/java/com/android/tools/r8/code/Format22s.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat22s.java
@@ -1,10 +1,11 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -15,25 +16,25 @@
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
-public abstract class Format22s extends Base2Format {
+public abstract class DexFormat22s extends DexBase2Format {
 
   public final byte A;
   public final byte B;
   public final short CCCC;
 
-  private static void specify(StructuralSpecification<Format22s, ?> spec) {
+  private static void specify(StructuralSpecification<DexFormat22s, ?> spec) {
     spec.withInt(i -> i.A).withInt(i -> i.B).withInt(i -> i.CCCC);
   }
 
   // vB | vA | op | #+CCCC
-  /*package*/ Format22s(int high, BytecodeStream stream) {
+  /*package*/ DexFormat22s(int high, BytecodeStream stream) {
     super(stream);
     A = (byte) (high & 0xf);
     B = (byte) ((high >> 4) & 0xf);
     CCCC = readSigned16BitValue(stream);
   }
 
-  /*package*/ Format22s(int A, int B, int CCCC) {
+  /*package*/ DexFormat22s(int A, int B, int CCCC) {
     assert 0 <= A && A <= Constants.U4BIT_MAX;
     assert 0 <= B && B <= Constants.U4BIT_MAX;
     assert Short.MIN_VALUE <= CCCC && CCCC <= Short.MAX_VALUE;
@@ -59,8 +60,8 @@
   }
 
   @Override
-  final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
-    return visitor.visit(this, (Format22s) other, Format22s::specify);
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
+    return visitor.visit(this, (DexFormat22s) other, DexFormat22s::specify);
   }
 
   @Override
@@ -76,9 +77,9 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     // No references.
   }
diff --git a/src/main/java/com/android/tools/r8/code/Format22t.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat22t.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/Format22t.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFormat22t.java
index 9688b4e..395ac6e 100644
--- a/src/main/java/com/android/tools/r8/code/Format22t.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat22t.java
@@ -1,10 +1,11 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -17,25 +18,25 @@
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
-public abstract class Format22t extends Base2Format {
+public abstract class DexFormat22t extends DexBase2Format {
 
   public final byte A;
   public final byte B;
   public /* offset */ short CCCC;
 
-  private static void specify(StructuralSpecification<Format22t, ?> spec) {
+  private static void specify(StructuralSpecification<DexFormat22t, ?> spec) {
     spec.withInt(i -> i.A).withInt(i -> i.B).withInt(i -> i.CCCC);
   }
 
   // vB | vA | op | +CCCC
-  Format22t(int high, BytecodeStream stream) {
+  DexFormat22t(int high, BytecodeStream stream) {
     super(stream);
     A = (byte) (high & 0xf);
     B = (byte) ((high >> 4) & 0xf);
     CCCC = readSigned16BitValue(stream);
   }
 
-  Format22t(int register1, int register2, int offset) {
+  DexFormat22t(int register1, int register2, int offset) {
     assert 0 <= register1 && register1 <= Constants.U4BIT_MAX;
     assert 0 <= register2 && register2 <= Constants.U4BIT_MAX;
     assert Short.MIN_VALUE <= offset && offset <= Short.MAX_VALUE;
@@ -61,8 +62,8 @@
   }
 
   @Override
-  final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
-    return visitor.visit(this, (Format22t) other, Format22t::specify);
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
+    return visitor.visit(this, (DexFormat22t) other, DexFormat22t::specify);
   }
 
   public abstract Type getType();
@@ -71,7 +72,7 @@
 
   @Override
   public int[] getTargets() {
-    return new int[]{CCCC, getSize()};
+    return new int[] {CCCC, getSize()};
   }
 
   @Override
@@ -93,9 +94,9 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     // No references.
   }
diff --git a/src/main/java/com/android/tools/r8/code/Format22x.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat22x.java
similarity index 74%
rename from src/main/java/com/android/tools/r8/code/Format22x.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFormat22x.java
index 1d9d8ba..e7d6f0c 100644
--- a/src/main/java/com/android/tools/r8/code/Format22x.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat22x.java
@@ -1,10 +1,11 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -14,23 +15,23 @@
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
-abstract class Format22x extends Base2Format {
+abstract class DexFormat22x extends DexBase2Format {
 
   public final short AA;
   public final char BBBB;
 
-  private static void specify(StructuralSpecification<Format22x, ?> spec) {
+  private static void specify(StructuralSpecification<DexFormat22x, ?> spec) {
     spec.withInt(i -> i.AA).withInt(i -> i.BBBB);
   }
 
   // AA | op | vBBBB
-  Format22x(int high, BytecodeStream stream) {
+  DexFormat22x(int high, BytecodeStream stream) {
     super(stream);
     AA = (short) high;
     BBBB = read16BitValue(stream);
   }
 
-  Format22x(int dest, int src) {
+  DexFormat22x(int dest, int src) {
     assert 0 <= dest && dest <= Constants.U8BIT_MAX;
     assert 0 <= src && src <= Constants.U16BIT_MAX;
     AA = (short) dest;
@@ -54,26 +55,25 @@
   }
 
   @Override
-  final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
-    return visitor.visit(this, (Format22x) other, Format22x::specify);
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
+    return visitor.visit(this, (DexFormat22x) other, DexFormat22x::specify);
   }
 
-
   @Override
   public String toString(ClassNameMapper naming) {
-    return formatString("v" + AA + ", v" + (int)BBBB);
+    return formatString("v" + AA + ", v" + (int) BBBB);
   }
 
   @Override
   public String toSmaliString(ClassNameMapper naming) {
-    return formatSmaliString("v" + AA + ", v" + (int)BBBB);
+    return formatSmaliString("v" + AA + ", v" + (int) BBBB);
   }
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     // No references.
   }
diff --git a/src/main/java/com/android/tools/r8/code/Format23x.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat23x.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/Format23x.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFormat23x.java
index ca3ef80..ee90cf8 100644
--- a/src/main/java/com/android/tools/r8/code/Format23x.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat23x.java
@@ -1,10 +1,11 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -14,25 +15,25 @@
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
-abstract class Format23x extends Base2Format {
+abstract class DexFormat23x extends DexBase2Format {
 
   public final short AA;
   public final short BB;
   public final short CC;
 
-  private static void specify(StructuralSpecification<Format23x, ?> spec) {
+  private static void specify(StructuralSpecification<DexFormat23x, ?> spec) {
     spec.withInt(i -> i.AA).withInt(i -> i.BB).withInt(i -> i.CC);
   }
 
   // vAA | op | vCC | vBB
-  Format23x(int high, BytecodeStream stream) {
+  DexFormat23x(int high, BytecodeStream stream) {
     super(stream);
     AA = (short) high;
     CC = read8BitValue(stream);
     BB = read8BitValue(stream);
   }
 
-  Format23x(int AA, int BB, int CC) {
+  DexFormat23x(int AA, int BB, int CC) {
     assert 0 <= AA && AA <= Constants.U8BIT_MAX;
     assert 0 <= BB && BB <= Constants.U8BIT_MAX;
     assert 0 <= CC && CC <= Constants.U8BIT_MAX;
@@ -58,8 +59,8 @@
   }
 
   @Override
-  final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
-    return visitor.visit(this, (Format23x) other, Format23x::specify);
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
+    return visitor.visit(this, (DexFormat23x) other, DexFormat23x::specify);
   }
 
   @Override
@@ -74,9 +75,9 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     // No references.
   }
diff --git a/src/main/java/com/android/tools/r8/code/Format30t.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat30t.java
similarity index 79%
rename from src/main/java/com/android/tools/r8/code/Format30t.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFormat30t.java
index ba986cc..878cc7b 100644
--- a/src/main/java/com/android/tools/r8/code/Format30t.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat30t.java
@@ -1,9 +1,10 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -12,17 +13,17 @@
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import java.nio.ShortBuffer;
 
-abstract class Format30t extends Base3Format {
+abstract class DexFormat30t extends DexBase3Format {
 
   public /* offset */ int AAAAAAAA;
 
   // øø | op | AAAAlo | AAAAhi
-  Format30t(int high, BytecodeStream stream) {
+  DexFormat30t(int high, BytecodeStream stream) {
     super(stream);
     AAAAAAAA = readSigned32BitValue(stream);
   }
 
-  protected Format30t(int AAAAAAAA) {
+  protected DexFormat30t(int AAAAAAAA) {
     this.AAAAAAAA = AAAAAAAA;
   }
 
@@ -43,8 +44,8 @@
   }
 
   @Override
-  final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
-    return visitor.visitInt(AAAAAAAA, ((Format30t) other).AAAAAAAA);
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
+    return visitor.visitInt(AAAAAAAA, ((DexFormat30t) other).AAAAAAAA);
   }
 
   @Override
@@ -59,9 +60,9 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     // No references.
   }
diff --git a/src/main/java/com/android/tools/r8/code/Format31c.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat31c.java
similarity index 76%
rename from src/main/java/com/android/tools/r8/code/Format31c.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFormat31c.java
index 6664662..82e033a 100644
--- a/src/main/java/com/android/tools/r8/code/Format31c.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat31c.java
@@ -1,11 +1,12 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import static com.android.tools.r8.dex.Constants.U8BIT_MAX;
 
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.IndexedDexItem;
@@ -18,23 +19,23 @@
 import java.nio.ShortBuffer;
 import java.util.function.BiPredicate;
 
-abstract class Format31c extends Base3Format {
+abstract class DexFormat31c extends DexBase3Format {
 
   public final short AA;
   public DexString BBBBBBBB;
 
-  private static void specify(StructuralSpecification<Format31c, ?> spec) {
+  private static void specify(StructuralSpecification<DexFormat31c, ?> spec) {
     spec.withInt(i -> i.AA).withItem(i -> i.BBBBBBBB);
   }
 
   // vAA | op | string@BBBBlo | string@#+BBBBhi
-  Format31c(int high, BytecodeStream stream, DexString[] map) {
+  DexFormat31c(int high, BytecodeStream stream, DexString[] map) {
     super(stream);
     AA = (short) high;
     BBBBBBBB = map[(int) read32BitValue(stream)];
   }
 
-  Format31c(int AA, DexString BBBBBBBB) {
+  DexFormat31c(int AA, DexString BBBBBBBB) {
     assert 0 <= AA && AA <= U8BIT_MAX;
     this.AA = (short) AA;
     this.BBBBBBBB = BBBBBBBB;
@@ -57,8 +58,8 @@
   }
 
   @Override
-  final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
-    return visitor.visit(this, (Format31c) other, Format31c::specify);
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
+    return visitor.visit(this, (DexFormat31c) other, DexFormat31c::specify);
   }
 
   @Override
@@ -69,19 +70,20 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     BBBBBBBB.collectIndexedItems(indexedItems);
   }
 
   @Override
-  public boolean equals(Instruction other, BiPredicate<IndexedDexItem, IndexedDexItem> equality) {
+  public boolean equals(
+      DexInstruction other, BiPredicate<IndexedDexItem, IndexedDexItem> equality) {
     if (other == null || (this.getClass() != other.getClass())) {
       return false;
     }
-    Format31c o = (Format31c) other;
+    DexFormat31c o = (DexFormat31c) other;
     return o.AA == AA && equality.test(BBBBBBBB, o.BBBBBBBB);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/code/Format31i.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat31i.java
similarity index 77%
rename from src/main/java/com/android/tools/r8/code/Format31i.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFormat31i.java
index c2fa1b1..04e57f1 100644
--- a/src/main/java/com/android/tools/r8/code/Format31i.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat31i.java
@@ -1,10 +1,11 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -14,23 +15,23 @@
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
-abstract class Format31i extends Base3Format {
+abstract class DexFormat31i extends DexBase3Format {
 
   public final short AA;
   public final int BBBBBBBB;
 
-  private static void specify(StructuralSpecification<Format31i, ?> spec) {
+  private static void specify(StructuralSpecification<DexFormat31i, ?> spec) {
     spec.withInt(i -> i.AA).withInt(i -> i.BBBBBBBB);
   }
 
   // vAA | op | #+BBBBlo | #+BBBBhi
-  /*package*/ Format31i(int high, BytecodeStream stream) {
+  /*package*/ DexFormat31i(int high, BytecodeStream stream) {
     super(stream);
     AA = (short) high;
     BBBBBBBB = readSigned32BitValue(stream);
   }
 
-  /*package*/ Format31i(int AA, int BBBBBBBB) {
+  /*package*/ DexFormat31i(int AA, int BBBBBBBB) {
     assert 0 <= AA && AA <= Constants.U8BIT_MAX;
     this.AA = (short) AA;
     this.BBBBBBBB = BBBBBBBB;
@@ -53,8 +54,8 @@
   }
 
   @Override
-  final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
-    return visitor.visit(this, (Format31i) other, Format31i::specify);
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
+    return visitor.visit(this, (DexFormat31i) other, DexFormat31i::specify);
   }
 
   @Override
@@ -64,9 +65,9 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     // No references.
   }
diff --git a/src/main/java/com/android/tools/r8/code/Format31t.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat31t.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/Format31t.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFormat31t.java
index f85aca6..cc57a14 100644
--- a/src/main/java/com/android/tools/r8/code/Format31t.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat31t.java
@@ -1,10 +1,11 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -14,23 +15,23 @@
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
-public abstract class Format31t extends Base3Format {
+public abstract class DexFormat31t extends DexBase3Format {
 
   public final short AA;
   protected /* offset */ int BBBBBBBB;
 
-  private static void specify(StructuralSpecification<Format31t, ?> spec) {
+  private static void specify(StructuralSpecification<DexFormat31t, ?> spec) {
     spec.withInt(i -> i.AA).withInt(i -> i.BBBBBBBB);
   }
 
   // vAA | op | +BBBBlo | +BBBBhi
-  Format31t(int high, BytecodeStream stream) {
+  DexFormat31t(int high, BytecodeStream stream) {
     super(stream);
     AA = (short) high;
     BBBBBBBB = readSigned32BitValue(stream);
   }
 
-  Format31t(int register, int payloadOffset) {
+  DexFormat31t(int register, int payloadOffset) {
     assert 0 <= register && register <= Constants.U8BIT_MAX;
     AA = (short) register;
     BBBBBBBB = payloadOffset;
@@ -68,8 +69,8 @@
   }
 
   @Override
-  final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
-    return visitor.visit(this, (Format31t) other, Format31t::specify);
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
+    return visitor.visit(this, (DexFormat31t) other, DexFormat31t::specify);
   }
 
   @Override
@@ -79,9 +80,9 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     // No references.
   }
diff --git a/src/main/java/com/android/tools/r8/code/Format32x.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat32x.java
similarity index 79%
rename from src/main/java/com/android/tools/r8/code/Format32x.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFormat32x.java
index c637383..f9a7792 100644
--- a/src/main/java/com/android/tools/r8/code/Format32x.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat32x.java
@@ -1,11 +1,12 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import static com.android.tools.r8.dex.Constants.U16BIT_MAX;
 
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -15,23 +16,23 @@
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
-abstract class Format32x extends Base3Format {
+abstract class DexFormat32x extends DexBase3Format {
 
   public final int AAAA;
   public final int BBBB;
 
-  private static void specify(StructuralSpecification<Format32x, ?> spec) {
+  private static void specify(StructuralSpecification<DexFormat32x, ?> spec) {
     spec.withInt(i -> i.AAAA).withInt(i -> i.BBBB);
   }
 
   // øø | op | AAAA | BBBB
-  Format32x(int high, BytecodeStream stream) {
+  DexFormat32x(int high, BytecodeStream stream) {
     super(stream);
     AAAA = read16BitValue(stream);
     BBBB = read16BitValue(stream);
   }
 
-  Format32x(int dest, int src) {
+  DexFormat32x(int dest, int src) {
     assert 0 <= dest && dest <= U16BIT_MAX;
     assert 0 <= src && src <= U16BIT_MAX;
     AAAA = dest;
@@ -56,8 +57,8 @@
   }
 
   @Override
-  final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
-    return visitor.visit(this, (Format32x) other, Format32x::specify);
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
+    return visitor.visit(this, (DexFormat32x) other, DexFormat32x::specify);
   }
 
   @Override
@@ -72,9 +73,9 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     // No references.
   }
diff --git a/src/main/java/com/android/tools/r8/code/Format35c.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat35c.java
similarity index 77%
rename from src/main/java/com/android/tools/r8/code/Format35c.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFormat35c.java
index e5d2489..78a5323 100644
--- a/src/main/java/com/android/tools/r8/code/Format35c.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat35c.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.graph.IndexedDexItem;
@@ -11,7 +11,8 @@
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.util.function.BiPredicate;
 
-public abstract class Format35c<T extends IndexedDexItem & StructuralItem<T>> extends Base3Format {
+public abstract class DexFormat35c<T extends IndexedDexItem & StructuralItem<T>>
+    extends DexBase3Format {
 
   public final byte A;
   public final byte C;
@@ -22,7 +23,7 @@
   public T BBBB;
 
   private static <T extends IndexedDexItem & StructuralItem<T>> void specify(
-      StructuralSpecification<Format35c<T>, ?> spec) {
+      StructuralSpecification<DexFormat35c<T>, ?> spec) {
     spec.withInt(i -> i.A)
         .withInt(i -> i.C)
         .withInt(i -> i.D)
@@ -33,7 +34,7 @@
   }
 
   // A | G | op | BBBB | F | E | D | C
-  Format35c(int high, BytecodeStream stream, T[] map) {
+  DexFormat35c(int high, BytecodeStream stream, T[] map) {
     super(stream);
     G = (byte) (high & 0xf);
     A = (byte) ((high >> 4) & 0xf);
@@ -46,7 +47,7 @@
     D = (byte) ((next >> 4) & 0xf);
   }
 
-  Format35c(int A, T BBBB, int C, int D, int E, int F, int G) {
+  DexFormat35c(int A, T BBBB, int C, int D, int E, int F, int G) {
     assert 0 <= A && A <= Constants.U4BIT_MAX;
     assert 0 <= C && C <= Constants.U4BIT_MAX;
     assert 0 <= D && D <= Constants.U4BIT_MAX;
@@ -64,19 +65,19 @@
 
   @Override
   public final int hashCode() {
-    return ((BBBB.hashCode() << 24) | (A << 20) | (C << 16) | (D << 12) | (E << 8) | (F << 4)
-        | G) ^ getClass().hashCode();
+    return ((BBBB.hashCode() << 24) | (A << 20) | (C << 16) | (D << 12) | (E << 8) | (F << 4) | G)
+        ^ getClass().hashCode();
   }
 
   @SuppressWarnings("unchecked")
   @Override
-  final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
-    return visitor.visit(this, (Format35c<T>) other, Format35c::specify);
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
+    return visitor.visit(this, (DexFormat35c<T>) other, DexFormat35c::specify);
   }
 
   private void appendRegisterArguments(StringBuilder builder, String separator) {
     builder.append("{ ");
-    int[] values = new int[]{C, D, E, F, G};
+    int[] values = new int[] {C, D, E, F, G};
     for (int i = 0; i < A; i++) {
       if (i != 0) {
         builder.append(separator);
@@ -110,12 +111,18 @@
   }
 
   @Override
-  public boolean equals(Instruction other, BiPredicate<IndexedDexItem, IndexedDexItem> equality) {
+  public boolean equals(
+      DexInstruction other, BiPredicate<IndexedDexItem, IndexedDexItem> equality) {
     if (other == null || (this.getClass() != other.getClass())) {
       return false;
     }
-    Format35c o = (Format35c) other;
-    return o.A == A && o.C == C && o.D == D && o.E == E && o.F == F && o.G == G
+    DexFormat35c o = (DexFormat35c) other;
+    return o.A == A
+        && o.C == C
+        && o.D == D
+        && o.E == E
+        && o.F == F
+        && o.G == G
         && equality.test(BBBB, o.BBBB);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/code/Format3rc.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat3rc.java
similarity index 79%
rename from src/main/java/com/android/tools/r8/code/Format3rc.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFormat3rc.java
index 0ceeb4a..01fff36b 100644
--- a/src/main/java/com/android/tools/r8/code/Format3rc.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat3rc.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.graph.IndexedDexItem;
@@ -11,26 +11,27 @@
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.util.function.BiPredicate;
 
-public abstract class Format3rc<T extends IndexedDexItem & StructuralItem<T>> extends Base3Format {
+public abstract class DexFormat3rc<T extends IndexedDexItem & StructuralItem<T>>
+    extends DexBase3Format {
 
   public final short AA;
   public final char CCCC;
   public T BBBB;
 
   private static <T extends IndexedDexItem & StructuralItem<T>> void specify(
-      StructuralSpecification<Format3rc<T>, ?> spec) {
+      StructuralSpecification<DexFormat3rc<T>, ?> spec) {
     spec.withInt(i -> i.AA).withInt(i -> i.CCCC).withItem(i -> i.BBBB);
   }
 
   // AA | op | [meth|type]@BBBBB | CCCC
-  Format3rc(int high, BytecodeStream stream, T[] map) {
+  DexFormat3rc(int high, BytecodeStream stream, T[] map) {
     super(stream);
     this.AA = (short) high;
     this.BBBB = map[read16BitValue(stream)];
     this.CCCC = read16BitValue(stream);
   }
 
-  Format3rc(int firstArgumentRegister, int argumentCount, T dexItem) {
+  DexFormat3rc(int firstArgumentRegister, int argumentCount, T dexItem) {
     assert 0 <= firstArgumentRegister && firstArgumentRegister <= Constants.U16BIT_MAX;
     assert 0 <= argumentCount && argumentCount <= Constants.U8BIT_MAX;
     this.CCCC = (char) firstArgumentRegister;
@@ -49,8 +50,8 @@
 
   @SuppressWarnings("unchecked")
   @Override
-  final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
-    return visitor.visit(this, (Format3rc<T>) other, Format3rc::specify);
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
+    return visitor.visit(this, (DexFormat3rc<T>) other, DexFormat3rc::specify);
   }
 
   private void appendRegisterRange(StringBuilder builder) {
@@ -87,11 +88,12 @@
   }
 
   @Override
-  public boolean equals(Instruction other, BiPredicate<IndexedDexItem, IndexedDexItem> equality) {
+  public boolean equals(
+      DexInstruction other, BiPredicate<IndexedDexItem, IndexedDexItem> equality) {
     if (other == null || (this.getClass() != other.getClass())) {
       return false;
     }
-    Format3rc<?> o = (Format3rc<?>) other;
+    DexFormat3rc<?> o = (DexFormat3rc<?>) other;
     return o.AA == AA && o.CCCC == CCCC && equality.test(BBBB, o.BBBB);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/code/Format45cc.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat45cc.java
similarity index 85%
rename from src/main/java/com/android/tools/r8/code/Format45cc.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFormat45cc.java
index 1542015..bdc0a15 100644
--- a/src/main/java/com/android/tools/r8/code/Format45cc.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat45cc.java
@@ -1,11 +1,12 @@
 // Copyright (c) 2017, 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.code;
+package com.android.tools.r8.dex.code;
 
 import static com.android.tools.r8.dex.Constants.U4BIT_MAX;
 
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.GraphLens;
@@ -21,7 +22,7 @@
 import java.nio.ShortBuffer;
 
 /** Format45cc for instructions of size 4, with 5 registers and 2 constant pool index. */
-public abstract class Format45cc extends Base4Format {
+public abstract class DexFormat45cc extends DexBase4Format {
 
   public final byte A;
   public final byte C;
@@ -32,7 +33,7 @@
   public DexMethod BBBB;
   public DexProto HHHH;
 
-  private static void specify(StructuralSpecification<Format45cc, ?> spec) {
+  private static void specify(StructuralSpecification<DexFormat45cc, ?> spec) {
     spec.withInt(i -> i.A)
         .withInt(i -> i.C)
         .withInt(i -> i.D)
@@ -43,7 +44,7 @@
         .withItem(i -> i.HHHH);
   }
 
-  Format45cc(int high, BytecodeStream stream, DexMethod[] methodMap, DexProto[] protoMap) {
+  DexFormat45cc(int high, BytecodeStream stream, DexMethod[] methodMap, DexProto[] protoMap) {
     super(stream);
     G = (byte) (high & 0xf);
     A = (byte) ((high >> 4) & 0xf);
@@ -58,7 +59,7 @@
   }
 
   // A | G | op | [meth]@BBBB | F | E | D | C | [proto]@HHHH
-  protected Format45cc(int A, DexMethod BBBB, DexProto HHHH, int C, int D, int E, int F, int G) {
+  protected DexFormat45cc(int A, DexMethod BBBB, DexProto HHHH, int C, int D, int E, int F, int G) {
     assert 0 <= A && A <= U4BIT_MAX;
     assert 0 <= C && C <= U4BIT_MAX;
     assert 0 <= D && D <= U4BIT_MAX;
@@ -89,23 +90,23 @@
   }
 
   @Override
-  final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
-    return visitor.visit(this, (Format45cc) other, Format45cc::specify);
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
+    return visitor.visit(this, (DexFormat45cc) other, DexFormat45cc::specify);
   }
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     MethodLookupResult lookup =
-        graphLens.lookupMethod(getMethod(), context.getReference(), Type.POLYMORPHIC);
+        appView.graphLens().lookupMethod(getMethod(), context.getReference(), Type.POLYMORPHIC);
     assert lookup.getType() == Type.POLYMORPHIC;
-    lookup.getReference().collectIndexedItems(indexedItems);
+    lookup.getReference().collectIndexedItems(appView, indexedItems);
 
     DexProto rewrittenProto = rewriter.rewriteProto(getProto());
-    rewrittenProto.collectIndexedItems(indexedItems);
+    rewrittenProto.collectIndexedItems(appView, indexedItems);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/Format4rcc.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat4rcc.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/Format4rcc.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFormat4rcc.java
index 4da5b40..a96b70b 100644
--- a/src/main/java/com/android/tools/r8/code/Format4rcc.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat4rcc.java
@@ -1,10 +1,11 @@
 // Copyright (c) 2017, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.GraphLens;
@@ -21,19 +22,19 @@
 import java.util.function.BiPredicate;
 
 /** Format4rcc for instructions of size 4, with a range of registers and 2 constant pool index. */
-public abstract class Format4rcc extends Base4Format {
+public abstract class DexFormat4rcc extends DexBase4Format {
 
   public final short AA;
   public final char CCCC;
   public DexMethod BBBB;
   public DexProto HHHH;
 
-  private static void specify(StructuralSpecification<Format4rcc, ?> spec) {
+  private static void specify(StructuralSpecification<DexFormat4rcc, ?> spec) {
     spec.withInt(i -> i.AA).withInt(i -> i.CCCC).withItem(i -> i.BBBB).withItem(i -> i.HHHH);
   }
 
   // AA | op | [meth]@BBBB | CCCC | [proto]@HHHH
-  Format4rcc(int high, BytecodeStream stream, DexMethod[] methodMap, DexProto[] protoMap) {
+  DexFormat4rcc(int high, BytecodeStream stream, DexMethod[] methodMap, DexProto[] protoMap) {
     super(stream);
     this.AA = (short) high;
     this.BBBB = methodMap[read16BitValue(stream)];
@@ -41,7 +42,7 @@
     this.HHHH = protoMap[read16BitValue(stream)];
   }
 
-  Format4rcc(int firstArgumentRegister, int argumentCount, DexMethod method, DexProto proto) {
+  DexFormat4rcc(int firstArgumentRegister, int argumentCount, DexMethod method, DexProto proto) {
     assert 0 <= firstArgumentRegister && firstArgumentRegister <= Constants.U16BIT_MAX;
     assert 0 <= argumentCount && argumentCount <= Constants.U8BIT_MAX;
     this.CCCC = (char) firstArgumentRegister;
@@ -75,8 +76,8 @@
   }
 
   @Override
-  final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
-    return visitor.visit(this, (Format4rcc) other, Format4rcc::specify);
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
+    return visitor.visit(this, (DexFormat4rcc) other, DexFormat4rcc::specify);
   }
 
   @Override
@@ -111,25 +112,26 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     MethodLookupResult lookup =
-        graphLens.lookupMethod(getMethod(), context.getReference(), Type.POLYMORPHIC);
+        appView.graphLens().lookupMethod(getMethod(), context.getReference(), Type.POLYMORPHIC);
     assert lookup.getType() == Type.POLYMORPHIC;
-    lookup.getReference().collectIndexedItems(indexedItems);
+    lookup.getReference().collectIndexedItems(appView, indexedItems);
 
     DexProto rewrittenProto = rewriter.rewriteProto(getProto());
-    rewrittenProto.collectIndexedItems(indexedItems);
+    rewrittenProto.collectIndexedItems(appView, indexedItems);
   }
 
   @Override
-  public boolean equals(Instruction other, BiPredicate<IndexedDexItem, IndexedDexItem> equality) {
+  public boolean equals(
+      DexInstruction other, BiPredicate<IndexedDexItem, IndexedDexItem> equality) {
     if (other == null || (this.getClass() != other.getClass())) {
       return false;
     }
-    Format4rcc o = (Format4rcc) other;
+    DexFormat4rcc o = (DexFormat4rcc) other;
     return o.AA == AA
         && o.CCCC == CCCC
         && equality.test(BBBB, o.BBBB)
diff --git a/src/main/java/com/android/tools/r8/code/Format51l.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat51l.java
similarity index 78%
rename from src/main/java/com/android/tools/r8/code/Format51l.java
rename to src/main/java/com/android/tools/r8/dex/code/DexFormat51l.java
index 1417bf8..fa88721 100644
--- a/src/main/java/com/android/tools/r8/code/Format51l.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat51l.java
@@ -1,10 +1,11 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -14,23 +15,23 @@
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
-abstract class Format51l extends Base5Format {
+abstract class DexFormat51l extends DexBase5Format {
 
   public final short AA;
   public final long BBBBBBBBBBBBBBBB;
 
-  private static void specify(StructuralSpecification<Format51l, ?> spec) {
+  private static void specify(StructuralSpecification<DexFormat51l, ?> spec) {
     spec.withInt(i -> i.AA).withLong(i -> i.BBBBBBBBBBBBBBBB);
   }
 
   // AA | op | BBBB | BBBB | BBBB | BBBB
-  Format51l(int high, BytecodeStream stream) {
+  DexFormat51l(int high, BytecodeStream stream) {
     super(stream);
     AA = (short) high;
     BBBBBBBBBBBBBBBB = read64BitValue(stream);
   }
 
-  public Format51l(int AA, long BBBBBBBBBBBBBBBB) {
+  public DexFormat51l(int AA, long BBBBBBBBBBBBBBBB) {
     assert 0 <= AA && AA <= Constants.U8BIT_MAX;
     this.AA = (short) AA;
     this.BBBBBBBBBBBBBBBB = BBBBBBBBBBBBBBBB;
@@ -53,8 +54,8 @@
   }
 
   @Override
-  final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
-    return visitor.visit(this, (Format51l) other, Format51l::specify);
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
+    return visitor.visit(this, (DexFormat51l) other, DexFormat51l::specify);
   }
 
   @Override
@@ -64,9 +65,9 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     // No references.
   }
diff --git a/src/main/java/com/android/tools/r8/code/Goto.java b/src/main/java/com/android/tools/r8/dex/code/DexGoto.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/Goto.java
rename to src/main/java/com/android/tools/r8/dex/code/DexGoto.java
index fc911ee..6b7c0b2 100644
--- a/src/main/java/com/android/tools/r8/code/Goto.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexGoto.java
@@ -1,21 +1,21 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class Goto extends Format10t {
+public class DexGoto extends DexFormat10t {
 
   public static final int OPCODE = 0x28;
   public static final String NAME = "Goto";
   public static final String SMALI_NAME = "goto";
 
-  Goto(int high, BytecodeStream stream) {
+  DexGoto(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public Goto(int AA) {
+  public DexGoto(int AA) {
     super(AA);
   }
 
@@ -36,7 +36,7 @@
 
   @Override
   public int[] getTargets() {
-    return new int[] { AA };
+    return new int[] {AA};
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/Goto16.java b/src/main/java/com/android/tools/r8/dex/code/DexGoto16.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/Goto16.java
rename to src/main/java/com/android/tools/r8/dex/code/DexGoto16.java
index c4cec89..0a41ab6 100644
--- a/src/main/java/com/android/tools/r8/code/Goto16.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexGoto16.java
@@ -1,21 +1,21 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class Goto16 extends Format20t {
+public class DexGoto16 extends DexFormat20t {
 
   public static final int OPCODE = 0x29;
   public static final String NAME = "Goto16";
   public static final String SMALI_NAME = "goto/16";
 
-  Goto16(int high, BytecodeStream stream) {
+  DexGoto16(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public Goto16(int AAAA) {
+  public DexGoto16(int AAAA) {
     super(AAAA);
   }
 
@@ -36,7 +36,7 @@
 
   @Override
   public int[] getTargets() {
-    return new int[]{AAAA};
+    return new int[] {AAAA};
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/Goto32.java b/src/main/java/com/android/tools/r8/dex/code/DexGoto32.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/Goto32.java
rename to src/main/java/com/android/tools/r8/dex/code/DexGoto32.java
index 3a4c6b8..bfa83cc 100644
--- a/src/main/java/com/android/tools/r8/code/Goto32.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexGoto32.java
@@ -1,21 +1,21 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class Goto32 extends Format30t {
+public class DexGoto32 extends DexFormat30t {
 
   public static final int OPCODE = 0x2a;
   public static final String NAME = "Goto32";
   public static final String SMALI_NAME = "goto/32";
 
-  Goto32(int high, BytecodeStream stream) {
+  DexGoto32(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public Goto32(int AAAAAAAA) {
+  public DexGoto32(int AAAAAAAA) {
     super(AAAAAAAA);
   }
 
@@ -36,7 +36,7 @@
 
   @Override
   public int[] getTargets() {
-    return new int[]{AAAAAAAA};
+    return new int[] {AAAAAAAA};
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/IfEq.java b/src/main/java/com/android/tools/r8/dex/code/DexIfEq.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/IfEq.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIfEq.java
index abd77ee..345328f 100644
--- a/src/main/java/com/android/tools/r8/code/IfEq.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIfEq.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.If.Type;
 import com.android.tools.r8.ir.code.ValueTypeConstraint;
 
-public class IfEq extends Format22t {
+public class DexIfEq extends DexFormat22t {
 
   public static final int OPCODE = 0x32;
   public static final String NAME = "IfEq";
   public static final String SMALI_NAME = "if-eq";
 
-  IfEq(int high, BytecodeStream stream) {
+  DexIfEq(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public IfEq(int register1, int register2, int offset) {
+  public DexIfEq(int register1, int register2, int offset) {
     super(register1, register2, offset);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/IfEqz.java b/src/main/java/com/android/tools/r8/dex/code/DexIfEqz.java
similarity index 83%
rename from src/main/java/com/android/tools/r8/code/IfEqz.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIfEqz.java
index 8bfed6d..517576c 100644
--- a/src/main/java/com/android/tools/r8/code/IfEqz.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIfEqz.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.If.Type;
 import com.android.tools.r8.ir.code.ValueTypeConstraint;
 
-public class IfEqz extends Format21t {
+public class DexIfEqz extends DexFormat21t {
 
   public static final int OPCODE = 0x38;
   public static final String NAME = "IfEqz";
   public static final String SMALI_NAME = "if-eqz";
 
-  IfEqz(int high, BytecodeStream stream) {
+  DexIfEqz(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public IfEqz(int register, int offset) {
+  public DexIfEqz(int register, int offset) {
     super(register, offset);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/IfGe.java b/src/main/java/com/android/tools/r8/dex/code/DexIfGe.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/IfGe.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIfGe.java
index dd123f2..4c49892 100644
--- a/src/main/java/com/android/tools/r8/code/IfGe.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIfGe.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.If.Type;
 import com.android.tools.r8.ir.code.ValueTypeConstraint;
 
-public class IfGe extends Format22t {
+public class DexIfGe extends DexFormat22t {
 
   public static final int OPCODE = 0x35;
   public static final String NAME = "IfGe";
   public static final String SMALI_NAME = "if-ge";
 
-  IfGe(int high, BytecodeStream stream) {
+  DexIfGe(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public IfGe(int register1, int register2, int offset) {
+  public DexIfGe(int register1, int register2, int offset) {
     super(register1, register2, offset);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/IfGez.java b/src/main/java/com/android/tools/r8/dex/code/DexIfGez.java
similarity index 83%
rename from src/main/java/com/android/tools/r8/code/IfGez.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIfGez.java
index 9ca69c0..6a9b49e 100644
--- a/src/main/java/com/android/tools/r8/code/IfGez.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIfGez.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.If.Type;
 import com.android.tools.r8.ir.code.ValueTypeConstraint;
 
-public class IfGez extends Format21t {
+public class DexIfGez extends DexFormat21t {
 
   public static final int OPCODE = 0x3b;
   public static final String NAME = "IfGez";
   public static final String SMALI_NAME = "if-gez";
 
-  IfGez(int high, BytecodeStream stream) {
+  DexIfGez(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public IfGez(int register, int offset) {
+  public DexIfGez(int register, int offset) {
     super(register, offset);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/IfGt.java b/src/main/java/com/android/tools/r8/dex/code/DexIfGt.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/IfGt.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIfGt.java
index 84a8fcb..20abfdc 100644
--- a/src/main/java/com/android/tools/r8/code/IfGt.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIfGt.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.If.Type;
 import com.android.tools.r8.ir.code.ValueTypeConstraint;
 
-public class IfGt extends Format22t {
+public class DexIfGt extends DexFormat22t {
 
   public static final int OPCODE = 0x36;
   public static final String NAME = "IfGt";
   public static final String SMALI_NAME = "if-gt";
 
-  IfGt(int high, BytecodeStream stream) {
+  DexIfGt(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public IfGt(int register1, int register2, int offset) {
+  public DexIfGt(int register1, int register2, int offset) {
     super(register1, register2, offset);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/IfGtz.java b/src/main/java/com/android/tools/r8/dex/code/DexIfGtz.java
similarity index 83%
rename from src/main/java/com/android/tools/r8/code/IfGtz.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIfGtz.java
index 8567a11..c3a8348 100644
--- a/src/main/java/com/android/tools/r8/code/IfGtz.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIfGtz.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.If.Type;
 import com.android.tools.r8.ir.code.ValueTypeConstraint;
 
-public class IfGtz extends Format21t {
+public class DexIfGtz extends DexFormat21t {
 
   public static final int OPCODE = 0x3c;
   public static final String NAME = "IfGtz";
   public static final String SMALI_NAME = "if-gtz";
 
-  IfGtz(int high, BytecodeStream stream) {
+  DexIfGtz(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public IfGtz(int register, int offset) {
+  public DexIfGtz(int register, int offset) {
     super(register, offset);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/IfLe.java b/src/main/java/com/android/tools/r8/dex/code/DexIfLe.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/IfLe.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIfLe.java
index c313a4f..9fde6a5 100644
--- a/src/main/java/com/android/tools/r8/code/IfLe.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIfLe.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.If.Type;
 import com.android.tools.r8.ir.code.ValueTypeConstraint;
 
-public class IfLe extends Format22t {
+public class DexIfLe extends DexFormat22t {
 
   public static final int OPCODE = 0x37;
   public static final String NAME = "IfLe";
   public static final String SMALI_NAME = "if-le";
 
-  IfLe(int high, BytecodeStream stream) {
+  DexIfLe(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public IfLe(int register1, int register2, int offset) {
+  public DexIfLe(int register1, int register2, int offset) {
     super(register1, register2, offset);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/IfLez.java b/src/main/java/com/android/tools/r8/dex/code/DexIfLez.java
similarity index 83%
rename from src/main/java/com/android/tools/r8/code/IfLez.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIfLez.java
index 9024a98..04ebeff 100644
--- a/src/main/java/com/android/tools/r8/code/IfLez.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIfLez.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.If.Type;
 import com.android.tools.r8.ir.code.ValueTypeConstraint;
 
-public class IfLez extends Format21t {
+public class DexIfLez extends DexFormat21t {
 
   public static final int OPCODE = 0x3d;
   public static final String NAME = "IfLez";
   public static final String SMALI_NAME = "if-lez";
 
-  IfLez(int high, BytecodeStream stream) {
+  DexIfLez(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public IfLez(int register, int offset) {
+  public DexIfLez(int register, int offset) {
     super(register, offset);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/IfLt.java b/src/main/java/com/android/tools/r8/dex/code/DexIfLt.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/IfLt.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIfLt.java
index 556de31..728ba10 100644
--- a/src/main/java/com/android/tools/r8/code/IfLt.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIfLt.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.If.Type;
 import com.android.tools.r8.ir.code.ValueTypeConstraint;
 
-public class IfLt extends Format22t {
+public class DexIfLt extends DexFormat22t {
 
   public static final int OPCODE = 0x34;
   public static final String NAME = "IfLt";
   public static final String SMALI_NAME = "if-lt";
 
-  IfLt(int high, BytecodeStream stream) {
+  DexIfLt(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public IfLt(int register1, int register2, int offset) {
+  public DexIfLt(int register1, int register2, int offset) {
     super(register1, register2, offset);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/IfLtz.java b/src/main/java/com/android/tools/r8/dex/code/DexIfLtz.java
similarity index 83%
rename from src/main/java/com/android/tools/r8/code/IfLtz.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIfLtz.java
index c19b0d9..0aba44f 100644
--- a/src/main/java/com/android/tools/r8/code/IfLtz.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIfLtz.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.If.Type;
 import com.android.tools.r8.ir.code.ValueTypeConstraint;
 
-public class IfLtz extends Format21t {
+public class DexIfLtz extends DexFormat21t {
 
   public static final int OPCODE = 0x3a;
   public static final String NAME = "IfLtz";
   public static final String SMALI_NAME = "if-ltz";
 
-  IfLtz(int high, BytecodeStream stream) {
+  DexIfLtz(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public IfLtz(int register, int offset) {
+  public DexIfLtz(int register, int offset) {
     super(register, offset);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/IfNe.java b/src/main/java/com/android/tools/r8/dex/code/DexIfNe.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/IfNe.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIfNe.java
index 24e45d9..9919538 100644
--- a/src/main/java/com/android/tools/r8/code/IfNe.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIfNe.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.If.Type;
 import com.android.tools.r8.ir.code.ValueTypeConstraint;
 
-public class IfNe extends Format22t {
+public class DexIfNe extends DexFormat22t {
 
   public static final int OPCODE = 0x33;
   public static final String NAME = "IfNe";
   public static final String SMALI_NAME = "if-ne";
 
-  IfNe(int high, BytecodeStream stream) {
+  DexIfNe(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public IfNe(int register1, int register2, int offset) {
+  public DexIfNe(int register1, int register2, int offset) {
     super(register1, register2, offset);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/IfNez.java b/src/main/java/com/android/tools/r8/dex/code/DexIfNez.java
similarity index 83%
rename from src/main/java/com/android/tools/r8/code/IfNez.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIfNez.java
index f9057e6..cb74246 100644
--- a/src/main/java/com/android/tools/r8/code/IfNez.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIfNez.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.If.Type;
 import com.android.tools.r8.ir.code.ValueTypeConstraint;
 
-public class IfNez extends Format21t {
+public class DexIfNez extends DexFormat21t {
 
   public static final int OPCODE = 0x39;
   public static final String NAME = "IfNez";
   public static final String SMALI_NAME = "if-nez";
 
-  IfNez(int high, BytecodeStream stream) {
+  DexIfNez(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public IfNez(int register, int offset) {
+  public DexIfNez(int register, int offset) {
     super(register, offset);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/Iget.java b/src/main/java/com/android/tools/r8/dex/code/DexIget.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/Iget.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIget.java
index ee8e7a0..0329505 100644
--- a/src/main/java/com/android/tools/r8/code/Iget.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIget.java
@@ -1,24 +1,24 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class Iget extends IgetOrIput implements CfOrDexInstanceFieldRead {
+public class DexIget extends DexIgetOrIput implements CfOrDexInstanceFieldRead {
 
   public static final int OPCODE = 0x52;
   public static final String NAME = "Iget";
   public static final String SMALI_NAME = "iget";
 
-  /*package*/ Iget(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  /*package*/ DexIget(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getFieldMap());
   }
 
-  public Iget(int destRegister, int objectRegister, DexField field) {
+  public DexIget(int destRegister, int objectRegister, DexField field) {
     super(destRegister, objectRegister, field);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/IgetBoolean.java b/src/main/java/com/android/tools/r8/dex/code/DexIgetBoolean.java
similarity index 79%
rename from src/main/java/com/android/tools/r8/code/IgetBoolean.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIgetBoolean.java
index 3212878..16bfd6d 100644
--- a/src/main/java/com/android/tools/r8/code/IgetBoolean.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIgetBoolean.java
@@ -1,24 +1,24 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class IgetBoolean extends IgetOrIput implements CfOrDexInstanceFieldRead {
+public class DexIgetBoolean extends DexIgetOrIput implements CfOrDexInstanceFieldRead {
 
   public static final int OPCODE = 0x55;
   public static final String NAME = "IgetBoolean";
   public static final String SMALI_NAME = "iget-boolean";
 
-  /*package*/ IgetBoolean(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  /*package*/ DexIgetBoolean(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getFieldMap());
   }
 
-  public IgetBoolean(int destRegister, int objectRegister, DexField field) {
+  public DexIgetBoolean(int destRegister, int objectRegister, DexField field) {
     super(destRegister, objectRegister, field);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/IgetByte.java b/src/main/java/com/android/tools/r8/dex/code/DexIgetByte.java
similarity index 79%
rename from src/main/java/com/android/tools/r8/code/IgetByte.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIgetByte.java
index a876d70..a1a04db 100644
--- a/src/main/java/com/android/tools/r8/code/IgetByte.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIgetByte.java
@@ -1,24 +1,24 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class IgetByte extends IgetOrIput implements CfOrDexInstanceFieldRead {
+public class DexIgetByte extends DexIgetOrIput implements CfOrDexInstanceFieldRead {
 
   public static final int OPCODE = 0x56;
   public static final String NAME = "IgetByte";
   public static final String SMALI_NAME = "iget-byte";
 
-  /*package*/ IgetByte(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  /*package*/ DexIgetByte(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getFieldMap());
   }
 
-  public IgetByte(int destRegister, int objectRegister, DexField field) {
+  public DexIgetByte(int destRegister, int objectRegister, DexField field) {
     super(destRegister, objectRegister, field);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/IgetChar.java b/src/main/java/com/android/tools/r8/dex/code/DexIgetChar.java
similarity index 79%
rename from src/main/java/com/android/tools/r8/code/IgetChar.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIgetChar.java
index efa458d..a546c34 100644
--- a/src/main/java/com/android/tools/r8/code/IgetChar.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIgetChar.java
@@ -1,24 +1,24 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class IgetChar extends IgetOrIput implements CfOrDexInstanceFieldRead {
+public class DexIgetChar extends DexIgetOrIput implements CfOrDexInstanceFieldRead {
 
   public static final int OPCODE = 0x57;
   public static final String NAME = "IgetChar";
   public static final String SMALI_NAME = "iget-char";
 
-  /*package*/ IgetChar(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  /*package*/ DexIgetChar(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getFieldMap());
   }
 
-  public IgetChar(int destRegister, int objectRegister, DexField field) {
+  public DexIgetChar(int destRegister, int objectRegister, DexField field) {
     super(destRegister, objectRegister, field);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/IgetObject.java b/src/main/java/com/android/tools/r8/dex/code/DexIgetObject.java
similarity index 79%
rename from src/main/java/com/android/tools/r8/code/IgetObject.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIgetObject.java
index 93540d6..b9d1e38 100644
--- a/src/main/java/com/android/tools/r8/code/IgetObject.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIgetObject.java
@@ -1,24 +1,24 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class IgetObject extends IgetOrIput implements CfOrDexInstanceFieldRead {
+public class DexIgetObject extends DexIgetOrIput implements CfOrDexInstanceFieldRead {
 
   public static final int OPCODE = 0x54;
   public static final String NAME = "IgetObject";
   public static final String SMALI_NAME = "iget-object";
 
-  /*package*/ IgetObject(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  /*package*/ DexIgetObject(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getFieldMap());
   }
 
-  public IgetObject(int destRegister, int objectRegister, DexField field) {
+  public DexIgetObject(int destRegister, int objectRegister, DexField field) {
     super(destRegister, objectRegister, field);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/IgetOrIput.java b/src/main/java/com/android/tools/r8/dex/code/DexIgetOrIput.java
similarity index 73%
rename from src/main/java/com/android/tools/r8/code/IgetOrIput.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIgetOrIput.java
index 33621e5..d1c298a 100644
--- a/src/main/java/com/android/tools/r8/code/IgetOrIput.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIgetOrIput.java
@@ -1,9 +1,10 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
@@ -11,24 +12,24 @@
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import java.nio.ShortBuffer;
 
-public abstract class IgetOrIput extends Format22c<DexField> {
+public abstract class DexIgetOrIput extends DexFormat22c<DexField> {
 
-  IgetOrIput(int high, BytecodeStream stream, DexField[] map) {
+  DexIgetOrIput(int high, BytecodeStream stream, DexField[] map) {
     super(high, stream, map);
   }
 
-  IgetOrIput(int A, int B, DexField CCCC) {
+  DexIgetOrIput(int A, int B, DexField CCCC) {
     super(A, B, CCCC);
   }
 
   @Override
   public final void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
-    DexField rewritten = graphLens.lookupField(getField());
-    rewritten.collectIndexedItems(indexedItems);
+    DexField rewritten = appView.graphLens().lookupField(getField());
+    rewritten.collectIndexedItems(appView, indexedItems);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/IgetShort.java b/src/main/java/com/android/tools/r8/dex/code/DexIgetShort.java
similarity index 79%
rename from src/main/java/com/android/tools/r8/code/IgetShort.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIgetShort.java
index 23bd792..653aac0 100644
--- a/src/main/java/com/android/tools/r8/code/IgetShort.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIgetShort.java
@@ -1,24 +1,24 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class IgetShort extends IgetOrIput implements CfOrDexInstanceFieldRead {
+public class DexIgetShort extends DexIgetOrIput implements CfOrDexInstanceFieldRead {
 
   public static final int OPCODE = 0x58;
   public static final String NAME = "IgetShort";
   public static final String SMALI_NAME = "iget-short";
 
-  /*package*/ IgetShort(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  /*package*/ DexIgetShort(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getFieldMap());
   }
 
-  public IgetShort(int destRegister, int objectRegister, DexField field) {
+  public DexIgetShort(int destRegister, int objectRegister, DexField field) {
     super(destRegister, objectRegister, field);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/IgetWide.java b/src/main/java/com/android/tools/r8/dex/code/DexIgetWide.java
similarity index 79%
rename from src/main/java/com/android/tools/r8/code/IgetWide.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIgetWide.java
index 12ad976..a2bcf17 100644
--- a/src/main/java/com/android/tools/r8/code/IgetWide.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIgetWide.java
@@ -1,24 +1,24 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class IgetWide extends IgetOrIput implements CfOrDexInstanceFieldRead {
+public class DexIgetWide extends DexIgetOrIput implements CfOrDexInstanceFieldRead {
 
   public static final int OPCODE = 0x53;
   public static final String NAME = "IgetWide";
   public static final String SMALI_NAME = "iget-wide";
 
-  /*package*/ IgetWide(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  /*package*/ DexIgetWide(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getFieldMap());
   }
 
-  public IgetWide(int destRegister, int objectRegister, DexField field) {
+  public DexIgetWide(int destRegister, int objectRegister, DexField field) {
     super(destRegister, objectRegister, field);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/DexInitClass.java b/src/main/java/com/android/tools/r8/dex/code/DexInitClass.java
similarity index 85%
rename from src/main/java/com/android/tools/r8/code/DexInitClass.java
rename to src/main/java/com/android/tools/r8/dex/code/DexInitClass.java
index 545c24c..b1e5025 100644
--- a/src/main/java/com/android/tools/r8/code/DexInitClass.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInitClass.java
@@ -2,10 +2,11 @@
 // 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GraphLens;
@@ -20,7 +21,7 @@
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
-public class DexInitClass extends Base2Format {
+public class DexInitClass extends DexBase2Format {
 
   public static final int OPCODE = 0x60;
   public static final String NAME = "InitClass";
@@ -46,15 +47,15 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     // We intentionally apply the graph lens first, and then the init class lens, using the fact
     // that the init class lens maps classes in the final program to fields in the final program.
-    DexType rewrittenClass = graphLens.lookupType(clazz);
-    DexField clinitField = indexedItems.getInitClassLens().getInitClassField(rewrittenClass);
-    clinitField.collectIndexedItems(indexedItems);
+    DexType rewrittenClass = appView.graphLens().lookupType(clazz);
+    DexField clinitField = appView.initClassLens().getInitClassField(rewrittenClass);
+    clinitField.collectIndexedItems(appView, indexedItems);
   }
 
   @Override
@@ -87,20 +88,20 @@
     switch (type) {
       case INT:
       case FLOAT:
-        return Sget.OPCODE;
+        return DexSget.OPCODE;
       case LONG:
       case DOUBLE:
-        return SgetWide.OPCODE;
+        return DexSgetWide.OPCODE;
       case OBJECT:
-        return SgetObject.OPCODE;
+        return DexSgetObject.OPCODE;
       case BOOLEAN:
-        return SgetBoolean.OPCODE;
+        return DexSgetBoolean.OPCODE;
       case BYTE:
-        return SgetByte.OPCODE;
+        return DexSgetByte.OPCODE;
       case CHAR:
-        return SgetChar.OPCODE;
+        return DexSgetChar.OPCODE;
       case SHORT:
-        return SgetShort.OPCODE;
+        return DexSgetShort.OPCODE;
       default:
         throw new Unreachable("Unexpected type: " + type);
     }
@@ -132,7 +133,7 @@
   }
 
   @Override
-  final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
     return visitor.visit(this, (DexInitClass) other, DexInitClass::specify);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/InstanceOf.java b/src/main/java/com/android/tools/r8/dex/code/DexInstanceOf.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/InstanceOf.java
rename to src/main/java/com/android/tools/r8/dex/code/DexInstanceOf.java
index c1b8293..601dffb 100644
--- a/src/main/java/com/android/tools/r8/code/InstanceOf.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInstanceOf.java
@@ -1,9 +1,10 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
@@ -14,22 +15,22 @@
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import java.nio.ShortBuffer;
 
-public class InstanceOf extends Format22c<DexType> {
+public class DexInstanceOf extends DexFormat22c<DexType> {
 
   public static final int OPCODE = 0x20;
   public static final String NAME = "InstanceOf";
   public static final String SMALI_NAME = "instance-of";
 
-  InstanceOf(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexInstanceOf(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getTypeMap());
   }
 
-  public InstanceOf(int dest, int value, DexType type) {
+  public DexInstanceOf(int dest, int value, DexType type) {
     super(dest, value, type);
   }
 
   @Override
-  public InstanceOf asInstanceOf() {
+  public DexInstanceOf asInstanceOf() {
     return this;
   }
 
@@ -55,12 +56,12 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
-    DexType rewritten = graphLens.lookupType(getType());
-    rewritten.collectIndexedItems(indexedItems);
+    DexType rewritten = appView.graphLens().lookupType(getType());
+    rewritten.collectIndexedItems(appView, indexedItems);
   }
 
   public DexType getType() {
diff --git a/src/main/java/com/android/tools/r8/code/Instruction.java b/src/main/java/com/android/tools/r8/dex/code/DexInstruction.java
similarity index 86%
rename from src/main/java/com/android/tools/r8/code/Instruction.java
rename to src/main/java/com/android/tools/r8/dex/code/DexInstruction.java
index 580d5ef..cc35c46 100644
--- a/src/main/java/com/android/tools/r8/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInstruction.java
@@ -1,12 +1,13 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.errors.InternalCompilerError;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexCallSite;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexMethod;
@@ -28,20 +29,20 @@
 import java.nio.ShortBuffer;
 import java.util.function.BiPredicate;
 
-public abstract class Instruction implements CfOrDexInstruction, StructuralItem<Instruction> {
-  public static final Instruction[] EMPTY_ARRAY = {};
+public abstract class DexInstruction implements CfOrDexInstruction, StructuralItem<DexInstruction> {
+  public static final DexInstruction[] EMPTY_ARRAY = {};
 
-  public final static int[] NO_TARGETS = null;
-  public final static int[] EXIT_TARGET = {};
+  public static final int[] NO_TARGETS = null;
+  public static final int[] EXIT_TARGET = {};
 
   private int offset;
 
-  Instruction(BytecodeStream stream) {
+  DexInstruction(BytecodeStream stream) {
     // When this constructor is invoked, we have already read 1 ushort from the stream.
     this.offset = stream.getOffset() - 1;
   }
 
-  protected Instruction() {
+  protected DexInstruction() {
     this.offset = -1;
   }
 
@@ -128,8 +129,8 @@
     write16BitValue(index, dest);
   }
 
-  protected void write32BitReference(IndexedDexItem item, ShortBuffer dest,
-      ObjectToOffsetMapping mapping) {
+  protected void write32BitReference(
+      IndexedDexItem item, ShortBuffer dest, ObjectToOffsetMapping mapping) {
     write32BitValue(item.getOffset(mapping), dest);
   }
 
@@ -156,11 +157,11 @@
   }
 
   @Override
-  public Instruction asDexInstruction() {
+  public DexInstruction asDexInstruction() {
     return this;
   }
 
-  public CheckCast asCheckCast() {
+  public DexCheckCast asCheckCast() {
     return null;
   }
 
@@ -168,7 +169,7 @@
     return false;
   }
 
-  public InstanceOf asInstanceOf() {
+  public DexInstanceOf asInstanceOf() {
     return null;
   }
 
@@ -176,7 +177,7 @@
     return false;
   }
 
-  public ConstString asConstString() {
+  public DexConstString asConstString() {
     return null;
   }
 
@@ -184,7 +185,7 @@
     return false;
   }
 
-  public ConstClass asConstClass() {
+  public DexConstClass asConstClass() {
     return null;
   }
 
@@ -204,7 +205,7 @@
     return false;
   }
 
-  public ConstStringJumbo asConstStringJumbo() {
+  public DexConstStringJumbo asConstStringJumbo() {
     return null;
   }
 
@@ -216,7 +217,7 @@
     return false;
   }
 
-  public InvokeVirtual asInvokeVirtual() {
+  public DexInvokeVirtual asInvokeVirtual() {
     return null;
   }
 
@@ -224,12 +225,12 @@
     return false;
   }
 
-  public InvokeVirtualRange asInvokeVirtualRange() {
+  public DexInvokeVirtualRange asInvokeVirtualRange() {
     return null;
   }
 
   public boolean isSimpleNop() {
-    return !isPayload() && this instanceof Nop;
+    return !isPayload() && this instanceof DexNop;
   }
 
   public boolean isPayload() {
@@ -324,12 +325,12 @@
   public abstract int hashCode();
 
   @Override
-  public Instruction self() {
+  public DexInstruction self() {
     return this;
   }
 
   @Override
-  public StructuralMapping<Instruction> getStructuralMapping() {
+  public StructuralMapping<DexInstruction> getStructuralMapping() {
     throw new Unreachable();
   }
 
@@ -338,10 +339,10 @@
   }
 
   // Abstract compare-to called only if the opcode/compare-id of the instruction matches.
-  abstract int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor);
+  abstract int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor);
 
   @Override
-  public final int acceptCompareTo(Instruction other, CompareToVisitor visitor) {
+  public final int acceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
     int opcodeDiff = visitor.visitInt(getCompareToId(), other.getCompareToId());
     if (opcodeDiff != 0) {
       return opcodeDiff;
@@ -367,7 +368,7 @@
 
   public abstract int getSize();
 
-  public String toSmaliString(Instruction payloadUser) {
+  public String toSmaliString(DexInstruction payloadUser) {
     throw new InternalCompilerError("Instruction " + payloadUser + " is not a payload user");
   }
 
@@ -379,7 +380,7 @@
 
   public abstract String toString(ClassNameMapper naming);
 
-  public String toString(ClassNameMapper naming, Instruction payloadUser) {
+  public String toString(ClassNameMapper naming, DexInstruction payloadUser) {
     throw new InternalCompilerError("Instruction " + payloadUser + " is not a payload user");
   }
 
@@ -396,12 +397,13 @@
       LensCodeRewriterUtils rewriter);
 
   public abstract void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter);
 
-  public boolean equals(Instruction other, BiPredicate<IndexedDexItem, IndexedDexItem> equality) {
+  public boolean equals(
+      DexInstruction other, BiPredicate<IndexedDexItem, IndexedDexItem> equality) {
     // In the default case, there is nothing to substitute.
     return this.equals(other);
   }
diff --git a/src/main/java/com/android/tools/r8/code/InstructionFactory.java b/src/main/java/com/android/tools/r8/dex/code/DexInstructionFactory.java
similarity index 73%
rename from src/main/java/com/android/tools/r8/code/InstructionFactory.java
rename to src/main/java/com/android/tools/r8/dex/code/DexInstructionFactory.java
index 6b60f29..356535c 100644
--- a/src/main/java/com/android/tools/r8/code/InstructionFactory.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInstructionFactory.java
@@ -1,32 +1,31 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import java.nio.ShortBuffer;
 import java.util.ArrayList;
 import java.util.List;
 
-public class InstructionFactory extends BaseInstructionFactory {
+public class DexInstructionFactory extends DexBaseInstructionFactory {
 
-  static private Instruction readFrom(ShortBufferBytecodeStream stream,
-      OffsetToObjectMapping mapping) {
+  private static DexInstruction readFrom(
+      ShortBufferBytecodeStream stream, OffsetToObjectMapping mapping) {
     int high = stream.nextByte();
     int opcode = stream.nextByte();
     return create(high, opcode, stream, mapping);
   }
 
-  public Instruction[] readSequenceFrom(ShortBuffer buffer, int startIndex, int length,
-      OffsetToObjectMapping mapping) {
-    ShortBufferBytecodeStream range =
-        new ShortBufferBytecodeStream(buffer, startIndex, length);
-    List<Instruction> insn = new ArrayList<>(length);
+  public DexInstruction[] readSequenceFrom(
+      ShortBuffer buffer, int startIndex, int length, OffsetToObjectMapping mapping) {
+    ShortBufferBytecodeStream range = new ShortBufferBytecodeStream(buffer, startIndex, length);
+    List<DexInstruction> insn = new ArrayList<>(length);
     while (range.hasMore()) {
-      Instruction instruction = readFrom(range, mapping);
+      DexInstruction instruction = readFrom(range, mapping);
       insn.add(instruction);
     }
-    return insn.toArray(Instruction.EMPTY_ARRAY);
+    return insn.toArray(DexInstruction.EMPTY_ARRAY);
   }
 
   private static class ShortBufferBytecodeStream implements BytecodeStream {
diff --git a/src/main/java/com/android/tools/r8/code/IntToByte.java b/src/main/java/com/android/tools/r8/dex/code/DexIntToByte.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/IntToByte.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIntToByte.java
index 2f6fde6..b2aefe3 100644
--- a/src/main/java/com/android/tools/r8/code/IntToByte.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIntToByte.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class IntToByte extends Format12x {
+
+public class DexIntToByte extends DexFormat12x {
 
   public static final int OPCODE = 0x8d;
   public static final String NAME = "IntToByte";
   public static final String SMALI_NAME = "int-to-byte";
 
-  IntToByte(int high, BytecodeStream stream) {
+  DexIntToByte(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public IntToByte(int dest, int source) {
+  public DexIntToByte(int dest, int source) {
     super(dest, source);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/IntToChar.java b/src/main/java/com/android/tools/r8/dex/code/DexIntToChar.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/IntToChar.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIntToChar.java
index 1994d77..a096373 100644
--- a/src/main/java/com/android/tools/r8/code/IntToChar.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIntToChar.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class IntToChar extends Format12x {
+public class DexIntToChar extends DexFormat12x {
 
   public static final int OPCODE = 0x8e;
   public static final String NAME = "IntToChar";
   public static final String SMALI_NAME = "int-to-char";
 
-  IntToChar(int high, BytecodeStream stream) {
+  DexIntToChar(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public IntToChar(int dest, int source) {
+  public DexIntToChar(int dest, int source) {
     super(dest, source);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/IntToDouble.java b/src/main/java/com/android/tools/r8/dex/code/DexIntToDouble.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/IntToDouble.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIntToDouble.java
index e7a3a51..f3b1c19 100644
--- a/src/main/java/com/android/tools/r8/code/IntToDouble.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIntToDouble.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class IntToDouble extends Format12x {
+public class DexIntToDouble extends DexFormat12x {
 
   public static final int OPCODE = 0x83;
   public static final String NAME = "IntToDouble";
   public static final String SMALI_NAME = "int-to-double";
 
-  IntToDouble(int high, BytecodeStream stream) {
+  DexIntToDouble(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public IntToDouble(int dest, int source) {
+  public DexIntToDouble(int dest, int source) {
     super(dest, source);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/IntToFloat.java b/src/main/java/com/android/tools/r8/dex/code/DexIntToFloat.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/IntToFloat.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIntToFloat.java
index 5865d4d..9883869 100644
--- a/src/main/java/com/android/tools/r8/code/IntToFloat.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIntToFloat.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class IntToFloat extends Format12x {
+
+public class DexIntToFloat extends DexFormat12x {
 
   public static final int OPCODE = 0x82;
   public static final String NAME = "IntToFloat";
   public static final String SMALI_NAME = "int-to-float";
 
-  IntToFloat(int high, BytecodeStream stream) {
+  DexIntToFloat(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public IntToFloat(int dest, int source) {
+  public DexIntToFloat(int dest, int source) {
     super(dest, source);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/IntToLong.java b/src/main/java/com/android/tools/r8/dex/code/DexIntToLong.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/IntToLong.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIntToLong.java
index 5a3592e..8c319b1 100644
--- a/src/main/java/com/android/tools/r8/code/IntToLong.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIntToLong.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class IntToLong extends Format12x {
+public class DexIntToLong extends DexFormat12x {
 
   public static final int OPCODE = 0x81;
   public static final String NAME = "IntToLong";
   public static final String SMALI_NAME = "int-to-long";
 
-  IntToLong(int high, BytecodeStream stream) {
+  DexIntToLong(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public IntToLong(int dest, int source) {
+  public DexIntToLong(int dest, int source) {
     super(dest, source);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/IntToShort.java b/src/main/java/com/android/tools/r8/dex/code/DexIntToShort.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/IntToShort.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIntToShort.java
index 6fbdaaa..579cff4 100644
--- a/src/main/java/com/android/tools/r8/code/IntToShort.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIntToShort.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class IntToShort extends Format12x {
+public class DexIntToShort extends DexFormat12x {
 
   public static final int OPCODE = 0x8f;
   public static final String NAME = "IntToShort";
   public static final String SMALI_NAME = "int-to-short";
 
-  IntToShort(int high, BytecodeStream stream) {
+  DexIntToShort(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public IntToShort(int dest, int source) {
+  public DexIntToShort(int dest, int source) {
     super(dest, source);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/InvokeCustom.java b/src/main/java/com/android/tools/r8/dex/code/DexInvokeCustom.java
similarity index 83%
rename from src/main/java/com/android/tools/r8/code/InvokeCustom.java
rename to src/main/java/com/android/tools/r8/dex/code/DexInvokeCustom.java
index ea07822..605b420 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeCustom.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInvokeCustom.java
@@ -1,9 +1,10 @@
 // Copyright (c) 2017, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexCallSite;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
@@ -14,17 +15,17 @@
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import java.nio.ShortBuffer;
 
-public class InvokeCustom extends Format35c<DexCallSite> {
+public class DexInvokeCustom extends DexFormat35c<DexCallSite> {
 
   public static final int OPCODE = 0xfc;
   public static final String NAME = "InvokeCustom";
   public static final String SMALI_NAME = "invoke-custom";
 
-  InvokeCustom(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexInvokeCustom(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getCallSiteMap());
   }
 
-  public InvokeCustom(int A, DexCallSite BBBB, int C, int D, int E, int F, int G) {
+  public DexInvokeCustom(int A, DexCallSite BBBB, int C, int D, int E, int F, int G) {
     super(A, BBBB, C, D, E, F, G);
   }
 
@@ -45,12 +46,12 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     DexCallSite rewritten = rewriter.rewriteCallSite(getCallSite(), context);
-    rewritten.collectIndexedItems(indexedItems);
+    rewritten.collectIndexedItems(appView, indexedItems);
   }
 
   @Override
@@ -65,7 +66,7 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addInvokeCustomRegisters(getCallSite(), A, new int[]{C, D, E, F, G});
+    builder.addInvokeCustomRegisters(getCallSite(), A, new int[] {C, D, E, F, G});
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/InvokeCustomRange.java b/src/main/java/com/android/tools/r8/dex/code/DexInvokeCustomRange.java
similarity index 83%
rename from src/main/java/com/android/tools/r8/code/InvokeCustomRange.java
rename to src/main/java/com/android/tools/r8/dex/code/DexInvokeCustomRange.java
index c057c94..a88f338 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeCustomRange.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInvokeCustomRange.java
@@ -1,9 +1,10 @@
 // Copyright (c) 2017, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexCallSite;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
@@ -14,17 +15,17 @@
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import java.nio.ShortBuffer;
 
-public class InvokeCustomRange extends Format3rc<DexCallSite> {
+public class DexInvokeCustomRange extends DexFormat3rc<DexCallSite> {
 
   public static final int OPCODE = 0xfd;
   public static final String NAME = "InvokeCustomRange";
   public static final String SMALI_NAME = "invoke-custom/range";
 
-  InvokeCustomRange(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexInvokeCustomRange(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getCallSiteMap());
   }
 
-  public InvokeCustomRange(int firstArgumentRegister, int argumentCount, DexCallSite callSite) {
+  public DexInvokeCustomRange(int firstArgumentRegister, int argumentCount, DexCallSite callSite) {
     super(firstArgumentRegister, argumentCount, callSite);
   }
 
@@ -45,12 +46,12 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     DexCallSite rewritten = rewriter.rewriteCallSite(getCallSite(), context);
-    rewritten.collectIndexedItems(indexedItems);
+    rewritten.collectIndexedItems(appView, indexedItems);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/InvokeDirect.java b/src/main/java/com/android/tools/r8/dex/code/DexInvokeDirect.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/InvokeDirect.java
rename to src/main/java/com/android/tools/r8/dex/code/DexInvokeDirect.java
index 4f5938f..b918754 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeDirect.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInvokeDirect.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
@@ -9,17 +9,17 @@
 import com.android.tools.r8.ir.code.Invoke.Type;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class InvokeDirect extends InvokeMethod {
+public class DexInvokeDirect extends DexInvokeMethod {
 
   public static final int OPCODE = 0x70;
   public static final String NAME = "InvokeDirect";
   public static final String SMALI_NAME = "invoke-direct";
 
-  InvokeDirect(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexInvokeDirect(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getMethodMap());
   }
 
-  public InvokeDirect(int A, DexMethod BBBB, int C, int D, int E, int F, int G) {
+  public DexInvokeDirect(int A, DexMethod BBBB, int C, int D, int E, int F, int G) {
     super(A, BBBB, C, D, E, F, G);
   }
 
@@ -50,7 +50,7 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addInvokeRegisters(Type.DIRECT, getMethod(), getProto(), A, new int[]{C, D, E, F, G});
+    builder.addInvokeRegisters(Type.DIRECT, getMethod(), getProto(), A, new int[] {C, D, E, F, G});
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/InvokeDirectRange.java b/src/main/java/com/android/tools/r8/dex/code/DexInvokeDirectRange.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/InvokeDirectRange.java
rename to src/main/java/com/android/tools/r8/dex/code/DexInvokeDirectRange.java
index 6f232c0..9134e4a 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeDirectRange.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInvokeDirectRange.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
@@ -9,17 +9,17 @@
 import com.android.tools.r8.ir.code.Invoke.Type;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class InvokeDirectRange extends InvokeMethodRange {
+public class DexInvokeDirectRange extends DexInvokeMethodRange {
 
   public static final int OPCODE = 0x76;
   public static final String NAME = "InvokeDirectRange";
   public static final String SMALI_NAME = "invoke-direct/range";
 
-  InvokeDirectRange(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexInvokeDirectRange(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getMethodMap());
   }
 
-  public InvokeDirectRange(int firstArgumentRegister, int argumentCount, DexMethod method) {
+  public DexInvokeDirectRange(int firstArgumentRegister, int argumentCount, DexMethod method) {
     super(firstArgumentRegister, argumentCount, method);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/InvokeInterface.java b/src/main/java/com/android/tools/r8/dex/code/DexInvokeInterface.java
similarity index 83%
rename from src/main/java/com/android/tools/r8/code/InvokeInterface.java
rename to src/main/java/com/android/tools/r8/dex/code/DexInvokeInterface.java
index 2e20c9c..d7a64be 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeInterface.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInvokeInterface.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
@@ -9,17 +9,17 @@
 import com.android.tools.r8.ir.code.Invoke.Type;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class InvokeInterface extends InvokeMethod {
+public class DexInvokeInterface extends DexInvokeMethod {
 
   public static final int OPCODE = 0x72;
   public static final String NAME = "InvokeInterface";
   public static final String SMALI_NAME = "invoke-interface";
 
-  InvokeInterface(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexInvokeInterface(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getMethodMap());
   }
 
-  public InvokeInterface(int A, DexMethod BBBB, int C, int D, int E, int F, int G) {
+  public DexInvokeInterface(int A, DexMethod BBBB, int C, int D, int E, int F, int G) {
     super(A, BBBB, C, D, E, F, G);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/InvokeInterfaceRange.java b/src/main/java/com/android/tools/r8/dex/code/DexInvokeInterfaceRange.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/InvokeInterfaceRange.java
rename to src/main/java/com/android/tools/r8/dex/code/DexInvokeInterfaceRange.java
index 7592e3d..b8dfc7b 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeInterfaceRange.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInvokeInterfaceRange.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
@@ -9,17 +9,17 @@
 import com.android.tools.r8.ir.code.Invoke.Type;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class InvokeInterfaceRange extends InvokeMethodRange {
+public class DexInvokeInterfaceRange extends DexInvokeMethodRange {
 
   public static final int OPCODE = 0x78;
   public static final String NAME = "InvokeInterfaceRange";
   public static final String SMALI_NAME = "invoke-interface/range";
 
-  InvokeInterfaceRange(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexInvokeInterfaceRange(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getMethodMap());
   }
 
-  public InvokeInterfaceRange(int firstArgumentRegister, int argumentCount, DexMethod method) {
+  public DexInvokeInterfaceRange(int firstArgumentRegister, int argumentCount, DexMethod method) {
     super(firstArgumentRegister, argumentCount, method);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/InvokeMethod.java b/src/main/java/com/android/tools/r8/dex/code/DexInvokeMethod.java
similarity index 74%
rename from src/main/java/com/android/tools/r8/code/InvokeMethod.java
rename to src/main/java/com/android/tools/r8/dex/code/DexInvokeMethod.java
index 9e5d8f2..9340e4a 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeMethod.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInvokeMethod.java
@@ -1,9 +1,10 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
@@ -13,25 +14,28 @@
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import java.nio.ShortBuffer;
 
-public abstract class InvokeMethod extends Format35c<DexMethod> {
+public abstract class DexInvokeMethod extends DexFormat35c<DexMethod> {
 
-  InvokeMethod(int high, BytecodeStream stream, DexMethod[] map) {
+  DexInvokeMethod(int high, BytecodeStream stream, DexMethod[] map) {
     super(high, stream, map);
   }
 
-  InvokeMethod(int A, DexMethod BBBB, int C, int D, int E, int F, int G) {
+  DexInvokeMethod(int A, DexMethod BBBB, int C, int D, int E, int F, int G) {
     super(A, BBBB, C, D, E, F, G);
   }
 
   @Override
   public final void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     DexMethod rewritten =
-        graphLens.lookupMethod(getMethod(), context.getReference(), getInvokeType()).getReference();
-    rewritten.collectIndexedItems(indexedItems);
+        appView
+            .graphLens()
+            .lookupMethod(getMethod(), context.getReference(), getInvokeType())
+            .getReference();
+    rewritten.collectIndexedItems(appView, indexedItems);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/InvokeMethodRange.java b/src/main/java/com/android/tools/r8/dex/code/DexInvokeMethodRange.java
similarity index 73%
rename from src/main/java/com/android/tools/r8/code/InvokeMethodRange.java
rename to src/main/java/com/android/tools/r8/dex/code/DexInvokeMethodRange.java
index ba248e0..34243ac 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeMethodRange.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInvokeMethodRange.java
@@ -1,9 +1,10 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
@@ -13,25 +14,28 @@
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import java.nio.ShortBuffer;
 
-public abstract class InvokeMethodRange extends Format3rc<DexMethod> {
+public abstract class DexInvokeMethodRange extends DexFormat3rc<DexMethod> {
 
-  InvokeMethodRange(int high, BytecodeStream stream, DexMethod[] map) {
+  DexInvokeMethodRange(int high, BytecodeStream stream, DexMethod[] map) {
     super(high, stream, map);
   }
 
-  InvokeMethodRange(int firstArgumentRegister, int argumentCount, DexMethod dexItem) {
+  DexInvokeMethodRange(int firstArgumentRegister, int argumentCount, DexMethod dexItem) {
     super(firstArgumentRegister, argumentCount, dexItem);
   }
 
   @Override
   public final void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     DexMethod rewritten =
-        graphLens.lookupMethod(getMethod(), context.getReference(), getInvokeType()).getReference();
-    rewritten.collectIndexedItems(indexedItems);
+        appView
+            .graphLens()
+            .lookupMethod(getMethod(), context.getReference(), getInvokeType())
+            .getReference();
+    rewritten.collectIndexedItems(appView, indexedItems);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/InvokePolymorphic.java b/src/main/java/com/android/tools/r8/dex/code/DexInvokePolymorphic.java
similarity index 86%
rename from src/main/java/com/android/tools/r8/code/InvokePolymorphic.java
rename to src/main/java/com/android/tools/r8/dex/code/DexInvokePolymorphic.java
index d5ecd11..72678f0 100644
--- a/src/main/java/com/android/tools/r8/code/InvokePolymorphic.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInvokePolymorphic.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2017, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProto;
@@ -13,17 +13,17 @@
  * An invoke-polymorphic instruction used to invoke a method in a MethodHandle using either
  * MethodHandle.invoke or MethodHandle.invokeExact.
  */
-public class InvokePolymorphic extends Format45cc {
+public class DexInvokePolymorphic extends DexFormat45cc {
 
   public static final int OPCODE = 0xfa;
   public static final String NAME = "InvokePolymorphic";
   public static final String SMALI_NAME = "invoke-polymorphic";
 
-  InvokePolymorphic(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexInvokePolymorphic(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getMethodMap(), mapping.getProtosMap());
   }
 
-  public InvokePolymorphic(
+  public DexInvokePolymorphic(
       int A, DexMethod BBBB, DexProto HHHH, int C, int D, int E, int F, int G) {
     super(A, BBBB, HHHH, C, D, E, F, G);
   }
diff --git a/src/main/java/com/android/tools/r8/code/InvokePolymorphicRange.java b/src/main/java/com/android/tools/r8/dex/code/DexInvokePolymorphicRange.java
similarity index 87%
rename from src/main/java/com/android/tools/r8/code/InvokePolymorphicRange.java
rename to src/main/java/com/android/tools/r8/dex/code/DexInvokePolymorphicRange.java
index 07cf3a0..186952b 100644
--- a/src/main/java/com/android/tools/r8/code/InvokePolymorphicRange.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInvokePolymorphicRange.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2017, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProto;
@@ -11,17 +11,17 @@
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
 /** An invoke-polymorphic range instruction used to call method with polymorphic signature. */
-public class InvokePolymorphicRange extends Format4rcc {
+public class DexInvokePolymorphicRange extends DexFormat4rcc {
 
   public static final int OPCODE = 0xfb;
   public static final String NAME = "InvokePolymorphicRange";
   public static final String SMALI_NAME = "invoke-polymorphic/range";
 
-  InvokePolymorphicRange(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexInvokePolymorphicRange(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getMethodMap(), mapping.getProtosMap());
   }
 
-  public InvokePolymorphicRange(
+  public DexInvokePolymorphicRange(
       int firstArgumentRegister, int argumentCount, DexMethod method, DexProto proto) {
     super(firstArgumentRegister, argumentCount, method, proto);
   }
diff --git a/src/main/java/com/android/tools/r8/code/InvokeStatic.java b/src/main/java/com/android/tools/r8/dex/code/DexInvokeStatic.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/InvokeStatic.java
rename to src/main/java/com/android/tools/r8/dex/code/DexInvokeStatic.java
index fb198e4..b645556 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeStatic.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInvokeStatic.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
@@ -9,17 +9,17 @@
 import com.android.tools.r8.ir.code.Invoke.Type;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class InvokeStatic extends InvokeMethod {
+public class DexInvokeStatic extends DexInvokeMethod {
 
   public static final int OPCODE = 0x71;
   public static final String NAME = "InvokeStatic";
   public static final String SMALI_NAME = "invoke-static";
 
-  InvokeStatic(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexInvokeStatic(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getMethodMap());
   }
 
-  public InvokeStatic(int A, DexMethod BBBB, int C, int D, int E, int F, int G) {
+  public DexInvokeStatic(int A, DexMethod BBBB, int C, int D, int E, int F, int G) {
     super(A, BBBB, C, D, E, F, G);
   }
 
@@ -50,7 +50,7 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addInvokeRegisters(Type.STATIC, getMethod(), getProto(), A, new int[]{C, D, E, F, G});
+    builder.addInvokeRegisters(Type.STATIC, getMethod(), getProto(), A, new int[] {C, D, E, F, G});
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/InvokeStaticRange.java b/src/main/java/com/android/tools/r8/dex/code/DexInvokeStaticRange.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/InvokeStaticRange.java
rename to src/main/java/com/android/tools/r8/dex/code/DexInvokeStaticRange.java
index de84a90..512632f 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeStaticRange.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInvokeStaticRange.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
@@ -9,17 +9,17 @@
 import com.android.tools.r8.ir.code.Invoke.Type;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class InvokeStaticRange extends InvokeMethodRange {
+public class DexInvokeStaticRange extends DexInvokeMethodRange {
 
   public static final int OPCODE = 0x77;
   public static final String NAME = "InvokeStaticRange";
   public static final String SMALI_NAME = "invoke-static/range";
 
-  InvokeStaticRange(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexInvokeStaticRange(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getMethodMap());
   }
 
-  public InvokeStaticRange(int firstArgumentRegister, int argumentCount, DexMethod method) {
+  public DexInvokeStaticRange(int firstArgumentRegister, int argumentCount, DexMethod method) {
     super(firstArgumentRegister, argumentCount, method);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/InvokeSuper.java b/src/main/java/com/android/tools/r8/dex/code/DexInvokeSuper.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/InvokeSuper.java
rename to src/main/java/com/android/tools/r8/dex/code/DexInvokeSuper.java
index 24ab80e..3be61ac 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeSuper.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInvokeSuper.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
@@ -9,17 +9,17 @@
 import com.android.tools.r8.ir.code.Invoke.Type;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class InvokeSuper extends InvokeMethod {
+public class DexInvokeSuper extends DexInvokeMethod {
 
   public static final int OPCODE = 0x6f;
   public static final String NAME = "InvokeSuper";
   public static final String SMALI_NAME = "invoke-super";
 
-  InvokeSuper(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexInvokeSuper(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getMethodMap());
   }
 
-  public InvokeSuper(int A, DexMethod BBBB, int C, int D, int E, int F, int G) {
+  public DexInvokeSuper(int A, DexMethod BBBB, int C, int D, int E, int F, int G) {
     super(A, BBBB, C, D, E, F, G);
   }
 
@@ -50,7 +50,7 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addInvokeRegisters(Type.SUPER, getMethod(), getProto(), A, new int[]{C, D, E, F, G});
+    builder.addInvokeRegisters(Type.SUPER, getMethod(), getProto(), A, new int[] {C, D, E, F, G});
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/InvokeSuperRange.java b/src/main/java/com/android/tools/r8/dex/code/DexInvokeSuperRange.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/InvokeSuperRange.java
rename to src/main/java/com/android/tools/r8/dex/code/DexInvokeSuperRange.java
index ac820c9..206e74f 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeSuperRange.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInvokeSuperRange.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
@@ -9,17 +9,17 @@
 import com.android.tools.r8.ir.code.Invoke.Type;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class InvokeSuperRange extends InvokeMethodRange {
+public class DexInvokeSuperRange extends DexInvokeMethodRange {
 
   public static final int OPCODE = 0x75;
   public static final String NAME = "InvokeSuperRange";
   public static final String SMALI_NAME = "invoke-super/range";
 
-  InvokeSuperRange(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexInvokeSuperRange(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getMethodMap());
   }
 
-  public InvokeSuperRange(int firstArgumentRegister, int argumentCount, DexMethod method) {
+  public DexInvokeSuperRange(int firstArgumentRegister, int argumentCount, DexMethod method) {
     super(firstArgumentRegister, argumentCount, method);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/InvokeVirtual.java b/src/main/java/com/android/tools/r8/dex/code/DexInvokeVirtual.java
similarity index 79%
rename from src/main/java/com/android/tools/r8/code/InvokeVirtual.java
rename to src/main/java/com/android/tools/r8/dex/code/DexInvokeVirtual.java
index 27e37c5..f1704e5 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeVirtual.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInvokeVirtual.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
@@ -9,17 +9,17 @@
 import com.android.tools.r8.ir.code.Invoke.Type;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class InvokeVirtual extends InvokeMethod {
+public class DexInvokeVirtual extends DexInvokeMethod {
 
   public static final int OPCODE = 0x6e;
   public static final String NAME = "InvokeVirtual";
   public static final String SMALI_NAME = "invoke-virtual";
 
-  InvokeVirtual(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexInvokeVirtual(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getMethodMap());
   }
 
-  public InvokeVirtual(int A, DexMethod BBBB, int C, int D, int E, int F, int G) {
+  public DexInvokeVirtual(int A, DexMethod BBBB, int C, int D, int E, int F, int G) {
     super(A, BBBB, C, D, E, F, G);
   }
 
@@ -49,7 +49,7 @@
   }
 
   @Override
-  public InvokeVirtual asInvokeVirtual() {
+  public DexInvokeVirtual asInvokeVirtual() {
     return this;
   }
 
@@ -60,7 +60,7 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addInvokeRegisters(Type.VIRTUAL, getMethod(), getProto(), A, new int[]{C, D, E, F, G});
+    builder.addInvokeRegisters(Type.VIRTUAL, getMethod(), getProto(), A, new int[] {C, D, E, F, G});
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/InvokeVirtualRange.java b/src/main/java/com/android/tools/r8/dex/code/DexInvokeVirtualRange.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/InvokeVirtualRange.java
rename to src/main/java/com/android/tools/r8/dex/code/DexInvokeVirtualRange.java
index e93733f..97a87f8 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeVirtualRange.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInvokeVirtualRange.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
@@ -9,17 +9,17 @@
 import com.android.tools.r8.ir.code.Invoke.Type;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class InvokeVirtualRange extends InvokeMethodRange {
+public class DexInvokeVirtualRange extends DexInvokeMethodRange {
 
   public static final int OPCODE = 0x74;
   public static final String NAME = "InvokeVirtualRange";
   public static final String SMALI_NAME = "invoke-virtual/range";
 
-  InvokeVirtualRange(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexInvokeVirtualRange(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getMethodMap());
   }
 
-  public InvokeVirtualRange(int firstArgumentRegister, int argumentCount, DexMethod method) {
+  public DexInvokeVirtualRange(int firstArgumentRegister, int argumentCount, DexMethod method) {
     super(firstArgumentRegister, argumentCount, method);
   }
 
@@ -49,7 +49,7 @@
   }
 
   @Override
-  public InvokeVirtualRange asInvokeVirtualRange() {
+  public DexInvokeVirtualRange asInvokeVirtualRange() {
     return this;
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/Iput.java b/src/main/java/com/android/tools/r8/dex/code/DexIput.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/Iput.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIput.java
index 76f90af..1a1cea9 100644
--- a/src/main/java/com/android/tools/r8/code/Iput.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIput.java
@@ -1,24 +1,24 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class Iput extends IgetOrIput {
+public class DexIput extends DexIgetOrIput {
 
   public static final int OPCODE = 0x59;
   public static final String NAME = "Iput";
   public static final String SMALI_NAME = "iput";
 
-  /*package*/ Iput(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  /*package*/ DexIput(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getFieldMap());
   }
 
-  public Iput(int valueRegister, int objectRegister, DexField field) {
+  public DexIput(int valueRegister, int objectRegister, DexField field) {
     super(valueRegister, objectRegister, field);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/IputBoolean.java b/src/main/java/com/android/tools/r8/dex/code/DexIputBoolean.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/IputBoolean.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIputBoolean.java
index 634657d..501d0e4 100644
--- a/src/main/java/com/android/tools/r8/code/IputBoolean.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIputBoolean.java
@@ -1,24 +1,24 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class IputBoolean extends IgetOrIput {
+public class DexIputBoolean extends DexIgetOrIput {
 
   public static final int OPCODE = 0x5c;
   public static final String NAME = "IputBoolean";
   public static final String SMALI_NAME = "iput-boolean";
 
-  /*package*/ IputBoolean(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  /*package*/ DexIputBoolean(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getFieldMap());
   }
 
-  public IputBoolean(int valueRegister, int objectRegister, DexField field) {
+  public DexIputBoolean(int valueRegister, int objectRegister, DexField field) {
     super(valueRegister, objectRegister, field);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/IputByte.java b/src/main/java/com/android/tools/r8/dex/code/DexIputByte.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/IputByte.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIputByte.java
index b579bec..2d5fec3 100644
--- a/src/main/java/com/android/tools/r8/code/IputByte.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIputByte.java
@@ -1,24 +1,24 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class IputByte extends IgetOrIput {
+public class DexIputByte extends DexIgetOrIput {
 
   public static final int OPCODE = 0x5d;
   public static final String NAME = "IputByte";
   public static final String SMALI_NAME = "iput-byte";
 
-  /*package*/ IputByte(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  /*package*/ DexIputByte(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getFieldMap());
   }
 
-  public IputByte(int valueRegister, int objectRegister, DexField field) {
+  public DexIputByte(int valueRegister, int objectRegister, DexField field) {
     super(valueRegister, objectRegister, field);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/IputChar.java b/src/main/java/com/android/tools/r8/dex/code/DexIputChar.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/IputChar.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIputChar.java
index 1b0d42d..bf96679 100644
--- a/src/main/java/com/android/tools/r8/code/IputChar.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIputChar.java
@@ -1,24 +1,24 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class IputChar extends IgetOrIput {
+public class DexIputChar extends DexIgetOrIput {
 
   public static final int OPCODE = 0x5e;
   public static final String NAME = "IputChar";
   public static final String SMALI_NAME = "iput-char";
 
-  /*package*/ IputChar(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  /*package*/ DexIputChar(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getFieldMap());
   }
 
-  public IputChar(int valueRegister, int objectRegister, DexField field) {
+  public DexIputChar(int valueRegister, int objectRegister, DexField field) {
     super(valueRegister, objectRegister, field);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/IputObject.java b/src/main/java/com/android/tools/r8/dex/code/DexIputObject.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/IputObject.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIputObject.java
index 816f81f..3052fec 100644
--- a/src/main/java/com/android/tools/r8/code/IputObject.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIputObject.java
@@ -1,24 +1,24 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class IputObject extends IgetOrIput {
+public class DexIputObject extends DexIgetOrIput {
 
   public static final int OPCODE = 0x5b;
   public static final String NAME = "IputObject";
   public static final String SMALI_NAME = "iput-object";
 
-  /*package*/ IputObject(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  /*package*/ DexIputObject(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getFieldMap());
   }
 
-  public IputObject(int valueRegister, int objectRegister, DexField field) {
+  public DexIputObject(int valueRegister, int objectRegister, DexField field) {
     super(valueRegister, objectRegister, field);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/IputShort.java b/src/main/java/com/android/tools/r8/dex/code/DexIputShort.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/IputShort.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIputShort.java
index dfa9ff7..d6d32a3 100644
--- a/src/main/java/com/android/tools/r8/code/IputShort.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIputShort.java
@@ -1,24 +1,24 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class IputShort extends IgetOrIput {
+public class DexIputShort extends DexIgetOrIput {
 
   public static final int OPCODE = 0x5f;
   public static final String NAME = "IputShort";
   public static final String SMALI_NAME = "iput-short";
 
-  /*package*/ IputShort(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  /*package*/ DexIputShort(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getFieldMap());
   }
 
-  public IputShort(int valueRegister, int objectRegister, DexField field) {
+  public DexIputShort(int valueRegister, int objectRegister, DexField field) {
     super(valueRegister, objectRegister, field);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/IputWide.java b/src/main/java/com/android/tools/r8/dex/code/DexIputWide.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/IputWide.java
rename to src/main/java/com/android/tools/r8/dex/code/DexIputWide.java
index 261dc26..2f70828 100644
--- a/src/main/java/com/android/tools/r8/code/IputWide.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexIputWide.java
@@ -1,24 +1,24 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class IputWide extends IgetOrIput {
+public class DexIputWide extends DexIgetOrIput {
 
   public static final int OPCODE = 0x5a;
   public static final String NAME = "IputWide";
   public static final String SMALI_NAME = "iput-wide";
 
-  /*package*/ IputWide(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  /*package*/ DexIputWide(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getFieldMap());
   }
 
-  public IputWide(int valueRegister, int objectRegister, DexField field) {
+  public DexIputWide(int valueRegister, int objectRegister, DexField field) {
     super(valueRegister, objectRegister, field);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/DexItemBasedConstString.java b/src/main/java/com/android/tools/r8/dex/code/DexItemBasedConstString.java
similarity index 90%
rename from src/main/java/com/android/tools/r8/code/DexItemBasedConstString.java
rename to src/main/java/com/android/tools/r8/dex/code/DexItemBasedConstString.java
index 70e9c4f..d34a783 100644
--- a/src/main/java/com/android/tools/r8/code/DexItemBasedConstString.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexItemBasedConstString.java
@@ -1,10 +1,11 @@
 // Copyright (c) 2018, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
@@ -17,7 +18,7 @@
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
-public class DexItemBasedConstString extends Format21c<DexReference> {
+public class DexItemBasedConstString extends DexFormat21c<DexReference> {
 
   public static final String NAME = "DexItemBasedConstString";
   public static final String SMALI_NAME = "const-string*";
@@ -40,11 +41,11 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
-    getItem().collectIndexedItems(indexedItems);
+    getItem().collectIndexedItems(appView, indexedItems);
   }
 
   @Override
@@ -69,7 +70,7 @@
   }
 
   @Override
-  void internalSubSpecify(StructuralSpecification<Format21c<DexReference>, ?> spec) {
+  void internalSubSpecify(StructuralSpecification<DexFormat21c<DexReference>, ?> spec) {
     spec.withDexReference(i -> i.BBBB);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/LongToDouble.java b/src/main/java/com/android/tools/r8/dex/code/DexLongToDouble.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/LongToDouble.java
rename to src/main/java/com/android/tools/r8/dex/code/DexLongToDouble.java
index f2ac125..224b047 100644
--- a/src/main/java/com/android/tools/r8/code/LongToDouble.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexLongToDouble.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class LongToDouble extends Format12x {
+
+public class DexLongToDouble extends DexFormat12x {
 
   public static final int OPCODE = 0x86;
   public static final String NAME = "LongToDouble";
   public static final String SMALI_NAME = "long-to-double";
 
-  LongToDouble(int high, BytecodeStream stream) {
+  DexLongToDouble(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public LongToDouble(int dest, int source) {
+  public DexLongToDouble(int dest, int source) {
     super(dest, source);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/LongToFloat.java b/src/main/java/com/android/tools/r8/dex/code/DexLongToFloat.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/LongToFloat.java
rename to src/main/java/com/android/tools/r8/dex/code/DexLongToFloat.java
index ead1ee2..ddec7bf 100644
--- a/src/main/java/com/android/tools/r8/code/LongToFloat.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexLongToFloat.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class LongToFloat extends Format12x {
+
+public class DexLongToFloat extends DexFormat12x {
 
   public static final int OPCODE = 0x85;
   public static final String NAME = "LongToFloat";
   public static final String SMALI_NAME = "long-to-float";
 
-  LongToFloat(int high, BytecodeStream stream) {
+  DexLongToFloat(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public LongToFloat(int dest, int source) {
+  public DexLongToFloat(int dest, int source) {
     super(dest, source);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/LongToInt.java b/src/main/java/com/android/tools/r8/dex/code/DexLongToInt.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/LongToInt.java
rename to src/main/java/com/android/tools/r8/dex/code/DexLongToInt.java
index bbb10b6..4d912a4 100644
--- a/src/main/java/com/android/tools/r8/code/LongToInt.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexLongToInt.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class LongToInt extends Format12x {
+public class DexLongToInt extends DexFormat12x {
 
   public static final int OPCODE = 0x84;
   public static final String NAME = "LongToInt";
   public static final String SMALI_NAME = "long-to-int";
 
-  LongToInt(int high, BytecodeStream stream) {
+  DexLongToInt(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public LongToInt(int dest, int source) {
+  public DexLongToInt(int dest, int source) {
     super(dest, source);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/MonitorEnter.java b/src/main/java/com/android/tools/r8/dex/code/DexMonitorEnter.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/MonitorEnter.java
rename to src/main/java/com/android/tools/r8/dex/code/DexMonitorEnter.java
index 17c9852..620c557 100644
--- a/src/main/java/com/android/tools/r8/code/MonitorEnter.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexMonitorEnter.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.Monitor.Type;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class MonitorEnter extends Format11x {
+
+public class DexMonitorEnter extends DexFormat11x {
 
   public static final int OPCODE = 0x1d;
   public static final String NAME = "MonitorEnter";
   public static final String SMALI_NAME = "monitor-enter";
 
-  MonitorEnter(int high, BytecodeStream stream) {
+  DexMonitorEnter(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public MonitorEnter(int register) {
+  public DexMonitorEnter(int register) {
     super(register);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/MonitorExit.java b/src/main/java/com/android/tools/r8/dex/code/DexMonitorExit.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/MonitorExit.java
rename to src/main/java/com/android/tools/r8/dex/code/DexMonitorExit.java
index 7725ca0..d001e32 100644
--- a/src/main/java/com/android/tools/r8/code/MonitorExit.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexMonitorExit.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.Monitor.Type;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class MonitorExit extends Format11x {
+
+public class DexMonitorExit extends DexFormat11x {
 
   public static final int OPCODE = 0x1e;
   public static final String NAME = "MonitorExit";
   public static final String SMALI_NAME = "monitor-exit";
 
-  MonitorExit(int high, BytecodeStream stream) {
+  DexMonitorExit(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public MonitorExit(int register) {
+  public DexMonitorExit(int register) {
     super(register);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/Move.java b/src/main/java/com/android/tools/r8/dex/code/DexMove.java
similarity index 83%
rename from src/main/java/com/android/tools/r8/code/Move.java
rename to src/main/java/com/android/tools/r8/dex/code/DexMove.java
index 3e750a6..5c45e0c 100644
--- a/src/main/java/com/android/tools/r8/code/Move.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexMove.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.ValueTypeConstraint;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class Move extends Format12x {
+public class DexMove extends DexFormat12x {
 
   public static final int OPCODE = 0x1;
   public static final String NAME = "Move";
   public static final String SMALI_NAME = "move";
 
-  Move(int high, BytecodeStream stream) {
+  DexMove(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public Move(int dest, int src) {
+  public DexMove(int dest, int src) {
     super(dest, src);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/Move16.java b/src/main/java/com/android/tools/r8/dex/code/DexMove16.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/Move16.java
rename to src/main/java/com/android/tools/r8/dex/code/DexMove16.java
index 64a0f7c..a003bc3 100644
--- a/src/main/java/com/android/tools/r8/code/Move16.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexMove16.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.ValueTypeConstraint;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class Move16 extends Format32x {
+public class DexMove16 extends DexFormat32x {
 
   public static final int OPCODE = 0x3;
   public static final String NAME = "Move16";
   public static final String SMALI_NAME = "move/16";
 
-  Move16(int high, BytecodeStream stream) {
+  DexMove16(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public Move16(int dest, int src) {
+  public DexMove16(int dest, int src) {
     super(dest, src);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/MoveException.java b/src/main/java/com/android/tools/r8/dex/code/DexMoveException.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/MoveException.java
rename to src/main/java/com/android/tools/r8/dex/code/DexMoveException.java
index ca79a0c..1f3888e 100644
--- a/src/main/java/com/android/tools/r8/code/MoveException.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexMoveException.java
@@ -1,21 +1,21 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class MoveException extends Format11x {
+public class DexMoveException extends DexFormat11x {
 
   public static final int OPCODE = 0xd;
   public static final String NAME = "MoveException";
   public static final String SMALI_NAME = "move-exception";
 
-  MoveException(int high, BytecodeStream stream) {
+  DexMoveException(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public MoveException(int AA) {
+  public DexMoveException(int AA) {
     super(AA);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/MoveFrom16.java b/src/main/java/com/android/tools/r8/dex/code/DexMoveFrom16.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/MoveFrom16.java
rename to src/main/java/com/android/tools/r8/dex/code/DexMoveFrom16.java
index 51b456e..48f9fa8 100644
--- a/src/main/java/com/android/tools/r8/code/MoveFrom16.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexMoveFrom16.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.ValueTypeConstraint;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class MoveFrom16 extends Format22x {
+public class DexMoveFrom16 extends DexFormat22x {
 
   public static final int OPCODE = 0x2;
   public static final String NAME = "MoveFrom16";
   public static final String SMALI_NAME = "move-from/16";
 
-  MoveFrom16(int high, BytecodeStream stream) {
+  DexMoveFrom16(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public MoveFrom16(int dest, int src) {
+  public DexMoveFrom16(int dest, int src) {
     super(dest, src);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/MoveObject.java b/src/main/java/com/android/tools/r8/dex/code/DexMoveObject.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/MoveObject.java
rename to src/main/java/com/android/tools/r8/dex/code/DexMoveObject.java
index a308ab1..22ee41c 100644
--- a/src/main/java/com/android/tools/r8/code/MoveObject.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexMoveObject.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class MoveObject extends Format12x {
+public class DexMoveObject extends DexFormat12x {
 
   public static final int OPCODE = 0x7;
   public static final String NAME = "MoveObject";
   public static final String SMALI_NAME = "move-object";
 
-  MoveObject(int high, BytecodeStream stream) {
+  DexMoveObject(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public MoveObject(int dest, int src) {
+  public DexMoveObject(int dest, int src) {
     super(dest, src);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/MoveObject16.java b/src/main/java/com/android/tools/r8/dex/code/DexMoveObject16.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/MoveObject16.java
rename to src/main/java/com/android/tools/r8/dex/code/DexMoveObject16.java
index a7eb12c..3598213 100644
--- a/src/main/java/com/android/tools/r8/code/MoveObject16.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexMoveObject16.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class MoveObject16 extends Format32x {
+public class DexMoveObject16 extends DexFormat32x {
 
   public static final int OPCODE = 0x9;
   public static final String NAME = "MoveObject16";
   public static final String SMALI_NAME = "move-object/16";
 
-  MoveObject16(int high, BytecodeStream stream) {
+  DexMoveObject16(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public MoveObject16(int dest, int src) {
+  public DexMoveObject16(int dest, int src) {
     super(dest, src);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/MoveObjectFrom16.java b/src/main/java/com/android/tools/r8/dex/code/DexMoveObjectFrom16.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/MoveObjectFrom16.java
rename to src/main/java/com/android/tools/r8/dex/code/DexMoveObjectFrom16.java
index 8b32125..4016567 100644
--- a/src/main/java/com/android/tools/r8/code/MoveObjectFrom16.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexMoveObjectFrom16.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class MoveObjectFrom16 extends Format22x {
+
+public class DexMoveObjectFrom16 extends DexFormat22x {
 
   public static final int OPCODE = 0x8;
   public static final String NAME = "MoveObjectFrom16";
   public static final String SMALI_NAME = "move-object-from/16";
 
-  MoveObjectFrom16(int high, BytecodeStream stream) {
+  DexMoveObjectFrom16(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public MoveObjectFrom16(int dest, int src) {
+  public DexMoveObjectFrom16(int dest, int src) {
     super(dest, src);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/MoveResult.java b/src/main/java/com/android/tools/r8/dex/code/DexMoveResult.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/MoveResult.java
rename to src/main/java/com/android/tools/r8/dex/code/DexMoveResult.java
index cd9eb78..caa3883 100644
--- a/src/main/java/com/android/tools/r8/code/MoveResult.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexMoveResult.java
@@ -1,20 +1,21 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class MoveResult extends Format11x {
+
+public class DexMoveResult extends DexFormat11x {
 
   public static final int OPCODE = 0xa;
   public static final String NAME = "MoveResult";
   public static final String SMALI_NAME = "move-result";
 
-  /*package*/ MoveResult(int high, BytecodeStream stream) {
+  /*package*/ DexMoveResult(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public MoveResult(int AA) {
+  public DexMoveResult(int AA) {
     super(AA);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/MoveResultObject.java b/src/main/java/com/android/tools/r8/dex/code/DexMoveResultObject.java
similarity index 78%
rename from src/main/java/com/android/tools/r8/code/MoveResultObject.java
rename to src/main/java/com/android/tools/r8/dex/code/DexMoveResultObject.java
index 3210b71..d5248c7 100644
--- a/src/main/java/com/android/tools/r8/code/MoveResultObject.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexMoveResultObject.java
@@ -1,21 +1,21 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class MoveResultObject extends Format11x {
+public class DexMoveResultObject extends DexFormat11x {
 
   public static final int OPCODE = 0xc;
   public static final String NAME = "MoveResultObject";
   public static final String SMALI_NAME = "move-result-object";
 
-  /*package*/ MoveResultObject(int high, BytecodeStream stream) {
+  /*package*/ DexMoveResultObject(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public MoveResultObject(int AA) {
+  public DexMoveResultObject(int AA) {
     super(AA);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/MoveResultWide.java b/src/main/java/com/android/tools/r8/dex/code/DexMoveResultWide.java
similarity index 79%
rename from src/main/java/com/android/tools/r8/code/MoveResultWide.java
rename to src/main/java/com/android/tools/r8/dex/code/DexMoveResultWide.java
index 95b4350..6bff9b6 100644
--- a/src/main/java/com/android/tools/r8/code/MoveResultWide.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexMoveResultWide.java
@@ -1,21 +1,21 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class MoveResultWide extends Format11x {
+public class DexMoveResultWide extends DexFormat11x {
 
   public static final int OPCODE = 0xb;
   public static final String NAME = "MoveResultWide";
   public static final String SMALI_NAME = "move-result-wide";
 
-  /*package*/ MoveResultWide(int high, BytecodeStream stream) {
+  /*package*/ DexMoveResultWide(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public MoveResultWide(int AA) {
+  public DexMoveResultWide(int AA) {
     super(AA);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/MoveWide.java b/src/main/java/com/android/tools/r8/dex/code/DexMoveWide.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/MoveWide.java
rename to src/main/java/com/android/tools/r8/dex/code/DexMoveWide.java
index 06d44a2..88fe616 100644
--- a/src/main/java/com/android/tools/r8/code/MoveWide.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexMoveWide.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.ValueTypeConstraint;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class MoveWide extends Format12x {
+public class DexMoveWide extends DexFormat12x {
 
   public static final int OPCODE = 0x4;
   public static final String NAME = "MoveWide";
   public static final String SMALI_NAME = "move-wide";
 
-  MoveWide(int high, BytecodeStream stream) {
+  DexMoveWide(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public MoveWide(int dest, int src) {
+  public DexMoveWide(int dest, int src) {
     super(dest, src);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/MoveWide16.java b/src/main/java/com/android/tools/r8/dex/code/DexMoveWide16.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/MoveWide16.java
rename to src/main/java/com/android/tools/r8/dex/code/DexMoveWide16.java
index 66fe3fd..fd80875 100644
--- a/src/main/java/com/android/tools/r8/code/MoveWide16.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexMoveWide16.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.ValueTypeConstraint;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class MoveWide16 extends Format32x {
+public class DexMoveWide16 extends DexFormat32x {
 
   public static final int OPCODE = 0x6;
   public static final String NAME = "MoveWide16";
   public static final String SMALI_NAME = "move-wide/16";
 
-  MoveWide16(int high, BytecodeStream stream) {
+  DexMoveWide16(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public MoveWide16(int dest, int src) {
+  public DexMoveWide16(int dest, int src) {
     super(dest, src);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/MoveWideFrom16.java b/src/main/java/com/android/tools/r8/dex/code/DexMoveWideFrom16.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/MoveWideFrom16.java
rename to src/main/java/com/android/tools/r8/dex/code/DexMoveWideFrom16.java
index 45c3840..a3c4f6d 100644
--- a/src/main/java/com/android/tools/r8/code/MoveWideFrom16.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexMoveWideFrom16.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.ValueTypeConstraint;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class MoveWideFrom16 extends Format22x {
+public class DexMoveWideFrom16 extends DexFormat22x {
 
   public static final int OPCODE = 0x5;
   public static final String NAME = "MoveWideFrom16";
   public static final String SMALI_NAME = "move-wide-from/16";
 
-  MoveWideFrom16(int high, BytecodeStream stream) {
+  DexMoveWideFrom16(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public MoveWideFrom16(int dest, int src) {
+  public DexMoveWideFrom16(int dest, int src) {
     super(dest, src);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/MulDouble.java b/src/main/java/com/android/tools/r8/dex/code/DexMulDouble.java
similarity index 86%
rename from src/main/java/com/android/tools/r8/code/MulDouble.java
rename to src/main/java/com/android/tools/r8/dex/code/DexMulDouble.java
index 5c3f9df..1f195a0 100644
--- a/src/main/java/com/android/tools/r8/code/MulDouble.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexMulDouble.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class MulDouble extends Format23x {
+public class DexMulDouble extends DexFormat23x {
 
   public static final int OPCODE = 0xad;
   public static final String NAME = "MulDouble";
   public static final String SMALI_NAME = "mul-double";
 
-  MulDouble(int high, BytecodeStream stream) {
+  DexMulDouble(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public MulDouble(int dest, int left, int right) {
+  public DexMulDouble(int dest, int left, int right) {
     super(dest, left, right);
     // The art x86 backend had a bug that made it fail on "mul r0, r1, r0" instructions where
     // the second src register and the dst register is the same (but the first src register is
diff --git a/src/main/java/com/android/tools/r8/code/MulDouble2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexMulDouble2Addr.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/MulDouble2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexMulDouble2Addr.java
index 347ef3a..8290b14 100644
--- a/src/main/java/com/android/tools/r8/code/MulDouble2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexMulDouble2Addr.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class MulDouble2Addr extends Format12x {
+public class DexMulDouble2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xcd;
   public static final String NAME = "MulDouble2Addr";
   public static final String SMALI_NAME = "mul-double/2addr";
 
-  MulDouble2Addr(int high, BytecodeStream stream) {
+  DexMulDouble2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public MulDouble2Addr(int left, int right) {
+  public DexMulDouble2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/MulFloat.java b/src/main/java/com/android/tools/r8/dex/code/DexMulFloat.java
similarity index 86%
rename from src/main/java/com/android/tools/r8/code/MulFloat.java
rename to src/main/java/com/android/tools/r8/dex/code/DexMulFloat.java
index 1792264..7155e5e 100644
--- a/src/main/java/com/android/tools/r8/code/MulFloat.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexMulFloat.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class MulFloat extends Format23x {
+public class DexMulFloat extends DexFormat23x {
 
   public static final int OPCODE = 0xa8;
   public static final String NAME = "MulFloat";
   public static final String SMALI_NAME = "mul-float";
 
-  MulFloat(int high, BytecodeStream stream) {
+  DexMulFloat(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public MulFloat(int dest, int left, int right) {
+  public DexMulFloat(int dest, int left, int right) {
     super(dest, left, right);
     // The art x86 backend had a bug that made it fail on "mul r0, r1, r0" instructions where
     // the second src register and the dst register is the same (but the first src register is
diff --git a/src/main/java/com/android/tools/r8/code/MulFloat2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexMulFloat2Addr.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/MulFloat2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexMulFloat2Addr.java
index 1e56be6..0147cac 100644
--- a/src/main/java/com/android/tools/r8/code/MulFloat2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexMulFloat2Addr.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class MulFloat2Addr extends Format12x {
+public class DexMulFloat2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xc8;
   public static final String NAME = "MulFloat2Addr";
   public static final String SMALI_NAME = "mul-float/2addr";
 
-  MulFloat2Addr(int high, BytecodeStream stream) {
+  DexMulFloat2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public MulFloat2Addr(int left, int right) {
+  public DexMulFloat2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/MulInt.java b/src/main/java/com/android/tools/r8/dex/code/DexMulInt.java
similarity index 86%
rename from src/main/java/com/android/tools/r8/code/MulInt.java
rename to src/main/java/com/android/tools/r8/dex/code/DexMulInt.java
index 2513ab9..12c5ed9 100644
--- a/src/main/java/com/android/tools/r8/code/MulInt.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexMulInt.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class MulInt extends Format23x {
+
+public class DexMulInt extends DexFormat23x {
 
   public static final int OPCODE = 0x92;
   public static final String NAME = "MulInt";
   public static final String SMALI_NAME = "mul-int";
 
-  MulInt(int high, BytecodeStream stream) {
+  DexMulInt(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public MulInt(int dest, int left, int right) {
+  public DexMulInt(int dest, int left, int right) {
     super(dest, left, right);
     // The art x86 backend had a bug that made it fail on "mul r0, r1, r0" instructions where
     // the second src register and the dst register is the same (but the first src register is
diff --git a/src/main/java/com/android/tools/r8/code/MulInt2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexMulInt2Addr.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/MulInt2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexMulInt2Addr.java
index e65146a..d0fda45 100644
--- a/src/main/java/com/android/tools/r8/code/MulInt2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexMulInt2Addr.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class MulInt2Addr extends Format12x {
+
+public class DexMulInt2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xb2;
   public static final String NAME = "MulInt2Addr";
   public static final String SMALI_NAME = "mul-int/2addr";
 
-  MulInt2Addr(int high, BytecodeStream stream) {
+  DexMulInt2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public MulInt2Addr(int left, int right) {
+  public DexMulInt2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/MulIntLit16.java b/src/main/java/com/android/tools/r8/dex/code/DexMulIntLit16.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/MulIntLit16.java
rename to src/main/java/com/android/tools/r8/dex/code/DexMulIntLit16.java
index efa2cfb..ba7acd0 100644
--- a/src/main/java/com/android/tools/r8/code/MulIntLit16.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexMulIntLit16.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class MulIntLit16 extends Format22s {
+public class DexMulIntLit16 extends DexFormat22s {
 
   public static final int OPCODE = 0xd2;
   public static final String NAME = "MulIntLit16";
   public static final String SMALI_NAME = "mul-int/lit16";
 
-  MulIntLit16(int high, BytecodeStream stream) {
+  DexMulIntLit16(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public MulIntLit16(int dest, int register, int constant) {
+  public DexMulIntLit16(int dest, int register, int constant) {
     super(dest, register, constant);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/MulIntLit8.java b/src/main/java/com/android/tools/r8/dex/code/DexMulIntLit8.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/MulIntLit8.java
rename to src/main/java/com/android/tools/r8/dex/code/DexMulIntLit8.java
index 0de1c6f..0173322 100644
--- a/src/main/java/com/android/tools/r8/code/MulIntLit8.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexMulIntLit8.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class MulIntLit8 extends Format22b {
+public class DexMulIntLit8 extends DexFormat22b {
 
   public static final int OPCODE = 0xda;
   public static final String NAME = "MulIntLit8";
   public static final String SMALI_NAME = "mul-int/lit8";
 
-  MulIntLit8(int high, BytecodeStream stream) {
+  DexMulIntLit8(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public MulIntLit8(int dest, int register, int constant) {
+  public DexMulIntLit8(int dest, int register, int constant) {
     super(dest, register, constant);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/MulLong.java b/src/main/java/com/android/tools/r8/dex/code/DexMulLong.java
similarity index 86%
rename from src/main/java/com/android/tools/r8/code/MulLong.java
rename to src/main/java/com/android/tools/r8/dex/code/DexMulLong.java
index 486b4d6..d545bec 100644
--- a/src/main/java/com/android/tools/r8/code/MulLong.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexMulLong.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class MulLong extends Format23x {
+public class DexMulLong extends DexFormat23x {
 
   public static final int OPCODE = 0x9d;
   public static final String NAME = "MulLong";
   public static final String SMALI_NAME = "mul-long";
 
-  MulLong(int high, BytecodeStream stream) {
+  DexMulLong(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public MulLong(int dest, int left, int right) {
+  public DexMulLong(int dest, int left, int right) {
     super(dest, left, right);
     // The art x86 backend had a bug that made it fail on "mul r0, r1, r0" instructions where
     // the second src register and the dst register is the same (but the first src register is
diff --git a/src/main/java/com/android/tools/r8/code/MulLong2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexMulLong2Addr.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/MulLong2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexMulLong2Addr.java
index 2cd78f6..ae0c5cf 100644
--- a/src/main/java/com/android/tools/r8/code/MulLong2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexMulLong2Addr.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class MulLong2Addr extends Format12x {
+public class DexMulLong2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xbd;
   public static final String NAME = "MulLong2Addr";
   public static final String SMALI_NAME = "mul-long/2addr";
 
-  MulLong2Addr(int high, BytecodeStream stream) {
+  DexMulLong2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public MulLong2Addr(int left, int right) {
+  public DexMulLong2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/NegDouble.java b/src/main/java/com/android/tools/r8/dex/code/DexNegDouble.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/NegDouble.java
rename to src/main/java/com/android/tools/r8/dex/code/DexNegDouble.java
index bd054aa..64c6dcd 100644
--- a/src/main/java/com/android/tools/r8/code/NegDouble.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexNegDouble.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class NegDouble extends Format12x {
+
+public class DexNegDouble extends DexFormat12x {
 
   public static final int OPCODE = 0x80;
   public static final String NAME = "NegDouble";
   public static final String SMALI_NAME = "neg-double";
 
-  /*package*/ NegDouble(int high, BytecodeStream stream) {
+  /*package*/ DexNegDouble(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public NegDouble(int dest, int source) {
+  public DexNegDouble(int dest, int source) {
     super(dest, source);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/NegFloat.java b/src/main/java/com/android/tools/r8/dex/code/DexNegFloat.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/NegFloat.java
rename to src/main/java/com/android/tools/r8/dex/code/DexNegFloat.java
index 54d3053..58d214c 100644
--- a/src/main/java/com/android/tools/r8/code/NegFloat.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexNegFloat.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class NegFloat extends Format12x {
+public class DexNegFloat extends DexFormat12x {
 
   public static final int OPCODE = 0x7f;
   public static final String NAME = "NegFloat";
   public static final String SMALI_NAME = "neg-float";
 
-  /*package*/ NegFloat(int high, BytecodeStream stream) {
+  /*package*/ DexNegFloat(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public NegFloat(int dest, int source) {
+  public DexNegFloat(int dest, int source) {
     super(dest, source);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/NegInt.java b/src/main/java/com/android/tools/r8/dex/code/DexNegInt.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/NegInt.java
rename to src/main/java/com/android/tools/r8/dex/code/DexNegInt.java
index 82e7b86..fda8099 100644
--- a/src/main/java/com/android/tools/r8/code/NegInt.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexNegInt.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class NegInt extends Format12x {
+public class DexNegInt extends DexFormat12x {
 
   public static final int OPCODE = 0x7b;
   public static final String NAME = "NegInt";
   public static final String SMALI_NAME = "neg-int";
 
-  /*package*/ NegInt(int high, BytecodeStream stream) {
+  /*package*/ DexNegInt(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public NegInt(int dest, int source) {
+  public DexNegInt(int dest, int source) {
     super(dest, source);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/NegLong.java b/src/main/java/com/android/tools/r8/dex/code/DexNegLong.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/NegLong.java
rename to src/main/java/com/android/tools/r8/dex/code/DexNegLong.java
index 3b2a304..43a8780 100644
--- a/src/main/java/com/android/tools/r8/code/NegLong.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexNegLong.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class NegLong extends Format12x {
+
+public class DexNegLong extends DexFormat12x {
 
   public static final int OPCODE = 0x7d;
   public static final String NAME = "NegLong";
   public static final String SMALI_NAME = "neg-long";
 
-  /*package*/ NegLong(int high, BytecodeStream stream) {
+  /*package*/ DexNegLong(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public NegLong(int dest, int source) {
+  public DexNegLong(int dest, int source) {
     super(dest, source);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/NewArray.java b/src/main/java/com/android/tools/r8/dex/code/DexNewArray.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/NewArray.java
rename to src/main/java/com/android/tools/r8/dex/code/DexNewArray.java
index 35b3187..8d35555 100644
--- a/src/main/java/com/android/tools/r8/code/NewArray.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexNewArray.java
@@ -1,9 +1,10 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
@@ -14,17 +15,17 @@
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
 import java.nio.ShortBuffer;
 
-public class NewArray extends Format22c<DexType> {
+public class DexNewArray extends DexFormat22c<DexType> {
 
   public static final int OPCODE = 0x23;
   public static final String NAME = "NewArray";
   public static final String SMALI_NAME = "new-array";
 
-  /*package*/ NewArray(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  /*package*/ DexNewArray(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getTypeMap());
   }
 
-  public NewArray(int dest, int size, DexType type) {
+  public DexNewArray(int dest, int size, DexType type) {
     super(dest, size, type);
   }
 
@@ -45,12 +46,12 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
-    DexType rewritten = graphLens.lookupType(getType());
-    rewritten.collectIndexedItems(indexedItems);
+    DexType rewritten = appView.graphLens().lookupType(getType());
+    rewritten.collectIndexedItems(appView, indexedItems);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/NewInstance.java b/src/main/java/com/android/tools/r8/dex/code/DexNewInstance.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/NewInstance.java
rename to src/main/java/com/android/tools/r8/dex/code/DexNewInstance.java
index 1aed86e..4382e71 100644
--- a/src/main/java/com/android/tools/r8/code/NewInstance.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexNewInstance.java
@@ -1,9 +1,10 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
@@ -15,17 +16,17 @@
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
-public class NewInstance extends Format21c<DexType> {
+public class DexNewInstance extends DexFormat21c<DexType> {
 
   public static final int OPCODE = 0x22;
   public static final String NAME = "NewInstance";
   public static final String SMALI_NAME = "new-instance";
 
-  NewInstance(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexNewInstance(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getTypeMap());
   }
 
-  public NewInstance(int AA, DexType BBBB) {
+  public DexNewInstance(int AA, DexType BBBB) {
     super(AA, BBBB);
   }
 
@@ -45,18 +46,18 @@
   }
 
   @Override
-  void internalSubSpecify(StructuralSpecification<Format21c<DexType>, ?> spec) {
+  void internalSubSpecify(StructuralSpecification<DexFormat21c<DexType>, ?> spec) {
     spec.withItem(i -> i.BBBB);
   }
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
-    DexType rewritten = graphLens.lookupType(getType());
-    rewritten.collectIndexedItems(indexedItems);
+    DexType rewritten = appView.graphLens().lookupType(getType());
+    rewritten.collectIndexedItems(appView, indexedItems);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/DexNewUnboxedEnumInstance.java b/src/main/java/com/android/tools/r8/dex/code/DexNewUnboxedEnumInstance.java
similarity index 89%
rename from src/main/java/com/android/tools/r8/code/DexNewUnboxedEnumInstance.java
rename to src/main/java/com/android/tools/r8/dex/code/DexNewUnboxedEnumInstance.java
index 9909ac6..387952c 100644
--- a/src/main/java/com/android/tools/r8/code/DexNewUnboxedEnumInstance.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexNewUnboxedEnumInstance.java
@@ -1,10 +1,11 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
@@ -16,7 +17,7 @@
 import java.nio.ShortBuffer;
 
 /** The dex representation of {@link com.android.tools.r8.ir.code.NewUnboxedEnumInstance}. */
-public class DexNewUnboxedEnumInstance extends Format21c<DexType> {
+public class DexNewUnboxedEnumInstance extends DexFormat21c<DexType> {
 
   public static final int OPCODE = 0x22;
   public static final String NAME = "NewUnboxedEnumInstance";
@@ -45,15 +46,15 @@
   }
 
   @Override
-  void internalSubSpecify(StructuralSpecification<Format21c<DexType>, ?> spec) {
+  void internalSubSpecify(StructuralSpecification<DexFormat21c<DexType>, ?> spec) {
     spec.withItem(i -> i.BBBB);
   }
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     throw new Unreachable();
   }
diff --git a/src/main/java/com/android/tools/r8/code/Nop.java b/src/main/java/com/android/tools/r8/dex/code/DexNop.java
similarity index 71%
rename from src/main/java/com/android/tools/r8/code/Nop.java
rename to src/main/java/com/android/tools/r8/dex/code/DexNop.java
index 1e46cfc..f25e0ec 100644
--- a/src/main/java/com/android/tools/r8/code/Nop.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexNop.java
@@ -1,40 +1,39 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 
-public class Nop extends Format10x {
+public class DexNop extends DexFormat10x {
 
   public static final int OPCODE = 0x0;
   public static final String NAME = "Nop";
   public static final String SMALI_NAME = "nop";
 
-  Nop(int high, BytecodeStream stream) {
+  DexNop(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public Nop() {
-  }
+  public DexNop() {}
 
-  public static Nop create(int high, BytecodeStream stream) {
+  public static DexNop create(int high, BytecodeStream stream) {
     switch (high) {
       case 0x01:
-        return new PackedSwitchPayload(high, stream);
+        return new DexPackedSwitchPayload(high, stream);
       case 0x02:
-        return new SparseSwitchPayload(high, stream);
+        return new DexSparseSwitchPayload(high, stream);
       case 0x03:
-        return new FillArrayDataPayload(high, stream);
+        return new DexFillArrayDataPayload(high, stream);
       default:
-        return new Nop(high, stream);
+        return new DexNop(high, stream);
     }
   }
 
   // Notice that this must be overridden by the "Nop" subtypes!
   @Override
-  int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+  int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
     return DexCompareHelper.compareIdUniquelyDeterminesEquality(this, other);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/NotInt.java b/src/main/java/com/android/tools/r8/dex/code/DexNotInt.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/NotInt.java
rename to src/main/java/com/android/tools/r8/dex/code/DexNotInt.java
index c9681a7..0dde493 100644
--- a/src/main/java/com/android/tools/r8/code/NotInt.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexNotInt.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class NotInt extends Format12x {
+public class DexNotInt extends DexFormat12x {
 
   public static final int OPCODE = 0x7c;
   public static final String NAME = "NotInt";
   public static final String SMALI_NAME = "not-int";
 
-  NotInt(int high, BytecodeStream stream) {
+  DexNotInt(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public NotInt(int dest, int source) {
+  public DexNotInt(int dest, int source) {
     super(dest, source);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/NotLong.java b/src/main/java/com/android/tools/r8/dex/code/DexNotLong.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/NotLong.java
rename to src/main/java/com/android/tools/r8/dex/code/DexNotLong.java
index fcbf475..ec5af4d 100644
--- a/src/main/java/com/android/tools/r8/code/NotLong.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexNotLong.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class NotLong extends Format12x {
+
+public class DexNotLong extends DexFormat12x {
 
   public static final int OPCODE = 0x7e;
   public static final String NAME = "NotLong";
   public static final String SMALI_NAME = "not-long";
 
-  NotLong(int high, BytecodeStream stream) {
+  DexNotLong(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public NotLong(int dest, int source) {
+  public DexNotLong(int dest, int source) {
     super(dest, source);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/OrInt.java b/src/main/java/com/android/tools/r8/dex/code/DexOrInt.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/OrInt.java
rename to src/main/java/com/android/tools/r8/dex/code/DexOrInt.java
index b7aeba4..61be0ac 100644
--- a/src/main/java/com/android/tools/r8/code/OrInt.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexOrInt.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class OrInt extends Format23x {
+
+public class DexOrInt extends DexFormat23x {
 
   public static final int OPCODE = 0x96;
   public static final String NAME = "OrInt";
   public static final String SMALI_NAME = "or-int";
 
-  OrInt(int high, BytecodeStream stream) {
+  DexOrInt(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public OrInt(int dest, int left, int right) {
+  public DexOrInt(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/OrInt2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexOrInt2Addr.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/OrInt2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexOrInt2Addr.java
index 869be4d..a152de8 100644
--- a/src/main/java/com/android/tools/r8/code/OrInt2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexOrInt2Addr.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class OrInt2Addr extends Format12x {
+public class DexOrInt2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xb6;
   public static final String NAME = "OrInt2Addr";
   public static final String SMALI_NAME = "or-int/2addr";
 
-  OrInt2Addr(int high, BytecodeStream stream) {
+  DexOrInt2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public OrInt2Addr(int left, int right) {
+  public DexOrInt2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/OrIntLit16.java b/src/main/java/com/android/tools/r8/dex/code/DexOrIntLit16.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/OrIntLit16.java
rename to src/main/java/com/android/tools/r8/dex/code/DexOrIntLit16.java
index 73e384d..9d3f245 100644
--- a/src/main/java/com/android/tools/r8/code/OrIntLit16.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexOrIntLit16.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class OrIntLit16 extends Format22s {
+public class DexOrIntLit16 extends DexFormat22s {
 
   public static final int OPCODE = 0xd6;
   public static final String NAME = "OrIntLit16";
   public static final String SMALI_NAME = "or-int/lit16";
 
-  OrIntLit16(int high, BytecodeStream stream) {
+  DexOrIntLit16(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public OrIntLit16(int dest, int register, int constant) {
+  public DexOrIntLit16(int dest, int register, int constant) {
     super(dest, register, constant);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/OrIntLit8.java b/src/main/java/com/android/tools/r8/dex/code/DexOrIntLit8.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/OrIntLit8.java
rename to src/main/java/com/android/tools/r8/dex/code/DexOrIntLit8.java
index 8c37e7b..4810953 100644
--- a/src/main/java/com/android/tools/r8/code/OrIntLit8.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexOrIntLit8.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class OrIntLit8 extends Format22b {
+public class DexOrIntLit8 extends DexFormat22b {
 
   public static final int OPCODE = 0xde;
   public static final String NAME = "OrIntLit8";
   public static final String SMALI_NAME = "or-int/lit8";
 
-  OrIntLit8(int high, BytecodeStream stream) {
+  DexOrIntLit8(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public OrIntLit8(int dest, int register, int constant) {
+  public DexOrIntLit8(int dest, int register, int constant) {
     super(dest, register, constant);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/OrLong.java b/src/main/java/com/android/tools/r8/dex/code/DexOrLong.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/OrLong.java
rename to src/main/java/com/android/tools/r8/dex/code/DexOrLong.java
index 0cef69b..02c9f52 100644
--- a/src/main/java/com/android/tools/r8/code/OrLong.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexOrLong.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class OrLong extends Format23x {
+
+public class DexOrLong extends DexFormat23x {
 
   public static final int OPCODE = 0xA1;
   public static final String NAME = "OrLong";
   public static final String SMALI_NAME = "or-long";
 
-  OrLong(int high, BytecodeStream stream) {
+  DexOrLong(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public OrLong(int dest, int left, int right) {
+  public DexOrLong(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/OrLong2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexOrLong2Addr.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/OrLong2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexOrLong2Addr.java
index 175a4a7..5fffef9 100644
--- a/src/main/java/com/android/tools/r8/code/OrLong2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexOrLong2Addr.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class OrLong2Addr extends Format12x {
+public class DexOrLong2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xc1;
   public static final String NAME = "OrLong2Addr";
   public static final String SMALI_NAME = "or-long/2addr";
 
-  OrLong2Addr(int high, BytecodeStream stream) {
+  DexOrLong2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public OrLong2Addr(int left, int right) {
+  public DexOrLong2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/PackedSwitch.java b/src/main/java/com/android/tools/r8/dex/code/DexPackedSwitch.java
similarity index 86%
rename from src/main/java/com/android/tools/r8/code/PackedSwitch.java
rename to src/main/java/com/android/tools/r8/dex/code/DexPackedSwitch.java
index 070b870..34029d8 100644
--- a/src/main/java/com/android/tools/r8/code/PackedSwitch.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexPackedSwitch.java
@@ -2,22 +2,22 @@
 // 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.naming.ClassNameMapper;
 
-public class PackedSwitch extends Format31t {
+public class DexPackedSwitch extends DexFormat31t {
 
   public static final int OPCODE = 0x2b;
   public static final String NAME = "PackedSwitch";
   public static final String SMALI_NAME = "packed-switch";
 
-  PackedSwitch(int high, BytecodeStream stream) {
+  DexPackedSwitch(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public PackedSwitch(int valueRegister) {
+  public DexPackedSwitch(int valueRegister) {
     super(valueRegister, -1);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/PackedSwitchPayload.java b/src/main/java/com/android/tools/r8/dex/code/DexPackedSwitchPayload.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/PackedSwitchPayload.java
rename to src/main/java/com/android/tools/r8/dex/code/DexPackedSwitchPayload.java
index 3d297bb..2b0a21f 100644
--- a/src/main/java/com/android/tools/r8/code/PackedSwitchPayload.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexPackedSwitchPayload.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
@@ -14,17 +14,17 @@
 import java.nio.ShortBuffer;
 import java.util.Arrays;
 
-public class PackedSwitchPayload extends SwitchPayload {
+public class DexPackedSwitchPayload extends DexSwitchPayload {
 
   public final int size;
   public final int first_key;
   public final /* offset */ int[] targets;
 
-  private static void specify(StructuralSpecification<PackedSwitchPayload, ?> spec) {
+  private static void specify(StructuralSpecification<DexPackedSwitchPayload, ?> spec) {
     spec.withInt(i -> i.size).withInt(i -> i.first_key).withIntArray(i -> i.targets);
   }
 
-  public PackedSwitchPayload(int high, BytecodeStream stream) {
+  public DexPackedSwitchPayload(int high, BytecodeStream stream) {
     super(high, stream);
     size = read16BitValue(stream);
     first_key = readSigned32BitValue(stream);
@@ -34,8 +34,8 @@
     }
   }
 
-  public PackedSwitchPayload(int first_key, int[] targets) {
-    assert targets.length > 0;  // Empty switches should be eliminated.
+  public DexPackedSwitchPayload(int first_key, int[] targets) {
+    assert targets.length > 0; // Empty switches should be eliminated.
     this.size = targets.length;
     this.first_key = first_key;
     this.targets = targets;
@@ -53,7 +53,7 @@
       GraphLens graphLens,
       ObjectToOffsetMapping mapping,
       LensCodeRewriterUtils rewriter) {
-    writeFirst(1, dest);  // Pseudo-opcode = 0x0100
+    writeFirst(1, dest); // Pseudo-opcode = 0x0100
     write16BitValue(size, dest);
     write32BitValue(first_key, dest);
     for (int i = 0; i < size; i++) {
@@ -62,8 +62,8 @@
   }
 
   @Override
-  final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
-    return visitor.visit(this, (PackedSwitchPayload) other, PackedSwitchPayload::specify);
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
+    return visitor.visit(this, (DexPackedSwitchPayload) other, DexPackedSwitchPayload::specify);
   }
 
   @Override
@@ -92,7 +92,7 @@
 
   @Override
   public int[] keys() {
-    return new int[]{first_key};
+    return new int[] {first_key};
   }
 
   @Override
@@ -101,7 +101,7 @@
   }
 
   @Override
-  public String toString(ClassNameMapper naming, Instruction payloadUser) {
+  public String toString(ClassNameMapper naming, DexInstruction payloadUser) {
     StringBuilder builder = new StringBuilder("[PackedSwitchPayload");
     if (payloadUser == null) {
       builder.append(" offsets relative to associated PackedSwitch");
@@ -121,7 +121,7 @@
   }
 
   @Override
-  public String toSmaliString(Instruction payloadUser) {
+  public String toSmaliString(DexInstruction payloadUser) {
     StringBuilder builder = new StringBuilder();
     builder.append("    ");
     builder.append(".packed-switch ");
diff --git a/src/main/java/com/android/tools/r8/code/DexRecordFieldValues.java b/src/main/java/com/android/tools/r8/dex/code/DexRecordFieldValues.java
similarity index 90%
rename from src/main/java/com/android/tools/r8/code/DexRecordFieldValues.java
rename to src/main/java/com/android/tools/r8/dex/code/DexRecordFieldValues.java
index 13cde75..0c03729 100644
--- a/src/main/java/com/android/tools/r8/code/DexRecordFieldValues.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexRecordFieldValues.java
@@ -1,10 +1,11 @@
-// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
@@ -20,7 +21,7 @@
 import java.nio.ShortBuffer;
 import java.util.Arrays;
 
-public class DexRecordFieldValues extends Instruction {
+public class DexRecordFieldValues extends DexInstruction {
 
   public static final String NAME = "RecordFieldValues";
   public static final String SMALI_NAME = "record-field-values*";
@@ -37,12 +38,12 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     for (DexField field : fields) {
-      field.collectIndexedItems(indexedItems);
+      field.collectIndexedItems(appView, indexedItems);
     }
   }
 
@@ -73,7 +74,7 @@
   }
 
   @Override
-  int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+  int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
     return visitor.visit(this, (DexRecordFieldValues) other, DexRecordFieldValues::specify);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/RemDouble.java b/src/main/java/com/android/tools/r8/dex/code/DexRemDouble.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/RemDouble.java
rename to src/main/java/com/android/tools/r8/dex/code/DexRemDouble.java
index 4107bf0..8ca18cb 100644
--- a/src/main/java/com/android/tools/r8/code/RemDouble.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexRemDouble.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class RemDouble extends Format23x {
+public class DexRemDouble extends DexFormat23x {
 
   public static final int OPCODE = 0xaf;
   public static final String NAME = "RemDouble";
   public static final String SMALI_NAME = "rem-double";
 
-  RemDouble(int high, BytecodeStream stream) {
+  DexRemDouble(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public RemDouble(int dest, int left, int right) {
+  public DexRemDouble(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/RemDouble2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexRemDouble2Addr.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/RemDouble2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexRemDouble2Addr.java
index a538dfd..022087a 100644
--- a/src/main/java/com/android/tools/r8/code/RemDouble2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexRemDouble2Addr.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class RemDouble2Addr extends Format12x {
+
+public class DexRemDouble2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xcf;
   public static final String NAME = "RemDouble2Addr";
   public static final String SMALI_NAME = "rem-double/2addr";
 
-  RemDouble2Addr(int high, BytecodeStream stream) {
+  DexRemDouble2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public RemDouble2Addr(int left, int right) {
+  public DexRemDouble2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/RemFloat.java b/src/main/java/com/android/tools/r8/dex/code/DexRemFloat.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/RemFloat.java
rename to src/main/java/com/android/tools/r8/dex/code/DexRemFloat.java
index 944332b..ac5984b 100644
--- a/src/main/java/com/android/tools/r8/code/RemFloat.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexRemFloat.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class RemFloat extends Format23x {
+
+public class DexRemFloat extends DexFormat23x {
 
   public static final int OPCODE = 0xaA;
   public static final String NAME = "RemFloat";
   public static final String SMALI_NAME = "rem-float";
 
-  RemFloat(int high, BytecodeStream stream) {
+  DexRemFloat(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public RemFloat(int dest, int left, int right) {
+  public DexRemFloat(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/RemFloat2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexRemFloat2Addr.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/RemFloat2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexRemFloat2Addr.java
index ddfdb15..fcad4b1 100644
--- a/src/main/java/com/android/tools/r8/code/RemFloat2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexRemFloat2Addr.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class RemFloat2Addr extends Format12x {
+
+public class DexRemFloat2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xca;
   public static final String NAME = "RemFloat2Addr";
   public static final String SMALI_NAME = "rem-float/2addr";
 
-  RemFloat2Addr(int high, BytecodeStream stream) {
+  DexRemFloat2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public RemFloat2Addr(int left, int right) {
+  public DexRemFloat2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/RemInt.java b/src/main/java/com/android/tools/r8/dex/code/DexRemInt.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/RemInt.java
rename to src/main/java/com/android/tools/r8/dex/code/DexRemInt.java
index f345fc6..3b6850e 100644
--- a/src/main/java/com/android/tools/r8/code/RemInt.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexRemInt.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class RemInt extends Format23x {
+public class DexRemInt extends DexFormat23x {
 
   public static final int OPCODE = 0x94;
   public static final String NAME = "RemInt";
   public static final String SMALI_NAME = "rem-int";
 
-  RemInt(int high, BytecodeStream stream) {
+  DexRemInt(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public RemInt(int dest, int left, int right) {
+  public DexRemInt(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/RemInt2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexRemInt2Addr.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/RemInt2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexRemInt2Addr.java
index 5e357d6..f1d1d8d 100644
--- a/src/main/java/com/android/tools/r8/code/RemInt2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexRemInt2Addr.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class RemInt2Addr extends Format12x {
+public class DexRemInt2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xb4;
   public static final String NAME = "RemInt2Addr";
   public static final String SMALI_NAME = "rem-int/2addr";
 
-  RemInt2Addr(int high, BytecodeStream stream) {
+  DexRemInt2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public RemInt2Addr(int left, int right) {
+  public DexRemInt2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/RemIntLit16.java b/src/main/java/com/android/tools/r8/dex/code/DexRemIntLit16.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/RemIntLit16.java
rename to src/main/java/com/android/tools/r8/dex/code/DexRemIntLit16.java
index 80f3277..630b564 100644
--- a/src/main/java/com/android/tools/r8/code/RemIntLit16.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexRemIntLit16.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class RemIntLit16 extends Format22s {
+public class DexRemIntLit16 extends DexFormat22s {
 
   public static final int OPCODE = 0xd4;
   public static final String NAME = "RemIntLit16";
   public static final String SMALI_NAME = "rem-int/lit16";
 
-  RemIntLit16(int high, BytecodeStream stream) {
+  DexRemIntLit16(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public RemIntLit16(int dest, int register, int constant) {
+  public DexRemIntLit16(int dest, int register, int constant) {
     super(dest, register, constant);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/RemIntLit8.java b/src/main/java/com/android/tools/r8/dex/code/DexRemIntLit8.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/RemIntLit8.java
rename to src/main/java/com/android/tools/r8/dex/code/DexRemIntLit8.java
index d1fcc7f..15ec213 100644
--- a/src/main/java/com/android/tools/r8/code/RemIntLit8.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexRemIntLit8.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class RemIntLit8 extends Format22b {
+
+public class DexRemIntLit8 extends DexFormat22b {
 
   public static final int OPCODE = 0xdc;
   public static final String NAME = "RemIntLit8";
   public static final String SMALI_NAME = "rem-int/lit8";
 
-  RemIntLit8(int high, BytecodeStream stream) {
+  DexRemIntLit8(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public RemIntLit8(int dest, int register, int constant) {
+  public DexRemIntLit8(int dest, int register, int constant) {
     super(dest, register, constant);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/RemLong.java b/src/main/java/com/android/tools/r8/dex/code/DexRemLong.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/RemLong.java
rename to src/main/java/com/android/tools/r8/dex/code/DexRemLong.java
index fa48d0c..46f1278 100644
--- a/src/main/java/com/android/tools/r8/code/RemLong.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexRemLong.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class RemLong extends Format23x {
+public class DexRemLong extends DexFormat23x {
 
   public static final int OPCODE = 0x9f;
   public static final String NAME = "RemLong";
   public static final String SMALI_NAME = "rem-long";
 
-  RemLong(int high, BytecodeStream stream) {
+  DexRemLong(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public RemLong(int dest, int left, int right) {
+  public DexRemLong(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/RemLong2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexRemLong2Addr.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/RemLong2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexRemLong2Addr.java
index ec14f4f..dcf2dc3 100644
--- a/src/main/java/com/android/tools/r8/code/RemLong2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexRemLong2Addr.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class RemLong2Addr extends Format12x {
+public class DexRemLong2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xbf;
   public static final String NAME = "RemLong2Addr";
   public static final String SMALI_NAME = "rem-long/2addr";
 
-  RemLong2Addr(int high, BytecodeStream stream) {
+  DexRemLong2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public RemLong2Addr(int left, int right) {
+  public DexRemLong2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/Return.java b/src/main/java/com/android/tools/r8/dex/code/DexReturn.java
similarity index 83%
rename from src/main/java/com/android/tools/r8/code/Return.java
rename to src/main/java/com/android/tools/r8/dex/code/DexReturn.java
index 6792c3a..2d3662d 100644
--- a/src/main/java/com/android/tools/r8/code/Return.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexReturn.java
@@ -1,21 +1,21 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class Return extends Format11x {
+public class DexReturn extends DexFormat11x {
 
   public static final int OPCODE = 0xf;
   public static final String NAME = "Return";
   public static final String SMALI_NAME = "return";
 
-  Return(int high, BytecodeStream stream) {
+  DexReturn(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public Return(int AA) {
+  public DexReturn(int AA) {
     super(AA);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/ReturnObject.java b/src/main/java/com/android/tools/r8/dex/code/DexReturnObject.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/ReturnObject.java
rename to src/main/java/com/android/tools/r8/dex/code/DexReturnObject.java
index c5008c7..07a795d 100644
--- a/src/main/java/com/android/tools/r8/code/ReturnObject.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexReturnObject.java
@@ -1,21 +1,21 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class ReturnObject extends Format11x {
+public class DexReturnObject extends DexFormat11x {
 
   public static final int OPCODE = 0x11;
   public static final String NAME = "ReturnObject";
   public static final String SMALI_NAME = "return-object";
 
-  ReturnObject(int high, BytecodeStream stream) {
+  DexReturnObject(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public ReturnObject(int AA) {
+  public DexReturnObject(int AA) {
     super(AA);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/ReturnVoid.java b/src/main/java/com/android/tools/r8/dex/code/DexReturnVoid.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/ReturnVoid.java
rename to src/main/java/com/android/tools/r8/dex/code/DexReturnVoid.java
index 32d75f8..fae79fc 100644
--- a/src/main/java/com/android/tools/r8/code/ReturnVoid.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexReturnVoid.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 
-public class ReturnVoid extends Format10x {
+public class DexReturnVoid extends DexFormat10x {
 
   public static final int OPCODE = 0xe;
   public static final String NAME = "ReturnVoid";
   public static final String SMALI_NAME = "return-void";
 
-  ReturnVoid(int high, BytecodeStream stream) {
+  DexReturnVoid(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public ReturnVoid() {}
+  public DexReturnVoid() {}
 
   @Override
   public String getName() {
@@ -34,7 +34,7 @@
   }
 
   @Override
-  final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
     return DexCompareHelper.compareIdUniquelyDeterminesEquality(this, other);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/ReturnWide.java b/src/main/java/com/android/tools/r8/dex/code/DexReturnWide.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/ReturnWide.java
rename to src/main/java/com/android/tools/r8/dex/code/DexReturnWide.java
index f1f40b2..c3670f0 100644
--- a/src/main/java/com/android/tools/r8/code/ReturnWide.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexReturnWide.java
@@ -1,21 +1,21 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class ReturnWide extends Format11x {
+public class DexReturnWide extends DexFormat11x {
 
   public static final int OPCODE = 0x10;
   public static final String NAME = "ReturnWide";
   public static final String SMALI_NAME = "return-wide";
 
-  ReturnWide(int high, BytecodeStream stream) {
+  DexReturnWide(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public ReturnWide(int AA) {
+  public DexReturnWide(int AA) {
     super(AA);
   }
 
@@ -43,4 +43,4 @@
   public void buildIR(IRBuilder builder) {
     builder.addReturn(AA);
   }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/android/tools/r8/code/RsubInt.java b/src/main/java/com/android/tools/r8/dex/code/DexRsubInt.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/RsubInt.java
rename to src/main/java/com/android/tools/r8/dex/code/DexRsubInt.java
index 410f81a..7a2d7bd 100644
--- a/src/main/java/com/android/tools/r8/code/RsubInt.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexRsubInt.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class RsubInt extends Format22s {
+public class DexRsubInt extends DexFormat22s {
 
   public static final int OPCODE = 0xd1;
   public static final String NAME = "RsubInt";
   public static final String SMALI_NAME = "rsub-int";
 
-  RsubInt(int high, BytecodeStream stream) {
+  DexRsubInt(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public RsubInt(int dest, int register, int constant) {
+  public DexRsubInt(int dest, int register, int constant) {
     super(dest, register, constant);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/RsubIntLit8.java b/src/main/java/com/android/tools/r8/dex/code/DexRsubIntLit8.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/RsubIntLit8.java
rename to src/main/java/com/android/tools/r8/dex/code/DexRsubIntLit8.java
index 242a3ba..8ea9a48 100644
--- a/src/main/java/com/android/tools/r8/code/RsubIntLit8.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexRsubIntLit8.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class RsubIntLit8 extends Format22b {
+
+public class DexRsubIntLit8 extends DexFormat22b {
 
   public static final int OPCODE = 0xd9;
   public static final String NAME = "RsubIntLit8";
   public static final String SMALI_NAME = "rsub-int/lit8";
 
-  RsubIntLit8(int high, BytecodeStream stream) {
+  DexRsubIntLit8(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public RsubIntLit8(int dest, int register, int constant) {
+  public DexRsubIntLit8(int dest, int register, int constant) {
     super(dest, register, constant);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/SafeCheckCast.java b/src/main/java/com/android/tools/r8/dex/code/DexSafeCheckCast.java
similarity index 68%
rename from src/main/java/com/android/tools/r8/code/SafeCheckCast.java
rename to src/main/java/com/android/tools/r8/dex/code/DexSafeCheckCast.java
index 8f19396..004708b 100644
--- a/src/main/java/com/android/tools/r8/code/SafeCheckCast.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSafeCheckCast.java
@@ -1,21 +1,21 @@
-// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class SafeCheckCast extends CheckCast {
+public class DexSafeCheckCast extends DexCheckCast {
 
-  SafeCheckCast(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexSafeCheckCast(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping);
   }
 
-  public SafeCheckCast(int valueRegister, DexType type) {
+  public DexSafeCheckCast(int valueRegister, DexType type) {
     super(valueRegister, type, true);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/Sget.java b/src/main/java/com/android/tools/r8/dex/code/DexSget.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/Sget.java
rename to src/main/java/com/android/tools/r8/dex/code/DexSget.java
index 2bd4653..91bfbd9 100644
--- a/src/main/java/com/android/tools/r8/code/Sget.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSget.java
@@ -1,24 +1,24 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class Sget extends SgetOrSput implements CfOrDexStaticFieldRead {
+public class DexSget extends DexSgetOrSput implements CfOrDexStaticFieldRead {
 
   public static final int OPCODE = 0x60;
   public static final String NAME = "Sget";
   public static final String SMALI_NAME = "sget";
 
-  Sget(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexSget(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getFieldMap());
   }
 
-  public Sget(int AA, DexField BBBB) {
+  public DexSget(int AA, DexField BBBB) {
     super(AA, BBBB);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/SgetBoolean.java b/src/main/java/com/android/tools/r8/dex/code/DexSgetBoolean.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/SgetBoolean.java
rename to src/main/java/com/android/tools/r8/dex/code/DexSgetBoolean.java
index fb51776..1f669e0 100644
--- a/src/main/java/com/android/tools/r8/code/SgetBoolean.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSgetBoolean.java
@@ -1,24 +1,24 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class SgetBoolean extends SgetOrSput implements CfOrDexStaticFieldRead {
+public class DexSgetBoolean extends DexSgetOrSput implements CfOrDexStaticFieldRead {
 
   public static final int OPCODE = 0x63;
   public static final String NAME = "SgetBoolean";
   public static final String SMALI_NAME = "sget-boolean";
 
-  SgetBoolean(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexSgetBoolean(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getFieldMap());
   }
 
-  public SgetBoolean(int AA, DexField BBBB) {
+  public DexSgetBoolean(int AA, DexField BBBB) {
     super(AA, BBBB);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/SgetByte.java b/src/main/java/com/android/tools/r8/dex/code/DexSgetByte.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/SgetByte.java
rename to src/main/java/com/android/tools/r8/dex/code/DexSgetByte.java
index ee693ac..ace5c84 100644
--- a/src/main/java/com/android/tools/r8/code/SgetByte.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSgetByte.java
@@ -1,24 +1,24 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class SgetByte extends SgetOrSput implements CfOrDexStaticFieldRead {
+public class DexSgetByte extends DexSgetOrSput implements CfOrDexStaticFieldRead {
 
   public static final int OPCODE = 0x64;
   public static final String NAME = "SgetByte";
   public static final String SMALI_NAME = "sget-byte";
 
-  SgetByte(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexSgetByte(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getFieldMap());
   }
 
-  public SgetByte(int AA, DexField BBBB) {
+  public DexSgetByte(int AA, DexField BBBB) {
     super(AA, BBBB);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/SgetChar.java b/src/main/java/com/android/tools/r8/dex/code/DexSgetChar.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/SgetChar.java
rename to src/main/java/com/android/tools/r8/dex/code/DexSgetChar.java
index 5f61f90..4219043 100644
--- a/src/main/java/com/android/tools/r8/code/SgetChar.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSgetChar.java
@@ -1,24 +1,24 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class SgetChar extends SgetOrSput implements CfOrDexStaticFieldRead {
+public class DexSgetChar extends DexSgetOrSput implements CfOrDexStaticFieldRead {
 
   public static final int OPCODE = 0x65;
   public static final String NAME = "SgetChar";
   public static final String SMALI_NAME = "sget-char";
 
-  SgetChar(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexSgetChar(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getFieldMap());
   }
 
-  public SgetChar(int AA, DexField BBBB) {
+  public DexSgetChar(int AA, DexField BBBB) {
     super(AA, BBBB);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/SgetObject.java b/src/main/java/com/android/tools/r8/dex/code/DexSgetObject.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/SgetObject.java
rename to src/main/java/com/android/tools/r8/dex/code/DexSgetObject.java
index 8e5018e..7894adf 100644
--- a/src/main/java/com/android/tools/r8/code/SgetObject.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSgetObject.java
@@ -1,24 +1,24 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class SgetObject extends SgetOrSput implements CfOrDexStaticFieldRead {
+public class DexSgetObject extends DexSgetOrSput implements CfOrDexStaticFieldRead {
 
   public static final int OPCODE = 0x62;
   public static final String NAME = "SgetObject";
   public static final String SMALI_NAME = "sget-object";
 
-  SgetObject(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexSgetObject(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getFieldMap());
   }
 
-  public SgetObject(int AA, DexField BBBB) {
+  public DexSgetObject(int AA, DexField BBBB) {
     super(AA, BBBB);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/SgetOrSput.java b/src/main/java/com/android/tools/r8/dex/code/DexSgetOrSput.java
similarity index 72%
rename from src/main/java/com/android/tools/r8/code/SgetOrSput.java
rename to src/main/java/com/android/tools/r8/dex/code/DexSgetOrSput.java
index 499d679..85c8ea3 100644
--- a/src/main/java/com/android/tools/r8/code/SgetOrSput.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSgetOrSput.java
@@ -1,9 +1,10 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
@@ -12,24 +13,24 @@
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.nio.ShortBuffer;
 
-abstract class SgetOrSput extends Format21c<DexField> {
+abstract class DexSgetOrSput extends DexFormat21c<DexField> {
 
-  SgetOrSput(int high, BytecodeStream stream, DexField[] map) {
+  DexSgetOrSput(int high, BytecodeStream stream, DexField[] map) {
     super(high, stream, map);
   }
 
-  protected SgetOrSput(int AA, DexField BBBB) {
+  protected DexSgetOrSput(int AA, DexField BBBB) {
     super(AA, BBBB);
   }
 
   @Override
   public final void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
-    DexField rewritten = graphLens.lookupField(getField());
-    rewritten.collectIndexedItems(indexedItems);
+    DexField rewritten = appView.graphLens().lookupField(getField());
+    rewritten.collectIndexedItems(appView, indexedItems);
   }
 
   @Override
@@ -50,7 +51,7 @@
   }
 
   @Override
-  void internalSubSpecify(StructuralSpecification<Format21c<DexField>, ?> spec) {
+  void internalSubSpecify(StructuralSpecification<DexFormat21c<DexField>, ?> spec) {
     spec.withItem(i -> i.BBBB);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/code/SgetShort.java b/src/main/java/com/android/tools/r8/dex/code/DexSgetShort.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/SgetShort.java
rename to src/main/java/com/android/tools/r8/dex/code/DexSgetShort.java
index 99fc4ee..b98797d 100644
--- a/src/main/java/com/android/tools/r8/code/SgetShort.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSgetShort.java
@@ -1,24 +1,24 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class SgetShort extends SgetOrSput implements CfOrDexStaticFieldRead {
+public class DexSgetShort extends DexSgetOrSput implements CfOrDexStaticFieldRead {
 
   public static final int OPCODE = 0x66;
   public static final String NAME = "SgetShort";
   public static final String SMALI_NAME = "sget-short";
 
-  SgetShort(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexSgetShort(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getFieldMap());
   }
 
-  public SgetShort(int AA, DexField BBBB) {
+  public DexSgetShort(int AA, DexField BBBB) {
     super(AA, BBBB);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/SgetWide.java b/src/main/java/com/android/tools/r8/dex/code/DexSgetWide.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/SgetWide.java
rename to src/main/java/com/android/tools/r8/dex/code/DexSgetWide.java
index 75a4343..5964d85 100644
--- a/src/main/java/com/android/tools/r8/code/SgetWide.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSgetWide.java
@@ -1,24 +1,24 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class SgetWide extends SgetOrSput implements CfOrDexStaticFieldRead {
+public class DexSgetWide extends DexSgetOrSput implements CfOrDexStaticFieldRead {
 
   public static final int OPCODE = 0x61;
   public static final String NAME = "SgetWide";
   public static final String SMALI_NAME = "sget-wide";
 
-  SgetWide(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexSgetWide(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getFieldMap());
   }
 
-  public SgetWide(int AA, DexField BBBB) {
+  public DexSgetWide(int AA, DexField BBBB) {
     super(AA, BBBB);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/ShlInt.java b/src/main/java/com/android/tools/r8/dex/code/DexShlInt.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/ShlInt.java
rename to src/main/java/com/android/tools/r8/dex/code/DexShlInt.java
index 2f724c0..1b8780e 100644
--- a/src/main/java/com/android/tools/r8/code/ShlInt.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexShlInt.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class ShlInt extends Format23x {
+public class DexShlInt extends DexFormat23x {
 
   public static final int OPCODE = 0x98;
   public static final String NAME = "ShlInt";
   public static final String SMALI_NAME = "shl-int";
 
-  ShlInt(int high, BytecodeStream stream) {
+  DexShlInt(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public ShlInt(int dest, int left, int right) {
+  public DexShlInt(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/ShlInt2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexShlInt2Addr.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/ShlInt2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexShlInt2Addr.java
index 97a0c89..88ee095 100644
--- a/src/main/java/com/android/tools/r8/code/ShlInt2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexShlInt2Addr.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class ShlInt2Addr extends Format12x {
+public class DexShlInt2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xb8;
   public static final String NAME = "ShlInt2Addr";
   public static final String SMALI_NAME = "shl-int/2addr";
 
-  ShlInt2Addr(int high, BytecodeStream stream) {
+  DexShlInt2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public ShlInt2Addr(int left, int right) {
+  public DexShlInt2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/ShlIntLit8.java b/src/main/java/com/android/tools/r8/dex/code/DexShlIntLit8.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/ShlIntLit8.java
rename to src/main/java/com/android/tools/r8/dex/code/DexShlIntLit8.java
index 173acdc..948680f 100644
--- a/src/main/java/com/android/tools/r8/code/ShlIntLit8.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexShlIntLit8.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class ShlIntLit8 extends Format22b {
+
+public class DexShlIntLit8 extends DexFormat22b {
 
   public static final int OPCODE = 0xe0;
   public static final String NAME = "ShlIntLit8";
   public static final String SMALI_NAME = "shl-int/lit8";
 
-  ShlIntLit8(int high, BytecodeStream stream) {
+  DexShlIntLit8(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public ShlIntLit8(int dest, int register, int constant) {
+  public DexShlIntLit8(int dest, int register, int constant) {
     super(dest, register, constant);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/ShlLong.java b/src/main/java/com/android/tools/r8/dex/code/DexShlLong.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/ShlLong.java
rename to src/main/java/com/android/tools/r8/dex/code/DexShlLong.java
index 54b98f9..1fcc10e 100644
--- a/src/main/java/com/android/tools/r8/code/ShlLong.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexShlLong.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class ShlLong extends Format23x {
+public class DexShlLong extends DexFormat23x {
 
   public static final int OPCODE = 0xA3;
   public static final String NAME = "ShlLong";
   public static final String SMALI_NAME = "shl-long";
 
-  ShlLong(int high, BytecodeStream stream) {
+  DexShlLong(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public ShlLong(int dest, int left, int right) {
+  public DexShlLong(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/ShlLong2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexShlLong2Addr.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/ShlLong2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexShlLong2Addr.java
index e7f35b0..36151a2 100644
--- a/src/main/java/com/android/tools/r8/code/ShlLong2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexShlLong2Addr.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class ShlLong2Addr extends Format12x {
+public class DexShlLong2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xc3;
   public static final String NAME = "ShlLong2Addr";
   public static final String SMALI_NAME = "shl-long/2addr";
 
-  ShlLong2Addr(int high, BytecodeStream stream) {
+  DexShlLong2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public ShlLong2Addr(int left, int right) {
+  public DexShlLong2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/ShrInt.java b/src/main/java/com/android/tools/r8/dex/code/DexShrInt.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/ShrInt.java
rename to src/main/java/com/android/tools/r8/dex/code/DexShrInt.java
index d51cce7..d86bdd6 100644
--- a/src/main/java/com/android/tools/r8/code/ShrInt.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexShrInt.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class ShrInt extends Format23x {
+public class DexShrInt extends DexFormat23x {
 
   public static final int OPCODE = 0x99;
   public static final String NAME = "ShrInt";
   public static final String SMALI_NAME = "shr-int";
 
-  ShrInt(int high, BytecodeStream stream) {
+  DexShrInt(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public ShrInt(int dest, int left, int right) {
+  public DexShrInt(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/ShrInt2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexShrInt2Addr.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/ShrInt2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexShrInt2Addr.java
index b90172b..10023c2 100644
--- a/src/main/java/com/android/tools/r8/code/ShrInt2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexShrInt2Addr.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class ShrInt2Addr extends Format12x {
+public class DexShrInt2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xb9;
   public static final String NAME = "ShrInt2Addr";
   public static final String SMALI_NAME = "shr-int/2addr";
 
-  ShrInt2Addr(int high, BytecodeStream stream) {
+  DexShrInt2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public ShrInt2Addr(int left, int right) {
+  public DexShrInt2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/ShrIntLit8.java b/src/main/java/com/android/tools/r8/dex/code/DexShrIntLit8.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/ShrIntLit8.java
rename to src/main/java/com/android/tools/r8/dex/code/DexShrIntLit8.java
index ecb58ff..0e5e6e9 100644
--- a/src/main/java/com/android/tools/r8/code/ShrIntLit8.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexShrIntLit8.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class ShrIntLit8 extends Format22b {
+public class DexShrIntLit8 extends DexFormat22b {
 
   public static final int OPCODE = 0xe1;
   public static final String NAME = "ShrIntLit8";
   public static final String SMALI_NAME = "shr-int/lit8";
 
-  ShrIntLit8(int high, BytecodeStream stream) {
+  DexShrIntLit8(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public ShrIntLit8(int dest, int register, int constant) {
+  public DexShrIntLit8(int dest, int register, int constant) {
     super(dest, register, constant);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/ShrLong.java b/src/main/java/com/android/tools/r8/dex/code/DexShrLong.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/ShrLong.java
rename to src/main/java/com/android/tools/r8/dex/code/DexShrLong.java
index fbf9ef2..913535b 100644
--- a/src/main/java/com/android/tools/r8/code/ShrLong.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexShrLong.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class ShrLong extends Format23x {
+public class DexShrLong extends DexFormat23x {
 
   public static final int OPCODE = 0xA4;
   public static final String NAME = "ShrLong";
   public static final String SMALI_NAME = "shr-long";
 
-  ShrLong(int high, BytecodeStream stream) {
+  DexShrLong(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public ShrLong(int dest, int left, int right) {
+  public DexShrLong(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/ShrLong2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexShrLong2Addr.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/ShrLong2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexShrLong2Addr.java
index 4732c39..c73273f 100644
--- a/src/main/java/com/android/tools/r8/code/ShrLong2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexShrLong2Addr.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class ShrLong2Addr extends Format12x {
+public class DexShrLong2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xc4;
   public static final String NAME = "ShrLong2Addr";
   public static final String SMALI_NAME = "shr-long/2addr";
 
-  ShrLong2Addr(int high, BytecodeStream stream) {
+  DexShrLong2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public ShrLong2Addr(int left, int right) {
+  public DexShrLong2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/SparseSwitch.java b/src/main/java/com/android/tools/r8/dex/code/DexSparseSwitch.java
similarity index 86%
rename from src/main/java/com/android/tools/r8/code/SparseSwitch.java
rename to src/main/java/com/android/tools/r8/dex/code/DexSparseSwitch.java
index b0a048a..4f15ab7 100644
--- a/src/main/java/com/android/tools/r8/code/SparseSwitch.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSparseSwitch.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.naming.ClassNameMapper;
 
-public class SparseSwitch extends Format31t {
+public class DexSparseSwitch extends DexFormat31t {
 
   public static final int OPCODE = 0x2c;
   public static final String NAME = "SparseSwitch";
   public static final String SMALI_NAME = "sparse-switch";
 
-  SparseSwitch(int high, BytecodeStream stream) {
+  DexSparseSwitch(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public SparseSwitch(int value) {
+  public DexSparseSwitch(int value) {
     super(value, -1);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/SparseSwitchPayload.java b/src/main/java/com/android/tools/r8/dex/code/DexSparseSwitchPayload.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/SparseSwitchPayload.java
rename to src/main/java/com/android/tools/r8/dex/code/DexSparseSwitchPayload.java
index 9dac193e..f9ed49e 100644
--- a/src/main/java/com/android/tools/r8/code/SparseSwitchPayload.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSparseSwitchPayload.java
@@ -1,7 +1,7 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
@@ -14,17 +14,17 @@
 import java.nio.ShortBuffer;
 import java.util.Arrays;
 
-public class SparseSwitchPayload extends SwitchPayload {
+public class DexSparseSwitchPayload extends DexSwitchPayload {
 
   public final int size;
   public final int[] keys;
   public final /* offset */ int[] targets;
 
-  private static void specify(StructuralSpecification<SparseSwitchPayload, ?> spec) {
+  private static void specify(StructuralSpecification<DexSparseSwitchPayload, ?> spec) {
     spec.withInt(i -> i.size).withIntArray(i -> i.keys).withIntArray(i -> i.targets);
   }
 
-  public SparseSwitchPayload(int high, BytecodeStream stream) {
+  public DexSparseSwitchPayload(int high, BytecodeStream stream) {
     super(high, stream);
     size = read16BitValue(stream);
     keys = new int[size];
@@ -38,8 +38,8 @@
     }
   }
 
-  public SparseSwitchPayload(int[] keys, int[] targets) {
-    assert targets.length > 0;  // Empty switches should be eliminated.
+  public DexSparseSwitchPayload(int[] keys, int[] targets) {
+    assert targets.length > 0; // Empty switches should be eliminated.
     this.size = targets.length;
     this.keys = keys;
     this.targets = targets;
@@ -57,7 +57,7 @@
       GraphLens graphLens,
       ObjectToOffsetMapping mapping,
       LensCodeRewriterUtils rewriter) {
-    writeFirst(2, dest);  // Pseudo-opcode = 0x0200
+    writeFirst(2, dest); // Pseudo-opcode = 0x0200
     write16BitValue(size, dest);
     for (int i = 0; i < size; i++) {
       write32BitValue(keys[i], dest);
@@ -68,8 +68,8 @@
   }
 
   @Override
-  final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
-    return visitor.visit(this, (SparseSwitchPayload) other, SparseSwitchPayload::specify);
+  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
+    return visitor.visit(this, (DexSparseSwitchPayload) other, DexSparseSwitchPayload::specify);
   }
 
   @Override
@@ -107,7 +107,7 @@
   }
 
   @Override
-  public String toString(ClassNameMapper naming, Instruction payloadUser) {
+  public String toString(ClassNameMapper naming, DexInstruction payloadUser) {
     StringBuilder builder = new StringBuilder("[SparseSwitchPayload");
     if (payloadUser == null) {
       builder.append(" offsets relative to associated SparseSwitch");
@@ -127,7 +127,7 @@
   }
 
   @Override
-  public String toSmaliString(Instruction payloadUser) {
+  public String toSmaliString(DexInstruction payloadUser) {
     StringBuilder builder = new StringBuilder();
     builder.append("    ");
     builder.append(".sparse-switch");
diff --git a/src/main/java/com/android/tools/r8/code/Sput.java b/src/main/java/com/android/tools/r8/dex/code/DexSput.java
similarity index 84%
rename from src/main/java/com/android/tools/r8/code/Sput.java
rename to src/main/java/com/android/tools/r8/dex/code/DexSput.java
index e9e7f56..8a7ab46 100644
--- a/src/main/java/com/android/tools/r8/code/Sput.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSput.java
@@ -1,24 +1,24 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class Sput extends SgetOrSput {
+public class DexSput extends DexSgetOrSput {
 
   public static final int OPCODE = 0x67;
   public static final String NAME = "Sput";
   public static final String SMALI_NAME = "sput";
 
-  Sput(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  DexSput(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getFieldMap());
   }
 
-  public Sput(int AA, DexField BBBB) {
+  public DexSput(int AA, DexField BBBB) {
     super(AA, BBBB);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/SputBoolean.java b/src/main/java/com/android/tools/r8/dex/code/DexSputBoolean.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/SputBoolean.java
rename to src/main/java/com/android/tools/r8/dex/code/DexSputBoolean.java
index d3ba949..1bc6555 100644
--- a/src/main/java/com/android/tools/r8/code/SputBoolean.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSputBoolean.java
@@ -1,24 +1,24 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class SputBoolean extends SgetOrSput {
+public class DexSputBoolean extends DexSgetOrSput {
 
   public static final int OPCODE = 0x6a;
   public static final String NAME = "SputBoolean";
   public static final String SMALI_NAME = "sput-boolean";
 
-  /*package*/ SputBoolean(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  /*package*/ DexSputBoolean(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getFieldMap());
   }
 
-  public SputBoolean(int AA, DexField BBBB) {
+  public DexSputBoolean(int AA, DexField BBBB) {
     super(AA, BBBB);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/SputByte.java b/src/main/java/com/android/tools/r8/dex/code/DexSputByte.java
similarity index 83%
rename from src/main/java/com/android/tools/r8/code/SputByte.java
rename to src/main/java/com/android/tools/r8/dex/code/DexSputByte.java
index e1c09f5..40f754e 100644
--- a/src/main/java/com/android/tools/r8/code/SputByte.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSputByte.java
@@ -1,24 +1,24 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class SputByte extends SgetOrSput {
+public class DexSputByte extends DexSgetOrSput {
 
   public static final int OPCODE = 0x6b;
   public static final String NAME = "SputByte";
   public static final String SMALI_NAME = "sput-byte";
 
-  /*package*/ SputByte(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  /*package*/ DexSputByte(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getFieldMap());
   }
 
-  public SputByte(int AA, DexField BBBB) {
+  public DexSputByte(int AA, DexField BBBB) {
     super(AA, BBBB);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/SputChar.java b/src/main/java/com/android/tools/r8/dex/code/DexSputChar.java
similarity index 83%
rename from src/main/java/com/android/tools/r8/code/SputChar.java
rename to src/main/java/com/android/tools/r8/dex/code/DexSputChar.java
index 2497f76..c4a1174 100644
--- a/src/main/java/com/android/tools/r8/code/SputChar.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSputChar.java
@@ -1,24 +1,24 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class SputChar extends SgetOrSput {
+public class DexSputChar extends DexSgetOrSput {
 
   public static final int OPCODE = 0x6c;
   public static final String NAME = "SputChar";
   public static final String SMALI_NAME = "sput-char";
 
-  /*package*/ SputChar(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  /*package*/ DexSputChar(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getFieldMap());
   }
 
-  public SputChar(int AA, DexField BBBB) {
+  public DexSputChar(int AA, DexField BBBB) {
     super(AA, BBBB);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/SputObject.java b/src/main/java/com/android/tools/r8/dex/code/DexSputObject.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/SputObject.java
rename to src/main/java/com/android/tools/r8/dex/code/DexSputObject.java
index 43a92b6..91dfca4 100644
--- a/src/main/java/com/android/tools/r8/code/SputObject.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSputObject.java
@@ -1,24 +1,24 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class SputObject extends SgetOrSput {
+public class DexSputObject extends DexSgetOrSput {
 
   public static final int OPCODE = 0x69;
   public static final String NAME = "SputObject";
   public static final String SMALI_NAME = "sput-object";
 
-  /*package*/ SputObject(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  /*package*/ DexSputObject(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getFieldMap());
   }
 
-  public SputObject(int AA, DexField BBBB) {
+  public DexSputObject(int AA, DexField BBBB) {
     super(AA, BBBB);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/SputShort.java b/src/main/java/com/android/tools/r8/dex/code/DexSputShort.java
similarity index 82%
rename from src/main/java/com/android/tools/r8/code/SputShort.java
rename to src/main/java/com/android/tools/r8/dex/code/DexSputShort.java
index 2335606..d4aec47 100644
--- a/src/main/java/com/android/tools/r8/code/SputShort.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSputShort.java
@@ -1,24 +1,24 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class SputShort extends SgetOrSput {
+public class DexSputShort extends DexSgetOrSput {
 
   public static final int OPCODE = 0x6d;
   public static final String NAME = "SputShort";
   public static final String SMALI_NAME = "sput-short";
 
-  /*package*/ SputShort(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  /*package*/ DexSputShort(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getFieldMap());
   }
 
-  public SputShort(int AA, DexField BBBB) {
+  public DexSputShort(int AA, DexField BBBB) {
     super(AA, BBBB);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/SputWide.java b/src/main/java/com/android/tools/r8/dex/code/DexSputWide.java
similarity index 83%
rename from src/main/java/com/android/tools/r8/code/SputWide.java
rename to src/main/java/com/android/tools/r8/dex/code/DexSputWide.java
index 278418a..a3a8003 100644
--- a/src/main/java/com/android/tools/r8/code/SputWide.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSputWide.java
@@ -1,24 +1,24 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class SputWide extends SgetOrSput {
+public class DexSputWide extends DexSgetOrSput {
 
   public static final int OPCODE = 0x68;
   public static final String NAME = "SputWide";
   public static final String SMALI_NAME = "sput-wide";
 
-  /*package*/ SputWide(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
+  /*package*/ DexSputWide(int high, BytecodeStream stream, OffsetToObjectMapping mapping) {
     super(high, stream, mapping.getFieldMap());
   }
 
-  public SputWide(int AA, DexField BBBB) {
+  public DexSputWide(int AA, DexField BBBB) {
     super(AA, BBBB);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/SubDouble.java b/src/main/java/com/android/tools/r8/dex/code/DexSubDouble.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/SubDouble.java
rename to src/main/java/com/android/tools/r8/dex/code/DexSubDouble.java
index f68b270..fc2176e 100644
--- a/src/main/java/com/android/tools/r8/code/SubDouble.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSubDouble.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class SubDouble extends Format23x {
+public class DexSubDouble extends DexFormat23x {
 
   public static final int OPCODE = 0xac;
   public static final String NAME = "SubDouble";
   public static final String SMALI_NAME = "sub-double";
 
-  SubDouble(int high, BytecodeStream stream) {
+  DexSubDouble(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public SubDouble(int dest, int left, int right) {
+  public DexSubDouble(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/SubDouble2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexSubDouble2Addr.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/SubDouble2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexSubDouble2Addr.java
index 2cd16ac..3b99bfc 100644
--- a/src/main/java/com/android/tools/r8/code/SubDouble2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSubDouble2Addr.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class SubDouble2Addr extends Format12x {
+public class DexSubDouble2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xcc;
   public static final String NAME = "SubDouble2Addr";
   public static final String SMALI_NAME = "sub-double/2addr";
 
-  SubDouble2Addr(int high, BytecodeStream stream) {
+  DexSubDouble2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public SubDouble2Addr(int left, int right) {
+  public DexSubDouble2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/SubFloat.java b/src/main/java/com/android/tools/r8/dex/code/DexSubFloat.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/SubFloat.java
rename to src/main/java/com/android/tools/r8/dex/code/DexSubFloat.java
index e49e843..45fa530 100644
--- a/src/main/java/com/android/tools/r8/code/SubFloat.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSubFloat.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class SubFloat extends Format23x {
+public class DexSubFloat extends DexFormat23x {
 
   public static final int OPCODE = 0xA7;
   public static final String NAME = "SubFloat";
   public static final String SMALI_NAME = "sub-float";
 
-  SubFloat(int high, BytecodeStream stream) {
+  DexSubFloat(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public SubFloat(int dest, int left, int right) {
+  public DexSubFloat(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/SubFloat2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexSubFloat2Addr.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/SubFloat2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexSubFloat2Addr.java
index 42c4442..4df6f33 100644
--- a/src/main/java/com/android/tools/r8/code/SubFloat2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSubFloat2Addr.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class SubFloat2Addr extends Format12x {
+public class DexSubFloat2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xc7;
   public static final String NAME = "SubFloat2Addr";
   public static final String SMALI_NAME = "sub-float/2addr";
 
-  SubFloat2Addr(int high, BytecodeStream stream) {
+  DexSubFloat2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public SubFloat2Addr(int left, int right) {
+  public DexSubFloat2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/SubInt.java b/src/main/java/com/android/tools/r8/dex/code/DexSubInt.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/SubInt.java
rename to src/main/java/com/android/tools/r8/dex/code/DexSubInt.java
index d187ea3..a161d5c 100644
--- a/src/main/java/com/android/tools/r8/code/SubInt.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSubInt.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class SubInt extends Format23x {
+public class DexSubInt extends DexFormat23x {
 
   public static final int OPCODE = 0x91;
   public static final String NAME = "SubInt";
   public static final String SMALI_NAME = "sub-int";
 
-  SubInt(int high, BytecodeStream stream) {
+  DexSubInt(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public SubInt(int dest, int left, int right) {
+  public DexSubInt(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/SubInt2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexSubInt2Addr.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/SubInt2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexSubInt2Addr.java
index 97f94a4..314744c 100644
--- a/src/main/java/com/android/tools/r8/code/SubInt2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSubInt2Addr.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class SubInt2Addr extends Format12x {
+
+public class DexSubInt2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xb1;
   public static final String NAME = "SubInt2Addr";
   public static final String SMALI_NAME = "sub-int/2addr";
 
-  SubInt2Addr(int high, BytecodeStream stream) {
+  DexSubInt2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public SubInt2Addr(int left, int right) {
+  public DexSubInt2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/SubLong.java b/src/main/java/com/android/tools/r8/dex/code/DexSubLong.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/SubLong.java
rename to src/main/java/com/android/tools/r8/dex/code/DexSubLong.java
index a2a0697..e418a52 100644
--- a/src/main/java/com/android/tools/r8/code/SubLong.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSubLong.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class SubLong extends Format23x {
+public class DexSubLong extends DexFormat23x {
 
   public static final int OPCODE = 0x9c;
   public static final String NAME = "SubLong";
   public static final String SMALI_NAME = "sub-long";
 
-  SubLong(int high, BytecodeStream stream) {
+  DexSubLong(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public SubLong(int dest, int left, int right) {
+  public DexSubLong(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/SubLong2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexSubLong2Addr.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/SubLong2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexSubLong2Addr.java
index 40d2c6b..75e13b7 100644
--- a/src/main/java/com/android/tools/r8/code/SubLong2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSubLong2Addr.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class SubLong2Addr extends Format12x {
+
+public class DexSubLong2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xbc;
   public static final String NAME = "SubLong2Addr";
   public static final String SMALI_NAME = "sub-long/2addr";
 
-  SubLong2Addr(int high, BytecodeStream stream) {
+  DexSubLong2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public SubLong2Addr(int left, int right) {
+  public DexSubLong2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/SwitchPayload.java b/src/main/java/com/android/tools/r8/dex/code/DexSwitchPayload.java
similarity index 76%
rename from src/main/java/com/android/tools/r8/code/SwitchPayload.java
rename to src/main/java/com/android/tools/r8/dex/code/DexSwitchPayload.java
index 0525e41..7f18ec2 100644
--- a/src/main/java/com/android/tools/r8/code/SwitchPayload.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSwitchPayload.java
@@ -2,20 +2,21 @@
 // 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public abstract class SwitchPayload extends Nop {
-  SwitchPayload(int high, BytecodeStream stream) {
+public abstract class DexSwitchPayload extends DexNop {
+  DexSwitchPayload(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public SwitchPayload() {
-  }
+  public DexSwitchPayload() {}
 
   public abstract int[] keys();
+
   public abstract int numberOfKeys();
+
   public abstract int[] switchTargetOffsets();
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/Throw.java b/src/main/java/com/android/tools/r8/dex/code/DexThrow.java
similarity index 84%
rename from src/main/java/com/android/tools/r8/code/Throw.java
rename to src/main/java/com/android/tools/r8/dex/code/DexThrow.java
index 40d69f1..2df333a 100644
--- a/src/main/java/com/android/tools/r8/code/Throw.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexThrow.java
@@ -1,21 +1,21 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class Throw extends Format11x {
+public class DexThrow extends DexFormat11x {
 
   public static final int OPCODE = 0x27;
   public static final String NAME = "Throw";
   public static final String SMALI_NAME = "throw";
 
-  Throw(int high, BytecodeStream stream) {
+  DexThrow(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public Throw(int AA) {
+  public DexThrow(int AA) {
     super(AA);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/UshrInt.java b/src/main/java/com/android/tools/r8/dex/code/DexUshrInt.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/UshrInt.java
rename to src/main/java/com/android/tools/r8/dex/code/DexUshrInt.java
index 6f480b1..c3ac597 100644
--- a/src/main/java/com/android/tools/r8/code/UshrInt.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexUshrInt.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class UshrInt extends Format23x {
+public class DexUshrInt extends DexFormat23x {
 
   public static final int OPCODE = 0x9A;
   public static final String NAME = "UshrInt";
   public static final String SMALI_NAME = "ushr-int";
 
-  UshrInt(int high, BytecodeStream stream) {
+  DexUshrInt(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public UshrInt(int dest, int left, int right) {
+  public DexUshrInt(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/UshrInt2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexUshrInt2Addr.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/UshrInt2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexUshrInt2Addr.java
index 3d9c135..fc5e4a7 100644
--- a/src/main/java/com/android/tools/r8/code/UshrInt2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexUshrInt2Addr.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class UshrInt2Addr extends Format12x {
+public class DexUshrInt2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xba;
   public static final String NAME = "UshrInt2Addr";
   public static final String SMALI_NAME = "ushr-int/2addr";
 
-  UshrInt2Addr(int high, BytecodeStream stream) {
+  DexUshrInt2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public UshrInt2Addr(int left, int right) {
+  public DexUshrInt2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/UshrIntLit8.java b/src/main/java/com/android/tools/r8/dex/code/DexUshrIntLit8.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/UshrIntLit8.java
rename to src/main/java/com/android/tools/r8/dex/code/DexUshrIntLit8.java
index 499c34d..625e1ee 100644
--- a/src/main/java/com/android/tools/r8/code/UshrIntLit8.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexUshrIntLit8.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class UshrIntLit8 extends Format22b {
+public class DexUshrIntLit8 extends DexFormat22b {
 
   public static final int OPCODE = 0xe2;
   public static final String NAME = "UshrIntLit8";
   public static final String SMALI_NAME = "ushr-int/lit8";
 
-  UshrIntLit8(int high, BytecodeStream stream) {
+  DexUshrIntLit8(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public UshrIntLit8(int dest, int register, int constant) {
+  public DexUshrIntLit8(int dest, int register, int constant) {
     super(dest, register, constant);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/UshrLong.java b/src/main/java/com/android/tools/r8/dex/code/DexUshrLong.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/UshrLong.java
rename to src/main/java/com/android/tools/r8/dex/code/DexUshrLong.java
index 43b816a..0aed94f 100644
--- a/src/main/java/com/android/tools/r8/code/UshrLong.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexUshrLong.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class UshrLong extends Format23x {
+
+public class DexUshrLong extends DexFormat23x {
 
   public static final int OPCODE = 0xa5;
   public static final String NAME = "UshrLong";
   public static final String SMALI_NAME = "ushr-long";
 
-  UshrLong(int high, BytecodeStream stream) {
+  DexUshrLong(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public UshrLong(int dest, int left, int right) {
+  public DexUshrLong(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/UshrLong2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexUshrLong2Addr.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/UshrLong2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexUshrLong2Addr.java
index 1651d6d..d140899 100644
--- a/src/main/java/com/android/tools/r8/code/UshrLong2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexUshrLong2Addr.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class UshrLong2Addr extends Format12x {
+public class DexUshrLong2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xc5;
   public static final String NAME = "UshrLong2Addr";
   public static final String SMALI_NAME = "ushr-long/2addr";
 
-  UshrLong2Addr(int high, BytecodeStream stream) {
+  DexUshrLong2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public UshrLong2Addr(int left, int right) {
+  public DexUshrLong2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/XorInt.java b/src/main/java/com/android/tools/r8/dex/code/DexXorInt.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/XorInt.java
rename to src/main/java/com/android/tools/r8/dex/code/DexXorInt.java
index 3e68cf6..063e107 100644
--- a/src/main/java/com/android/tools/r8/code/XorInt.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexXorInt.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class XorInt extends Format23x {
+public class DexXorInt extends DexFormat23x {
 
   public static final int OPCODE = 0x97;
   public static final String NAME = "XorInt";
   public static final String SMALI_NAME = "xor-int";
 
-  XorInt(int high, BytecodeStream stream) {
+  DexXorInt(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public XorInt(int dest, int left, int right) {
+  public DexXorInt(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/XorInt2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexXorInt2Addr.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/XorInt2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexXorInt2Addr.java
index 1c0f1a6..b927dba 100644
--- a/src/main/java/com/android/tools/r8/code/XorInt2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexXorInt2Addr.java
@@ -1,21 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
-public class XorInt2Addr extends Format12x {
+
+public class DexXorInt2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xb7;
   public static final String NAME = "XorInt2Addr";
   public static final String SMALI_NAME = "xor-int/2addr";
 
-  XorInt2Addr(int high, BytecodeStream stream) {
+  DexXorInt2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public XorInt2Addr(int left, int right) {
+  public DexXorInt2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/XorIntLit16.java b/src/main/java/com/android/tools/r8/dex/code/DexXorIntLit16.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/XorIntLit16.java
rename to src/main/java/com/android/tools/r8/dex/code/DexXorIntLit16.java
index 8efa8ac..e55d037 100644
--- a/src/main/java/com/android/tools/r8/code/XorIntLit16.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexXorIntLit16.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class XorIntLit16 extends Format22s {
+public class DexXorIntLit16 extends DexFormat22s {
 
   public static final int OPCODE = 0xd7;
   public static final String NAME = "XorIntLit16";
   public static final String SMALI_NAME = "xor-int/lit16";
 
-  XorIntLit16(int high, BytecodeStream stream) {
+  DexXorIntLit16(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public XorIntLit16(int dest, int register, int constant) {
+  public DexXorIntLit16(int dest, int register, int constant) {
     super(dest, register, constant);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/XorIntLit8.java b/src/main/java/com/android/tools/r8/dex/code/DexXorIntLit8.java
similarity index 80%
rename from src/main/java/com/android/tools/r8/code/XorIntLit8.java
rename to src/main/java/com/android/tools/r8/dex/code/DexXorIntLit8.java
index 8447abb..0cdceff 100644
--- a/src/main/java/com/android/tools/r8/code/XorIntLit8.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexXorIntLit8.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class XorIntLit8 extends Format22b {
+public class DexXorIntLit8 extends DexFormat22b {
 
   public static final int OPCODE = 0xdf;
   public static final String NAME = "XorIntLit8";
   public static final String SMALI_NAME = "xor-int/lit8";
 
-  XorIntLit8(int high, BytecodeStream stream) {
+  DexXorIntLit8(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public XorIntLit8(int dest, int register, int constant) {
+  public DexXorIntLit8(int dest, int register, int constant) {
     super(dest, register, constant);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/XorLong.java b/src/main/java/com/android/tools/r8/dex/code/DexXorLong.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/XorLong.java
rename to src/main/java/com/android/tools/r8/dex/code/DexXorLong.java
index c2f7b7f..53a3deb 100644
--- a/src/main/java/com/android/tools/r8/code/XorLong.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexXorLong.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class XorLong extends Format23x {
+public class DexXorLong extends DexFormat23x {
 
   public static final int OPCODE = 0xA2;
   public static final String NAME = "XorLong";
   public static final String SMALI_NAME = "xor-long";
 
-  XorLong(int high, BytecodeStream stream) {
+  DexXorLong(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public XorLong(int dest, int left, int right) {
+  public DexXorLong(int dest, int left, int right) {
     super(dest, left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/code/XorLong2Addr.java b/src/main/java/com/android/tools/r8/dex/code/DexXorLong2Addr.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/code/XorLong2Addr.java
rename to src/main/java/com/android/tools/r8/dex/code/DexXorLong2Addr.java
index ec3f5ef..6e8ddb3 100644
--- a/src/main/java/com/android/tools/r8/code/XorLong2Addr.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexXorLong2Addr.java
@@ -1,22 +1,22 @@
 // Copyright (c) 2016, 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.code;
+package com.android.tools.r8.dex.code;
 
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 
-public class XorLong2Addr extends Format12x {
+public class DexXorLong2Addr extends DexFormat12x {
 
   public static final int OPCODE = 0xc2;
   public static final String NAME = "XorLong2Addr";
   public static final String SMALI_NAME = "xor-long/2addr";
 
-  XorLong2Addr(int high, BytecodeStream stream) {
+  DexXorLong2Addr(int high, BytecodeStream stream) {
     super(high, stream);
   }
 
-  public XorLong2Addr(int left, int right) {
+  public DexXorLong2Addr(int left, int right) {
     super(left, right);
   }
 
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/EmptyStartupOrder.java b/src/main/java/com/android/tools/r8/experimental/startup/EmptyStartupOrder.java
new file mode 100644
index 0000000..7279ee7
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/experimental/startup/EmptyStartupOrder.java
@@ -0,0 +1,47 @@
+// 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.experimental.startup;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.PrunedItems;
+import java.util.Collection;
+import java.util.Collections;
+
+public class EmptyStartupOrder extends StartupOrder {
+
+  EmptyStartupOrder() {}
+
+  @Override
+  public boolean contains(DexType type) {
+    return false;
+  }
+
+  @Override
+  public Collection<DexType> getClasses() {
+    return Collections.emptyList();
+  }
+
+  @Override
+  public boolean isEmpty() {
+    return true;
+  }
+
+  @Override
+  public EmptyStartupOrder rewrittenWithLens(GraphLens graphLens) {
+    return this;
+  }
+
+  @Override
+  public StartupOrder toStartupOrderForWriting(AppView<?> appView) {
+    return this;
+  }
+
+  @Override
+  public EmptyStartupOrder withoutPrunedItems(PrunedItems prunedItems) {
+    return this;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/NonEmptyStartupOrder.java b/src/main/java/com/android/tools/r8/experimental/startup/NonEmptyStartupOrder.java
new file mode 100644
index 0000000..0427fc3
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/experimental/startup/NonEmptyStartupOrder.java
@@ -0,0 +1,149 @@
+// 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.experimental.startup;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.PrunedItems;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.IdentityHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+
+public class NonEmptyStartupOrder extends StartupOrder {
+
+  private final LinkedHashSet<DexType> startupClasses;
+
+  NonEmptyStartupOrder(LinkedHashSet<DexType> startupClasses) {
+    assert !startupClasses.isEmpty();
+    this.startupClasses = startupClasses;
+  }
+
+  @Override
+  public boolean contains(DexType type) {
+    return startupClasses.contains(type);
+  }
+
+  @Override
+  public Collection<DexType> getClasses() {
+    return startupClasses;
+  }
+
+  @Override
+  public boolean isEmpty() {
+    return false;
+  }
+
+  @Override
+  public StartupOrder rewrittenWithLens(GraphLens graphLens) {
+    LinkedHashSet<DexType> rewrittenStartupClasses = new LinkedHashSet<>(startupClasses.size());
+    for (DexType startupClass : startupClasses) {
+      DexType rewrittenStartupClass = graphLens.lookupType(startupClass);
+      rewrittenStartupClasses.add(rewrittenStartupClass);
+    }
+    return createNonEmpty(rewrittenStartupClasses);
+  }
+
+  @Override
+  public StartupOrder toStartupOrderForWriting(AppView<?> appView) {
+    LinkedHashSet<DexType> rewrittenStartupClasses = new LinkedHashSet<>(startupClasses.size());
+    Map<DexType, List<DexProgramClass>> syntheticContextsToSyntheticClasses =
+        new IdentityHashMap<>();
+    for (DexProgramClass clazz : appView.appInfo().classes()) {
+      if (appView.getSyntheticItems().isSyntheticClass(clazz)) {
+        for (DexType synthesizingContextType :
+            appView.getSyntheticItems().getSynthesizingContextTypes(clazz.getType())) {
+          syntheticContextsToSyntheticClasses
+              .computeIfAbsent(synthesizingContextType, ignoreKey -> new ArrayList<>())
+              .add(clazz);
+        }
+      }
+    }
+    for (DexType startupClass : startupClasses) {
+      addClassAndParentClasses(
+          startupClass, rewrittenStartupClasses, syntheticContextsToSyntheticClasses, appView);
+    }
+    return createNonEmpty(rewrittenStartupClasses);
+  }
+
+  private static boolean addClass(
+      DexProgramClass clazz, LinkedHashSet<DexType> rewrittenStartupClasses) {
+    return rewrittenStartupClasses.add(clazz.getType());
+  }
+
+  private static void addClassAndParentClasses(
+      DexType type,
+      LinkedHashSet<DexType> rewrittenStartupClasses,
+      Map<DexType, List<DexProgramClass>> syntheticContextsToSyntheticClasses,
+      AppView<?> appView) {
+    DexProgramClass definition = appView.app().programDefinitionFor(type);
+    if (definition != null) {
+      addClassAndParentClasses(
+          definition, rewrittenStartupClasses, syntheticContextsToSyntheticClasses, appView);
+    }
+  }
+
+  private static void addClassAndParentClasses(
+      DexProgramClass clazz,
+      LinkedHashSet<DexType> rewrittenStartupClasses,
+      Map<DexType, List<DexProgramClass>> syntheticContextsToSyntheticClasses,
+      AppView<?> appView) {
+    if (addClass(clazz, rewrittenStartupClasses)) {
+      addSyntheticClassesAndParentClasses(
+          clazz, rewrittenStartupClasses, syntheticContextsToSyntheticClasses, appView);
+      addParentClasses(
+          clazz, rewrittenStartupClasses, syntheticContextsToSyntheticClasses, appView);
+    }
+  }
+
+  private static void addSyntheticClassesAndParentClasses(
+      DexProgramClass clazz,
+      LinkedHashSet<DexType> rewrittenStartupClasses,
+      Map<DexType, List<DexProgramClass>> syntheticContextsToSyntheticClasses,
+      AppView<?> appView) {
+    List<DexProgramClass> derivedClasses =
+        syntheticContextsToSyntheticClasses.remove(clazz.getType());
+    if (derivedClasses != null) {
+      for (DexProgramClass derivedClass : derivedClasses) {
+        addClassAndParentClasses(
+            derivedClass, rewrittenStartupClasses, syntheticContextsToSyntheticClasses, appView);
+      }
+    }
+  }
+
+  private static void addParentClasses(
+      DexProgramClass clazz,
+      LinkedHashSet<DexType> rewrittenStartupClasses,
+      Map<DexType, List<DexProgramClass>> syntheticContextsToSyntheticClasses,
+      AppView<?> appView) {
+    clazz.forEachImmediateSupertype(
+        supertype ->
+            addClassAndParentClasses(
+                supertype, rewrittenStartupClasses, syntheticContextsToSyntheticClasses, appView));
+  }
+
+  @Override
+  public StartupOrder withoutPrunedItems(PrunedItems prunedItems) {
+    LinkedHashSet<DexType> rewrittenStartupClasses = new LinkedHashSet<>(startupClasses.size());
+    for (DexType startupClass : startupClasses) {
+      if (!prunedItems.isRemoved(startupClass)) {
+        rewrittenStartupClasses.add(startupClass);
+      }
+    }
+    return createNonEmpty(rewrittenStartupClasses);
+  }
+
+  private StartupOrder createNonEmpty(LinkedHashSet<DexType> startupClasses) {
+    if (startupClasses.isEmpty()) {
+      assert false;
+      return empty();
+    }
+    return new NonEmptyStartupOrder(startupClasses);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupConfiguration.java b/src/main/java/com/android/tools/r8/experimental/startup/StartupConfiguration.java
index 0c1425c..7e78009 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/StartupConfiguration.java
+++ b/src/main/java/com/android/tools/r8/experimental/startup/StartupConfiguration.java
@@ -14,6 +14,7 @@
 import com.android.tools.r8.utils.Reporter;
 import com.android.tools.r8.utils.StringDiagnostic;
 import java.io.IOException;
+import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.List;
@@ -46,15 +47,18 @@
   public static StartupConfiguration createStartupConfiguration(
       DexItemFactory dexItemFactory, Reporter reporter) {
     String propertyValue = System.getProperty("com.android.tools.r8.startup.config");
-    if (propertyValue == null) {
-      return null;
-    }
+    return propertyValue != null
+        ? createStartupConfigurationFromFile(dexItemFactory, reporter, Paths.get(propertyValue))
+        : null;
+  }
 
+  public static StartupConfiguration createStartupConfigurationFromFile(
+      DexItemFactory dexItemFactory, Reporter reporter, Path path) {
     reporter.warning("Use of startupconfig is experimental");
 
     List<String> startupDescriptors;
     try {
-      startupDescriptors = FileUtils.readAllLines(Paths.get(propertyValue));
+      startupDescriptors = FileUtils.readAllLines(path);
     } catch (IOException e) {
       throw reporter.fatalError(new ExceptionDiagnostic(e));
     }
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupOrder.java b/src/main/java/com/android/tools/r8/experimental/startup/StartupOrder.java
new file mode 100644
index 0000000..da68a15
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/experimental/startup/StartupOrder.java
@@ -0,0 +1,46 @@
+// 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.experimental.startup;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.utils.InternalOptions;
+import java.util.Collection;
+import java.util.LinkedHashSet;
+
+public abstract class StartupOrder {
+
+  StartupOrder() {}
+
+  public static StartupOrder createInitialStartupOrder(InternalOptions options) {
+    if (!options.getStartupOptions().hasStartupConfiguration()) {
+      return empty();
+    }
+    StartupConfiguration startupConfiguration =
+        options.getStartupOptions().getStartupConfiguration();
+    if (!startupConfiguration.hasStartupClasses()) {
+      return empty();
+    }
+    return new NonEmptyStartupOrder(new LinkedHashSet<>(startupConfiguration.getStartupClasses()));
+  }
+
+  public static StartupOrder empty() {
+    return new EmptyStartupOrder();
+  }
+
+  public abstract boolean contains(DexType type);
+
+  public abstract Collection<DexType> getClasses();
+
+  public abstract boolean isEmpty();
+
+  public abstract StartupOrder rewrittenWithLens(GraphLens graphLens);
+
+  public abstract StartupOrder toStartupOrderForWriting(AppView<?> appView);
+
+  public abstract StartupOrder withoutPrunedItems(PrunedItems prunedItems);
+}
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
index 2547884..836f1a5 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
@@ -7,6 +7,7 @@
 import static com.android.tools.r8.utils.TraversalContinuation.doBreak;
 import static com.android.tools.r8.utils.TraversalContinuation.doContinue;
 
+import com.android.tools.r8.experimental.startup.StartupOrder;
 import com.android.tools.r8.features.ClassToFeatureSplitMap;
 import com.android.tools.r8.ir.analysis.type.InterfaceCollection;
 import com.android.tools.r8.ir.analysis.type.InterfaceCollection.Builder;
@@ -48,15 +49,18 @@
       DexApplication application,
       ClassToFeatureSplitMap classToFeatureSplitMap,
       MainDexInfo mainDexInfo,
-      GlobalSyntheticsStrategy globalSyntheticsStrategy) {
+      GlobalSyntheticsStrategy globalSyntheticsStrategy,
+      StartupOrder startupOrder) {
     return new AppInfoWithClassHierarchy(
         SyntheticItems.createInitialSyntheticItems(application, globalSyntheticsStrategy),
         classToFeatureSplitMap,
         mainDexInfo,
-        MissingClasses.empty());
+        MissingClasses.empty(),
+        startupOrder);
   }
 
   private final ClassToFeatureSplitMap classToFeatureSplitMap;
+  private final StartupOrder startupOrder;
 
   /** Set of types that are mentioned in the program, but for which no definition exists. */
   // TODO(b/175659048): Consider hoisting to AppInfo to allow using MissingClasses in D8 desugar.
@@ -67,10 +71,12 @@
       CommittedItems committedItems,
       ClassToFeatureSplitMap classToFeatureSplitMap,
       MainDexInfo mainDexInfo,
-      MissingClasses missingClasses) {
+      MissingClasses missingClasses,
+      StartupOrder startupOrder) {
     super(committedItems, mainDexInfo);
     this.classToFeatureSplitMap = classToFeatureSplitMap;
     this.missingClasses = missingClasses;
+    this.startupOrder = startupOrder;
   }
 
   // For desugaring.
@@ -80,6 +86,7 @@
     // TODO(b/175659048): Migrate the reporting of missing classes in D8 desugar to MissingClasses,
     //  and use the missing classes from AppInfo instead of MissingClasses.empty().
     this.missingClasses = MissingClasses.empty();
+    this.startupOrder = StartupOrder.empty();
   }
 
   public static AppInfoWithClassHierarchy createForDesugaring(AppInfo appInfo) {
@@ -89,7 +96,11 @@
 
   public final AppInfoWithClassHierarchy rebuildWithClassHierarchy(CommittedItems commit) {
     return new AppInfoWithClassHierarchy(
-        commit, getClassToFeatureSplitMap(), getMainDexInfo(), getMissingClasses());
+        commit,
+        getClassToFeatureSplitMap(),
+        getMainDexInfo(),
+        getMissingClasses(),
+        getStartupOrder());
   }
 
   public AppInfoWithClassHierarchy rebuildWithClassHierarchy(
@@ -99,7 +110,8 @@
         getSyntheticItems().commit(fn.apply(app())),
         getClassToFeatureSplitMap(),
         getMainDexInfo(),
-        getMissingClasses());
+        getMissingClasses(),
+        getStartupOrder());
   }
 
   @Override
@@ -110,7 +122,8 @@
         getSyntheticItems().commit(app()),
         getClassToFeatureSplitMap(),
         mainDexInfo,
-        getMissingClasses());
+        getMissingClasses(),
+        getStartupOrder());
   }
 
   @Override
@@ -126,7 +139,8 @@
         getSyntheticItems().commitPrunedItems(prunedItems),
         getClassToFeatureSplitMap().withoutPrunedItems(prunedItems),
         getMainDexInfo().withoutPrunedItems(prunedItems),
-        getMissingClasses());
+        getMissingClasses(),
+        getStartupOrder().withoutPrunedItems(prunedItems));
   }
 
   public ClassToFeatureSplitMap getClassToFeatureSplitMap() {
@@ -137,6 +151,10 @@
     return missingClasses;
   }
 
+  public StartupOrder getStartupOrder() {
+    return startupOrder;
+  }
+
   @Override
   public boolean hasClassHierarchy() {
     assert checkIfObsolete();
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index 1cc7843..6dd2ee7 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -9,6 +9,7 @@
 import com.android.tools.r8.contexts.CompilationContext;
 import com.android.tools.r8.contexts.CompilationContext.ProcessorContext;
 import com.android.tools.r8.errors.dontwarn.DontWarnConfiguration;
+import com.android.tools.r8.experimental.startup.StartupOrder;
 import com.android.tools.r8.features.ClassToFeatureSplitMap;
 import com.android.tools.r8.graph.DexValue.DexValueString;
 import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
@@ -29,6 +30,7 @@
 import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoFactory;
 import com.android.tools.r8.ir.optimize.library.LibraryMemberOptimizer;
 import com.android.tools.r8.ir.optimize.library.LibraryMethodSideEffectModelCollection;
+import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.naming.SeedMapper;
 import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagator;
 import com.android.tools.r8.optimize.interfaces.collection.OpenClosedInterfacesCollection;
@@ -77,6 +79,7 @@
   private GraphLens codeLens = GraphLens.getIdentityLens();
   private GraphLens graphLens = GraphLens.getIdentityLens();
   private InitClassLens initClassLens;
+  private NamingLens namingLens = NamingLens.getIdentityLens();
   private ProguardCompatibilityActions proguardCompatibilityActions;
   private RootSet rootSet;
   private MainDexRootSet mainDexRootSet = null;
@@ -201,12 +204,14 @@
       DexApplication application, MainDexInfo mainDexInfo) {
     ClassToFeatureSplitMap classToFeatureSplitMap =
         ClassToFeatureSplitMap.createInitialClassToFeatureSplitMap(application.options);
+    StartupOrder startupOrder = StartupOrder.createInitialStartupOrder(application.options);
     AppInfoWithClassHierarchy appInfo =
         AppInfoWithClassHierarchy.createInitialAppInfoWithClassHierarchy(
             application,
             classToFeatureSplitMap,
             mainDexInfo,
-            GlobalSyntheticsStrategy.forSingleOutputMode());
+            GlobalSyntheticsStrategy.forSingleOutputMode(),
+            startupOrder);
     return new AppView<>(appInfo, WholeProgramOptimizations.ON, defaultTypeRewriter(appInfo));
   }
 
@@ -244,8 +249,12 @@
     return appInfo;
   }
 
+  public AppInfoWithClassHierarchy appInfoWithClassHierarchy() {
+    return hasClassHierarchy() ? appInfo.withClassHierarchy() : null;
+  }
+
   public AppInfoWithLiveness appInfoWithLiveness() {
-    return appInfo.hasLiveness() ? appInfo.withLiveness() : null;
+    return hasLiveness() ? appInfo.withLiveness() : null;
   }
 
   public AppInfoWithClassHierarchy appInfoForDesugaring() {
@@ -571,6 +580,14 @@
     return getKeepInfo().getMethodInfo(method);
   }
 
+  public NamingLens getNamingLens() {
+    return namingLens;
+  }
+
+  public void setNamingLens(NamingLens namingLens) {
+    this.namingLens = namingLens;
+  }
+
   public boolean hasProguardCompatibilityActions() {
     return proguardCompatibilityActions != null;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/CfCode.java b/src/main/java/com/android/tools/r8/graph/CfCode.java
index 3a727a8..321c775 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -18,8 +18,8 @@
 import com.android.tools.r8.cf.code.CfPosition;
 import com.android.tools.r8.cf.code.CfReturnVoid;
 import com.android.tools.r8.cf.code.CfTryCatch;
-import com.android.tools.r8.code.Base5Format;
-import com.android.tools.r8.code.CfOrDexInstruction;
+import com.android.tools.r8.dex.code.CfOrDexInstruction;
+import com.android.tools.r8.dex.code.DexBase5Format;
 import com.android.tools.r8.errors.InvalidDebugInfoException;
 import com.android.tools.r8.errors.Unimplemented;
 import com.android.tools.r8.errors.Unreachable;
@@ -303,7 +303,7 @@
 
   @Override
   public int estimatedDexCodeSizeUpperBoundInBytes() {
-    return estimatedSizeForInlining() * Base5Format.SIZE;
+    return estimatedSizeForInlining() * DexBase5Format.SIZE;
   }
 
   public int bytecodeSizeUpperBound() {
diff --git a/src/main/java/com/android/tools/r8/graph/ClasspathOrLibraryClass.java b/src/main/java/com/android/tools/r8/graph/ClasspathOrLibraryClass.java
index da19912..d666539 100644
--- a/src/main/java/com/android/tools/r8/graph/ClasspathOrLibraryClass.java
+++ b/src/main/java/com/android/tools/r8/graph/ClasspathOrLibraryClass.java
@@ -5,5 +5,14 @@
 package com.android.tools.r8.graph;
 
 public interface ClasspathOrLibraryClass extends ClassDefinition, ClasspathOrLibraryDefinition {
+
+  void appendInstanceField(DexEncodedField field);
+
   DexClass asDexClass();
+
+  DexEncodedField lookupField(DexField field);
+
+  static ClasspathOrLibraryClass asClasspathOrLibraryClass(DexClass clazz) {
+    return clazz != null ? clazz.asClasspathOrLibraryClass() : null;
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/Code.java b/src/main/java/com/android/tools/r8/graph/Code.java
index 8152305..0edeb6f 100644
--- a/src/main/java/com/android/tools/r8/graph/Code.java
+++ b/src/main/java/com/android/tools/r8/graph/Code.java
@@ -3,8 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.graph;
 
-import com.android.tools.r8.code.CfOrDexInstruction;
 import com.android.tools.r8.dex.MixedSectionCollection;
+import com.android.tools.r8.dex.code.CfOrDexInstruction;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.bytecodemetadata.BytecodeInstructionMetadata;
 import com.android.tools.r8.graph.bytecodemetadata.BytecodeMetadata;
diff --git a/src/main/java/com/android/tools/r8/graph/DefaultInstanceInitializerCode.java b/src/main/java/com/android/tools/r8/graph/DefaultInstanceInitializerCode.java
index 07fd8c4..5569e34 100644
--- a/src/main/java/com/android/tools/r8/graph/DefaultInstanceInitializerCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DefaultInstanceInitializerCode.java
@@ -9,11 +9,11 @@
 import com.android.tools.r8.cf.code.CfInvoke;
 import com.android.tools.r8.cf.code.CfLoad;
 import com.android.tools.r8.cf.code.CfReturnVoid;
-import com.android.tools.r8.code.InvokeDirect;
-import com.android.tools.r8.code.ReturnVoid;
 import com.android.tools.r8.dex.CodeToKeep;
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.dex.MixedSectionCollection;
+import com.android.tools.r8.dex.code.DexInvokeDirect;
+import com.android.tools.r8.dex.code.DexReturnVoid;
 import com.android.tools.r8.graph.DexCode.Try;
 import com.android.tools.r8.graph.DexCode.TryHandler;
 import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
@@ -169,16 +169,17 @@
 
   @Override
   public int codeSizeInBytes() {
-    return InvokeDirect.SIZE + ReturnVoid.SIZE;
+    return DexInvokeDirect.SIZE + DexReturnVoid.SIZE;
   }
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
-    getParentConstructor(context, rewriter.dexItemFactory()).collectIndexedItems(indexedItems);
+    getParentConstructor(context, rewriter.dexItemFactory())
+        .collectIndexedItems(appView, indexedItems);
   }
 
   @Override
@@ -369,9 +370,9 @@
       GraphLens graphLens,
       LensCodeRewriterUtils lensCodeRewriter,
       ObjectToOffsetMapping mapping) {
-    new InvokeDirect(1, getParentConstructor(context, mapping.dexItemFactory()), 0, 0, 0, 0, 0)
+    new DexInvokeDirect(1, getParentConstructor(context, mapping.dexItemFactory()), 0, 0, 0, 0, 0)
         .write(shortBuffer, context, graphLens, mapping, lensCodeRewriter);
-    new ReturnVoid().write(shortBuffer, context, graphLens, mapping, lensCodeRewriter);
+    new DexReturnVoid().write(shortBuffer, context, graphLens, mapping, lensCodeRewriter);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
index d26278f..44ac005 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
@@ -101,8 +101,8 @@
     return visibility + " " + annotation;
   }
 
-  public void collectIndexedItems(IndexedItemCollection indexedItems) {
-    annotation.collectIndexedItems(indexedItems);
+  public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
+    annotation.collectIndexedItems(appView, indexedItems);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotationDirectory.java b/src/main/java/com/android/tools/r8/graph/DexAnnotationDirectory.java
index d2d763e..c0060f3 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotationDirectory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotationDirectory.java
@@ -8,6 +8,7 @@
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.function.Consumer;
 
 public class DexAnnotationDirectory extends DexItem {
 
@@ -41,6 +42,46 @@
     }
   }
 
+  public void visitAnnotations(
+      Consumer<DexAnnotation> annotationConsumer,
+      Consumer<DexAnnotationSet> annotationSetConsumer,
+      Consumer<ParameterAnnotationsList> parameterAnnotationsListConsumer) {
+    visitAnnotationSet(clazz.annotations(), annotationConsumer, annotationSetConsumer);
+    clazz.forEachField(
+        field ->
+            visitAnnotationSet(field.annotations(), annotationConsumer, annotationSetConsumer));
+    clazz.forEachMethod(
+        method -> {
+          visitAnnotationSet(method.annotations(), annotationConsumer, annotationSetConsumer);
+          visitParameterAnnotationsList(
+              method.getParameterAnnotations(),
+              annotationConsumer,
+              annotationSetConsumer,
+              parameterAnnotationsListConsumer);
+        });
+  }
+
+  private void visitAnnotationSet(
+      DexAnnotationSet annotationSet,
+      Consumer<DexAnnotation> annotationConsumer,
+      Consumer<DexAnnotationSet> annotationSetConsumer) {
+    annotationSetConsumer.accept(annotationSet);
+    for (DexAnnotation annotation : annotationSet.getAnnotations()) {
+      annotationConsumer.accept(annotation);
+    }
+  }
+
+  private void visitParameterAnnotationsList(
+      ParameterAnnotationsList parameterAnnotationsList,
+      Consumer<DexAnnotation> annotationConsumer,
+      Consumer<DexAnnotationSet> annotationSetConsumer,
+      Consumer<ParameterAnnotationsList> parameterAnnotationsListConsumer) {
+    parameterAnnotationsListConsumer.accept(parameterAnnotationsList);
+    for (DexAnnotationSet annotationSet : parameterAnnotationsList.getAnnotationSets()) {
+      visitAnnotationSet(annotationSet, annotationConsumer, annotationSetConsumer);
+    }
+  }
+
   public DexAnnotationSet getClazzAnnotations() {
     return clazz.annotations();
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotationElement.java b/src/main/java/com/android/tools/r8/graph/DexAnnotationElement.java
index f351642..a2be262 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotationElement.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotationElement.java
@@ -60,9 +60,9 @@
     return name + "=" + value;
   }
 
-  public void collectIndexedItems(IndexedItemCollection indexedItems) {
+  public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
     name.collectIndexedItems(indexedItems);
-    value.collectIndexedItems(indexedItems);
+    value.collectIndexedItems(appView, indexedItems);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java b/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java
index 40ff50e..bcddd66 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java
@@ -65,6 +65,10 @@
     return this;
   }
 
+  public DexAnnotation[] getAnnotations() {
+    return annotations;
+  }
+
   @Override
   public StructuralMapping<DexAnnotationSet> getStructuralMapping() {
     return DexAnnotationSet::specify;
@@ -116,9 +120,9 @@
     return false;
   }
 
-  public void collectIndexedItems(IndexedItemCollection indexedItems) {
+  public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
     for (DexAnnotation annotation : annotations) {
-      annotation.collectIndexedItems(indexedItems);
+      annotation.collectIndexedItems(appView, indexedItems);
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/graph/DexCallSite.java b/src/main/java/com/android/tools/r8/graph/DexCallSite.java
index 3aa03da..e3b49d1 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCallSite.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCallSite.java
@@ -160,20 +160,20 @@
     return builder.toString();
   }
 
-  public void collectIndexedItems(IndexedItemCollection indexedItems) {
+  public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
     if (indexedItems.addCallSite(this)) {
       methodName.collectIndexedItems(indexedItems);
-      methodProto.collectIndexedItems(indexedItems);
-      bootstrapMethod.collectIndexedItems(indexedItems);
+      methodProto.collectIndexedItems(appView, indexedItems);
+      bootstrapMethod.collectIndexedItems(appView, indexedItems);
       for (DexValue arg : bootstrapArgs) {
-        arg.collectIndexedItems(indexedItems);
+        arg.collectIndexedItems(appView, indexedItems);
       }
     }
   }
 
   @Override
   void collectMixedSectionItems(MixedSectionCollection mixedItems) {
-    mixedItems.add(getEncodedArray());
+    getEncodedArray().collectMixedSectionItems(mixedItems);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index a615b1f..a377b46 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -788,6 +788,10 @@
     return type;
   }
 
+  public boolean hasSuperType() {
+    return superType != null;
+  }
+
   public DexType getSuperType() {
     return superType;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexCode.java b/src/main/java/com/android/tools/r8/graph/DexCode.java
index c99b310..0a485e7 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -3,14 +3,14 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.graph;
 
-import com.android.tools.r8.code.CfOrDexInstruction;
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.ReturnVoid;
-import com.android.tools.r8.code.SwitchPayload;
 import com.android.tools.r8.dex.CodeToKeep;
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.dex.JumboStringRewriter;
 import com.android.tools.r8.dex.MixedSectionCollection;
+import com.android.tools.r8.dex.code.CfOrDexInstruction;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexReturnVoid;
+import com.android.tools.r8.dex.code.DexSwitchPayload;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DexCode.TryHandler.TypeAddrPair;
 import com.android.tools.r8.graph.DexDebugEvent.SetPositionFrame;
@@ -60,13 +60,13 @@
   public final int outgoingRegisterSize;
   public final Try[] tries;
   public final TryHandler[] handlers;
-  public final Instruction[] instructions;
+  public final DexInstruction[] instructions;
 
   public DexString highestSortingString;
   private DexDebugInfo debugInfo;
   private DexDebugInfoForWriting debugInfoForWriting;
 
-  private final BytecodeMetadata<Instruction> metadata;
+  private final BytecodeMetadata<DexInstruction> metadata;
 
   private static void specify(StructuralSpecification<DexCode, ?> spec) {
     spec.withInt(c -> c.registerSize)
@@ -82,7 +82,7 @@
       int registerSize,
       int insSize,
       int outsSize,
-      Instruction[] instructions,
+      DexInstruction[] instructions,
       Try[] tries,
       TryHandler[] handlers,
       DexDebugInfo debugInfo) {
@@ -101,11 +101,11 @@
       int registerSize,
       int insSize,
       int outsSize,
-      Instruction[] instructions,
+      DexInstruction[] instructions,
       Try[] tries,
       TryHandler[] handlers,
       DexDebugInfo debugInfo,
-      BytecodeMetadata<Instruction> metadata) {
+      BytecodeMetadata<DexInstruction> metadata) {
     this.incomingRegisterSize = insSize;
     this.registerSize = registerSize;
     this.outgoingRegisterSize = outsSize;
@@ -126,7 +126,7 @@
   }
 
   @Override
-  public BytecodeMetadata<Instruction> getMetadata() {
+  public BytecodeMetadata<DexInstruction> getMetadata() {
     return metadata;
   }
 
@@ -135,7 +135,7 @@
     return getMetadata(instruction.asDexInstruction());
   }
 
-  public BytecodeInstructionMetadata getMetadata(Instruction instruction) {
+  public BytecodeInstructionMetadata getMetadata(DexInstruction instruction) {
     return metadata.getMetadata(instruction);
   }
 
@@ -157,8 +157,8 @@
       firstJumboString = mapping.getFirstString();
     } else {
       assert highestSortingString != null
-          || Arrays.stream(instructions).noneMatch(Instruction::isConstString);
-      assert Arrays.stream(instructions).noneMatch(Instruction::isDexItemBasedConstString);
+          || Arrays.stream(instructions).noneMatch(DexInstruction::isConstString);
+      assert Arrays.stream(instructions).noneMatch(DexInstruction::isDexItemBasedConstString);
       if (highestSortingString != null
           && highestSortingString.isGreaterThanOrEqualTo(mapping.getFirstJumboString())) {
         firstJumboString = mapping.getFirstJumboString();
@@ -171,7 +171,7 @@
 
   @Override
   public void setCallSiteContexts(ProgramMethod method) {
-    for (Instruction instruction : instructions) {
+    for (DexInstruction instruction : instructions) {
       DexCallSite callSite = instruction.getCallSite();
       if (callSite != null) {
         callSite.setContext(method.getReference(), instruction.getOffset());
@@ -363,7 +363,7 @@
 
   @Override
   public boolean isEmptyVoidMethod() {
-    return instructions.length == 1 && instructions[0] instanceof ReturnVoid;
+    return instructions.length == 1 && instructions[0] instanceof DexReturnVoid;
   }
 
   @Override
@@ -421,7 +421,7 @@
 
   private void internalRegisterCodeReferences(DexClassAndMethod method, UseRegistry registry) {
     assert registry.getTraversalContinuation().shouldContinue();
-    for (Instruction insn : instructions) {
+    for (DexInstruction insn : instructions) {
       insn.registerUse(registry);
       if (registry.getTraversalContinuation().shouldBreak()) {
         return;
@@ -456,8 +456,8 @@
     builder.append("------------------------------------------------------------\n");
 
     // Collect payload users.
-    Map<Integer, Instruction> payloadUsers = new HashMap<>();
-    for (Instruction dex : instructions) {
+    Map<Integer, DexInstruction> payloadUsers = new HashMap<>();
+    for (DexInstruction dex : instructions) {
       if (dex.hasPayload()) {
         payloadUsers.put(dex.getOffset() + dex.getPayloadOffset(), dex);
       }
@@ -472,7 +472,7 @@
     }
     int instructionNumber = 0;
     Map<Integer, DebugLocalInfo> locals = Collections.emptyMap();
-    for (Instruction insn : instructions) {
+    for (DexInstruction insn : instructions) {
       debugInfo = advanceToOffset(insn.getOffset() - 1, debugInfo, debugInfoIterator);
       while (debugInfo != null && debugInfo.address == insn.getOffset()) {
         if (debugInfo.lineEntry || !locals.equals(debugInfo.locals)) {
@@ -484,7 +484,7 @@
       StringUtils.appendLeftPadded(builder, Integer.toString(instructionNumber++), 5);
       builder.append(": ");
       if (insn.isSwitchPayload()) {
-        Instruction payloadUser = payloadUsers.get(insn.getOffset());
+        DexInstruction payloadUser = payloadUsers.get(insn.getOffset());
         builder.append(insn.toString(naming, payloadUser));
       } else {
         builder.append(insn.toString(naming));
@@ -494,7 +494,7 @@
     if (isPcBasedInfo) {
       builder.append(getDebugInfo()).append("\n");
     } else if (debugInfoIterator.hasNext()) {
-      Instruction lastInstruction = ArrayUtils.last(instructions);
+      DexInstruction lastInstruction = ArrayUtils.last(instructions);
       debugInfo = advanceToOffset(lastInstruction.getOffset(), debugInfo, debugInfoIterator);
       if (debugInfo != null) {
         throw new Unreachable("Could not print all debug information.");
@@ -531,12 +531,12 @@
   public String toSmaliString(ClassNameMapper naming) {
     StringBuilder builder = new StringBuilder();
     // Find labeled targets.
-    Map<Integer, Instruction> payloadUsers = new HashMap<>();
+    Map<Integer, DexInstruction> payloadUsers = new HashMap<>();
     Set<Integer> labledTargets = new HashSet<>();
     // Collect payload users and labeled targets for non-payload instructions.
-    for (Instruction dex : instructions) {
+    for (DexInstruction dex : instructions) {
       int[] targets = dex.getTargets();
-      if (targets != Instruction.NO_TARGETS && targets != Instruction.EXIT_TARGET) {
+      if (targets != DexInstruction.NO_TARGETS && targets != DexInstruction.EXIT_TARGET) {
         assert targets.length <= 2;
         // For if instructions the second target is the fallthrough, for which no label is needed.
         labledTargets.add(dex.getOffset() + targets[0]);
@@ -546,11 +546,11 @@
       }
     }
     // Collect labeled targets for payload instructions.
-    for (Instruction dex : instructions) {
+    for (DexInstruction dex : instructions) {
       if (dex.isSwitchPayload()) {
-        Instruction payloadUser = payloadUsers.get(dex.getOffset());
-        if (dex instanceof SwitchPayload) {
-          SwitchPayload payload = (SwitchPayload) dex;
+        DexInstruction payloadUser = payloadUsers.get(dex.getOffset());
+        if (dex instanceof DexSwitchPayload) {
+          DexSwitchPayload payload = (DexSwitchPayload) dex;
           for (int target : payload.switchTargetOffsets()) {
             labledTargets.add(payloadUser.getOffset() + target);
           }
@@ -558,14 +558,14 @@
       }
     }
     // Generate smali for all instructions.
-    for (Instruction dex : instructions) {
+    for (DexInstruction dex : instructions) {
       if (labledTargets.contains(dex.getOffset())) {
         builder.append("  :label_");
         builder.append(dex.getOffset());
         builder.append("\n");
       }
       if (dex.isSwitchPayload()) {
-        Instruction payloadUser = payloadUsers.get(dex.getOffset());
+        DexInstruction payloadUser = payloadUsers.get(dex.getOffset());
         builder.append(dex.toSmaliString(payloadUser)).append('\n');
       } else {
         builder.append(dex.toSmaliString(naming)).append('\n');
@@ -589,14 +589,14 @@
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     highestSortingString = null;
-    for (Instruction insn : instructions) {
+    for (DexInstruction insn : instructions) {
       assert !insn.isDexItemBasedConstString();
-      insn.collectIndexedItems(indexedItems, context, graphLens, rewriter);
+      insn.collectIndexedItems(appView, indexedItems, context, rewriter);
       if (insn.isConstString()) {
         updateHighestSortingString(insn.asConstString().getString());
       } else if (insn.isConstStringJumbo()) {
@@ -604,10 +604,10 @@
       }
     }
     if (debugInfo != null) {
-      getDebugInfoForWriting().collectIndexedItems(indexedItems, graphLens);
+      getDebugInfoForWriting().collectIndexedItems(appView, indexedItems);
     }
     for (TryHandler handler : handlers) {
-      handler.collectIndexedItems(indexedItems, graphLens);
+      handler.collectIndexedItems(appView, indexedItems);
     }
   }
 
@@ -665,7 +665,7 @@
 
   @Override
   public int codeSizeInBytes() {
-    Instruction last = instructions[instructions.length - 1];
+    DexInstruction last = instructions[instructions.length - 1];
     assert last.hasOffset();
     int result = last.getOffset() + last.getSize();
     assert result == computeCodeSizeInBytes();
@@ -674,7 +674,7 @@
 
   private int computeCodeSizeInBytes() {
     int size = 0;
-    for (Instruction insn : instructions) {
+    for (DexInstruction insn : instructions) {
       size += insn.getSize();
     }
     return size;
@@ -682,7 +682,7 @@
 
   @Override
   public void writeKeepRulesForDesugaredLibrary(CodeToKeep desugaredLibraryCodeToKeep) {
-    for (Instruction instruction : instructions) {
+    for (DexInstruction instruction : instructions) {
       DexMethod method = instruction.getMethod();
       DexField field = instruction.getField();
       if (field != null) {
@@ -707,7 +707,7 @@
       GraphLens graphLens,
       LensCodeRewriterUtils lensCodeRewriter,
       ObjectToOffsetMapping mapping) {
-    for (Instruction instruction : instructions) {
+    for (DexInstruction instruction : instructions) {
       instruction.write(shortBuffer, context, graphLens, mapping, lensCodeRewriter);
     }
   }
@@ -813,9 +813,9 @@
       return Equatable.equalsImpl(this, other);
     }
 
-    public void collectIndexedItems(IndexedItemCollection indexedItems, GraphLens graphLens) {
+    public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
       for (TypeAddrPair pair : pairs) {
-        pair.collectIndexedItems(indexedItems, graphLens);
+        pair.collectIndexedItems(appView, indexedItems);
       }
     }
 
@@ -877,9 +877,9 @@
         return lens.lookupType(type);
       }
 
-      public void collectIndexedItems(IndexedItemCollection indexedItems, GraphLens graphLens) {
-        DexType rewritten = getType(graphLens);
-        rewritten.collectIndexedItems(indexedItems);
+      public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
+        DexType rewritten = getType(appView.graphLens());
+        rewritten.collectIndexedItems(appView, indexedItems);
       }
 
       @Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java b/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java
index 27aacbe..16bf079 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java
@@ -23,7 +23,7 @@
 
   public static final DexDebugEvent[] EMPTY_ARRAY = {};
 
-  public void collectIndexedItems(IndexedItemCollection collection, GraphLens graphLens) {
+  public void collectIndexedItems(AppView<?> appView, IndexedItemCollection collection) {
     // Empty by default.
   }
 
@@ -350,13 +350,13 @@
     }
 
     @Override
-    public void collectIndexedItems(IndexedItemCollection collection, GraphLens graphLens) {
+    public void collectIndexedItems(AppView<?> appView, IndexedItemCollection collection) {
       if (name != null) {
         name.collectIndexedItems(collection);
       }
       if (type != null) {
-        DexType rewritten = graphLens.lookupType(type);
-        rewritten.collectIndexedItems(collection);
+        DexType rewritten = appView.graphLens().lookupType(type);
+        rewritten.collectIndexedItems(appView, collection);
       }
       if (signature != null) {
         signature.collectIndexedItems(collection);
@@ -524,7 +524,7 @@
     }
 
     @Override
-    public void collectIndexedItems(IndexedItemCollection collection, GraphLens graphLens) {
+    public void collectIndexedItems(AppView<?> appView, IndexedItemCollection collection) {
       fileName.collectIndexedItems(collection);
     }
 
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java b/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java
index 09f740e..b6f5fd9 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java
@@ -3,11 +3,11 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.graph;
 
-import com.android.tools.r8.code.Instruction;
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.DebugBytecodeWriter;
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.dex.MixedSectionCollection;
+import com.android.tools.r8.dex.code.DexInstruction;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.utils.ArrayUtils;
 import com.android.tools.r8.utils.LebUtils;
@@ -144,7 +144,7 @@
     }
 
     @Override
-    public void collectIndexedItems(IndexedItemCollection indexedItems, GraphLens graphLens) {
+    public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
       // No indexed items to collect.
     }
 
@@ -255,14 +255,14 @@
       return visitor.visit(this, other.asEventBasedInfo(), EventBasedDebugInfo::specify);
     }
 
-    public void collectIndexedItems(IndexedItemCollection indexedItems, GraphLens graphLens) {
+    public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
       for (DexString parameter : parameters) {
         if (parameter != null) {
           parameter.collectIndexedItems(indexedItems);
         }
       }
       for (DexDebugEvent event : events) {
-        event.collectIndexedItems(indexedItems, graphLens);
+        event.collectIndexedItems(appView, indexedItems);
       }
     }
 
@@ -298,7 +298,7 @@
     List<DexDebugEvent> events = new ArrayList<>(code.instructions.length);
     int pc = 0;
     int delta = 0;
-    for (Instruction instruction : code.instructions) {
+    for (DexInstruction instruction : code.instructions) {
       if (instruction.canThrow()) {
         DexDebugEventBuilder.addDefaultEventWithAdvancePcIfNecessary(delta, delta, events, factory);
         pc += delta;
@@ -337,8 +337,8 @@
     }
 
     @Override
-    public void collectIndexedItems(IndexedItemCollection indexedItems, GraphLens graphLens) {
-      super.collectIndexedItems(indexedItems, graphLens);
+    public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
+      super.collectIndexedItems(appView, indexedItems);
     }
 
     @Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugInfoForWriting.java b/src/main/java/com/android/tools/r8/graph/DexDebugInfoForWriting.java
index 5f94db9..75cdd80 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugInfoForWriting.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugInfoForWriting.java
@@ -13,7 +13,7 @@
 
   void collectMixedSectionItems(MixedSectionCollection collection);
 
-  void collectIndexedItems(IndexedItemCollection indexedItems, GraphLens graphLens);
+  void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems);
 
   int estimatedWriteSize();
 
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java b/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java
index e338ef5..0d4f388 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java
@@ -41,10 +41,10 @@
     return DexEncodedAnnotation::specify;
   }
 
-  public void collectIndexedItems(IndexedItemCollection indexedItems) {
-    type.collectIndexedItems(indexedItems);
+  public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
+    type.collectIndexedItems(appView, indexedItems);
     for (DexAnnotationElement element : elements) {
-      element.collectIndexedItems(indexedItems);
+      element.collectIndexedItems(appView, indexedItems);
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedArray.java b/src/main/java/com/android/tools/r8/graph/DexEncodedArray.java
index 19ec6c2..4192720 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedArray.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedArray.java
@@ -15,9 +15,9 @@
     this.values = values;
   }
 
-  public void collectIndexedItems(IndexedItemCollection indexedItems) {
+  public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
     for (DexValue value : values) {
-      value.collectIndexedItems(indexedItems);
+      value.collectIndexedItems(appView, indexedItems);
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 4196ca2..73e3420 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -29,16 +29,16 @@
 import com.android.tools.r8.cf.code.CfStackInstruction.Opcode;
 import com.android.tools.r8.cf.code.CfStore;
 import com.android.tools.r8.cf.code.CfThrow;
-import com.android.tools.r8.code.ConstString;
-import com.android.tools.r8.code.InstanceOf;
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.InvokeDirect;
-import com.android.tools.r8.code.InvokeStatic;
-import com.android.tools.r8.code.NewInstance;
-import com.android.tools.r8.code.Return;
-import com.android.tools.r8.code.Throw;
-import com.android.tools.r8.code.XorIntLit8;
 import com.android.tools.r8.dex.MixedSectionCollection;
+import com.android.tools.r8.dex.code.DexConstString;
+import com.android.tools.r8.dex.code.DexInstanceOf;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexInvokeDirect;
+import com.android.tools.r8.dex.code.DexInvokeStatic;
+import com.android.tools.r8.dex.code.DexNewInstance;
+import com.android.tools.r8.dex.code.DexReturn;
+import com.android.tools.r8.dex.code.DexThrow;
+import com.android.tools.r8.dex.code.DexXorIntLit8;
 import com.android.tools.r8.errors.InternalCompilerError;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DexAnnotation.AnnotatedKind;
@@ -889,13 +889,11 @@
     return getReference().toSourceString();
   }
 
-  /**
-   * Generates a {@link DexCode} object for the given instructions.
-   */
+  /** Generates a {@link DexCode} object for the given instructions. */
   private DexCode generateCodeFromTemplate(
-      int numberOfRegisters, int outRegisters, Instruction... instructions) {
+      int numberOfRegisters, int outRegisters, DexInstruction... instructions) {
     int offset = 0;
-    for (Instruction instruction : instructions) {
+    for (DexInstruction instruction : instructions) {
       instruction.setOffset(offset);
       offset += instruction.getSize();
     }
@@ -937,13 +935,13 @@
   }
 
   public DexCode buildInstanceOfDexCode(DexType type, boolean negate) {
-    Instruction[] instructions = new Instruction[2 + BooleanUtils.intValue(negate)];
+    DexInstruction[] instructions = new DexInstruction[2 + BooleanUtils.intValue(negate)];
     int i = 0;
-    instructions[i++] = new InstanceOf(0, 0, type);
+    instructions[i++] = new DexInstanceOf(0, 0, type);
     if (negate) {
-      instructions[i++] = new XorIntLit8(0, 0, 1);
+      instructions[i++] = new DexXorIntLit8(0, 0, 1);
     }
-    instructions[i] = new Return(0);
+    instructions[i] = new DexReturn(0);
     return generateCodeFromTemplate(1, 0, instructions);
   }
 
@@ -998,12 +996,12 @@
     return generateCodeFromTemplate(
         2,
         2,
-        new ConstString(0, tag),
-        new ConstString(1, message),
-        new InvokeStatic(2, logMethod, 0, 1, 0, 0, 0),
-        new NewInstance(0, exceptionType),
-        new InvokeDirect(2, exceptionInitMethod, 0, 1, 0, 0, 0),
-        new Throw(0));
+        new DexConstString(0, tag),
+        new DexConstString(1, message),
+        new DexInvokeStatic(2, logMethod, 0, 1, 0, 0, 0),
+        new DexNewInstance(0, exceptionType),
+        new DexInvokeDirect(2, exceptionInitMethod, 0, 1, 0, 0, 0),
+        new DexThrow(0));
   }
 
   private CfCode toCfCodeThatLogsError(DexItemFactory itemFactory) {
diff --git a/src/main/java/com/android/tools/r8/graph/DexField.java b/src/main/java/com/android/tools/r8/graph/DexField.java
index 1f86536..9fbbdb1 100644
--- a/src/main/java/com/android/tools/r8/graph/DexField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexField.java
@@ -143,11 +143,11 @@
   }
 
   @Override
-  public void collectIndexedItems(IndexedItemCollection indexedItems) {
+  public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
     if (indexedItems.addField(this)) {
-      holder.collectIndexedItems(indexedItems);
-      type.collectIndexedItems(indexedItems);
-      indexedItems.getRenamedName(this).collectIndexedItems(indexedItems);
+      holder.collectIndexedItems(appView, indexedItems);
+      type.collectIndexedItems(appView, indexedItems);
+      appView.getNamingLens().lookupName(this).collectIndexedItems(indexedItems);
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/graph/DexMemberAnnotation.java b/src/main/java/com/android/tools/r8/graph/DexMemberAnnotation.java
index 5c9dad2..5bac75e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMemberAnnotation.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMemberAnnotation.java
@@ -44,9 +44,9 @@
       super(item, annotations);
     }
 
-    public void collectIndexedItems(IndexedItemCollection indexedItems) {
-      item.collectIndexedItems(indexedItems);
-      annotations.collectIndexedItems(indexedItems);
+    public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
+      item.collectIndexedItems(appView, indexedItems);
+      annotations.collectIndexedItems(appView, indexedItems);
     }
   }
 
@@ -56,9 +56,9 @@
       super(item, annotations);
     }
 
-    public void collectIndexedItems(IndexedItemCollection indexedItems) {
-      item.collectIndexedItems(indexedItems);
-      annotations.collectIndexedItems(indexedItems);
+    public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
+      item.collectIndexedItems(appView, indexedItems);
+      annotations.collectIndexedItems(appView, indexedItems);
     }
   }
 
@@ -69,9 +69,9 @@
       super(item, annotations);
     }
 
-    public void collectIndexedItems(IndexedItemCollection indexedItems) {
-      item.collectIndexedItems(indexedItems);
-      annotations.collectIndexedItems(indexedItems);
+    public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
+      item.collectIndexedItems(appView, indexedItems);
+      annotations.collectIndexedItems(appView, indexedItems);
     }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethod.java b/src/main/java/com/android/tools/r8/graph/DexMethod.java
index 466e1cf..2fbdbdc 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethod.java
@@ -174,23 +174,23 @@
   }
 
   @Override
-  public void collectIndexedItems(IndexedItemCollection indexedItems) {
-    if (collectIndexedItemsExceptName(indexedItems)) {
-      collectIndexedItemsName(indexedItems);
+  public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
+    if (collectIndexedItemsExceptName(appView, indexedItems)) {
+      collectIndexedItemsName(appView, indexedItems);
     }
   }
 
-  boolean collectIndexedItemsExceptName(IndexedItemCollection indexedItems) {
+  boolean collectIndexedItemsExceptName(AppView<?> appView, IndexedItemCollection indexedItems) {
     if (indexedItems.addMethod(this)) {
-      holder.collectIndexedItems(indexedItems);
-      proto.collectIndexedItems(indexedItems);
+      holder.collectIndexedItems(appView, indexedItems);
+      proto.collectIndexedItems(appView, indexedItems);
       return true;
     }
     return false;
   }
 
-  void collectIndexedItemsName(IndexedItemCollection indexedItems) {
-    indexedItems.getRenamedName(this).collectIndexedItems(indexedItems);
+  void collectIndexedItemsName(AppView<?> appView, IndexedItemCollection indexedItems) {
+    appView.getNamingLens().lookupName(this).collectIndexedItems(indexedItems);
   }
 
   @Override
@@ -269,6 +269,10 @@
     return toSourceString(false, false);
   }
 
+  public String toSourceStringWithoutReturnType() {
+    return toSourceString(true, false);
+  }
+
   private String toSourceString(boolean includeHolder, boolean includeReturnType) {
     StringBuilder builder = new StringBuilder();
     if (includeReturnType) {
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java b/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java
index 63c3261..8859c3c 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java
@@ -254,22 +254,22 @@
     return builder.toString();
   }
 
-  public void collectIndexedItems(IndexedItemCollection indexedItems) {
+  public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
     if (indexedItems.addMethodHandle(this)) {
       if (member.isDexField()) {
         DexField field = member.asDexField();
-        field.collectIndexedItems(indexedItems);
+        field.collectIndexedItems(appView, indexedItems);
       } else {
         DexMethod method = member.asDexMethod();
         if (rewrittenTarget != null) {
           // If there is a rewritten target we need to use that to get the right name of the
           // targeted method (only member rebound methods take part in naming). The rest of the
           // indexed items are collected from method.
-          if (method.collectIndexedItemsExceptName(indexedItems)) {
-            rewrittenTarget.collectIndexedItemsName(indexedItems);
+          if (method.collectIndexedItemsExceptName(appView, indexedItems)) {
+            rewrittenTarget.collectIndexedItemsName(appView, indexedItems);
           }
         } else {
-          method.collectIndexedItems(indexedItems);
+          method.collectIndexedItems(appView, indexedItems);
         }
       }
     }
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index 5e30d52..46bebdc 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -401,30 +401,30 @@
   }
 
   public void collectIndexedItems(
-      IndexedItemCollection indexedItems, GraphLens graphLens, LensCodeRewriterUtils rewriter) {
+      AppView<?> appView, IndexedItemCollection indexedItems, LensCodeRewriterUtils rewriter) {
     if (indexedItems.addClass(this)) {
-      type.collectIndexedItems(indexedItems);
+      type.collectIndexedItems(appView, indexedItems);
       if (superType != null) {
-        superType.collectIndexedItems(indexedItems);
+        superType.collectIndexedItems(appView, indexedItems);
       } else {
         assert type.toDescriptorString().equals("Ljava/lang/Object;");
       }
       if (sourceFile != null) {
         sourceFile.collectIndexedItems(indexedItems);
       }
-      annotations().collectIndexedItems(indexedItems);
+      annotations().collectIndexedItems(appView, indexedItems);
       if (interfaces != null) {
-        interfaces.collectIndexedItems(indexedItems);
+        interfaces.collectIndexedItems(appView, indexedItems);
       }
       if (getEnclosingMethodAttribute() != null) {
-        getEnclosingMethodAttribute().collectIndexedItems(indexedItems);
+        getEnclosingMethodAttribute().collectIndexedItems(appView, indexedItems);
       }
       for (InnerClassAttribute attribute : getInnerClasses()) {
-        attribute.collectIndexedItems(indexedItems);
+        attribute.collectIndexedItems(appView, indexedItems);
       }
       // We are explicitly not adding items referenced in signatures.
-      forEachProgramField(field -> field.collectIndexedItems(indexedItems));
-      forEachProgramMethod(method -> method.collectIndexedItems(indexedItems, graphLens, rewriter));
+      forEachProgramField(field -> field.collectIndexedItems(appView, indexedItems));
+      forEachProgramMethod(method -> method.collectIndexedItems(appView, indexedItems, rewriter));
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/graph/DexProto.java b/src/main/java/com/android/tools/r8/graph/DexProto.java
index 990eccc..80ff41d 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProto.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProto.java
@@ -96,11 +96,11 @@
     return "Proto " + shorty + " " + returnType + " " + parameters;
   }
 
-  public void collectIndexedItems(IndexedItemCollection indexedItems) {
+  public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
     if (indexedItems.addProto(this)) {
       shorty.collectIndexedItems(indexedItems);
-      returnType.collectIndexedItems(indexedItems);
-      parameters.collectIndexedItems(indexedItems);
+      returnType.collectIndexedItems(appView, indexedItems);
+      parameters.collectIndexedItems(appView, indexedItems);
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/graph/DexReference.java b/src/main/java/com/android/tools/r8/graph/DexReference.java
index e813d7c..6956170 100644
--- a/src/main/java/com/android/tools/r8/graph/DexReference.java
+++ b/src/main/java/com/android/tools/r8/graph/DexReference.java
@@ -45,7 +45,7 @@
     throw new Unreachable();
   }
 
-  public abstract void collectIndexedItems(IndexedItemCollection indexedItems);
+  public abstract void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems);
 
   public abstract int compareTo(DexReference other);
 
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java
index 8a60b81..df11e7e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -238,9 +238,9 @@
   }
 
   @Override
-  public void collectIndexedItems(IndexedItemCollection collection) {
+  public void collectIndexedItems(AppView<?> appView, IndexedItemCollection collection) {
     if (collection.addType(this)) {
-      collection.getRenamedDescriptor(this).collectIndexedItems(collection);
+      appView.getNamingLens().lookupDescriptor(this).collectIndexedItems(collection);
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/graph/DexTypeList.java b/src/main/java/com/android/tools/r8/graph/DexTypeList.java
index f07c38e..afba589 100644
--- a/src/main/java/com/android/tools/r8/graph/DexTypeList.java
+++ b/src/main/java/com/android/tools/r8/graph/DexTypeList.java
@@ -109,9 +109,9 @@
     return Arrays.hashCode(values);
   }
 
-  void collectIndexedItems(IndexedItemCollection indexedItems) {
+  void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
     for (DexType type : values) {
-      type.collectIndexedItems(indexedItems);
+      type.collectIndexedItems(appView, indexedItems);
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/graph/DexValue.java b/src/main/java/com/android/tools/r8/graph/DexValue.java
index 52a57bf..2cb6abd 100644
--- a/src/main/java/com/android/tools/r8/graph/DexValue.java
+++ b/src/main/java/com/android/tools/r8/graph/DexValue.java
@@ -350,7 +350,7 @@
     dest.putByte((byte) ((arg << 5) | kind.toByte()));
   }
 
-  public void collectIndexedItems(IndexedItemCollection indexedItems) {
+  public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
     // Intentionally left empty
   }
 
@@ -1218,7 +1218,7 @@
     }
 
     @Override
-    public void collectIndexedItems(IndexedItemCollection indexedItems) {
+    public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
       value.collectIndexedItems(indexedItems);
     }
 
@@ -1305,8 +1305,8 @@
     }
 
     @Override
-    public void collectIndexedItems(IndexedItemCollection indexedItems) {
-      value.collectIndexedItems(indexedItems);
+    public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
+      value.collectIndexedItems(appView, indexedItems);
     }
 
     public NameComputationInfo<?> getNameComputationInfo() {
@@ -1384,8 +1384,8 @@
     }
 
     @Override
-    public void collectIndexedItems(IndexedItemCollection indexedItems) {
-      value.collectIndexedItems(indexedItems);
+    public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
+      value.collectIndexedItems(appView, indexedItems);
     }
 
     @Override
@@ -1426,8 +1426,8 @@
     }
 
     @Override
-    public void collectIndexedItems(IndexedItemCollection indexedItems) {
-      value.collectIndexedItems(indexedItems);
+    public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
+      value.collectIndexedItems(appView, indexedItems);
     }
 
     @Override
@@ -1468,8 +1468,8 @@
     }
 
     @Override
-    public void collectIndexedItems(IndexedItemCollection indexedItems) {
-      value.collectIndexedItems(indexedItems);
+    public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
+      value.collectIndexedItems(appView, indexedItems);
     }
 
     @Override
@@ -1510,8 +1510,8 @@
     }
 
     @Override
-    public void collectIndexedItems(IndexedItemCollection indexedItems) {
-      value.collectIndexedItems(indexedItems);
+    public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
+      value.collectIndexedItems(appView, indexedItems);
     }
 
     @Override
@@ -1562,8 +1562,8 @@
     }
 
     @Override
-    public void collectIndexedItems(IndexedItemCollection indexedItems) {
-      value.collectIndexedItems(indexedItems);
+    public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
+      value.collectIndexedItems(appView, indexedItems);
     }
 
     @Override
@@ -1606,9 +1606,9 @@
     }
 
     @Override
-    public void collectIndexedItems(IndexedItemCollection indexedItems) {
+    public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
       for (DexValue value : values) {
-        value.collectIndexedItems(indexedItems);
+        value.collectIndexedItems(appView, indexedItems);
       }
     }
 
@@ -1719,8 +1719,8 @@
     }
 
     @Override
-    public void collectIndexedItems(IndexedItemCollection indexedItems) {
-      value.collectIndexedItems(indexedItems);
+    public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
+      value.collectIndexedItems(appView, indexedItems);
     }
 
     @Override
@@ -1994,8 +1994,8 @@
     }
 
     @Override
-    public void collectIndexedItems(IndexedItemCollection indexedItems) {
-      value.collectIndexedItems(indexedItems);
+    public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
+      value.collectIndexedItems(appView, indexedItems);
     }
 
     @Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexWritableCode.java b/src/main/java/com/android/tools/r8/graph/DexWritableCode.java
index ef6bd3b..1458f08 100644
--- a/src/main/java/com/android/tools/r8/graph/DexWritableCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexWritableCode.java
@@ -54,9 +54,9 @@
   int codeSizeInBytes();
 
   void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter);
 
   void collectMixedSectionItems(MixedSectionCollection mixedItems);
diff --git a/src/main/java/com/android/tools/r8/graph/EnclosingMethodAttribute.java b/src/main/java/com/android/tools/r8/graph/EnclosingMethodAttribute.java
index d2ea75e..4062f96 100644
--- a/src/main/java/com/android/tools/r8/graph/EnclosingMethodAttribute.java
+++ b/src/main/java/com/android/tools/r8/graph/EnclosingMethodAttribute.java
@@ -81,12 +81,12 @@
         enclosingMethod == ((EnclosingMethodAttribute) obj).enclosingMethod;
   }
 
-  public void collectIndexedItems(IndexedItemCollection indexedItems) {
+  public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
     if (enclosingClass != null) {
-      enclosingClass.collectIndexedItems(indexedItems);
+      enclosingClass.collectIndexedItems(appView, indexedItems);
     }
     if (enclosingMethod != null) {
-      enclosingMethod.collectIndexedItems(indexedItems);
+      enclosingMethod.collectIndexedItems(appView, indexedItems);
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/graph/FieldResolution.java b/src/main/java/com/android/tools/r8/graph/FieldResolution.java
index 3dcd872..ce7cbd3 100644
--- a/src/main/java/com/android/tools/r8/graph/FieldResolution.java
+++ b/src/main/java/com/android/tools/r8/graph/FieldResolution.java
@@ -28,35 +28,40 @@
     definitionFor
         .contextIndependentDefinitionForWithResolutionResult(type)
         .forEachClassResolutionResult(
-            clazz -> builder.addResolutionResult(resolveFieldOn(clazz, field)));
+            clazz -> resolveFieldOn(clazz, field, clazz, SetUtils.newIdentityHashSet(8), builder));
     return builder.buildOrIfEmpty(FieldResolutionResult.failure());
   }
 
   public FieldResolutionResult resolveFieldOn(DexClass holder, DexField field) {
     assert holder != null;
-    return resolveFieldOn(holder, field, holder, SetUtils.newIdentityHashSet(8));
+    FieldResolutionResult.Builder builder = FieldResolutionResult.builder();
+    resolveFieldOn(holder, field, holder, SetUtils.newIdentityHashSet(8), builder);
+    return builder.buildOrIfEmpty(FieldResolutionResult.failure());
   }
 
-  private FieldResolutionResult resolveFieldOn(
+  private void resolveFieldOn(
       DexClass holder,
       DexField field,
       DexClass initialResolutionHolder,
-      Set<DexType> visitedInterfaces) {
+      Set<DexType> visitedInterfaces,
+      FieldResolutionResult.Builder builder) {
     assert holder != null;
     // Step 1: Class declares the field.
     DexEncodedField definition = holder.lookupField(field);
     if (definition != null) {
-      return createSingleFieldResolutionResult(initialResolutionHolder, holder, definition);
+      builder.addResolutionResult(
+          createSingleFieldResolutionResult(initialResolutionHolder, holder, definition));
+      return;
     }
     // Step 2: Apply recursively to direct superinterfaces. First match succeeds.
     FieldResolutionResult result =
         resolveFieldOnDirectInterfaces(initialResolutionHolder, holder, field, visitedInterfaces);
     if (result != null) {
-      return result;
+      builder.addResolutionResult(result);
+      return;
     }
     // Step 3: Apply recursively to superclass.
     if (holder.superType != null) {
-      FieldResolutionResult.Builder builder = FieldResolutionResult.builder();
       definitionFor
           .contextIndependentDefinitionForWithResolutionResult(holder.superType)
           .forEachClassResolutionResult(
@@ -66,12 +71,12 @@
                 if (holder.isLibraryClass() && !superClass.isLibraryClass()) {
                   return;
                 }
-                builder.addResolutionResult(
-                    resolveFieldOn(superClass, field, initialResolutionHolder, visitedInterfaces));
+                resolveFieldOn(
+                    superClass, field, initialResolutionHolder, visitedInterfaces, builder);
               });
-      return builder.buildOrIfEmpty(null);
+    } else {
+      builder.addResolutionResult(FieldResolutionResult.failure());
     }
-    return FieldResolutionResult.failure();
   }
 
   private FieldResolutionResult resolveFieldOnDirectInterfaces(
@@ -91,9 +96,12 @@
                   if (clazz.isLibraryClass() && !ifaceClass.isLibraryClass()) {
                     return;
                   }
-                  builder.addResolutionResult(
+                  FieldResolutionResult otherResult =
                       resolveFieldOnInterface(
-                          initialResolutionHolder, ifaceClass, field, visitedInterfaces));
+                          initialResolutionHolder, ifaceClass, field, visitedInterfaces);
+                  if (otherResult != null) {
+                    builder.addResolutionResult(otherResult);
+                  }
                 });
         FieldResolutionResult fieldResolutionResult = builder.buildOrIfEmpty(null);
         if (fieldResolutionResult != null) {
diff --git a/src/main/java/com/android/tools/r8/graph/FieldResolutionResult.java b/src/main/java/com/android/tools/r8/graph/FieldResolutionResult.java
index 029b8e4..196864a 100644
--- a/src/main/java/com/android/tools/r8/graph/FieldResolutionResult.java
+++ b/src/main/java/com/android/tools/r8/graph/FieldResolutionResult.java
@@ -504,6 +504,7 @@
     private Builder() {}
 
     public void addResolutionResult(FieldResolutionResult otherResult) {
+      assert otherResult != null;
       if (currentResult == null) {
         currentResult = otherResult;
         return;
diff --git a/src/main/java/com/android/tools/r8/graph/InnerClassAttribute.java b/src/main/java/com/android/tools/r8/graph/InnerClassAttribute.java
index bb0fbf8..d2f5628 100644
--- a/src/main/java/com/android/tools/r8/graph/InnerClassAttribute.java
+++ b/src/main/java/com/android/tools/r8/graph/InnerClassAttribute.java
@@ -87,10 +87,10 @@
         access);
   }
 
-  public void collectIndexedItems(IndexedItemCollection indexedItems) {
-    inner.collectIndexedItems(indexedItems);
+  public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
+    inner.collectIndexedItems(appView, indexedItems);
     if (outer != null) {
-      outer.collectIndexedItems(indexedItems);
+      outer.collectIndexedItems(appView, indexedItems);
     }
     if (innerName != null) {
       innerName.collectIndexedItems(indexedItems);
diff --git a/src/main/java/com/android/tools/r8/graph/MethodResolution.java b/src/main/java/com/android/tools/r8/graph/MethodResolution.java
index 983c69e..f7271b7 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodResolution.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodResolution.java
@@ -658,8 +658,13 @@
         // as a target. For deterministic resolution, we return the first mapped method (of the
         // linked map).
         if (nonAbstractOnComplete.isEmpty()) {
-          return singleResultHelper(
-              initialResolutionHolder, firstNonNullEntry(maximallySpecificMethodsOnCompletePaths));
+          Entry<DexClass, DexEncodedMethod> abstractMethod =
+              firstNonNullEntry(maximallySpecificMethodsOnCompletePaths);
+          if (abstractMethod == null) {
+            abstractMethod = firstNonNullEntry(maximallySpecificMethodsOnIncompletePaths);
+          }
+          assert abstractMethod != null && abstractMethod.getValue().isAbstract();
+          return singleResultHelper(initialResolutionHolder, abstractMethod);
         } else {
           // If there is exactly one non-abstract method (a default method) it is the resolution
           // target.
@@ -717,7 +722,6 @@
           return entry;
         }
       }
-      assert false : "Should not be called on a collection without any non-null candidates";
       return null;
     }
   }
diff --git a/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java b/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java
index 3d987c1..6173bef 100644
--- a/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java
+++ b/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java
@@ -18,17 +18,16 @@
 import it.unimi.dsi.fastutil.objects.Reference2IntMap.Entry;
 import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 import java.util.function.Consumer;
-import java.util.stream.Collectors;
 
 public class ObjectToOffsetMapping {
 
   private final static int NOT_FOUND = -1;
-  private final static int NOT_SET = -2;
 
   private final int lazyDexStringsCount;
   private final AppView<?> appView;
@@ -54,7 +53,6 @@
 
   public ObjectToOffsetMapping(
       AppView<?> appView,
-      NamingLens namingLens,
       LensCodeRewriterUtils lensCodeRewriter,
       Collection<DexProgramClass> classes,
       Collection<DexProto> protos,
@@ -78,7 +76,7 @@
     this.lazyDexStringsCount = lazyDexStringsCount;
     this.appView = appView;
     this.graphLens = appView.graphLens();
-    this.namingLens = namingLens;
+    this.namingLens = appView.getNamingLens();
     this.initClassLens = appView.initClassLens();
     this.lensCodeRewriter = lensCodeRewriter;
     timing.begin("Sort strings");
@@ -94,7 +92,7 @@
         new CompareToVisitorWithTypeTable(namingLens, this.strings::getInt, this.types::getInt);
     timing.end();
     timing.begin("Sort classes");
-    this.classes = sortClasses(appView.appInfo(), classes, namingLens);
+    this.classes = sortClasses(classes, visitor);
     timing.end();
     timing.begin("Sort protos");
     this.protos = createSortedMap(protos, compare(visitor), this::failOnOverflow);
@@ -241,20 +239,19 @@
     }
   }
 
-  private static DexProgramClass[] sortClasses(
-      AppInfo appInfo, Collection<DexProgramClass> classes, NamingLens namingLens) {
+  private DexProgramClass[] sortClasses(
+      Collection<DexProgramClass> classes, CompareToVisitor visitor) {
     // Collect classes in subtyping order, based on a sorted list of classes to start with.
-    ProgramClassDepthsMemoized classDepths = new ProgramClassDepthsMemoized(appInfo);
-    List<DexProgramClass> sortedClasses =
-        classes.stream()
-            .sorted(
-                (x, y) -> {
-                  int dx = classDepths.getDepth(x);
-                  int dy = classDepths.getDepth(y);
-                  return dx != dy ? dx - dy : x.type.compareToWithNamingLens(y.type, namingLens);
-                })
-            .collect(Collectors.toList());
-    return sortedClasses.toArray(DexProgramClass.EMPTY_ARRAY);
+    ProgramClassDepthsMemoized classDepths = new ProgramClassDepthsMemoized(appView.appInfo());
+    DexProgramClass[] sortedClasses = classes.toArray(DexProgramClass.EMPTY_ARRAY);
+    Arrays.sort(
+        sortedClasses,
+        (x, y) -> {
+          int dx = classDepths.getDepth(x);
+          int dy = classDepths.getDepth(y);
+          return dx != dy ? dx - dy : visitor.visitDexType(x.type, y.type);
+        });
+    return sortedClasses;
   }
 
   private static <T> Collection<T> keysOrEmpty(Reference2IntLinkedOpenHashMap<T> map) {
@@ -329,7 +326,6 @@
 
   private <T extends IndexedDexItem> int getOffsetFor(T item, Reference2IntMap<T> map) {
     int index = map.getInt(item);
-    assert index != NOT_SET : "Index was not set: " + item;
     assert index != NOT_FOUND : "Missing dependency: " + item;
     return index;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/ParameterAnnotationsList.java b/src/main/java/com/android/tools/r8/graph/ParameterAnnotationsList.java
index fdda61b..5f7c865 100644
--- a/src/main/java/com/android/tools/r8/graph/ParameterAnnotationsList.java
+++ b/src/main/java/com/android/tools/r8/graph/ParameterAnnotationsList.java
@@ -119,9 +119,9 @@
     return false;
   }
 
-  public void collectIndexedItems(IndexedItemCollection indexedItems) {
+  public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
     for (DexAnnotationSet value : values) {
-      value.collectIndexedItems(indexedItems);
+      value.collectIndexedItems(appView, indexedItems);
     }
   }
 
@@ -132,6 +132,10 @@
     mixedItems.add(this);
   }
 
+  public DexAnnotationSet[] getAnnotationSets() {
+    return values;
+  }
+
   public boolean isEmpty() {
     return values.length == 0;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramClassVisitor.java b/src/main/java/com/android/tools/r8/graph/ProgramClassVisitor.java
index 3414037..06d0943 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramClassVisitor.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramClassVisitor.java
@@ -3,17 +3,17 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.graph;
 
-import java.util.HashSet;
+import com.google.common.collect.Sets;
 import java.util.Set;
 
 /**
  * Implements traversal of the class hierarchy in topological order. A class is visited after its
- * super class and its interfaces are visited. Only visits program classes and does NOT visit 
+ * super class and its interfaces are visited. Only visits program classes and does NOT visit
  * classpath, nor library classes.
  *
- * NOTE: The visiting is processed by traversing program classes only, which means that
- * in presence of classpath it is NOT guaranteed that class C is visited before class D
- * if there exists a classpath class X in class hierarchy between C and D, like:
+ * <p>NOTE: The visiting is processed by traversing program classes only, which means that in
+ * presence of classpath it is NOT guaranteed that class C is visited before class D if there exists
+ * a classpath class X in class hierarchy between C and D, like:
  *
  * <pre>
  *   class ProgramClassS {}
@@ -21,29 +21,24 @@
  *   class ProgramClassD extends ClasspathClassX {}
  * </pre>
  *
- * The above consideration does not apply to library classes, since we assume library
- * classes never extend or implement program/classpath class.
+ * The above consideration does not apply to library classes, since we assume library classes never
+ * extend or implement program/classpath class.
  */
 public abstract class ProgramClassVisitor {
 
-  final DexApplication application;
-  private final Set<DexItem> visited = new HashSet<>();
+  final AppView<?> appView;
 
-  protected ProgramClassVisitor(DexApplication application) {
-    this.application = application;
+  private final Set<DexProgramClass> visited = Sets.newIdentityHashSet();
+
+  protected ProgramClassVisitor(AppView<?> appView) {
+    this.appView = appView;
   }
 
   private void accept(DexType type) {
-    if (type == null || visited.contains(type)) {
-      return;
-    }
-    DexClass clazz = application.programDefinitionFor(type);
+    DexProgramClass clazz = appView.app().programDefinitionFor(type);
     if (clazz != null) {
       accept(clazz);
-      return;
     }
-    visit(type);
-    visited.add(type);
   }
 
   private void accept(DexTypeList types) {
@@ -52,14 +47,14 @@
     }
   }
 
-  private void accept(DexClass clazz) {
-    if (visited.contains(clazz)) {
-      return;
+  private void accept(DexProgramClass clazz) {
+    if (visited.add(clazz)) {
+      if (clazz.hasSuperType()) {
+        accept(clazz.getSuperType());
+      }
+      accept(clazz.getInterfaces());
+      visit(clazz);
     }
-    accept(clazz.superType);
-    accept(clazz.interfaces);
-    visit(clazz);
-    visited.add(clazz);
   }
 
   public void run(DexProgramClass[] classes) {
@@ -68,24 +63,6 @@
     }
   }
 
-  public void run(Iterable<DexProgramClass> classes) {
-    for (DexProgramClass clazz : classes) {
-      accept(clazz);
-    }
-  }
-
-  public void run() {
-    run(application.classes());
-  }
-
-  /**
-   * Called for each library class used in the class hierarchy. A library class is a class that is
-   * not present in the application.
-   */
-  public abstract void visit(DexType type);
-
-  /**
-   * Called for each class defined in the application.
-   */
-  public abstract void visit(DexClass clazz);
+  /** Called for each class defined in the application. */
+  public abstract void visit(DexProgramClass clazz);
 }
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramDexCode.java b/src/main/java/com/android/tools/r8/graph/ProgramDexCode.java
deleted file mode 100644
index 4e15eac..0000000
--- a/src/main/java/com/android/tools/r8/graph/ProgramDexCode.java
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) 2020, 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.graph;
-
-public class ProgramDexCode {
-
-  private final DexWritableCode code;
-  private final ProgramMethod method;
-
-  public ProgramDexCode(DexWritableCode code, ProgramMethod method) {
-    this.code = code;
-    this.method = method;
-  }
-
-  public DexWritableCode getCode() {
-    return code;
-  }
-
-  public ProgramMethod getMethod() {
-    return method;
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramField.java b/src/main/java/com/android/tools/r8/graph/ProgramField.java
index 0007521..85146d6 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramField.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramField.java
@@ -14,12 +14,12 @@
     super(holder, field);
   }
 
-  public void collectIndexedItems(IndexedItemCollection indexedItems) {
-    getReference().collectIndexedItems(indexedItems);
+  public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
+    getReference().collectIndexedItems(appView, indexedItems);
     DexEncodedField definition = getDefinition();
-    definition.annotations().collectIndexedItems(indexedItems);
+    definition.annotations().collectIndexedItems(appView, indexedItems);
     if (definition.isStatic() && definition.hasExplicitStaticValue()) {
-      definition.getStaticValue().collectIndexedItems(indexedItems);
+      definition.getStaticValue().collectIndexedItems(appView, indexedItems);
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
index 37d165b..7980af2 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
@@ -65,16 +65,16 @@
   }
 
   public void collectIndexedItems(
-      IndexedItemCollection indexedItems, GraphLens graphLens, LensCodeRewriterUtils rewriter) {
+      AppView<?> appView, IndexedItemCollection indexedItems, LensCodeRewriterUtils rewriter) {
     DexEncodedMethod definition = getDefinition();
     assert !definition.isObsolete();
-    getReference().collectIndexedItems(indexedItems);
+    getReference().collectIndexedItems(appView, indexedItems);
     if (definition.hasCode()) {
       Code code = definition.getCode();
-      code.asDexWritableCode().collectIndexedItems(indexedItems, this, graphLens, rewriter);
+      code.asDexWritableCode().collectIndexedItems(appView, indexedItems, this, rewriter);
     }
-    definition.annotations().collectIndexedItems(indexedItems);
-    definition.parameterAnnotationsList.collectIndexedItems(indexedItems);
+    definition.annotations().collectIndexedItems(appView, indexedItems);
+    definition.parameterAnnotationsList.collectIndexedItems(appView, indexedItems);
   }
 
   public boolean canBeConvertedToAbstractMethod(AppView<AppInfoWithLiveness> appView) {
diff --git a/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java b/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java
index 55e6f8c..789bb19 100644
--- a/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java
+++ b/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java
@@ -4,12 +4,12 @@
 
 package com.android.tools.r8.graph;
 
-import com.android.tools.r8.code.InvokeDirect;
-import com.android.tools.r8.code.NewInstance;
-import com.android.tools.r8.code.Throw;
 import com.android.tools.r8.dex.CodeToKeep;
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.dex.MixedSectionCollection;
+import com.android.tools.r8.dex.code.DexInvokeDirect;
+import com.android.tools.r8.dex.code.DexNewInstance;
+import com.android.tools.r8.dex.code.DexThrow;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DexCode.Try;
 import com.android.tools.r8.graph.DexCode.TryHandler;
@@ -72,19 +72,19 @@
 
   @Override
   public int codeSizeInBytes() {
-    return NewInstance.SIZE + InvokeDirect.SIZE + Throw.SIZE;
+    return DexNewInstance.SIZE + DexInvokeDirect.SIZE + DexThrow.SIZE;
   }
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     rewriter
         .dexItemFactory()
         .createInstanceInitializer(exceptionType)
-        .collectIndexedItems(indexedItems);
+        .collectIndexedItems(appView, indexedItems);
   }
 
   @Override
@@ -216,14 +216,14 @@
     int register = 0;
     int notUsed = 0;
     int argumentCount = 1;
-    new NewInstance(register, exceptionType)
+    new DexNewInstance(register, exceptionType)
         .write(shortBuffer, context, graphLens, mapping, lensCodeRewriter);
     DexMethod instanceInitializer =
         lensCodeRewriter.dexItemFactory().createInstanceInitializer(exceptionType);
-    new InvokeDirect(
+    new DexInvokeDirect(
             argumentCount, instanceInitializer, register, notUsed, notUsed, notUsed, notUsed)
         .write(shortBuffer, context, graphLens, mapping, lensCodeRewriter);
-    new Throw(register).write(shortBuffer, context, graphLens, mapping, lensCodeRewriter);
+    new DexThrow(register).write(shortBuffer, context, graphLens, mapping, lensCodeRewriter);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java b/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java
index 5b02c12..cac6f7a 100644
--- a/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java
+++ b/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java
@@ -5,11 +5,11 @@
 package com.android.tools.r8.graph;
 
 import com.android.tools.r8.cf.CfVersion;
-import com.android.tools.r8.code.Const4;
-import com.android.tools.r8.code.Throw;
 import com.android.tools.r8.dex.CodeToKeep;
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.dex.MixedSectionCollection;
+import com.android.tools.r8.dex.code.DexConst4;
+import com.android.tools.r8.dex.code.DexThrow;
 import com.android.tools.r8.graph.DexCode.Try;
 import com.android.tools.r8.graph.DexCode.TryHandler;
 import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
@@ -81,14 +81,14 @@
 
   @Override
   public int codeSizeInBytes() {
-    return Const4.SIZE + Throw.SIZE;
+    return DexConst4.SIZE + DexThrow.SIZE;
   }
 
   @Override
   public void collectIndexedItems(
+      AppView<?> appView,
       IndexedItemCollection indexedItems,
       ProgramMethod context,
-      GraphLens graphLens,
       LensCodeRewriterUtils rewriter) {
     // Intentionally empty.
   }
@@ -251,8 +251,8 @@
       LensCodeRewriterUtils lensCodeRewriter,
       ObjectToOffsetMapping mapping) {
     int register = 0;
-    new Const4(register, 0).write(shortBuffer, context, graphLens, mapping, lensCodeRewriter);
-    new Throw(register).write(shortBuffer, context, graphLens, mapping, lensCodeRewriter);
+    new DexConst4(register, 0).write(shortBuffer, context, graphLens, mapping, lensCodeRewriter);
+    new DexThrow(register).write(shortBuffer, context, graphLens, mapping, lensCodeRewriter);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/graph/UseRegistry.java b/src/main/java/com/android/tools/r8/graph/UseRegistry.java
index 6e08e6c..0b066d6 100644
--- a/src/main/java/com/android/tools/r8/graph/UseRegistry.java
+++ b/src/main/java/com/android/tools/r8/graph/UseRegistry.java
@@ -3,9 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.graph;
 
-import com.android.tools.r8.code.CfOrDexInstanceFieldRead;
-import com.android.tools.r8.code.CfOrDexInstruction;
-import com.android.tools.r8.code.CfOrDexStaticFieldRead;
+import com.android.tools.r8.dex.code.CfOrDexInstanceFieldRead;
+import com.android.tools.r8.dex.code.CfOrDexInstruction;
+import com.android.tools.r8.dex.code.CfOrDexStaticFieldRead;
 import com.android.tools.r8.ir.code.Invoke;
 import com.android.tools.r8.utils.TraversalContinuation;
 import java.util.ListIterator;
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java
index 02b1abe..be68650 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java
@@ -131,9 +131,13 @@
     instructions.add(fallthroughLabel);
     instructions.add(createCfFrameForSwitchCase(method, maxLocals));
 
-    DexMethod fallthroughTarget =
-        lens.getNextMethodSignature(
-            superMethod != null ? superMethod : mappedMethods.get(mappedMethods.lastIntKey()));
+    DexMethod fallthroughTarget;
+    if (superMethod == null) {
+      fallthroughTarget =
+          lens.getNextMethodSignature(mappedMethods.get(mappedMethods.lastIntKey()));
+    } else {
+      fallthroughTarget = lens.lookupInvokeSuper(superMethod, method).getReference();
+    }
     instructions.add(
         new CfInvoke(Opcodes.INVOKESPECIAL, fallthroughTarget, method.getHolder().isInterface()));
 
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
index eb5b57e..70f752e 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
@@ -12,6 +12,7 @@
 import com.android.tools.r8.horizontalclassmerging.policies.AllInstantiatedOrUninstantiated;
 import com.android.tools.r8.horizontalclassmerging.policies.CheckAbstractClasses;
 import com.android.tools.r8.horizontalclassmerging.policies.CheckSyntheticClasses;
+import com.android.tools.r8.horizontalclassmerging.policies.ComputeApiLevelOfSyntheticClass;
 import com.android.tools.r8.horizontalclassmerging.policies.FinalizeMergeGroup;
 import com.android.tools.r8.horizontalclassmerging.policies.LimitClassGroups;
 import com.android.tools.r8.horizontalclassmerging.policies.LimitInterfaceGroups;
@@ -137,7 +138,8 @@
     ImmutableList.Builder<SingleClassPolicy> builder =
         ImmutableList.<SingleClassPolicy>builder()
             .add(new CheckSyntheticClasses(appView))
-            .add(new OnlyClassesWithStaticDefinitionsAndNoClassInitializer());
+            .add(new OnlyClassesWithStaticDefinitionsAndNoClassInitializer())
+            .add(new ComputeApiLevelOfSyntheticClass(appView));
     assert verifySingleClassPoliciesIrrelevantForMergingSyntheticsInD8(appView, mode, builder);
     return builder.build();
   }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/ComputeApiLevelOfSyntheticClass.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/ComputeApiLevelOfSyntheticClass.java
new file mode 100644
index 0000000..3568c17
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/ComputeApiLevelOfSyntheticClass.java
@@ -0,0 +1,207 @@
+// 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.horizontalclassmerging.policies;
+
+import com.android.tools.r8.androidapi.AndroidApiLevelCompute;
+import com.android.tools.r8.androidapi.ComputedApiLevel;
+import com.android.tools.r8.dex.code.CfOrDexInstruction;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexCallSite;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexMethodHandle;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexReference;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.horizontalclassmerging.SingleClassPolicy;
+import com.android.tools.r8.synthesis.SyntheticItems;
+import java.util.ListIterator;
+
+public class ComputeApiLevelOfSyntheticClass extends SingleClassPolicy {
+
+  private final AppView<?> appView;
+  private final SyntheticItems syntheticItems;
+
+  public ComputeApiLevelOfSyntheticClass(AppView<?> appView) {
+    this.appView = appView;
+    this.syntheticItems = appView.getSyntheticItems();
+  }
+
+  @Override
+  public boolean canMerge(DexProgramClass clazz) {
+    assert syntheticItems.isSyntheticClass(clazz);
+    clazz.forEachProgramMethod(
+        programMethod -> {
+          DexEncodedMethod definition = programMethod.getDefinition();
+          if (definition.getApiLevelForCode().isNotSetApiLevel()) {
+            ComputeApiLevelUseRegistry computeApiLevel =
+                new ComputeApiLevelUseRegistry(appView, programMethod, appView.apiLevelCompute());
+            computeApiLevel.accept(programMethod);
+            ComputedApiLevel maxApiReferenceLevel = computeApiLevel.getMaxApiReferenceLevel();
+            assert !maxApiReferenceLevel.isNotSetApiLevel();
+            definition.setApiLevelForCode(maxApiReferenceLevel);
+            definition.setApiLevelForDefinition(computeApiLevel.getMaxApiReferenceLevel());
+          }
+        });
+    return true;
+  }
+
+  @Override
+  public String getName() {
+    return "ComputeApiLevelOfSyntheticClass";
+  }
+
+  private static class ComputeApiLevelUseRegistry extends UseRegistry<ProgramMethod> {
+
+    private final AppView<?> appView;
+    private final AndroidApiLevelCompute apiLevelCompute;
+    private ComputedApiLevel maxApiReferenceLevel;
+
+    public ComputeApiLevelUseRegistry(
+        AppView<?> appView, ProgramMethod context, AndroidApiLevelCompute apiLevelCompute) {
+      super(appView, context);
+      this.appView = appView;
+      this.apiLevelCompute = apiLevelCompute;
+      maxApiReferenceLevel = appView.computedMinApiLevel();
+    }
+
+    @Override
+    public void registerInitClass(DexType clazz) {
+      assert false : "Unexpected call to an instruction that should not exist on DEX";
+    }
+
+    @Override
+    public void registerRecordFieldValues(DexField[] fields) {
+      assert false : "Unexpected call to an instruction that should not exist on DEX";
+    }
+
+    @Override
+    public void registerInvokeVirtual(DexMethod invokedMethod) {
+      setMaxApiReferenceLevel(invokedMethod);
+    }
+
+    @Override
+    public void registerInvokeDirect(DexMethod invokedMethod) {
+      setMaxApiReferenceLevel(invokedMethod);
+    }
+
+    @Override
+    public void registerInvokeStatic(DexMethod invokedMethod) {
+      setMaxApiReferenceLevel(invokedMethod);
+    }
+
+    @Override
+    public void registerInvokeInterface(DexMethod invokedMethod) {
+      setMaxApiReferenceLevel(invokedMethod);
+    }
+
+    @Override
+    public void registerInvokeSuper(DexMethod invokedMethod) {
+      setMaxApiReferenceLevel(invokedMethod);
+    }
+
+    @Override
+    public void registerInstanceFieldRead(DexField field) {
+      setMaxApiReferenceLevel(field);
+    }
+
+    @Override
+    public void registerInstanceFieldReadFromMethodHandle(DexField field) {
+      setMaxApiReferenceLevel(field);
+    }
+
+    @Override
+    public void registerInstanceFieldWrite(DexField field) {
+      setMaxApiReferenceLevel(field);
+    }
+
+    @Override
+    public void registerInstanceFieldWriteFromMethodHandle(DexField field) {
+      setMaxApiReferenceLevel(field);
+    }
+
+    @Override
+    public void registerNewInstance(DexType type) {
+      setMaxApiReferenceLevel(type);
+    }
+
+    @Override
+    public void registerStaticFieldRead(DexField field) {
+      setMaxApiReferenceLevel(field);
+    }
+
+    @Override
+    public void registerStaticFieldReadFromMethodHandle(DexField field) {
+      setMaxApiReferenceLevel(field);
+    }
+
+    @Override
+    public void registerStaticFieldWrite(DexField field) {
+      setMaxApiReferenceLevel(field);
+    }
+
+    @Override
+    public void registerStaticFieldWriteFromMethodHandle(DexField field) {
+      setMaxApiReferenceLevel(field);
+    }
+
+    @Override
+    public void registerConstClass(
+        DexType type,
+        ListIterator<? extends CfOrDexInstruction> iterator,
+        boolean ignoreCompatRules) {
+      // Intentionally empty.
+    }
+
+    @Override
+    public void registerCheckCast(DexType type, boolean ignoreCompatRules) {
+      // Intentionally empty.
+    }
+
+    @Override
+    public void registerSafeCheckCast(DexType type) {
+      // Intentionally empty.
+    }
+
+    @Override
+    public void registerTypeReference(DexType type) {
+      // Intentionally empty.
+    }
+
+    @Override
+    public void registerInstanceOf(DexType type) {
+      // Intentionally empty.
+    }
+
+    @Override
+    public void registerExceptionGuard(DexType guard) {
+      setMaxApiReferenceLevel(guard);
+    }
+
+    @Override
+    public void registerMethodHandle(DexMethodHandle methodHandle, MethodHandleUse use) {
+      assert false : "Unexpected call to an instruction that should not exist on DEX";
+    }
+
+    @Override
+    public void registerCallSite(DexCallSite callSite) {
+      assert false : "Unexpected call to an instruction that should not exist on DEX";
+    }
+
+    private void setMaxApiReferenceLevel(DexReference reference) {
+      maxApiReferenceLevel =
+          maxApiReferenceLevel.max(
+              apiLevelCompute.computeApiLevelForLibraryReference(
+                  reference, apiLevelCompute.getPlatformApiLevelOrUnknown(appView)));
+    }
+
+    public ComputedApiLevel getMaxApiReferenceLevel() {
+      return maxApiReferenceLevel;
+    }
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassInitializerCycles.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassInitializerCycles.java
index 0b2c884..744154c 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassInitializerCycles.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassInitializerCycles.java
@@ -9,7 +9,7 @@
 import static com.android.tools.r8.ir.desugar.LambdaDescriptor.isLambdaMetafactoryMethod;
 import static com.android.tools.r8.utils.MapUtils.ignoreKey;
 
-import com.android.tools.r8.code.CfOrDexInstruction;
+import com.android.tools.r8.dex.code.CfOrDexInstruction;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexCallSite;
 import com.android.tools.r8.graph.DexClassAndMethod;
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDefaultInterfaceMethodMerging.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDefaultInterfaceMethodMerging.java
index ac73202..043bd34 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDefaultInterfaceMethodMerging.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDefaultInterfaceMethodMerging.java
@@ -6,18 +6,21 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexMethodSignature;
 import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.horizontalclassmerging.HorizontalClassMerger.Mode;
 import com.android.tools.r8.horizontalclassmerging.MergeGroup;
 import com.android.tools.r8.horizontalclassmerging.MultiClassPolicy;
-import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.ListUtils;
+import com.android.tools.r8.utils.WorkList;
+import com.android.tools.r8.utils.collections.DexMethodSignatureMap;
 import com.android.tools.r8.utils.collections.DexMethodSignatureSet;
 import com.google.common.collect.Lists;
 import java.util.Collection;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.function.Function;
 
 /**
  * For interfaces, we cannot introduce an instance field `int $r8$classId`. Therefore, we can't
@@ -29,42 +32,61 @@
  */
 public class NoDefaultInterfaceMethodMerging extends MultiClassPolicy {
 
-  private final Mode mode;
-  private final InternalOptions options;
+  private final AppView<?> appView;
+  private final DexType MULTIPLE_SENTINEL;
 
   public NoDefaultInterfaceMethodMerging(AppView<?> appView, Mode mode) {
-    this.mode = mode;
-    this.options = appView.options();
+    this.appView = appView;
+    // Use the java.lang.Object type to indicate more than one interface type, as that type
+    // itself is not an interface type.
+    this.MULTIPLE_SENTINEL = appView.dexItemFactory().objectType;
   }
 
   @Override
   public Collection<MergeGroup> apply(MergeGroup group) {
-    if (!group.isInterfaceGroup()) {
-      return ListUtils.newLinkedList(group);
-    }
-
     // Split the group into smaller groups such that no default methods collide.
-    Map<MergeGroup, DexMethodSignatureSet> newGroups = new LinkedHashMap<>();
+    // TODO(b/229951607): This fixes the ICCE issue for synthetic lambda classes, but a more
+    //  general solution possibly extending the policy NoDefaultInterfaceMethodCollisions.
+    Map<MergeGroup, DexMethodSignatureMap<DexType>> newGroups = new LinkedHashMap<>();
     for (DexProgramClass clazz : group) {
-      addClassToGroup(clazz, newGroups);
+      addClassToGroup(
+          clazz,
+          newGroups,
+          group.isInterfaceGroup()
+              ? this::collectDefaultMethodsInInterfaces
+              : this::collectDefaultMethodsInImplementedInterfaces);
     }
 
     return removeTrivialGroups(Lists.newLinkedList(newGroups.keySet()));
   }
 
   private void addClassToGroup(
-      DexProgramClass clazz, Map<MergeGroup, DexMethodSignatureSet> newGroups) {
-    DexMethodSignatureSet classSignatures = DexMethodSignatureSet.create();
-    classSignatures.addAllMethods(clazz.virtualMethods(DexEncodedMethod::isDefaultMethod));
+      DexProgramClass clazz,
+      Map<MergeGroup, DexMethodSignatureMap<DexType>> newGroups,
+      Function<DexProgramClass, DexMethodSignatureMap<DexType>> fn) {
+    DexMethodSignatureMap<DexType> classSignatures = fn.apply(clazz);
 
     // Find a group that does not have any collisions with `clazz`.
-    for (Entry<MergeGroup, DexMethodSignatureSet> entry : newGroups.entrySet()) {
+    nextGroup:
+    for (Entry<MergeGroup, DexMethodSignatureMap<DexType>> entry : newGroups.entrySet()) {
       MergeGroup group = entry.getKey();
-      DexMethodSignatureSet groupSignatures = entry.getValue();
-      if (!groupSignatures.containsAnyOf(classSignatures)) {
-        groupSignatures.addAll(classSignatures);
+      DexMethodSignatureMap<DexType> groupSignatures = entry.getValue();
+      if (!groupSignatures.containsAnyKeyOf(classSignatures.keySet())) {
+        groupSignatures.putAll(classSignatures);
         group.add(clazz);
         return;
+      } else {
+        DexMethodSignatureSet overlappingSignatures =
+            groupSignatures.intersectionWithKeys(classSignatures.keySet());
+        for (DexMethodSignature signature : overlappingSignatures) {
+          if ((groupSignatures.get(signature) != classSignatures.get(signature))
+              || (groupSignatures.get(signature) == MULTIPLE_SENTINEL)) {
+            continue nextGroup;
+          }
+          groupSignatures.putAll(classSignatures);
+          group.add(clazz);
+          return;
+        }
       }
     }
 
@@ -72,13 +94,59 @@
     newGroups.put(new MergeGroup(clazz), classSignatures);
   }
 
-  @Override
-  public String getName() {
-    return "NoDefaultInterfaceMethodMerging";
+  private void addDefaultMethods(DexMethodSignatureMap<DexType> signatures, DexProgramClass iface) {
+    // When the same signature is added from several interfaces just move to the "multiple" state
+    // and do not keep track of the actual interfaces.
+    iface.forEachProgramVirtualMethodMatching(
+        DexEncodedMethod::isDefaultMethod,
+        method ->
+            signatures.merge(
+                method.getDefinition(),
+                iface.getType(),
+                (ignoreKey, current) -> current == iface.getType() ? current : MULTIPLE_SENTINEL));
+  }
+
+  private DexMethodSignatureMap<DexType> collectDefaultMethodsInInterfaces(DexProgramClass iface) {
+    assert iface.isInterface();
+    DexMethodSignatureMap<DexType> signatures = DexMethodSignatureMap.create();
+    WorkList<DexProgramClass> workList = WorkList.newIdentityWorkList();
+    workList.addIfNotSeen(iface);
+    while (workList.hasNext()) {
+      DexProgramClass item = workList.next();
+      assert item.isInterface();
+      addDefaultMethods(signatures, item);
+      addInterfacesToWorklist(item, workList);
+    }
+    return signatures;
+  }
+
+  // TODO(b/229951607): This only adresses the ICCE issue for synthetic lambda classes.
+  private DexMethodSignatureMap<DexType> collectDefaultMethodsInImplementedInterfaces(
+      DexProgramClass clazz) {
+    assert !clazz.isInterface();
+    DexMethodSignatureMap<DexType> signatures = DexMethodSignatureMap.create();
+    WorkList<DexProgramClass> workList = WorkList.newIdentityWorkList();
+    addInterfacesToWorklist(clazz, workList);
+    while (workList.hasNext()) {
+      DexProgramClass item = workList.next();
+      assert item.isInterface();
+      addDefaultMethods(signatures, item);
+      addInterfacesToWorklist(item, workList);
+    }
+    return signatures;
+  }
+
+  private void addInterfacesToWorklist(DexProgramClass clazz, WorkList<DexProgramClass> worklist) {
+    for (DexType iface : clazz.getInterfaces()) {
+      DexProgramClass ifaceDefinition = appView.programDefinitionFor(iface, clazz);
+      if (ifaceDefinition != null && ifaceDefinition.isInterface()) {
+        worklist.addIfNotSeen(ifaceDefinition);
+      }
+    }
   }
 
   @Override
-  public boolean shouldSkipPolicy() {
-    return !options.horizontalClassMergerOptions().isInterfaceMergingEnabled(mode);
+  public String getName() {
+    return "NoDefaultInterfaceMethodMerging";
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
index d2b1d3b..acc6daa 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
@@ -9,8 +9,8 @@
 import static com.android.tools.r8.shaking.ObjectAllocationInfoCollectionUtils.mayHaveFinalizeMethodDirectlyOrIndirectly;
 import static com.android.tools.r8.utils.MapUtils.ignoreKey;
 
-import com.android.tools.r8.code.CfOrDexInstanceFieldRead;
-import com.android.tools.r8.code.CfOrDexStaticFieldRead;
+import com.android.tools.r8.dex.code.CfOrDexInstanceFieldRead;
+import com.android.tools.r8.dex.code.CfOrDexStaticFieldRead;
 import com.android.tools.r8.graph.AbstractAccessContexts;
 import com.android.tools.r8.graph.AbstractAccessContexts.ConcreteAccessContexts;
 import com.android.tools.r8.graph.AppView;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/AbstractState.java b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/AbstractState.java
index 68b456b..914cc9e 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/AbstractState.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/AbstractState.java
@@ -8,7 +8,13 @@
 
 /** The abstract state of the dataflow analysis, which is computed for each {@link BasicBlock}. */
 public abstract class AbstractState<StateType extends AbstractState<StateType>>
-    implements TransferFunctionResult<StateType> {
+    implements Cloneable, TransferFunctionResult<StateType> {
+
+  @Override
+  public StateType clone() {
+    // For immutable states there is no need to clone.
+    return asAbstractState();
+  }
 
   public abstract StateType join(StateType state);
 
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/AbstractTransferFunction.java b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/AbstractTransferFunction.java
index a3013e3..4e73e2a 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/AbstractTransferFunction.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/AbstractTransferFunction.java
@@ -13,6 +13,10 @@
 
   TransferFunctionResult<StateType> apply(Instruction instruction, StateType state);
 
+  default StateType computeInitialState(Block entryBlock, StateType bottom) {
+    return bottom;
+  }
+
   default StateType computeBlockEntryState(
       Block block, Block predecessor, StateType predecessorExitState) {
     return predecessorExitState;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/ControlFlowGraph.java b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/ControlFlowGraph.java
index a6150bc..db0d7ca 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/ControlFlowGraph.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/ControlFlowGraph.java
@@ -12,6 +12,8 @@
 
 public interface ControlFlowGraph<Block, Instruction> {
 
+  Block getEntryBlock();
+
   default boolean hasUniquePredecessor(Block block) {
     return TraversalUtils.isSingleton(counter -> traversePredecessors(block, counter));
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/IntraProceduralDataflowAnalysisBase.java b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/IntraProceduralDataflowAnalysisBase.java
index f904da3..2cc7448 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/IntraProceduralDataflowAnalysisBase.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/IntraProceduralDataflowAnalysisBase.java
@@ -111,7 +111,10 @@
     return new SuccessfulDataflowAnalysisResult<>(blockExitStates);
   }
 
-  StateType computeBlockEntryState(Block block) {
+  public StateType computeBlockEntryState(Block block) {
+    if (block == cfg.getEntryBlock()) {
+      return transfer.computeInitialState(block, bottom);
+    }
     if (shouldCacheBlockEntryStateFor(block)) {
       return blockEntryStatesCache.getOrDefault(block, bottom);
     }
@@ -125,7 +128,7 @@
               return TraversalContinuation.doContinue(entryState.join(edgeState));
             },
             bottom);
-    return traversalContinuation.asContinue().getValue();
+    return traversalContinuation.asContinue().getValue().clone();
   }
 
   boolean setBlockExitState(Block block, StateType state) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/cf/CfBlock.java b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/cf/CfBlock.java
index b86915c..357ff33 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/cf/CfBlock.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/cf/CfBlock.java
@@ -8,7 +8,10 @@
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.utils.SetUtils;
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Set;
 
 /** A basic block for {@link com.android.tools.r8.graph.CfCode}. */
 public class CfBlock {
@@ -21,7 +24,7 @@
 
   // The predecessors of the block. These are stored explicitly (unlike the successors) since they
   // cannot efficiently be computed from the block.
-  final List<CfBlock> predecessors = new ArrayList<>();
+  final Set<CfBlock> predecessors = new LinkedHashSet<>();
 
   // The exceptional predecessors of the block.
   final List<CfBlock> exceptionalPredecessors = new ArrayList<>();
@@ -48,7 +51,7 @@
     return lastInstructionIndex;
   }
 
-  public List<CfBlock> getPredecessors() {
+  public Collection<CfBlock> getPredecessors() {
     return predecessors;
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/cf/CfControlFlowGraph.java b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/cf/CfControlFlowGraph.java
index 4cf9e5e..ff69065 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/cf/CfControlFlowGraph.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/cf/CfControlFlowGraph.java
@@ -57,6 +57,7 @@
     return blocks.get(blockEntry);
   }
 
+  @Override
   public CfBlock getEntryBlock() {
     return getBlock(code.getInstructions().get(0));
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoEnqueuerUseRegistry.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoEnqueuerUseRegistry.java
index 253665f..13495c3 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoEnqueuerUseRegistry.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoEnqueuerUseRegistry.java
@@ -7,7 +7,7 @@
 import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
 
 import com.android.tools.r8.androidapi.AndroidApiLevelCompute;
-import com.android.tools.r8.code.CfOrDexInstruction;
+import com.android.tools.r8.dex.code.CfOrDexInstruction;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexField;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/BooleanTypeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/BooleanTypeElement.java
index eea19ef..e00ecf9 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/BooleanTypeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/BooleanTypeElement.java
@@ -12,6 +12,11 @@
   }
 
   @Override
+  public String getTypeName() {
+    return "boolean";
+  }
+
+  @Override
   boolean isBoolean() {
     return true;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/ByteTypeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/ByteTypeElement.java
index c9e5e9f..849f508 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/ByteTypeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/ByteTypeElement.java
@@ -12,6 +12,11 @@
   }
 
   @Override
+  public String getTypeName() {
+    return "byte";
+  }
+
+  @Override
   boolean isByte() {
     return true;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/CharTypeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/CharTypeElement.java
index 0d33bfd..5a47cda 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/CharTypeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/CharTypeElement.java
@@ -12,6 +12,11 @@
   }
 
   @Override
+  public String getTypeName() {
+    return "char";
+  }
+
+  @Override
   boolean isChar() {
     return true;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/DoubleTypeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/DoubleTypeElement.java
index e9632a8..85a501c 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/DoubleTypeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/DoubleTypeElement.java
@@ -12,6 +12,11 @@
   }
 
   @Override
+  public String getTypeName() {
+    return "double";
+  }
+
+  @Override
   public boolean isDouble() {
     return true;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/FloatTypeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/FloatTypeElement.java
index 386981d..9efadf8 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/FloatTypeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/FloatTypeElement.java
@@ -11,6 +11,11 @@
   }
 
   @Override
+  public String getTypeName() {
+    return "float";
+  }
+
+  @Override
   public boolean isFloat() {
     return true;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/IntTypeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/IntTypeElement.java
index 5ecb417..881cb19 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/IntTypeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/IntTypeElement.java
@@ -11,6 +11,11 @@
   }
 
   @Override
+  public String getTypeName() {
+    return "int";
+  }
+
+  @Override
   public boolean isInt() {
     return true;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/LongTypeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/LongTypeElement.java
index caf2ed3..7f71468 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/LongTypeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/LongTypeElement.java
@@ -12,6 +12,11 @@
   }
 
   @Override
+  public String getTypeName() {
+    return "long";
+  }
+
+  @Override
   public boolean isLong() {
     return true;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/PrimitiveTypeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/PrimitiveTypeElement.java
index 4e9b5f1a..9797274 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/PrimitiveTypeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/PrimitiveTypeElement.java
@@ -12,6 +12,8 @@
 /** A {@link TypeElement} that abstracts primitive types. */
 public abstract class PrimitiveTypeElement extends TypeElement {
 
+  public abstract String getTypeName();
+
   @Override
   public Nullability nullability() {
     return Nullability.definitelyNotNull();
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/ShortTypeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/ShortTypeElement.java
index 61b8514..fd7d65a 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/ShortTypeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/ShortTypeElement.java
@@ -12,6 +12,11 @@
   }
 
   @Override
+  public String getTypeName() {
+    return "short";
+  }
+
+  @Override
   boolean isShort() {
     return true;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/SinglePrimitiveTypeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/SinglePrimitiveTypeElement.java
index 40436d1..5d3d16b 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/SinglePrimitiveTypeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/SinglePrimitiveTypeElement.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.analysis.type;
 
+import com.android.tools.r8.errors.Unreachable;
+
 /** A {@link TypeElement} that abstracts primitive types, which fit in 32 bits. */
 public class SinglePrimitiveTypeElement extends PrimitiveTypeElement {
 
@@ -17,6 +19,11 @@
   }
 
   @Override
+  public String getTypeName() {
+    throw new Unreachable("Unexpected attempt to get type name of " + this);
+  }
+
+  @Override
   public boolean isSinglePrimitive() {
     return true;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/TypeAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/type/TypeAnalysis.java
index 879e5a3..a0fd66f 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/TypeAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/TypeAnalysis.java
@@ -14,11 +14,8 @@
 import com.android.tools.r8.ir.code.Phi;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.google.common.collect.Lists;
 import java.util.ArrayDeque;
-import java.util.Comparator;
 import java.util.Deque;
-import java.util.List;
 
 public class TypeAnalysis {
 
@@ -72,11 +69,7 @@
   }
 
   public void narrowing(Iterable<? extends Value> values) {
-    // TODO(b/125492155) Not sorting causes us to have non-deterministic behaviour. This should be
-    //  removed when the bug is fixed.
-    List<Value> sortedValues = Lists.newArrayList(values);
-    sortedValues.sort(Comparator.comparingInt(Value::getNumber));
-    analyzeValues(sortedValues, Mode.NARROWING);
+    analyzeValues(values, Mode.NARROWING);
   }
 
   public boolean verifyValuesUpToDate(Iterable<? extends Value> values) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/WidePrimitiveTypeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/WidePrimitiveTypeElement.java
index 0ae7426..f13800d 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/WidePrimitiveTypeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/WidePrimitiveTypeElement.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.analysis.type;
 
+import com.android.tools.r8.errors.Unreachable;
+
 /** A {@link TypeElement} that abstracts primitive types, which fit in 64 bits. */
 public class WidePrimitiveTypeElement extends PrimitiveTypeElement {
 
@@ -17,6 +19,11 @@
   }
 
   @Override
+  public String getTypeName() {
+    throw new Unreachable("Unexpected attempt to get type name of " + this);
+  }
+
+  @Override
   public boolean isWidePrimitive() {
     return true;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Add.java b/src/main/java/com/android/tools/r8/ir/code/Add.java
index 3a5fa32..dc8cb05 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Add.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Add.java
@@ -5,16 +5,17 @@
 package com.android.tools.r8.ir.code;
 
 import com.android.tools.r8.cf.code.CfArithmeticBinop;
-import com.android.tools.r8.code.AddDouble;
-import com.android.tools.r8.code.AddDouble2Addr;
-import com.android.tools.r8.code.AddFloat;
-import com.android.tools.r8.code.AddFloat2Addr;
-import com.android.tools.r8.code.AddInt;
-import com.android.tools.r8.code.AddInt2Addr;
-import com.android.tools.r8.code.AddIntLit16;
-import com.android.tools.r8.code.AddIntLit8;
-import com.android.tools.r8.code.AddLong;
-import com.android.tools.r8.code.AddLong2Addr;
+import com.android.tools.r8.dex.code.DexAddDouble;
+import com.android.tools.r8.dex.code.DexAddDouble2Addr;
+import com.android.tools.r8.dex.code.DexAddFloat;
+import com.android.tools.r8.dex.code.DexAddFloat2Addr;
+import com.android.tools.r8.dex.code.DexAddInt;
+import com.android.tools.r8.dex.code.DexAddInt2Addr;
+import com.android.tools.r8.dex.code.DexAddIntLit16;
+import com.android.tools.r8.dex.code.DexAddIntLit8;
+import com.android.tools.r8.dex.code.DexAddLong;
+import com.android.tools.r8.dex.code.DexAddLong2Addr;
+import com.android.tools.r8.dex.code.DexInstruction;
 
 public class Add extends ArithmeticBinop {
 
@@ -38,53 +39,53 @@
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateInt(int dest, int left, int right) {
-    return new AddInt(dest, left, right);
+  public DexInstruction CreateInt(int dest, int left, int right) {
+    return new DexAddInt(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateLong(int dest, int left, int right) {
-    return new AddLong(dest, left, right);
+  public DexInstruction CreateLong(int dest, int left, int right) {
+    return new DexAddLong(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateFloat(int dest, int left, int right) {
-    return new AddFloat(dest, left, right);
+  public DexInstruction CreateFloat(int dest, int left, int right) {
+    return new DexAddFloat(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateDouble(int dest, int left, int right) {
-    return new AddDouble(dest, left, right);
+  public DexInstruction CreateDouble(int dest, int left, int right) {
+    return new DexAddDouble(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateInt2Addr(int left, int right) {
-    return new AddInt2Addr(left, right);
+  public DexInstruction CreateInt2Addr(int left, int right) {
+    return new DexAddInt2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateLong2Addr(int left, int right) {
-    return new AddLong2Addr(left, right);
+  public DexInstruction CreateLong2Addr(int left, int right) {
+    return new DexAddLong2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateFloat2Addr(int left, int right) {
-    return new AddFloat2Addr(left, right);
+  public DexInstruction CreateFloat2Addr(int left, int right) {
+    return new DexAddFloat2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateDouble2Addr(int left, int right) {
-    return new AddDouble2Addr(left, right);
+  public DexInstruction CreateDouble2Addr(int left, int right) {
+    return new DexAddDouble2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateIntLit8(int dest, int left, int constant) {
-    return new AddIntLit8(dest, left, constant);
+  public DexInstruction CreateIntLit8(int dest, int left, int constant) {
+    return new DexAddIntLit8(dest, left, constant);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateIntLit16(int dest, int left, int constant) {
-    return new AddIntLit16(dest, left, constant);
+  public DexInstruction CreateIntLit16(int dest, int left, int constant) {
+    return new DexAddIntLit16(dest, left, constant);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/AlwaysMaterializingDefinition.java b/src/main/java/com/android/tools/r8/ir/code/AlwaysMaterializingDefinition.java
index ed2cdd8..7f3a0b9 100644
--- a/src/main/java/com/android/tools/r8/ir/code/AlwaysMaterializingDefinition.java
+++ b/src/main/java/com/android/tools/r8/ir/code/AlwaysMaterializingDefinition.java
@@ -4,9 +4,9 @@
 package com.android.tools.r8.ir.code;
 
 import com.android.tools.r8.cf.LoadStoreHelper;
-import com.android.tools.r8.code.Const16;
-import com.android.tools.r8.code.Const4;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexConst16;
+import com.android.tools.r8.dex.code.DexConst4;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.ir.conversion.CfBuilder;
@@ -39,7 +39,8 @@
   public void buildDex(DexBuilder builder) {
     int register = builder.allocatedRegister(outValue, getNumber());
     builder.add(
-        this, (register & 0xf) == register ? new Const4(register, 0) : new Const16(register, 0));
+        this,
+        (register & 0xf) == register ? new DexConst4(register, 0) : new DexConst16(register, 0));
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/And.java b/src/main/java/com/android/tools/r8/ir/code/And.java
index 86c193b..f7aac6c 100644
--- a/src/main/java/com/android/tools/r8/ir/code/And.java
+++ b/src/main/java/com/android/tools/r8/ir/code/And.java
@@ -5,12 +5,13 @@
 package com.android.tools.r8.ir.code;
 
 import com.android.tools.r8.cf.code.CfLogicalBinop;
-import com.android.tools.r8.code.AndInt;
-import com.android.tools.r8.code.AndInt2Addr;
-import com.android.tools.r8.code.AndIntLit16;
-import com.android.tools.r8.code.AndIntLit8;
-import com.android.tools.r8.code.AndLong;
-import com.android.tools.r8.code.AndLong2Addr;
+import com.android.tools.r8.dex.code.DexAndInt;
+import com.android.tools.r8.dex.code.DexAndInt2Addr;
+import com.android.tools.r8.dex.code.DexAndIntLit16;
+import com.android.tools.r8.dex.code.DexAndIntLit8;
+import com.android.tools.r8.dex.code.DexAndLong;
+import com.android.tools.r8.dex.code.DexAndLong2Addr;
+import com.android.tools.r8.dex.code.DexInstruction;
 import java.util.Set;
 
 public class And extends LogicalBinop {
@@ -45,33 +46,33 @@
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateInt(int dest, int left, int right) {
-    return new AndInt(dest, left, right);
+  public DexInstruction CreateInt(int dest, int left, int right) {
+    return new DexAndInt(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateLong(int dest, int left, int right) {
-    return new AndLong(dest, left, right);
+  public DexInstruction CreateLong(int dest, int left, int right) {
+    return new DexAndLong(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateInt2Addr(int left, int right) {
-    return new AndInt2Addr(left, right);
+  public DexInstruction CreateInt2Addr(int left, int right) {
+    return new DexAndInt2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateLong2Addr(int left, int right) {
-    return new AndLong2Addr(left, right);
+  public DexInstruction CreateLong2Addr(int left, int right) {
+    return new DexAndLong2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateIntLit8(int dest, int left, int constant) {
-    return new AndIntLit8(dest, left, constant);
+  public DexInstruction CreateIntLit8(int dest, int left, int constant) {
+    return new DexAndIntLit8(dest, left, constant);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateIntLit16(int dest, int left, int constant) {
-    return new AndIntLit16(dest, left, constant);
+  public DexInstruction CreateIntLit16(int dest, int left, int constant) {
+    return new DexAndIntLit16(dest, left, constant);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArithmeticBinop.java b/src/main/java/com/android/tools/r8/ir/code/ArithmeticBinop.java
index a4be195..cf6039c 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ArithmeticBinop.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ArithmeticBinop.java
@@ -4,7 +4,7 @@
 package com.android.tools.r8.ir.code;
 
 import com.android.tools.r8.cf.code.CfArithmeticBinop;
-import com.android.tools.r8.code.Instruction;
+import com.android.tools.r8.dex.code.DexInstruction;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.ir.analysis.constant.Bottom;
 import com.android.tools.r8.ir.analysis.constant.ConstLatticeElement;
@@ -20,25 +20,25 @@
     super(type, dest, left, right);
   }
 
-  public abstract com.android.tools.r8.code.Instruction CreateInt(int dest, int left, int right);
+  public abstract DexInstruction CreateInt(int dest, int left, int right);
 
-  public abstract Instruction CreateLong(int dest, int left, int right);
+  public abstract DexInstruction CreateLong(int dest, int left, int right);
 
-  public abstract Instruction CreateFloat(int dest, int left, int right);
+  public abstract DexInstruction CreateFloat(int dest, int left, int right);
 
-  public abstract Instruction CreateDouble(int dest, int left, int right);
+  public abstract DexInstruction CreateDouble(int dest, int left, int right);
 
-  public abstract Instruction CreateInt2Addr(int left, int right);
+  public abstract DexInstruction CreateInt2Addr(int left, int right);
 
-  public abstract Instruction CreateLong2Addr(int left, int right);
+  public abstract DexInstruction CreateLong2Addr(int left, int right);
 
-  public abstract Instruction CreateFloat2Addr(int left, int right);
+  public abstract DexInstruction CreateFloat2Addr(int left, int right);
 
-  public abstract Instruction CreateDouble2Addr(int left, int right);
+  public abstract DexInstruction CreateDouble2Addr(int left, int right);
 
-  public abstract Instruction CreateIntLit8(int dest, int left, int constant);
+  public abstract DexInstruction CreateIntLit8(int dest, int left, int constant);
 
-  public abstract Instruction CreateIntLit16(int dest, int left, int constant);
+  public abstract DexInstruction CreateIntLit16(int dest, int left, int constant);
 
   @Override
   public boolean canBeFolded() {
@@ -64,7 +64,7 @@
     // Method needsValueInRegister ensures that left value has an allocated register.
     int left = builder.allocatedRegister(leftValue(), getNumber());
     int dest = builder.allocatedRegister(outValue, getNumber());
-    Instruction instruction = null;
+    DexInstruction instruction = null;
     if (isTwoAddr(builder.getRegisterAllocator())) {
       int right = builder.allocatedRegister(rightValue(), getNumber());
       if (left != dest) {
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java b/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java
index 82a2ef7..2bfd3c3 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java
@@ -6,14 +6,15 @@
 import com.android.tools.r8.cf.LoadStoreHelper;
 import com.android.tools.r8.cf.TypeVerificationHelper;
 import com.android.tools.r8.cf.code.CfArrayLoad;
-import com.android.tools.r8.code.Aget;
-import com.android.tools.r8.code.AgetBoolean;
-import com.android.tools.r8.code.AgetByte;
-import com.android.tools.r8.code.AgetChar;
-import com.android.tools.r8.code.AgetObject;
-import com.android.tools.r8.code.AgetShort;
-import com.android.tools.r8.code.AgetWide;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexAget;
+import com.android.tools.r8.dex.code.DexAgetBoolean;
+import com.android.tools.r8.dex.code.DexAgetByte;
+import com.android.tools.r8.dex.code.DexAgetChar;
+import com.android.tools.r8.dex.code.DexAgetObject;
+import com.android.tools.r8.dex.code.DexAgetShort;
+import com.android.tools.r8.dex.code.DexAgetWide;
+import com.android.tools.r8.dex.code.DexInstruction;
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
@@ -73,36 +74,36 @@
     int dest = builder.allocatedRegister(dest(), getNumber());
     int array = builder.allocatedRegister(array(), getNumber());
     int index = builder.allocatedRegister(index(), getNumber());
-    com.android.tools.r8.code.Instruction instruction;
+    DexInstruction instruction;
     switch (type) {
       case INT:
       case FLOAT:
-        instruction = new Aget(dest, array, index);
+        instruction = new DexAget(dest, array, index);
         break;
       case LONG:
       case DOUBLE:
         assert builder.getOptions().canUseSameArrayAndResultRegisterInArrayGetWide()
             || dest != array;
-        instruction = new AgetWide(dest, array, index);
+        instruction = new DexAgetWide(dest, array, index);
         break;
       case OBJECT:
-        instruction = new AgetObject(dest, array, index);
+        instruction = new DexAgetObject(dest, array, index);
         break;
       case BOOLEAN_OR_BYTE:
         ArrayTypeElement arrayType = array().getType().asArrayType();
         if (arrayType != null && arrayType.getMemberType() == TypeElement.getBoolean()) {
-          instruction = new AgetBoolean(dest, array, index);
+          instruction = new DexAgetBoolean(dest, array, index);
         } else {
           assert array().getType().isDefinitelyNull()
               || arrayType.getMemberType() == TypeElement.getByte();
-          instruction = new AgetByte(dest, array, index);
+          instruction = new DexAgetByte(dest, array, index);
         }
         break;
       case CHAR:
-        instruction = new AgetChar(dest, array, index);
+        instruction = new DexAgetChar(dest, array, index);
         break;
       case SHORT:
-        instruction = new AgetShort(dest, array, index);
+        instruction = new DexAgetShort(dest, array, index);
         break;
       case INT_OR_FLOAT:
       case LONG_OR_DOUBLE:
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java b/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java
index a0bf286..14837ee 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.cf.LoadStoreHelper;
 import com.android.tools.r8.cf.code.CfArrayLength;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexArrayLength;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
@@ -55,7 +56,7 @@
   public void buildDex(DexBuilder builder) {
     int dest = builder.allocatedRegister(dest(), getNumber());
     int array = builder.allocatedRegister(array(), getNumber());
-    builder.add(this, new com.android.tools.r8.code.ArrayLength(dest, array));
+    builder.add(this, new DexArrayLength(dest, array));
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java b/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java
index aa70b4f..4e43590 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java
@@ -5,14 +5,15 @@
 
 import com.android.tools.r8.cf.LoadStoreHelper;
 import com.android.tools.r8.cf.code.CfArrayStore;
-import com.android.tools.r8.code.Aput;
-import com.android.tools.r8.code.AputBoolean;
-import com.android.tools.r8.code.AputByte;
-import com.android.tools.r8.code.AputChar;
-import com.android.tools.r8.code.AputObject;
-import com.android.tools.r8.code.AputShort;
-import com.android.tools.r8.code.AputWide;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexAput;
+import com.android.tools.r8.dex.code.DexAputBoolean;
+import com.android.tools.r8.dex.code.DexAputByte;
+import com.android.tools.r8.dex.code.DexAputChar;
+import com.android.tools.r8.dex.code.DexAputObject;
+import com.android.tools.r8.dex.code.DexAputShort;
+import com.android.tools.r8.dex.code.DexAputWide;
+import com.android.tools.r8.dex.code.DexInstruction;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -66,34 +67,34 @@
     int value = builder.allocatedRegister(value(), getNumber());
     int array = builder.allocatedRegister(array(), getNumber());
     int index = builder.allocatedRegister(index(), getNumber());
-    com.android.tools.r8.code.Instruction instruction;
+    DexInstruction instruction;
     switch (type) {
       case INT:
       case FLOAT:
-        instruction = new Aput(value, array, index);
+        instruction = new DexAput(value, array, index);
         break;
       case LONG:
       case DOUBLE:
-        instruction = new AputWide(value, array, index);
+        instruction = new DexAputWide(value, array, index);
         break;
       case OBJECT:
-        instruction = new AputObject(value, array, index);
+        instruction = new DexAputObject(value, array, index);
         break;
       case BOOLEAN_OR_BYTE:
         ArrayTypeElement arrayType = array().getType().asArrayType();
         if (arrayType != null && arrayType.getMemberType() == TypeElement.getBoolean()) {
-          instruction = new AputBoolean(value, array, index);
+          instruction = new DexAputBoolean(value, array, index);
         } else {
           assert array().getType().isDefinitelyNull()
               || arrayType.getMemberType() == TypeElement.getByte();
-          instruction = new AputByte(value, array, index);
+          instruction = new DexAputByte(value, array, index);
         }
         break;
       case CHAR:
-        instruction = new AputChar(value, array, index);
+        instruction = new DexAputChar(value, array, index);
         break;
       case SHORT:
-        instruction = new AputShort(value, array, index);
+        instruction = new DexAputShort(value, array, index);
         break;
       case INT_OR_FLOAT:
       case LONG_OR_DOUBLE:
diff --git a/src/main/java/com/android/tools/r8/ir/code/CheckCast.java b/src/main/java/com/android/tools/r8/ir/code/CheckCast.java
index 5e96f46..ea014e6 100644
--- a/src/main/java/com/android/tools/r8/ir/code/CheckCast.java
+++ b/src/main/java/com/android/tools/r8/ir/code/CheckCast.java
@@ -9,9 +9,10 @@
 import com.android.tools.r8.cf.LoadStoreHelper;
 import com.android.tools.r8.cf.TypeVerificationHelper;
 import com.android.tools.r8.cf.code.CfCheckCast;
-import com.android.tools.r8.code.MoveObject;
-import com.android.tools.r8.code.MoveObjectFrom16;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexCheckCast;
+import com.android.tools.r8.dex.code.DexMoveObject;
+import com.android.tools.r8.dex.code.DexMoveObjectFrom16;
 import com.android.tools.r8.graph.AccessControl;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
@@ -107,18 +108,18 @@
       if (inRegister == outRegister) {
         builder.add(this, createCheckCast(outRegister));
       } else {
-        com.android.tools.r8.code.CheckCast cast = createCheckCast(outRegister);
+        DexCheckCast cast = createCheckCast(outRegister);
         if (outRegister <= Constants.U4BIT_MAX && inRegister <= Constants.U4BIT_MAX) {
-          builder.add(this, new MoveObject(outRegister, inRegister), cast);
+          builder.add(this, new DexMoveObject(outRegister, inRegister), cast);
         } else {
-          builder.add(this, new MoveObjectFrom16(outRegister, inRegister), cast);
+          builder.add(this, new DexMoveObjectFrom16(outRegister, inRegister), cast);
         }
       }
     }
   }
 
-  com.android.tools.r8.code.CheckCast createCheckCast(int register) {
-    return new com.android.tools.r8.code.CheckCast(register, getType(), ignoreCompatRules());
+  DexCheckCast createCheckCast(int register) {
+    return new DexCheckCast(register, getType(), ignoreCompatRules());
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/Cmp.java b/src/main/java/com/android/tools/r8/ir/code/Cmp.java
index a7b25a3..a03637e 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Cmp.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Cmp.java
@@ -4,12 +4,13 @@
 package com.android.tools.r8.ir.code;
 
 import com.android.tools.r8.cf.code.CfCmp;
-import com.android.tools.r8.code.CmpLong;
-import com.android.tools.r8.code.CmpgDouble;
-import com.android.tools.r8.code.CmpgFloat;
-import com.android.tools.r8.code.CmplDouble;
-import com.android.tools.r8.code.CmplFloat;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexCmpLong;
+import com.android.tools.r8.dex.code.DexCmpgDouble;
+import com.android.tools.r8.dex.code.DexCmpgFloat;
+import com.android.tools.r8.dex.code.DexCmplDouble;
+import com.android.tools.r8.dex.code.DexCmplFloat;
+import com.android.tools.r8.dex.code.DexInstruction;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.ir.analysis.constant.Bottom;
@@ -53,7 +54,7 @@
 
   @Override
   public void buildDex(DexBuilder builder) {
-    com.android.tools.r8.code.Instruction instruction;
+    DexInstruction instruction;
     int dest = builder.allocatedRegister(outValue, getNumber());
     int left = builder.allocatedRegister(leftValue(), getNumber());
     int right = builder.allocatedRegister(rightValue(), getNumber());
@@ -61,24 +62,24 @@
       case DOUBLE:
         assert bias != Bias.NONE;
         if (bias == Bias.GT) {
-          instruction = new CmpgDouble(dest, left, right);
+          instruction = new DexCmpgDouble(dest, left, right);
         } else {
           assert bias == Bias.LT;
-          instruction = new CmplDouble(dest, left, right);
+          instruction = new DexCmplDouble(dest, left, right);
         }
         break;
       case FLOAT:
         assert bias != Bias.NONE;
         if (bias == Bias.GT) {
-          instruction = new CmpgFloat(dest, left, right);
+          instruction = new DexCmpgFloat(dest, left, right);
         } else {
           assert bias == Bias.LT;
-          instruction = new CmplFloat(dest, left, right);
+          instruction = new DexCmplFloat(dest, left, right);
         }
         break;
       case LONG:
         assert bias == Bias.NONE;
-        instruction = new CmpLong(dest, left, right);
+        instruction = new DexCmpLong(dest, left, right);
         break;
       default:
         throw new Unreachable("Unexpected type " + type);
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstClass.java b/src/main/java/com/android/tools/r8/ir/code/ConstClass.java
index 05869bb..1fd0fed 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstClass.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstClass.java
@@ -8,6 +8,7 @@
 import com.android.tools.r8.cf.TypeVerificationHelper;
 import com.android.tools.r8.cf.code.CfConstClass;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexConstClass;
 import com.android.tools.r8.graph.AccessControl;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
@@ -79,7 +80,7 @@
   @Override
   public void buildDex(DexBuilder builder) {
     int dest = builder.allocatedRegister(dest(), getNumber());
-    builder.add(this, new com.android.tools.r8.code.ConstClass(dest, clazz, ignoreCompatRules()));
+    builder.add(this, new DexConstClass(dest, clazz, ignoreCompatRules()));
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstMethodHandle.java b/src/main/java/com/android/tools/r8/ir/code/ConstMethodHandle.java
index 35cef20..78ee74e 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstMethodHandle.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.cf.TypeVerificationHelper;
 import com.android.tools.r8.cf.code.CfConstMethodHandle;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexConstMethodHandle;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethodHandle;
 import com.android.tools.r8.graph.DexType;
@@ -58,7 +59,7 @@
   @Override
   public void buildDex(DexBuilder builder) {
     int dest = builder.allocatedRegister(dest(), getNumber());
-    builder.add(this, new com.android.tools.r8.code.ConstMethodHandle(dest, methodHandle));
+    builder.add(this, new DexConstMethodHandle(dest, methodHandle));
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstMethodType.java b/src/main/java/com/android/tools/r8/ir/code/ConstMethodType.java
index 64359c8..5ce3e31 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstMethodType.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstMethodType.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.cf.TypeVerificationHelper;
 import com.android.tools.r8.cf.code.CfConstMethodType;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexConstMethodType;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexType;
@@ -58,7 +59,7 @@
   @Override
   public void buildDex(DexBuilder builder) {
     int dest = builder.allocatedRegister(dest(), getNumber());
-    builder.add(this, new com.android.tools.r8.code.ConstMethodType(dest, methodType));
+    builder.add(this, new DexConstMethodType(dest, methodType));
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java b/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
index 958816b..8d39b43 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
@@ -7,15 +7,15 @@
 import com.android.tools.r8.cf.TypeVerificationHelper;
 import com.android.tools.r8.cf.code.CfConstNull;
 import com.android.tools.r8.cf.code.CfConstNumber;
-import com.android.tools.r8.code.Const;
-import com.android.tools.r8.code.Const16;
-import com.android.tools.r8.code.Const4;
-import com.android.tools.r8.code.ConstHigh16;
-import com.android.tools.r8.code.ConstWide;
-import com.android.tools.r8.code.ConstWide16;
-import com.android.tools.r8.code.ConstWide32;
-import com.android.tools.r8.code.ConstWideHigh16;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexConst;
+import com.android.tools.r8.dex.code.DexConst16;
+import com.android.tools.r8.dex.code.DexConst4;
+import com.android.tools.r8.dex.code.DexConstHigh16;
+import com.android.tools.r8.dex.code.DexConstWide;
+import com.android.tools.r8.dex.code.DexConstWide16;
+import com.android.tools.r8.dex.code.DexConstWide32;
+import com.android.tools.r8.dex.code.DexConstWideHigh16;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
@@ -143,24 +143,24 @@
     if (outType().isObject() || outType().isSingle()) {
       assert NumberUtils.is32Bit(value);
       if ((register & 0xf) == register && NumberUtils.is4Bit(value)) {
-        builder.add(this, new Const4(register, (int) value));
+        builder.add(this, new DexConst4(register, (int) value));
       } else if (NumberUtils.is16Bit(value)) {
-        builder.add(this, new Const16(register, (int) value));
+        builder.add(this, new DexConst16(register, (int) value));
       } else if ((value & 0x0000ffffL) == 0) {
-        builder.add(this, new ConstHigh16(register, ((int) value) >>> 16));
+        builder.add(this, new DexConstHigh16(register, ((int) value) >>> 16));
       } else {
-        builder.add(this, new Const(register, (int) value));
+        builder.add(this, new DexConst(register, (int) value));
       }
     } else {
       assert outType().isWide();
       if (NumberUtils.is16Bit(value)) {
-        builder.add(this, new ConstWide16(register, (int) value));
+        builder.add(this, new DexConstWide16(register, (int) value));
       } else if ((value & 0x0000ffffffffffffL) == 0) {
-        builder.add(this, new ConstWideHigh16(register, (int) (value >>> 48)));
+        builder.add(this, new DexConstWideHigh16(register, (int) (value >>> 48)));
       } else if (NumberUtils.is32Bit(value)) {
-        builder.add(this, new ConstWide32(register, (int) value));
+        builder.add(this, new DexConstWide32(register, (int) value));
       } else {
-        builder.add(this, new ConstWide(register, value));
+        builder.add(this, new DexConstWide(register, value));
       }
     }
   }
@@ -222,24 +222,24 @@
     if (type.isSingle()) {
       assert NumberUtils.is32Bit(value);
       if (NumberUtils.is4Bit(value)) {
-        return Const4.SIZE;
+        return DexConst4.SIZE;
       } else if (NumberUtils.is16Bit(value)) {
-        return Const16.SIZE;
+        return DexConst16.SIZE;
       } else if ((value & 0x0000ffffL) == 0) {
-        return ConstHigh16.SIZE;
+        return DexConstHigh16.SIZE;
       } else {
-        return Const.SIZE;
+        return DexConst.SIZE;
       }
     } else {
       assert type.isWide();
       if (NumberUtils.is16Bit(value)) {
-        return ConstWide16.SIZE;
+        return DexConstWide16.SIZE;
       } else if ((value & 0x0000ffffffffffffL) == 0) {
-        return ConstWideHigh16.SIZE;
+        return DexConstWideHigh16.SIZE;
       } else if (NumberUtils.is32Bit(value)) {
-        return ConstWide32.SIZE;
+        return DexConstWide32.SIZE;
       } else {
-        return ConstWide.SIZE;
+        return DexConstWide.SIZE;
       }
     }
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstString.java b/src/main/java/com/android/tools/r8/ir/code/ConstString.java
index 3df5d13..ca71070 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstString.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstString.java
@@ -9,6 +9,7 @@
 import com.android.tools.r8.cf.TypeVerificationHelper;
 import com.android.tools.r8.cf.code.CfConstString;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexConstString;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexString;
@@ -69,7 +70,7 @@
   @Override
   public void buildDex(DexBuilder builder) {
     int dest = builder.allocatedRegister(dest(), getNumber());
-    builder.add(this, new com.android.tools.r8.code.ConstString(dest, value));
+    builder.add(this, new DexConstString(dest, value));
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/DexItemBasedConstString.java b/src/main/java/com/android/tools/r8/ir/code/DexItemBasedConstString.java
index b7820c1..78a582b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/DexItemBasedConstString.java
+++ b/src/main/java/com/android/tools/r8/ir/code/DexItemBasedConstString.java
@@ -83,7 +83,7 @@
     int dest = builder.allocatedRegister(outValue(), getNumber());
     builder.add(
         this,
-        new com.android.tools.r8.code.DexItemBasedConstString(dest, item, nameComputationInfo));
+        new com.android.tools.r8.dex.code.DexItemBasedConstString(dest, item, nameComputationInfo));
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/Div.java b/src/main/java/com/android/tools/r8/ir/code/Div.java
index 45a743f..21031fb 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Div.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Div.java
@@ -4,16 +4,17 @@
 package com.android.tools.r8.ir.code;
 
 import com.android.tools.r8.cf.code.CfArithmeticBinop;
-import com.android.tools.r8.code.DivDouble;
-import com.android.tools.r8.code.DivDouble2Addr;
-import com.android.tools.r8.code.DivFloat;
-import com.android.tools.r8.code.DivFloat2Addr;
-import com.android.tools.r8.code.DivInt;
-import com.android.tools.r8.code.DivInt2Addr;
-import com.android.tools.r8.code.DivIntLit16;
-import com.android.tools.r8.code.DivIntLit8;
-import com.android.tools.r8.code.DivLong;
-import com.android.tools.r8.code.DivLong2Addr;
+import com.android.tools.r8.dex.code.DexDivDouble;
+import com.android.tools.r8.dex.code.DexDivDouble2Addr;
+import com.android.tools.r8.dex.code.DexDivFloat;
+import com.android.tools.r8.dex.code.DexDivFloat2Addr;
+import com.android.tools.r8.dex.code.DexDivInt;
+import com.android.tools.r8.dex.code.DexDivInt2Addr;
+import com.android.tools.r8.dex.code.DexDivIntLit16;
+import com.android.tools.r8.dex.code.DexDivIntLit8;
+import com.android.tools.r8.dex.code.DexDivLong;
+import com.android.tools.r8.dex.code.DexDivLong2Addr;
+import com.android.tools.r8.dex.code.DexInstruction;
 import com.android.tools.r8.ir.analysis.constant.Bottom;
 import com.android.tools.r8.ir.analysis.constant.LatticeElement;
 import java.util.function.Function;
@@ -50,53 +51,53 @@
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateInt(int dest, int left, int right) {
-    return new DivInt(dest, left, right);
+  public DexInstruction CreateInt(int dest, int left, int right) {
+    return new DexDivInt(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateLong(int dest, int left, int right) {
-    return new DivLong(dest, left, right);
+  public DexInstruction CreateLong(int dest, int left, int right) {
+    return new DexDivLong(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateFloat(int dest, int left, int right) {
-    return new DivFloat(dest, left, right);
+  public DexInstruction CreateFloat(int dest, int left, int right) {
+    return new DexDivFloat(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateDouble(int dest, int left, int right) {
-    return new DivDouble(dest, left, right);
+  public DexInstruction CreateDouble(int dest, int left, int right) {
+    return new DexDivDouble(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateInt2Addr(int left, int right) {
-    return new DivInt2Addr(left, right);
+  public DexInstruction CreateInt2Addr(int left, int right) {
+    return new DexDivInt2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateLong2Addr(int left, int right) {
-    return new DivLong2Addr(left, right);
+  public DexInstruction CreateLong2Addr(int left, int right) {
+    return new DexDivLong2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateFloat2Addr(int left, int right) {
-    return new DivFloat2Addr(left, right);
+  public DexInstruction CreateFloat2Addr(int left, int right) {
+    return new DexDivFloat2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateDouble2Addr(int left, int right) {
-    return new DivDouble2Addr(left, right);
+  public DexInstruction CreateDouble2Addr(int left, int right) {
+    return new DexDivDouble2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateIntLit8(int dest, int left, int constant) {
-    return new DivIntLit8(dest, left, constant);
+  public DexInstruction CreateIntLit8(int dest, int left, int constant) {
+    return new DexDivIntLit8(dest, left, constant);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateIntLit16(int dest, int left, int constant) {
-    return new DivIntLit16(dest, left, constant);
+  public DexInstruction CreateIntLit16(int dest, int left, int constant) {
+    return new DexDivIntLit16(dest, left, constant);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRCode.java b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
index 4656ad8..8f310c8 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IRCode.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
@@ -173,6 +173,11 @@
     return blocks.getFirst();
   }
 
+  @Override
+  public BasicBlock getEntryBlock() {
+    return blocks.getFirst();
+  }
+
   public Position getEntryPosition() {
     return entryPosition;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InitClass.java b/src/main/java/com/android/tools/r8/ir/code/InitClass.java
index 80351a6..f331383 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InitClass.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InitClass.java
@@ -6,8 +6,8 @@
 
 import com.android.tools.r8.cf.LoadStoreHelper;
 import com.android.tools.r8.cf.code.CfInitClass;
-import com.android.tools.r8.code.DexInitClass;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexInitClass;
 import com.android.tools.r8.graph.AccessControl;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java b/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java
index 0bc0830..b88555d 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java
@@ -7,14 +7,15 @@
 import com.android.tools.r8.cf.LoadStoreHelper;
 import com.android.tools.r8.cf.TypeVerificationHelper;
 import com.android.tools.r8.cf.code.CfInstanceFieldRead;
-import com.android.tools.r8.code.Iget;
-import com.android.tools.r8.code.IgetBoolean;
-import com.android.tools.r8.code.IgetByte;
-import com.android.tools.r8.code.IgetChar;
-import com.android.tools.r8.code.IgetObject;
-import com.android.tools.r8.code.IgetShort;
-import com.android.tools.r8.code.IgetWide;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexIget;
+import com.android.tools.r8.dex.code.DexIgetBoolean;
+import com.android.tools.r8.dex.code.DexIgetByte;
+import com.android.tools.r8.dex.code.DexIgetChar;
+import com.android.tools.r8.dex.code.DexIgetObject;
+import com.android.tools.r8.dex.code.DexIgetShort;
+import com.android.tools.r8.dex.code.DexIgetWide;
+import com.android.tools.r8.dex.code.DexInstruction;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexField;
@@ -79,31 +80,31 @@
   public void buildDex(DexBuilder builder) {
     int destRegister = builder.allocatedRegister(dest(), getNumber());
     int objectRegister = builder.allocatedRegister(object(), getNumber());
-    com.android.tools.r8.code.Instruction instruction;
+    DexInstruction instruction;
     DexField field = getField();
     switch (getType()) {
       case INT:
       case FLOAT:
-        instruction = new Iget(destRegister, objectRegister, field);
+        instruction = new DexIget(destRegister, objectRegister, field);
         break;
       case LONG:
       case DOUBLE:
-        instruction = new IgetWide(destRegister, objectRegister, field);
+        instruction = new DexIgetWide(destRegister, objectRegister, field);
         break;
       case OBJECT:
-        instruction = new IgetObject(destRegister, objectRegister, field);
+        instruction = new DexIgetObject(destRegister, objectRegister, field);
         break;
       case BOOLEAN:
-        instruction = new IgetBoolean(destRegister, objectRegister, field);
+        instruction = new DexIgetBoolean(destRegister, objectRegister, field);
         break;
       case BYTE:
-        instruction = new IgetByte(destRegister, objectRegister, field);
+        instruction = new DexIgetByte(destRegister, objectRegister, field);
         break;
       case CHAR:
-        instruction = new IgetChar(destRegister, objectRegister, field);
+        instruction = new DexIgetChar(destRegister, objectRegister, field);
         break;
       case SHORT:
-        instruction = new IgetShort(destRegister, objectRegister, field);
+        instruction = new DexIgetShort(destRegister, objectRegister, field);
         break;
       default:
         throw new Unreachable("Unexpected type: " + getType());
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java b/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java
index 123eb45..4af4442 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.cf.LoadStoreHelper;
 import com.android.tools.r8.cf.code.CfInstanceOf;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexInstanceOf;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -52,7 +53,7 @@
   public void buildDex(DexBuilder builder) {
     int dest = builder.allocatedRegister(dest(), getNumber());
     int value = builder.allocatedRegister(value(), getNumber());
-    builder.addInstanceOf(this, new com.android.tools.r8.code.InstanceOf(dest, value, type));
+    builder.addInstanceOf(this, new DexInstanceOf(dest, value, type));
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstancePut.java b/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
index 68d7ffc..be3739e 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
@@ -6,14 +6,15 @@
 
 import com.android.tools.r8.cf.LoadStoreHelper;
 import com.android.tools.r8.cf.code.CfInstanceFieldWrite;
-import com.android.tools.r8.code.Iput;
-import com.android.tools.r8.code.IputBoolean;
-import com.android.tools.r8.code.IputByte;
-import com.android.tools.r8.code.IputChar;
-import com.android.tools.r8.code.IputObject;
-import com.android.tools.r8.code.IputShort;
-import com.android.tools.r8.code.IputWide;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexIput;
+import com.android.tools.r8.dex.code.DexIputBoolean;
+import com.android.tools.r8.dex.code.DexIputByte;
+import com.android.tools.r8.dex.code.DexIputChar;
+import com.android.tools.r8.dex.code.DexIputObject;
+import com.android.tools.r8.dex.code.DexIputShort;
+import com.android.tools.r8.dex.code.DexIputWide;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedField;
@@ -87,33 +88,33 @@
 
   @Override
   public void buildDex(DexBuilder builder) {
-    com.android.tools.r8.code.Instruction instruction;
+    DexInstruction instruction;
     int valueRegister = builder.allocatedRegister(value(), getNumber());
     int objectRegister = builder.allocatedRegister(object(), getNumber());
     DexField field = getField();
     switch (getType()) {
       case INT:
       case FLOAT:
-        instruction = new Iput(valueRegister, objectRegister, field);
+        instruction = new DexIput(valueRegister, objectRegister, field);
         break;
       case LONG:
       case DOUBLE:
-        instruction = new IputWide(valueRegister, objectRegister, field);
+        instruction = new DexIputWide(valueRegister, objectRegister, field);
         break;
       case OBJECT:
-        instruction = new IputObject(valueRegister, objectRegister, field);
+        instruction = new DexIputObject(valueRegister, objectRegister, field);
         break;
       case BOOLEAN:
-        instruction = new IputBoolean(valueRegister, objectRegister, field);
+        instruction = new DexIputBoolean(valueRegister, objectRegister, field);
         break;
       case BYTE:
-        instruction = new IputByte(valueRegister, objectRegister, field);
+        instruction = new DexIputByte(valueRegister, objectRegister, field);
         break;
       case CHAR:
-        instruction = new IputChar(valueRegister, objectRegister, field);
+        instruction = new DexIputChar(valueRegister, objectRegister, field);
         break;
       case SHORT:
-        instruction = new IputShort(valueRegister, objectRegister, field);
+        instruction = new DexIputShort(valueRegister, objectRegister, field);
         break;
       default:
         throw new Unreachable("Unexpected type: " + getType());
diff --git a/src/main/java/com/android/tools/r8/ir/code/IntSwitch.java b/src/main/java/com/android/tools/r8/ir/code/IntSwitch.java
index 601f67f..9ccd91e 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IntSwitch.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IntSwitch.java
@@ -8,12 +8,12 @@
 import com.android.tools.r8.cf.code.CfLabel;
 import com.android.tools.r8.cf.code.CfSwitch;
 import com.android.tools.r8.cf.code.CfSwitch.Kind;
-import com.android.tools.r8.code.Nop;
-import com.android.tools.r8.code.PackedSwitch;
-import com.android.tools.r8.code.PackedSwitchPayload;
-import com.android.tools.r8.code.SparseSwitch;
-import com.android.tools.r8.code.SparseSwitchPayload;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexNop;
+import com.android.tools.r8.dex.code.DexPackedSwitch;
+import com.android.tools.r8.dex.code.DexPackedSwitchPayload;
+import com.android.tools.r8.dex.code.DexSparseSwitch;
+import com.android.tools.r8.dex.code.DexSparseSwitchPayload;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
@@ -202,9 +202,9 @@
   public void buildDex(DexBuilder builder) {
     int value = builder.allocatedRegister(value(), getNumber());
     if (emitPacked(InternalOutputMode.DexIndexed)) {
-      builder.addSwitch(this, new PackedSwitch(value));
+      builder.addSwitch(this, new DexPackedSwitch(value));
     } else {
-      builder.addSwitch(this, new SparseSwitch(value));
+      builder.addSwitch(this, new DexSparseSwitch(value));
     }
   }
 
@@ -224,14 +224,14 @@
     return result;
   }
 
-  public Nop buildPayload(int[] targets, int fallthroughTarget, InternalOutputMode mode) {
+  public DexNop buildPayload(int[] targets, int fallthroughTarget, InternalOutputMode mode) {
     assert keys.length == targets.length;
     assert mode.isGeneratingDex();
     if (emitPacked(mode)) {
       int targetsCount = (int) numberOfTargetsIfPacked(keys);
       if (targets.length == targetsCount) {
         // All targets are already present.
-        return new PackedSwitchPayload(getFirstKey(), targets);
+        return new DexPackedSwitchPayload(getFirstKey(), targets);
       } else {
         // Generate the list of targets for all key values. Set the target for keys not present
         // to the fallthrough.
@@ -247,11 +247,11 @@
           }
         }
         assert originalIndex == keys.length;
-        return new PackedSwitchPayload(getFirstKey(), packedTargets);
+        return new DexPackedSwitchPayload(getFirstKey(), packedTargets);
       }
     } else {
       assert numberOfKeys() == keys.length;
-      return new SparseSwitchPayload(keys, targets);
+      return new DexSparseSwitchPayload(keys, targets);
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/Invoke.java b/src/main/java/com/android/tools/r8/ir/code/Invoke.java
index 9e6d8a6..786a73e 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Invoke.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Invoke.java
@@ -3,17 +3,26 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.code;
 
-import com.android.tools.r8.code.InvokeCustomRange;
-import com.android.tools.r8.code.InvokeDirectRange;
-import com.android.tools.r8.code.InvokeInterfaceRange;
-import com.android.tools.r8.code.InvokePolymorphicRange;
-import com.android.tools.r8.code.InvokeStaticRange;
-import com.android.tools.r8.code.InvokeSuperRange;
-import com.android.tools.r8.code.InvokeVirtualRange;
-import com.android.tools.r8.code.MoveResult;
-import com.android.tools.r8.code.MoveResultObject;
-import com.android.tools.r8.code.MoveResultWide;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexInvokeCustom;
+import com.android.tools.r8.dex.code.DexInvokeCustomRange;
+import com.android.tools.r8.dex.code.DexInvokeDirect;
+import com.android.tools.r8.dex.code.DexInvokeDirectRange;
+import com.android.tools.r8.dex.code.DexInvokeInterface;
+import com.android.tools.r8.dex.code.DexInvokeInterfaceRange;
+import com.android.tools.r8.dex.code.DexInvokePolymorphic;
+import com.android.tools.r8.dex.code.DexInvokePolymorphicRange;
+import com.android.tools.r8.dex.code.DexInvokeStatic;
+import com.android.tools.r8.dex.code.DexInvokeStaticRange;
+import com.android.tools.r8.dex.code.DexInvokeSuper;
+import com.android.tools.r8.dex.code.DexInvokeSuperRange;
+import com.android.tools.r8.dex.code.DexInvokeVirtual;
+import com.android.tools.r8.dex.code.DexInvokeVirtualRange;
+import com.android.tools.r8.dex.code.DexMoveResult;
+import com.android.tools.r8.dex.code.DexMoveResultObject;
+import com.android.tools.r8.dex.code.DexMoveResultWide;
+import com.android.tools.r8.dex.code.DexNewArray;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClassAndMethod;
@@ -39,15 +48,15 @@
   private static final int NO_SUCH_DEX_INSTRUCTION = -1;
 
   public enum Type {
-    DIRECT(com.android.tools.r8.code.InvokeDirect.OPCODE, InvokeDirectRange.OPCODE),
-    INTERFACE(com.android.tools.r8.code.InvokeInterface.OPCODE, InvokeInterfaceRange.OPCODE),
-    STATIC(com.android.tools.r8.code.InvokeStatic.OPCODE, InvokeStaticRange.OPCODE),
-    SUPER(com.android.tools.r8.code.InvokeSuper.OPCODE, InvokeSuperRange.OPCODE),
-    VIRTUAL(com.android.tools.r8.code.InvokeVirtual.OPCODE, InvokeVirtualRange.OPCODE),
-    NEW_ARRAY(com.android.tools.r8.code.NewArray.OPCODE, NO_SUCH_DEX_INSTRUCTION),
+    DIRECT(DexInvokeDirect.OPCODE, DexInvokeDirectRange.OPCODE),
+    INTERFACE(DexInvokeInterface.OPCODE, DexInvokeInterfaceRange.OPCODE),
+    STATIC(DexInvokeStatic.OPCODE, DexInvokeStaticRange.OPCODE),
+    SUPER(DexInvokeSuper.OPCODE, DexInvokeSuperRange.OPCODE),
+    VIRTUAL(DexInvokeVirtual.OPCODE, DexInvokeVirtualRange.OPCODE),
+    NEW_ARRAY(DexNewArray.OPCODE, NO_SUCH_DEX_INSTRUCTION),
     MULTI_NEW_ARRAY(NO_SUCH_DEX_INSTRUCTION, NO_SUCH_DEX_INSTRUCTION),
-    CUSTOM(com.android.tools.r8.code.InvokeCustom.OPCODE, InvokeCustomRange.OPCODE),
-    POLYMORPHIC(com.android.tools.r8.code.InvokePolymorphic.OPCODE, InvokePolymorphicRange.OPCODE);
+    CUSTOM(DexInvokeCustom.OPCODE, DexInvokeCustomRange.OPCODE),
+    POLYMORPHIC(DexInvokePolymorphic.OPCODE, DexInvokePolymorphicRange.OPCODE);
 
     private final int dexOpcode;
     private final int dexOpcodeRange;
@@ -346,18 +355,17 @@
     return true;
   }
 
-  protected void addInvokeAndMoveResult(
-      com.android.tools.r8.code.Instruction instruction, DexBuilder builder) {
+  protected void addInvokeAndMoveResult(DexInstruction instruction, DexBuilder builder) {
     if (outValue != null && outValue.needsRegister()) {
       TypeElement moveType = outValue.getType();
       int register = builder.allocatedRegister(outValue, getNumber());
-      com.android.tools.r8.code.Instruction moveResult;
+      DexInstruction moveResult;
       if (moveType.isSinglePrimitive()) {
-        moveResult = new MoveResult(register);
+        moveResult = new DexMoveResult(register);
       } else if (moveType.isWidePrimitive()) {
-        moveResult = new MoveResultWide(register);
+        moveResult = new DexMoveResultWide(register);
       } else if (moveType.isReferenceType()) {
-        moveResult = new MoveResultObject(register);
+        moveResult = new DexMoveResultObject(register);
       } else {
         throw new Unreachable("Unexpected result type " + outType());
       }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java b/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java
index 1296742..e43b0f0 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java
@@ -6,7 +6,9 @@
 import com.android.tools.r8.cf.LoadStoreHelper;
 import com.android.tools.r8.cf.TypeVerificationHelper;
 import com.android.tools.r8.cf.code.CfInvokeDynamic;
-import com.android.tools.r8.code.InvokeCustomRange;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexInvokeCustom;
+import com.android.tools.r8.dex.code.DexInvokeCustomRange;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexCallSite;
 import com.android.tools.r8.graph.DexType;
@@ -123,24 +125,25 @@
 
   @Override
   public void buildDex(DexBuilder builder) {
-    com.android.tools.r8.code.Instruction instruction;
+    DexInstruction instruction;
     int argumentRegisters = requiredArgumentRegisters();
     builder.requestOutgoingRegisters(argumentRegisters);
     if (needsRangedInvoke(builder)) {
       assert argumentsConsecutive(builder);
       int firstRegister = argumentRegisterValue(0, builder);
-      instruction = new InvokeCustomRange(firstRegister, argumentRegisters, getCallSite());
+      instruction = new DexInvokeCustomRange(firstRegister, argumentRegisters, getCallSite());
     } else {
       int[] individualArgumentRegisters = new int[5];
       int argumentRegistersCount = fillArgumentRegisters(builder, individualArgumentRegisters);
-      instruction = new com.android.tools.r8.code.InvokeCustom(
-          argumentRegistersCount,
-          getCallSite(),
-          individualArgumentRegisters[0], // C
-          individualArgumentRegisters[1], // D
-          individualArgumentRegisters[2], // E
-          individualArgumentRegisters[3], // F
-          individualArgumentRegisters[4]); // G
+      instruction =
+          new DexInvokeCustom(
+              argumentRegistersCount,
+              getCallSite(),
+              individualArgumentRegisters[0], // C
+              individualArgumentRegisters[1], // D
+              individualArgumentRegisters[2], // E
+              individualArgumentRegisters[3], // F
+              individualArgumentRegisters[4]); // G
     }
     addInvokeAndMoveResult(instruction, builder);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java b/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
index f57b79f..ff70fed 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
@@ -6,8 +6,10 @@
 import static com.android.tools.r8.graph.DexEncodedMethod.asDexClassAndMethodOrNull;
 
 import com.android.tools.r8.cf.code.CfInvoke;
-import com.android.tools.r8.code.InvokeDirectRange;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexInvokeDirect;
+import com.android.tools.r8.dex.code.DexInvokeDirectRange;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedMethod;
@@ -76,24 +78,25 @@
 
   @Override
   public void buildDex(DexBuilder builder) {
-    com.android.tools.r8.code.Instruction instruction;
+    DexInstruction instruction;
     int argumentRegisters = requiredArgumentRegisters();
     builder.requestOutgoingRegisters(argumentRegisters);
     if (needsRangedInvoke(builder)) {
       assert argumentsConsecutive(builder);
       int firstRegister = argumentRegisterValue(0, builder);
-      instruction = new InvokeDirectRange(firstRegister, argumentRegisters, getInvokedMethod());
+      instruction = new DexInvokeDirectRange(firstRegister, argumentRegisters, getInvokedMethod());
     } else {
       int[] individualArgumentRegisters = new int[5];
       int argumentRegistersCount = fillArgumentRegisters(builder, individualArgumentRegisters);
-      instruction = new com.android.tools.r8.code.InvokeDirect(
-          argumentRegistersCount,
-          getInvokedMethod(),
-          individualArgumentRegisters[0],  // C
-          individualArgumentRegisters[1],  // D
-          individualArgumentRegisters[2],  // E
-          individualArgumentRegisters[3],  // F
-          individualArgumentRegisters[4]); // G
+      instruction =
+          new DexInvokeDirect(
+              argumentRegistersCount,
+              getInvokedMethod(),
+              individualArgumentRegisters[0], // C
+              individualArgumentRegisters[1], // D
+              individualArgumentRegisters[2], // E
+              individualArgumentRegisters[3], // F
+              individualArgumentRegisters[4]); // G
     }
     addInvokeAndMoveResult(instruction, builder);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java b/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java
index 6749695..67e78d6 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java
@@ -6,7 +6,9 @@
 import static com.android.tools.r8.graph.DexEncodedMethod.asDexClassAndMethodOrNull;
 
 import com.android.tools.r8.cf.code.CfInvoke;
-import com.android.tools.r8.code.InvokeInterfaceRange;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexInvokeInterface;
+import com.android.tools.r8.dex.code.DexInvokeInterfaceRange;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedMethod;
@@ -57,24 +59,26 @@
 
   @Override
   public void buildDex(DexBuilder builder) {
-    com.android.tools.r8.code.Instruction instruction;
+    DexInstruction instruction;
     int argumentRegisters = requiredArgumentRegisters();
     builder.requestOutgoingRegisters(argumentRegisters);
     if (needsRangedInvoke(builder)) {
       assert argumentsConsecutive(builder);
       int firstRegister = argumentRegisterValue(0, builder);
-      instruction = new InvokeInterfaceRange(firstRegister, argumentRegisters, getInvokedMethod());
+      instruction =
+          new DexInvokeInterfaceRange(firstRegister, argumentRegisters, getInvokedMethod());
     } else {
       int[] individualArgumentRegisters = new int[5];
       int argumentRegistersCount = fillArgumentRegisters(builder, individualArgumentRegisters);
-      instruction = new com.android.tools.r8.code.InvokeInterface(
-          argumentRegistersCount,
-          getInvokedMethod(),
-          individualArgumentRegisters[0],  // C
-          individualArgumentRegisters[1],  // D
-          individualArgumentRegisters[2],  // E
-          individualArgumentRegisters[3],  // F
-          individualArgumentRegisters[4]); // G
+      instruction =
+          new DexInvokeInterface(
+              argumentRegistersCount,
+              getInvokedMethod(),
+              individualArgumentRegisters[0], // C
+              individualArgumentRegisters[1], // D
+              individualArgumentRegisters[2], // E
+              individualArgumentRegisters[3], // F
+              individualArgumentRegisters[4]); // G
     }
     addInvokeAndMoveResult(instruction, builder);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java b/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
index 1b356e3..9bc1728 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
@@ -5,8 +5,9 @@
 
 import com.android.tools.r8.cf.LoadStoreHelper;
 import com.android.tools.r8.cf.TypeVerificationHelper;
-import com.android.tools.r8.code.FilledNewArray;
-import com.android.tools.r8.code.FilledNewArrayRange;
+import com.android.tools.r8.dex.code.DexFilledNewArray;
+import com.android.tools.r8.dex.code.DexFilledNewArrayRange;
+import com.android.tools.r8.dex.code.DexInstruction;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AccessControl;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
@@ -70,24 +71,25 @@
 
   @Override
   public void buildDex(DexBuilder builder) {
-    com.android.tools.r8.code.Instruction instruction;
+    DexInstruction instruction;
     int argumentRegisters = requiredArgumentRegisters();
     builder.requestOutgoingRegisters(argumentRegisters);
     if (needsRangedInvoke(builder)) {
       assert argumentsConsecutive(builder);
       int firstRegister = argumentRegisterValue(0, builder);
-      instruction = new FilledNewArrayRange(firstRegister, argumentRegisters, type);
+      instruction = new DexFilledNewArrayRange(firstRegister, argumentRegisters, type);
     } else {
       int[] individualArgumentRegisters = new int[5];
       int argumentRegistersCount = fillArgumentRegisters(builder, individualArgumentRegisters);
-      instruction = new FilledNewArray(
-          argumentRegistersCount,
-          type,
-          individualArgumentRegisters[0],  // C
-          individualArgumentRegisters[1],  // D
-          individualArgumentRegisters[2],  // E
-          individualArgumentRegisters[3],  // F
-          individualArgumentRegisters[4]); // G
+      instruction =
+          new DexFilledNewArray(
+              argumentRegistersCount,
+              type,
+              individualArgumentRegisters[0], // C
+              individualArgumentRegisters[1], // D
+              individualArgumentRegisters[2], // E
+              individualArgumentRegisters[3], // F
+              individualArgumentRegisters[4]); // G
     }
     addInvokeAndMoveResult(instruction, builder);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java b/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java
index ad8c087..c09c441 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java
@@ -4,7 +4,9 @@
 package com.android.tools.r8.ir.code;
 
 import com.android.tools.r8.cf.code.CfInvoke;
-import com.android.tools.r8.code.InvokePolymorphicRange;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexInvokePolymorphic;
+import com.android.tools.r8.dex.code.DexInvokePolymorphicRange;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClassAndMethod;
@@ -71,18 +73,20 @@
 
   @Override
   public void buildDex(DexBuilder builder) {
-    com.android.tools.r8.code.Instruction instruction;
+    DexInstruction instruction;
     int argumentRegisters = requiredArgumentRegisters();
     builder.requestOutgoingRegisters(argumentRegisters);
     if (needsRangedInvoke(builder)) {
       assert argumentsConsecutive(builder);
       int firstRegister = argumentRegisterValue(0, builder);
-      instruction = new InvokePolymorphicRange(
+      instruction =
+          new DexInvokePolymorphicRange(
               firstRegister, argumentRegisters, getInvokedMethod(), getProto());
     } else {
       int[] individualArgumentRegisters = new int[5];
       int argumentRegistersCount = fillArgumentRegisters(builder, individualArgumentRegisters);
-      instruction = new com.android.tools.r8.code.InvokePolymorphic(
+      instruction =
+          new DexInvokePolymorphic(
               argumentRegistersCount,
               getInvokedMethod(),
               getProto(),
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java b/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
index b405dbb..8f47b31 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
@@ -6,7 +6,9 @@
 import static com.android.tools.r8.graph.DexEncodedMethod.asDexClassAndMethodOrNull;
 
 import com.android.tools.r8.cf.code.CfInvoke;
-import com.android.tools.r8.code.InvokeStaticRange;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexInvokeStatic;
+import com.android.tools.r8.dex.code.DexInvokeStaticRange;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexClassAndMethod;
@@ -74,24 +76,25 @@
 
   @Override
   public void buildDex(DexBuilder builder) {
-    com.android.tools.r8.code.Instruction instruction;
+    DexInstruction instruction;
     int argumentRegisters = requiredArgumentRegisters();
     builder.requestOutgoingRegisters(argumentRegisters);
     if (needsRangedInvoke(builder)) {
       assert argumentsConsecutive(builder);
       int firstRegister = argumentRegisterValue(0, builder);
-      instruction = new InvokeStaticRange(firstRegister, argumentRegisters, getInvokedMethod());
+      instruction = new DexInvokeStaticRange(firstRegister, argumentRegisters, getInvokedMethod());
     } else {
       int[] individualArgumentRegisters = new int[5];
       int argumentRegistersCount = fillArgumentRegisters(builder, individualArgumentRegisters);
-      instruction = new com.android.tools.r8.code.InvokeStatic(
-          argumentRegistersCount,
-          getInvokedMethod(),
-          individualArgumentRegisters[0],  // C
-          individualArgumentRegisters[1],  // D
-          individualArgumentRegisters[2],  // E
-          individualArgumentRegisters[3],  // F
-          individualArgumentRegisters[4]); // G
+      instruction =
+          new DexInvokeStatic(
+              argumentRegistersCount,
+              getInvokedMethod(),
+              individualArgumentRegisters[0], // C
+              individualArgumentRegisters[1], // D
+              individualArgumentRegisters[2], // E
+              individualArgumentRegisters[3], // F
+              individualArgumentRegisters[4]); // G
     }
     addInvokeAndMoveResult(instruction, builder);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java b/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java
index d41559e..705c7f9 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java
@@ -5,7 +5,9 @@
 
 
 import com.android.tools.r8.cf.code.CfInvoke;
-import com.android.tools.r8.code.InvokeSuperRange;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexInvokeSuper;
+import com.android.tools.r8.dex.code.DexInvokeSuperRange;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexMethod;
@@ -58,24 +60,25 @@
 
   @Override
   public void buildDex(DexBuilder builder) {
-    com.android.tools.r8.code.Instruction instruction;
+    DexInstruction instruction;
     int argumentRegisters = requiredArgumentRegisters();
     builder.requestOutgoingRegisters(argumentRegisters);
     if (needsRangedInvoke(builder)) {
       assert argumentsConsecutive(builder);
       int firstRegister = argumentRegisterValue(0, builder);
-      instruction = new InvokeSuperRange(firstRegister, argumentRegisters, getInvokedMethod());
+      instruction = new DexInvokeSuperRange(firstRegister, argumentRegisters, getInvokedMethod());
     } else {
       int[] individualArgumentRegisters = new int[5];
       int argumentRegistersCount = fillArgumentRegisters(builder, individualArgumentRegisters);
-      instruction = new com.android.tools.r8.code.InvokeSuper(
-          argumentRegistersCount,
-          getInvokedMethod(),
-          individualArgumentRegisters[0],  // C
-          individualArgumentRegisters[1],  // D
-          individualArgumentRegisters[2],  // E
-          individualArgumentRegisters[3],  // F
-          individualArgumentRegisters[4]); // G
+      instruction =
+          new DexInvokeSuper(
+              argumentRegistersCount,
+              getInvokedMethod(),
+              individualArgumentRegisters[0], // C
+              individualArgumentRegisters[1], // D
+              individualArgumentRegisters[2], // E
+              individualArgumentRegisters[3], // F
+              individualArgumentRegisters[4]); // G
     }
     addInvokeAndMoveResult(instruction, builder);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java b/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
index d0bca6a..fed5f58 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
@@ -6,7 +6,9 @@
 import static com.android.tools.r8.graph.DexEncodedMethod.asDexClassAndMethodOrNull;
 
 import com.android.tools.r8.cf.code.CfInvoke;
-import com.android.tools.r8.code.InvokeVirtualRange;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexInvokeVirtual;
+import com.android.tools.r8.dex.code.DexInvokeVirtualRange;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexClassAndMethod;
@@ -62,24 +64,25 @@
 
   @Override
   public void buildDex(DexBuilder builder) {
-    com.android.tools.r8.code.Instruction instruction;
+    DexInstruction instruction;
     int argumentRegisters = requiredArgumentRegisters();
     builder.requestOutgoingRegisters(argumentRegisters);
     if (needsRangedInvoke(builder)) {
       assert argumentsConsecutive(builder);
       int firstRegister = argumentRegisterValue(0, builder);
-      instruction = new InvokeVirtualRange(firstRegister, argumentRegisters, getInvokedMethod());
+      instruction = new DexInvokeVirtualRange(firstRegister, argumentRegisters, getInvokedMethod());
     } else {
       int[] individualArgumentRegisters = new int[5];
       int argumentRegistersCount = fillArgumentRegisters(builder, individualArgumentRegisters);
-      instruction = new com.android.tools.r8.code.InvokeVirtual(
-          argumentRegistersCount,
-          getInvokedMethod(),
-          individualArgumentRegisters[0],  // C
-          individualArgumentRegisters[1],  // D
-          individualArgumentRegisters[2],  // E
-          individualArgumentRegisters[3],  // F
-          individualArgumentRegisters[4]); // G
+      instruction =
+          new DexInvokeVirtual(
+              argumentRegistersCount,
+              getInvokedMethod(),
+              individualArgumentRegisters[0], // C
+              individualArgumentRegisters[1], // D
+              individualArgumentRegisters[2], // E
+              individualArgumentRegisters[3], // F
+              individualArgumentRegisters[4]); // G
     }
     addInvokeAndMoveResult(instruction, builder);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/LogicalBinop.java b/src/main/java/com/android/tools/r8/ir/code/LogicalBinop.java
index b647ecf..c9a1b03 100644
--- a/src/main/java/com/android/tools/r8/ir/code/LogicalBinop.java
+++ b/src/main/java/com/android/tools/r8/ir/code/LogicalBinop.java
@@ -4,7 +4,7 @@
 package com.android.tools.r8.ir.code;
 
 import com.android.tools.r8.cf.code.CfLogicalBinop;
-import com.android.tools.r8.code.Instruction;
+import com.android.tools.r8.dex.code.DexInstruction;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.ir.analysis.constant.Bottom;
 import com.android.tools.r8.ir.analysis.constant.ConstLatticeElement;
@@ -20,17 +20,17 @@
     super(type, dest, left, right);
   }
 
-  public abstract com.android.tools.r8.code.Instruction CreateInt(int dest, int left, int right);
+  public abstract DexInstruction CreateInt(int dest, int left, int right);
 
-  public abstract Instruction CreateLong(int dest, int left, int right);
+  public abstract DexInstruction CreateLong(int dest, int left, int right);
 
-  public abstract Instruction CreateInt2Addr(int left, int right);
+  public abstract DexInstruction CreateInt2Addr(int left, int right);
 
-  public abstract Instruction CreateLong2Addr(int left, int right);
+  public abstract DexInstruction CreateLong2Addr(int left, int right);
 
-  public abstract Instruction CreateIntLit8(int dest, int left, int constant);
+  public abstract DexInstruction CreateIntLit8(int dest, int left, int constant);
 
-  public abstract Instruction CreateIntLit16(int dest, int left, int constant);
+  public abstract DexInstruction CreateIntLit16(int dest, int left, int constant);
 
   @Override
   public boolean canBeFolded() {
@@ -54,7 +54,7 @@
     // that will change.
     int left = builder.allocatedRegister(leftValue(), getNumber());
     int dest = builder.allocatedRegister(outValue, getNumber());
-    Instruction instruction;
+    DexInstruction instruction;
     if (isTwoAddr(builder.getRegisterAllocator())) {
       int right = builder.allocatedRegister(rightValue(), getNumber());
       if (left != dest) {
diff --git a/src/main/java/com/android/tools/r8/ir/code/Monitor.java b/src/main/java/com/android/tools/r8/ir/code/Monitor.java
index 648c9fd..1e00e9b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Monitor.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Monitor.java
@@ -8,8 +8,8 @@
 
 import com.android.tools.r8.cf.LoadStoreHelper;
 import com.android.tools.r8.cf.code.CfMonitor;
-import com.android.tools.r8.code.MonitorEnter;
-import com.android.tools.r8.code.MonitorExit;
+import com.android.tools.r8.dex.code.DexMonitorEnter;
+import com.android.tools.r8.dex.code.DexMonitorExit;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -65,9 +65,9 @@
       object = builder.allocatedRegister(object(), getNumber());
     }
     if (type == Type.ENTER) {
-      builder.add(this, new MonitorEnter(object));
+      builder.add(this, new DexMonitorEnter(object));
     } else {
-      builder.add(this, new MonitorExit(object));
+      builder.add(this, new DexMonitorExit(object));
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/MoveException.java b/src/main/java/com/android/tools/r8/ir/code/MoveException.java
index efec2dd..616882a 100644
--- a/src/main/java/com/android/tools/r8/ir/code/MoveException.java
+++ b/src/main/java/com/android/tools/r8/ir/code/MoveException.java
@@ -6,6 +6,7 @@
 import com.android.tools.r8.cf.LoadStoreHelper;
 import com.android.tools.r8.cf.TypeVerificationHelper;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexMoveException;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -45,7 +46,7 @@
   @Override
   public void buildDex(DexBuilder builder) {
     int dest = builder.allocatedRegister(dest(), getNumber());
-    builder.add(this, new com.android.tools.r8.code.MoveException(dest));
+    builder.add(this, new DexMoveException(dest));
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/Mul.java b/src/main/java/com/android/tools/r8/ir/code/Mul.java
index dcc8e1b..ccddf6a 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Mul.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Mul.java
@@ -5,16 +5,17 @@
 package com.android.tools.r8.ir.code;
 
 import com.android.tools.r8.cf.code.CfArithmeticBinop;
-import com.android.tools.r8.code.MulDouble;
-import com.android.tools.r8.code.MulDouble2Addr;
-import com.android.tools.r8.code.MulFloat;
-import com.android.tools.r8.code.MulFloat2Addr;
-import com.android.tools.r8.code.MulInt;
-import com.android.tools.r8.code.MulInt2Addr;
-import com.android.tools.r8.code.MulIntLit16;
-import com.android.tools.r8.code.MulIntLit8;
-import com.android.tools.r8.code.MulLong;
-import com.android.tools.r8.code.MulLong2Addr;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexMulDouble;
+import com.android.tools.r8.dex.code.DexMulDouble2Addr;
+import com.android.tools.r8.dex.code.DexMulFloat;
+import com.android.tools.r8.dex.code.DexMulFloat2Addr;
+import com.android.tools.r8.dex.code.DexMulInt;
+import com.android.tools.r8.dex.code.DexMulInt2Addr;
+import com.android.tools.r8.dex.code.DexMulIntLit16;
+import com.android.tools.r8.dex.code.DexMulIntLit8;
+import com.android.tools.r8.dex.code.DexMulLong;
+import com.android.tools.r8.dex.code.DexMulLong2Addr;
 
 public class Mul extends ArithmeticBinop {
 
@@ -38,65 +39,67 @@
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateInt(int dest, int left, int right) {
+  public DexInstruction CreateInt(int dest, int left, int right) {
     // Flip arguments if dest and right are the same to work around x86 code generation bug on
     // Android L. See https://android-review.googlesource.com/#/c/114932/ for the fix for Android
     // M.
-    return dest == right ? new MulInt(dest, right, left) : new MulInt(dest, left, right);
+    return dest == right ? new DexMulInt(dest, right, left) : new DexMulInt(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateLong(int dest, int left, int right) {
+  public DexInstruction CreateLong(int dest, int left, int right) {
     // Flip arguments if dest and right are the same to work around x86 code generation bug on
     // Android L. See https://android-review.googlesource.com/#/c/114932/ for the fix for Android
     // M.
-    return dest == right ? new MulLong(dest, right, left) : new MulLong(dest, left, right);
+    return dest == right ? new DexMulLong(dest, right, left) : new DexMulLong(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateFloat(int dest, int left, int right) {
+  public DexInstruction CreateFloat(int dest, int left, int right) {
     // Flip arguments if dest and right are the same to work around x86 code generation bug on
     // Android L. See https://android-review.googlesource.com/#/c/114932/ for the fix for Android
     // M.
-    return dest == right ? new MulFloat(dest, right, left) : new MulFloat(dest, left, right);
+    return dest == right ? new DexMulFloat(dest, right, left) : new DexMulFloat(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateDouble(int dest, int left, int right) {
+  public DexInstruction CreateDouble(int dest, int left, int right) {
     // Flip arguments if dest and right are the same to work around x86 code generation bug on
     // Android L. See https://android-review.googlesource.com/#/c/114932/ for the fix for Android
     // M.
-    return dest == right ? new MulDouble(dest, right, left) : new MulDouble(dest, left, right);
+    return dest == right
+        ? new DexMulDouble(dest, right, left)
+        : new DexMulDouble(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateInt2Addr(int left, int right) {
-    return new MulInt2Addr(left, right);
+  public DexInstruction CreateInt2Addr(int left, int right) {
+    return new DexMulInt2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateLong2Addr(int left, int right) {
-    return new MulLong2Addr(left, right);
+  public DexInstruction CreateLong2Addr(int left, int right) {
+    return new DexMulLong2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateFloat2Addr(int left, int right) {
-    return new MulFloat2Addr(left, right);
+  public DexInstruction CreateFloat2Addr(int left, int right) {
+    return new DexMulFloat2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateDouble2Addr(int left, int right) {
-    return new MulDouble2Addr(left, right);
+  public DexInstruction CreateDouble2Addr(int left, int right) {
+    return new DexMulDouble2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateIntLit8(int dest, int left, int constant) {
-    return new MulIntLit8(dest, left, constant);
+  public DexInstruction CreateIntLit8(int dest, int left, int constant) {
+    return new DexMulIntLit8(dest, left, constant);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateIntLit16(int dest, int left, int constant) {
-    return new MulIntLit16(dest, left, constant);
+  public DexInstruction CreateIntLit16(int dest, int left, int constant) {
+    return new DexMulIntLit16(dest, left, constant);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/Neg.java b/src/main/java/com/android/tools/r8/ir/code/Neg.java
index 459c8c5..dde52df 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Neg.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Neg.java
@@ -4,10 +4,11 @@
 package com.android.tools.r8.ir.code;
 
 import com.android.tools.r8.cf.code.CfNeg;
-import com.android.tools.r8.code.NegDouble;
-import com.android.tools.r8.code.NegFloat;
-import com.android.tools.r8.code.NegInt;
-import com.android.tools.r8.code.NegLong;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexNegDouble;
+import com.android.tools.r8.dex.code.DexNegFloat;
+import com.android.tools.r8.dex.code.DexNegInt;
+import com.android.tools.r8.dex.code.DexNegLong;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.ir.analysis.constant.Bottom;
 import com.android.tools.r8.ir.analysis.constant.ConstLatticeElement;
@@ -51,21 +52,21 @@
 
   @Override
   public void buildDex(DexBuilder builder) {
-    com.android.tools.r8.code.Instruction instruction;
+    DexInstruction instruction;
     int dest = builder.allocatedRegister(dest(), getNumber());
     int src = builder.allocatedRegister(source(), getNumber());
     switch (type) {
       case INT:
-        instruction = new NegInt(dest, src);
+        instruction = new DexNegInt(dest, src);
         break;
       case LONG:
-        instruction = new NegLong(dest, src);
+        instruction = new DexNegLong(dest, src);
         break;
       case FLOAT:
-        instruction = new NegFloat(dest, src);
+        instruction = new DexNegFloat(dest, src);
         break;
       case DOUBLE:
-        instruction = new NegDouble(dest, src);
+        instruction = new DexNegDouble(dest, src);
         break;
       default:
         throw new Unreachable("Unexpected type " + type);
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java b/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
index 500766c..88bd18d 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
@@ -6,8 +6,8 @@
 import com.android.tools.r8.cf.LoadStoreHelper;
 import com.android.tools.r8.cf.TypeVerificationHelper;
 import com.android.tools.r8.cf.code.CfNewArray;
-import com.android.tools.r8.code.NewArray;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexNewArray;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
@@ -59,7 +59,7 @@
   public void buildDex(DexBuilder builder) {
     int size = builder.allocatedRegister(size(), getNumber());
     int dest = builder.allocatedRegister(dest(), getNumber());
-    builder.add(this, new NewArray(dest, size, type));
+    builder.add(this, new DexNewArray(dest, size, type));
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java b/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java
index 260689f..15f7224 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java
@@ -4,9 +4,9 @@
 package com.android.tools.r8.ir.code;
 
 import com.android.tools.r8.cf.LoadStoreHelper;
-import com.android.tools.r8.code.FillArrayData;
-import com.android.tools.r8.code.FillArrayDataPayload;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexFillArrayData;
+import com.android.tools.r8.dex.code.DexFillArrayDataPayload;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
@@ -50,14 +50,14 @@
     return inValues.get(0);
   }
 
-  public FillArrayDataPayload createPayload() {
-    return new FillArrayDataPayload(element_width, size, data);
+  public DexFillArrayDataPayload createPayload() {
+    return new DexFillArrayDataPayload(element_width, size, data);
   }
 
   @Override
   public void buildDex(DexBuilder builder) {
     int src = builder.allocatedRegister(src(), getNumber());
-    builder.addFillArrayData(this, new FillArrayData(src));
+    builder.addFillArrayData(this, new DexFillArrayData(src));
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewInstance.java b/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
index 85bae5c..d6c938d 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.cf.TypeVerificationHelper;
 import com.android.tools.r8.cf.code.CfNew;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexNewInstance;
 import com.android.tools.r8.graph.AccessControl;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
@@ -68,7 +69,7 @@
   @Override
   public void buildDex(DexBuilder builder) {
     int dest = builder.allocatedRegister(dest(), getNumber());
-    builder.add(this, new com.android.tools.r8.code.NewInstance(dest, clazz));
+    builder.add(this, new DexNewInstance(dest, clazz));
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewUnboxedEnumInstance.java b/src/main/java/com/android/tools/r8/ir/code/NewUnboxedEnumInstance.java
index b56600f..2274754 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewUnboxedEnumInstance.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewUnboxedEnumInstance.java
@@ -6,8 +6,8 @@
 import com.android.tools.r8.cf.LoadStoreHelper;
 import com.android.tools.r8.cf.TypeVerificationHelper;
 import com.android.tools.r8.cf.code.CfNewUnboxedEnum;
-import com.android.tools.r8.code.DexNewUnboxedEnumInstance;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexNewUnboxedEnumInstance;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.ProgramMethod;
diff --git a/src/main/java/com/android/tools/r8/ir/code/Not.java b/src/main/java/com/android/tools/r8/ir/code/Not.java
index d000623..097ae22 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Not.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Not.java
@@ -4,8 +4,9 @@
 package com.android.tools.r8.ir.code;
 
 import com.android.tools.r8.cf.LoadStoreHelper;
-import com.android.tools.r8.code.NotInt;
-import com.android.tools.r8.code.NotLong;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexNotInt;
+import com.android.tools.r8.dex.code.DexNotLong;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.ir.analysis.constant.Bottom;
 import com.android.tools.r8.ir.analysis.constant.ConstLatticeElement;
@@ -62,15 +63,15 @@
   @Override
   public void buildDex(DexBuilder builder) {
     assert builder.getOptions().canUseNotInstruction();
-    com.android.tools.r8.code.Instruction instruction;
+    DexInstruction instruction;
     int dest = builder.allocatedRegister(dest(), getNumber());
     int src = builder.allocatedRegister(source(), getNumber());
     switch (type) {
       case INT:
-        instruction = new NotInt(dest, src);
+        instruction = new DexNotInt(dest, src);
         break;
       case LONG:
-        instruction = new NotLong(dest, src);
+        instruction = new DexNotLong(dest, src);
         break;
       default:
         throw new Unreachable("Unexpected type " + type);
diff --git a/src/main/java/com/android/tools/r8/ir/code/NumberConversion.java b/src/main/java/com/android/tools/r8/ir/code/NumberConversion.java
index 5f3b592..55ed123 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NumberConversion.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NumberConversion.java
@@ -4,21 +4,22 @@
 package com.android.tools.r8.ir.code;
 
 import com.android.tools.r8.cf.code.CfNumberConversion;
-import com.android.tools.r8.code.DoubleToFloat;
-import com.android.tools.r8.code.DoubleToInt;
-import com.android.tools.r8.code.DoubleToLong;
-import com.android.tools.r8.code.FloatToDouble;
-import com.android.tools.r8.code.FloatToInt;
-import com.android.tools.r8.code.FloatToLong;
-import com.android.tools.r8.code.IntToByte;
-import com.android.tools.r8.code.IntToChar;
-import com.android.tools.r8.code.IntToDouble;
-import com.android.tools.r8.code.IntToFloat;
-import com.android.tools.r8.code.IntToLong;
-import com.android.tools.r8.code.IntToShort;
-import com.android.tools.r8.code.LongToDouble;
-import com.android.tools.r8.code.LongToFloat;
-import com.android.tools.r8.code.LongToInt;
+import com.android.tools.r8.dex.code.DexDoubleToFloat;
+import com.android.tools.r8.dex.code.DexDoubleToInt;
+import com.android.tools.r8.dex.code.DexDoubleToLong;
+import com.android.tools.r8.dex.code.DexFloatToDouble;
+import com.android.tools.r8.dex.code.DexFloatToInt;
+import com.android.tools.r8.dex.code.DexFloatToLong;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexIntToByte;
+import com.android.tools.r8.dex.code.DexIntToChar;
+import com.android.tools.r8.dex.code.DexIntToDouble;
+import com.android.tools.r8.dex.code.DexIntToFloat;
+import com.android.tools.r8.dex.code.DexIntToLong;
+import com.android.tools.r8.dex.code.DexIntToShort;
+import com.android.tools.r8.dex.code.DexLongToDouble;
+import com.android.tools.r8.dex.code.DexLongToFloat;
+import com.android.tools.r8.dex.code.DexLongToInt;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.ir.analysis.type.PrimitiveTypeElement;
@@ -54,29 +55,29 @@
 
   @Override
   public void buildDex(DexBuilder builder) {
-    com.android.tools.r8.code.Instruction instruction;
+    DexInstruction instruction;
     int dest = builder.allocatedRegister(dest(), getNumber());
     int src = builder.allocatedRegister(source(), getNumber());
     switch (from) {
       case INT:
         switch (to) {
           case BYTE:
-            instruction = new IntToByte(dest, src);
+            instruction = new DexIntToByte(dest, src);
             break;
           case CHAR:
-            instruction = new IntToChar(dest, src);
+            instruction = new DexIntToChar(dest, src);
             break;
           case SHORT:
-            instruction = new IntToShort(dest, src);
+            instruction = new DexIntToShort(dest, src);
             break;
           case LONG:
-            instruction = new IntToLong(dest, src);
+            instruction = new DexIntToLong(dest, src);
             break;
           case FLOAT:
-            instruction = new IntToFloat(dest, src);
+            instruction = new DexIntToFloat(dest, src);
             break;
           case DOUBLE:
-            instruction = new IntToDouble(dest, src);
+            instruction = new DexIntToDouble(dest, src);
             break;
           default:
             throw new Unreachable("Unexpected types " + from + ", " + to);
@@ -85,13 +86,13 @@
       case LONG:
         switch (to) {
           case INT:
-            instruction = new LongToInt(dest, src);
+            instruction = new DexLongToInt(dest, src);
             break;
           case FLOAT:
-            instruction = new LongToFloat(dest, src);
+            instruction = new DexLongToFloat(dest, src);
             break;
           case DOUBLE:
-            instruction = new LongToDouble(dest, src);
+            instruction = new DexLongToDouble(dest, src);
             break;
           default:
             throw new Unreachable("Unexpected types " + from + ", " + to);
@@ -100,13 +101,13 @@
       case FLOAT:
         switch (to) {
           case INT:
-            instruction = new FloatToInt(dest, src);
+            instruction = new DexFloatToInt(dest, src);
             break;
           case LONG:
-            instruction = new FloatToLong(dest, src);
+            instruction = new DexFloatToLong(dest, src);
             break;
           case DOUBLE:
-            instruction = new FloatToDouble(dest, src);
+            instruction = new DexFloatToDouble(dest, src);
             break;
           default:
             throw new Unreachable("Unexpected types " + from + ", " + to);
@@ -115,13 +116,13 @@
       case DOUBLE:
         switch (to) {
           case INT:
-            instruction = new DoubleToInt(dest, src);
+            instruction = new DexDoubleToInt(dest, src);
             break;
           case LONG:
-            instruction = new DoubleToLong(dest, src);
+            instruction = new DexDoubleToLong(dest, src);
             break;
           case FLOAT:
-            instruction = new DoubleToFloat(dest, src);
+            instruction = new DexDoubleToFloat(dest, src);
             break;
           default:
             throw new Unreachable("Unexpected types " + from + ", " + to);
diff --git a/src/main/java/com/android/tools/r8/ir/code/Or.java b/src/main/java/com/android/tools/r8/ir/code/Or.java
index a17cb7f..3fd1a77 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Or.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Or.java
@@ -4,12 +4,13 @@
 package com.android.tools.r8.ir.code;
 
 import com.android.tools.r8.cf.code.CfLogicalBinop;
-import com.android.tools.r8.code.OrInt;
-import com.android.tools.r8.code.OrInt2Addr;
-import com.android.tools.r8.code.OrIntLit16;
-import com.android.tools.r8.code.OrIntLit8;
-import com.android.tools.r8.code.OrLong;
-import com.android.tools.r8.code.OrLong2Addr;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexOrInt;
+import com.android.tools.r8.dex.code.DexOrInt2Addr;
+import com.android.tools.r8.dex.code.DexOrIntLit16;
+import com.android.tools.r8.dex.code.DexOrIntLit8;
+import com.android.tools.r8.dex.code.DexOrLong;
+import com.android.tools.r8.dex.code.DexOrLong2Addr;
 import java.util.Set;
 
 public class Or extends LogicalBinop {
@@ -44,33 +45,33 @@
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateInt(int dest, int left, int right) {
-    return new OrInt(dest, left, right);
+  public DexInstruction CreateInt(int dest, int left, int right) {
+    return new DexOrInt(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateLong(int dest, int left, int right) {
-    return new OrLong(dest, left, right);
+  public DexInstruction CreateLong(int dest, int left, int right) {
+    return new DexOrLong(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateInt2Addr(int left, int right) {
-    return new OrInt2Addr(left, right);
+  public DexInstruction CreateInt2Addr(int left, int right) {
+    return new DexOrInt2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateLong2Addr(int left, int right) {
-    return new OrLong2Addr(left, right);
+  public DexInstruction CreateLong2Addr(int left, int right) {
+    return new DexOrLong2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateIntLit8(int dest, int left, int constant) {
-    return new OrIntLit8(dest, left, constant);
+  public DexInstruction CreateIntLit8(int dest, int left, int constant) {
+    return new DexOrIntLit8(dest, left, constant);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateIntLit16(int dest, int left, int constant) {
-    return new OrIntLit16(dest, left, constant);
+  public DexInstruction CreateIntLit16(int dest, int left, int constant) {
+    return new DexOrIntLit16(dest, left, constant);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/RecordFieldValues.java b/src/main/java/com/android/tools/r8/ir/code/RecordFieldValues.java
index a2949d0..db1cfaf 100644
--- a/src/main/java/com/android/tools/r8/ir/code/RecordFieldValues.java
+++ b/src/main/java/com/android/tools/r8/ir/code/RecordFieldValues.java
@@ -6,8 +6,8 @@
 
 import com.android.tools.r8.cf.LoadStoreHelper;
 import com.android.tools.r8.cf.code.CfRecordFieldValues;
-import com.android.tools.r8.code.DexRecordFieldValues;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexRecordFieldValues;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.ProgramMethod;
diff --git a/src/main/java/com/android/tools/r8/ir/code/Rem.java b/src/main/java/com/android/tools/r8/ir/code/Rem.java
index f6f40fa..df5ffc1 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Rem.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Rem.java
@@ -4,16 +4,17 @@
 package com.android.tools.r8.ir.code;
 
 import com.android.tools.r8.cf.code.CfArithmeticBinop;
-import com.android.tools.r8.code.RemDouble;
-import com.android.tools.r8.code.RemDouble2Addr;
-import com.android.tools.r8.code.RemFloat;
-import com.android.tools.r8.code.RemFloat2Addr;
-import com.android.tools.r8.code.RemInt;
-import com.android.tools.r8.code.RemInt2Addr;
-import com.android.tools.r8.code.RemIntLit16;
-import com.android.tools.r8.code.RemIntLit8;
-import com.android.tools.r8.code.RemLong;
-import com.android.tools.r8.code.RemLong2Addr;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexRemDouble;
+import com.android.tools.r8.dex.code.DexRemDouble2Addr;
+import com.android.tools.r8.dex.code.DexRemFloat;
+import com.android.tools.r8.dex.code.DexRemFloat2Addr;
+import com.android.tools.r8.dex.code.DexRemInt;
+import com.android.tools.r8.dex.code.DexRemInt2Addr;
+import com.android.tools.r8.dex.code.DexRemIntLit16;
+import com.android.tools.r8.dex.code.DexRemIntLit8;
+import com.android.tools.r8.dex.code.DexRemLong;
+import com.android.tools.r8.dex.code.DexRemLong2Addr;
 import com.android.tools.r8.ir.analysis.constant.Bottom;
 import com.android.tools.r8.ir.analysis.constant.LatticeElement;
 import java.util.function.Function;
@@ -50,53 +51,53 @@
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateInt(int dest, int left, int right) {
-    return new RemInt(dest, left, right);
+  public DexInstruction CreateInt(int dest, int left, int right) {
+    return new DexRemInt(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateLong(int dest, int left, int right) {
-    return new RemLong(dest, left, right);
+  public DexInstruction CreateLong(int dest, int left, int right) {
+    return new DexRemLong(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateFloat(int dest, int left, int right) {
-    return new RemFloat(dest, left, right);
+  public DexInstruction CreateFloat(int dest, int left, int right) {
+    return new DexRemFloat(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateDouble(int dest, int left, int right) {
-    return new RemDouble(dest, left, right);
+  public DexInstruction CreateDouble(int dest, int left, int right) {
+    return new DexRemDouble(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateInt2Addr(int left, int right) {
-    return new RemInt2Addr(left, right);
+  public DexInstruction CreateInt2Addr(int left, int right) {
+    return new DexRemInt2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateLong2Addr(int left, int right) {
-    return new RemLong2Addr(left, right);
+  public DexInstruction CreateLong2Addr(int left, int right) {
+    return new DexRemLong2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateFloat2Addr(int left, int right) {
-    return new RemFloat2Addr(left, right);
+  public DexInstruction CreateFloat2Addr(int left, int right) {
+    return new DexRemFloat2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateDouble2Addr(int left, int right) {
-    return new RemDouble2Addr(left, right);
+  public DexInstruction CreateDouble2Addr(int left, int right) {
+    return new DexRemDouble2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateIntLit8(int dest, int left, int constant) {
-    return new RemIntLit8(dest, left, constant);
+  public DexInstruction CreateIntLit8(int dest, int left, int constant) {
+    return new DexRemIntLit8(dest, left, constant);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateIntLit16(int dest, int left, int constant) {
-    return new RemIntLit16(dest, left, constant);
+  public DexInstruction CreateIntLit16(int dest, int left, int constant) {
+    return new DexRemIntLit16(dest, left, constant);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/Return.java b/src/main/java/com/android/tools/r8/ir/code/Return.java
index 1ec1a8e..752b30c 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Return.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Return.java
@@ -6,10 +6,12 @@
 import com.android.tools.r8.cf.LoadStoreHelper;
 import com.android.tools.r8.cf.code.CfReturn;
 import com.android.tools.r8.cf.code.CfReturnVoid;
-import com.android.tools.r8.code.ReturnObject;
-import com.android.tools.r8.code.ReturnVoid;
-import com.android.tools.r8.code.ReturnWide;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexReturn;
+import com.android.tools.r8.dex.code.DexReturnObject;
+import com.android.tools.r8.dex.code.DexReturnVoid;
+import com.android.tools.r8.dex.code.DexReturnWide;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
@@ -60,20 +62,20 @@
     return inValues.get(0);
   }
 
-  public com.android.tools.r8.code.Instruction createDexInstruction(DexBuilder builder) {
+  public DexInstruction createDexInstruction(DexBuilder builder) {
     if (isReturnVoid()) {
-      return new ReturnVoid();
+      return new DexReturnVoid();
     }
     int register = builder.allocatedRegister(returnValue(), getNumber());
     TypeElement returnType = getReturnType();
     if (returnType.isReferenceType()) {
-      return new ReturnObject(register);
+      return new DexReturnObject(register);
     }
     if (returnType.isSinglePrimitive()) {
-      return new com.android.tools.r8.code.Return(register);
+      return new DexReturn(register);
     }
     if (returnType.isWidePrimitive()) {
-      return new ReturnWide(register);
+      return new DexReturnWide(register);
     }
     throw new Unreachable();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/SafeCheckCast.java b/src/main/java/com/android/tools/r8/ir/code/SafeCheckCast.java
index b811f86..1aee996 100644
--- a/src/main/java/com/android/tools/r8/ir/code/SafeCheckCast.java
+++ b/src/main/java/com/android/tools/r8/ir/code/SafeCheckCast.java
@@ -5,6 +5,8 @@
 package com.android.tools.r8.ir.code;
 
 import com.android.tools.r8.cf.code.CfSafeCheckCast;
+import com.android.tools.r8.dex.code.DexCheckCast;
+import com.android.tools.r8.dex.code.DexSafeCheckCast;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -26,8 +28,8 @@
   }
 
   @Override
-  com.android.tools.r8.code.CheckCast createCheckCast(int register) {
-    return new com.android.tools.r8.code.SafeCheckCast(register, getType());
+  DexCheckCast createCheckCast(int register) {
+    return new DexSafeCheckCast(register, getType());
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/Shl.java b/src/main/java/com/android/tools/r8/ir/code/Shl.java
index b297552..d18262a 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Shl.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Shl.java
@@ -4,11 +4,12 @@
 package com.android.tools.r8.ir.code;
 
 import com.android.tools.r8.cf.code.CfLogicalBinop;
-import com.android.tools.r8.code.ShlInt;
-import com.android.tools.r8.code.ShlInt2Addr;
-import com.android.tools.r8.code.ShlIntLit8;
-import com.android.tools.r8.code.ShlLong;
-import com.android.tools.r8.code.ShlLong2Addr;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexShlInt;
+import com.android.tools.r8.dex.code.DexShlInt2Addr;
+import com.android.tools.r8.dex.code.DexShlIntLit8;
+import com.android.tools.r8.dex.code.DexShlLong;
+import com.android.tools.r8.dex.code.DexShlLong2Addr;
 import com.android.tools.r8.errors.Unreachable;
 
 public class Shl extends LogicalBinop {
@@ -49,32 +50,32 @@
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateInt(int dest, int left, int right) {
-    return new ShlInt(dest, left, right);
+  public DexInstruction CreateInt(int dest, int left, int right) {
+    return new DexShlInt(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateLong(int dest, int left, int right) {
-    return new ShlLong(dest, left, right);
+  public DexInstruction CreateLong(int dest, int left, int right) {
+    return new DexShlLong(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateInt2Addr(int left, int right) {
-    return new ShlInt2Addr(left, right);
+  public DexInstruction CreateInt2Addr(int left, int right) {
+    return new DexShlInt2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateLong2Addr(int left, int right) {
-    return new ShlLong2Addr(left, right);
+  public DexInstruction CreateLong2Addr(int left, int right) {
+    return new DexShlLong2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateIntLit8(int dest, int left, int constant) {
-    return new ShlIntLit8(dest, left, constant);
+  public DexInstruction CreateIntLit8(int dest, int left, int constant) {
+    return new DexShlIntLit8(dest, left, constant);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateIntLit16(int dest, int left, int constant) {
+  public DexInstruction CreateIntLit16(int dest, int left, int constant) {
     throw new Unreachable("Unsupported instruction ShlIntLit16");
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/Shr.java b/src/main/java/com/android/tools/r8/ir/code/Shr.java
index 36ff98b..5a93057 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Shr.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Shr.java
@@ -4,11 +4,12 @@
 package com.android.tools.r8.ir.code;
 
 import com.android.tools.r8.cf.code.CfLogicalBinop;
-import com.android.tools.r8.code.ShrInt;
-import com.android.tools.r8.code.ShrInt2Addr;
-import com.android.tools.r8.code.ShrIntLit8;
-import com.android.tools.r8.code.ShrLong;
-import com.android.tools.r8.code.ShrLong2Addr;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexShrInt;
+import com.android.tools.r8.dex.code.DexShrInt2Addr;
+import com.android.tools.r8.dex.code.DexShrIntLit8;
+import com.android.tools.r8.dex.code.DexShrLong;
+import com.android.tools.r8.dex.code.DexShrLong2Addr;
 import com.android.tools.r8.errors.Unreachable;
 
 public class Shr extends LogicalBinop {
@@ -49,32 +50,32 @@
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateInt(int dest, int left, int right) {
-    return new ShrInt(dest, left, right);
+  public DexInstruction CreateInt(int dest, int left, int right) {
+    return new DexShrInt(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateLong(int dest, int left, int right) {
-    return new ShrLong(dest, left, right);
+  public DexInstruction CreateLong(int dest, int left, int right) {
+    return new DexShrLong(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateInt2Addr(int left, int right) {
-    return new ShrInt2Addr(left, right);
+  public DexInstruction CreateInt2Addr(int left, int right) {
+    return new DexShrInt2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateLong2Addr(int left, int right) {
-    return new ShrLong2Addr(left, right);
+  public DexInstruction CreateLong2Addr(int left, int right) {
+    return new DexShrLong2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateIntLit8(int dest, int left, int constant) {
-    return new ShrIntLit8(dest, left, constant);
+  public DexInstruction CreateIntLit8(int dest, int left, int constant) {
+    return new DexShrIntLit8(dest, left, constant);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateIntLit16(int dest, int left, int constant) {
+  public DexInstruction CreateIntLit16(int dest, int left, int constant) {
     throw new Unreachable("Unsupported instruction ShrIntLit16");
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/StaticGet.java b/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
index c4413d0..a078dde 100644
--- a/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
+++ b/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
@@ -6,14 +6,15 @@
 import com.android.tools.r8.cf.LoadStoreHelper;
 import com.android.tools.r8.cf.TypeVerificationHelper;
 import com.android.tools.r8.cf.code.CfStaticFieldRead;
-import com.android.tools.r8.code.Sget;
-import com.android.tools.r8.code.SgetBoolean;
-import com.android.tools.r8.code.SgetByte;
-import com.android.tools.r8.code.SgetChar;
-import com.android.tools.r8.code.SgetObject;
-import com.android.tools.r8.code.SgetShort;
-import com.android.tools.r8.code.SgetWide;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexSget;
+import com.android.tools.r8.dex.code.DexSgetBoolean;
+import com.android.tools.r8.dex.code.DexSgetByte;
+import com.android.tools.r8.dex.code.DexSgetChar;
+import com.android.tools.r8.dex.code.DexSgetObject;
+import com.android.tools.r8.dex.code.DexSgetShort;
+import com.android.tools.r8.dex.code.DexSgetWide;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClassAndField;
@@ -97,32 +98,32 @@
 
   @Override
   public void buildDex(DexBuilder builder) {
-    com.android.tools.r8.code.Instruction instruction;
+    DexInstruction instruction;
     int dest = builder.allocatedRegister(dest(), getNumber());
     DexField field = getField();
     switch (getType()) {
       case INT:
       case FLOAT:
-        instruction = new Sget(dest, field);
+        instruction = new DexSget(dest, field);
         break;
       case LONG:
       case DOUBLE:
-        instruction = new SgetWide(dest, field);
+        instruction = new DexSgetWide(dest, field);
         break;
       case OBJECT:
-        instruction = new SgetObject(dest, field);
+        instruction = new DexSgetObject(dest, field);
         break;
       case BOOLEAN:
-        instruction = new SgetBoolean(dest, field);
+        instruction = new DexSgetBoolean(dest, field);
         break;
       case BYTE:
-        instruction = new SgetByte(dest, field);
+        instruction = new DexSgetByte(dest, field);
         break;
       case CHAR:
-        instruction = new SgetChar(dest, field);
+        instruction = new DexSgetChar(dest, field);
         break;
       case SHORT:
-        instruction = new SgetShort(dest, field);
+        instruction = new DexSgetShort(dest, field);
         break;
       default:
         throw new Unreachable("Unexpected type: " + getType());
diff --git a/src/main/java/com/android/tools/r8/ir/code/StaticPut.java b/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
index b28f281..7d54dbb 100644
--- a/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
@@ -5,14 +5,15 @@
 
 import com.android.tools.r8.cf.LoadStoreHelper;
 import com.android.tools.r8.cf.code.CfStaticFieldWrite;
-import com.android.tools.r8.code.Sput;
-import com.android.tools.r8.code.SputBoolean;
-import com.android.tools.r8.code.SputByte;
-import com.android.tools.r8.code.SputChar;
-import com.android.tools.r8.code.SputObject;
-import com.android.tools.r8.code.SputShort;
-import com.android.tools.r8.code.SputWide;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexSput;
+import com.android.tools.r8.dex.code.DexSputBoolean;
+import com.android.tools.r8.dex.code.DexSputByte;
+import com.android.tools.r8.dex.code.DexSputChar;
+import com.android.tools.r8.dex.code.DexSputObject;
+import com.android.tools.r8.dex.code.DexSputShort;
+import com.android.tools.r8.dex.code.DexSputWide;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedField;
@@ -65,32 +66,32 @@
 
   @Override
   public void buildDex(DexBuilder builder) {
-    com.android.tools.r8.code.Instruction instruction;
+    DexInstruction instruction;
     int src = builder.allocatedRegister(value(), getNumber());
     DexField field = getField();
     switch (getType()) {
       case INT:
       case FLOAT:
-        instruction = new Sput(src, field);
+        instruction = new DexSput(src, field);
         break;
       case LONG:
       case DOUBLE:
-        instruction = new SputWide(src, field);
+        instruction = new DexSputWide(src, field);
         break;
       case OBJECT:
-        instruction = new SputObject(src, field);
+        instruction = new DexSputObject(src, field);
         break;
       case BOOLEAN:
-        instruction = new SputBoolean(src, field);
+        instruction = new DexSputBoolean(src, field);
         break;
       case BYTE:
-        instruction = new SputByte(src, field);
+        instruction = new DexSputByte(src, field);
         break;
       case CHAR:
-        instruction = new SputChar(src, field);
+        instruction = new DexSputChar(src, field);
         break;
       case SHORT:
-        instruction = new SputShort(src, field);
+        instruction = new DexSputShort(src, field);
         break;
       default:
         throw new Unreachable("Unexpected type: " + getType());
diff --git a/src/main/java/com/android/tools/r8/ir/code/Sub.java b/src/main/java/com/android/tools/r8/ir/code/Sub.java
index e161b8e..fab70d7 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Sub.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Sub.java
@@ -5,19 +5,20 @@
 package com.android.tools.r8.ir.code;
 
 import com.android.tools.r8.cf.code.CfArithmeticBinop;
-import com.android.tools.r8.code.AddIntLit16;
-import com.android.tools.r8.code.AddIntLit8;
-import com.android.tools.r8.code.RsubInt;
-import com.android.tools.r8.code.RsubIntLit8;
-import com.android.tools.r8.code.SubDouble;
-import com.android.tools.r8.code.SubDouble2Addr;
-import com.android.tools.r8.code.SubFloat;
-import com.android.tools.r8.code.SubFloat2Addr;
-import com.android.tools.r8.code.SubInt;
-import com.android.tools.r8.code.SubInt2Addr;
-import com.android.tools.r8.code.SubLong;
-import com.android.tools.r8.code.SubLong2Addr;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexAddIntLit16;
+import com.android.tools.r8.dex.code.DexAddIntLit8;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexRsubInt;
+import com.android.tools.r8.dex.code.DexRsubIntLit8;
+import com.android.tools.r8.dex.code.DexSubDouble;
+import com.android.tools.r8.dex.code.DexSubDouble2Addr;
+import com.android.tools.r8.dex.code.DexSubFloat;
+import com.android.tools.r8.dex.code.DexSubFloat2Addr;
+import com.android.tools.r8.dex.code.DexSubInt;
+import com.android.tools.r8.dex.code.DexSubInt2Addr;
+import com.android.tools.r8.dex.code.DexSubLong;
+import com.android.tools.r8.dex.code.DexSubLong2Addr;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.ir.conversion.DexBuilder;
 
@@ -43,53 +44,53 @@
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateInt(int dest, int left, int right) {
-    return new SubInt(dest, left, right);
+  public DexInstruction CreateInt(int dest, int left, int right) {
+    return new DexSubInt(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateLong(int dest, int left, int right) {
-    return new SubLong(dest, left, right);
+  public DexInstruction CreateLong(int dest, int left, int right) {
+    return new DexSubLong(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateFloat(int dest, int left, int right) {
-    return new SubFloat(dest, left, right);
+  public DexInstruction CreateFloat(int dest, int left, int right) {
+    return new DexSubFloat(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateDouble(int dest, int left, int right) {
-    return new SubDouble(dest, left, right);
+  public DexInstruction CreateDouble(int dest, int left, int right) {
+    return new DexSubDouble(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateInt2Addr(int left, int right) {
-    return new SubInt2Addr(left, right);
+  public DexInstruction CreateInt2Addr(int left, int right) {
+    return new DexSubInt2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateLong2Addr(int left, int right) {
-    return new SubLong2Addr(left, right);
+  public DexInstruction CreateLong2Addr(int left, int right) {
+    return new DexSubLong2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateFloat2Addr(int left, int right) {
-    return new SubFloat2Addr(left, right);
+  public DexInstruction CreateFloat2Addr(int left, int right) {
+    return new DexSubFloat2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateDouble2Addr(int left, int right) {
-    return new SubDouble2Addr(left, right);
+  public DexInstruction CreateDouble2Addr(int left, int right) {
+    return new DexSubDouble2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateIntLit8(int dest, int left, int constant) {
+  public DexInstruction CreateIntLit8(int dest, int left, int constant) {
     // The sub instructions with constants are rsub, and is handled below.
     throw new Unreachable("Unsupported instruction SubIntLit8");
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateIntLit16(int dest, int left, int constant) {
+  public DexInstruction CreateIntLit16(int dest, int left, int constant) {
     // The sub instructions with constants are rsub, and is handled below.
     throw new Unreachable("Unsupported instruction SubIntLit16");
   }
@@ -166,7 +167,7 @@
       return;
     }
 
-    com.android.tools.r8.code.Instruction instruction = null;
+    DexInstruction instruction = null;
     if (!needsValueInRegister(leftValue())) {
       // Sub instructions with small left constant is emitted as rsub.
       assert fitsInDexInstruction(leftValue());
@@ -174,10 +175,10 @@
       int right = builder.allocatedRegister(rightValue(), getNumber());
       int dest = builder.allocatedRegister(outValue, getNumber());
       if (left.is8Bit()) {
-        instruction = new RsubIntLit8(dest, right, left.getIntValue());
+        instruction = new DexRsubIntLit8(dest, right, left.getIntValue());
       } else {
         assert left.is16Bit();
-        instruction = new RsubInt(dest, right, left.getIntValue());
+        instruction = new DexRsubInt(dest, right, left.getIntValue());
       }
     } else if (!needsValueInRegister(rightValue())) {
       // Sub instructions with small right constant are emitted as add of the negative constant.
@@ -187,10 +188,10 @@
       int left = builder.allocatedRegister(leftValue(), getNumber());
       ConstNumber right = rightValue().getConstInstruction().asConstNumber();
       if (right.negativeIs8Bit()) {
-        instruction = new AddIntLit8(dest, left, -right.getIntValue());
+        instruction = new DexAddIntLit8(dest, left, -right.getIntValue());
       } else {
         assert right.negativeIs16Bit();
-        instruction = new AddIntLit16(dest, left, -right.getIntValue());
+        instruction = new DexAddIntLit16(dest, left, -right.getIntValue());
       }
     } else {
       assert type == NumericType.INT;
diff --git a/src/main/java/com/android/tools/r8/ir/code/Throw.java b/src/main/java/com/android/tools/r8/ir/code/Throw.java
index 6350255..7968409 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Throw.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Throw.java
@@ -6,6 +6,7 @@
 import com.android.tools.r8.cf.LoadStoreHelper;
 import com.android.tools.r8.cf.code.CfThrow;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexThrow;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
@@ -36,7 +37,7 @@
 
   @Override
   public void buildDex(DexBuilder builder) {
-    builder.add(this, new com.android.tools.r8.code.Throw(builder.allocatedRegister(exception(), getNumber())));
+    builder.add(this, new DexThrow(builder.allocatedRegister(exception(), getNumber())));
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/Ushr.java b/src/main/java/com/android/tools/r8/ir/code/Ushr.java
index 5de1830..4ea3be9 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Ushr.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Ushr.java
@@ -4,11 +4,12 @@
 package com.android.tools.r8.ir.code;
 
 import com.android.tools.r8.cf.code.CfLogicalBinop;
-import com.android.tools.r8.code.UshrInt;
-import com.android.tools.r8.code.UshrInt2Addr;
-import com.android.tools.r8.code.UshrIntLit8;
-import com.android.tools.r8.code.UshrLong;
-import com.android.tools.r8.code.UshrLong2Addr;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexUshrInt;
+import com.android.tools.r8.dex.code.DexUshrInt2Addr;
+import com.android.tools.r8.dex.code.DexUshrIntLit8;
+import com.android.tools.r8.dex.code.DexUshrLong;
+import com.android.tools.r8.dex.code.DexUshrLong2Addr;
 import com.android.tools.r8.errors.Unreachable;
 
 public class Ushr extends LogicalBinop {
@@ -49,32 +50,32 @@
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateInt(int dest, int left, int right) {
-    return new UshrInt(dest, left, right);
+  public DexInstruction CreateInt(int dest, int left, int right) {
+    return new DexUshrInt(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateLong(int dest, int left, int right) {
-    return new UshrLong(dest, left, right);
+  public DexInstruction CreateLong(int dest, int left, int right) {
+    return new DexUshrLong(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateInt2Addr(int left, int right) {
-    return new UshrInt2Addr(left, right);
+  public DexInstruction CreateInt2Addr(int left, int right) {
+    return new DexUshrInt2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateLong2Addr(int left, int right) {
-    return new UshrLong2Addr(left, right);
+  public DexInstruction CreateLong2Addr(int left, int right) {
+    return new DexUshrLong2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateIntLit8(int dest, int left, int constant) {
-    return new UshrIntLit8(dest, left, constant);
+  public DexInstruction CreateIntLit8(int dest, int left, int constant) {
+    return new DexUshrIntLit8(dest, left, constant);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateIntLit16(int dest, int left, int constant) {
+  public DexInstruction CreateIntLit16(int dest, int left, int constant) {
     throw new Unreachable("Unsupported instruction ShrIntLit16");
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/Xor.java b/src/main/java/com/android/tools/r8/ir/code/Xor.java
index dce5686..657374a 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Xor.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Xor.java
@@ -4,12 +4,13 @@
 package com.android.tools.r8.ir.code;
 
 import com.android.tools.r8.cf.code.CfLogicalBinop;
-import com.android.tools.r8.code.XorInt;
-import com.android.tools.r8.code.XorInt2Addr;
-import com.android.tools.r8.code.XorIntLit16;
-import com.android.tools.r8.code.XorIntLit8;
-import com.android.tools.r8.code.XorLong;
-import com.android.tools.r8.code.XorLong2Addr;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexXorInt;
+import com.android.tools.r8.dex.code.DexXorInt2Addr;
+import com.android.tools.r8.dex.code.DexXorIntLit16;
+import com.android.tools.r8.dex.code.DexXorIntLit8;
+import com.android.tools.r8.dex.code.DexXorLong;
+import com.android.tools.r8.dex.code.DexXorLong2Addr;
 import java.util.Set;
 
 public class Xor extends LogicalBinop {
@@ -44,33 +45,33 @@
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateInt(int dest, int left, int right) {
-    return new XorInt(dest, left, right);
+  public DexInstruction CreateInt(int dest, int left, int right) {
+    return new DexXorInt(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateLong(int dest, int left, int right) {
-    return new XorLong(dest, left, right);
+  public DexInstruction CreateLong(int dest, int left, int right) {
+    return new DexXorLong(dest, left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateInt2Addr(int left, int right) {
-    return new XorInt2Addr(left, right);
+  public DexInstruction CreateInt2Addr(int left, int right) {
+    return new DexXorInt2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateLong2Addr(int left, int right) {
-    return new XorLong2Addr(left, right);
+  public DexInstruction CreateLong2Addr(int left, int right) {
+    return new DexXorLong2Addr(left, right);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateIntLit8(int dest, int left, int constant) {
-    return new XorIntLit8(dest, left, constant);
+  public DexInstruction CreateIntLit8(int dest, int left, int constant) {
+    return new DexXorIntLit8(dest, left, constant);
   }
 
   @Override
-  public com.android.tools.r8.code.Instruction CreateIntLit16(int dest, int left, int constant) {
-    return new XorIntLit16(dest, left, constant);
+  public DexInstruction CreateIntLit16(int dest, int left, int constant) {
+    return new DexXorIntLit16(dest, left, constant);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/ArrayFilledDataPayloadResolver.java b/src/main/java/com/android/tools/r8/ir/conversion/ArrayFilledDataPayloadResolver.java
index 4f91695..739fb9f 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/ArrayFilledDataPayloadResolver.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/ArrayFilledDataPayloadResolver.java
@@ -4,8 +4,8 @@
 
 package com.android.tools.r8.ir.conversion;
 
-import com.android.tools.r8.code.FillArrayData;
-import com.android.tools.r8.code.FillArrayDataPayload;
+import com.android.tools.r8.dex.code.DexFillArrayData;
+import com.android.tools.r8.dex.code.DexFillArrayDataPayload;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -20,21 +20,21 @@
     public short[] data;
   }
 
-  private final Map<Integer, FillArrayDataPayload> unresolvedPayload = new HashMap<>();
+  private final Map<Integer, DexFillArrayDataPayload> unresolvedPayload = new HashMap<>();
   private final Map<Integer, PayloadData> payloadToData = new HashMap<>();
 
-  public void addPayloadUser(FillArrayData dex) {
+  public void addPayloadUser(DexFillArrayData dex) {
     int offset = dex.getOffset();
     int payloadOffset = offset + dex.getPayloadOffset();
     assert !payloadToData.containsKey(payloadOffset);
     payloadToData.put(payloadOffset, new PayloadData());
     if (unresolvedPayload.containsKey(payloadOffset)) {
-      FillArrayDataPayload payload = unresolvedPayload.remove(payloadOffset);
+      DexFillArrayDataPayload payload = unresolvedPayload.remove(payloadOffset);
       resolve(payload);
     }
   }
 
-  public void resolve(FillArrayDataPayload payload) {
+  public void resolve(DexFillArrayDataPayload payload) {
     int payloadOffset = payload.getOffset();
     PayloadData data = payloadToData.get(payloadOffset);
     if (data == null) {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java
index de631d3..201c789 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java
@@ -3,37 +3,38 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.conversion;
 
-import com.android.tools.r8.code.FillArrayData;
-import com.android.tools.r8.code.FillArrayDataPayload;
-import com.android.tools.r8.code.Format31t;
-import com.android.tools.r8.code.Goto;
-import com.android.tools.r8.code.Goto16;
-import com.android.tools.r8.code.Goto32;
-import com.android.tools.r8.code.IfEq;
-import com.android.tools.r8.code.IfEqz;
-import com.android.tools.r8.code.IfGe;
-import com.android.tools.r8.code.IfGez;
-import com.android.tools.r8.code.IfGt;
-import com.android.tools.r8.code.IfGtz;
-import com.android.tools.r8.code.IfLe;
-import com.android.tools.r8.code.IfLez;
-import com.android.tools.r8.code.IfLt;
-import com.android.tools.r8.code.IfLtz;
-import com.android.tools.r8.code.IfNe;
-import com.android.tools.r8.code.IfNez;
-import com.android.tools.r8.code.InstanceOf;
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.Move16;
-import com.android.tools.r8.code.MoveFrom16;
-import com.android.tools.r8.code.MoveObject;
-import com.android.tools.r8.code.MoveObject16;
-import com.android.tools.r8.code.MoveObjectFrom16;
-import com.android.tools.r8.code.MoveWide;
-import com.android.tools.r8.code.MoveWide16;
-import com.android.tools.r8.code.MoveWideFrom16;
-import com.android.tools.r8.code.Nop;
-import com.android.tools.r8.code.Throw;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexFillArrayData;
+import com.android.tools.r8.dex.code.DexFillArrayDataPayload;
+import com.android.tools.r8.dex.code.DexFormat31t;
+import com.android.tools.r8.dex.code.DexGoto;
+import com.android.tools.r8.dex.code.DexGoto16;
+import com.android.tools.r8.dex.code.DexGoto32;
+import com.android.tools.r8.dex.code.DexIfEq;
+import com.android.tools.r8.dex.code.DexIfEqz;
+import com.android.tools.r8.dex.code.DexIfGe;
+import com.android.tools.r8.dex.code.DexIfGez;
+import com.android.tools.r8.dex.code.DexIfGt;
+import com.android.tools.r8.dex.code.DexIfGtz;
+import com.android.tools.r8.dex.code.DexIfLe;
+import com.android.tools.r8.dex.code.DexIfLez;
+import com.android.tools.r8.dex.code.DexIfLt;
+import com.android.tools.r8.dex.code.DexIfLtz;
+import com.android.tools.r8.dex.code.DexIfNe;
+import com.android.tools.r8.dex.code.DexIfNez;
+import com.android.tools.r8.dex.code.DexInstanceOf;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexMove;
+import com.android.tools.r8.dex.code.DexMove16;
+import com.android.tools.r8.dex.code.DexMoveFrom16;
+import com.android.tools.r8.dex.code.DexMoveObject;
+import com.android.tools.r8.dex.code.DexMoveObject16;
+import com.android.tools.r8.dex.code.DexMoveObjectFrom16;
+import com.android.tools.r8.dex.code.DexMoveWide;
+import com.android.tools.r8.dex.code.DexMoveWide16;
+import com.android.tools.r8.dex.code.DexMoveWideFrom16;
+import com.android.tools.r8.dex.code.DexNop;
+import com.android.tools.r8.dex.code.DexThrow;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DebugLocalInfo;
 import com.android.tools.r8.graph.DexCode;
@@ -86,7 +87,7 @@
   private final IRCode ir;
 
   // Extra information that should be attached to the bytecode instructions.
-  private final BytecodeMetadata.Builder<Instruction> bytecodeMetadataBuilder;
+  private final BytecodeMetadata.Builder<DexInstruction> bytecodeMetadataBuilder;
 
   // The register allocator providing register assignments for the code to build.
   private final RegisterAllocator registerAllocator;
@@ -236,7 +237,7 @@
 
     // Build instructions.
     DexDebugEventBuilder debugEventBuilder = new DexDebugEventBuilder(ir, options);
-    List<Instruction> dexInstructions = new ArrayList<>(numberOfInstructions);
+    List<DexInstruction> dexInstructions = new ArrayList<>(numberOfInstructions);
     int instructionOffset = 0;
     for (com.android.tools.r8.ir.code.Instruction irInstruction : ir.instructions()) {
       Info info = getInfo(irInstruction);
@@ -244,7 +245,7 @@
       info.addInstructions(this, dexInstructions);
       int instructionStartOffset = instructionOffset;
       while (previousInstructionCount < dexInstructions.size()) {
-        Instruction dexInstruction = dexInstructions.get(previousInstructionCount++);
+        DexInstruction dexInstruction = dexInstructions.get(previousInstructionCount++);
         dexInstruction.setOffset(instructionOffset);
         instructionOffset += dexInstruction.getSize();
       }
@@ -257,7 +258,7 @@
     // We could have also changed the block order, however, moving the throwing block higher
     // led to larger code in all experiments (multiple gmscore version and R8 run on itself).
     if (options.canHaveTracingPastInstructionsStreamBug()
-        && dexInstructions.get(dexInstructions.size() - 1) instanceof Throw
+        && dexInstructions.get(dexInstructions.size() - 1) instanceof DexThrow
         && hasBackwardsBranch) {
       // This is the last in a series of different workarounds tried out.
       // Having an empty non reachable loop make some mediatek vms crash: b/119895393
@@ -275,12 +276,12 @@
       // That way we have no unreachable code, and we never end in a throw. The tracer will still
       // trace to the throw, but after moving to the second goto it will trace back again and see
       // an instruction it has already seen.
-      Instruction throwInstruction = dexInstructions.get(dexInstructions.size() -1);
+      DexInstruction throwInstruction = dexInstructions.get(dexInstructions.size() - 1);
       offset = throwInstruction.getOffset();
 
       // Generate the new forward and backward gotos, update offsets.
-      Instruction forward = new Goto(throwInstruction.getSize() + Goto.SIZE);
-      Instruction backward = new Goto(-throwInstruction.getSize());
+      DexInstruction forward = new DexGoto(throwInstruction.getSize() + DexGoto.SIZE);
+      DexInstruction backward = new DexGoto(-throwInstruction.getSize());
       forward.setOffset(offset);
       offset += forward.getSize();
       throwInstruction.setOffset(offset);
@@ -298,12 +299,12 @@
     for (SwitchPayloadInfo switchPayloadInfo : switchPayloadInfos) {
       // Align payloads at even addresses.
       if (offset % 2 != 0) {
-        Nop nop = new Nop();
+        DexNop nop = new DexNop();
         nop.setOffset(offset++);
         dexInstructions.add(nop);
       }
       // Create payload and add it to the instruction stream.
-      Nop payload = createSwitchPayload(switchPayloadInfo, offset);
+      DexNop payload = createSwitchPayload(switchPayloadInfo, offset);
       payload.setOffset(offset);
       offset += payload.getSize();
       dexInstructions.add(payload);
@@ -313,12 +314,12 @@
     for (FillArrayDataInfo info : fillArrayDataInfos) {
       // Align payloads at even addresses.
       if (offset % 2 != 0) {
-        Nop nop = new Nop();
+        DexNop nop = new DexNop();
         nop.setOffset(offset++);
         dexInstructions.add(nop);
       }
       // Create payload and add it to the instruction stream.
-      FillArrayDataPayload payload = info.ir.createPayload();
+      DexFillArrayDataPayload payload = info.ir.createPayload();
       payload.setOffset(offset);
       info.dex.setPayloadOffset(offset - info.dex.getOffset());
       offset += payload.getSize();
@@ -334,7 +335,7 @@
             registerAllocator.registersUsed(),
             inRegisterCount,
             outRegisterCount,
-            dexInstructions.toArray(Instruction.EMPTY_ARRAY),
+            dexInstructions.toArray(DexInstruction.EMPTY_ARRAY),
             tryInfo.tries,
             tryInfo.handlers,
             debugEventBuilder.build(),
@@ -584,7 +585,7 @@
     }
   }
 
-  private boolean needsNopBetweenMoveAndInstanceOf(InstanceOf instanceOf) {
+  private boolean needsNopBetweenMoveAndInstanceOf(DexInstanceOf instanceOf) {
     if (!options.canHaveArtInstanceOfVerifierBug()) {
       return false;
     }
@@ -608,9 +609,9 @@
     return false;
   }
 
-  public void addInstanceOf(com.android.tools.r8.ir.code.InstanceOf ir, InstanceOf instanceOf) {
+  public void addInstanceOf(com.android.tools.r8.ir.code.InstanceOf ir, DexInstanceOf instanceOf) {
     if (needsNopBetweenMoveAndInstanceOf(instanceOf)) {
-      add(ir, new Nop(), instanceOf);
+      add(ir, new DexNop(), instanceOf);
     } else {
       add(ir, instanceOf);
     }
@@ -645,7 +646,7 @@
   }
 
   public void addNop(com.android.tools.r8.ir.code.Instruction ir) {
-    add(ir, new FixedSizeInfo(ir, new Nop()));
+    add(ir, new FixedSizeInfo(ir, new DexNop()));
   }
 
   public void addDebugPosition(DebugPosition position) {
@@ -654,24 +655,24 @@
     addNop(position);
   }
 
-  public void add(com.android.tools.r8.ir.code.Instruction instr, Instruction dex) {
+  public void add(com.android.tools.r8.ir.code.Instruction instr, DexInstruction dex) {
     assert !instr.isGoto();
     add(instr, new FixedSizeInfo(instr, dex));
     bytecodeMetadataBuilder.setMetadata(instr, dex);
   }
 
-  public void add(com.android.tools.r8.ir.code.Instruction ir, Instruction... dex) {
+  public void add(com.android.tools.r8.ir.code.Instruction ir, DexInstruction... dex) {
     assert !ir.isGoto();
     add(ir, new MultiFixedSizeInfo(ir, dex));
   }
 
-  public void addSwitch(IntSwitch s, Format31t dex) {
+  public void addSwitch(IntSwitch s, DexFormat31t dex) {
     assert nextBlock == s.fallthroughBlock();
     switchPayloadInfos.add(new SwitchPayloadInfo(s, dex));
     add(s, dex);
   }
 
-  public void addFillArrayData(NewArrayFilledData nafd, FillArrayData dex) {
+  public void addFillArrayData(NewArrayFilledData nafd, DexFillArrayData dex) {
     fillArrayDataInfos.add(new FillArrayDataInfo(nafd, dex));
     add(nafd, dex);
   }
@@ -681,7 +682,7 @@
     add(argument, new FallThroughInfo(argument));
   }
 
-  public void addReturn(Return ret, Instruction dex) {
+  public void addReturn(Return ret, DexInstruction dex) {
     if (nextBlock != null
         && ret.identicalAfterRegisterAllocation(
             nextBlock.entry(), registerAllocator, conversionOptions)) {
@@ -759,7 +760,7 @@
   }
 
   // Helper for computing switch payloads.
-  private Nop createSwitchPayload(SwitchPayloadInfo info, int offset) {
+  private DexNop createSwitchPayload(SwitchPayloadInfo info, int offset) {
     IntSwitch ir = info.ir;
     // Patch the payload offset in the generated switch instruction now
     // that the location is known.
@@ -951,7 +952,7 @@
 
     // Materialize the actual construction.
     // All instruction offsets are known at this point.
-    public abstract void addInstructions(DexBuilder builder, List<Instruction> instructions);
+    public abstract void addInstructions(DexBuilder builder, List<DexInstruction> instructions);
 
     // Lower bound on the size of the instruction.
     public abstract int minSize();
@@ -1000,9 +1001,9 @@
 
   private static class FixedSizeInfo extends Info {
 
-    private final Instruction instruction;
+    private final DexInstruction instruction;
 
-    public FixedSizeInfo(com.android.tools.r8.ir.code.Instruction ir, Instruction instruction) {
+    public FixedSizeInfo(com.android.tools.r8.ir.code.Instruction ir, DexInstruction instruction) {
       super(ir);
       this.instruction = instruction;
     }
@@ -1029,7 +1030,7 @@
     }
 
     @Override
-    public void addInstructions(DexBuilder builder, List<Instruction> instructions) {
+    public void addInstructions(DexBuilder builder, List<DexInstruction> instructions) {
       instructions.add(instruction);
     }
 
@@ -1042,15 +1043,15 @@
 
   private static class MultiFixedSizeInfo extends Info {
 
-    private final Instruction[] instructions;
+    private final DexInstruction[] instructions;
     private final int size;
 
-    public MultiFixedSizeInfo(com.android.tools.r8.ir.code.Instruction ir,
-        Instruction[] instructions) {
+    public MultiFixedSizeInfo(
+        com.android.tools.r8.ir.code.Instruction ir, DexInstruction[] instructions) {
       super(ir);
       this.instructions = instructions;
       int size = 0;
-      for (Instruction instruction : instructions) {
+      for (DexInstruction instruction : instructions) {
         size += instruction.getSize();
       }
       this.size = size;
@@ -1062,9 +1063,9 @@
     }
 
     @Override
-    public void addInstructions(DexBuilder builder, List<Instruction> instructions) {
+    public void addInstructions(DexBuilder builder, List<DexInstruction> instructions) {
       int offset = getOffset();
-      for (Instruction instruction : this.instructions) {
+      for (DexInstruction instruction : this.instructions) {
         instructions.add(instruction);
         instruction.setOffset(offset);
         offset += instruction.getSize();
@@ -1110,8 +1111,7 @@
     }
 
     @Override
-    public void addInstructions(DexBuilder builder, List<Instruction> instructions) {
-    }
+    public void addInstructions(DexBuilder builder, List<DexInstruction> instructions) {}
 
     @Override
     public int minSize() {
@@ -1149,13 +1149,13 @@
 
     @Override
     public int minSize() {
-      assert new Goto(42).getSize() == 1;
+      assert new DexGoto(42).getSize() == 1;
       return 1;
     }
 
     @Override
     public int maxSize() {
-      assert new Goto32(0).getSize() == 3;
+      assert new DexGoto32(0).getSize() == 3;
       return 3;
     }
 
@@ -1201,7 +1201,7 @@
     }
 
     @Override
-    public void addInstructions(DexBuilder builder, List<Instruction> instructions) {
+    public void addInstructions(DexBuilder builder, List<DexInstruction> instructions) {
       com.android.tools.r8.ir.code.Goto jump = getJump();
       int source = builder.getInfo(jump).getOffset();
       Info targetInfo = builder.getTargetInfo(jump.getTarget());
@@ -1213,7 +1213,7 @@
       // size of this instruction.
       Return ret = targetInfo.getIR().asReturn();
       if (ret != null && size == targetInfo.getSize() && ret.getPosition().isNone()) {
-        Instruction dex = ret.createDexInstruction(builder);
+        DexInstruction dex = ret.createDexInstruction(builder);
         dex.setOffset(getOffset()); // for better printing of the dex code.
         instructions.add(dex);
       } else if (size == relativeOffset) {
@@ -1222,29 +1222,29 @@
         // jit crashes on 'goto next instruction' on Android 4.1.1.
         // TODO(b/34726595): We currently do hit this case and we should see if we can avoid that.
         for (int i = 0; i < size; i++) {
-          Instruction dex = new Nop();
+          DexInstruction dex = new DexNop();
           assert dex.getSize() == 1;
           dex.setOffset(getOffset() + i); // for better printing of the dex code.
           instructions.add(dex);
         }
       } else {
-        Instruction dex;
+        DexInstruction dex;
         switch (size) {
           case 1:
             assert relativeOffset != 0;
-            dex = new Goto(relativeOffset);
+            dex = new DexGoto(relativeOffset);
             break;
           case 2:
             if (relativeOffset == 0) {
-              Nop nop = new Nop();
+              DexNop nop = new DexNop();
               instructions.add(nop);
-              dex = new Goto(-nop.getSize());
+              dex = new DexGoto(-nop.getSize());
             } else {
-              dex = new Goto16(relativeOffset);
+              dex = new DexGoto16(relativeOffset);
             }
             break;
           case 3:
-            dex = new Goto32(relativeOffset);
+            dex = new DexGoto32(relativeOffset);
             break;
           default:
             throw new Unreachable("Unexpected size for goto instruction: " + size);
@@ -1307,7 +1307,7 @@
     }
 
     @Override
-    public void addInstructions(DexBuilder builder, List<Instruction> instructions) {
+    public void addInstructions(DexBuilder builder, List<DexInstruction> instructions) {
       If branch = getBranch();
       int source = builder.getInfo(branch).getOffset();
       int target = builder.getInfo(branch.getTrueTarget().entry()).getOffset();
@@ -1320,53 +1320,53 @@
 
       if (size == 3) {
         assert branchesToSelf(builder);
-        Nop nop = new Nop();
+        DexNop nop = new DexNop();
         relativeOffset -= nop.getSize();
         instructions.add(nop);
       }
       assert relativeOffset != 0;
-      Instruction instruction = null;
+      DexInstruction instruction = null;
       if (branch.isZeroTest()) {
         switch (getBranch().getType()) {
           case EQ:
-            instruction = new IfEqz(register1, relativeOffset);
+            instruction = new DexIfEqz(register1, relativeOffset);
             break;
           case GE:
-            instruction = new IfGez(register1, relativeOffset);
+            instruction = new DexIfGez(register1, relativeOffset);
             break;
           case GT:
-            instruction = new IfGtz(register1, relativeOffset);
+            instruction = new DexIfGtz(register1, relativeOffset);
             break;
           case LE:
-            instruction = new IfLez(register1, relativeOffset);
+            instruction = new DexIfLez(register1, relativeOffset);
             break;
           case LT:
-            instruction = new IfLtz(register1, relativeOffset);
+            instruction = new DexIfLtz(register1, relativeOffset);
             break;
           case NE:
-            instruction = new IfNez(register1, relativeOffset);
+            instruction = new DexIfNez(register1, relativeOffset);
             break;
         }
       } else {
         int register2 = getRegister(1, builder);
         switch (getBranch().getType()) {
           case EQ:
-            instruction = new IfEq(register1, register2, relativeOffset);
+            instruction = new DexIfEq(register1, register2, relativeOffset);
             break;
           case GE:
-            instruction = new IfGe(register1, register2, relativeOffset);
+            instruction = new DexIfGe(register1, register2, relativeOffset);
             break;
           case GT:
-            instruction = new IfGt(register1, register2, relativeOffset);
+            instruction = new DexIfGt(register1, register2, relativeOffset);
             break;
           case LE:
-            instruction = new IfLe(register1, register2, relativeOffset);
+            instruction = new DexIfLe(register1, register2, relativeOffset);
             break;
           case LT:
-            instruction = new IfLt(register1, register2, relativeOffset);
+            instruction = new DexIfLt(register1, register2, relativeOffset);
             break;
           case NE:
-            instruction = new IfNe(register1, register2, relativeOffset);
+            instruction = new DexIfNe(register1, register2, relativeOffset);
             break;
         }
       }
@@ -1456,46 +1456,46 @@
     }
 
     @Override
-    public void addInstructions(DexBuilder builder, List<Instruction> instructions) {
+    public void addInstructions(DexBuilder builder, List<DexInstruction> instructions) {
       Move move = getMove();
       TypeElement moveType = move.getOutType();
       int src = srcRegister(builder);
       int dest = destRegister(builder);
-      Instruction instruction;
+      DexInstruction instruction;
       switch (size) {
         case 1:
           if (src == dest) {
-            instruction = new Nop();
+            instruction = new DexNop();
             break;
           }
           if (moveType.isSinglePrimitive()) {
-            instruction = new com.android.tools.r8.code.Move(dest, src);
+            instruction = new DexMove(dest, src);
           } else if (moveType.isWidePrimitive()) {
-            instruction = new MoveWide(dest, src);
+            instruction = new DexMoveWide(dest, src);
           } else if (moveType.isReferenceType()) {
-            instruction = new MoveObject(dest, src);
+            instruction = new DexMoveObject(dest, src);
           } else {
             throw new Unreachable("Unexpected type: " + move.outType());
           }
           break;
         case 2:
           if (moveType.isSinglePrimitive()) {
-            instruction = new MoveFrom16(dest, src);
+            instruction = new DexMoveFrom16(dest, src);
           } else if (moveType.isWidePrimitive()) {
-            instruction = new MoveWideFrom16(dest, src);
+            instruction = new DexMoveWideFrom16(dest, src);
           } else if (moveType.isReferenceType()) {
-            instruction = new MoveObjectFrom16(dest, src);
+            instruction = new DexMoveObjectFrom16(dest, src);
           } else {
             throw new Unreachable("Unexpected type: " + move.outType());
           }
           break;
         case 3:
           if (moveType.isSinglePrimitive()) {
-            instruction = new Move16(dest, src);
+            instruction = new DexMove16(dest, src);
           } else if (moveType.isWidePrimitive()) {
-            instruction = new MoveWide16(dest, src);
+            instruction = new DexMoveWide16(dest, src);
           } else if (moveType.isReferenceType()) {
-            instruction = new MoveObject16(dest, src);
+            instruction = new DexMoveObject16(dest, src);
           } else {
             throw new Unreachable("Unexpected type: " + move.outType());
           }
@@ -1509,13 +1509,13 @@
 
     @Override
     public int minSize() {
-      assert new Nop().getSize() == 1 && new com.android.tools.r8.code.Move(0, 0).getSize() == 1;
+      assert new DexNop().getSize() == 1 && new DexMove(0, 0).getSize() == 1;
       return 1;
     }
 
     @Override
     public int maxSize() {
-      assert new Move16(0, 0).getSize() == 3;
+      assert new DexMove16(0, 0).getSize() == 3;
       return 3;
     }
 
@@ -1560,9 +1560,9 @@
   private static class SwitchPayloadInfo {
 
     public final IntSwitch ir;
-    public final Format31t dex;
+    public final DexFormat31t dex;
 
-    public SwitchPayloadInfo(IntSwitch ir, Format31t dex) {
+    public SwitchPayloadInfo(IntSwitch ir, DexFormat31t dex) {
       this.ir = ir;
       this.dex = dex;
     }
@@ -1571,9 +1571,9 @@
   private static class FillArrayDataInfo {
 
     public final NewArrayFilledData ir;
-    public final FillArrayData dex;
+    public final DexFillArrayData dex;
 
-    public FillArrayDataInfo(NewArrayFilledData ir, FillArrayData dex) {
+    public FillArrayDataInfo(NewArrayFilledData ir, DexFillArrayData dex) {
       this.ir = ir;
       this.dex = dex;
     }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
index a8d0ccd..3fbcdc8 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
@@ -4,31 +4,31 @@
 
 package com.android.tools.r8.ir.conversion;
 
-import com.android.tools.r8.code.FillArrayData;
-import com.android.tools.r8.code.FillArrayDataPayload;
-import com.android.tools.r8.code.FilledNewArray;
-import com.android.tools.r8.code.FilledNewArrayRange;
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.InvokeCustom;
-import com.android.tools.r8.code.InvokeCustomRange;
-import com.android.tools.r8.code.InvokeDirect;
-import com.android.tools.r8.code.InvokeDirectRange;
-import com.android.tools.r8.code.InvokeInterface;
-import com.android.tools.r8.code.InvokeInterfaceRange;
-import com.android.tools.r8.code.InvokePolymorphic;
-import com.android.tools.r8.code.InvokePolymorphicRange;
-import com.android.tools.r8.code.InvokeStatic;
-import com.android.tools.r8.code.InvokeStaticRange;
-import com.android.tools.r8.code.InvokeSuper;
-import com.android.tools.r8.code.InvokeSuperRange;
-import com.android.tools.r8.code.InvokeVirtual;
-import com.android.tools.r8.code.InvokeVirtualRange;
-import com.android.tools.r8.code.MoveException;
-import com.android.tools.r8.code.MoveResult;
-import com.android.tools.r8.code.MoveResultObject;
-import com.android.tools.r8.code.MoveResultWide;
-import com.android.tools.r8.code.SwitchPayload;
-import com.android.tools.r8.code.Throw;
+import com.android.tools.r8.dex.code.DexFillArrayData;
+import com.android.tools.r8.dex.code.DexFillArrayDataPayload;
+import com.android.tools.r8.dex.code.DexFilledNewArray;
+import com.android.tools.r8.dex.code.DexFilledNewArrayRange;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexInvokeCustom;
+import com.android.tools.r8.dex.code.DexInvokeCustomRange;
+import com.android.tools.r8.dex.code.DexInvokeDirect;
+import com.android.tools.r8.dex.code.DexInvokeDirectRange;
+import com.android.tools.r8.dex.code.DexInvokeInterface;
+import com.android.tools.r8.dex.code.DexInvokeInterfaceRange;
+import com.android.tools.r8.dex.code.DexInvokePolymorphic;
+import com.android.tools.r8.dex.code.DexInvokePolymorphicRange;
+import com.android.tools.r8.dex.code.DexInvokeStatic;
+import com.android.tools.r8.dex.code.DexInvokeStaticRange;
+import com.android.tools.r8.dex.code.DexInvokeSuper;
+import com.android.tools.r8.dex.code.DexInvokeSuperRange;
+import com.android.tools.r8.dex.code.DexInvokeVirtual;
+import com.android.tools.r8.dex.code.DexInvokeVirtualRange;
+import com.android.tools.r8.dex.code.DexMoveException;
+import com.android.tools.r8.dex.code.DexMoveResult;
+import com.android.tools.r8.dex.code.DexMoveResultObject;
+import com.android.tools.r8.dex.code.DexMoveResultWide;
+import com.android.tools.r8.dex.code.DexSwitchPayload;
+import com.android.tools.r8.dex.code.DexThrow;
 import com.android.tools.r8.graph.DebugLocalInfo;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.graph.DexCode.Try;
@@ -66,7 +66,7 @@
 
   private Try currentTryRange = null;
   private CatchHandlers<Integer> currentCatchHandlers = null;
-  private Instruction currentDexInstruction = null;
+  private DexInstruction currentDexInstruction = null;
   private boolean isBuildingPrelude;
 
   private Position currentPosition = null;
@@ -126,13 +126,13 @@
   public void setUp() {
     // Collect all payloads in the instruction stream.
     for (int index = 0; index < code.instructions.length; index++) {
-      Instruction insn = code.instructions[index];
+      DexInstruction insn = code.instructions[index];
       offsetToInstructionIndex.put(insn.getOffset(), index);
       if (insn.isPayload()) {
         if (insn.isSwitchPayload()) {
-          switchPayloadResolver.resolve((SwitchPayload) insn);
+          switchPayloadResolver.resolve((DexSwitchPayload) insn);
         } else {
-          arrayFilledDataPayloadResolver.resolve((FillArrayDataPayload) insn);
+          arrayFilledDataPayloadResolver.resolve((DexFillArrayDataPayload) insn);
         }
       }
     }
@@ -183,9 +183,9 @@
 
   @Override
   public int getMoveExceptionRegister(int instructionIndex) {
-    Instruction instruction = code.instructions[instructionIndex];
-    if (instruction instanceof MoveException) {
-      MoveException moveException = (MoveException) instruction;
+    DexInstruction instruction = code.instructions[instructionIndex];
+    if (instruction instanceof DexMoveException) {
+      DexMoveException moveException = (DexMoveException) instruction;
       return moveException.AA;
     }
     return -1;
@@ -297,38 +297,38 @@
         arrayFilledDataPayloadResolver.getData(payloadOffset));
   }
 
-  private boolean isInvoke(Instruction dex) {
-    return dex instanceof InvokeCustom
-        || dex instanceof InvokeCustomRange
-        || dex instanceof InvokeDirect
-        || dex instanceof InvokeDirectRange
-        || dex instanceof InvokeVirtual
-        || dex instanceof InvokeVirtualRange
-        || dex instanceof InvokeInterface
-        || dex instanceof InvokeInterfaceRange
-        || dex instanceof InvokeStatic
-        || dex instanceof InvokeStaticRange
-        || dex instanceof InvokeSuper
-        || dex instanceof InvokeSuperRange
-        || dex instanceof InvokePolymorphic
-        || dex instanceof InvokePolymorphicRange
-        || dex instanceof FilledNewArray
-        || dex instanceof FilledNewArrayRange;
+  private boolean isInvoke(DexInstruction dex) {
+    return dex instanceof DexInvokeCustom
+        || dex instanceof DexInvokeCustomRange
+        || dex instanceof DexInvokeDirect
+        || dex instanceof DexInvokeDirectRange
+        || dex instanceof DexInvokeVirtual
+        || dex instanceof DexInvokeVirtualRange
+        || dex instanceof DexInvokeInterface
+        || dex instanceof DexInvokeInterfaceRange
+        || dex instanceof DexInvokeStatic
+        || dex instanceof DexInvokeStaticRange
+        || dex instanceof DexInvokeSuper
+        || dex instanceof DexInvokeSuperRange
+        || dex instanceof DexInvokePolymorphic
+        || dex instanceof DexInvokePolymorphicRange
+        || dex instanceof DexFilledNewArray
+        || dex instanceof DexFilledNewArrayRange;
   }
 
-  private boolean isMoveResult(Instruction dex) {
-    return dex instanceof MoveResult
-        || dex instanceof MoveResultObject
-        || dex instanceof MoveResultWide;
+  private boolean isMoveResult(DexInstruction dex) {
+    return dex instanceof DexMoveResult
+        || dex instanceof DexMoveResultObject
+        || dex instanceof DexMoveResultWide;
   }
 
   @Override
   public int traceInstruction(int index, IRBuilder builder) {
-    Instruction dex = code.instructions[index];
+    DexInstruction dex = code.instructions[index];
     int offset = dex.getOffset();
     assert !dex.isPayload();
     int[] targets = dex.getTargets();
-    if (targets != Instruction.NO_TARGETS) {
+    if (targets != DexInstruction.NO_TARGETS) {
       // Check that we don't ever have instructions that can throw and have targets.
       assert !dex.canThrow();
       for (int relativeOffset : targets) {
@@ -339,7 +339,7 @@
     if (dex.canThrow()) {
       // TODO(zerny): Remove this from block computation.
       if (dex.hasPayload()) {
-        arrayFilledDataPayloadResolver.addPayloadUser((FillArrayData) dex);
+        arrayFilledDataPayloadResolver.addPayloadUser((DexFillArrayData) dex);
       }
       // If the instruction can throw and is in a try block, add edges to its catch successors.
       Try tryRange = getTryForOffset(offset);
@@ -366,13 +366,13 @@
           dex = code.instructions[index];
         }
         // Edge to normal successor if any (fallthrough).
-        if (!(dex instanceof Throw)) {
+        if (!(dex instanceof DexThrow)) {
           builder.ensureNormalSuccessorBlock(offset, dex.getOffset() + dex.getSize());
         }
         return index;
       }
       // Close the block if the instruction is a throw, otherwise the block remains open.
-      return dex instanceof Throw ? index : -1;
+      return dex instanceof DexThrow ? index : -1;
     }
     if (dex.isIntSwitch()) {
       // TODO(zerny): Remove this from block computation.
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/SwitchPayloadResolver.java b/src/main/java/com/android/tools/r8/ir/conversion/SwitchPayloadResolver.java
index 39e494d..fb2709f 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/SwitchPayloadResolver.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/SwitchPayloadResolver.java
@@ -4,8 +4,8 @@
 
 package com.android.tools.r8.ir.conversion;
 
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.SwitchPayload;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexSwitchPayload;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
@@ -28,20 +28,20 @@
     }
   }
 
-  private final Map<Integer, SwitchPayload> unresolvedPayload = new HashMap<>();
+  private final Map<Integer, DexSwitchPayload> unresolvedPayload = new HashMap<>();
   private final Map<Integer, PayloadData> payloadToData = new HashMap<>();
 
-  public void addPayloadUser(Instruction dex) {
+  public void addPayloadUser(DexInstruction dex) {
     int offset = dex.getOffset();
     int payloadOffset = offset + dex.getPayloadOffset();
     payloadToData.put(payloadOffset, new PayloadData(offset));
     if (unresolvedPayload.containsKey(payloadOffset)) {
-      SwitchPayload payload = unresolvedPayload.remove(payloadOffset);
+      DexSwitchPayload payload = unresolvedPayload.remove(payloadOffset);
       resolve(payload);
     }
   }
 
-  public void resolve(SwitchPayload payload) {
+  public void resolve(DexSwitchPayload payload) {
     int payloadOffset = payload.getOffset();
     PayloadData data = payloadToData.get(payloadOffset);
     if (data == null) {
@@ -59,7 +59,7 @@
     data.size = payload.numberOfKeys();
   }
 
-  public int[] absoluteTargets(Instruction dex) {
+  public int[] absoluteTargets(DexInstruction dex) {
     assert dex.isIntSwitch();
     return absoluteTargets(dex.getOffset() + dex.getPayloadOffset());
   }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
index 1376bb4..fcf37fb 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
@@ -117,6 +117,11 @@
     }
 
     @Override
+    public void acceptCovariantRetargetMethod(ProgramMethod method) {
+      methodProcessor.scheduleMethodForProcessing(method, this);
+    }
+
+    @Override
     public void acceptBackportedMethod(ProgramMethod backportedMethod, ProgramMethod context) {
       methodProcessor.scheduleMethodForProcessing(backportedMethod, this);
     }
@@ -346,6 +351,11 @@
     }
 
     @Override
+    public void acceptCovariantRetargetMethod(ProgramMethod method) {
+      // Intentionally empty. The method will be hit by tracing if required.
+    }
+
+    @Override
     public void acceptThrowMethod(ProgramMethod method, ProgramMethod context) {
       // Intentionally empty. The method will be hit by tracing if required.
     }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringEventConsumer.java
index 883a44a..e67d55a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringEventConsumer.java
@@ -76,6 +76,11 @@
     }
 
     @Override
+    public void acceptCovariantRetargetMethod(ProgramMethod method) {
+      addMethodToReprocess(method);
+    }
+
+    @Override
     public void acceptInterfaceInjection(DexProgramClass clazz, DexClass newInterface) {
       // Intentionally empty.
     }
@@ -165,6 +170,11 @@
     }
 
     @Override
+    public void acceptCovariantRetargetMethod(ProgramMethod method) {
+      additions.addLiveMethod(method);
+    }
+
+    @Override
     public void acceptForwardingMethod(ProgramMethod method) {
       additions.addLiveMethod(method);
     }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java
index 0ef825c..3c0046f 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java
@@ -104,12 +104,6 @@
         || methodApiLevel.isUnknownApiLevel()) {
       return appView.computedMinApiLevel();
     }
-    // Compute the api level of the holder to see if the method will be stubbed.
-    ComputedApiLevel holderApiLevel =
-        apiLevelCompute.computeApiLevelForLibraryReference(holderType, ComputedApiLevel.unknown());
-    if (holderApiLevel.isGreaterThanOrEqualTo(methodApiLevel)) {
-      return appView.computedMinApiLevel();
-    }
     // Check for protected or package private access flags before outlining.
     if (holder.isInterface()) {
       return methodApiLevel;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
index 0a35b58..38682e7 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
@@ -2218,15 +2218,11 @@
             new CfGoto(label2),
             label1,
             new CfFrame(
-                new Int2ObjectAVLTreeMap<>(
-                    new int[] {0},
-                    new FrameType[] {FrameType.initialized(options.itemFactory.floatType)})),
+                new Int2ObjectAVLTreeMap<>(new int[] {0}, new FrameType[] {FrameType.floatType()})),
             new CfConstNumber(0, ValueType.INT),
             label2,
             new CfFrame(
-                new Int2ObjectAVLTreeMap<>(
-                    new int[] {0},
-                    new FrameType[] {FrameType.initialized(options.itemFactory.floatType)}),
+                new Int2ObjectAVLTreeMap<>(new int[] {0}, new FrameType[] {FrameType.floatType()}),
                 new ArrayDeque<>(Arrays.asList(FrameType.intType()))),
             new CfReturn(ValueType.INT),
             label3),
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 9a0dd0e..189dca8 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
@@ -56,6 +56,7 @@
   static final String DONT_REWRITE_PREFIX_KEY = "dont_rewrite_prefix";
   static final String MAINTAIN_PREFIX_KEY = "maintain_prefix";
   static final String RETARGET_STATIC_FIELD_KEY = "retarget_static_field";
+  static final String COVARIANT_RETARGET_METHOD_KEY = "covariant_retarget_method";
   static final String RETARGET_METHOD_KEY = "retarget_method";
   static final String RETARGET_METHOD_EMULATED_DISPATCH_KEY =
       "retarget_method_with_emulated_dispatch";
@@ -301,6 +302,14 @@
             stringDescriptorToDexType(retarget.getValue().getAsString()));
       }
     }
+    if (jsonFlagSet.has(COVARIANT_RETARGET_METHOD_KEY)) {
+      for (Map.Entry<String, JsonElement> retarget :
+          jsonFlagSet.get(COVARIANT_RETARGET_METHOD_KEY).getAsJsonObject().entrySet()) {
+        builder.covariantRetargetMethod(
+            parseMethod(retarget.getKey()),
+            stringDescriptorToDexType(retarget.getValue().getAsString()));
+      }
+    }
     if (jsonFlagSet.has(RETARGET_METHOD_EMULATED_DISPATCH_KEY)) {
       for (Map.Entry<String, JsonElement> retarget :
           jsonFlagSet.get(RETARGET_METHOD_EMULATED_DISPATCH_KEY).getAsJsonObject().entrySet()) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java
index 7c17a74..94ae8d0 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java
@@ -31,6 +31,7 @@
   private final Map<String, Map<String, String>> rewriteDerivedPrefix;
   private final Map<DexType, DexType> emulatedInterfaces;
   private final Map<DexField, DexType> retargetStaticField;
+  private final Map<DexMethod, DexType> covariantRetarget;
   private final Map<DexMethod, DexType> retargetMethod;
   private final Map<DexMethod, DexType> retargetMethodEmulatedDispatch;
   private final Map<DexMethod, DexType[]> apiConversionCollection;
@@ -49,6 +50,7 @@
       Map<String, Map<String, String>> rewriteDerivedPrefix,
       Map<DexType, DexType> emulateLibraryInterface,
       Map<DexField, DexType> retargetStaticField,
+      Map<DexMethod, DexType> covariantRetarget,
       Map<DexMethod, DexType> retargetMethod,
       Map<DexMethod, DexType> retargetMethodEmulatedDispatch,
       Map<DexMethod, DexType[]> apiConversionCollection,
@@ -65,6 +67,7 @@
     this.rewriteDerivedPrefix = rewriteDerivedPrefix;
     this.emulatedInterfaces = emulateLibraryInterface;
     this.retargetStaticField = retargetStaticField;
+    this.covariantRetarget = covariantRetarget;
     this.retargetMethod = retargetMethod;
     this.retargetMethodEmulatedDispatch = retargetMethodEmulatedDispatch;
     this.apiConversionCollection = apiConversionCollection;
@@ -90,6 +93,7 @@
         ImmutableMap.of(),
         ImmutableMap.of(),
         ImmutableMap.of(),
+        ImmutableMap.of(),
         ImmutableSet.of(),
         ImmutableSet.of(),
         ImmutableMap.of(),
@@ -111,6 +115,7 @@
         rewriteDerivedPrefix,
         emulatedInterfaces,
         retargetStaticField,
+        covariantRetarget,
         retargetMethod,
         retargetMethodEmulatedDispatch,
         apiConversionCollection,
@@ -147,6 +152,10 @@
     return retargetStaticField;
   }
 
+  public Map<DexMethod, DexType> getCovariantRetarget() {
+    return covariantRetarget;
+  }
+
   public Map<DexMethod, DexType> getRetargetMethod() {
     return retargetMethod;
   }
@@ -192,6 +201,7 @@
         && rewriteDerivedPrefix.isEmpty()
         && maintainPrefix.isEmpty()
         && emulatedInterfaces.isEmpty()
+        && covariantRetarget.isEmpty()
         && retargetMethod.isEmpty()
         && retargetMethodEmulatedDispatch.isEmpty()
         && retargetStaticField.isEmpty();
@@ -208,6 +218,7 @@
     private final Map<String, Map<String, String>> rewriteDerivedPrefix;
     private final Map<DexType, DexType> emulatedInterfaces;
     private final Map<DexField, DexType> retargetStaticField;
+    private final Map<DexMethod, DexType> covariantRetarget;
     private final Map<DexMethod, DexType> retargetMethod;
     private final Map<DexMethod, DexType> retargetMethodEmulatedDispatch;
     private final Map<DexMethod, DexType[]> apiConversionCollection;
@@ -234,6 +245,7 @@
           new IdentityHashMap<>(),
           new IdentityHashMap<>(),
           new IdentityHashMap<>(),
+          new IdentityHashMap<>(),
           Sets.newIdentityHashSet(),
           Sets.newIdentityHashSet(),
           new IdentityHashMap<>(),
@@ -250,6 +262,7 @@
         Map<String, Map<String, String>> rewriteDerivedPrefix,
         Map<DexType, DexType> emulateLibraryInterface,
         Map<DexField, DexType> retargetStaticField,
+        Map<DexMethod, DexType> covariantRetarget,
         Map<DexMethod, DexType> retargetMethod,
         Map<DexMethod, DexType> retargetMethodEmulatedDispatch,
         Map<DexMethod, DexType[]> apiConversionCollection,
@@ -268,6 +281,7 @@
       this.rewriteDerivedPrefix = new HashMap<>(rewriteDerivedPrefix);
       this.emulatedInterfaces = new IdentityHashMap<>(emulateLibraryInterface);
       this.retargetStaticField = new IdentityHashMap<>(retargetStaticField);
+      this.covariantRetarget = new IdentityHashMap<>(covariantRetarget);
       this.retargetMethod = new IdentityHashMap<>(retargetMethod);
       this.retargetMethodEmulatedDispatch = new IdentityHashMap<>(retargetMethodEmulatedDispatch);
       this.apiConversionCollection = new IdentityHashMap<>(apiConversionCollection);
@@ -365,6 +379,15 @@
       return this;
     }
 
+    public Builder covariantRetargetMethod(DexMethod key, DexType rewrittenType) {
+      put(
+          covariantRetarget,
+          key,
+          rewrittenType,
+          HumanDesugaredLibrarySpecificationParser.COVARIANT_RETARGET_METHOD_KEY);
+      return this;
+    }
+
     public Builder retargetStaticField(DexField key, DexType rewrittenType) {
       put(
           retargetStaticField,
@@ -429,6 +452,7 @@
           ImmutableMap.copyOf(rewriteDerivedPrefix),
           ImmutableMap.copyOf(emulatedInterfaces),
           ImmutableMap.copyOf(retargetStaticField),
+          ImmutableMap.copyOf(covariantRetarget),
           ImmutableMap.copyOf(retargetMethod),
           ImmutableMap.copyOf(retargetMethodEmulatedDispatch),
           ImmutableMap.copyOf(apiConversionCollection),
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 0fdbe35..328bbf4 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
@@ -27,7 +27,7 @@
 
 public class LegacyDesugaredLibrarySpecificationParser {
 
-  public static final int MAX_SUPPORTED_VERSION = 4;
+  public static final int MAX_SUPPORTED_VERSION = 5;
   public static final SemanticVersion MIN_SUPPORTED_VERSION = SemanticVersion.create(1, 0, 9);
 
   static final String VERSION_KEY = "version";
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 5533d92..4e08dc9 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
@@ -100,6 +100,10 @@
     return rewritingFlags.getStaticFieldRetarget();
   }
 
+  public Map<DexMethod, DexMethod> getCovariantRetarget() {
+    return rewritingFlags.getCovariantRetarget();
+  }
+
   public Map<DexMethod, DexMethod> getStaticRetarget() {
     return rewritingFlags.getStaticRetarget();
   }
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 0b8530b..7245ddc 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
@@ -30,6 +30,7 @@
       Set<DexType> maintainType,
       Map<DexType, DexType> rewriteDerivedTypeOnly,
       Map<DexField, DexField> staticFieldRetarget,
+      Map<DexMethod, DexMethod> covariantRetarget,
       Map<DexMethod, DexMethod> staticRetarget,
       Map<DexMethod, DexMethod> nonEmulatedVirtualRetarget,
       Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedVirtualRetarget,
@@ -46,6 +47,7 @@
     this.maintainType = maintainType;
     this.rewriteDerivedTypeOnly = rewriteDerivedTypeOnly;
     this.staticFieldRetarget = staticFieldRetarget;
+    this.covariantRetarget = covariantRetarget;
     this.staticRetarget = staticRetarget;
     this.nonEmulatedVirtualRetarget = nonEmulatedVirtualRetarget;
     this.emulatedVirtualRetarget = emulatedVirtualRetarget;
@@ -71,6 +73,9 @@
   // Fields to retarget.
   private final Map<DexField, DexField> staticFieldRetarget;
 
+  // Methods with covariant return type to retarget.
+  private final Map<DexMethod, DexMethod> covariantRetarget;
+
   // Static methods to retarget.
   private final Map<DexMethod, DexMethod> staticRetarget;
 
@@ -119,6 +124,10 @@
     return staticFieldRetarget;
   }
 
+  public Map<DexMethod, DexMethod> getCovariantRetarget() {
+    return covariantRetarget;
+  }
+
   public Map<DexMethod, DexMethod> getStaticRetarget() {
     return staticRetarget;
   }
@@ -182,7 +191,8 @@
   }
 
   public boolean hasRetargeting() {
-    return !staticRetarget.isEmpty()
+    return !covariantRetarget.isEmpty()
+        || !staticRetarget.isEmpty()
         || !nonEmulatedVirtualRetarget.isEmpty()
         || !emulatedVirtualRetarget.isEmpty()
         || !staticFieldRetarget.isEmpty();
@@ -223,6 +233,8 @@
     private final Map<DexType, DexType> rewriteDerivedTypeOnly = new IdentityHashMap<>();
     private final ImmutableMap.Builder<DexField, DexField> staticFieldRetarget =
         ImmutableMap.builder();
+    private final ImmutableMap.Builder<DexMethod, DexMethod> covariantRetarget =
+        ImmutableMap.builder();
     private final ImmutableMap.Builder<DexMethod, DexMethod> staticRetarget =
         ImmutableMap.builder();
     private final ImmutableMap.Builder<DexMethod, DexMethod> nonEmulatedVirtualRetarget =
@@ -266,6 +278,10 @@
       staticFieldRetarget.put(src, dest);
     }
 
+    public void putCovariantRetarget(DexMethod src, DexMethod dest) {
+      covariantRetarget.put(src, dest);
+    }
+
     public void putStaticRetarget(DexMethod src, DexMethod dest) {
       staticRetarget.put(src, dest);
     }
@@ -324,6 +340,7 @@
           maintainType.build(),
           rewriteDerivedTypeOnly,
           staticFieldRetarget.build(),
+          covariantRetarget.build(),
           staticRetarget.build(),
           nonEmulatedVirtualRetarget.build(),
           emulatedVirtualRetarget.build(),
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 8213473..b9c92a6 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
@@ -31,8 +31,8 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.function.BiFunction;
 import java.util.function.Consumer;
-import java.util.function.Function;
 import org.objectweb.asm.Opcodes;
 
 public class DesugaredLibraryRetargeter implements CfInstructionDesugaring {
@@ -41,6 +41,7 @@
   private final DesugaredLibraryRetargeterSyntheticHelper syntheticHelper;
 
   private final Map<DexField, DexField> staticFieldRetarget;
+  private final Map<DexMethod, DexMethod> covariantRetarget;
   private final Map<DexMethod, DexMethod> staticRetarget;
   private final Map<DexMethod, DexMethod> nonEmulatedVirtualRetarget;
   private final Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedVirtualRetarget;
@@ -51,6 +52,7 @@
     MachineDesugaredLibrarySpecification specification =
         appView.options().machineDesugaredLibrarySpecification;
     staticFieldRetarget = specification.getStaticFieldRetarget();
+    covariantRetarget = specification.getCovariantRetarget();
     staticRetarget = specification.getStaticRetarget();
     nonEmulatedVirtualRetarget = specification.getNonEmulatedVirtualRetarget();
     emulatedVirtualRetarget = specification.getEmulatedVirtualRetarget();
@@ -76,7 +78,7 @@
     if (instruction.isFieldInstruction() && needsDesugaring(instruction, context)) {
       return desugarFieldInstruction(instruction.asFieldInstruction(), context);
     } else if (instruction.isInvoke() && needsDesugaring(instruction, context)) {
-      return desugarInvoke(instruction.asInvoke(), eventConsumer, context);
+      return desugarInvoke(instruction.asInvoke(), eventConsumer, context, methodProcessingContext);
     }
     return null;
   }
@@ -90,10 +92,14 @@
   }
 
   private List<CfInstruction> desugarInvoke(
-      CfInvoke invoke, CfInstructionDesugaringEventConsumer eventConsumer, ProgramMethod context) {
+      CfInvoke invoke,
+      CfInstructionDesugaringEventConsumer eventConsumer,
+      ProgramMethod context,
+      MethodProcessingContext methodProcessingContext) {
     InvokeRetargetingResult invokeRetargetingResult = computeNewInvokeTarget(invoke, context);
     assert invokeRetargetingResult.hasNewInvokeTarget();
-    DexMethod newInvokeTarget = invokeRetargetingResult.getNewInvokeTarget(eventConsumer);
+    DexMethod newInvokeTarget =
+        invokeRetargetingResult.getNewInvokeTarget(eventConsumer, methodProcessingContext);
     return Collections.singletonList(
         new CfInvoke(Opcodes.INVOKESTATIC, newInvokeTarget, invoke.isInterface()));
   }
@@ -128,7 +134,7 @@
     }
     return new InvokeRetargetingResult(
         true,
-        eventConsumer -> {
+        (eventConsumer, methodProcessingContext) -> {
           syntheticHelper.ensureRetargetMethod(retarget, eventConsumer);
           return retarget;
         });
@@ -137,15 +143,19 @@
   static class InvokeRetargetingResult {
 
     static InvokeRetargetingResult NO_REWRITING =
-        new InvokeRetargetingResult(false, ignored -> null);
+        new InvokeRetargetingResult(false, (ignored, alsoIgnored) -> null);
 
     private final boolean hasNewInvokeTarget;
-    private final Function<DesugaredLibraryRetargeterInstructionEventConsumer, DexMethod>
+    private final BiFunction<
+            DesugaredLibraryRetargeterInstructionEventConsumer, MethodProcessingContext, DexMethod>
         newInvokeTargetSupplier;
 
     private InvokeRetargetingResult(
         boolean hasNewInvokeTarget,
-        Function<DesugaredLibraryRetargeterInstructionEventConsumer, DexMethod>
+        BiFunction<
+                DesugaredLibraryRetargeterInstructionEventConsumer,
+                MethodProcessingContext,
+                DexMethod>
             newInvokeTargetSupplier) {
       this.hasNewInvokeTarget = hasNewInvokeTarget;
       this.newInvokeTargetSupplier = newInvokeTargetSupplier;
@@ -156,9 +166,10 @@
     }
 
     public DexMethod getNewInvokeTarget(
-        DesugaredLibraryRetargeterInstructionEventConsumer eventConsumer) {
+        DesugaredLibraryRetargeterInstructionEventConsumer eventConsumer,
+        MethodProcessingContext methodProcessingContext) {
       assert hasNewInvokeTarget();
-      return newInvokeTargetSupplier.apply(eventConsumer);
+      return newInvokeTargetSupplier.apply(eventConsumer, methodProcessingContext);
     }
   }
 
@@ -205,11 +216,21 @@
     if (descriptor != null) {
       return new InvokeRetargetingResult(
           true,
-          eventConsumer ->
+          (eventConsumer, methodProcessingContext) ->
               superInvoke
                   ? syntheticHelper.ensureForwardingMethod(descriptor, eventConsumer)
                   : syntheticHelper.ensureEmulatedHolderDispatchMethod(descriptor, eventConsumer));
     }
+    if (covariantRetarget.containsKey(singleTarget)) {
+      return new InvokeRetargetingResult(
+          true,
+          (eventConsumer, methodProcessingContext) ->
+              syntheticHelper.ensureCovariantRetargetMethod(
+                  singleTarget,
+                  covariantRetarget.get(singleTarget),
+                  eventConsumer,
+                  methodProcessingContext));
+    }
     return ensureInvokeRetargetingResult(nonEmulatedVirtualRetarget.get(singleTarget));
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterSynthesizerEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterSynthesizerEventConsumer.java
index 7785430..7e86c5b 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterSynthesizerEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterSynthesizerEventConsumer.java
@@ -17,6 +17,8 @@
 
   interface DesugaredLibraryRetargeterInstructionEventConsumer {
     void acceptDesugaredLibraryRetargeterDispatchClasspathClass(DexClasspathClass clazz);
+
+    void acceptCovariantRetargetMethod(ProgramMethod method);
   }
 
   interface DesugaredLibraryRetargeterPostProcessingEventConsumer
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterSyntheticHelper.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterSyntheticHelper.java
index 1fa4b75..8e6aca3 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterSyntheticHelper.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterSyntheticHelper.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter;
 
+import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
@@ -13,11 +14,13 @@
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.MethodAccessFlags;
+import com.android.tools.r8.graph.ProgramMethod;
 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.retargeter.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterInstructionEventConsumer;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterL8SynthesizerEventConsumer;
 import com.android.tools.r8.ir.synthetic.EmulateDispatchSyntheticCfCodeProvider;
+import com.android.tools.r8.ir.synthetic.ForwardMethodBuilder;
 import com.android.tools.r8.synthesis.SyntheticClassBuilder;
 import com.android.tools.r8.synthesis.SyntheticItems.SyntheticKindSelector;
 import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
@@ -31,6 +34,33 @@
     this.appView = appView;
   }
 
+  public DexMethod ensureCovariantRetargetMethod(
+      DexMethod target,
+      DexMethod retarget,
+      DesugaredLibraryRetargeterInstructionEventConsumer eventConsumer,
+      MethodProcessingContext methodProcessingContext) {
+    ProgramMethod method =
+        appView
+            .getSyntheticItems()
+            .createMethod(
+                kinds -> kinds.COVARIANT_OUTLINE,
+                methodProcessingContext.createUniqueContext(),
+                appView,
+                methodBuilder ->
+                    methodBuilder
+                        .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic())
+                        .setProto(appView.dexItemFactory().prependHolderToProto(target))
+                        .setCode(
+                            m ->
+                                ForwardMethodBuilder.builder(appView.dexItemFactory())
+                                    .setVirtualTarget(retarget, false)
+                                    .setNonStaticSource(target)
+                                    .setCastResult()
+                                    .build()));
+    eventConsumer.acceptCovariantRetargetMethod(method);
+    return method.getReference();
+  }
+
   public DexMethod ensureRetargetMethod(
       DexMethod retarget, DesugaredLibraryRetargeterInstructionEventConsumer eventConsumer) {
     DexClass holderClass = appView.definitionFor(retarget.getHolderType());
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 56af1fc..7dcb8a8 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
@@ -42,6 +42,9 @@
         .getRetargetStaticField()
         .forEach((field, type) -> convertRetargetField(builder, field, type));
     rewritingFlags
+        .getCovariantRetarget()
+        .forEach((method, type) -> convertCovariantRetarget(builder, method, type));
+    rewritingFlags
         .getRetargetMethod()
         .forEach((method, type) -> convertRetargetMethod(builder, method, type));
     rewritingFlags
@@ -95,6 +98,41 @@
     convertEmulatedVirtualRetarget(builder, rewritingFlags, foundMethod, type);
   }
 
+  private void convertCovariantRetarget(
+      MachineRewritingFlags.Builder builder, DexMethod method, DexType type) {
+    DexClass holder = appInfo.definitionFor(method.holder);
+    DexProto proto = method.getProto();
+    DexProto newProto = appInfo.dexItemFactory().createProto(type, proto.parameters);
+    DexMethod covariant = method.withProto(newProto, appInfo.dexItemFactory());
+    DexEncodedMethod foundMethod = holder.lookupMethod(covariant);
+    if (foundMethod == null) {
+      missingReferences.add(covariant);
+      return;
+    }
+    if (foundMethod.isStatic()) {
+      appInfo
+          .app()
+          .options
+          .reporter
+          .warning(
+              "Static method "
+                  + foundMethod
+                  + " is flagged as having a covariant return type, which is not possible.");
+      return;
+    }
+    if (seemsToNeedEmulatedDispatch(holder, foundMethod)) {
+      appInfo
+          .app()
+          .options
+          .reporter
+          .warning(
+              "Covariant retargeting of non final method "
+                  + foundMethod
+                  + " which could lead to invalid runtime execution in overrides.");
+    }
+    builder.putCovariantRetarget(method, covariant);
+  }
+
   private void convertRetargetMethod(
       MachineRewritingFlags.Builder builder, DexMethod method, DexType type) {
     DexClass holder = appInfo.definitionFor(method.holder);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
index f963a21..89a9163 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
@@ -6,8 +6,8 @@
 
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.cf.code.CfInvoke;
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.InvokeSuper;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexInvokeSuper;
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.Code;
@@ -193,8 +193,8 @@
     Code code = method.getDefinition().getCode();
     assert code != null;
     if (code.isDexCode()) {
-      for (Instruction insn : code.asDexCode().instructions) {
-        if (insn instanceof InvokeSuper) {
+      for (DexInstruction insn : code.asDexCode().instructions) {
+        if (insn instanceof DexInvokeSuper) {
           return false;
         }
       }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
index 3788e98..107bd20 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
@@ -7,9 +7,9 @@
 import static com.android.tools.r8.ir.optimize.inliner.InlinerUtils.collectAllMonitorEnterValues;
 import static com.android.tools.r8.utils.AndroidApiLevelUtils.isApiSafeForInlining;
 
-import com.android.tools.r8.code.MoveResult;
-import com.android.tools.r8.code.MoveResultObject;
-import com.android.tools.r8.code.MoveResultWide;
+import com.android.tools.r8.dex.code.DexMoveResult;
+import com.android.tools.r8.dex.code.DexMoveResultObject;
+import com.android.tools.r8.dex.code.DexMoveResultWide;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.features.ClassToFeatureSplitMap;
 import com.android.tools.r8.graph.AppView;
@@ -245,9 +245,9 @@
     if (appView.options().isGeneratingDex()
         && invoke.hasOutValue()
         && invoke.outValue().hasNonDebugUsers()) {
-      assert MoveResult.SIZE == MoveResultObject.SIZE;
-      assert MoveResult.SIZE == MoveResultWide.SIZE;
-      instructionLimit += MoveResult.SIZE;
+      assert DexMoveResult.SIZE == DexMoveResultObject.SIZE;
+      assert DexMoveResult.SIZE == DexMoveResultWide.SIZE;
+      instructionLimit += DexMoveResult.SIZE;
     }
     return instructionLimit;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerCostAnalysis.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerCostAnalysis.java
index 93b5d8f..12028fb 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerCostAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerCostAnalysis.java
@@ -9,9 +9,9 @@
 import static com.android.tools.r8.ir.code.Opcodes.INSTANCE_PUT;
 import static com.android.tools.r8.ir.code.Opcodes.RETURN;
 
-import com.android.tools.r8.code.Iget;
-import com.android.tools.r8.code.Iput;
-import com.android.tools.r8.code.Return;
+import com.android.tools.r8.dex.code.DexIget;
+import com.android.tools.r8.dex.code.DexIput;
+import com.android.tools.r8.dex.code.DexReturn;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -130,7 +130,7 @@
             if (appView.options().isGeneratingClassFiles()) {
               result++;
             } else {
-              result += instruction.isInstanceGet() ? Iget.SIZE : Iput.SIZE;
+              result += instruction.isInstanceGet() ? DexIget.SIZE : DexIput.SIZE;
             }
           }
           break;
@@ -140,7 +140,7 @@
           if (appView.options().isGeneratingClassFiles()) {
             result++;
           } else {
-            result += Return.SIZE;
+            result += DexReturn.SIZE;
           }
           break;
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryFieldSynthesis.java b/src/main/java/com/android/tools/r8/ir/optimize/library/FieldSynthesis.java
similarity index 81%
rename from src/main/java/com/android/tools/r8/ir/optimize/library/LibraryFieldSynthesis.java
rename to src/main/java/com/android/tools/r8/ir/optimize/library/FieldSynthesis.java
index 5cb256c..dcbca18 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryFieldSynthesis.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/FieldSynthesis.java
@@ -4,29 +4,29 @@
 
 package com.android.tools.r8.ir.optimize.library;
 
-import static com.android.tools.r8.graph.DexLibraryClass.asLibraryClassOrNull;
+import static com.android.tools.r8.graph.ClasspathOrLibraryClass.asClasspathOrLibraryClass;
 
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.ClasspathOrLibraryClass;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexLibraryClass;
 import com.android.tools.r8.graph.FieldAccessFlags;
 
 /**
- * This class synthesizes library fields that we rely on for modeling.
+ * This class synthesizes classpath/library fields that we rely on for modeling.
  *
  * <p>For example, we synthesize the field `java.lang.String java.lang.Enum.name` if it is not
  * present. We use this to model that the constructor `void java.lang.Enum.<init>(java.lang.String,
  * int)` initializes `java.lang.String java.lang.Enum.name` to the first argument of the
  * constructor.
  */
-public class LibraryFieldSynthesis {
+public class FieldSynthesis {
 
   public static void synthesizeEnumFields(AppView<?> appView) {
     DexItemFactory dexItemFactory = appView.dexItemFactory();
-    DexLibraryClass enumClass =
-        asLibraryClassOrNull(appView.definitionFor(dexItemFactory.enumType));
+    ClasspathOrLibraryClass enumClass =
+        asClasspathOrLibraryClass(appView.definitionFor(dexItemFactory.enumType));
     if (enumClass != null) {
       dexItemFactory.enumMembers.forEachField(
           field -> {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryOptimizationInfoInitializer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryOptimizationInfoInitializer.java
index a7041c8..df2c436 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryOptimizationInfoInitializer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryOptimizationInfoInitializer.java
@@ -68,7 +68,7 @@
     EnumMembers enumMembers = dexItemFactory.enumMembers;
     DexEncodedMethod enumConstructor = lookupMethod(enumMembers.constructor);
     if (enumConstructor != null) {
-      LibraryFieldSynthesis.synthesizeEnumFields(appView);
+      FieldSynthesis.synthesizeEnumFields(appView);
       InstanceFieldInitializationInfoFactory factory =
           appView.instanceFieldInitializationInfoFactory();
       InstanceFieldInitializationInfoCollection fieldInitializationInfos =
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/apiconverter/APIConversionCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/apiconverter/APIConversionCfCodeProvider.java
index 5932c0b..9bd1ba2 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/apiconverter/APIConversionCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/apiconverter/APIConversionCfCodeProvider.java
@@ -120,17 +120,14 @@
 
   private void generateParameterConvertAndLoads(
       List<CfInstruction> instructions, boolean isStatic) {
-    int stackIndex = BooleanUtils.intValue(!isStatic);
+    int localIndex = BooleanUtils.intValue(!isStatic);
     for (int i = 0; i < forwardMethod.getArity(); i++) {
       ValueType valueType = valueTypeFromForwardMethod(forwardMethod.getParameter(i));
-      instructions.add(new CfLoad(valueType, stackIndex));
+      instructions.add(new CfLoad(valueType, localIndex));
       if (parameterConversions[i] != null) {
         instructions.add(new CfInvoke(Opcodes.INVOKESTATIC, parameterConversions[i], false));
       }
-      if (valueType.isWide()) {
-        stackIndex++;
-      }
-      stackIndex++;
+      localIndex += valueType.isWide() ? 2 : 1;
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
index 3ac9bc61..418a665 100644
--- a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
@@ -88,17 +88,15 @@
 
   private final DexApplication application;
   private final AppView<?> appView;
-  private final NamingLens namingLens;
   private final InternalOptions options;
   private final Marker marker;
   private final Predicate<DexType> isTypeMissing;
 
   private static final CfVersion MIN_VERSION_FOR_COMPILER_GENERATED_CODE = CfVersion.V1_6;
 
-  public CfApplicationWriter(AppView<?> appView, Marker marker, NamingLens namingLens) {
+  public CfApplicationWriter(AppView<?> appView, Marker marker) {
     this.application = appView.appInfo().app();
     this.appView = appView;
-    this.namingLens = namingLens;
     this.options = appView.options();
     assert marker != null;
     this.marker = marker;
@@ -106,6 +104,10 @@
         PredicateUtils.isNull(appView.appInfo()::definitionForWithoutExistenceAssert);
   }
 
+  private NamingLens getNamingLens() {
+    return appView.getNamingLens();
+  }
+
   public void write(ClassFileConsumer consumer) {
     assert options.proguardMapConsumer == null;
     write(consumer, null);
@@ -138,7 +140,6 @@
           runAndWriteMap(
               inputApp,
               appView,
-              namingLens,
               application.timing,
               OriginalSourceFiles.fromClasses(),
               DebugRepresentation.none(options));
@@ -174,9 +175,9 @@
         writeClassCatchingErrors(
             clazz, globalsConsumer, rewriter, markerString, sourceFileEnvironment);
       }
-      globalsConsumer.finished(appView, namingLens);
+      globalsConsumer.finished(appView);
     }
-    ApplicationWriter.supplyAdditionalConsumers(application, appView, namingLens, options);
+    ApplicationWriter.supplyAdditionalConsumers(appView);
   }
 
   private void writeClassCatchingErrors(
@@ -248,16 +249,16 @@
     if (clazz.isDeprecated()) {
       access = AsmUtils.withDeprecated(access);
     }
-    String desc = namingLens.lookupDescriptor(clazz.type).toString();
-    String name = namingLens.lookupInternalName(clazz.type);
-    String signature = clazz.getClassSignature().toRenamedString(namingLens, isTypeMissing);
+    String desc = getNamingLens().lookupDescriptor(clazz.type).toString();
+    String name = getNamingLens().lookupInternalName(clazz.type);
+    String signature = clazz.getClassSignature().toRenamedString(getNamingLens(), isTypeMissing);
     String superName =
         clazz.type == options.itemFactory.objectType
             ? null
-            : namingLens.lookupInternalName(clazz.superType);
+            : getNamingLens().lookupInternalName(clazz.superType);
     String[] interfaces = new String[clazz.interfaces.values.length];
     for (int i = 0; i < clazz.interfaces.values.length; i++) {
-      interfaces[i] = namingLens.lookupInternalName(clazz.interfaces.values[i]);
+      interfaces[i] = getNamingLens().lookupInternalName(clazz.interfaces.values[i]);
     }
     assert SyntheticNaming.verifyNotInternalSynthetic(name);
     writer.visit(version.raw(), access, name, signature, superName, interfaces);
@@ -266,15 +267,15 @@
     ImmutableMap<DexString, DexValue> defaults = getAnnotationDefaults(clazz.annotations());
 
     if (clazz.getEnclosingMethodAttribute() != null) {
-      clazz.getEnclosingMethodAttribute().write(writer, namingLens);
+      clazz.getEnclosingMethodAttribute().write(writer, getNamingLens());
     }
 
     if (clazz.getNestHostClassAttribute() != null) {
-      clazz.getNestHostClassAttribute().write(writer, namingLens);
+      clazz.getNestHostClassAttribute().write(writer, getNamingLens());
     }
 
     for (NestMemberClassAttribute entry : clazz.getNestMembersClassAttributes()) {
-      entry.write(writer, namingLens);
+      entry.write(writer, getNamingLens());
       assert clazz.getNestHostClassAttribute() == null
           : "A nest host cannot also be a nest member.";
     }
@@ -282,17 +283,17 @@
     if (clazz.isRecord()) {
       // TODO(b/169645628): Strip record components if not kept.
       for (DexEncodedField instanceField : clazz.instanceFields()) {
-        String componentName = namingLens.lookupName(instanceField.getReference()).toString();
+        String componentName = getNamingLens().lookupName(instanceField.getReference()).toString();
         String componentDescriptor =
-            namingLens.lookupDescriptor(instanceField.getReference().type).toString();
+            getNamingLens().lookupDescriptor(instanceField.getReference().type).toString();
         String componentSignature =
-            instanceField.getGenericSignature().toRenamedString(namingLens, isTypeMissing);
+            instanceField.getGenericSignature().toRenamedString(getNamingLens(), isTypeMissing);
         writer.visitRecordComponent(componentName, componentDescriptor, componentSignature);
       }
     }
 
     for (InnerClassAttribute entry : clazz.getInnerClasses()) {
-      entry.write(writer, namingLens, options);
+      entry.write(writer, getNamingLens(), options);
     }
 
     for (DexEncodedField field : clazz.staticFields()) {
@@ -328,11 +329,11 @@
   }
 
   private int compareTypesThroughLens(DexType a, DexType b) {
-    return namingLens.lookupDescriptor(a).compareTo(namingLens.lookupDescriptor(b));
+    return getNamingLens().lookupDescriptor(a).compareTo(getNamingLens().lookupDescriptor(b));
   }
 
   private DexString returnTypeThroughLens(DexMethod method) {
-    return namingLens.lookupDescriptor(method.getReturnType());
+    return getNamingLens().lookupDescriptor(method.getReturnType());
   }
 
   private int compareMethodsThroughLens(ProgramMethod a, ProgramMethod b) {
@@ -422,7 +423,7 @@
     DexValue[] values = value.asDexValueArray().getValues();
     String[] res = new String[values.length];
     for (int i = 0; i < values.length; i++) {
-      res[i] = namingLens.lookupInternalName(values[i].asDexValueType().value);
+      res[i] = getNamingLens().lookupInternalName(values[i].asDexValueType().value);
     }
     return res;
   }
@@ -439,9 +440,9 @@
     if (field.isDeprecated()) {
       access = AsmUtils.withDeprecated(access);
     }
-    String name = namingLens.lookupName(field.getReference()).toString();
-    String desc = namingLens.lookupDescriptor(field.getReference().type).toString();
-    String signature = field.getGenericSignature().toRenamedString(namingLens, isTypeMissing);
+    String name = getNamingLens().lookupName(field.getReference()).toString();
+    String desc = getNamingLens().lookupDescriptor(field.getReference().type).toString();
+    String signature = field.getGenericSignature().toRenamedString(getNamingLens(), isTypeMissing);
     Object value = getStaticValue(field);
     FieldVisitor visitor = writer.visitField(access, name, desc, signature, value);
     writeAnnotations(visitor::visitAnnotation, field.annotations().annotations);
@@ -454,13 +455,11 @@
       LensCodeRewriterUtils rewriter,
       ClassWriter writer,
       ImmutableMap<DexString, DexValue> defaults) {
-    NamingLens namingLens = this.namingLens;
-
     // For "pass through" classes which has already been library desugared use the identity lens.
-    if (appView.isAlreadyLibraryDesugared(method.getHolder())) {
-      namingLens = NamingLens.getIdentityLens();
-    }
-
+    NamingLens namingLens =
+        appView.isAlreadyLibraryDesugared(method.getHolder())
+            ? NamingLens.getIdentityLens()
+            : getNamingLens();
     DexEncodedMethod definition = method.getDefinition();
     int access = definition.getAccessFlags().getAsCfAccessFlags();
     if (definition.isDeprecated()) {
@@ -540,7 +539,7 @@
       }
       AnnotationVisitor v =
           visitor.visit(
-              namingLens.lookupDescriptor(dexAnnotation.annotation.type).toString(),
+              getNamingLens().lookupDescriptor(dexAnnotation.annotation.type).toString(),
               dexAnnotation.visibility == DexAnnotation.VISIBILITY_RUNTIME);
       if (v != null) {
         writeAnnotation(v, dexAnnotation.annotation);
@@ -562,7 +561,7 @@
           DexValueAnnotation valueAnnotation = value.asDexValueAnnotation();
           AnnotationVisitor innerVisitor =
               visitor.visitAnnotation(
-                  name, namingLens.lookupDescriptor(valueAnnotation.value.type).toString());
+                  name, getNamingLens().lookupDescriptor(valueAnnotation.value.type).toString());
           if (innerVisitor != null) {
             writeAnnotation(innerVisitor, valueAnnotation.value);
             innerVisitor.visitEnd();
@@ -587,8 +586,8 @@
         DexField enumField = value.asDexValueEnum().getValue();
         visitor.visitEnum(
             name,
-            namingLens.lookupDescriptor(enumField.getType()).toString(),
-            namingLens.lookupName(enumField).toString());
+            getNamingLens().lookupDescriptor(enumField.getType()).toString(),
+            getNamingLens().lookupName(enumField).toString());
         break;
 
       case FIELD:
@@ -610,7 +609,8 @@
       case TYPE:
         visitor.visit(
             name,
-            Type.getType(namingLens.lookupDescriptor(value.asDexValueType().value).toString()));
+            Type.getType(
+                getNamingLens().lookupDescriptor(value.asDexValueType().value).toString()));
         break;
 
       default:
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationArgumentInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationArgumentInfo.java
index 6f34ad1..7d9fd7f 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationArgumentInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationArgumentInfo.java
@@ -8,7 +8,6 @@
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.kotlin.Kotlin.ClassClassifiers;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
@@ -28,8 +27,7 @@
   private static final Map<String, KotlinAnnotationArgumentInfo> EMPTY_ARGUMENTS =
       ImmutableMap.of();
 
-  abstract boolean rewrite(
-      Consumer<KmAnnotationArgument> consumer, AppView<?> appView, NamingLens namingLens);
+  abstract boolean rewrite(Consumer<KmAnnotationArgument> consumer, AppView<?> appView);
 
   private static KotlinAnnotationArgumentInfo createArgument(
       KmAnnotationArgument arg, DexItemFactory factory) {
@@ -78,12 +76,10 @@
     }
 
     @Override
-    boolean rewrite(
-        Consumer<KmAnnotationArgument> consumer, AppView<?> appView, NamingLens namingLens) {
+    boolean rewrite(Consumer<KmAnnotationArgument> consumer, AppView<?> appView) {
       return value.toRenamedBinaryNameOrDefault(
           rewrittenValue -> consumer.accept(new KClassValue(rewrittenValue, arrayDimensionCount)),
           appView,
-          namingLens,
           ClassClassifiers.anyName);
     }
   }
@@ -111,13 +107,11 @@
     }
 
     @Override
-    boolean rewrite(
-        Consumer<KmAnnotationArgument> consumer, AppView<?> appView, NamingLens namingLens) {
+    boolean rewrite(Consumer<KmAnnotationArgument> consumer, AppView<?> appView) {
       return enumClassName.toRenamedBinaryNameOrDefault(
           rewrittenEnumClassName ->
               consumer.accept(new EnumValue(rewrittenEnumClassName, enumEntryName)),
           appView,
-          namingLens,
           ClassClassifiers.anyName);
     }
   }
@@ -142,16 +136,14 @@
     }
 
     @Override
-    boolean rewrite(
-        Consumer<KmAnnotationArgument> consumer, AppView<?> appView, NamingLens namingLens) {
+    boolean rewrite(Consumer<KmAnnotationArgument> consumer, AppView<?> appView) {
       return value.rewrite(
           rewrittenAnnotation -> {
             if (rewrittenAnnotation != null) {
               consumer.accept(new AnnotationValue(rewrittenAnnotation));
             }
           },
-          appView,
-          namingLens);
+          appView);
     }
   }
 
@@ -185,8 +177,7 @@
     }
 
     @Override
-    boolean rewrite(
-        Consumer<KmAnnotationArgument> consumer, AppView<?> appView, NamingLens namingLens) {
+    boolean rewrite(Consumer<KmAnnotationArgument> consumer, AppView<?> appView) {
       List<KmAnnotationArgument> rewrittenArguments = new ArrayList<>();
       boolean rewritten = false;
       for (KotlinAnnotationArgumentInfo kotlinAnnotationArgumentInfo : value) {
@@ -197,8 +188,7 @@
                     rewrittenArguments.add(rewrittenArg);
                   }
                 },
-                appView,
-                namingLens);
+                appView);
       }
       consumer.accept(new ArrayValue(rewrittenArguments));
       return rewritten;
@@ -223,8 +213,7 @@
     }
 
     @Override
-    boolean rewrite(
-        Consumer<KmAnnotationArgument> consumer, AppView<?> appView, NamingLens namingLens) {
+    boolean rewrite(Consumer<KmAnnotationArgument> consumer, AppView<?> appView) {
       consumer.accept(argument);
       return false;
     }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java
index d21cfb1..249f68f 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java
@@ -7,7 +7,6 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.BooleanBox;
 import com.android.tools.r8.utils.DescriptorUtils;
@@ -51,9 +50,7 @@
   }
 
   boolean rewrite(
-      KmVisitorProviders.KmAnnotationVisitorProvider visitorProvider,
-      AppView<?> appView,
-      NamingLens namingLens) {
+      KmVisitorProviders.KmAnnotationVisitorProvider visitorProvider, AppView<?> appView) {
     BooleanBox rewritten = new BooleanBox(false);
     rewritten.or(
         annotationType.toRenamedDescriptorOrDefault(
@@ -74,12 +71,10 @@
                                   rewrittenArguments.put(key, rewrittenArg);
                                 }
                               },
-                              appView,
-                              namingLens)));
+                              appView)));
               visitorProvider.get(new KmAnnotation(classifier, rewrittenArguments));
             },
             appView,
-            namingLens,
             null));
     return rewritten.get();
   }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java
index bd8696b..9ddddfe 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java
@@ -15,7 +15,6 @@
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.utils.Box;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.Pair;
@@ -255,14 +254,13 @@
   }
 
   @Override
-  public Pair<KotlinClassHeader, Boolean> rewrite(
-      DexClass clazz, AppView<?> appView, NamingLens namingLens) {
+  public Pair<KotlinClassHeader, Boolean> rewrite(DexClass clazz, AppView<?> appView) {
     KmClass kmClass = new KmClass();
     // TODO(b/154348683): Set flags.
     kmClass.setFlags(flags);
     // Set potentially renamed class name.
     DexString originalDescriptor = clazz.type.descriptor;
-    DexString rewrittenDescriptor = namingLens.lookupDescriptor(clazz.type);
+    DexString rewrittenDescriptor = appView.getNamingLens().lookupDescriptor(clazz.type);
     boolean rewritten = !originalDescriptor.equals(rewrittenDescriptor);
     if (!nameCanBeSynthesizedFromClassOrAnonymousObjectOrigin) {
       kmClass.setName(this.name);
@@ -273,8 +271,7 @@
       if (anonymousObjectOrigin != null
           && name.equals(anonymousObjectOrigin.toKotlinClassifier(true))) {
         Box<String> rewrittenOrigin = new Box<>();
-        anonymousObjectOrigin.toRenamedBinaryNameOrDefault(
-            rewrittenOrigin::set, appView, namingLens, null);
+        anonymousObjectOrigin.toRenamedBinaryNameOrDefault(rewrittenOrigin::set, appView, null);
         if (rewrittenOrigin.isSet()) {
           rewrittenName = "." + rewrittenOrigin.get();
         }
@@ -290,19 +287,22 @@
     for (DexEncodedField field : clazz.fields()) {
       if (field.getKotlinInfo().isCompanion()) {
         rewritten |=
-            field.getKotlinInfo().asCompanion().rewrite(kmClass, field.getReference(), namingLens);
+            field
+                .getKotlinInfo()
+                .asCompanion()
+                .rewrite(kmClass, field.getReference(), appView.getNamingLens());
       }
     }
     // Take all not backed constructors because we will never find them in definitions.
     for (KotlinConstructorInfo constructorInfo : constructorsWithNoBacking) {
-      rewritten |= constructorInfo.rewrite(kmClass, null, appView, namingLens);
+      rewritten |= constructorInfo.rewrite(kmClass, null, appView);
     }
     // Find all constructors.
     KotlinMetadataMembersTracker rewrittenReferences = new KotlinMetadataMembersTracker(appView);
     for (DexEncodedMethod method : clazz.methods()) {
       if (method.getKotlinInfo().isConstructor()) {
         KotlinConstructorInfo constructorInfo = method.getKotlinInfo().asConstructor();
-        rewritten |= constructorInfo.rewrite(kmClass, method, appView, namingLens);
+        rewritten |= constructorInfo.rewrite(kmClass, method, appView);
         rewrittenReferences.add(method.getReference());
       }
     }
@@ -314,17 +314,16 @@
             kmClass::visitTypeAlias,
             clazz,
             appView,
-            namingLens,
             rewrittenReferences);
     // Rewrite type parameters.
     for (KotlinTypeParameterInfo typeParameter : typeParameters) {
-      rewritten |= typeParameter.rewrite(kmClass::visitTypeParameter, appView, namingLens);
+      rewritten |= typeParameter.rewrite(kmClass::visitTypeParameter, appView);
     }
     // Rewrite super types.
     for (KotlinTypeInfo superType : superTypes) {
       // Ensure the rewritten super type is not this type.
       if (clazz.getType() != superType.rewriteType(appView.graphLens())) {
-        rewritten |= superType.rewrite(kmClass::visitSupertype, appView, namingLens);
+        rewritten |= superType.rewrite(kmClass::visitSupertype, appView);
       } else {
         rewritten = true;
       }
@@ -333,8 +332,7 @@
     for (KotlinTypeReference nestedClass : nestedClasses) {
       Box<String> nestedDescriptorBox = new Box<>();
       boolean nestedClassRewritten =
-          nestedClass.toRenamedBinaryNameOrDefault(
-              nestedDescriptorBox::set, appView, namingLens, null);
+          nestedClass.toRenamedBinaryNameOrDefault(nestedDescriptorBox::set, appView, null);
       if (nestedDescriptorBox.isSet()) {
         if (nestedClassRewritten) {
           // If the class is a nested class, it should be on the form Foo.Bar$Baz, where Baz
@@ -361,7 +359,6 @@
                 }
               },
               appView,
-              namingLens,
               null);
     }
     // TODO(b/154347404): Understand enum entries.
@@ -370,8 +367,7 @@
     if (inlineClassUnderlyingPropertyName != null && inlineClassUnderlyingType != null) {
       kmClass.setInlineClassUnderlyingPropertyName(inlineClassUnderlyingPropertyName);
       rewritten |=
-          inlineClassUnderlyingType.rewrite(
-              kmClass::visitInlineClassUnderlyingType, appView, namingLens);
+          inlineClassUnderlyingType.rewrite(kmClass::visitInlineClassUnderlyingType, appView);
     }
     JvmClassExtensionVisitor extensionVisitor =
         (JvmClassExtensionVisitor) kmClass.visitExtensions(JvmClassExtensionVisitor.TYPE);
@@ -386,12 +382,10 @@
                 }
               },
               appView,
-              namingLens,
               null);
     }
     rewritten |=
-        localDelegatedProperties.rewrite(
-            extensionVisitor::visitLocalDelegatedProperty, appView, namingLens);
+        localDelegatedProperties.rewrite(extensionVisitor::visitLocalDelegatedProperty, appView);
     extensionVisitor.visitEnd();
     KotlinClassMetadata.Class.Writer writer = new KotlinClassMetadata.Class.Writer();
     kmClass.accept(writer);
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassLevelInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassLevelInfo.java
index 34c60de..e8f7fd0 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassLevelInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassLevelInfo.java
@@ -6,7 +6,6 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.Pair;
 import kotlinx.metadata.jvm.KotlinClassHeader;
@@ -57,8 +56,7 @@
     return null;
   }
 
-  Pair<KotlinClassHeader, Boolean> rewrite(
-      DexClass clazz, AppView<?> appView, NamingLens namingLens);
+  Pair<KotlinClassHeader, Boolean> rewrite(DexClass clazz, AppView<?> appView);
 
   String getPackageName();
 
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java
index 9b2939e..b6ee8e3 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java
@@ -12,7 +12,6 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.kotlin.Kotlin.ClassClassifiers;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.Reporter;
@@ -50,7 +49,7 @@
     }
   }
 
-  abstract boolean rewrite(KmTypeVisitor visitor, AppView<?> appView, NamingLens namingLens);
+  abstract boolean rewrite(KmTypeVisitor visitor, AppView<?> appView);
 
   public DexType rewriteType(GraphLens graphLens) {
     return null;
@@ -67,14 +66,12 @@
     }
 
     @Override
-    boolean rewrite(KmTypeVisitor visitor, AppView<?> appView, NamingLens namingLens) {
+    boolean rewrite(KmTypeVisitor visitor, AppView<?> appView) {
       return type.toRenamedDescriptorOrDefault(
-          descriptor -> {
-            visitor.visitClass(
-                getKotlinLocalOrAnonymousNameFromDescriptor(descriptor, isLocalOrAnonymous));
-          },
+          descriptor ->
+              visitor.visitClass(
+                  getKotlinLocalOrAnonymousNameFromDescriptor(descriptor, isLocalOrAnonymous)),
           appView,
-          namingLens,
           ClassClassifiers.anyDescriptor);
     }
 
@@ -98,7 +95,7 @@
     }
 
     @Override
-    boolean rewrite(KmTypeVisitor visitor, AppView<?> appView, NamingLens namingLens) {
+    boolean rewrite(KmTypeVisitor visitor, AppView<?> appView) {
       visitor.visitTypeParameter(typeId);
       return false;
     }
@@ -118,7 +115,7 @@
     }
 
     @Override
-    boolean rewrite(KmTypeVisitor visitor, AppView<?> appView, NamingLens namingLens) {
+    boolean rewrite(KmTypeVisitor visitor, AppView<?> appView) {
       visitor.visitTypeAlias(typeAlias);
       return false;
     }
@@ -137,7 +134,7 @@
     }
 
     @Override
-    boolean rewrite(KmTypeVisitor visitor, AppView<?> appView, NamingLens namingLens) {
+    boolean rewrite(KmTypeVisitor visitor, AppView<?> appView) {
       visitor.visitClass(classifier);
       return false;
     }
@@ -156,7 +153,7 @@
     }
 
     @Override
-    boolean rewrite(KmTypeVisitor visitor, AppView<?> appView, NamingLens namingLens) {
+    boolean rewrite(KmTypeVisitor visitor, AppView<?> appView) {
       visitor.visitTypeAlias(classifier);
       return false;
     }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinConstructorInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinConstructorInfo.java
index dd82d58..4c93733 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinConstructorInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinConstructorInfo.java
@@ -10,7 +10,6 @@
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.utils.Reporter;
 import java.util.List;
 import kotlinx.metadata.KmClass;
@@ -55,8 +54,7 @@
             : null);
   }
 
-  boolean rewrite(
-      KmClass kmClass, DexEncodedMethod method, AppView<?> appView, NamingLens namingLens) {
+  boolean rewrite(KmClass kmClass, DexEncodedMethod method, AppView<?> appView) {
     // Note that JvmExtensionsKt.setSignature does not have an overload for KmConstructorVisitor,
     // thus we rely on creating the KmConstructor manually.
     // TODO(b/154348683): Check for special flags to pass in.
@@ -67,12 +65,10 @@
           signature.rewrite(
               rewrittenSignature -> JvmExtensionsKt.setSignature(kmConstructor, rewrittenSignature),
               method,
-              appView,
-              namingLens);
+              appView);
     }
     for (KotlinValueParameterInfo valueParameterInfo : valueParameters) {
-      rewritten |=
-          valueParameterInfo.rewrite(kmConstructor::visitValueParameter, appView, namingLens);
+      rewritten |= valueParameterInfo.rewrite(kmConstructor::visitValueParameter, appView);
     }
     rewritten |= versionRequirements.rewrite(kmConstructor::visitVersionRequirement);
     kmClass.getConstructors().add(kmConstructor);
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinContractInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinContractInfo.java
index 2afb66e..c437bba 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinContractInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinContractInfo.java
@@ -9,7 +9,6 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.Reporter;
 import com.google.common.collect.ImmutableList;
@@ -50,16 +49,14 @@
   }
 
   boolean rewrite(
-      KmVisitorProviders.KmContractVisitorProvider visitorProvider,
-      AppView<?> appView,
-      NamingLens namingLens) {
+      KmVisitorProviders.KmContractVisitorProvider visitorProvider, AppView<?> appView) {
     if (this == NO_EFFECT) {
       return false;
     }
     boolean rewritten = false;
     KmContractVisitor kmContractVisitor = visitorProvider.get();
     for (KotlinEffectInfo effect : effects) {
-      rewritten |= effect.rewrite(kmContractVisitor::visitEffect, appView, namingLens);
+      rewritten |= effect.rewrite(kmContractVisitor::visitEffect, appView);
     }
     kmContractVisitor.visitEnd();
     return rewritten;
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java
index 5022d48..9307053 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java
@@ -15,7 +15,6 @@
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.kotlin.KotlinMetadataUtils.KmPropertyProcessor;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.Reporter;
 import com.google.common.collect.ImmutableList;
@@ -185,12 +184,11 @@
       KmVisitorProviders.KmTypeAliasVisitorProvider typeAliasProvider,
       DexClass clazz,
       AppView<?> appView,
-      NamingLens namingLens,
       KotlinMetadataMembersTracker rewrittenMembersWithKotlinInfo) {
     // Type aliases only have a representation here, so we can generate them directly.
     boolean rewritten = false;
     for (KotlinTypeAliasInfo typeAlias : typeAliases) {
-      rewritten |= typeAlias.rewrite(typeAliasProvider, appView, namingLens);
+      rewritten |= typeAlias.rewrite(typeAliasProvider, appView);
     }
     // For properties, we need to combine potentially a field, setter and getter.
     Map<KotlinPropertyInfo, KotlinPropertyGroup> properties = new LinkedHashMap<>();
@@ -205,11 +203,7 @@
     }
     for (DexEncodedMethod method : clazz.methods()) {
       if (method.getKotlinInfo().isFunction()) {
-        rewritten |=
-            method
-                .getKotlinInfo()
-                .asFunction()
-                .rewrite(functionProvider, method, appView, namingLens);
+        rewritten |= method.getKotlinInfo().asFunction().rewrite(functionProvider, method, appView);
         rewrittenMembersWithKotlinInfo.add(method.getReference());
         continue;
       }
@@ -235,16 +229,14 @@
               kotlinPropertyGroup.backingField,
               kotlinPropertyGroup.getter,
               kotlinPropertyGroup.setter,
-              appView,
-              namingLens);
+              appView);
     }
     // Add all not backed functions and properties.
     for (KotlinFunctionInfo notBackedFunction : functionsWithNoBacking) {
-      rewritten |= notBackedFunction.rewrite(functionProvider, null, appView, namingLens);
+      rewritten |= notBackedFunction.rewrite(functionProvider, null, appView);
     }
     for (KotlinPropertyInfo notBackedProperty : propertiesWithNoBacking) {
-      rewritten |=
-          notBackedProperty.rewrite(propertyProvider, null, null, null, appView, namingLens);
+      rewritten |= notBackedProperty.rewrite(propertyProvider, null, null, null, appView);
     }
     return rewritten;
   }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinEffectExpressionInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinEffectExpressionInfo.java
index bc7cda0..18afe26 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinEffectExpressionInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinEffectExpressionInfo.java
@@ -10,7 +10,6 @@
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.kotlin.KmVisitorProviders.KmEffectExpressionVisitorProvider;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.Reporter;
 import com.google.common.collect.ImmutableList;
@@ -85,8 +84,7 @@
     forEachApply(orArguments, arg -> arg::trace, definitionSupplier);
   }
 
-  boolean rewrite(
-      KmEffectExpressionVisitorProvider provider, AppView<?> appView, NamingLens namingLens) {
+  boolean rewrite(KmEffectExpressionVisitorProvider provider, AppView<?> appView) {
     if (this == NO_EXPRESSION) {
       return false;
     }
@@ -97,13 +95,13 @@
     }
     boolean rewritten = false;
     if (isInstanceType != null) {
-      rewritten |= isInstanceType.rewrite(visitor::visitIsInstanceType, appView, namingLens);
+      rewritten |= isInstanceType.rewrite(visitor::visitIsInstanceType, appView);
     }
     for (KotlinEffectExpressionInfo andArgument : andArguments) {
-      rewritten |= andArgument.rewrite(visitor::visitAndArgument, appView, namingLens);
+      rewritten |= andArgument.rewrite(visitor::visitAndArgument, appView);
     }
     for (KotlinEffectExpressionInfo orArgument : orArguments) {
-      rewritten |= orArgument.rewrite(visitor::visitAndArgument, appView, namingLens);
+      rewritten |= orArgument.rewrite(visitor::visitAndArgument, appView);
     }
     visitor.visitEnd();
     return rewritten;
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinEffectInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinEffectInfo.java
index e581526..e93b126 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinEffectInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinEffectInfo.java
@@ -10,7 +10,6 @@
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.kotlin.KmVisitorProviders.KmEffectVisitorProvider;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.Reporter;
 import java.util.List;
@@ -51,16 +50,12 @@
     conclusion.trace(definitionSupplier);
   }
 
-  boolean rewrite(
-      KmEffectVisitorProvider visitorProvider, AppView<?> appView, NamingLens namingLens) {
+  boolean rewrite(KmEffectVisitorProvider visitorProvider, AppView<?> appView) {
     KmEffectVisitor kmEffectVisitor = visitorProvider.get(type, invocationKind);
     boolean rewritten =
-        conclusion.rewrite(
-            kmEffectVisitor::visitConclusionOfConditionalEffect, appView, namingLens);
+        conclusion.rewrite(kmEffectVisitor::visitConclusionOfConditionalEffect, appView);
     for (KotlinEffectExpressionInfo constructorArgument : constructorArguments) {
-      rewritten |=
-          constructorArgument.rewrite(
-              kmEffectVisitor::visitConstructorArgument, appView, namingLens);
+      rewritten |= constructorArgument.rewrite(kmEffectVisitor::visitConstructorArgument, appView);
     }
     kmEffectVisitor.visitEnd();
     return rewritten;
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinFileFacadeInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinFileFacadeInfo.java
index 7981195..f112b4f 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinFileFacadeInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinFileFacadeInfo.java
@@ -8,7 +8,6 @@
 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.naming.NamingLens;
 import com.android.tools.r8.utils.Pair;
 import java.util.function.Consumer;
 import kotlinx.metadata.KmPackage;
@@ -58,10 +57,9 @@
   }
 
   @Override
-  public Pair<KotlinClassHeader, Boolean> rewrite(
-      DexClass clazz, AppView<?> appView, NamingLens namingLens) {
+  public Pair<KotlinClassHeader, Boolean> rewrite(DexClass clazz, AppView<?> appView) {
     KmPackage kmPackage = new KmPackage();
-    boolean rewritten = packageInfo.rewrite(kmPackage, clazz, appView, namingLens);
+    boolean rewritten = packageInfo.rewrite(kmPackage, clazz, appView);
     KotlinClassMetadata.FileFacade.Writer writer = new KotlinClassMetadata.FileFacade.Writer();
     kmPackage.accept(writer);
     return Pair.create(writer.write().getHeader(), rewritten);
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinFlexibleTypeUpperBoundInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinFlexibleTypeUpperBoundInfo.java
index e2a2083..35e52f5 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinFlexibleTypeUpperBoundInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinFlexibleTypeUpperBoundInfo.java
@@ -7,7 +7,6 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.Reporter;
 import kotlinx.metadata.KmFlexibleTypeUpperBound;
@@ -39,9 +38,7 @@
   }
 
   boolean rewrite(
-      KmVisitorProviders.KmFlexibleUpperBoundVisitorProvider visitorProvider,
-      AppView<?> appView,
-      NamingLens namingLens) {
+      KmVisitorProviders.KmFlexibleUpperBoundVisitorProvider visitorProvider, AppView<?> appView) {
     if (this == NO_FLEXIBLE_UPPER_BOUND) {
       // Nothing to do.
       return false;
@@ -50,8 +47,7 @@
       assert false;
       return false;
     }
-    return kotlinTypeInfo.rewrite(
-        flags -> visitorProvider.get(flags, typeFlexibilityId), appView, namingLens);
+    return kotlinTypeInfo.rewrite(flags -> visitorProvider.get(flags, typeFlexibilityId), appView);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinFunctionInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinFunctionInfo.java
index 5001c40..63e7c95 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinFunctionInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinFunctionInfo.java
@@ -10,7 +10,6 @@
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.utils.Reporter;
 import java.util.List;
 import kotlinx.metadata.KmFunction;
@@ -119,14 +118,13 @@
   boolean rewrite(
       KmVisitorProviders.KmFunctionVisitorProvider visitorProvider,
       DexEncodedMethod method,
-      AppView<?> appView,
-      NamingLens namingLens) {
+      AppView<?> appView) {
     // TODO(b/154348683): Check method for flags to pass in.
     boolean rewritten = false;
     String finalName = this.name;
     if (method != null) {
       String methodName = method.getReference().name.toString();
-      String rewrittenName = namingLens.lookupName(method.getReference()).toString();
+      String rewrittenName = appView.getNamingLens().lookupName(method.getReference()).toString();
       if (!methodName.equals(rewrittenName)) {
         rewritten = true;
         finalName = rewrittenName;
@@ -134,23 +132,21 @@
     }
     KmFunctionVisitor kmFunction = visitorProvider.get(flags, finalName);
     // TODO(b/154348149): ReturnType could have been merged to a subtype.
-    rewritten |= returnType.rewrite(kmFunction::visitReturnType, appView, namingLens);
+    rewritten |= returnType.rewrite(kmFunction::visitReturnType, appView);
     for (KotlinValueParameterInfo valueParameterInfo : valueParameters) {
-      rewritten |= valueParameterInfo.rewrite(kmFunction::visitValueParameter, appView, namingLens);
+      rewritten |= valueParameterInfo.rewrite(kmFunction::visitValueParameter, appView);
     }
     for (KotlinTypeParameterInfo typeParameterInfo : typeParameters) {
-      rewritten |= typeParameterInfo.rewrite(kmFunction::visitTypeParameter, appView, namingLens);
+      rewritten |= typeParameterInfo.rewrite(kmFunction::visitTypeParameter, appView);
     }
     if (receiverParameterType != null) {
-      rewritten |=
-          receiverParameterType.rewrite(
-              kmFunction::visitReceiverParameterType, appView, namingLens);
+      rewritten |= receiverParameterType.rewrite(kmFunction::visitReceiverParameterType, appView);
     }
     rewritten |= versionRequirements.rewrite(kmFunction::visitVersionRequirement);
     JvmFunctionExtensionVisitor extensionVisitor =
         (JvmFunctionExtensionVisitor) kmFunction.visitExtensions(JvmFunctionExtensionVisitor.TYPE);
     if (signature != null && extensionVisitor != null) {
-      rewritten |= signature.rewrite(extensionVisitor::visit, method, appView, namingLens);
+      rewritten |= signature.rewrite(extensionVisitor::visit, method, appView);
     }
     if (lambdaClassOrigin != null && extensionVisitor != null) {
       rewritten |=
@@ -161,10 +157,9 @@
                 }
               },
               appView,
-              namingLens,
               null);
     }
-    rewritten |= contract.rewrite(kmFunction::visitContract, appView, namingLens);
+    rewritten |= contract.rewrite(kmFunction::visitContract, appView);
     return rewritten;
   }
 
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinJvmFieldSignatureInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinJvmFieldSignatureInfo.java
index 340275a..a7a8f78 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinJvmFieldSignatureInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinJvmFieldSignatureInfo.java
@@ -8,7 +8,6 @@
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.Box;
 import java.util.function.Consumer;
@@ -38,16 +37,12 @@
         KotlinTypeReference.fromDescriptor(fieldSignature.getDesc(), factory));
   }
 
-  boolean rewrite(
-      Consumer<JvmFieldSignature> consumer,
-      DexEncodedField field,
-      AppView<?> appView,
-      NamingLens namingLens) {
+  boolean rewrite(Consumer<JvmFieldSignature> consumer, DexEncodedField field, AppView<?> appView) {
     boolean rewritten = false;
     String finalName = name;
     if (field != null) {
       String fieldName = field.getReference().name.toString();
-      String rewrittenName = namingLens.lookupName(field.getReference()).toString();
+      String rewrittenName = appView.getNamingLens().lookupName(field.getReference()).toString();
       if (!fieldName.equals(rewrittenName)) {
         rewritten = true;
         finalName = rewrittenName;
@@ -55,8 +50,7 @@
     }
     String defValue = appView.dexItemFactory().objectType.toDescriptorString();
     Box<String> renamedDescriptor = new Box<>();
-    rewritten |=
-        type.toRenamedDescriptorOrDefault(renamedDescriptor::set, appView, namingLens, defValue);
+    rewritten |= type.toRenamedDescriptorOrDefault(renamedDescriptor::set, appView, defValue);
     consumer.accept(new JvmFieldSignature(finalName, renamedDescriptor.get()));
     return rewritten;
   }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinJvmMethodSignatureInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinJvmMethodSignatureInfo.java
index 5cfa5ac..2760ece 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinJvmMethodSignatureInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinJvmMethodSignatureInfo.java
@@ -10,7 +10,6 @@
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.google.common.collect.ImmutableList;
@@ -72,10 +71,7 @@
   }
 
   boolean rewrite(
-      Consumer<JvmMethodSignature> consumer,
-      DexEncodedMethod method,
-      AppView<?> appView,
-      NamingLens namingLens) {
+      Consumer<JvmMethodSignature> consumer, DexEncodedMethod method, AppView<?> appView) {
     if (invalidDescriptor != null) {
       consumer.accept(new JvmMethodSignature(name, invalidDescriptor));
       return false;
@@ -85,7 +81,7 @@
     boolean rewritten = false;
     if (method != null) {
       String methodName = method.getReference().name.toString();
-      String rewrittenName = namingLens.lookupName(method.getReference()).toString();
+      String rewrittenName = appView.getNamingLens().lookupName(method.getReference()).toString();
       if (!methodName.equals(rewrittenName)) {
         finalName = rewrittenName;
         rewritten = true;
@@ -95,13 +91,10 @@
     descBuilder.append("(");
     String defValue = appView.dexItemFactory().objectType.toDescriptorString();
     for (KotlinTypeReference parameter : parameters) {
-      rewritten |=
-          parameter.toRenamedDescriptorOrDefault(
-              descBuilder::append, appView, namingLens, defValue);
+      rewritten |= parameter.toRenamedDescriptorOrDefault(descBuilder::append, appView, defValue);
     }
     descBuilder.append(")");
-    rewritten |=
-        returnType.toRenamedDescriptorOrDefault(descBuilder::append, appView, namingLens, defValue);
+    rewritten |= returnType.toRenamedDescriptorOrDefault(descBuilder::append, appView, defValue);
     consumer.accept(new JvmMethodSignature(finalName, descBuilder.toString()));
     return rewritten;
   }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinLambdaInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinLambdaInfo.java
index b9e4f84..ffe08b4 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinLambdaInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinLambdaInfo.java
@@ -11,7 +11,6 @@
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.Reporter;
 import kotlinx.metadata.KmLambda;
@@ -60,10 +59,9 @@
   boolean rewrite(
       KmVisitorProviders.KmLambdaVisitorProvider visitorProvider,
       DexClass clazz,
-      AppView<?> appView,
-      NamingLens namingLens) {
+      AppView<?> appView) {
     if (!hasBacking) {
-      function.rewrite(visitorProvider.get()::visitFunction, null, appView, namingLens);
+      function.rewrite(visitorProvider.get()::visitFunction, null, appView);
       return true;
     }
     DexEncodedMethod backing = null;
@@ -73,7 +71,7 @@
         break;
       }
     }
-    return function.rewrite(visitorProvider.get()::visitFunction, backing, appView, namingLens);
+    return function.rewrite(visitorProvider.get()::visitFunction, backing, appView);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinLocalDelegatedPropertyInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinLocalDelegatedPropertyInfo.java
index 9548bde..4bdce09 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinLocalDelegatedPropertyInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinLocalDelegatedPropertyInfo.java
@@ -10,7 +10,6 @@
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.kotlin.KmVisitorProviders.KmPropertyVisitorProvider;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.Reporter;
 import com.google.common.collect.ImmutableList;
@@ -52,11 +51,10 @@
     forEachApply(propertyInfos, prop -> prop::trace, definitionSupplier);
   }
 
-  boolean rewrite(
-      KmPropertyVisitorProvider visitorProvider, AppView<?> appView, NamingLens namingLens) {
+  boolean rewrite(KmPropertyVisitorProvider visitorProvider, AppView<?> appView) {
     boolean rewritten = false;
     for (KotlinPropertyInfo propertyInfo : propertyInfos) {
-      rewritten |= propertyInfo.rewrite(visitorProvider, null, null, null, appView, namingLens);
+      rewritten |= propertyInfo.rewrite(visitorProvider, null, null, null, appView);
     }
     return rewritten;
   }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
index fb6575c..5353319 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
@@ -20,7 +20,6 @@
 import com.android.tools.r8.graph.DexValue.DexValueArray;
 import com.android.tools.r8.graph.DexValue.DexValueInt;
 import com.android.tools.r8.graph.DexValue.DexValueString;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.utils.ConsumerUtils;
 import com.android.tools.r8.utils.Pair;
 import com.android.tools.r8.utils.ThreadUtils;
@@ -71,13 +70,11 @@
   }
 
   private final AppView<?> appView;
-  private final NamingLens lens;
   private final DexItemFactory factory;
   private final Kotlin kotlin;
 
-  public KotlinMetadataRewriter(AppView<?> appView, NamingLens lens) {
+  public KotlinMetadataRewriter(AppView<?> appView) {
     this.appView = appView;
-    this.lens = lens;
     this.factory = appView.dexItemFactory();
     this.kotlin = factory.kotlin;
   }
@@ -130,7 +127,7 @@
   }
 
   public void runForD8(ExecutorService executorService) throws ExecutionException {
-    if (lens.isIdentityLens()) {
+    if (appView.getNamingLens().isIdentityLens()) {
       return;
     }
     final WriteMetadataFieldInfo writeMetadataFieldInfo = WriteMetadataFieldInfo.rewriteAll();
@@ -158,7 +155,7 @@
       DexAnnotation oldMeta,
       WriteMetadataFieldInfo writeMetadataFieldInfo) {
     try {
-      Pair<KotlinClassHeader, Boolean> kotlinClassHeader = kotlinInfo.rewrite(clazz, appView, lens);
+      Pair<KotlinClassHeader, Boolean> kotlinClassHeader = kotlinInfo.rewrite(clazz, appView);
       // TODO(b/185756596): Remove when special handling is no longer needed.
       if (!kotlinClassHeader.getSecond()
           && appView.options().testing.keepMetadataInR8IfNotRewritten) {
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java
index 1d927fe..d5884f5 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java
@@ -14,7 +14,6 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.InnerClassAttribute;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.shaking.ProguardConfiguration;
 import com.android.tools.r8.shaking.ProguardConfigurationRule;
 import com.android.tools.r8.shaking.ProguardKeepRule;
@@ -51,8 +50,7 @@
     }
 
     @Override
-    public Pair<KotlinClassHeader, Boolean> rewrite(
-        DexClass clazz, AppView<?> appView, NamingLens namingLens) {
+    public Pair<KotlinClassHeader, Boolean> rewrite(DexClass clazz, AppView<?> appView) {
       throw new Unreachable("Should never be called");
     }
 
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassFacadeInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassFacadeInfo.java
index 0545b20..2a89998 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassFacadeInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassFacadeInfo.java
@@ -10,7 +10,6 @@
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.utils.Pair;
 import com.google.common.collect.ImmutableList;
 import java.util.ArrayList;
@@ -56,8 +55,7 @@
   }
 
   @Override
-  public Pair<KotlinClassHeader, Boolean> rewrite(
-      DexClass clazz, AppView<?> appView, NamingLens namingLens) {
+  public Pair<KotlinClassHeader, Boolean> rewrite(DexClass clazz, AppView<?> appView) {
     List<String> partClassNameStrings = new ArrayList<>(partClassNames.size());
     boolean rewritten = false;
     for (KotlinTypeReference partClassName : partClassNames) {
@@ -69,7 +67,6 @@
                 }
               },
               appView,
-              namingLens,
               null);
     }
     KotlinClassMetadata.MultiFileClassFacade.Writer writer =
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassPartInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassPartInfo.java
index 24cb385..6c96b8d 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassPartInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassPartInfo.java
@@ -8,7 +8,6 @@
 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.naming.NamingLens;
 import com.android.tools.r8.utils.Pair;
 import java.util.function.Consumer;
 import kotlinx.metadata.KmPackage;
@@ -65,10 +64,9 @@
   }
 
   @Override
-  public Pair<KotlinClassHeader, Boolean> rewrite(
-      DexClass clazz, AppView<?> appView, NamingLens namingLens) {
+  public Pair<KotlinClassHeader, Boolean> rewrite(DexClass clazz, AppView<?> appView) {
     KmPackage kmPackage = new KmPackage();
-    boolean rewritten = packageInfo.rewrite(kmPackage, clazz, appView, namingLens);
+    boolean rewritten = packageInfo.rewrite(kmPackage, clazz, appView);
     KotlinClassMetadata.MultiFileClassPart.Writer writer =
         new KotlinClassMetadata.MultiFileClassPart.Writer();
     kmPackage.accept(writer);
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinPackageInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinPackageInfo.java
index fa483ae..f1e2573 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinPackageInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinPackageInfo.java
@@ -12,7 +12,6 @@
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import java.util.HashMap;
 import java.util.Map;
@@ -74,7 +73,7 @@
         originalMembersWithKotlinInfo);
   }
 
-  boolean rewrite(KmPackage kmPackage, DexClass clazz, AppView<?> appView, NamingLens namingLens) {
+  boolean rewrite(KmPackage kmPackage, DexClass clazz, AppView<?> appView) {
     KotlinMetadataMembersTracker rewrittenReferences = new KotlinMetadataMembersTracker(appView);
     boolean rewritten =
         containerInfo.rewrite(
@@ -83,13 +82,11 @@
             kmPackage::visitTypeAlias,
             clazz,
             appView,
-            namingLens,
             rewrittenReferences);
     JvmPackageExtensionVisitor extensionVisitor =
         (JvmPackageExtensionVisitor) kmPackage.visitExtensions(JvmPackageExtensionVisitor.TYPE);
     rewritten |=
-        localDelegatedProperties.rewrite(
-            extensionVisitor::visitLocalDelegatedProperty, appView, namingLens);
+        localDelegatedProperties.rewrite(extensionVisitor::visitLocalDelegatedProperty, appView);
     extensionVisitor.visitModuleName(moduleName);
     extensionVisitor.visitEnd();
     return rewritten || !originalMembersWithKotlinInfo.isEqual(rewrittenReferences, appView);
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinPropertyInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinPropertyInfo.java
index 39ab90c..6d10139 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinPropertyInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinPropertyInfo.java
@@ -11,7 +11,6 @@
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.utils.Box;
 import com.android.tools.r8.utils.Reporter;
 import java.util.List;
@@ -144,25 +143,22 @@
       DexEncodedField field,
       DexEncodedMethod getter,
       DexEncodedMethod setter,
-      AppView<?> appView,
-      NamingLens namingLens) {
+      AppView<?> appView) {
     // TODO(b/154348683): Flags again.
     KmPropertyVisitor kmProperty = visitorProvider.get(flags, name, getterFlags, setterFlags);
     // TODO(b/154348149): ReturnType could have been merged to a subtype.
     boolean rewritten = false;
     if (returnType != null) {
-      rewritten = returnType.rewrite(kmProperty::visitReturnType, appView, namingLens);
+      rewritten = returnType.rewrite(kmProperty::visitReturnType, appView);
     }
     if (receiverParameterType != null) {
-      rewritten |=
-          receiverParameterType.rewrite(
-              kmProperty::visitReceiverParameterType, appView, namingLens);
+      rewritten |= receiverParameterType.rewrite(kmProperty::visitReceiverParameterType, appView);
     }
     if (setterParameter != null) {
-      rewritten |= setterParameter.rewrite(kmProperty::visitSetterParameter, appView, namingLens);
+      rewritten |= setterParameter.rewrite(kmProperty::visitSetterParameter, appView);
     }
     for (KotlinTypeParameterInfo typeParameter : typeParameters) {
-      rewritten |= typeParameter.rewrite(kmProperty::visitTypeParameter, appView, namingLens);
+      rewritten |= typeParameter.rewrite(kmProperty::visitTypeParameter, appView);
     }
     rewritten |= versionRequirements.rewrite(kmProperty::visitVersionRequirement);
     JvmPropertyExtensionVisitor extensionVisitor =
@@ -170,18 +166,15 @@
     if (extensionVisitor != null) {
       Box<JvmFieldSignature> rewrittenFieldSignature = new Box<>();
       if (fieldSignature != null) {
-        rewritten |=
-            fieldSignature.rewrite(rewrittenFieldSignature::set, field, appView, namingLens);
+        rewritten |= fieldSignature.rewrite(rewrittenFieldSignature::set, field, appView);
       }
       Box<JvmMethodSignature> rewrittenGetterSignature = new Box<>();
       if (getterSignature != null) {
-        rewritten |=
-            getterSignature.rewrite(rewrittenGetterSignature::set, getter, appView, namingLens);
+        rewritten |= getterSignature.rewrite(rewrittenGetterSignature::set, getter, appView);
       }
       Box<JvmMethodSignature> rewrittenSetterSignature = new Box<>();
       if (setterSignature != null) {
-        rewritten |=
-            setterSignature.rewrite(rewrittenSetterSignature::set, setter, appView, namingLens);
+        rewritten |= setterSignature.rewrite(rewrittenSetterSignature::set, setter, appView);
       }
       extensionVisitor.visit(
           jvmFlags,
@@ -191,12 +184,12 @@
       if (syntheticMethodForAnnotations != null) {
         rewritten |=
             syntheticMethodForAnnotations.rewrite(
-                extensionVisitor::visitSyntheticMethodForAnnotations, null, appView, namingLens);
+                extensionVisitor::visitSyntheticMethodForAnnotations, null, appView);
       }
       if (syntheticMethodForDelegate != null) {
         rewritten |=
             syntheticMethodForDelegate.rewrite(
-                extensionVisitor::visitSyntheticMethodForDelegate, null, appView, namingLens);
+                extensionVisitor::visitSyntheticMethodForDelegate, null, appView);
       }
     }
     return rewritten;
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinSyntheticClassInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinSyntheticClassInfo.java
index ee55f8b..fb9b55f 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinSyntheticClassInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinSyntheticClassInfo.java
@@ -7,7 +7,6 @@
 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.naming.NamingLens;
 import com.android.tools.r8.utils.Pair;
 import kotlinx.metadata.KmLambda;
 import kotlinx.metadata.jvm.KotlinClassHeader;
@@ -74,13 +73,12 @@
   }
 
   @Override
-  public Pair<KotlinClassHeader, Boolean> rewrite(
-      DexClass clazz, AppView<?> appView, NamingLens namingLens) {
+  public Pair<KotlinClassHeader, Boolean> rewrite(DexClass clazz, AppView<?> appView) {
     Writer writer = new Writer();
     boolean rewritten = false;
     if (lambda != null) {
       KmLambda kmLambda = new KmLambda();
-      rewritten = lambda.rewrite(() -> kmLambda, clazz, appView, namingLens);
+      rewritten = lambda.rewrite(() -> kmLambda, clazz, appView);
       kmLambda.accept(writer);
     }
     return Pair.create(writer.write().getHeader(), rewritten);
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeAliasInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeAliasInfo.java
index c4e307b..8f89b9e 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeAliasInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeAliasInfo.java
@@ -9,7 +9,6 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.Reporter;
 import java.util.List;
@@ -59,19 +58,15 @@
   }
 
   boolean rewrite(
-      KmVisitorProviders.KmTypeAliasVisitorProvider visitorProvider,
-      AppView<?> appView,
-      NamingLens namingLens) {
+      KmVisitorProviders.KmTypeAliasVisitorProvider visitorProvider, AppView<?> appView) {
     KmTypeAliasVisitor kmTypeAliasVisitor = visitorProvider.get(flags, name);
-    boolean rewritten =
-        underlyingType.rewrite(kmTypeAliasVisitor::visitUnderlyingType, appView, namingLens);
-    rewritten |= expandedType.rewrite(kmTypeAliasVisitor::visitExpandedType, appView, namingLens);
+    boolean rewritten = underlyingType.rewrite(kmTypeAliasVisitor::visitUnderlyingType, appView);
+    rewritten |= expandedType.rewrite(kmTypeAliasVisitor::visitExpandedType, appView);
     for (KotlinTypeParameterInfo typeParameter : typeParameters) {
-      rewritten |=
-          typeParameter.rewrite(kmTypeAliasVisitor::visitTypeParameter, appView, namingLens);
+      rewritten |= typeParameter.rewrite(kmTypeAliasVisitor::visitTypeParameter, appView);
     }
     for (KotlinAnnotationInfo annotation : annotations) {
-      rewritten |= annotation.rewrite(kmTypeAliasVisitor::visitAnnotation, appView, namingLens);
+      rewritten |= annotation.rewrite(kmTypeAliasVisitor::visitAnnotation, appView);
     }
     rewritten |= versionRequirements.rewrite(kmTypeAliasVisitor::visitVersionRequirement);
     return rewritten;
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeInfo.java
index 6127754..e83cff6 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeInfo.java
@@ -83,31 +83,24 @@
     return arguments.build();
   }
 
-  boolean rewrite(
-      KmVisitorProviders.KmTypeVisitorProvider visitorProvider,
-      AppView<?> appView,
-      NamingLens namingLens) {
+  boolean rewrite(KmVisitorProviders.KmTypeVisitorProvider visitorProvider, AppView<?> appView) {
     // TODO(b/154348683): Check for correct flags
     KmTypeVisitor kmTypeVisitor = visitorProvider.get(flags);
-    boolean rewritten = classifier.rewrite(kmTypeVisitor, appView, namingLens);
+    NamingLens namingLens = appView.getNamingLens();
+    boolean rewritten = classifier.rewrite(kmTypeVisitor, appView);
     if (abbreviatedType != null) {
-      rewritten |=
-          abbreviatedType.rewrite(kmTypeVisitor::visitAbbreviatedType, appView, namingLens);
+      rewritten |= abbreviatedType.rewrite(kmTypeVisitor::visitAbbreviatedType, appView);
     }
     if (outerType != null) {
-      rewritten |= outerType.rewrite(kmTypeVisitor::visitOuterType, appView, namingLens);
+      rewritten |= outerType.rewrite(kmTypeVisitor::visitOuterType, appView);
     }
     for (KotlinTypeProjectionInfo argument : arguments) {
       rewritten |=
           argument.rewrite(
-              kmTypeVisitor::visitArgument,
-              kmTypeVisitor::visitStarProjection,
-              appView,
-              namingLens);
+              kmTypeVisitor::visitArgument, kmTypeVisitor::visitStarProjection, appView);
     }
     rewritten |=
-        flexibleTypeUpperBound.rewrite(
-            kmTypeVisitor::visitFlexibleTypeUpperBound, appView, namingLens);
+        flexibleTypeUpperBound.rewrite(kmTypeVisitor::visitFlexibleTypeUpperBound, appView);
     if (annotations.isEmpty() && !isRaw) {
       return rewritten;
     }
@@ -115,7 +108,7 @@
         (JvmTypeExtensionVisitor) kmTypeVisitor.visitExtensions(JvmTypeExtensionVisitor.TYPE);
     if (extensionVisitor != null) {
       for (KotlinAnnotationInfo annotation : annotations) {
-        rewritten |= annotation.rewrite(extensionVisitor::visitAnnotation, appView, namingLens);
+        rewritten |= annotation.rewrite(extensionVisitor::visitAnnotation, appView);
       }
       extensionVisitor.visit(isRaw);
     }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeParameterInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeParameterInfo.java
index 21aeaa1..e6cc10f 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeParameterInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeParameterInfo.java
@@ -9,7 +9,6 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.Reporter;
 import com.google.common.collect.ImmutableList;
@@ -85,14 +84,11 @@
   }
 
   boolean rewrite(
-      KmVisitorProviders.KmTypeParameterVisitorProvider visitorProvider,
-      AppView<?> appView,
-      NamingLens namingLens) {
+      KmVisitorProviders.KmTypeParameterVisitorProvider visitorProvider, AppView<?> appView) {
     KmTypeParameterVisitor kmTypeParameterVisitor = visitorProvider.get(flags, name, id, variance);
     boolean rewritten = false;
     for (KotlinTypeInfo originalUpperBound : originalUpperBounds) {
-      rewritten |=
-          originalUpperBound.rewrite(kmTypeParameterVisitor::visitUpperBound, appView, namingLens);
+      rewritten |= originalUpperBound.rewrite(kmTypeParameterVisitor::visitUpperBound, appView);
     }
     if (annotations.isEmpty()) {
       return rewritten;
@@ -102,7 +98,7 @@
             kmTypeParameterVisitor.visitExtensions(JvmTypeParameterExtensionVisitor.TYPE);
     if (extensionVisitor != null) {
       for (KotlinAnnotationInfo annotation : annotations) {
-        rewritten |= annotation.rewrite(extensionVisitor::visitAnnotation, appView, namingLens);
+        rewritten |= annotation.rewrite(extensionVisitor::visitAnnotation, appView);
       }
     }
     return rewritten;
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeProjectionInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeProjectionInfo.java
index 8fe760b..85791fe 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeProjectionInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeProjectionInfo.java
@@ -7,7 +7,6 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.Reporter;
 import kotlinx.metadata.KmTypeProjection;
@@ -38,13 +37,12 @@
   boolean rewrite(
       KmVisitorProviders.KmTypeProjectionVisitorProvider visitorProvider,
       KmVisitorProviders.KmTypeStarProjectionVisitorProvider starProjectionProvider,
-      AppView<?> appView,
-      NamingLens namingLens) {
+      AppView<?> appView) {
     if (isStarProjection()) {
       starProjectionProvider.get();
       return false;
     } else {
-      return typeInfo.rewrite(flags -> visitorProvider.get(flags, variance), appView, namingLens);
+      return typeInfo.rewrite(flags -> visitorProvider.get(flags, variance), appView);
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
index 4fd93a0..adbb277 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
@@ -12,7 +12,6 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.kotlin.Kotlin.ClassClassifiers;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.DescriptorUtils;
 import java.util.function.Consumer;
@@ -72,7 +71,6 @@
   boolean toRenamedDescriptorOrDefault(
       Consumer<String> rewrittenConsumer,
       AppView<?> appView,
-      NamingLens namingLens,
       String defaultValue) {
     if (known == null) {
       rewrittenConsumer.accept(originalName);
@@ -91,7 +89,7 @@
         return true;
       }
     }
-    String renamedString = namingLens.lookupDescriptor(rewrittenType).toString();
+    String renamedString = appView.getNamingLens().lookupDescriptor(rewrittenType).toString();
     rewrittenConsumer.accept(renamedString);
     return !known.toDescriptorString().equals(renamedString);
   }
@@ -107,7 +105,6 @@
   boolean toRenamedBinaryNameOrDefault(
       Consumer<String> rewrittenConsumer,
       AppView<?> appView,
-      NamingLens namingLens,
       String defaultValue) {
     if (known == null) {
       // Unknown values are always on the input form, so we can just return it.
@@ -124,7 +121,6 @@
           }
         },
         appView,
-        namingLens,
         defaultValue);
   }
 
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinValueParameterInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinValueParameterInfo.java
index 293c35a..1e12db6 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinValueParameterInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinValueParameterInfo.java
@@ -7,7 +7,6 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.Reporter;
 import com.google.common.collect.ImmutableList;
@@ -67,15 +66,12 @@
   }
 
   boolean rewrite(
-      KmVisitorProviders.KmValueParameterVisitorProvider visitorProvider,
-      AppView<?> appView,
-      NamingLens namingLens) {
+      KmVisitorProviders.KmValueParameterVisitorProvider visitorProvider, AppView<?> appView) {
     KmValueParameterVisitor kmValueParameterVisitor = visitorProvider.get(flags, name);
-    boolean rewritten = type.rewrite(kmValueParameterVisitor::visitType, appView, namingLens);
+    boolean rewritten = type.rewrite(kmValueParameterVisitor::visitType, appView);
     if (varargElementType != null) {
       rewritten |=
-          varargElementType.rewrite(
-              kmValueParameterVisitor::visitVarargElementType, appView, namingLens);
+          varargElementType.rewrite(kmValueParameterVisitor::visitVarargElementType, appView);
     }
     return rewritten;
   }
diff --git a/src/main/java/com/android/tools/r8/naming/IdentifierMinifier.java b/src/main/java/com/android/tools/r8/naming/IdentifierMinifier.java
index 0ad986c..ada07f6 100644
--- a/src/main/java/com/android/tools/r8/naming/IdentifierMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/IdentifierMinifier.java
@@ -8,9 +8,9 @@
 import com.android.tools.r8.cf.code.CfConstString;
 import com.android.tools.r8.cf.code.CfDexItemBasedConstString;
 import com.android.tools.r8.cf.code.CfInstruction;
-import com.android.tools.r8.code.ConstString;
-import com.android.tools.r8.code.DexItemBasedConstString;
-import com.android.tools.r8.code.Instruction;
+import com.android.tools.r8.dex.code.DexConstString;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexItemBasedConstString;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.Code;
 import com.android.tools.r8.graph.DexClass;
@@ -91,9 +91,9 @@
       return;
     }
     if (code.isDexCode()) {
-      for (Instruction instruction : code.asDexCode().instructions) {
+      for (DexInstruction instruction : code.asDexCode().instructions) {
         if (instruction.isConstString()) {
-          ConstString cnst = instruction.asConstString();
+          DexConstString cnst = instruction.asConstString();
           cnst.BBBB = getRenamedStringLiteral(cnst.getString());
         }
       }
@@ -163,15 +163,15 @@
     Code code = programMethod.getDefinition().getCode();
     assert code != null;
     if (code.isDexCode()) {
-      Instruction[] instructions = code.asDexCode().instructions;
+      DexInstruction[] instructions = code.asDexCode().instructions;
       for (int i = 0; i < instructions.length; ++i) {
-        Instruction instruction = instructions[i];
+        DexInstruction instruction = instructions[i];
         if (instruction.isDexItemBasedConstString()) {
           DexItemBasedConstString cnst = instruction.asDexItemBasedConstString();
           DexString replacement =
               cnst.getNameComputationInfo()
                   .computeNameFor(cnst.getItem(), appView, appView.graphLens(), lens);
-          ConstString constString = new ConstString(cnst.AA, replacement);
+          DexConstString constString = new DexConstString(cnst.AA, replacement);
           constString.setOffset(instruction.getOffset());
           instructions[i] = constString;
         }
diff --git a/src/main/java/com/android/tools/r8/naming/PrefixRewritingNamingLens.java b/src/main/java/com/android/tools/r8/naming/PrefixRewritingNamingLens.java
index 2add666..297c363 100644
--- a/src/main/java/com/android/tools/r8/naming/PrefixRewritingNamingLens.java
+++ b/src/main/java/com/android/tools/r8/naming/PrefixRewritingNamingLens.java
@@ -16,27 +16,20 @@
 // Naming lens for rewriting type prefixes.
 public class PrefixRewritingNamingLens extends NonIdentityNamingLens {
 
-  final NamingLens namingLens;
-  final InternalOptions options;
-  final AppView<?> appView;
+  private final AppView<?> appView;
+  private final NamingLens namingLens;
 
   public static NamingLens createPrefixRewritingNamingLens(AppView<?> appView) {
-    return createPrefixRewritingNamingLens(appView, NamingLens.getIdentityLens());
-  }
-
-  public static NamingLens createPrefixRewritingNamingLens(
-      AppView<?> appView, NamingLens namingLens) {
     if (!appView.typeRewriter.isRewriting()) {
-      return namingLens;
+      return appView.getNamingLens();
     }
-    return new PrefixRewritingNamingLens(namingLens, appView);
+    return new PrefixRewritingNamingLens(appView);
   }
 
-  public PrefixRewritingNamingLens(NamingLens namingLens, AppView<?> appView) {
+  public PrefixRewritingNamingLens(AppView<?> appView) {
     super(appView.dexItemFactory());
     this.appView = appView;
-    this.namingLens = namingLens;
-    this.options = appView.options();
+    this.namingLens = appView.getNamingLens();
   }
 
   private boolean isRenamed(DexType type) {
diff --git a/src/main/java/com/android/tools/r8/naming/RecordRewritingNamingLens.java b/src/main/java/com/android/tools/r8/naming/RecordRewritingNamingLens.java
index fe2654f..9fdb66a 100644
--- a/src/main/java/com/android/tools/r8/naming/RecordRewritingNamingLens.java
+++ b/src/main/java/com/android/tools/r8/naming/RecordRewritingNamingLens.java
@@ -17,25 +17,24 @@
 // Naming lens for rewriting java.lang.Record to the internal RecordTag type.
 public class RecordRewritingNamingLens extends NonIdentityNamingLens {
 
-  final NamingLens namingLens;
   private final DexItemFactory factory;
+  private final NamingLens namingLens;
 
-  public static NamingLens createRecordRewritingNamingLens(
-      AppView<?> appView, NamingLens namingLens) {
+  public static NamingLens createRecordRewritingNamingLens(AppView<?> appView) {
     if (appView.options().shouldDesugarRecords()
         && appView
                 .appInfo()
                 .definitionForWithoutExistenceAssert(appView.dexItemFactory().recordType)
             != null) {
-      return new RecordRewritingNamingLens(namingLens, appView);
+      return new RecordRewritingNamingLens(appView);
     }
-    return namingLens;
+    return appView.getNamingLens();
   }
 
-  public RecordRewritingNamingLens(NamingLens namingLens, AppView<?> appView) {
+  public RecordRewritingNamingLens(AppView<?> appView) {
     super(appView.dexItemFactory());
-    this.namingLens = namingLens;
-    factory = appView.dexItemFactory();
+    this.factory = appView.dexItemFactory();
+    this.namingLens = appView.getNamingLens();
   }
 
   private boolean isRenamed(DexType type) {
diff --git a/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java b/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java
index e50737d..e4b384f 100644
--- a/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java
+++ b/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java
@@ -12,7 +12,6 @@
 import com.android.tools.r8.graph.GenericSignatureContextBuilder;
 import com.android.tools.r8.graph.GenericSignaturePartialTypeArgumentApplier;
 import com.android.tools.r8.graph.GenericSignatureTypeRewriter;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.utils.IterableUtils;
 import com.android.tools.r8.utils.ThreadUtils;
 import java.util.concurrent.ExecutionException;
@@ -24,23 +23,21 @@
 public class GenericSignatureRewriter {
 
   private final AppView<?> appView;
-  private final NamingLens namingLens;
   private final GenericSignatureContextBuilder contextBuilder;
 
-  public GenericSignatureRewriter(AppView<?> appView, NamingLens namingLens) {
-    this(appView, namingLens, null);
+  public GenericSignatureRewriter(AppView<?> appView) {
+    this(appView, null);
   }
 
   public GenericSignatureRewriter(
-      AppView<?> appView, NamingLens namingLens, GenericSignatureContextBuilder contextBuilder) {
+      AppView<?> appView, GenericSignatureContextBuilder contextBuilder) {
     this.appView = appView;
-    this.namingLens = namingLens;
     this.contextBuilder = contextBuilder;
   }
 
   public void runForD8(Iterable<? extends DexProgramClass> classes, ExecutorService executorService)
       throws ExecutionException {
-    if (namingLens.isIdentityLens()) {
+    if (appView.getNamingLens().isIdentityLens()) {
       return;
     }
     run(classes, executorService);
@@ -50,7 +47,7 @@
       throws ExecutionException {
     // Rewrite signature annotations for applications that are minified or if we have liveness
     // information, since we could have pruned types.
-    if (namingLens.isIdentityLens()
+    if (appView.getNamingLens().isIdentityLens()
         && !appView.appInfo().hasLiveness()
         && !appView.options().parseSignatureAttribute()) {
       return;
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
index a03ff91..0f67814 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
@@ -291,6 +291,14 @@
             return;
           }
 
+          if (method.getHolderType().isArrayType()) {
+            assert resolutionResult.getResolvedHolder().getType()
+                == appView.dexItemFactory().objectType;
+            lensBuilder.map(
+                method, resolutionResult.getResolvedMethod().getReference(), invokeType);
+            return;
+          }
+
           // TODO(b/128404854) Rebind to the lowest library class or program class. For now we allow
           //  searching in library for methods, but this should be done on classpath instead.
           DexClassAndMethod resolvedMethod = resolutionResult.getResolutionPair();
diff --git a/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java b/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java
index f640d08..09966ca 100644
--- a/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java
+++ b/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java
@@ -7,9 +7,9 @@
 
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.cf.code.CfInvoke;
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.InvokeVirtual;
-import com.android.tools.r8.code.InvokeVirtualRange;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexInvokeVirtual;
+import com.android.tools.r8.dex.code.DexInvokeVirtualRange;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.BottomUpClassHierarchyTraversal;
@@ -332,24 +332,24 @@
   }
 
   private DexCode createDexCodeForVirtualBridge(DexCode code, DexMethod methodToInvoke) {
-    Instruction[] newInstructions = new Instruction[code.instructions.length];
+    DexInstruction[] newInstructions = new DexInstruction[code.instructions.length];
     boolean modified = false;
     for (int i = 0; i < code.instructions.length; i++) {
-      Instruction instruction = code.instructions[i];
+      DexInstruction instruction = code.instructions[i];
       if (instruction.isInvokeVirtual()
           && instruction.asInvokeVirtual().getMethod() != methodToInvoke) {
-        InvokeVirtual invoke = instruction.asInvokeVirtual();
-        InvokeVirtual newInvoke =
-            new InvokeVirtual(
+        DexInvokeVirtual invoke = instruction.asInvokeVirtual();
+        DexInvokeVirtual newInvoke =
+            new DexInvokeVirtual(
                 invoke.A, methodToInvoke, invoke.C, invoke.D, invoke.E, invoke.F, invoke.G);
         newInvoke.setOffset(invoke.getOffset());
         newInstructions[i] = newInvoke;
         modified = true;
       } else if (instruction.isInvokeVirtualRange()
           && instruction.asInvokeVirtualRange().getMethod() != methodToInvoke) {
-        InvokeVirtualRange invoke = instruction.asInvokeVirtualRange();
-        InvokeVirtualRange newInvoke =
-            new InvokeVirtualRange(invoke.CCCC, invoke.AA, methodToInvoke);
+        DexInvokeVirtualRange invoke = instruction.asInvokeVirtualRange();
+        DexInvokeVirtualRange newInvoke =
+            new DexInvokeVirtualRange(invoke.CCCC, invoke.AA, methodToInvoke);
         newInvoke.setOffset(invoke.getOffset());
         modified = true;
         newInstructions[i] = newInvoke;
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/BottomCfFrameState.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/BottomCfFrameState.java
index 3c647b9..fc3c106 100644
--- a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/BottomCfFrameState.java
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/BottomCfFrameState.java
@@ -4,13 +4,11 @@
 
 package com.android.tools.r8.optimize.interfaces.analysis;
 
-import com.android.tools.r8.cf.code.CfAssignability;
 import com.android.tools.r8.cf.code.CfFrame;
 import com.android.tools.r8.cf.code.CfFrame.FrameType;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.code.ValueType;
 import java.util.function.BiFunction;
 
@@ -31,11 +29,7 @@
 
   @Override
   public CfFrameState check(AppView<?> appView, CfFrame frame) {
-    if (CfAssignability.isFrameAssignable(new CfFrame(), frame, appView).isFailed()) {
-      return error();
-    }
-    CfFrame frameCopy = frame.mutableCopy();
-    return new ConcreteCfFrameState(frameCopy.getLocals(), frameCopy.getStack());
+    return new ConcreteCfFrameState().check(appView, frame);
   }
 
   @Override
@@ -45,60 +39,61 @@
 
   @Override
   public CfFrameState markInitialized(FrameType uninitializedType, DexType initializedType) {
-    return error();
+    // Initializing an uninitialized type is a no-op when the frame is empty.
+    return this;
   }
 
   @Override
-  public CfFrameState pop() {
-    return error();
+  public ErroneousCfFrameState pop() {
+    return error("Unexpected pop from empty stack");
   }
 
   @Override
-  public CfFrameState pop(BiFunction<CfFrameState, FrameType, CfFrameState> fn) {
-    return error();
+  public ErroneousCfFrameState pop(BiFunction<CfFrameState, FrameType, CfFrameState> fn) {
+    return pop();
   }
 
   @Override
-  public CfFrameState popAndInitialize(
-      AppView<?> appView, DexMethod constructor, ProgramMethod context) {
-    return error();
+  public ErroneousCfFrameState popAndInitialize(
+      AppView<?> appView, DexMethod constructor, CfAnalysisConfig config) {
+    return pop();
   }
 
   @Override
-  public CfFrameState popInitialized(
+  public ErroneousCfFrameState popInitialized(
       AppView<?> appView,
       DexType expectedType,
       BiFunction<CfFrameState, FrameType, CfFrameState> fn) {
-    return error();
+    return pop();
   }
 
   @Override
   public CfFrameState popInitialized(AppView<?> appView, DexType... expectedTypes) {
-    return error();
+    return expectedTypes.length == 0 ? this : pop();
   }
 
   @Override
-  public CfFrameState push(DexType type) {
-    return new ConcreteCfFrameState().push(type);
+  public CfFrameState push(CfAnalysisConfig config, DexType type) {
+    return new ConcreteCfFrameState().push(config, type);
   }
 
   @Override
-  public CfFrameState push(FrameType frameType) {
-    return new ConcreteCfFrameState().push(frameType);
+  public CfFrameState push(CfAnalysisConfig config, FrameType frameType) {
+    return new ConcreteCfFrameState().push(config, frameType);
   }
 
   @Override
-  public CfFrameState readLocal(
+  public ErroneousCfFrameState readLocal(
       AppView<?> appView,
       int localIndex,
       ValueType expectedType,
       BiFunction<CfFrameState, FrameType, CfFrameState> fn) {
-    return error();
+    return error("Unexpected local read from empty frame");
   }
 
   @Override
-  public CfFrameState storeLocal(int localIndex, FrameType frameType) {
-    return new ConcreteCfFrameState().storeLocal(localIndex, frameType);
+  public CfFrameState storeLocal(int localIndex, FrameType frameType, CfAnalysisConfig config) {
+    return new ConcreteCfFrameState().storeLocal(localIndex, frameType, config);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfAnalysisConfig.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfAnalysisConfig.java
new file mode 100644
index 0000000..bd8a7c9
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfAnalysisConfig.java
@@ -0,0 +1,19 @@
+// 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.optimize.interfaces.analysis;
+
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
+
+public interface CfAnalysisConfig {
+
+  DexMethod getCurrentContext();
+
+  int getMaxLocals();
+
+  int getMaxStack();
+
+  boolean isImmediateSuperClassOfCurrentContext(DexType type);
+}
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfFrameState.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfFrameState.java
index 1cddb8f..b12cc01 100644
--- a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfFrameState.java
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfFrameState.java
@@ -4,6 +4,9 @@
 
 package com.android.tools.r8.optimize.interfaces.analysis;
 
+import static com.android.tools.r8.optimize.interfaces.analysis.ErroneousCfFrameState.formatActual;
+import static com.android.tools.r8.optimize.interfaces.analysis.ErroneousCfFrameState.formatExpected;
+
 import com.android.tools.r8.cf.code.CfAssignability;
 import com.android.tools.r8.cf.code.CfFrame;
 import com.android.tools.r8.cf.code.CfFrame.FrameType;
@@ -11,7 +14,6 @@
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.framework.intraprocedural.AbstractState;
 import com.android.tools.r8.ir.analysis.type.PrimitiveTypeElement;
 import com.android.tools.r8.ir.code.MemberType;
@@ -20,6 +22,7 @@
 import com.android.tools.r8.utils.FunctionUtils;
 import com.android.tools.r8.utils.TriFunction;
 import java.util.function.BiFunction;
+import java.util.function.UnaryOperator;
 
 public abstract class CfFrameState extends AbstractState<CfFrameState> {
 
@@ -27,8 +30,39 @@
     return BottomCfFrameState.getInstance();
   }
 
-  public static ErroneousCfFrameState error() {
-    return ErroneousCfFrameState.getInstance();
+  public static ErroneousCfFrameState error(String message) {
+    return new ErroneousCfFrameState(message);
+  }
+
+  public static ErroneousCfFrameState errorUnexpectedLocal(
+      FrameType frameType, ValueType expectedType, int localIndex) {
+    return internalError(
+        formatActual(frameType), formatExpected(expectedType), "at local index " + localIndex);
+  }
+
+  public static ErroneousCfFrameState errorUnexpectedStack(
+      FrameType frameType, DexType expectedType) {
+    return internalErrorUnexpectedStack(formatActual(frameType), formatExpected(expectedType));
+  }
+
+  public static ErroneousCfFrameState errorUnexpectedStack(
+      FrameType frameType, FrameType expectedType) {
+    return internalErrorUnexpectedStack(formatActual(frameType), formatExpected(expectedType));
+  }
+
+  public static ErroneousCfFrameState errorUnexpectedStack(
+      FrameType frameType, ValueType expectedType) {
+    return internalErrorUnexpectedStack(formatActual(frameType), formatExpected(expectedType));
+  }
+
+  private static ErroneousCfFrameState internalErrorUnexpectedStack(
+      String actual, String expected) {
+    return internalError(actual, expected, "on stack");
+  }
+
+  private static ErroneousCfFrameState internalError(
+      String actual, String expected, String location) {
+    return error("Expected " + expected + " " + location + ", but was " + actual);
   }
 
   @Override
@@ -36,6 +70,15 @@
     return this;
   }
 
+  @Override
+  public boolean isGreaterThanOrEquals(CfFrameState state) {
+    if (this == state) {
+      return true;
+    }
+    CfFrameState leastUpperBound = join(state, UnaryOperator.identity());
+    return equals(leastUpperBound);
+  }
+
   public boolean isBottom() {
     return false;
   }
@@ -52,6 +95,10 @@
     return false;
   }
 
+  public ErroneousCfFrameState asError() {
+    return null;
+  }
+
   public abstract CfFrameState check(AppView<?> appView, CfFrame frame);
 
   public abstract CfFrameState clear();
@@ -64,7 +111,7 @@
   public abstract CfFrameState pop(BiFunction<CfFrameState, FrameType, CfFrameState> fn);
 
   public abstract CfFrameState popAndInitialize(
-      AppView<?> appView, DexMethod constructor, ProgramMethod context);
+      AppView<?> appView, DexMethod constructor, CfAnalysisConfig config);
 
   public final CfFrameState popInitialized(AppView<?> appView, DexType expectedType) {
     return popInitialized(appView, expectedType, FunctionUtils::getFirst);
@@ -101,22 +148,26 @@
   }
 
   public final CfFrameState popObject(BiFunction<CfFrameState, FrameType, CfFrameState> fn) {
-    return pop((state, head) -> head.isObject() ? fn.apply(state, head) : error());
+    return pop(
+        (state, head) ->
+            head.isObject() ? fn.apply(state, head) : errorUnexpectedStack(head, ValueType.OBJECT));
   }
 
   @SuppressWarnings("InconsistentOverloads")
   public final CfFrameState popObject(
       AppView<?> appView,
       DexType expectedType,
-      ProgramMethod context,
+      CfAnalysisConfig config,
       BiFunction<CfFrameState, FrameType, CfFrameState> fn) {
     return pop(
         (state, head) ->
             head.isObject()
                     && CfAssignability.isAssignable(
-                        head.getObjectType(context), expectedType, appView)
+                        head.getObjectType(config.getCurrentContext().getHolderType()),
+                        expectedType,
+                        appView)
                 ? fn.apply(state, head)
-                : error());
+                : errorUnexpectedStack(head, expectedType));
   }
 
   public final CfFrameState popSingle() {
@@ -124,7 +175,11 @@
   }
 
   public final CfFrameState popSingle(BiFunction<CfFrameState, FrameType, CfFrameState> fn) {
-    return pop((state, single) -> single.isSingle() ? fn.apply(state, single) : error());
+    return pop(
+        (state, single) ->
+            single.isSingle()
+                ? fn.apply(state, single)
+                : errorUnexpectedStack(single, FrameType.oneWord()));
   }
 
   public final CfFrameState popSingles(
@@ -150,61 +205,77 @@
         wideFn);
   }
 
-  // TODO(b/214496607): Pushing a value should return an error if the stack grows larger than the
-  //  max stack height.
-  public abstract CfFrameState push(DexType type);
+  public abstract CfFrameState push(CfAnalysisConfig config, DexType type);
 
-  // TODO(b/214496607): Pushing a value should return an error if the stack grows larger than the
-  //  max stack height.
-  public abstract CfFrameState push(FrameType frameType);
+  public abstract CfFrameState push(CfAnalysisConfig config, FrameType frameType);
 
-  public final CfFrameState push(FrameType frameType, FrameType frameType2) {
-    return push(frameType).push(frameType2);
-  }
-
-  public final CfFrameState push(FrameType frameType, FrameType frameType2, FrameType frameType3) {
-    return push(frameType).push(frameType2).push(frameType3);
+  public final CfFrameState push(
+      CfAnalysisConfig config, FrameType frameType, FrameType frameType2) {
+    return push(config, frameType).push(config, frameType2);
   }
 
   public final CfFrameState push(
-      FrameType frameType, FrameType frameType2, FrameType frameType3, FrameType frameType4) {
-    return push(frameType).push(frameType2).push(frameType3).push(frameType4);
+      CfAnalysisConfig config, FrameType frameType, FrameType frameType2, FrameType frameType3) {
+    return push(config, frameType).push(config, frameType2).push(config, frameType3);
   }
 
   public final CfFrameState push(
+      CfAnalysisConfig config,
+      FrameType frameType,
+      FrameType frameType2,
+      FrameType frameType3,
+      FrameType frameType4) {
+    return push(config, frameType)
+        .push(config, frameType2)
+        .push(config, frameType3)
+        .push(config, frameType4);
+  }
+
+  public final CfFrameState push(
+      CfAnalysisConfig config,
       FrameType frameType,
       FrameType frameType2,
       FrameType frameType3,
       FrameType frameType4,
       FrameType frameType5) {
-    return push(frameType).push(frameType2).push(frameType3).push(frameType4).push(frameType5);
+    return push(config, frameType)
+        .push(config, frameType2)
+        .push(config, frameType3)
+        .push(config, frameType4)
+        .push(config, frameType5);
   }
 
   public final CfFrameState push(
+      CfAnalysisConfig config,
       FrameType frameType,
       FrameType frameType2,
       FrameType frameType3,
       FrameType frameType4,
       FrameType frameType5,
       FrameType frameType6) {
-    return push(frameType)
-        .push(frameType2)
-        .push(frameType3)
-        .push(frameType4)
-        .push(frameType5)
-        .push(frameType6);
+    return push(config, frameType)
+        .push(config, frameType2)
+        .push(config, frameType3)
+        .push(config, frameType4)
+        .push(config, frameType5)
+        .push(config, frameType6);
   }
 
-  public final CfFrameState push(AppView<?> appView, MemberType memberType) {
-    return push(FrameType.fromPreciseMemberType(memberType, appView.dexItemFactory()));
+  @SuppressWarnings("InconsistentOverloads")
+  public final CfFrameState push(
+      AppView<?> appView, CfAnalysisConfig config, MemberType memberType) {
+    return push(config, FrameType.fromPreciseMemberType(memberType, appView.dexItemFactory()));
   }
 
-  public final CfFrameState push(AppView<?> appView, NumericType numericType) {
-    return push(numericType.toDexType(appView.dexItemFactory()));
+  @SuppressWarnings("InconsistentOverloads")
+  public final CfFrameState push(
+      AppView<?> appView, CfAnalysisConfig config, NumericType numericType) {
+    return push(config, numericType.toDexType(appView.dexItemFactory()));
   }
 
-  public final CfFrameState push(AppView<?> appView, ValueType valueType) {
-    return push(valueType.toDexType(appView.dexItemFactory()));
+  @SuppressWarnings("InconsistentOverloads")
+  public final CfFrameState push(AppView<?> appView, CfAnalysisConfig config, ValueType valueType) {
+    return push(config, valueType.toDexType(appView.dexItemFactory()));
   }
 
   public abstract CfFrameState readLocal(
@@ -213,20 +284,32 @@
       ValueType expectedType,
       BiFunction<CfFrameState, FrameType, CfFrameState> consumer);
 
-  public abstract CfFrameState storeLocal(int localIndex, FrameType frameType);
+  public abstract CfFrameState storeLocal(
+      int localIndex, FrameType frameType, CfAnalysisConfig config);
 
   public final CfFrameState storeLocal(
-      int localIndex, PrimitiveTypeElement primitiveType, AppView<?> appView) {
+      int localIndex,
+      PrimitiveTypeElement primitiveType,
+      AppView<?> appView,
+      CfAnalysisConfig config) {
     assert primitiveType.isInt()
         || primitiveType.isFloat()
         || primitiveType.isLong()
         || primitiveType.isDouble();
     return storeLocal(
-        localIndex, FrameType.initialized(primitiveType.toDexType(appView.dexItemFactory())));
+        localIndex,
+        FrameType.initialized(primitiveType.toDexType(appView.dexItemFactory())),
+        config);
   }
 
   @Override
   public final CfFrameState join(CfFrameState state) {
+    return join(
+        state, frameType -> frameType.isSingle() ? FrameType.oneWord() : FrameType.twoWord());
+  }
+
+  public final CfFrameState join(
+      CfFrameState state, UnaryOperator<FrameType> joinWithMissingLocal) {
     if (state.isBottom() || isError()) {
       return this;
     }
@@ -235,7 +318,7 @@
     }
     assert isConcrete();
     assert state.isConcrete();
-    return asConcrete().join(state.asConcrete());
+    return asConcrete().join(state.asConcrete(), joinWithMissingLocal);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfOpenClosedInterfacesAnalysis.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfOpenClosedInterfacesAnalysis.java
index 288f281..33e4cf2 100644
--- a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfOpenClosedInterfacesAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfOpenClosedInterfacesAnalysis.java
@@ -9,7 +9,9 @@
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.Code;
 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.DexType;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.framework.intraprocedural.AbstractTransferFunction;
 import com.android.tools.r8.ir.analysis.framework.intraprocedural.DataflowAnalysisResult;
@@ -53,16 +55,41 @@
   private class TransferFunction
       implements AbstractTransferFunction<CfBlock, CfInstruction, CfFrameState> {
 
-    private final ProgramMethod context;
+    private final CfAnalysisConfig config;
 
     TransferFunction(ProgramMethod context) {
-      this.context = context;
+      CfCode code = context.getDefinition().getCode().asCfCode();
+      int maxLocals = code.getMaxLocals();
+      int maxStack = code.getMaxStack();
+      this.config =
+          new CfAnalysisConfig() {
+
+            @Override
+            public DexMethod getCurrentContext() {
+              return context.getReference();
+            }
+
+            @Override
+            public int getMaxLocals() {
+              return maxLocals;
+            }
+
+            @Override
+            public int getMaxStack() {
+              return maxStack;
+            }
+
+            @Override
+            public boolean isImmediateSuperClassOfCurrentContext(DexType type) {
+              return type == context.getHolder().getSuperType();
+            }
+          };
     }
 
     @Override
     public TransferFunctionResult<CfFrameState> apply(
         CfInstruction instruction, CfFrameState state) {
-      return instruction.evaluate(state, context, appView, appView.dexItemFactory());
+      return instruction.evaluate(state, appView, config, appView.dexItemFactory());
     }
 
     @Override
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ConcreteCfFrameState.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ConcreteCfFrameState.java
index 7f52c1b..a76a6d3 100644
--- a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ConcreteCfFrameState.java
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ConcreteCfFrameState.java
@@ -5,8 +5,10 @@
 package com.android.tools.r8.optimize.interfaces.analysis;
 
 import static com.android.tools.r8.cf.code.CfFrame.getInitializedFrameType;
+import static com.android.tools.r8.optimize.interfaces.analysis.ErroneousCfFrameState.formatActual;
 
 import com.android.tools.r8.cf.code.CfAssignability;
+import com.android.tools.r8.cf.code.CfAssignability.AssignabilityResult;
 import com.android.tools.r8.cf.code.CfFrame;
 import com.android.tools.r8.cf.code.CfFrame.FrameType;
 import com.android.tools.r8.cf.code.frame.SingleFrameType;
@@ -14,8 +16,10 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.code.ValueType;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.FunctionUtils;
+import com.google.common.collect.Iterables;
 import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap;
 import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
 import it.unimi.dsi.fastutil.ints.Int2ObjectMap.Entry;
@@ -26,19 +30,28 @@
 import java.util.Iterator;
 import java.util.Objects;
 import java.util.function.BiFunction;
+import java.util.function.UnaryOperator;
 
 public class ConcreteCfFrameState extends CfFrameState {
 
-  private final Int2ObjectSortedMap<FrameType> locals;
-  private final Deque<FrameType> stack;
+  private final Int2ObjectAVLTreeMap<FrameType> locals;
+  private final ArrayDeque<FrameType> stack;
+  private int stackHeight;
 
   ConcreteCfFrameState() {
-    this(new Int2ObjectAVLTreeMap<>(), new ArrayDeque<>());
+    this(new Int2ObjectAVLTreeMap<>(), new ArrayDeque<>(), 0);
   }
 
-  ConcreteCfFrameState(Int2ObjectSortedMap<FrameType> locals, Deque<FrameType> stack) {
+  ConcreteCfFrameState(
+      Int2ObjectAVLTreeMap<FrameType> locals, ArrayDeque<FrameType> stack, int stackHeight) {
     this.locals = locals;
     this.stack = stack;
+    this.stackHeight = stackHeight;
+  }
+
+  @Override
+  public CfFrameState clone() {
+    return new ConcreteCfFrameState(locals.clone(), stack.clone(), stackHeight);
   }
 
   @Override
@@ -53,11 +66,15 @@
 
   @Override
   public CfFrameState check(AppView<?> appView, CfFrame frame) {
-    if (CfAssignability.isFrameAssignable(new CfFrame(), frame, appView).isFailed()) {
-      return error();
+    CfFrame currentFrame = CfFrame.builder().setLocals(locals).setStack(stack).build();
+    AssignabilityResult assignabilityResult =
+        CfAssignability.isFrameAssignable(currentFrame, frame, appView);
+    if (assignabilityResult.isFailed()) {
+      return error(assignabilityResult.asFailed().getMessage());
     }
     CfFrame frameCopy = frame.mutableCopy();
-    return new ConcreteCfFrameState(frameCopy.getLocals(), frameCopy.getStack());
+    return new ConcreteCfFrameState(
+        frameCopy.getMutableLocals(), frameCopy.getMutableStack(), stackHeight);
   }
 
   @Override
@@ -68,7 +85,7 @@
   @Override
   public CfFrameState markInitialized(FrameType uninitializedType, DexType initializedType) {
     if (uninitializedType.isInitialized()) {
-      return error();
+      return error("Unexpected attempt to initialize already initialized type");
     }
     for (Int2ObjectMap.Entry<FrameType> entry : locals.int2ObjectEntrySet()) {
       FrameType frameType = entry.getValue();
@@ -78,67 +95,89 @@
     }
     // TODO(b/214496607): By using a collection that supports element replacement this could mutate
     //  the existing stack instead of building a new one.
-    Deque<FrameType> newStack = new ArrayDeque<>();
+    ArrayDeque<FrameType> newStack = new ArrayDeque<>();
     for (FrameType frameType : stack) {
       FrameType initializedFrameType =
           getInitializedFrameType(uninitializedType, frameType, initializedType);
       newStack.addLast(initializedFrameType);
     }
-    return new ConcreteCfFrameState(locals, newStack);
+    return new ConcreteCfFrameState(locals, newStack, stackHeight);
   }
 
   @Override
   public CfFrameState pop() {
-    if (stack.isEmpty()) {
-      return error();
-    }
-    stack.removeLast();
-    return this;
+    return pop(FunctionUtils::getFirst);
   }
 
   @Override
   public CfFrameState pop(BiFunction<CfFrameState, FrameType, CfFrameState> fn) {
     if (stack.isEmpty()) {
-      return error();
+      // Return the same error as when popping from the bottom state.
+      return bottom().pop();
     }
     FrameType frameType = stack.removeLast();
+    stackHeight -= frameType.getWidth();
     return fn.apply(this, frameType);
   }
 
   @Override
   public CfFrameState popAndInitialize(
-      AppView<?> appView, DexMethod constructor, ProgramMethod context) {
+      AppView<?> appView, DexMethod constructor, CfAnalysisConfig config) {
     return pop(
         (state, frameType) -> {
-          if (frameType.isUninitializedThis()) {
-            if (constructor.getHolderType() == context.getHolderType()
-                || constructor.getHolderType() == context.getHolder().getSuperType()) {
-              return state.markInitialized(frameType, context.getHolderType());
+          if (frameType.isUninitializedObject()) {
+            if (frameType.isUninitializedThis()) {
+              if (constructor.getHolderType() == config.getCurrentContext().getHolderType()
+                  || config.isImmediateSuperClassOfCurrentContext(constructor.getHolderType())) {
+                return state.markInitialized(frameType, config.getCurrentContext().getHolderType());
+              }
+            } else if (frameType.isUninitializedNew()) {
+              DexType uninitializedNewType = frameType.getUninitializedNewType();
+              if (constructor.getHolderType() == uninitializedNewType) {
+                return state.markInitialized(frameType, uninitializedNewType);
+              }
             }
-          } else if (frameType.isUninitializedNew()) {
-            DexType uninitializedNewType = frameType.getUninitializedNewType();
-            if (constructor.getHolderType() == uninitializedNewType) {
-              return state.markInitialized(frameType, uninitializedNewType);
-            }
+            return popAndInitializeConstructorMismatchError(frameType, constructor, config);
           }
-          return error();
+          return popAndInitializeInitializedObjectError(frameType);
         });
   }
 
+  private ErroneousCfFrameState popAndInitializeConstructorMismatchError(
+      FrameType frameType, DexMethod constructor, CfAnalysisConfig config) {
+    assert frameType.isUninitializedObject();
+    StringBuilder message = new StringBuilder("Constructor mismatch, expected constructor from ");
+    if (frameType.isUninitializedNew()) {
+      message.append(frameType.getUninitializedNewType().getTypeName());
+    } else {
+      assert frameType.isUninitializedThis();
+      message
+          .append(config.getCurrentContext().getHolderType().getTypeName())
+          .append(" or its superclass");
+    }
+    message.append(", but was ").append(constructor.toSourceStringWithoutReturnType());
+    return error(message.toString());
+  }
+
+  private ErroneousCfFrameState popAndInitializeInitializedObjectError(FrameType frameType) {
+    return error("Unexpected attempt to initialize " + formatActual(frameType));
+  }
+
   @Override
   public CfFrameState popInitialized(
       AppView<?> appView,
       DexType expectedType,
       BiFunction<CfFrameState, FrameType, CfFrameState> fn) {
     return pop(
-        (state, frameType) ->
-            frameType.isInitialized()
-                    && CfAssignability.isAssignable(
-                        frameType.getInitializedType(appView.dexItemFactory()),
-                        expectedType,
-                        appView)
-                ? fn.apply(state, frameType)
-                : error());
+        (state, frameType) -> {
+          if (frameType.isInitialized()) {
+            DexType initializedType = frameType.getInitializedType(appView.dexItemFactory());
+            if (CfAssignability.isAssignable(initializedType, expectedType, appView)) {
+              return fn.apply(state, frameType);
+            }
+          }
+          return errorUnexpectedStack(frameType, FrameType.initialized(expectedType));
+        });
   }
 
   @Override
@@ -151,16 +190,31 @@
   }
 
   @Override
-  public CfFrameState push(DexType type) {
-    return push(FrameType.initialized(type));
+  public CfFrameState push(CfAnalysisConfig config, DexType type) {
+    return push(config, FrameType.initialized(type));
   }
 
   @Override
-  public CfFrameState push(FrameType frameType) {
-    stack.push(frameType);
+  public CfFrameState push(CfAnalysisConfig config, FrameType frameType) {
+    int newStackHeight = stackHeight + frameType.getWidth();
+    if (newStackHeight > config.getMaxStack()) {
+      return pushError(config, frameType);
+    }
+    stack.addLast(frameType);
+    stackHeight = newStackHeight;
     return this;
   }
 
+  private ErroneousCfFrameState pushError(CfAnalysisConfig config, FrameType frameType) {
+    return error(
+        "The max stack height of "
+            + config.getMaxStack()
+            + " is violated when pushing "
+            + formatActual(frameType)
+            + " to existing stack of size "
+            + stackHeight);
+  }
+
   @Override
   public CfFrameState readLocal(
       AppView<?> appView,
@@ -169,21 +223,25 @@
       BiFunction<CfFrameState, FrameType, CfFrameState> fn) {
     FrameType frameType = locals.get(localIndex);
     if (frameType == null) {
-      return error();
+      return error("Unexpected read of missing local at index " + localIndex);
     }
-    if (frameType.isInitialized()
-        && CfAssignability.isAssignable(
-            frameType.getInitializedType(appView.dexItemFactory()), expectedType, appView)) {
+    if (frameType.isInitialized()) {
+      if (CfAssignability.isAssignable(
+          frameType.getInitializedType(appView.dexItemFactory()), expectedType, appView)) {
+        return fn.apply(this, frameType);
+      }
+    } else if (frameType.isUninitializedObject() && expectedType.isObject()) {
       return fn.apply(this, frameType);
     }
-    if (frameType.isUninitializedObject() && expectedType.isObject()) {
-      return fn.apply(this, frameType);
-    }
-    return error();
+    return errorUnexpectedLocal(frameType, expectedType, localIndex);
   }
 
   @Override
-  public CfFrameState storeLocal(int localIndex, FrameType frameType) {
+  public CfFrameState storeLocal(int localIndex, FrameType frameType, CfAnalysisConfig config) {
+    int maxLocalIndex = localIndex + BooleanUtils.intValue(frameType.isWide());
+    if (maxLocalIndex >= config.getMaxLocals()) {
+      return storeLocalError(localIndex, frameType, config);
+    }
     locals.put(localIndex, frameType);
     if (frameType.isWide()) {
       locals.put(localIndex + 1, frameType);
@@ -191,28 +249,47 @@
     return this;
   }
 
-  public CfFrameState join(ConcreteCfFrameState state) {
+  private ErroneousCfFrameState storeLocalError(
+      int localIndex, FrameType frameType, CfAnalysisConfig config) {
+    StringBuilder message =
+        new StringBuilder("The max locals of ")
+            .append(config.getMaxLocals())
+            .append(" is violated when storing ")
+            .append(formatActual(frameType))
+            .append(" at local index ")
+            .append(localIndex);
+    if (frameType.isWide()) {
+      message.append(" and ").append(localIndex + 1);
+    }
+    return error(message.toString());
+  }
+
+  public CfFrameState join(
+      ConcreteCfFrameState state, UnaryOperator<FrameType> joinWithMissingLocal) {
     CfFrame.Builder builder = CfFrame.builder();
-    joinLocals(state.locals, builder);
+    joinLocals(state.locals, builder, joinWithMissingLocal);
     ErroneousCfFrameState error = joinStack(state.stack, builder);
     if (error != null) {
       return error;
     }
     CfFrame frame = builder.buildMutable();
-    return new ConcreteCfFrameState(frame.getLocals(), frame.getStack());
+    return new ConcreteCfFrameState(frame.getMutableLocals(), frame.getMutableStack(), stackHeight);
   }
 
-  private void joinLocals(Int2ObjectSortedMap<FrameType> locals, CfFrame.Builder builder) {
+  private void joinLocals(
+      Int2ObjectSortedMap<FrameType> locals,
+      CfFrame.Builder builder,
+      UnaryOperator<FrameType> joinWithMissingLocal) {
     ObjectBidirectionalIterator<Entry<FrameType>> iterator =
         this.locals.int2ObjectEntrySet().iterator();
     ObjectBidirectionalIterator<Entry<FrameType>> otherIterator =
         locals.int2ObjectEntrySet().iterator();
     while (iterator.hasNext() && otherIterator.hasNext()) {
-      Entry<FrameType> entry = iterator.next();
+      Entry<FrameType> entry = nextLocal(iterator);
       int localIndex = entry.getIntKey();
       FrameType frameType = entry.getValue();
 
-      Entry<FrameType> otherEntry = otherIterator.next();
+      Entry<FrameType> otherEntry = nextLocal(otherIterator);
       int otherLocalIndex = otherEntry.getIntKey();
       FrameType otherFrameType = otherEntry.getValue();
 
@@ -239,8 +316,8 @@
             localIndex, frameType, otherFrameType, iterator, otherIterator, builder);
       }
     }
-    iterator.forEachRemaining(entry -> joinLocalOnlyPresentInOne(entry, builder));
-    otherIterator.forEachRemaining(entry -> joinLocalOnlyPresentInOne(entry, builder));
+    joinLocalsOnlyPresentInOne(iterator, builder, joinWithMissingLocal);
+    joinLocalsOnlyPresentInOne(otherIterator, builder, joinWithMissingLocal);
   }
 
   private void joinLocalsWithDifferentIndices(
@@ -256,7 +333,7 @@
     // Check if the smaller local does not overlap with the larger local.
     if (frameType.isSingle() || localIndex + 1 < otherLocalIndex) {
       setLocalToTop(localIndex, frameType, builder);
-      otherIterator.previous();
+      previousLocal(otherIterator);
       return;
     }
 
@@ -324,7 +401,7 @@
       CfFrame.Builder builder) {
     ObjectBidirectionalIterator<Entry<FrameType>> currentIterator = iterator;
     while (currentIterator.hasNext()) {
-      Entry<FrameType> entry = currentIterator.next();
+      Entry<FrameType> entry = nextLocal(currentIterator);
       int currentLocalIndex = entry.getIntKey();
       FrameType currentFrameType = entry.getValue();
 
@@ -332,7 +409,7 @@
       // this local is not affected.
       if (lastLocalIndexMarkedTop < currentLocalIndex) {
         // The current local still needs to be handled, thus this rewinds the iterator.
-        currentIterator.previous();
+        previousLocal(currentIterator);
         break;
       }
 
@@ -355,8 +432,45 @@
     }
   }
 
-  private void joinLocalOnlyPresentInOne(Entry<FrameType> entry, CfFrame.Builder builder) {
-    setLocalToTop(entry.getIntKey(), entry.getValue(), builder);
+  private void joinLocalsOnlyPresentInOne(
+      ObjectBidirectionalIterator<Entry<FrameType>> iterator,
+      CfFrame.Builder builder,
+      UnaryOperator<FrameType> joinWithMissingLocal) {
+    while (iterator.hasNext()) {
+      Entry<FrameType> entry = nextLocal(iterator);
+      int localIndex = entry.getIntKey();
+      FrameType frameType = entry.getValue();
+      FrameType joinFrameType = joinWithMissingLocal.apply(frameType);
+      assert joinFrameType.isSingle() == frameType.isSingle();
+      if (joinFrameType.isOneWord() || joinFrameType.isTwoWord()) {
+        setLocalToTop(localIndex, joinFrameType, builder);
+      } else {
+        builder.store(localIndex, joinFrameType);
+      }
+    }
+  }
+
+  private Entry<FrameType> nextLocal(ObjectBidirectionalIterator<Entry<FrameType>> iterator) {
+    Entry<FrameType> entry = iterator.next();
+    FrameType frameType = entry.getValue();
+    if (frameType.isWide()) {
+      assert frameType.isDouble() || frameType.isLong();
+      Entry<FrameType> highEntry = iterator.next();
+      assert highEntry.getIntKey() == entry.getIntKey() + 1;
+      assert highEntry.getValue() == frameType;
+    }
+    return entry;
+  }
+
+  private void previousLocal(ObjectBidirectionalIterator<Entry<FrameType>> iterator) {
+    Entry<FrameType> entry = iterator.previous();
+    FrameType frameType = entry.getValue();
+    if (frameType.isWide()) {
+      assert frameType.isDouble() || frameType.isLong();
+      Entry<FrameType> lowEntry = iterator.previous();
+      assert lowEntry.getIntKey() == entry.getIntKey() - 1;
+      assert lowEntry.getValue() == frameType;
+    }
   }
 
   private void setLocalToTop(int localIndex, FrameType frameType, CfFrame.Builder builder) {
@@ -380,31 +494,54 @@
   }
 
   private ErroneousCfFrameState joinStack(Deque<FrameType> stack, CfFrame.Builder builder) {
-    Iterator<FrameType> iterator = this.stack.descendingIterator();
-    Iterator<FrameType> otherIterator = stack.descendingIterator();
+    Iterator<FrameType> iterator = this.stack.iterator();
+    Iterator<FrameType> otherIterator = stack.iterator();
+    int stackIndex = 0;
     while (iterator.hasNext() && otherIterator.hasNext()) {
       FrameType frameType = iterator.next();
       FrameType otherFrameType = otherIterator.next();
       if (frameType.isSingle() != otherFrameType.isSingle()) {
-        return error();
+        return error(
+            "Cannot join stacks, expected frame types at stack index "
+                + stackIndex
+                + " to have the same width, but was: "
+                + formatActual(frameType)
+                + " and "
+                + formatActual(otherFrameType));
       }
       if (frameType.isSingle()) {
         SingleFrameType join = frameType.asSingle().join(otherFrameType.asSingle());
         if (join.isOneWord()) {
-          return error();
+          return joinStackImpreciseJoinError(stackIndex, frameType, otherFrameType);
         }
         builder.push(join.asFrameType());
       } else {
         WideFrameType join = frameType.asWide().join(otherFrameType.asWide());
         if (join.isTwoWord()) {
-          return error();
+          return joinStackImpreciseJoinError(stackIndex, frameType, otherFrameType);
         }
         builder.push(join.asFrameType());
       }
+      stackIndex++;
+    }
+    if (iterator.hasNext() || otherIterator.hasNext()) {
+      return error("Cannot join stacks of different size");
     }
     return null;
   }
 
+  private ErroneousCfFrameState joinStackImpreciseJoinError(
+      int stackIndex, FrameType first, FrameType second) {
+    return error(
+        "Cannot join stacks, expected frame types at stack index "
+            + stackIndex
+            + " to join to a precise (non-top) type, but types "
+            + formatActual(first)
+            + " and "
+            + formatActual(second)
+            + " do not");
+  }
+
   @Override
   public boolean equals(Object o) {
     if (this == o) {
@@ -413,9 +550,8 @@
     if (o == null || getClass() != o.getClass()) {
       return false;
     }
-    // TODO(b/214496607): FrameType should implement equals() and hashCode().
     ConcreteCfFrameState that = (ConcreteCfFrameState) o;
-    return locals.equals(that.locals) && stack.equals(that.stack);
+    return locals.equals(that.locals) && Iterables.elementsEqual(stack, that.stack);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ErroneousCfFrameState.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ErroneousCfFrameState.java
index 23a6351..47e2d24 100644
--- a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ErroneousCfFrameState.java
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ErroneousCfFrameState.java
@@ -9,19 +9,96 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.code.ValueType;
 import java.util.function.BiFunction;
 
 /** An analysis state representing that the code does not type check. */
 public class ErroneousCfFrameState extends CfFrameState {
 
-  private static final ErroneousCfFrameState INSTANCE = new ErroneousCfFrameState();
+  private enum FormatKind {
+    ACTUAL,
+    EXPECTED
+  }
 
-  private ErroneousCfFrameState() {}
+  private final String message;
 
-  static ErroneousCfFrameState getInstance() {
-    return INSTANCE;
+  ErroneousCfFrameState(String message) {
+    this.message = message;
+  }
+
+  public static String formatExpected(DexType type) {
+    return format(type);
+  }
+
+  private static String format(DexType type) {
+    if (type.isArrayType() || type.isClassType()) {
+      return type.getTypeName();
+    } else if (type.isNullValueType()) {
+      return "null";
+    } else {
+      assert type.isPrimitiveType();
+      return "primitive " + type.getTypeName();
+    }
+  }
+
+  public static String formatActual(FrameType frameType) {
+    return format(frameType, FormatKind.ACTUAL);
+  }
+
+  public static String formatExpected(FrameType frameType) {
+    return format(frameType, FormatKind.EXPECTED);
+  }
+
+  private static String format(FrameType frameType, FormatKind formatKind) {
+    if (frameType.isInitialized()) {
+      if (frameType.isObject()) {
+        DexType initializedType = frameType.asSingleInitializedType().getInitializedType();
+        if (initializedType.isArrayType()) {
+          return initializedType.getTypeName();
+        } else if (initializedType.isClassType()) {
+          return "initialized " + initializedType.getTypeName();
+        } else {
+          assert initializedType.isNullValueType();
+          return "null";
+        }
+      } else {
+        assert frameType.isPrimitive();
+        return "primitive " + frameType.asPrimitive().getTypeName();
+      }
+    } else if (frameType.isUninitializedObject()) {
+      if (frameType.isUninitializedNew()) {
+        DexType uninitializedNewType = frameType.getUninitializedNewType();
+        if (uninitializedNewType != null) {
+          return "uninitialized " + uninitializedNewType.getTypeName();
+        }
+        return "uninitialized-new";
+      } else {
+        return "uninitialized-this";
+      }
+    } else {
+      assert frameType.isOneWord() || frameType.isTwoWord();
+      if (formatKind == FormatKind.ACTUAL) {
+        return "top";
+      } else {
+        return frameType.isOneWord() ? "a single width value" : "a double width value";
+      }
+    }
+  }
+
+  public static String formatExpected(ValueType valueType) {
+    return format(valueType);
+  }
+
+  private static String format(ValueType valueType) {
+    if (valueType.isObject()) {
+      return "object";
+    } else {
+      return "primitive " + valueType.toPrimitiveType().getTypeName();
+    }
+  }
+
+  public String getMessage() {
+    return message;
   }
 
   @Override
@@ -30,6 +107,11 @@
   }
 
   @Override
+  public ErroneousCfFrameState asError() {
+    return this;
+  }
+
+  @Override
   public CfFrameState check(AppView<?> appView, CfFrame frame) {
     return this;
   }
@@ -56,7 +138,7 @@
 
   @Override
   public CfFrameState popAndInitialize(
-      AppView<?> appView, DexMethod constructor, ProgramMethod context) {
+      AppView<?> appView, DexMethod constructor, CfAnalysisConfig config) {
     return this;
   }
 
@@ -74,12 +156,12 @@
   }
 
   @Override
-  public CfFrameState push(DexType type) {
+  public CfFrameState push(CfAnalysisConfig config, DexType type) {
     return this;
   }
 
   @Override
-  public CfFrameState push(FrameType frameType) {
+  public CfFrameState push(CfAnalysisConfig config, FrameType frameType) {
     return this;
   }
 
@@ -93,7 +175,7 @@
   }
 
   @Override
-  public CfFrameState storeLocal(int localIndex, FrameType frameType) {
+  public CfFrameState storeLocal(int localIndex, FrameType frameType, CfAnalysisConfig config) {
     return this;
   }
 
diff --git a/src/main/java/com/android/tools/r8/relocator/Relocator.java b/src/main/java/com/android/tools/r8/relocator/Relocator.java
index 6f889ff..711610f 100644
--- a/src/main/java/com/android/tools/r8/relocator/Relocator.java
+++ b/src/main/java/com/android/tools/r8/relocator/Relocator.java
@@ -16,7 +16,6 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.jar.CfApplicationWriter;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.naming.signature.GenericSignatureRewriter;
 import com.android.tools.r8.synthesis.SyntheticItems.GlobalSyntheticsStrategy;
 import com.android.tools.r8.utils.AndroidApp;
@@ -85,12 +84,11 @@
       appView.setAppServices(AppServices.builder(appView).build());
 
       SimplePackagesRewritingMapper packageRemapper = new SimplePackagesRewritingMapper(appView);
-      NamingLens namingLens = packageRemapper.compute(command.getMapping());
+      appView.setNamingLens(packageRemapper.compute(command.getMapping()));
 
-      new GenericSignatureRewriter(appView, namingLens).run(appInfo.classes(), executor);
+      new GenericSignatureRewriter(appView).run(appInfo.classes(), executor);
 
-      new CfApplicationWriter(appView, new Marker(Tool.Relocator), namingLens)
-          .write(command.getConsumer());
+      new CfApplicationWriter(appView, new Marker(Tool.Relocator)).write(command.getConsumer());
       options.printWarnings();
     } catch (ExecutionException e) {
       throw unwrapExecutionException(e);
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 5a6ef63..94b44d0 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -9,6 +9,7 @@
 import static com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult.isOverriding;
 
 import com.android.tools.r8.cf.CfVersion;
+import com.android.tools.r8.experimental.startup.StartupOrder;
 import com.android.tools.r8.features.ClassToFeatureSplitMap;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
@@ -202,11 +203,12 @@
 
   // TODO(zerny): Clean up the constructors so we have just one.
   AppInfoWithLiveness(
-      CommittedItems syntheticItems,
+      CommittedItems committedItems,
       ClassToFeatureSplitMap classToFeatureSplitMap,
       MainDexInfo mainDexInfo,
-      Set<DexType> deadProtoTypes,
       MissingClasses missingClasses,
+      StartupOrder startupOrder,
+      Set<DexType> deadProtoTypes,
       Set<DexType> liveTypes,
       Set<DexMethod> targetedMethods,
       Set<DexMethod> failedMethodResolutionTargets,
@@ -239,7 +241,7 @@
       Set<DexType> lockCandidates,
       Map<DexType, Visibility> initClassReferences,
       Set<DexMethod> recordFieldValuesReferences) {
-    super(syntheticItems, classToFeatureSplitMap, mainDexInfo, missingClasses);
+    super(committedItems, classToFeatureSplitMap, mainDexInfo, missingClasses, startupOrder);
     this.deadProtoTypes = deadProtoTypes;
     this.liveTypes = liveTypes;
     this.targetedMethods = targetedMethods;
@@ -281,8 +283,9 @@
         committedItems,
         previous.getClassToFeatureSplitMap(),
         previous.getMainDexInfo(),
-        previous.deadProtoTypes,
         previous.getMissingClasses(),
+        previous.getStartupOrder(),
+        previous.deadProtoTypes,
         CollectionUtils.addAll(previous.liveTypes, committedItems.getCommittedProgramTypes()),
         previous.targetedMethods,
         previous.failedMethodResolutionTargets,
@@ -326,8 +329,9 @@
         previous.getSyntheticItems().commitPrunedItems(prunedItems),
         previous.getClassToFeatureSplitMap().withoutPrunedItems(prunedItems),
         previous.getMainDexInfo().withoutPrunedItems(prunedItems),
-        previous.deadProtoTypes,
         previous.getMissingClasses(),
+        previous.getStartupOrder().withoutPrunedItems(prunedItems),
+        previous.deadProtoTypes,
         pruneClasses(previous.liveTypes, prunedItems, executorService, futures),
         pruneMethods(previous.targetedMethods, prunedItems, executorService, futures),
         pruneMethods(previous.failedMethodResolutionTargets, prunedItems, executorService, futures),
@@ -531,8 +535,9 @@
         getSyntheticItems().commit(app()),
         getClassToFeatureSplitMap(),
         mainDexInfo,
-        deadProtoTypes,
         getMissingClasses(),
+        getStartupOrder(),
+        deadProtoTypes,
         liveTypes,
         targetedMethods,
         failedMethodResolutionTargets,
@@ -610,7 +615,8 @@
         previous.getSyntheticItems().commit(previous.app()),
         previous.getClassToFeatureSplitMap(),
         previous.getMainDexInfo(),
-        previous.getMissingClasses());
+        previous.getMissingClasses(),
+        previous.getStartupOrder());
     this.deadProtoTypes = previous.deadProtoTypes;
     this.liveTypes = previous.liveTypes;
     this.targetedMethods = previous.targetedMethods;
@@ -1217,8 +1223,9 @@
         committedItems,
         getClassToFeatureSplitMap().rewrittenWithLens(lens),
         getMainDexInfo().rewrittenWithLens(getSyntheticItems(), lens),
-        deadProtoTypes,
         getMissingClasses(),
+        getStartupOrder().rewrittenWithLens(lens),
+        deadProtoTypes,
         lens.rewriteReferences(liveTypes),
         lens.rewriteReferences(targetedMethods),
         lens.rewriteReferences(failedMethodResolutionTargets),
diff --git a/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java b/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java
index 597a07d..192b16a 100644
--- a/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java
+++ b/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java
@@ -8,7 +8,7 @@
 
 import com.android.tools.r8.androidapi.AndroidApiLevelCompute;
 import com.android.tools.r8.androidapi.ComputedApiLevel;
-import com.android.tools.r8.code.CfOrDexInstruction;
+import com.android.tools.r8.dex.code.CfOrDexInstruction;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexCallSite;
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index c93bdb3..295dc47 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -18,10 +18,10 @@
 import com.android.tools.r8.Diagnostic;
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.cf.code.CfInvoke;
-import com.android.tools.r8.code.CfOrDexInstruction;
 import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
 import com.android.tools.r8.contexts.CompilationContext.ProcessorContext;
 import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.dex.code.CfOrDexInstruction;
 import com.android.tools.r8.errors.InterfaceDesugarMissingTypeDiagnostic;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.experimental.graphinfo.GraphConsumer;
@@ -2281,7 +2281,7 @@
     // annotation.
     AnnotationReferenceMarker referenceMarker =
         new AnnotationReferenceMarker(annotation, annotatedItem);
-    annotation.annotation.collectIndexedItems(referenceMarker);
+    annotation.annotation.collectIndexedItems(appView, referenceMarker);
   }
 
   private boolean shouldKeepAnnotation(
@@ -4096,11 +4096,12 @@
             appInfo.getSyntheticItems().commit(app),
             appInfo.getClassToFeatureSplitMap(),
             appInfo.getMainDexInfo(),
-            deadProtoTypes,
             mode.isInitialTreeShaking()
                 ? missingClassesBuilder.reportMissingClasses(
                     appView, lambdaSynthesizingContextOracle)
                 : missingClassesBuilder.assertNoMissingClasses(appView),
+            appInfo.getStartupOrder(),
+            deadProtoTypes,
             SetUtils.mapIdentityHashSet(liveTypes.getItems(), DexProgramClass::getType),
             Enqueuer.toDescriptorSet(targetedMethods.getItems()),
             failedMethodResolutionTargets,
diff --git a/src/main/java/com/android/tools/r8/shaking/MainDexDirectReferenceTracer.java b/src/main/java/com/android/tools/r8/shaking/MainDexDirectReferenceTracer.java
index 06ceb79..4cc4154 100644
--- a/src/main/java/com/android/tools/r8/shaking/MainDexDirectReferenceTracer.java
+++ b/src/main/java/com/android/tools/r8/shaking/MainDexDirectReferenceTracer.java
@@ -93,7 +93,7 @@
   }
 
   private void traceAnnotationsDirectDependencies(DexAnnotationSet annotations) {
-    annotations.collectIndexedItems(annotationDirectReferenceCollector);
+    annotations.collectIndexedItems(appView, annotationDirectReferenceCollector);
   }
 
   private void traceMethodDirectDependencies(DexMethod method, Consumer<DexType> consumer) {
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 f23e6cf..ffba372 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
@@ -229,11 +229,11 @@
     this.globalSyntheticsStrategy = globalSyntheticsStrategy;
   }
 
-  public Map<DexType, Set<DexType>> getFinalGlobalSyntheticContexts(
-      AppView appView, NamingLens namingLens) {
+  public Map<DexType, Set<DexType>> getFinalGlobalSyntheticContexts(AppView appView) {
     assert isFinalized();
     DexItemFactory factory = appView.dexItemFactory();
     ImmutableMap<DexType, Set<DexType>> globalContexts = committed.getGlobalContexts();
+    NamingLens namingLens = appView.getNamingLens();
     Map<DexType, Set<DexType>> rewritten = new IdentityHashMap<>(globalContexts.size());
     globalContexts.forEach(
         (global, contexts) -> {
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
index d9ae12f..29ca8e4 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
@@ -78,6 +78,7 @@
   public final SyntheticKind TWR_CLOSE_RESOURCE = generator.forSingleMethod("TwrCloseResource");
   public final SyntheticKind SERVICE_LOADER = generator.forSingleMethod("ServiceLoad");
   public final SyntheticKind OUTLINE = generator.forSingleMethod("Outline");
+  public final SyntheticKind COVARIANT_OUTLINE = generator.forSingleMethod("CovariantOutline");
   public final SyntheticKind API_CONVERSION = generator.forSingleMethod("APIConversion");
   public final SyntheticKind API_CONVERSION_PARAMETERS =
       generator.forSingleMethod("APIConversionParameters");
diff --git a/src/main/java/com/android/tools/r8/tracereferences/TraceReferences.java b/src/main/java/com/android/tools/r8/tracereferences/TraceReferences.java
index 7f03acb..1344816 100644
--- a/src/main/java/com/android/tools/r8/tracereferences/TraceReferences.java
+++ b/src/main/java/com/android/tools/r8/tracereferences/TraceReferences.java
@@ -28,7 +28,10 @@
 public class TraceReferences {
 
   public static void run(TraceReferencesCommand command) throws CompilationFailedException {
-    ExceptionUtils.withCompilationHandler(command.getReporter(), () -> runInternal(command));
+    InternalOptions options = new InternalOptions();
+    options.loadAllClassDefinitions = true;
+    ExceptionUtils.withCompilationHandler(
+        command.getReporter(), () -> runInternal(command, options));
   }
 
   private static void forEachDescriptor(ProgramResourceProvider provider, Consumer<String> consumer)
@@ -54,7 +57,13 @@
     }
   }
 
-  private static void runInternal(TraceReferencesCommand command)
+  static void runForTesting(TraceReferencesCommand command, InternalOptions options)
+      throws CompilationFailedException {
+    ExceptionUtils.withCompilationHandler(
+        command.getReporter(), () -> runInternal(command, options));
+  }
+
+  private static void runInternal(TraceReferencesCommand command, InternalOptions options)
       throws IOException, ResourceException {
     AndroidApp.Builder builder = AndroidApp.builder();
     command.getLibrary().forEach(builder::addLibraryResourceProvider);
@@ -67,9 +76,6 @@
     for (ProgramResourceProvider provider : command.getSource()) {
       forEachDescriptor(provider, targetDescriptors::remove);
     }
-    InternalOptions options = new InternalOptions();
-    // TODO(b/231928368): enable this
-    options.loadAllClassDefinitions = false;
     Tracer tracer = new Tracer(targetDescriptors, builder.build(), command.getReporter(), options);
     tracer.run(command.getConsumer());
   }
diff --git a/src/main/java/com/android/tools/r8/tracereferences/Tracer.java b/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
index 3a25350..4b98b5f 100644
--- a/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
+++ b/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.dex.ApplicationReader;
 import com.android.tools.r8.diagnostic.DefinitionContext;
 import com.android.tools.r8.diagnostic.internal.DefinitionContextUtils;
+import com.android.tools.r8.experimental.startup.StartupOrder;
 import com.android.tools.r8.features.ClassToFeatureSplitMap;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
@@ -31,6 +32,7 @@
 import com.android.tools.r8.graph.GraphLens.FieldLookupResult;
 import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
 import com.android.tools.r8.graph.MethodResolutionResult;
+import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
 import com.android.tools.r8.graph.ProgramField;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry;
@@ -51,6 +53,7 @@
 import java.io.IOException;
 import java.util.HashSet;
 import java.util.Set;
+import java.util.function.Function;
 import java.util.function.Predicate;
 
 public class Tracer {
@@ -71,7 +74,8 @@
                 new ApplicationReader(inputApp, options, Timing.empty()).read().toDirect(),
                 ClassToFeatureSplitMap.createEmptyClassToFeatureSplitMap(),
                 MainDexInfo.none(),
-                GlobalSyntheticsStrategy.forSingleOutputMode())),
+                GlobalSyntheticsStrategy.forSingleOutputMode(),
+                StartupOrder.empty())),
         diagnostics,
         type -> targetDescriptors.contains(type.toDescriptorString()));
   }
@@ -314,7 +318,9 @@
         assert lookupResult.getType().isStatic();
         DexMethod rewrittenMethod = lookupResult.getReference();
         handleRewrittenMethodResolution(
-            rewrittenMethod, appInfo().unsafeResolveMethodDueToDexFormat(rewrittenMethod));
+            rewrittenMethod,
+            appInfo().unsafeResolveMethodDueToDexFormat(rewrittenMethod),
+            SingleResolutionResult::getResolutionPair);
       }
 
       @Override
@@ -322,16 +328,10 @@
         MethodLookupResult lookupResult = graphLens().lookupInvokeSuper(method, getContext());
         assert lookupResult.getType().isSuper();
         DexMethod rewrittenMethod = lookupResult.getReference();
-        MethodResolutionResult resolutionResult =
-            appInfo().unsafeResolveMethodDueToDexFormat(rewrittenMethod);
-        if (resolutionResult.isFailedResolution()
-            && resolutionResult.asFailedResolution().hasMethodsCausingError()) {
-          handleRewrittenMethodResolution(rewrittenMethod, resolutionResult);
-          return;
-        }
-        handleRewrittenMethodReference(
-            rewrittenMethod,
-            resolutionResult.lookupInvokeSuperTarget(getContext().getHolder(), appInfo()));
+        handleRewrittenMethodResolution(
+            method,
+            appInfo().unsafeResolveMethodDueToDexFormat(rewrittenMethod),
+            result -> result.lookupInvokeSuperTarget(getContext().getHolder(), appInfo()));
       }
 
       @Override
@@ -353,24 +353,29 @@
             method,
             lookupResult.getType().isInterface()
                 ? appInfo().resolveMethodOnInterfaceHolder(method)
-                : appInfo().resolveMethodOnClassHolder(method));
+                : appInfo().resolveMethodOnClassHolder(method),
+            SingleResolutionResult::getResolutionPair);
       }
 
       private void handleRewrittenMethodResolution(
-          DexMethod method, MethodResolutionResult resolutionResult) {
+          DexMethod method,
+          MethodResolutionResult resolutionResult,
+          Function<SingleResolutionResult<?>, DexClassAndMethod> getResult) {
         resolutionResult.forEachMethodResolutionResult(
             result -> {
-              if (result.isFailedResolution()
-                  && result.asFailedResolution().hasTypesOrMethodsCausingError()) {
+              if (result.isFailedResolution()) {
                 result
                     .asFailedResolution()
                     .forEachFailureDependency(
                         type -> addType(type, referencedFrom),
                         methodCausingFailure ->
                             handleRewrittenMethodReference(method, methodCausingFailure));
+                if (!result.asFailedResolution().hasTypesOrMethodsCausingError()) {
+                  handleRewrittenMethodReference(method, (DexEncodedMethod) null);
+                }
                 return;
               }
-              handleRewrittenMethodReference(method, result.getResolutionPair());
+              handleRewrittenMethodReference(method, getResult.apply(result.asSingleResolution()));
             });
       }
 
diff --git a/src/main/java/com/android/tools/r8/utils/ArchiveBuilder.java b/src/main/java/com/android/tools/r8/utils/ArchiveBuilder.java
index 9a521fb..a50dbb9 100644
--- a/src/main/java/com/android/tools/r8/utils/ArchiveBuilder.java
+++ b/src/main/java/com/android/tools/r8/utils/ArchiveBuilder.java
@@ -9,6 +9,7 @@
 import com.android.tools.r8.DataResource;
 import com.android.tools.r8.DiagnosticsHandler;
 import com.android.tools.r8.ResourceException;
+import com.android.tools.r8.androidapi.AndroidApiDataAccess;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.origin.PathOrigin;
 import com.google.common.io.ByteStreams;
@@ -133,7 +134,11 @@
     try (InputStream in = content.getByteStream()) {
       ByteDataView view = ByteDataView.of(ByteStreams.toByteArray(in));
       synchronized (this) {
-        delayedWrites.add(DelayedData.createFile(name, view));
+        if (AndroidApiDataAccess.isApiDatabaseEntry(name)) {
+          writeFileNow(name, view, handler);
+        } else {
+          delayedWrites.add(DelayedData.createFile(name, view));
+        }
       }
     } catch (IOException e) {
       handleIOException(e, handler);
@@ -150,7 +155,11 @@
 
   private void writeFileNow(String name, ByteDataView content, DiagnosticsHandler handler) {
     try {
-      ZipUtils.writeToZipStream(getStream(), name, content, ZipEntry.DEFLATED);
+      ZipUtils.writeToZipStream(
+          getStream(),
+          name,
+          content,
+          AndroidApiDataAccess.isApiDatabaseEntry(name) ? ZipEntry.STORED : ZipEntry.DEFLATED);
     } catch (IOException e) {
       handleIOException(e, handler);
     }
diff --git a/src/main/java/com/android/tools/r8/utils/InternalGlobalSyntheticsProgramConsumer.java b/src/main/java/com/android/tools/r8/utils/InternalGlobalSyntheticsProgramConsumer.java
index 81929a2..a1e7b70 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalGlobalSyntheticsProgramConsumer.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalGlobalSyntheticsProgramConsumer.java
@@ -17,7 +17,6 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.references.Reference;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -117,7 +116,7 @@
     }
 
     @Override
-    public void finished(AppView<?> appView, NamingLens namingLens) {
+    public void finished(AppView<?> appView) {
       byte[] bytes = null;
       try {
         bytes = builder.build();
@@ -201,9 +200,9 @@
     }
 
     @Override
-    public void finished(AppView<?> appView, NamingLens namingLens) {
+    public void finished(AppView<?> appView) {
       Map<DexType, Set<DexType>> globalsToContexts =
-          appView.getSyntheticItems().getFinalGlobalSyntheticContexts(appView, namingLens);
+          appView.getSyntheticItems().getFinalGlobalSyntheticContexts(appView);
       Map<DexType, Set<DexType>> contextToGlobals = new IdentityHashMap<>();
       for (DexType globalType : globalToBytes.keySet()) {
         // It would be good to assert that the global is a synthetic type, but the naming-lens
@@ -249,5 +248,5 @@
     }
   }
 
-  public abstract void finished(AppView<?> appView, NamingLens namingLens);
+  public abstract void finished(AppView<?> appView);
 }
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 48ac2b9..95120b2 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -256,7 +256,6 @@
     enableInitializedClassesAnalysis = false;
     callSiteOptimizationOptions.disableOptimization();
     horizontalClassMergerOptions.setRestrictToSynthetics();
-    apiModelTestingOptions.disableApiCallerIdentification();
   }
 
   public boolean printTimes = System.getProperty("com.android.tools.r8.printtimes") != null;
@@ -1644,6 +1643,9 @@
     public boolean enableOutliningOfMethods =
         System.getProperty("com.android.tools.r8.disableApiModeling") == null;
 
+    // TODO(b/232823652): Enable when we can compute the offset correctly.
+    public boolean useMemoryMappedByteBuffer = false;
+
     // A mapping from references to the api-level introducing them.
     public Map<MethodReference, AndroidApiLevel> methodApiMapping = new HashMap<>();
     public Map<FieldReference, AndroidApiLevel> fieldApiMapping = new HashMap<>();
@@ -1669,6 +1671,15 @@
           });
     }
 
+    /**
+     * Disable the workarounds for missing APIs. This does not disable the use of the database, just
+     * the introduction of soft-verification workarounds for potentially missing API references.
+     */
+    public void disableMissingApiModeling() {
+      enableOutliningOfMethods = false;
+      enableStubbingOfClasses = false;
+    }
+
     public void disableApiCallerIdentification() {
       enableApiCallerIdentification = false;
     }
@@ -2506,4 +2517,10 @@
   public boolean canHaveInvokeInterfaceToObjectMethodBug() {
     return isGeneratingDex() && getMinApiLevel().isLessThan(AndroidApiLevel.P);
   }
+
+  // Until we fully drop support for API levels < 16, we have to emit an empty annotation set to
+  // work around a DALVIK bug. See b/36951668.
+  public boolean canHaveDalvikEmptyAnnotationSetBug() {
+    return minApiLevel.isLessThan(AndroidApiLevel.J_MR1);
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
index f277168..fb61406 100644
--- a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
+++ b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.cf.code.CfPosition;
 import com.android.tools.r8.debuginfo.DebugRepresentation.DebugRepresentationPredicate;
+import com.android.tools.r8.dex.code.DexInstruction;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
@@ -39,7 +40,6 @@
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.DexValue.DexValueString;
-import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.code.Position;
 import com.android.tools.r8.ir.code.Position.OutlineCallerPosition;
@@ -56,7 +56,6 @@
 import com.android.tools.r8.naming.MemberNaming;
 import com.android.tools.r8.naming.MemberNaming.FieldSignature;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.naming.ProguardMapSupplier;
 import com.android.tools.r8.naming.ProguardMapSupplier.ProguardMapId;
 import com.android.tools.r8.naming.Range;
@@ -332,7 +331,6 @@
   public static ProguardMapId runAndWriteMap(
       AndroidApp inputApp,
       AppView<?> appView,
-      NamingLens namingLens,
       Timing timing,
       OriginalSourceFiles originalSourceFiles,
       DebugRepresentationPredicate representation) {
@@ -344,9 +342,7 @@
     ClassNameMapper mapper =
         run(
             appView,
-            appView.appInfo().app(),
             inputApp,
-            namingLens,
             originalSourceFiles,
             representation);
     timing.end();
@@ -469,9 +465,7 @@
 
   public static ClassNameMapper run(
       AppView<?> appView,
-      DexApplication application,
       AndroidApp inputApp,
-      NamingLens namingLens,
       OriginalSourceFiles originalSourceFiles,
       DebugRepresentationPredicate representation) {
     // For finding methods in kotlin files based on SourceDebugExtensions, we use a line method map.
@@ -489,17 +483,17 @@
             : new Pc2PcMappingSupport(appView.options().allowDiscardingResidualDebugInfo());
 
     // Collect which files contain which classes that need to have their line numbers optimized.
-    for (DexProgramClass clazz : application.classes()) {
+    for (DexProgramClass clazz : appView.appInfo().classes()) {
       boolean isSyntheticClass = appView.getSyntheticItems().isSyntheticClass(clazz);
 
       IdentityHashMap<DexString, List<ProgramMethod>> methodsByRenamedName =
-          groupMethodsByRenamedName(appView.graphLens(), namingLens, clazz);
+          groupMethodsByRenamedName(appView, clazz);
 
       // At this point we don't know if we really need to add this class to the builder.
       // It depends on whether any methods/fields are renamed or some methods contain positions.
       // Create a supplier which creates a new, cached ClassNaming.Builder on-demand.
       DexType originalType = appView.graphLens().getOriginalType(clazz.type);
-      DexString renamedDescriptor = namingLens.lookupDescriptor(clazz.getType());
+      DexString renamedDescriptor = appView.getNamingLens().lookupDescriptor(clazz.getType());
       LazyBox<ClassNaming.Builder> onDemandClassNamingBuilder =
           new LazyBox<>(
               () ->
@@ -530,8 +524,7 @@
       addClassToClassNaming(originalType, renamedDescriptor, onDemandClassNamingBuilder);
 
       // First transfer renamed fields to classNamingBuilder.
-      addFieldsToClassNaming(
-          appView.graphLens(), namingLens, clazz, originalType, onDemandClassNamingBuilder);
+      addFieldsToClassNaming(appView, clazz, originalType, onDemandClassNamingBuilder);
 
       // Then process the methods, ordered by renamed name.
       List<DexString> renamedMethodNames = new ArrayList<>(methodsByRenamedName.keySet());
@@ -599,7 +592,8 @@
           MethodSignature originalSignature =
               MethodSignature.fromDexMethod(originalMethod, originalMethod.holder != originalType);
 
-          DexString obfuscatedNameDexString = namingLens.lookupName(method.getReference());
+          DexString obfuscatedNameDexString =
+              appView.getNamingLens().lookupName(method.getReference());
           String obfuscatedName = obfuscatedNameDexString.toString();
 
           List<MappingInformation> methodMappingInfo = new ArrayList<>();
@@ -902,16 +896,15 @@
   }
 
   private static void addFieldsToClassNaming(
-      GraphLens graphLens,
-      NamingLens namingLens,
+      AppView<?> appView,
       DexProgramClass clazz,
       DexType originalType,
       LazyBox<Builder> onDemandClassNamingBuilder) {
     clazz.forEachField(
         dexEncodedField -> {
           DexField dexField = dexEncodedField.getReference();
-          DexField originalField = graphLens.getOriginalFieldSignature(dexField);
-          DexString renamedName = namingLens.lookupName(dexField);
+          DexField originalField = appView.graphLens().getOriginalFieldSignature(dexField);
+          DexString renamedName = appView.getNamingLens().lookupName(dexField);
           if (renamedName != originalField.name || originalField.holder != originalType) {
             FieldSignature originalSignature =
                 FieldSignature.fromDexField(originalField, originalField.holder != originalType);
@@ -922,16 +915,16 @@
   }
 
   public static IdentityHashMap<DexString, List<ProgramMethod>> groupMethodsByRenamedName(
-      GraphLens graphLens, NamingLens namingLens, DexProgramClass clazz) {
+      AppView<?> appView, DexProgramClass clazz) {
     IdentityHashMap<DexString, List<ProgramMethod>> methodsByRenamedName =
         new IdentityHashMap<>(clazz.getMethodCollection().size());
     for (ProgramMethod programMethod : clazz.programMethods()) {
       // Add method only if renamed, moved, or contains positions.
       DexEncodedMethod definition = programMethod.getDefinition();
       DexMethod method = programMethod.getReference();
-      DexString renamedName = namingLens.lookupName(method);
+      DexString renamedName = appView.getNamingLens().lookupName(method);
       if (renamedName != method.name
-          || graphLens.getOriginalMethodSignature(method) != method
+          || appView.graphLens().getOriginalMethodSignature(method) != method
           || doesContainPositions(definition)
           || definition.isD8R8Synthesized()) {
         methodsByRenamedName
@@ -1139,6 +1132,7 @@
     EventBasedDebugInfo debugInfo =
         DexDebugInfo.convertToEventBased(dexCode, appView.dexItemFactory());
     assert debugInfo != null;
+    IntBox firstDefaultEventPc = new IntBox(-1);
     BooleanBox singleOriginalLine = new BooleanBox(true);
     Pair<Integer, Position> lastPosition = new Pair<>();
     DexDebugEventVisitor visitor =
@@ -1149,6 +1143,9 @@
           public void visit(Default defaultEvent) {
             super.visit(defaultEvent);
             assert getCurrentLine() >= 0;
+            if (firstDefaultEventPc.get() < 0) {
+              firstDefaultEventPc.set(getCurrentPc());
+            }
             Position currentPosition = getPositionFromPositionState(this);
             if (lastPosition.getSecond() != null) {
               if (singleOriginalLine.isTrue()
@@ -1172,6 +1169,20 @@
       event.accept(visitor);
     }
 
+    // If the method has a single non-preamble line, check that the preamble is not active on any
+    // throwing instruction before the single line becomes active.
+    if (singleOriginalLine.isTrue() && firstDefaultEventPc.get() > 0) {
+      for (DexInstruction instruction : dexCode.instructions) {
+        if (instruction.getOffset() < firstDefaultEventPc.get()) {
+          if (instruction.canThrow()) {
+            singleOriginalLine.set(false);
+          }
+        } else {
+          break;
+        }
+      }
+    }
+
     int lastInstructionPc = ArrayUtils.last(dexCode.instructions).getOffset();
     if (lastPosition.getSecond() != null) {
       remapAndAddForPc(
diff --git a/src/main/java/com/android/tools/r8/utils/MapUtils.java b/src/main/java/com/android/tools/r8/utils/MapUtils.java
index 2f55680..bf80d7a 100644
--- a/src/main/java/com/android/tools/r8/utils/MapUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/MapUtils.java
@@ -45,6 +45,13 @@
     return map;
   }
 
+  public static <K, V> IdentityHashMap<K, V> newIdentityHashMap(
+      BiForEachable<K, V> forEachable, int capacity) {
+    IdentityHashMap<K, V> map = new IdentityHashMap<>(capacity);
+    forEachable.forEach(map::put);
+    return map;
+  }
+
   public static <T> void removeIdentityMappings(Map<T, T> map) {
     map.entrySet().removeIf(entry -> entry.getKey() == entry.getValue());
   }
diff --git a/src/main/java/com/android/tools/r8/utils/ZipUtils.java b/src/main/java/com/android/tools/r8/utils/ZipUtils.java
index 9d8cedd..34714e4 100644
--- a/src/main/java/com/android/tools/r8/utils/ZipUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/ZipUtils.java
@@ -11,6 +11,7 @@
 import com.android.tools.r8.DataEntryResource;
 import com.android.tools.r8.ProgramResource;
 import com.android.tools.r8.ResourceException;
+import com.android.tools.r8.androidapi.AndroidApiDataAccess;
 import com.android.tools.r8.errors.CompilationError;
 import com.google.common.io.ByteStreams;
 import com.google.common.io.Closer;
@@ -44,12 +45,24 @@
 
 public class ZipUtils {
 
+  // Beginning of extra field length: https://en.wikipedia.org/wiki/ZIP_(file_format)
+  private static final int EXTRA_FIELD_LENGTH_OFFSET = 30;
+
   public static void writeResourcesToZip(
       List<ProgramResource> resources,
       Set<DataEntryResource> dataResources,
       Closer closer,
       ZipOutputStream out)
       throws IOException, ResourceException {
+    for (DataEntryResource dataResource : dataResources) {
+      String entryName = dataResource.getName();
+      byte[] bytes = ByteStreams.toByteArray(closer.register(dataResource.getByteStream()));
+      writeToZipStream(
+          out,
+          entryName,
+          bytes,
+          AndroidApiDataAccess.isApiDatabaseEntry(entryName) ? ZipEntry.STORED : ZipEntry.DEFLATED);
+    }
     for (ProgramResource resource : resources) {
       assert resource.getClassDescriptors().size() == 1;
       Iterator<String> iterator = resource.getClassDescriptors().iterator();
@@ -58,11 +71,6 @@
       byte[] bytes = ByteStreams.toByteArray(closer.register(resource.getByteStream()));
       writeToZipStream(out, entryName, bytes, ZipEntry.DEFLATED);
     }
-    for (DataEntryResource dataResource : dataResources) {
-      String entryName = dataResource.getName();
-      byte[] bytes = ByteStreams.toByteArray(closer.register(dataResource.getByteStream()));
-      writeToZipStream(out, entryName, bytes, ZipEntry.DEFLATED);
-    }
   }
 
   public interface OnEntryHandler {
@@ -290,4 +298,25 @@
   public static String zipEntryNameForClass(Class<?> clazz) {
     return DescriptorUtils.getClassBinaryName(clazz) + CLASS_EXTENSION;
   }
+
+  public static long getOffsetOfResourceInZip(File file, String entry) throws IOException {
+    // Look into the jar file to see find the offset.
+    ZipFile zipFile = new ZipFile(file);
+    Enumeration<? extends ZipEntry> entries = zipFile.entries();
+    long offset = 0;
+    while (entries.hasMoreElements()) {
+      ZipEntry zipEntry = entries.nextElement();
+      byte[] extra = zipEntry.getExtra();
+      offset +=
+          EXTRA_FIELD_LENGTH_OFFSET
+              + zipEntry.getName().length()
+              + (extra == null ? 0 : extra.length);
+      if (zipEntry.getName().equals(entry)) {
+        return zipEntry.getSize() == zipEntry.getCompressedSize() ? offset : -1;
+      } else if (!zipEntry.isDirectory()) {
+        offset += zipEntry.getCompressedSize();
+      }
+    }
+    return -1;
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/utils/collections/DexClassAndMethodSetBase.java b/src/main/java/com/android/tools/r8/utils/collections/DexClassAndMethodSetBase.java
index f42a8cd..0787662 100644
--- a/src/main/java/com/android/tools/r8/utils/collections/DexClassAndMethodSetBase.java
+++ b/src/main/java/com/android/tools/r8/utils/collections/DexClassAndMethodSetBase.java
@@ -8,6 +8,7 @@
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.utils.SetUtils;
+import com.google.common.collect.Iterables;
 import java.util.Collection;
 import java.util.IdentityHashMap;
 import java.util.Iterator;
@@ -18,7 +19,8 @@
 import java.util.function.Supplier;
 import java.util.stream.Stream;
 
-public abstract class DexClassAndMethodSetBase<T extends DexClassAndMethod> implements Iterable<T> {
+public abstract class DexClassAndMethodSetBase<T extends DexClassAndMethod>
+    implements Collection<T> {
 
   protected final Map<DexMethod, T> backing;
   protected final Supplier<? extends Map<DexMethod, T>> backingFactory;
@@ -33,14 +35,20 @@
     this.backingFactory = backingFactory;
   }
 
+  @Override
   public boolean add(T method) {
     T existing = backing.put(method.getReference(), method);
     assert existing == null || existing.isStructurallyEqualTo(method);
     return existing == null;
   }
 
-  public void addAll(Iterable<T> methods) {
-    methods.forEach(this::add);
+  @Override
+  public boolean addAll(Collection<? extends T> methods) {
+    boolean changed = false;
+    for (T method : methods) {
+      changed |= add(method);
+    }
+    return changed;
   }
 
   public T get(DexMethod method) {
@@ -51,6 +59,15 @@
     return iterator().next();
   }
 
+  @Override
+  public boolean contains(Object o) {
+    if (o instanceof DexClassAndMethod) {
+      DexClassAndMethod method = (DexClassAndMethod) o;
+      return contains(method.getReference());
+    }
+    return false;
+  }
+
   public boolean contains(DexMethod method) {
     return backing.containsKey(method);
   }
@@ -63,10 +80,17 @@
     return backing.containsKey(method.getReference());
   }
 
+  @Override
+  public boolean containsAll(Collection<?> collection) {
+    return Iterables.all(collection, this::contains);
+  }
+
+  @Override
   public void clear() {
     backing.clear();
   }
 
+  @Override
   public boolean isEmpty() {
     return backing.isEmpty();
   }
@@ -76,6 +100,15 @@
     return backing.values().iterator();
   }
 
+  @Override
+  public boolean remove(Object o) {
+    if (o instanceof DexClassAndMethod) {
+      DexClassAndMethod method = (DexClassAndMethod) o;
+      return remove(method.getReference());
+    }
+    return false;
+  }
+
   public boolean remove(DexMethod method) {
     T existing = backing.remove(method);
     return existing != null;
@@ -85,18 +118,45 @@
     return remove(method.getReference());
   }
 
+  @Override
+  public boolean removeAll(Collection<?> collection) {
+    boolean changed = false;
+    for (Object o : collection) {
+      changed |= remove(o);
+    }
+    return changed;
+  }
+
+  @Override
   public boolean removeIf(Predicate<? super T> predicate) {
     return backing.values().removeIf(predicate);
   }
 
+  @Override
+  public boolean retainAll(Collection<?> collection) {
+    return backing.values().retainAll(collection);
+  }
+
+  @Override
   public int size() {
     return backing.size();
   }
 
+  @Override
   public Stream<T> stream() {
     return backing.values().stream();
   }
 
+  @Override
+  public Object[] toArray() {
+    return backing.values().toArray();
+  }
+
+  @Override
+  public <S> S[] toArray(S[] ss) {
+    return backing.values().toArray(ss);
+  }
+
   public Collection<T> toCollection() {
     return backing.values();
   }
diff --git a/src/main/java/com/android/tools/r8/utils/collections/DexMethodSignatureMap.java b/src/main/java/com/android/tools/r8/utils/collections/DexMethodSignatureMap.java
new file mode 100644
index 0000000..cff8be7
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/collections/DexMethodSignatureMap.java
@@ -0,0 +1,210 @@
+// 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.utils.collections;
+
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexMethodSignature;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import org.jetbrains.annotations.NotNull;
+
+public class DexMethodSignatureMap<T> implements Map<DexMethodSignature, T> {
+
+  private final Map<DexMethodSignature, T> backing;
+
+  private DexMethodSignatureMap(Map<DexMethodSignature, T> backing) {
+    this.backing = backing;
+  }
+
+  public static <T> DexMethodSignatureMap<T> create() {
+    return new DexMethodSignatureMap<>(new HashMap<>());
+  }
+
+  public static <T> DexMethodSignatureMap<T> createLinked() {
+    return new DexMethodSignatureMap<>(new LinkedHashMap<>());
+  }
+
+  @Override
+  public T put(DexMethodSignature signature, T value) {
+    return backing.put(signature, value);
+  }
+
+  public T put(DexMethod method, T value) {
+    return put(method.getSignature(), value);
+  }
+
+  public T put(DexEncodedMethod method, T value) {
+    return put(method.getReference(), value);
+  }
+
+  @Override
+  public void clear() {
+    backing.clear();
+  }
+
+  @Override
+  public Set<DexMethodSignature> keySet() {
+    return backing.keySet();
+  }
+
+  @Override
+  public Collection<T> values() {
+    return backing.values();
+  }
+
+  @Override
+  public Set<Entry<DexMethodSignature, T>> entrySet() {
+    return backing.entrySet();
+  }
+
+  @Override
+  public T getOrDefault(Object key, T defaultValue) {
+    return backing.getOrDefault(key, defaultValue);
+  }
+
+  @Override
+  public void forEach(BiConsumer<? super DexMethodSignature, ? super T> action) {
+    backing.forEach(action);
+  }
+
+  @Override
+  public void replaceAll(BiFunction<? super DexMethodSignature, ? super T, ? extends T> function) {
+    backing.replaceAll(function);
+  }
+
+  @Override
+  public T putIfAbsent(DexMethodSignature key, T value) {
+    return backing.putIfAbsent(key, value);
+  }
+
+  @Override
+  public boolean remove(Object key, Object value) {
+    return backing.remove(key, value);
+  }
+
+  @Override
+  public boolean replace(DexMethodSignature key, T oldValue, T newValue) {
+    return backing.replace(key, oldValue, newValue);
+  }
+
+  @Override
+  public T replace(DexMethodSignature key, T value) {
+    return backing.replace(key, value);
+  }
+
+  @Override
+  public T computeIfAbsent(
+      DexMethodSignature key,
+      @NotNull Function<? super DexMethodSignature, ? extends T> mappingFunction) {
+    return backing.computeIfAbsent(key, mappingFunction);
+  }
+
+  @Override
+  public T computeIfPresent(
+      DexMethodSignature key,
+      @NotNull BiFunction<? super DexMethodSignature, ? super T, ? extends T> remappingFunction) {
+    return backing.computeIfPresent(key, remappingFunction);
+  }
+
+  @Override
+  public T compute(
+      DexMethodSignature key,
+      @NotNull BiFunction<? super DexMethodSignature, ? super T, ? extends T> remappingFunction) {
+    return backing.compute(key, remappingFunction);
+  }
+
+  @Override
+  public T merge(
+      DexMethodSignature key,
+      @NotNull T value,
+      @NotNull BiFunction<? super T, ? super T, ? extends T> remappingFunction) {
+    return backing.merge(key, value, remappingFunction);
+  }
+
+  public T merge(
+      DexMethod method,
+      @NotNull T value,
+      @NotNull BiFunction<? super T, ? super T, ? extends T> remappingFunction) {
+    return merge(method.getSignature(), value, remappingFunction);
+  }
+
+  public T merge(
+      DexEncodedMethod method,
+      @NotNull T value,
+      @NotNull BiFunction<? super T, ? super T, ? extends T> remappingFunction) {
+    return merge(method.getReference(), value, remappingFunction);
+  }
+
+  @Override
+  public boolean containsKey(Object o) {
+    return backing.containsKey(o);
+  }
+
+  @Override
+  public boolean containsValue(Object value) {
+    return backing.containsValue(value);
+  }
+
+  @Override
+  public T get(Object key) {
+    return backing.get(key);
+  }
+
+  public boolean containsKey(DexMethodSignature signature) {
+    return backing.containsKey(signature);
+  }
+
+  public boolean containsAnyKeyOf(Iterable<DexMethodSignature> signatures) {
+    for (DexMethodSignature signature : signatures) {
+      if (containsKey(signature)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  public DexMethodSignatureSet intersectionWithKeys(Iterable<DexMethodSignature> signatures) {
+    DexMethodSignatureSet result = DexMethodSignatureSet.create();
+    for (DexMethodSignature signature : signatures) {
+      if (containsKey(signature)) {
+        result.add(signature);
+      }
+    }
+    return result;
+  }
+
+  @Override
+  public boolean isEmpty() {
+    return backing.isEmpty();
+  }
+
+  @Override
+  public T remove(Object o) {
+    return backing.remove(o);
+  }
+
+  @Override
+  public void putAll(@NotNull Map<? extends DexMethodSignature, ? extends T> m) {}
+
+  public T remove(DexMethodSignature signature) {
+    return backing.remove(signature);
+  }
+
+  public T remove(DexEncodedMethod method) {
+    return remove(method.getSignature());
+  }
+
+  @Override
+  public int size() {
+    return backing.size();
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/LinkedProgramMethodSet.java b/src/main/java/com/android/tools/r8/utils/collections/LinkedProgramMethodSet.java
new file mode 100644
index 0000000..b323e7e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/collections/LinkedProgramMethodSet.java
@@ -0,0 +1,26 @@
+// 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.utils.collections;
+
+import java.util.LinkedHashMap;
+
+public class LinkedProgramMethodSet extends ProgramMethodSet {
+
+  LinkedProgramMethodSet() {
+    super(LinkedProgramMethodSet::createBacking, createBacking());
+  }
+
+  LinkedProgramMethodSet(int capacity) {
+    super(LinkedProgramMethodSet::createBacking, createBacking(capacity));
+  }
+
+  private static <K, V> LinkedHashMap<K, V> createBacking() {
+    return new LinkedHashMap<>();
+  }
+
+  private static <K, V> LinkedHashMap<K, V> createBacking(int capacity) {
+    return new LinkedHashMap<>(capacity);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/ProgramMethodSet.java b/src/main/java/com/android/tools/r8/utils/collections/ProgramMethodSet.java
index 12deaa2..81bb460 100644
--- a/src/main/java/com/android/tools/r8/utils/collections/ProgramMethodSet.java
+++ b/src/main/java/com/android/tools/r8/utils/collections/ProgramMethodSet.java
@@ -13,7 +13,6 @@
 import com.android.tools.r8.utils.ForEachable;
 import com.google.common.collect.ImmutableMap;
 import java.util.IdentityHashMap;
-import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Supplier;
@@ -62,8 +61,12 @@
     return new ProgramMethodSet(ConcurrentHashMap::new);
   }
 
-  public static ProgramMethodSet createLinked() {
-    return new ProgramMethodSet(LinkedHashMap::new);
+  public static LinkedProgramMethodSet createLinked() {
+    return new LinkedProgramMethodSet();
+  }
+
+  public static LinkedProgramMethodSet createLinked(int capacity) {
+    return new LinkedProgramMethodSet(capacity);
   }
 
   public static ProgramMethodSet empty() {
diff --git a/src/test/java/com/android/tools/r8/L8TestBuilder.java b/src/test/java/com/android/tools/r8/L8TestBuilder.java
index aa20557..7b84c77 100644
--- a/src/test/java/com/android/tools/r8/L8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/L8TestBuilder.java
@@ -43,6 +43,8 @@
   private StringResource desugaredLibrarySpecification =
       StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting());
   private List<Path> libraryFiles = new ArrayList<>();
+  private ProgramConsumer programConsumer;
+  private boolean finalPrefixVerification = true;
 
   private L8TestBuilder(AndroidApiLevel apiLevel, Backend backend, TestState state) {
     this.apiLevel = apiLevel;
@@ -54,6 +56,11 @@
     return new L8TestBuilder(apiLevel, backend, state);
   }
 
+  public L8TestBuilder ignoreFinalPrefixVerification() {
+    finalPrefixVerification = false;
+    return this;
+  }
+
   public L8TestBuilder addProgramFiles(Collection<Path> programFiles) {
     this.additionalProgramFiles.addAll(programFiles);
     return this;
@@ -64,6 +71,11 @@
     return this;
   }
 
+  public L8TestBuilder addLibraryFiles(Collection<Path> libraryFiles) {
+    this.libraryFiles.addAll(libraryFiles);
+    return this;
+  }
+
   public L8TestBuilder addLibraryFiles(Path... libraryFiles) {
     Collections.addAll(this.libraryFiles, libraryFiles);
     return this;
@@ -92,6 +104,11 @@
     return this;
   }
 
+  public L8TestBuilder apply(ThrowableConsumer<L8TestBuilder> thenConsumer) {
+    thenConsumer.acceptWithRuntimeException(this);
+    return this;
+  }
+
   public L8TestBuilder applyIf(boolean condition, ThrowableConsumer<L8TestBuilder> thenConsumer) {
     return applyIf(condition, thenConsumer, ThrowableConsumer.empty());
   }
@@ -128,6 +145,11 @@
     return this;
   }
 
+  public L8TestBuilder setProgramConsumer(ProgramConsumer programConsumer) {
+    this.programConsumer = programConsumer;
+    return this;
+  }
+
   public L8TestBuilder setDesugarJDKLibsCustomConversions(Path desugarJDKLibsConfiguration) {
     this.customConversions = desugarJDKLibsConfiguration;
     return this;
@@ -148,6 +170,15 @@
         options -> options.disableL8AnnotationRemoval = disableL8AnnotationRemoval);
   }
 
+  private ProgramConsumer computeProgramConsumer(AndroidAppConsumers sink) {
+    if (programConsumer != null) {
+      return programConsumer;
+    }
+    return backend.isCf()
+        ? sink.wrapProgramConsumer(ClassFileConsumer.emptyConsumer())
+        : sink.wrapProgramConsumer(DexIndexedConsumer.emptyConsumer());
+  }
+
   public L8TestCompileResult compile()
       throws IOException, CompilationFailedException, ExecutionException {
     // We wrap exceptions in a RuntimeException to call this from a lambda.
@@ -157,43 +188,50 @@
             .addProgramFiles(getProgramFiles())
             .addLibraryFiles(getLibraryFiles())
             .setMode(mode)
+            .setIncludeClassesChecksum(true)
             .addDesugaredLibraryConfiguration(desugaredLibrarySpecification)
             .setMinApiLevel(apiLevel.getLevel())
-            .setProgramConsumer(
-                backend.isCf()
-                    ? sink.wrapProgramConsumer(ClassFileConsumer.emptyConsumer())
-                    : sink.wrapProgramConsumer(DexIndexedConsumer.emptyConsumer()));
+            .setProgramConsumer(computeProgramConsumer(sink));
     addProgramClassFileData(l8Builder);
     Path mapping = null;
+    ImmutableList<String> allKeepRules = null;
     if (!keepRules.isEmpty() || generatedKeepRules != null) {
       mapping = state.getNewTempFile("mapping.txt");
+      allKeepRules =
+          ImmutableList.<String>builder()
+              .addAll(keepRules)
+              .addAll(
+                  generatedKeepRules != null
+                      ? ImmutableList.of(generatedKeepRules)
+                      : Collections.emptyList())
+              .build();
       l8Builder
-          .addProguardConfiguration(
-              ImmutableList.<String>builder()
-                  .addAll(keepRules)
-                  .addAll(
-                      generatedKeepRules != null
-                          ? ImmutableList.of(generatedKeepRules)
-                          : Collections.emptyList())
-                  .build(),
-              Origin.unknown())
+          .addProguardConfiguration(allKeepRules, Origin.unknown())
           .setProguardMapOutputPath(mapping);
     }
     ToolHelper.runL8(l8Builder.build(), optionsModifier);
+    // With special program consumer we may not be able to build the resulting app.
+    if (programConsumer != null) {
+      return null;
+    }
     return new L8TestCompileResult(
             sink.build(),
             apiLevel,
+            allKeepRules,
             generatedKeepRules,
             mapping,
             state,
             backend.isCf() ? OutputMode.ClassFile : OutputMode.DexIndexed)
-        .inspect(
-            inspector ->
-                inspector.forAllClasses(
-                    clazz ->
-                        assertTrue(
-                            clazz.getFinalName().startsWith("j$.")
-                                || clazz.getFinalName().startsWith("java."))));
+        .applyIf(
+            finalPrefixVerification,
+            compileResult ->
+                compileResult.inspect(
+                    inspector ->
+                        inspector.forAllClasses(
+                            clazz ->
+                                assertTrue(
+                                    clazz.getFinalName().startsWith("j$.")
+                                        || clazz.getFinalName().startsWith("java.")))));
   }
 
   private Collection<Path> getProgramFiles() {
diff --git a/src/test/java/com/android/tools/r8/L8TestCompileResult.java b/src/test/java/com/android/tools/r8/L8TestCompileResult.java
index c5ca216..fd5af1c 100644
--- a/src/test/java/com/android/tools/r8/L8TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/L8TestCompileResult.java
@@ -11,25 +11,30 @@
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.FileUtils;
+import com.android.tools.r8.utils.ThrowingConsumer;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.util.List;
 import java.util.Set;
 
 public class L8TestCompileResult extends TestCompileResult<L8TestCompileResult, L8TestRunResult> {
 
+  private final List<String> allKeepRules;
   private final String generatedKeepRules;
   private final Path mapping;
 
   public L8TestCompileResult(
       AndroidApp app,
       AndroidApiLevel apiLevel,
+      List<String> allKeepRules,
       String generatedKeepRules,
       Path mapping,
       TestState state,
       OutputMode outputMode) {
     super(state, app, apiLevel.getLevel(), outputMode);
+    this.allKeepRules = allKeepRules;
     this.generatedKeepRules = generatedKeepRules;
     this.mapping = mapping;
   }
@@ -71,6 +76,12 @@
     return this;
   }
 
+  public <E extends Throwable> L8TestCompileResult inspectKeepRules(
+      ThrowingConsumer<List<String>, E> consumer) throws Throwable {
+    consumer.accept(allKeepRules);
+    return self();
+  }
+
   public L8TestCompileResult writeGeneratedKeepRules(Path path) throws IOException {
     assertNotNull(generatedKeepRules);
     FileUtils.writeTextFile(path, generatedKeepRules);
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index 08e9395..4383be5 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -23,9 +23,10 @@
 import com.android.tools.r8.ToolHelper.DexVm;
 import com.android.tools.r8.ToolHelper.ProcessResult;
 import com.android.tools.r8.cf.CfVersion;
-import com.android.tools.r8.code.Instruction;
 import com.android.tools.r8.dex.ApplicationReader;
+import com.android.tools.r8.dex.code.DexInstruction;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.experimental.startup.StartupOrder;
 import com.android.tools.r8.features.ClassToFeatureSplitMap;
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
@@ -776,7 +777,8 @@
         readApplicationForDexOutput(app, new InternalOptions()),
         ClassToFeatureSplitMap.createEmptyClassToFeatureSplitMap(),
         MainDexInfo.none(),
-        GlobalSyntheticsStrategy.forSingleOutputMode());
+        GlobalSyntheticsStrategy.forSingleOutputMode(),
+        StartupOrder.empty());
   }
 
   protected static AppView<AppInfoWithClassHierarchy> computeAppViewWithClassHierarchy(
@@ -1544,7 +1546,7 @@
   }
 
   protected static void checkInstructions(
-      DexCode code, List<Class<? extends Instruction>> instructions) {
+      DexCode code, List<Class<? extends DexInstruction>> instructions) {
     assertEquals(instructions.size(), code.instructions.length);
     for (int i = 0; i < instructions.size(); ++i) {
       assertEquals("Unexpected instruction at index " + i,
@@ -1552,8 +1554,8 @@
     }
   }
 
-  protected Stream<Instruction> filterInstructionKind(
-      DexCode dexCode, Class<? extends Instruction> kind) {
+  protected Stream<DexInstruction> filterInstructionKind(
+      DexCode dexCode, Class<? extends DexInstruction> kind) {
     return Arrays.stream(dexCode.instructions)
         .filter(kind::isInstance)
         .map(kind::cast);
diff --git a/src/test/java/com/android/tools/r8/TestParametersBuilder.java b/src/test/java/com/android/tools/r8/TestParametersBuilder.java
index cf33980..59d2bc6 100644
--- a/src/test/java/com/android/tools/r8/TestParametersBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestParametersBuilder.java
@@ -187,6 +187,7 @@
 
   private boolean enableApiLevels = false;
   private boolean enableApiLevelsForCf = false;
+  private boolean onlyDexRuntimeApiLevel = false;
 
   private Predicate<AndroidApiLevel> apiLevelFilter = param -> false;
   private List<AndroidApiLevel> explicitApiLevels = new ArrayList<>();
@@ -202,6 +203,12 @@
     return withApiFilter(api -> true);
   }
 
+  public TestParametersBuilder withOnlyDexRuntimeApiLevel() {
+    enableApiLevels = true;
+    onlyDexRuntimeApiLevel = true;
+    return this;
+  }
+
   public TestParametersBuilder enableApiLevelsForCf() {
     enableApiLevelsForCf = true;
     return this;
@@ -266,6 +273,10 @@
     if (runtime.isCf() && !enableApiLevelsForCf) {
       return Stream.of(new TestParameters(runtime));
     }
+    AndroidApiLevel vmLevel = runtime.maxSupportedApiLevel();
+    if (onlyDexRuntimeApiLevel) {
+      return Stream.of(new TestParameters(runtime, vmLevel));
+    }
     List<AndroidApiLevel> sortedApiLevels =
         AndroidApiLevel.getAndroidApiLevelsSorted().stream()
             .filter(apiLevelFilter)
@@ -273,7 +284,6 @@
     if (sortedApiLevels.isEmpty()) {
       return Stream.of();
     }
-    AndroidApiLevel vmLevel = runtime.maxSupportedApiLevel();
     AndroidApiLevel lowestApplicable = sortedApiLevels.get(0);
     if (vmLevel.getLevel() < lowestApplicable.getLevel()) {
       return Stream.of();
@@ -281,6 +291,9 @@
     if (sortedApiLevels.size() > 1) {
       for (int i = sortedApiLevels.size() - 1; i >= 0; i--) {
         AndroidApiLevel highestApplicable = sortedApiLevels.get(i);
+        if (onlyDexRuntimeApiLevel) {
+          return Stream.of(new TestParameters(runtime, highestApplicable));
+        }
         if (highestApplicable.getLevel() <= vmLevel.getLevel()
             && lowestApplicable != highestApplicable) {
           Set<AndroidApiLevel> set = new TreeSet<>();
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index f219969..bc5f2e4 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -23,7 +23,6 @@
 import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DirectMappedDexApplication;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.position.Position;
 import com.android.tools.r8.shaking.FilteredClassPath;
@@ -133,7 +132,6 @@
   public static final String DEFAULT_DEX_FILENAME = "classes.dex";
   public static final String DEFAULT_PROGUARD_MAP_FILE = "proguard.map";
 
-  public static final String JAVA_8_RUNTIME = "third_party/openjdk/openjdk-rt-1.8/rt.jar";
   public static final String CORE_LAMBDA_STUBS =
       "third_party/core-lambda-stubs/core-lambda-stubs.jar";
   public static final String JSR223_RI_JAR = "third_party/jsr223-api-1.0/jsr223-api-1.0.jar";
@@ -146,7 +144,9 @@
       "third_party/android_jar/lib-v%d/api-versions.xml";
   private static final AndroidApiLevel DEFAULT_MIN_SDK = AndroidApiLevel.I;
 
-  public static final String JDK_11_TESTS_DIR = "third_party/openjdk/jdk-11-test/";
+  public static final String OPEN_JDK_DIR = "third_party/openjdk/";
+  public static final String JAVA_8_RUNTIME = OPEN_JDK_DIR + "openjdk-rt-1.8/rt.jar";
+  public static final String JDK_11_TESTS_DIR = OPEN_JDK_DIR + "jdk-11-test/";
   public static final String JDK_11_TIME_TESTS_DIR = JDK_11_TESTS_DIR + "java/time/";
 
   private static final String PROGUARD5_2_1 = "third_party/proguard/proguard5.2.1/bin/proguard";
@@ -180,15 +180,24 @@
 
   public static final Path DESUGAR_LIB_CONVERSIONS =
       Paths.get(LIBS_DIR, "library_desugar_conversions.zip");
+  public static final String DESUGARED_LIB_RELEASES_DIR =
+      OPEN_JDK_DIR + "desugar_jdk_libs_releases/";
+  public static final Path DESUGARED_JDK_8_LIB_JAR =
+      Paths.get(OPEN_JDK_DIR + "desugar_jdk_libs/desugar_jdk_libs.jar");
+  public static final Path DESUGARED_JDK_11_LIB_JAR =
+      DesugaredLibraryJDK11Undesugarer.undesugaredJarJDK11(
+          Paths.get(OPEN_JDK_DIR + "desugar_jdk_libs_11/desugar_jdk_libs.jar"));
 
   public static Path getDesugarJDKLibs() {
     return DesugaredLibraryJDK11Undesugarer.undesugaredJar();
   }
 
   public static Path getDesugarJDKLibsBazelGeneratedFile() {
-    return Paths.get(
-        System.getProperty(
-            "desugar_jdk_libs", "third_party/openjdk/desugar_jdk_libs/desugar_jdk_libs.jar"));
+    String property = System.getProperty("desugar_jdk_libs");
+    if (property == null) {
+      return DESUGARED_JDK_8_LIB_JAR;
+    }
+    return Paths.get(property);
   }
 
   private static String getDesugarLibraryJsonDir() {
@@ -2265,12 +2274,7 @@
 
   public static void writeApplication(AppView<?> appView, InternalOptions options)
       throws ExecutionException {
-    R8.writeApplication(
-        Executors.newSingleThreadExecutor(),
-        appView,
-        NamingLens.getIdentityLens(),
-        options,
-        null);
+    R8.writeApplication(appView, null, Executors.newSingleThreadExecutor());
   }
 
   public static void disassemble(AndroidApp app, PrintStream ps) throws IOException {
diff --git a/src/test/java/com/android/tools/r8/accessrelaxation/InvokeTypeConversionTest.java b/src/test/java/com/android/tools/r8/accessrelaxation/InvokeTypeConversionTest.java
index 8a91c84..c80de82 100644
--- a/src/test/java/com/android/tools/r8/accessrelaxation/InvokeTypeConversionTest.java
+++ b/src/test/java/com/android/tools/r8/accessrelaxation/InvokeTypeConversionTest.java
@@ -13,8 +13,8 @@
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.ToolHelper.DexVm.Version;
-import com.android.tools.r8.code.InvokeDirect;
-import com.android.tools.r8.code.InvokeVirtual;
+import com.android.tools.r8.dex.code.DexInvokeDirect;
+import com.android.tools.r8.dex.code.DexInvokeVirtual;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.smali.SmaliBuilder;
@@ -111,15 +111,18 @@
         parameters.getRuntime().asDex().getVm().getVersion().isOlderThanOrEqual(Version.V4_4_4)
             ? "VerifyError"
             : "IncompatibleClassChangeError";
-    run(builder, expectedError, dexInspector -> {
-      ClassSubject clazz = dexInspector.clazz(CLASS_NAME);
-      assertThat(clazz, isPresent());
-      DexEncodedMethod method = getMethod(dexInspector, main);
-      assertNotNull(method);
-      DexCode code = method.getCode().asDexCode();
-      // The given invoke line is remained as-is.
-      assertTrue(code.instructions[2] instanceof InvokeDirect);
-    });
+    run(
+        builder,
+        expectedError,
+        dexInspector -> {
+          ClassSubject clazz = dexInspector.clazz(CLASS_NAME);
+          assertThat(clazz, isPresent());
+          DexEncodedMethod method = getMethod(dexInspector, main);
+          assertNotNull(method);
+          DexCode code = method.getCode().asDexCode();
+          // The given invoke line is remained as-is.
+          assertTrue(code.instructions[2] instanceof DexInvokeDirect);
+        });
   }
 
   // The following test checks invoke-direct, which refers to the private instance method, *is*
@@ -139,15 +142,18 @@
   public void invokeDirectToPublicizedMethod() throws Exception {
     SmaliBuilder builder = buildTestClass(
         "invoke-direct { v1 }, L" + CLASS_NAME + ";->foo()I");
-    run(builder, null, dexInspector -> {
-      ClassSubject clazz = dexInspector.clazz(CLASS_NAME);
-      assertThat(clazz, isPresent());
-      DexEncodedMethod method = getMethod(dexInspector, main);
-      assertNotNull(method);
-      DexCode code = method.getCode().asDexCode();
-      // The given invoke line is changed to invoke-virtual
-      assertTrue(code.instructions[2] instanceof InvokeVirtual);
-    });
+    run(
+        builder,
+        null,
+        dexInspector -> {
+          ClassSubject clazz = dexInspector.clazz(CLASS_NAME);
+          assertThat(clazz, isPresent());
+          DexEncodedMethod method = getMethod(dexInspector, main);
+          assertNotNull(method);
+          DexCode code = method.getCode().asDexCode();
+          // The given invoke line is changed to invoke-virtual
+          assertTrue(code.instructions[2] instanceof DexInvokeVirtual);
+        });
   }
 
 }
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/apimodel/AndroidApiHashingDatabaseBuilderGenerator.java b/src/test/java/com/android/tools/r8/apimodel/AndroidApiHashingDatabaseBuilderGenerator.java
index a409fd6..708858e 100644
--- a/src/test/java/com/android/tools/r8/apimodel/AndroidApiHashingDatabaseBuilderGenerator.java
+++ b/src/test/java/com/android/tools/r8/apimodel/AndroidApiHashingDatabaseBuilderGenerator.java
@@ -10,6 +10,7 @@
 import static com.android.tools.r8.lightir.ByteUtils.isU2;
 import static com.android.tools.r8.lightir.ByteUtils.setBitAtIndex;
 import static com.android.tools.r8.utils.MapUtils.ignoreKey;
+import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.ToolHelper;
@@ -211,12 +212,12 @@
     Map<Integer, List<Pair<DexReference, AndroidApiLevel>>> generationMap = new HashMap<>();
     ConstantPool constantPool = new ConstantPool();
 
-    int constantPoolMapSize = 1 << AndroidApiDataAccess.entrySizeInBitsForConstantPoolMap();
-    int apiMapSize = 1 << AndroidApiDataAccess.entrySizeInBitsForApiLevelMap();
+    int constantPoolHashMapSize = 1 << AndroidApiDataAccess.entrySizeInBitsForConstantPoolMap();
+    int apiHashMapSize = 1 << AndroidApiDataAccess.entrySizeInBitsForApiLevelMap();
 
     for (Entry<DexReference, AndroidApiLevel> entry : referenceMap.entrySet()) {
       int newCode = AndroidApiDataAccess.apiLevelHash(entry.getKey());
-      assert newCode >= 0 && newCode <= apiMapSize;
+      assert newCode >= 0 && newCode <= apiHashMapSize;
       generationMap
           .computeIfAbsent(newCode, ignoreKey(ArrayList::new))
           .add(Pair.create(entry.getKey(), entry.getValue()));
@@ -238,6 +239,7 @@
     outputStream.writeInt(constantPool.size());
 
     // Write constant pool consisting of <u4:payload_offset><u2:length>.
+    assertEquals(AndroidApiDataAccess.constantPoolOffset(), outputStream.size());
     IntBox lastReadIndex = new IntBox(-1);
     constantPool.forEach(
         (string, id) -> {
@@ -252,14 +254,14 @@
     constantPool.forEach(
         (string, id) -> {
           int constantPoolHash = constantPoolHash(string);
-          assert constantPoolHash >= 0 && constantPoolHash <= constantPoolMapSize;
+          assert constantPoolHash >= 0 && constantPoolHash <= constantPoolHashMapSize;
           constantPoolLookupTable
               .computeIfAbsent(constantPoolHash, ignoreKey(ArrayList::new))
               .add(id);
         });
 
-    int[] constantPoolEntries = new int[constantPoolMapSize];
-    int[] constantPoolEntryLengths = new int[constantPoolMapSize];
+    int[] constantPoolEntries = new int[constantPoolHashMapSize];
+    int[] constantPoolEntryLengths = new int[constantPoolHashMapSize];
     for (Entry<Integer, List<Integer>> entry : constantPoolLookupTable.entrySet()) {
       // Tag if we have a unique value
       if (entry.getValue().size() == 1) {
@@ -276,13 +278,15 @@
       }
     }
     // Write constant pool lookup entries consisting of <u4:payload_offset><u2:length>
+    assertEquals(
+        AndroidApiDataAccess.constantPoolHashMapOffset(constantPool.size()), outputStream.size());
     for (int i = 0; i < constantPoolEntries.length; i++) {
       outputStream.writeInt(constantPoolEntries[i]);
       outputStream.writeShort(constantPoolEntryLengths[i]);
     }
 
-    int[] apiOffsets = new int[apiMapSize];
-    int[] apiOffsetLengths = new int[apiMapSize];
+    int[] apiOffsets = new int[apiHashMapSize];
+    int[] apiOffsetLengths = new int[apiHashMapSize];
     for (Entry<Integer, Pair<Integer, Integer>> hashIndexAndOffset : offsetMap.entrySet()) {
       assert apiOffsets[hashIndexAndOffset.getKey()] == 0;
       Pair<Integer, Integer> value = hashIndexAndOffset.getValue();
@@ -293,6 +297,8 @@
     }
 
     // Write api lookup entries consisting of <u4:payload_offset><u2:length>
+    assertEquals(
+        AndroidApiDataAccess.apiLevelHashMapOffset(constantPool.size()), outputStream.size());
     for (int i = 0; i < apiOffsets.length; i++) {
       outputStream.writeInt(apiOffsets[i]);
       outputStream.writeShort(apiOffsetLengths[i]);
diff --git a/src/test/java/com/android/tools/r8/apimodel/AndroidApiHashingDatabaseBuilderGeneratorTest.java b/src/test/java/com/android/tools/r8/apimodel/AndroidApiHashingDatabaseBuilderGeneratorTest.java
index dcf406d..53f5fda 100644
--- a/src/test/java/com/android/tools/r8/apimodel/AndroidApiHashingDatabaseBuilderGeneratorTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/AndroidApiHashingDatabaseBuilderGeneratorTest.java
@@ -8,6 +8,7 @@
 import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestDiagnosticMessagesImpl;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.ToolHelper;
@@ -19,6 +20,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.IntBox;
+import com.android.tools.r8.utils.InternalOptions;
 import com.google.common.collect.ImmutableList;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -117,8 +119,10 @@
         AndroidApiVersionsXmlParser.getParsedApiClasses(
             ToolHelper.getApiVersionsXmlFile(API_LEVEL).toFile(), API_LEVEL);
     DexItemFactory factory = new DexItemFactory();
+    TestDiagnosticMessagesImpl diagnosticsHandler = new TestDiagnosticMessagesImpl();
     AndroidApiLevelHashingDatabaseImpl androidApiLevelDatabase =
-        new AndroidApiLevelHashingDatabaseImpl(ImmutableList.of());
+        new AndroidApiLevelHashingDatabaseImpl(
+            ImmutableList.of(), new InternalOptions(), diagnosticsHandler);
     parsedApiClasses.forEach(
         parsedApiClass -> {
           DexType type = factory.createType(parsedApiClass.getClassReference().getDescriptor());
@@ -147,6 +151,7 @@
                             .isLessThanOrEqualTo(fieldApiLevel);
                       }));
         });
+    diagnosticsHandler.assertNoMessages();
   }
 
   /**
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelHorizontalMergeAndD8MergeTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelHorizontalMergeAndD8MergeTest.java
new file mode 100644
index 0000000..774de69
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelHorizontalMergeAndD8MergeTest.java
@@ -0,0 +1,172 @@
+// 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.apimodel;
+
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.OutputMode;
+import com.android.tools.r8.SingleTestRunResult;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestCompilerBuilder;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
+import com.android.tools.r8.synthesis.globals.GlobalSyntheticsTestingConsumer;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ApiModelHorizontalMergeAndD8MergeTest extends TestBase {
+
+  private final AndroidApiLevel mockLevel = AndroidApiLevel.M;
+
+  @Parameter() public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withDexRuntimes().withAllApiLevels().build();
+  }
+
+  private boolean isGreaterOrEqualToMockLevel() {
+    return parameters.isDexRuntime() && parameters.getApiLevel().isGreaterThanOrEqualTo(mockLevel);
+  }
+
+  private void setupTestCompileBuilder(TestCompilerBuilder<?, ?, ?, ?, ?> testBuilder)
+      throws NoSuchMethodException {
+    testBuilder
+        .addLibraryClasses(LibraryClass.class)
+        .addDefaultRuntimeLibrary(parameters)
+        .setMinApi(parameters.getApiLevel())
+        .apply(ApiModelingTestHelper::enableApiCallerIdentification)
+        .apply(ApiModelingTestHelper::enableOutliningOfMethods)
+        .apply(setMockApiLevelForClass(LibraryClass.class, mockLevel))
+        .apply(setMockApiLevelForMethod(LibraryClass.class.getDeclaredMethod("foo"), mockLevel))
+        .apply(setMockApiLevelForMethod(LibraryClass.class.getDeclaredMethod("bar"), mockLevel));
+  }
+
+  private boolean addToBootClasspath() {
+    return parameters.isDexRuntime()
+        && parameters.getRuntime().maxSupportedApiLevel().isGreaterThanOrEqualTo(mockLevel);
+  }
+
+  @Test
+  public void testD8DebugDexFilePerClassFile() throws Exception {
+    testD8Merge(CompilationMode.DEBUG);
+  }
+
+  @Test
+  public void testD8ReleaseDexFilePerClassFile() throws Exception {
+    testD8Merge(CompilationMode.RELEASE);
+  }
+
+  private Path runD8ForClass(
+      Class<?> clazz, GlobalSyntheticsTestingConsumer global, CompilationMode mode)
+      throws Exception {
+    return testForD8()
+        .addProgramClasses(clazz)
+        .setMode(mode)
+        .setOutputMode(OutputMode.DexFilePerClassFile)
+        .apply(b -> b.getBuilder().setGlobalSyntheticsConsumer(global))
+        .apply(this::setupTestCompileBuilder)
+        .compile()
+        .writeToZip();
+  }
+
+  public void testD8Merge(CompilationMode mode) throws Exception {
+    List<Path> paths = new ArrayList<>();
+    GlobalSyntheticsTestingConsumer mainGlobals = new GlobalSyntheticsTestingConsumer();
+    GlobalSyntheticsTestingConsumer testCallingFooGlobals = new GlobalSyntheticsTestingConsumer();
+    GlobalSyntheticsTestingConsumer testCallingBarGlobals = new GlobalSyntheticsTestingConsumer();
+    paths.add(runD8ForClass(Main.class, mainGlobals, mode));
+    paths.add(runD8ForClass(TestCallingFoo.class, testCallingFooGlobals, mode));
+    paths.add(runD8ForClass(TestCallingBar.class, testCallingBarGlobals, mode));
+    assertFalse(mainGlobals.hasGlobals());
+    assertFalse(testCallingFooGlobals.hasGlobals());
+    assertFalse(testCallingBarGlobals.hasGlobals());
+    testForD8()
+        .setMode(mode)
+        .addProgramFiles(paths)
+        .apply(this::setupTestCompileBuilder)
+        .addHorizontallyMergedClassesInspector(
+            inspector -> {
+              if (isGreaterOrEqualToMockLevel() || mode.isDebug()) {
+                inspector.assertNoClassesMerged();
+              } else {
+                inspector.assertClassReferencesMerged(
+                    SyntheticItemsTestUtils.syntheticApiOutlineClass(TestCallingFoo.class, 0),
+                    SyntheticItemsTestUtils.syntheticApiOutlineClass(TestCallingBar.class, 0));
+              }
+            })
+        .compile()
+        .inspect(inspector -> inspect(inspector, mode))
+        .applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
+        .run(parameters.getRuntime(), Main.class)
+        .apply(this::checkOutput);
+  }
+
+  private void inspect(CodeInspector inspector, CompilationMode mode) {
+    ClassSubject libraryClassSubject = inspector.clazz(LibraryClass.class);
+    if (isGreaterOrEqualToMockLevel()) {
+      assertThat(libraryClassSubject, isAbsent());
+    } else {
+      assertEquals(mode.isRelease() ? 4 : 5, inspector.allClasses().size());
+    }
+  }
+
+  private void checkOutput(SingleTestRunResult<?> runResult) {
+    runResult.assertSuccessWithOutputLinesIf(
+        addToBootClasspath(), "LibraryClass::foo", "LibraryClass::bar");
+    runResult.assertFailureWithErrorThatThrowsIf(!addToBootClasspath(), NoClassDefFoundError.class);
+  }
+
+  // Only present form api level 23.
+  public static class LibraryClass {
+
+    public static void foo() {
+      System.out.println("LibraryClass::foo");
+    }
+
+    public static void bar() {
+      System.out.println("LibraryClass::bar");
+    }
+  }
+
+  public static class TestCallingFoo {
+
+    public static void callFoo() {
+      LibraryClass.foo();
+    }
+  }
+
+  public static class TestCallingBar {
+
+    public static void callBar() {
+      LibraryClass.bar();
+    }
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) {
+      TestCallingFoo.callFoo();
+      TestCallingBar.callBar();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassInstanceInitTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassInstanceInitTest.java
index 61a9e78..4f31982 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassInstanceInitTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassInstanceInitTest.java
@@ -65,7 +65,7 @@
         .applyIf(isGreaterOrEqualToMockLevel(), b -> b.addBootClasspathClasses(LibraryClass.class))
         .run(parameters.getRuntime(), Main.class)
         .apply(this::checkOutput)
-        .inspect(ApiModelingTestHelper::assertNoSynthesizedClasses);
+        .inspect(this::inspect);
   }
 
   @Test
@@ -73,8 +73,6 @@
     assumeTrue(parameters.isDexRuntime());
     testForD8()
         .setMode(CompilationMode.RELEASE)
-        // TODO(b/213552119): Remove when enabled by default.
-        .apply(ApiModelingTestHelper::enableApiCallerIdentification)
         .apply(this::setupTestBuilder)
         .compile()
         .applyIf(isGreaterOrEqualToMockLevel(), b -> b.addBootClasspathClasses(LibraryClass.class))
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingTest.java
index ec4a09e..b9476a7 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingTest.java
@@ -5,7 +5,6 @@
 package com.android.tools.r8.apimodel;
 
 import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
-import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer;
 import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
 import static org.junit.Assume.assumeTrue;
 
@@ -46,8 +45,7 @@
         .addDefaultRuntimeLibrary(parameters)
         .setMinApi(parameters.getApiLevel())
         .apply(ApiModelingTestHelper::enableStubbingOfClasses)
-        .apply(setMockApiLevelForClass(LibraryClass.class, mockLevel))
-        .apply(setMockApiLevelForDefaultInstanceInitializer(LibraryClass.class, mockLevel));
+        .apply(setMockApiLevelForClass(LibraryClass.class, mockLevel));
   }
 
   @Test
@@ -57,7 +55,7 @@
         .setMode(CompilationMode.DEBUG)
         .apply(this::setupTestBuilder)
         .compile()
-        .inspect(ApiModelingTestHelper::assertNoSynthesizedClasses)
+        .inspect(this::inspect)
         .applyIf(isGreaterOrEqualToMockLevel(), b -> b.addBootClasspathClasses(LibraryClass.class))
         .run(parameters.getRuntime(), Main.class)
         .apply(this::checkOutput);
@@ -68,8 +66,6 @@
     assumeTrue(parameters.isDexRuntime());
     testForD8()
         .setMode(CompilationMode.RELEASE)
-        // TODO(b/213552119): Remove when enabled by default.
-        .apply(ApiModelingTestHelper::enableApiCallerIdentification)
         .apply(this::setupTestBuilder)
         .compile()
         .inspect(this::inspect)
@@ -103,7 +99,7 @@
   // Only present form api level 23.
   public static class LibraryClass {
 
-    public static void foo() {
+    public void foo() {
       System.out.println("Hello World");
     }
   }
@@ -111,7 +107,7 @@
   public static class Main {
 
     public static void main(String[] args) {
-      LibraryClass.foo();
+      new LibraryClass().foo();
     }
   }
 }
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassTest.java
index 184e984..2f8bd1e 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassTest.java
@@ -81,10 +81,10 @@
         .setMode(CompilationMode.DEBUG)
         .apply(this::setupTestBuilder)
         .compile()
-        .inspect(ApiModelingTestHelper::assertNoSynthesizedClasses)
         .applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
         .run(parameters.getRuntime(), Main.class)
-        .apply(this::checkOutput);
+        .apply(this::checkOutput)
+        .inspect(this::inspect);
   }
 
   @Test
@@ -92,8 +92,6 @@
     assumeTrue(parameters.isDexRuntime());
     testForD8()
         .setMode(CompilationMode.RELEASE)
-        // TODO(b/213552119): Remove when enabled by default.
-        .apply(ApiModelingTestHelper::enableApiCallerIdentification)
         .apply(this::setupTestBuilder)
         .compile()
         .applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
@@ -187,6 +185,7 @@
   // Only present from api level 23.
   public static class LibraryClass {
 
+    // Do not model foo. If foo was modeled we would not stub.
     public void foo() {
       System.out.println("LibraryClass::foo");
     }
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java
index 78c5fc1..322b30f 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java
@@ -64,10 +64,10 @@
         .setMode(CompilationMode.DEBUG)
         .apply(this::setupTestBuilder)
         .compile()
-        .inspect(ApiModelingTestHelper::assertNoSynthesizedClasses)
         .applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
         .run(parameters.getRuntime(), Main.class)
-        .apply(this::checkOutput);
+        .apply(this::checkOutput)
+        .inspect(this::inspect);
   }
 
   @Test
@@ -75,8 +75,6 @@
     assumeTrue(parameters.isDexRuntime());
     testForD8()
         .setMode(CompilationMode.RELEASE)
-        // TODO(b/213552119): Remove when enabled by default.
-        .apply(ApiModelingTestHelper::enableApiCallerIdentification)
         .apply(this::setupTestBuilder)
         .compile()
         .applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockMergeTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockMergeTest.java
new file mode 100644
index 0000000..5798d5a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockMergeTest.java
@@ -0,0 +1,182 @@
+// 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.apimodel;
+
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer;
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+
+import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.OutputMode;
+import com.android.tools.r8.SingleTestRunResult;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestCompilerBuilder;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.synthesis.globals.GlobalSyntheticsTestingConsumer;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ApiModelMockMergeTest extends TestBase {
+
+  private final AndroidApiLevel mockLevel = AndroidApiLevel.M;
+
+  @Parameter() public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withDexRuntimes().withAllApiLevels().build();
+  }
+
+  private boolean isGreaterOrEqualToMockLevel() {
+    return parameters.isDexRuntime() && parameters.getApiLevel().isGreaterThanOrEqualTo(mockLevel);
+  }
+
+  private void setupTestCompileBuilder(
+      TestCompilerBuilder<?, ?, ?, ?, ?> testBuilder, Class<?> programClass)
+      throws NoSuchMethodException {
+    testBuilder
+        .addProgramClasses(programClass)
+        .addLibraryClasses(LibraryClass.class)
+        .addDefaultRuntimeLibrary(parameters)
+        .setMinApi(parameters.getApiLevel())
+        .apply(ApiModelingTestHelper::enableApiCallerIdentification)
+        .apply(ApiModelingTestHelper::enableStubbingOfClasses)
+        .apply(setMockApiLevelForClass(LibraryClass.class, mockLevel))
+        .apply(setMockApiLevelForDefaultInstanceInitializer(LibraryClass.class, mockLevel))
+        .apply(setMockApiLevelForMethod(LibraryClass.class.getDeclaredMethod("foo"), mockLevel))
+        .apply(setMockApiLevelForMethod(LibraryClass.class.getDeclaredMethod("bar"), mockLevel));
+  }
+
+  private boolean addToBootClasspath() {
+    return parameters.isDexRuntime()
+        && parameters.getRuntime().maxSupportedApiLevel().isGreaterThanOrEqualTo(mockLevel);
+  }
+
+  @Test
+  public void testD8DebugDexFilePerClassFile() throws Exception {
+    testD8Merge(CompilationMode.DEBUG);
+  }
+
+  @Test
+  public void testD8ReleaseDexFilePerClassFile() throws Exception {
+    testD8Merge(CompilationMode.RELEASE);
+  }
+
+  private Path runD8ForClass(
+      Class<?> clazz, GlobalSyntheticsTestingConsumer global, CompilationMode mode)
+      throws Exception {
+    return testForD8()
+        .setMode(mode)
+        .setOutputMode(OutputMode.DexFilePerClassFile)
+        .apply(b -> b.getBuilder().setGlobalSyntheticsConsumer(global))
+        .apply(builder -> setupTestCompileBuilder(builder, clazz))
+        .compile()
+        .writeToZip();
+  }
+
+  public void testD8Merge(CompilationMode mode) throws Exception {
+    List<Path> paths = new ArrayList<>();
+    GlobalSyntheticsTestingConsumer mainGlobals = new GlobalSyntheticsTestingConsumer();
+    GlobalSyntheticsTestingConsumer testCallingFooGlobals = new GlobalSyntheticsTestingConsumer();
+    GlobalSyntheticsTestingConsumer testCallingBarGlobals = new GlobalSyntheticsTestingConsumer();
+    paths.add(runD8ForClass(Main.class, mainGlobals, mode));
+    paths.add(runD8ForClass(TestCallingFoo.class, testCallingFooGlobals, mode));
+    paths.add(runD8ForClass(TestCallingBar.class, testCallingBarGlobals, mode));
+    assertFalse(mainGlobals.hasGlobals());
+    if (isGreaterOrEqualToMockLevel()) {
+      assertFalse(testCallingFooGlobals.hasGlobals());
+      assertFalse(testCallingBarGlobals.hasGlobals());
+    } else {
+      // The TestCallingX does reference the mock and should have globals.
+      assertNotNull(
+          testCallingFooGlobals.getProvider(Reference.classFromClass(TestCallingFoo.class)));
+      assertNotNull(
+          testCallingBarGlobals.getProvider(Reference.classFromClass(TestCallingBar.class)));
+    }
+
+    testForD8()
+        .setMode(mode)
+        .addProgramFiles(paths)
+        .setMinApi(parameters.getApiLevel())
+        .apply(
+            b ->
+                b.getBuilder()
+                    .addGlobalSyntheticsResourceProviders(testCallingFooGlobals.getProviders())
+                    .addGlobalSyntheticsResourceProviders(testCallingBarGlobals.getProviders()))
+        .compile()
+        .inspect(this::inspect)
+        .applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
+        .run(parameters.getRuntime(), Main.class)
+        .apply(this::checkOutput);
+  }
+
+  private void inspect(CodeInspector inspector) {
+    ClassSubject libraryClassSubject = inspector.clazz(LibraryClass.class);
+    if (isGreaterOrEqualToMockLevel()) {
+      assertThat(libraryClassSubject, isAbsent());
+    } else {
+      assertThat(libraryClassSubject, isPresent());
+      assertThat(libraryClassSubject.uniqueMethodWithName("foo"), isAbsent());
+      assertThat(libraryClassSubject.uniqueMethodWithName("bar"), isAbsent());
+    }
+  }
+
+  private void checkOutput(SingleTestRunResult<?> runResult) {
+    runResult.assertSuccessWithOutputLinesIf(
+        addToBootClasspath(), "LibraryClass::foo", "LibraryClass::bar");
+    runResult.assertFailureWithErrorThatThrowsIf(!addToBootClasspath(), NoClassDefFoundError.class);
+  }
+
+  // Only present form api level 23.
+  public static class LibraryClass {
+
+    public void foo() {
+      System.out.println("LibraryClass::foo");
+    }
+
+    public void bar() {
+      System.out.println("LibraryClass::bar");
+    }
+  }
+
+  public static class TestCallingFoo {
+
+    public static void callFoo() {
+      new LibraryClass().foo();
+    }
+  }
+
+  public static class TestCallingBar {
+
+    public static void callBar() {
+      new LibraryClass().bar();
+    }
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) {
+      TestCallingFoo.callFoo();
+      TestCallingBar.callBar();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java
index d6911db..5d4fc8f 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java
@@ -74,7 +74,6 @@
         .setMode(CompilationMode.DEBUG)
         .apply(this::setupTestBuilder)
         .compile()
-        .inspect(ApiModelingTestHelper::assertNoSynthesizedClasses)
         .applyIf(
             addLibraryClassesToBootClasspath(),
             b -> b.addBootClasspathClasses(LibraryClass.class, LibraryInterface.class))
@@ -82,7 +81,8 @@
             addOtherLibraryClassesToBootClasspath(),
             b -> b.addBootClasspathClasses(OtherLibraryClass.class))
         .run(parameters.getRuntime(), Main.class)
-        .apply(this::checkOutput);
+        .apply(this::checkOutput)
+        .inspect(this::inspect);
   }
 
   @Test
@@ -90,8 +90,6 @@
     assumeTrue(parameters.isDexRuntime());
     testForD8()
         .setMode(CompilationMode.RELEASE)
-        // TODO(b/213552119): Remove when enabled by default.
-        .apply(ApiModelingTestHelper::enableApiCallerIdentification)
         .apply(this::setupTestBuilder)
         .compile()
         .applyIf(
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoHorizontalMergeAndD8MergeTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoHorizontalMergeAndD8MergeTest.java
new file mode 100644
index 0000000..e241455
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoHorizontalMergeAndD8MergeTest.java
@@ -0,0 +1,167 @@
+// 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.apimodel;
+
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.OutputMode;
+import com.android.tools.r8.SingleTestRunResult;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestCompilerBuilder;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.synthesis.globals.GlobalSyntheticsTestingConsumer;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.HorizontallyMergedClassesInspector;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ApiModelNoHorizontalMergeAndD8MergeTest extends TestBase {
+
+  private final AndroidApiLevel oneMockLevel = AndroidApiLevel.M;
+  private final AndroidApiLevel otherMockLevel = AndroidApiLevel.N;
+
+  @Parameter() public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withDexRuntimes().withAllApiLevels().build();
+  }
+
+  private boolean isGreaterOrEqualToMockLevel() {
+    return parameters.isDexRuntime()
+        && parameters.getApiLevel().isGreaterThanOrEqualTo(oneMockLevel);
+  }
+
+  private void setupTestCompileBuilder(TestCompilerBuilder<?, ?, ?, ?, ?> testBuilder)
+      throws NoSuchMethodException {
+    testBuilder
+        .addLibraryClasses(LibraryClass.class)
+        .addDefaultRuntimeLibrary(parameters)
+        .setMinApi(parameters.getApiLevel())
+        .apply(ApiModelingTestHelper::enableApiCallerIdentification)
+        .apply(ApiModelingTestHelper::enableOutliningOfMethods)
+        .apply(setMockApiLevelForClass(LibraryClass.class, oneMockLevel))
+        .apply(setMockApiLevelForMethod(LibraryClass.class.getDeclaredMethod("foo"), oneMockLevel))
+        .apply(
+            setMockApiLevelForMethod(LibraryClass.class.getDeclaredMethod("bar"), otherMockLevel));
+  }
+
+  private boolean addToBootClasspath() {
+    return parameters.isDexRuntime()
+        && parameters.getRuntime().maxSupportedApiLevel().isGreaterThanOrEqualTo(oneMockLevel);
+  }
+
+  @Test
+  public void testD8DebugDexFilePerClassFile() throws Exception {
+    testD8Merge(CompilationMode.DEBUG);
+  }
+
+  @Test
+  public void testD8ReleaseDexFilePerClassFile() throws Exception {
+    testD8Merge(CompilationMode.RELEASE);
+  }
+
+  private Path runD8ForClass(
+      Class<?> clazz, GlobalSyntheticsTestingConsumer global, CompilationMode mode)
+      throws Exception {
+    return testForD8()
+        .addProgramClasses(clazz)
+        .setMode(mode)
+        .setOutputMode(OutputMode.DexFilePerClassFile)
+        .apply(b -> b.getBuilder().setGlobalSyntheticsConsumer(global))
+        .apply(this::setupTestCompileBuilder)
+        .compile()
+        .writeToZip();
+  }
+
+  public void testD8Merge(CompilationMode mode) throws Exception {
+    List<Path> paths = new ArrayList<>();
+    GlobalSyntheticsTestingConsumer mainGlobals = new GlobalSyntheticsTestingConsumer();
+    GlobalSyntheticsTestingConsumer testCallingFooGlobals = new GlobalSyntheticsTestingConsumer();
+    GlobalSyntheticsTestingConsumer testCallingBarGlobals = new GlobalSyntheticsTestingConsumer();
+    paths.add(runD8ForClass(Main.class, mainGlobals, mode));
+    paths.add(runD8ForClass(TestCallingFoo.class, testCallingFooGlobals, mode));
+    paths.add(runD8ForClass(TestCallingBar.class, testCallingBarGlobals, mode));
+    assertFalse(mainGlobals.hasGlobals());
+    assertFalse(testCallingFooGlobals.hasGlobals());
+    assertFalse(testCallingBarGlobals.hasGlobals());
+    testForD8()
+        .setMode(mode)
+        .addProgramFiles(paths)
+        .apply(this::setupTestCompileBuilder)
+        .addHorizontallyMergedClassesInspector(
+            HorizontallyMergedClassesInspector::assertNoClassesMerged)
+        .compile()
+        .inspect(inspector -> inspect(inspector, mode))
+        .applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
+        .run(parameters.getRuntime(), Main.class)
+        .apply(this::checkOutput);
+  }
+
+  private void inspect(CodeInspector inspector, CompilationMode mode) {
+    ClassSubject libraryClassSubject = inspector.clazz(LibraryClass.class);
+    if (isGreaterOrEqualToMockLevel()) {
+      assertThat(libraryClassSubject, isAbsent());
+    } else {
+      assertEquals(5, inspector.allClasses().size());
+    }
+  }
+
+  private void checkOutput(SingleTestRunResult<?> runResult) {
+    runResult.assertSuccessWithOutputLinesIf(
+        addToBootClasspath(), "LibraryClass::foo", "LibraryClass::bar");
+    runResult.assertFailureWithErrorThatThrowsIf(!addToBootClasspath(), NoClassDefFoundError.class);
+  }
+
+  // Only present form api level 23.
+  public static class LibraryClass {
+
+    public static void foo() {
+      System.out.println("LibraryClass::foo");
+    }
+
+    public static void bar() {
+      System.out.println("LibraryClass::bar");
+    }
+  }
+
+  public static class TestCallingFoo {
+
+    public static void callFoo() {
+      LibraryClass.foo();
+    }
+  }
+
+  public static class TestCallingBar {
+
+    public static void callBar() {
+      LibraryClass.bar();
+    }
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) {
+      TestCallingFoo.callFoo();
+      TestCallingBar.callBar();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoOutlineForFullyMockedTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoOutlineForFullyMockedTest.java
index a3183b0..4bb470c 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoOutlineForFullyMockedTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoOutlineForFullyMockedTest.java
@@ -8,8 +8,8 @@
 import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer;
 import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
 import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assume.assumeTrue;
 
@@ -79,8 +79,7 @@
         .applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutput(result)
-        // TODO(b/213552119): Add stubs to D8
-        .inspect(inspector -> inspect(inspector, false));
+        .inspect(inspector -> inspect(inspector, true, true));
   }
 
   @Test
@@ -94,7 +93,7 @@
         .applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
         .run(parameters.getRuntime(), Main.class)
         .apply(this::checkOutput)
-        .inspect(inspector -> inspect(inspector, true));
+        .inspect(inspector -> inspect(inspector, true, true));
   }
 
   private void checkOutput(SingleTestRunResult<?> runResult) {
@@ -106,15 +105,21 @@
     }
   }
 
-  private void inspect(CodeInspector inspector, boolean canStub) throws Exception {
+  private void inspect(CodeInspector inspector, boolean canOutline, boolean canStub)
+      throws Exception {
     Method methodOn23 = LibraryClass.class.getDeclaredMethod("methodOn23");
     Method mainMethod = Main.class.getDeclaredMethod("main", String[].class);
     assertThat(inspector.method(mainMethod), isPresent());
-    verifyThat(inspector, parameters, methodOn23).isNotOutlinedFrom(mainMethod);
+    if (canOutline) {
+      verifyThat(inspector, parameters, methodOn23)
+          .isOutlinedFromUntil(mainMethod, libraryApiLevel);
+    } else {
+      verifyThat(inspector, parameters, methodOn23).isNotOutlinedFrom(mainMethod);
+    }
     if (canStub) {
       verifyThat(inspector, parameters, LibraryClass.class).stubbedUntil(libraryApiLevel);
     } else {
-      assertThat(inspector.clazz(LibraryClass.class), not(isPresent()));
+      assertThat(inspector.clazz(LibraryClass.class), isAbsent());
     }
   }
 
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodMissingClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodMissingClassTest.java
index 0fbd97c..21db603 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodMissingClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodMissingClassTest.java
@@ -140,12 +140,15 @@
                         && invokesMethodWithName("missingNotReferenced").matches(methodSubject))
             .findFirst();
     assertFalse(synthesizedMissingNotReferenced.isPresent());
-    verifyThat(inspector, parameters, addedOn23()).isNotOutlinedFrom(testMethod);
+    verifyThat(inspector, parameters, addedOn23())
+        .isOutlinedFromUntil(testMethod, initialLibraryMockLevel);
     verifyThat(inspector, parameters, addedOn27())
         .isOutlinedFromUntil(testMethod, finalLibraryMethodLevel);
     verifyThat(inspector, parameters, LibraryClass.class.getDeclaredMethod("missingAndReferenced"))
         .isNotOutlinedFrom(testMethod);
-    if (parameters.getApiLevel().isLessThan(finalLibraryMethodLevel)) {
+    if (parameters.getApiLevel().isLessThan(initialLibraryMockLevel)) {
+      assertEquals(5, inspector.allClasses().size());
+    } else if (parameters.getApiLevel().isLessThan(finalLibraryMethodLevel)) {
       assertEquals(4, inspector.allClasses().size());
     } else {
       assertEquals(3, inspector.allClasses().size());
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java
index 94f733d..f11b7a1 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java
@@ -115,6 +115,7 @@
   static void enableStubbingOfClasses(TestCompilerBuilder<?, ?, ?, ?, ?> compilerBuilder) {
     compilerBuilder.addOptionsModification(
         options -> {
+          options.apiModelingOptions().enableApiCallerIdentification = true;
           options.apiModelingOptions().enableStubbingOfClasses = true;
         });
   }
@@ -122,6 +123,7 @@
   static void enableOutliningOfMethods(TestCompilerBuilder<?, ?, ?, ?, ?> compilerBuilder) {
     compilerBuilder.addOptionsModification(
         options -> {
+          options.apiModelingOptions().enableApiCallerIdentification = true;
           options.apiModelingOptions().enableOutliningOfMethods = true;
         });
   }
@@ -130,6 +132,7 @@
       TestCompilerBuilder<?, ?, ?, ?, ?> compilerBuilder) {
     compilerBuilder.addOptionsModification(
         options -> {
+          options.apiModelingOptions().enableApiCallerIdentification = true;
           options.apiModelingOptions().checkAllApiReferencesAreSet = false;
         });
   }
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/B77836766.java b/src/test/java/com/android/tools/r8/bridgeremoval/B77836766.java
index fb4f27e..57c41a8 100644
--- a/src/test/java/com/android/tools/r8/bridgeremoval/B77836766.java
+++ b/src/test/java/com/android/tools/r8/bridgeremoval/B77836766.java
@@ -12,8 +12,8 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.code.InvokeVirtual;
-import com.android.tools.r8.code.ReturnVoid;
+import com.android.tools.r8.dex.code.DexInvokeVirtual;
+import com.android.tools.r8.dex.code.DexReturnVoid;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.jasmin.JasminBuilder;
 import com.android.tools.r8.jasmin.JasminBuilder.ClassBuilder;
@@ -180,13 +180,15 @@
 
               if (parameters.isDexRuntime()) {
                 DexCode code = fooFromCls2InAbsCls.getMethod().getCode().asDexCode();
-                checkInstructions(code, ImmutableList.of(InvokeVirtual.class, ReturnVoid.class));
-                InvokeVirtual invoke = (InvokeVirtual) code.instructions[0];
+                checkInstructions(
+                    code, ImmutableList.of(DexInvokeVirtual.class, DexReturnVoid.class));
+                DexInvokeVirtual invoke = (DexInvokeVirtual) code.instructions[0];
                 assertEquals(absSubject.getDexProgramClass().type, invoke.getMethod().holder);
 
                 code = fooFromCls1InAbsCls.getMethod().getCode().asDexCode();
-                checkInstructions(code, ImmutableList.of(InvokeVirtual.class, ReturnVoid.class));
-                invoke = (InvokeVirtual) code.instructions[0];
+                checkInstructions(
+                    code, ImmutableList.of(DexInvokeVirtual.class, DexReturnVoid.class));
+                invoke = (DexInvokeVirtual) code.instructions[0];
                 assertEquals(absSubject.getDexProgramClass().type, invoke.getMethod().holder);
               }
             })
@@ -304,13 +306,15 @@
 
               if (parameters.isDexRuntime()) {
                 DexCode code = barInCls2.getMethod().getCode().asDexCode();
-                checkInstructions(code, ImmutableList.of(InvokeVirtual.class, ReturnVoid.class));
-                InvokeVirtual invoke = (InvokeVirtual) code.instructions[0];
+                checkInstructions(
+                    code, ImmutableList.of(DexInvokeVirtual.class, DexReturnVoid.class));
+                DexInvokeVirtual invoke = (DexInvokeVirtual) code.instructions[0];
                 assertEquals(baseSubject.getDexProgramClass().type, invoke.getMethod().holder);
 
                 code = fooInBase.getMethod().getCode().asDexCode();
-                checkInstructions(code, ImmutableList.of(InvokeVirtual.class, ReturnVoid.class));
-                invoke = (InvokeVirtual) code.instructions[0];
+                checkInstructions(
+                    code, ImmutableList.of(DexInvokeVirtual.class, DexReturnVoid.class));
+                invoke = (DexInvokeVirtual) code.instructions[0];
                 assertEquals(baseSubject.getDexProgramClass().type, invoke.getMethod().holder);
               }
             })
@@ -405,8 +409,9 @@
 
               if (parameters.isDexRuntime()) {
                 DexCode code = barInSub.getMethod().getCode().asDexCode();
-                checkInstructions(code, ImmutableList.of(InvokeVirtual.class, ReturnVoid.class));
-                InvokeVirtual invoke = (InvokeVirtual) code.instructions[0];
+                checkInstructions(
+                    code, ImmutableList.of(DexInvokeVirtual.class, DexReturnVoid.class));
+                DexInvokeVirtual invoke = (DexInvokeVirtual) code.instructions[0];
                 assertEquals(baseSubject.getDexProgramClass().type, invoke.getMethod().holder);
               }
             })
@@ -491,8 +496,9 @@
 
               if (parameters.isDexRuntime()) {
                 DexCode code = barInSub.getMethod().getCode().asDexCode();
-                checkInstructions(code, ImmutableList.of(InvokeVirtual.class, ReturnVoid.class));
-                InvokeVirtual invoke = (InvokeVirtual) code.instructions[0];
+                checkInstructions(
+                    code, ImmutableList.of(DexInvokeVirtual.class, DexReturnVoid.class));
+                DexInvokeVirtual invoke = (DexInvokeVirtual) code.instructions[0];
                 assertEquals(baseSubject.getDexProgramClass().type, invoke.getMethod().holder);
               }
             })
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/DefaultInterfaceMethodCollisionAfterClassMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/DefaultInterfaceMethodCollisionAfterClassMergingTest.java
new file mode 100644
index 0000000..f5ba678
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/DefaultInterfaceMethodCollisionAfterClassMergingTest.java
@@ -0,0 +1,95 @@
+// 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.classmerging.horizontal;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoHorizontalClassMerging;
+import com.android.tools.r8.NoUnusedInterfaceRemoval;
+import com.android.tools.r8.NoVerticalClassMerging;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class DefaultInterfaceMethodCollisionAfterClassMergingTest extends TestBase {
+
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(getClass())
+        .addKeepClassAndMembersRules(Main.class)
+        .addHorizontallyMergedClassesInspector(
+            inspector ->
+                inspector.applyIf(
+                    !parameters.canUseDefaultAndStaticInterfaceMethods(),
+                    i ->
+                        i.assertIsCompleteMergeGroup(A.class, B.class)
+                            .assertNoOtherClassesMerged()))
+        .enableInliningAnnotations()
+        .enableNoHorizontalClassMergingAnnotations()
+        .enableNoUnusedInterfaceRemovalAnnotations()
+        .enableNoVerticalClassMergingAnnotations()
+        .setMinApi(parameters.getApiLevel())
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines("I", "J");
+  }
+
+  static class Main {
+
+    public static void main(String[] args) {
+      test(new A());
+      test(new B());
+    }
+
+    // @Keep
+    static void test(I i) {
+      i.m();
+    }
+
+    // @Keep
+    static void test(J j) {
+      j.m();
+    }
+  }
+
+  @NoHorizontalClassMerging
+  @NoUnusedInterfaceRemoval
+  @NoVerticalClassMerging
+  interface I {
+
+    @NeverInline
+    default void m() {
+      System.out.println("I");
+    }
+  }
+
+  @NoHorizontalClassMerging
+  @NoUnusedInterfaceRemoval
+  @NoVerticalClassMerging
+  interface J {
+
+    @NeverInline
+    default void m() {
+      System.out.println("J");
+    }
+  }
+
+  static class A implements I {}
+
+  static class B implements J {}
+}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/DefaultInterfaceMethodCollisionInSubclassAfterClassMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/DefaultInterfaceMethodCollisionInSubclassAfterClassMergingTest.java
new file mode 100644
index 0000000..e8919da
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/DefaultInterfaceMethodCollisionInSubclassAfterClassMergingTest.java
@@ -0,0 +1,118 @@
+// 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.classmerging.horizontal;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoHorizontalClassMerging;
+import com.android.tools.r8.NoUnusedInterfaceRemoval;
+import com.android.tools.r8.NoVerticalClassMerging;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRuntime.CfVm;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class DefaultInterfaceMethodCollisionInSubclassAfterClassMergingTest extends TestBase {
+
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(getClass())
+        .addKeepClassAndMembersRules(Main.class)
+        .addHorizontallyMergedClassesInspector(
+            inspector ->
+                // TODO(b/229951607): Should only merge A and B when desugaring.
+                inspector.assertIsCompleteMergeGroup(A.class, B.class).assertNoOtherClassesMerged())
+        .enableInliningAnnotations()
+        .enableNoHorizontalClassMergingAnnotations()
+        .enableNoUnusedInterfaceRemovalAnnotations()
+        .enableNoVerticalClassMergingAnnotations()
+        .setMinApi(parameters.getApiLevel())
+        .run(parameters.getRuntime(), Main.class)
+        // TODO(b/229951607): Should always succeed.
+        .applyIf(
+            parameters.canUseDefaultAndStaticInterfaceMethods(),
+            runResult ->
+                runResult.assertFailureWithErrorThatThrows(
+                    parameters.isCfRuntime()
+                            && parameters.getRuntime().asCf().isNewerThanOrEqual(CfVm.JDK11)
+                        ? AbstractMethodError.class
+                        : IncompatibleClassChangeError.class),
+            runResult -> runResult.assertSuccessWithOutputLines("A", "I", "J"));
+  }
+
+  static class Main {
+
+    public static void main(String[] args) {
+      escape(new A());
+      test(new ASub());
+      test(new B());
+    }
+
+    // @Keep
+    static void escape(Object o) {
+      System.out.println(o);
+    }
+
+    // @Keep
+    static void test(I i) {
+      i.m();
+    }
+
+    // @Keep
+    static void test(J j) {
+      j.m();
+    }
+  }
+
+  @NoHorizontalClassMerging
+  @NoUnusedInterfaceRemoval
+  @NoVerticalClassMerging
+  interface I {
+
+    @NeverInline
+    default void m() {
+      System.out.println("I");
+    }
+  }
+
+  @NoHorizontalClassMerging
+  @NoUnusedInterfaceRemoval
+  @NoVerticalClassMerging
+  interface J {
+
+    @NeverInline
+    default void m() {
+      System.out.println("J");
+    }
+  }
+
+  @NoVerticalClassMerging
+  static class A {
+
+    @Override
+    public String toString() {
+      return "A";
+    }
+  }
+
+  @NoHorizontalClassMerging
+  static class ASub extends A implements I {}
+
+  static class B implements J {}
+}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodMergingWithAbsentMethodAndSuperClassMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodMergingWithAbsentMethodAndSuperClassMergingTest.java
new file mode 100644
index 0000000..8ee3476
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodMergingWithAbsentMethodAndSuperClassMergingTest.java
@@ -0,0 +1,119 @@
+// 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.classmerging.horizontal;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+/** Reproduction of b/231900726. */
+@RunWith(Parameterized.class)
+public class VirtualMethodMergingWithAbsentMethodAndSuperClassMergingTest extends TestBase {
+
+  @Parameter(0)
+  public Class<?> upperMergeTarget;
+
+  @Parameter(1)
+  public Class<?> lowerMergeTarget;
+
+  @Parameter(2)
+  public TestParameters parameters;
+
+  @Parameters(name = "{2}, upper merge target: {0}, lower merge target: {1}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        ImmutableList.of(A.class, B.class),
+        ImmutableList.of(C.class, D.class),
+        getTestParameters().withAllRuntimesAndApiLevels().build());
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(getClass())
+        .addKeepMainRule(Main.class)
+        // Control the targets of the horizontal class merger.
+        .addOptionsModification(
+            options ->
+                options.testing.horizontalClassMergingTarget =
+                    (appView, candidates, target) -> {
+                      if (Iterables.any(
+                          candidates,
+                          candidate -> candidate.getTypeName().equals(A.class.getTypeName()))) {
+                        return Iterables.find(
+                            candidates,
+                            candidate ->
+                                candidate.getTypeName().equals(upperMergeTarget.getTypeName()));
+                      }
+                      if (Iterables.any(
+                          candidates,
+                          candidate -> candidate.getTypeName().equals(C.class.getTypeName()))) {
+                        return Iterables.find(
+                            candidates,
+                            candidate ->
+                                candidate.getTypeName().equals(lowerMergeTarget.getTypeName()));
+                      }
+                      return target;
+                    })
+        // Verify that the targets are as expected.
+        .addHorizontallyMergedClassesInspector(
+            inspector ->
+                inspector
+                    .applyIf(
+                        upperMergeTarget == A.class,
+                        i -> i.assertMergedInto(B.class, A.class),
+                        i -> i.assertMergedInto(A.class, B.class))
+                    .applyIf(
+                        lowerMergeTarget == C.class,
+                        i -> i.assertMergedInto(D.class, C.class),
+                        i -> i.assertMergedInto(C.class, D.class))
+                    .assertNoOtherClassesMerged())
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines("A", "B", "C", "A");
+  }
+
+  static class Main {
+
+    public static void main(String[] args) {
+      new A().m();
+      new B().m();
+      new C().m();
+      new D().m();
+    }
+  }
+
+  static class A {
+
+    void m() {
+      System.out.println("A");
+    }
+  }
+
+  static class B {
+
+    void m() {
+      System.out.println("B");
+    }
+  }
+
+  static class C extends A {
+
+    @Override
+    void m() {
+      System.out.println("C");
+    }
+  }
+
+  static class D extends A {}
+}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/interfaces/CollisionWithDefaultMethodsTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/interfaces/CollisionWithDefaultMethodsTest.java
index 072962b..c4313e1 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/interfaces/CollisionWithDefaultMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/interfaces/CollisionWithDefaultMethodsTest.java
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.classmerging.horizontal.interfaces;
 
+import static org.junit.Assert.assertEquals;
+
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.utils.StringUtils;
@@ -25,7 +27,8 @@
         getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build());
   }
 
-  private static final String EXPECTED_OUTPUT = StringUtils.lines("Event1", "Event2");
+  private static final String EXPECTED_OUTPUT =
+      StringUtils.lines("Event1", "Event2", "Event1!", "Event2!", "Event1#", "Event2#");
 
   @Test
   public void testDesugaring() throws Exception {
@@ -42,12 +45,17 @@
         .addKeepMainRule(TestClass.class)
         .setMinApi(parameters.getApiLevel())
         .addKeepRules("-keep class ** { *; }")
+        .addHorizontallyMergedClassesInspector(
+            inspector -> {
+              if (parameters.isCfRuntime()) {
+                inspector.assertNoClassesMerged();
+              } else if (parameters.isDexRuntime()
+                  && parameters.canUseDefaultAndStaticInterfaceMethods()) {
+                assertEquals(2, inspector.getMergeGroups().size());
+              }
+            })
         .run(parameters.getRuntime(), TestClass.class)
-        // TODO(b/229951607): This should never throw ICCE.
-        .applyIf(
-            parameters.isDexRuntime() && hasDefaultInterfaceMethodsSupport(parameters),
-            r -> r.assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class),
-            r -> r.assertSuccessWithOutput(EXPECTED_OUTPUT));
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
   }
 
   static class Event {}
@@ -96,6 +104,11 @@
     public static void main(String[] args) throws Exception {
       eventOnListener1(System.out::println);
       eventOnListener2(System.out::println);
+      // This will create two merge groups with default methods in the implemented interfaces.
+      eventOnListener1(e -> System.out.println(e.toString() + "!"));
+      eventOnListener2(e -> System.out.println(e.toString() + "!"));
+      eventOnListener1(e -> System.out.println(e.toString() + "#"));
+      eventOnListener2(e -> System.out.println(e.toString() + "#"));
     }
   }
 }
diff --git a/src/test/java/com/android/tools/r8/code/InstructionFactoryTest.java b/src/test/java/com/android/tools/r8/code/InstructionFactoryTest.java
index a1cfe7b..3476df7 100644
--- a/src/test/java/com/android/tools/r8/code/InstructionFactoryTest.java
+++ b/src/test/java/com/android/tools/r8/code/InstructionFactoryTest.java
@@ -5,6 +5,8 @@
 
 import static org.junit.Assert.assertTrue;
 
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexInstructionFactory;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import java.nio.ByteBuffer;
 import org.junit.Test;
@@ -17,8 +19,8 @@
   @Test
   public void emptyBuffer() {
     ByteBuffer emptyBuffer = ByteBuffer.allocate(0);
-    InstructionFactory factory = new InstructionFactory();
-    Instruction[] instructions =
+    DexInstructionFactory factory = new DexInstructionFactory();
+    DexInstruction[] instructions =
         factory.readSequenceFrom(emptyBuffer.asShortBuffer(), 0, 0, new OffsetToObjectMapping());
     assertTrue(instructions.length == 0);
   }
diff --git a/src/test/java/com/android/tools/r8/compatproguard/AtomicFieldUpdaterTest.java b/src/test/java/com/android/tools/r8/compatproguard/AtomicFieldUpdaterTest.java
index 2521e02..3d3aecc 100644
--- a/src/test/java/com/android/tools/r8/compatproguard/AtomicFieldUpdaterTest.java
+++ b/src/test/java/com/android/tools/r8/compatproguard/AtomicFieldUpdaterTest.java
@@ -6,10 +6,10 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.code.ConstClass;
-import com.android.tools.r8.code.ConstString;
-import com.android.tools.r8.code.InvokeStatic;
-import com.android.tools.r8.code.ReturnVoid;
+import com.android.tools.r8.dex.code.DexConstClass;
+import com.android.tools.r8.dex.code.DexConstString;
+import com.android.tools.r8.dex.code.DexInvokeStatic;
+import com.android.tools.r8.dex.code.DexReturnVoid;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.smali.SmaliBuilder;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -52,12 +52,12 @@
     assertTrue(method.isPresent());
 
     DexCode code = method.getMethod().getCode().asDexCode();
-    assertTrue(code.instructions[0] instanceof ConstClass);
-    assertTrue(code.instructions[1] instanceof ConstString);
-    ConstString constString = (ConstString) code.instructions[1];
+    assertTrue(code.instructions[0] instanceof DexConstClass);
+    assertTrue(code.instructions[1] instanceof DexConstString);
+    DexConstString constString = (DexConstString) code.instructions[1];
     assertNotEquals("foo", constString.getString().toString());
-    assertTrue(code.instructions[2] instanceof InvokeStatic);
-    assertTrue(code.instructions[3] instanceof ReturnVoid);
+    assertTrue(code.instructions[2] instanceof DexInvokeStatic);
+    assertTrue(code.instructions[3] instanceof DexReturnVoid);
   }
 
   @Test
@@ -88,12 +88,12 @@
     assertTrue(method.isPresent());
 
     DexCode code = method.getMethod().getCode().asDexCode();
-    assertTrue(code.instructions[0] instanceof ConstClass);
-    assertTrue(code.instructions[1] instanceof ConstString);
-    ConstString constString = (ConstString) code.instructions[1];
+    assertTrue(code.instructions[0] instanceof DexConstClass);
+    assertTrue(code.instructions[1] instanceof DexConstString);
+    DexConstString constString = (DexConstString) code.instructions[1];
     assertNotEquals("foo", constString.getString().toString());
-    assertTrue(code.instructions[2] instanceof InvokeStatic);
-    assertTrue(code.instructions[3] instanceof ReturnVoid);
+    assertTrue(code.instructions[2] instanceof DexInvokeStatic);
+    assertTrue(code.instructions[3] instanceof DexReturnVoid);
   }
 
   @Test
@@ -125,12 +125,12 @@
     assertTrue(method.isPresent());
 
     DexCode code = method.getMethod().getCode().asDexCode();
-    assertTrue(code.instructions[0] instanceof ConstClass);
-    assertTrue(code.instructions[1] instanceof ConstClass);
-    assertTrue(code.instructions[2] instanceof ConstString);
-    ConstString constString = (ConstString) code.instructions[2];
+    assertTrue(code.instructions[0] instanceof DexConstClass);
+    assertTrue(code.instructions[1] instanceof DexConstClass);
+    assertTrue(code.instructions[2] instanceof DexConstString);
+    DexConstString constString = (DexConstString) code.instructions[2];
     assertNotEquals("foo", constString.getString().toString());
-    assertTrue(code.instructions[3] instanceof InvokeStatic);
-    assertTrue(code.instructions[4] instanceof ReturnVoid);
+    assertTrue(code.instructions[3] instanceof DexInvokeStatic);
+    assertTrue(code.instructions[4] instanceof DexReturnVoid);
   }
 }
diff --git a/src/test/java/com/android/tools/r8/compatproguard/ForNameTest.java b/src/test/java/com/android/tools/r8/compatproguard/ForNameTest.java
index b79721f..a5a9f0a1 100644
--- a/src/test/java/com/android/tools/r8/compatproguard/ForNameTest.java
+++ b/src/test/java/com/android/tools/r8/compatproguard/ForNameTest.java
@@ -7,9 +7,9 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.code.ConstString;
-import com.android.tools.r8.code.InvokeStatic;
-import com.android.tools.r8.code.ReturnVoid;
+import com.android.tools.r8.dex.code.DexConstString;
+import com.android.tools.r8.dex.code.DexInvokeStatic;
+import com.android.tools.r8.dex.code.DexReturnVoid;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.smali.SmaliBuilder;
 import com.android.tools.r8.utils.AndroidApiLevel;
@@ -52,11 +52,11 @@
     assertTrue(method.isPresent());
 
     DexCode code = method.getMethod().getCode().asDexCode();
-    assertTrue(code.instructions[0] instanceof ConstString);
-    ConstString constString = (ConstString) code.instructions[0];
+    assertTrue(code.instructions[0] instanceof DexConstString);
+    DexConstString constString = (DexConstString) code.instructions[0];
     assertNotEquals(BOO, constString.getString().toString());
-    assertTrue(code.instructions[1] instanceof InvokeStatic);
-    assertTrue(code.instructions[2] instanceof ReturnVoid);
+    assertTrue(code.instructions[1] instanceof DexInvokeStatic);
+    assertTrue(code.instructions[2] instanceof DexReturnVoid);
   }
 
   @Test
@@ -88,11 +88,11 @@
     assertTrue(method.isPresent());
 
     DexCode code = method.getMethod().getCode().asDexCode();
-    assertTrue(code.instructions[0] instanceof ConstString);
-    ConstString constString = (ConstString) code.instructions[0];
+    assertTrue(code.instructions[0] instanceof DexConstString);
+    DexConstString constString = (DexConstString) code.instructions[0];
     assertEquals(BOO, constString.getString().toString());
-    assertTrue(code.instructions[1] instanceof InvokeStatic);
-    assertTrue(code.instructions[2] instanceof ReturnVoid);
+    assertTrue(code.instructions[1] instanceof DexInvokeStatic);
+    assertTrue(code.instructions[2] instanceof DexReturnVoid);
   }
 
 }
diff --git a/src/test/java/com/android/tools/r8/compatproguard/GetMembersTest.java b/src/test/java/com/android/tools/r8/compatproguard/GetMembersTest.java
index 5771019..7a30afd 100644
--- a/src/test/java/com/android/tools/r8/compatproguard/GetMembersTest.java
+++ b/src/test/java/com/android/tools/r8/compatproguard/GetMembersTest.java
@@ -6,13 +6,13 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.code.AputObject;
-import com.android.tools.r8.code.Const4;
-import com.android.tools.r8.code.ConstClass;
-import com.android.tools.r8.code.ConstString;
-import com.android.tools.r8.code.InvokeVirtual;
-import com.android.tools.r8.code.NewArray;
-import com.android.tools.r8.code.ReturnVoid;
+import com.android.tools.r8.dex.code.DexAputObject;
+import com.android.tools.r8.dex.code.DexConst4;
+import com.android.tools.r8.dex.code.DexConstClass;
+import com.android.tools.r8.dex.code.DexConstString;
+import com.android.tools.r8.dex.code.DexInvokeVirtual;
+import com.android.tools.r8.dex.code.DexNewArray;
+import com.android.tools.r8.dex.code.DexReturnVoid;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.smali.SmaliBuilder;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -53,12 +53,12 @@
     assertTrue(method.isPresent());
 
     DexCode code = method.getMethod().getCode().asDexCode();
-    assertTrue(code.instructions[0] instanceof ConstClass);
-    assertTrue(code.instructions[1] instanceof ConstString);
-    ConstString constString = (ConstString) code.instructions[1];
+    assertTrue(code.instructions[0] instanceof DexConstClass);
+    assertTrue(code.instructions[1] instanceof DexConstString);
+    DexConstString constString = (DexConstString) code.instructions[1];
     assertNotEquals("foo", constString.getString().toString());
-    assertTrue(code.instructions[2] instanceof InvokeVirtual);
-    assertTrue(code.instructions[3] instanceof ReturnVoid);
+    assertTrue(code.instructions[2] instanceof DexInvokeVirtual);
+    assertTrue(code.instructions[3] instanceof DexReturnVoid);
   }
 
   @Test
@@ -93,17 +93,17 @@
     assertTrue(method.isPresent());
 
     DexCode code = method.getMethod().getCode().asDexCode();
-    assertTrue(code.instructions[0] instanceof ConstClass);
-    assertTrue(code.instructions[1] instanceof Const4);
-    assertTrue(code.instructions[2] instanceof NewArray);
-    assertTrue(code.instructions[3] instanceof Const4);
-    assertTrue(code.instructions[4] instanceof AputObject);
-    assertTrue(code.instructions[5] instanceof ConstClass);
-    assertTrue(code.instructions[6] instanceof ConstString);
-    ConstString constString = (ConstString) code.instructions[6];
+    assertTrue(code.instructions[0] instanceof DexConstClass);
+    assertTrue(code.instructions[1] instanceof DexConst4);
+    assertTrue(code.instructions[2] instanceof DexNewArray);
+    assertTrue(code.instructions[3] instanceof DexConst4);
+    assertTrue(code.instructions[4] instanceof DexAputObject);
+    assertTrue(code.instructions[5] instanceof DexConstClass);
+    assertTrue(code.instructions[6] instanceof DexConstString);
+    DexConstString constString = (DexConstString) code.instructions[6];
     assertNotEquals("foo", constString.getString().toString());
-    assertTrue(code.instructions[7] instanceof InvokeVirtual);
-    assertTrue(code.instructions[8] instanceof ReturnVoid);
+    assertTrue(code.instructions[7] instanceof DexInvokeVirtual);
+    assertTrue(code.instructions[8] instanceof DexReturnVoid);
   }
 
 }
diff --git a/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestCollection.java b/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestCollection.java
index 70aa283..0dcd986 100644
--- a/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestCollection.java
+++ b/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestCollection.java
@@ -18,6 +18,7 @@
 import com.android.tools.r8.compilerapi.sourcefile.CustomSourceFileTest;
 import com.android.tools.r8.compilerapi.testsetup.ApiTestingSetUpTest;
 import com.android.tools.r8.compilerapi.wrappers.CommandLineParserTest;
+import com.android.tools.r8.compilerapi.wrappers.EnableMissingLibraryApiModelingTest;
 import com.google.common.collect.ImmutableList;
 import java.nio.file.Path;
 import java.nio.file.Paths;
@@ -41,7 +42,10 @@
           DesugarDependenciesTest.ApiTest.class);
 
   private static final List<Class<? extends CompilerApiTest>> CLASSES_PENDING_BINARY_COMPATIBILITY =
-      ImmutableList.of(GlobalSyntheticsTest.ApiTest.class, CommandLineParserTest.ApiTest.class);
+      ImmutableList.of(
+          GlobalSyntheticsTest.ApiTest.class,
+          CommandLineParserTest.ApiTest.class,
+          EnableMissingLibraryApiModelingTest.ApiTest.class);
 
   private final TemporaryFolder temp;
 
diff --git a/src/test/java/com/android/tools/r8/compilerapi/wrappers/EnableMissingLibraryApiModelingTest.java b/src/test/java/com/android/tools/r8/compilerapi/wrappers/EnableMissingLibraryApiModelingTest.java
new file mode 100644
index 0000000..115212d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/compilerapi/wrappers/EnableMissingLibraryApiModelingTest.java
@@ -0,0 +1,45 @@
+// 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.compilerapi.wrappers;
+
+import com.android.tools.r8.D8Command;
+import com.android.tools.r8.R8Command;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.compilerapi.CompilerApiTest;
+import com.android.tools.r8.compilerapi.CompilerApiTestRunner;
+import org.junit.Test;
+
+public class EnableMissingLibraryApiModelingTest extends CompilerApiTestRunner {
+
+  public EnableMissingLibraryApiModelingTest(TestParameters parameters) {
+    super(parameters);
+  }
+
+  @Override
+  public Class<? extends CompilerApiTest> binaryTestClass() {
+    return ApiTest.class;
+  }
+
+  @Test
+  public void test() throws Exception {
+    new ApiTest(ApiTest.PARAMETERS).run();
+  }
+
+  public static class ApiTest extends CompilerApiTest {
+
+    public ApiTest(Object parameters) {
+      super(parameters);
+    }
+
+    public void run() throws Exception {
+      D8Command.builder().setEnableExperimentalMissingLibraryApiModeling(true);
+      R8Command.builder().setEnableExperimentalMissingLibraryApiModeling(true);
+    }
+
+    @Test
+    public void test() throws Exception {
+      run();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/debug/SmaliDebugTest.java b/src/test/java/com/android/tools/r8/debug/SmaliDebugTest.java
index a275033..1f41abc 100644
--- a/src/test/java/com/android/tools/r8/debug/SmaliDebugTest.java
+++ b/src/test/java/com/android/tools/r8/debug/SmaliDebugTest.java
@@ -7,9 +7,9 @@
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.code.IfEqz;
-import com.android.tools.r8.code.Instruction;
 import com.android.tools.r8.debuginfo.DebugInfoInspector;
+import com.android.tools.r8.dex.code.DexIfEqz;
+import com.android.tools.r8.dex.code.DexInstruction;
 import com.android.tools.r8.graph.DexDebugEntry;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
 import com.android.tools.r8.smali.SmaliBuilder;
@@ -111,10 +111,10 @@
             AndroidApp.builder().addProgramFiles(outs).build(),
             CLASS,
             new MethodSignature(methodName, "int", new String[] {"int"}));
-    IfEqz cond = null;
-    for (Instruction instruction : info.getMethod().getCode().asDexCode().instructions) {
-      if (instruction.getOpcode() == IfEqz.OPCODE) {
-        cond = (IfEqz) instruction;
+    DexIfEqz cond = null;
+    for (DexInstruction instruction : info.getMethod().getCode().asDexCode().instructions) {
+      if (instruction.getOpcode() == DexIfEqz.OPCODE) {
+        cond = (DexIfEqz) instruction;
         break;
       }
     }
diff --git a/src/test/java/com/android/tools/r8/debuginfo/CodeGeneratorTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/CodeGeneratorTestRunner.java
index 1f6520e..1ac5aff 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/CodeGeneratorTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/CodeGeneratorTestRunner.java
@@ -6,10 +6,10 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.code.AddInt;
-import com.android.tools.r8.code.AddInt2Addr;
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.Return;
+import com.android.tools.r8.dex.code.DexAddInt;
+import com.android.tools.r8.dex.code.DexAddInt2Addr;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexReturn;
 import com.android.tools.r8.utils.AndroidApp;
 import org.junit.Test;
 
@@ -31,11 +31,11 @@
 
     DebugInfoInspector inspector = inspectMethod(d8App, clazz, "int", "intAddition", "int", "int",
         "int");
-    Instruction[] instructions = inspector.getMethod().getCode().asDexCode().instructions;
-    assertTrue(instructions[0] instanceof AddInt2Addr);
-    assertTrue(instructions[1] instanceof AddInt2Addr);
-    assertTrue(instructions[2] instanceof AddInt);
-    assertTrue(instructions[3] instanceof Return);
+    DexInstruction[] instructions = inspector.getMethod().getCode().asDexCode().instructions;
+    assertTrue(instructions[0] instanceof DexAddInt2Addr);
+    assertTrue(instructions[1] instanceof DexAddInt2Addr);
+    assertTrue(instructions[2] instanceof DexAddInt);
+    assertTrue(instructions[3] instanceof DexReturn);
   }
 
 }
diff --git a/src/test/java/com/android/tools/r8/debuginfo/NoLineInfoTest.java b/src/test/java/com/android/tools/r8/debuginfo/NoLineInfoTest.java
new file mode 100644
index 0000000..f8e88c6
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debuginfo/NoLineInfoTest.java
@@ -0,0 +1,254 @@
+// 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.debuginfo;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assume.assumeFalse;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.naming.retrace.StackTrace;
+import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.transformers.MethodTransformer;
+import com.android.tools.r8.utils.BooleanUtils;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.objectweb.asm.Label;
+
+@RunWith(Parameterized.class)
+public class NoLineInfoTest extends TestBase {
+
+  private static final String INPUT_SOURCE_FILE = "InputSourceFile.java";
+  private static final String CUSTOM_SOURCE_FILE = "TaggedSourceFile";
+  private static final String DEFAULT_SOURCE_FILE = "SourceFile";
+  private static final String UNKNOWN_SOURCE_FILE = "Unknown Source";
+
+  private final TestParameters parameters;
+  private final boolean customSourceFile;
+
+  @Parameterized.Parameters(name = "{0}, custom-sf:{1}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values());
+  }
+
+  public NoLineInfoTest(TestParameters parameters, boolean customSourceFile) {
+    this.parameters = parameters;
+    this.customSourceFile = customSourceFile;
+  }
+
+  private byte[] getTestClassTransformed() throws IOException {
+    return transformer(TestClass.class)
+        .setSourceFile(INPUT_SOURCE_FILE)
+        .addMethodTransformer(
+            new MethodTransformer() {
+              private final Map<MethodReference, Integer> lines = new HashMap<>();
+
+              @Override
+              public void visitLineNumber(int line, Label start) {
+                Integer nextLine = lines.getOrDefault(getContext().getReference(), 0);
+                if (nextLine > 0) {
+                  super.visitLineNumber(nextLine, start);
+                }
+                // Increment the actual line content by 100 so that each one is clearly distinct
+                // from a PC value for any of the methods.
+                lines.put(getContext().getReference(), nextLine + 100);
+              }
+            })
+        .transform();
+  }
+
+  public boolean isRuntimeWithPcAsLineNumberSupport() {
+    return parameters.isDexRuntime()
+        && parameters
+            .getRuntime()
+            .maxSupportedApiLevel()
+            .isGreaterThanOrEqualTo(apiLevelWithPcAsLineNumberSupport());
+  }
+
+  public boolean isCompileWithPcAsLineNumberSupport() {
+    return parameters.isDexRuntime()
+        && parameters.getApiLevel().isGreaterThanOrEqualTo(apiLevelWithPcAsLineNumberSupport());
+  }
+
+  @Test
+  public void testReference() throws Exception {
+    assumeFalse(customSourceFile);
+    testForRuntime(parameters)
+        .addProgramClassFileData(getTestClassTransformed())
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertFailureWithErrorThatThrows(NullPointerException.class)
+        .inspectStackTrace(
+            stacktrace -> {
+              if (isRuntimeWithPcAsLineNumberSupport()) {
+                // On VMs with PC support the lack of a line will emit the PC instead.
+                assertThat(stacktrace, StackTrace.isSame(getExpectedInputStacktraceOnPcVms()));
+              } else {
+                assertThat(stacktrace, StackTrace.isSame(getExpectedInputStacktrace()));
+              }
+            });
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramClassFileData(getTestClassTransformed())
+        .addKeepClassAndMembersRules(TestClass.class)
+        .addKeepAttributeSourceFile()
+        .addKeepAttributeLineNumberTable()
+        .setMinApi(parameters.getApiLevel())
+        .addOptionsModification(o -> o.testing.forcePcBasedEncoding = true)
+        .applyIf(
+            customSourceFile,
+            b -> b.getBuilder().setSourceFileProvider(environment -> CUSTOM_SOURCE_FILE))
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertFailureWithErrorThatThrows(NullPointerException.class)
+        .inspectOriginalStackTrace(
+            stackTrace ->
+                assertThat(
+                    "Unexpected residual stacktrace",
+                    stackTrace,
+                    StackTrace.isSame(getResidualStacktrace())))
+        .inspectStackTrace(
+            stacktrace ->
+                assertThat(
+                    "Unexpected input-source stacktrace",
+                    stacktrace,
+                    StackTrace.isSame(getUnexpectedRetracedStacktrace())));
+  }
+
+  private StackTraceLine line(String file, String method, int line) {
+    return StackTraceLine.builder()
+        .setClassName(typeName(TestClass.class))
+        .setFileName(file)
+        .setMethodName(method)
+        .setLineNumber(line)
+        .build();
+  }
+
+  // Normal reference line from the input.
+  private StackTraceLine inputLine(String method, int line) {
+    return line(INPUT_SOURCE_FILE, method, line);
+  }
+
+  // Line as printed for PC supporting VMs when the line is absent (D8 compilation).
+  private StackTraceLine inputPcLine(String method, int pc) {
+    return line(UNKNOWN_SOURCE_FILE, method, pc);
+  }
+
+  // Residual line depends on the source file parameter.
+  private StackTraceLine residualLine(String method, int line) {
+    String defaultFile =
+        isCompileWithPcAsLineNumberSupport() ? UNKNOWN_SOURCE_FILE : DEFAULT_SOURCE_FILE;
+    String file = customSourceFile ? CUSTOM_SOURCE_FILE : defaultFile;
+    return line(file, method, line);
+  }
+
+  // This is the real "reference" stack trace as given by JVM on inputs and should be retraced to.
+  private StackTrace getExpectedInputStacktrace() {
+    return StackTrace.builder()
+        .add(inputLine("foo", -1))
+        .add(inputLine("bar", -1))
+        .add(inputLine("baz", -1))
+        .add(inputLine("main", 200))
+        .build();
+  }
+
+  // When D8 compiling reference inputs directly there is (currently) no way to recover from the PC
+  // printing. Thus, this is the expected stack trace on those VMs.
+  private StackTrace getExpectedInputStacktraceOnPcVms() {
+    return StackTrace.builder()
+        .add(inputPcLine("foo", 1))
+        .add(inputPcLine("bar", 0))
+        .add(inputPcLine("baz", 0))
+        .add(inputLine("main", 200))
+        .build();
+  }
+
+  // TODO(b/232212653): The retraced stack trace should be the same as `getExpectedInputStacktrace`.
+  private StackTrace getUnexpectedRetracedStacktrace() {
+
+    // TODO(b/232212653): Retracing the PC 1 preserves it but it should map to <noline>
+    StackTraceLine fooLine =
+        isRuntimeWithPcAsLineNumberSupport() ? inputLine("foo", 1) : inputLine("foo", -1);
+
+    // TODO(b/232212653): Normal line-opt will cause a single-line mapping. Retrace should not
+    //  optimize that to mean it represents a single possible line. (<noline> should not match 1:x).
+    StackTraceLine barLine = parameters.isCfRuntime() ? inputLine("bar", 100) : inputLine("bar", 0);
+
+    // TODO(b/232212653): The retracing in CF where the line table is preserved is incorrect.
+    //  same issue as for bar.
+    StackTraceLine bazLine = parameters.isCfRuntime() ? inputLine("baz", 100) : inputLine("baz", 0);
+
+    return StackTrace.builder()
+        .add(fooLine)
+        .add(barLine)
+        .add(bazLine)
+        .add(inputLine("main", 200))
+        .build();
+  }
+
+  private StackTrace getResidualStacktrace() {
+    if (parameters.isCfRuntime()) {
+      // For CF compilation the line number increments are used and each preamble is retained as
+      // such. This is the expected output.
+      return StackTrace.builder()
+          .add(residualLine("foo", -1))
+          .add(residualLine("bar", -1))
+          .add(residualLine("baz", -1))
+          .add(residualLine("main", 101)) // TODO(b/232212653) Why is this 101?
+          .build();
+    }
+
+    // TODO(b/232212653): The correct line should be with CUSTOM_SOURCE_FILE and PC 1.
+    //   When compiling with debug info encoding PCs this is almost the expected output. The issue
+    //   being that even "foo" should have PC based encoding too to ensure the SF remains on
+    //   newer VMs too.
+    StackTraceLine fooLine =
+        isRuntimeWithPcAsLineNumberSupport()
+            ? line(UNKNOWN_SOURCE_FILE, "foo", 1)
+            : residualLine("foo", -1);
+
+    return StackTrace.builder()
+        .add(fooLine)
+        .add(residualLine("bar", 0))
+        .add(residualLine("baz", 0))
+        .add(residualLine("main", 6))
+        .build();
+  }
+
+  // Test with a call stack where each initial line is stripped (see getTestClassTransformed)
+  // Line numbers are indicated in comments. The stacktrace is marked by ***.
+  static class TestClass {
+
+    public static void nop() {}
+
+    public static void foo() {
+      throw null; // noline ***
+    }
+
+    public static void bar() {
+      foo(); // noline ***
+      nop(); // 100
+    }
+
+    public static void baz() {
+      bar(); // noline ***
+      nop(); // 100
+      nop(); // 200
+    }
+
+    public static void main(String[] args) {
+      nop(); // noline
+      nop(); // 100
+      baz(); // 200 ***
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/debuginfo/Regress111337896TestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/Regress111337896TestRunner.java
index be25d4a..f144498 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/Regress111337896TestRunner.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/Regress111337896TestRunner.java
@@ -9,8 +9,8 @@
 import com.android.tools.r8.D8;
 import com.android.tools.r8.D8Command;
 import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.Nop;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexNop;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.AndroidAppConsumers;
@@ -51,8 +51,8 @@
     info.checkStartLine(12);
     assertEquals(1, info.checkLineExists(18));
     int nopsFound = 0;
-    for (Instruction instruction : info.getMethod().getCode().asDexCode().instructions) {
-      if (instruction instanceof Nop) {
+    for (DexInstruction instruction : info.getMethod().getCode().asDexCode().instructions) {
+      if (instruction instanceof DexNop) {
         nopsFound++;
       }
     }
@@ -103,8 +103,8 @@
     info.checkStartLine(11);
     assertEquals(1, info.checkLineExists(13));
     int nopsFound = 0;
-    for (Instruction instruction : info.getMethod().getCode().asDexCode().instructions) {
-      if (instruction instanceof Nop) {
+    for (DexInstruction instruction : info.getMethod().getCode().asDexCode().instructions) {
+      if (instruction instanceof DexNop) {
         nopsFound++;
       }
     }
diff --git a/src/test/java/com/android/tools/r8/debuginfo/Regress216178582Test.java b/src/test/java/com/android/tools/r8/debuginfo/Regress216178582Test.java
index ac4be8c..92a8a3d 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/Regress216178582Test.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/Regress216178582Test.java
@@ -10,7 +10,7 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.code.Instruction;
+import com.android.tools.r8.dex.code.DexInstruction;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.graph.DexDebugEntry;
 import com.android.tools.r8.graph.DexDebugEntryBuilder;
@@ -68,7 +68,7 @@
                       new DexDebugEntryBuilder(method, inspector.getFactory()).build();
                   Iterator<DexDebugEntry> it = entries.iterator();
                   int pc = 0;
-                  for (Instruction instruction : code.instructions) {
+                  for (DexInstruction instruction : code.instructions) {
                     if (instruction.canThrow()) {
                       DexDebugEntry next = it.next();
                       assertEquals(
diff --git a/src/test/java/com/android/tools/r8/desugar/DesugarToClassFileBackport.java b/src/test/java/com/android/tools/r8/desugar/DesugarToClassFileBackport.java
index 2297f3f..9444833 100644
--- a/src/test/java/com/android/tools/r8/desugar/DesugarToClassFileBackport.java
+++ b/src/test/java/com/android/tools/r8/desugar/DesugarToClassFileBackport.java
@@ -13,8 +13,8 @@
 import com.android.tools.r8.cf.code.CfArithmeticBinop;
 import com.android.tools.r8.cf.code.CfArithmeticBinop.Opcode;
 import com.android.tools.r8.cf.code.CfInstruction;
-import com.android.tools.r8.code.AddLong2Addr;
-import com.android.tools.r8.code.Instruction;
+import com.android.tools.r8.dex.code.DexAddLong2Addr;
+import com.android.tools.r8.dex.code.DexInstruction;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.ir.code.NumericType;
@@ -47,8 +47,8 @@
         && (((CfArithmeticBinop) instruction).getType() == NumericType.LONG);
   }
 
-  private boolean isDexAddLong(Instruction instruction) {
-    return instruction instanceof AddLong2Addr;
+  private boolean isDexAddLong(DexInstruction instruction) {
+    return instruction instanceof DexAddLong2Addr;
   }
 
   private boolean boxedDoubleIsFiniteInvoke(InstructionSubject instruction) {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ConcurrentHashMapSubclassTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ConcurrentHashMapSubclassTest.java
index 6b4cf39..4022ff8 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ConcurrentHashMapSubclassTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ConcurrentHashMapSubclassTest.java
@@ -4,17 +4,18 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
-import static org.junit.Assert.assertEquals;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.SPECIFICATIONS_WITH_CF2CF;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.StringUtils;
-import java.nio.file.Path;
 import java.util.IdentityHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
-import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -27,93 +28,35 @@
       StringUtils.lines("1.0", "2.0", "10.0", "1.0", "2.0", "10.0", "1.0", "2.0", "10.0");
 
   private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
 
-  @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        BooleanUtils.values(),
-        getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build());
+        getTestParameters()
+            .withAllRuntimes()
+            .withAllApiLevelsAlsoForCf()
+            .withApiLevel(AndroidApiLevel.N)
+            .build(),
+        getJdk8Jdk11(),
+        SPECIFICATIONS_WITH_CF2CF);
   }
 
-  public ConcurrentHashMapSubclassTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+  public ConcurrentHashMapSubclassTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   @Test
-  public void testCustomCollectionD8() throws Exception {
-    Assume.assumeTrue(parameters.getRuntime().isDex());
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForD8()
-        .addLibraryFiles(getLibraryFile())
-        .addInnerClasses(ConcurrentHashMapSubclassTest.class)
-        .setMinApi(parameters.getApiLevel())
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-        .compile()
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
-        .run(parameters.getRuntime(), Executor.class)
-        .assertSuccessWithOutput(EXPECTED_RESULT);
-  }
-
-  @Test
-  public void testCustomCollectionD8CF() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    Path jar =
-        testForD8(Backend.CF)
-            .addInnerClasses(ConcurrentHashMapSubclassTest.class)
-            .setMinApi(parameters.getApiLevel())
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-            .compile()
-            .writeToZip();
-    String desugaredLibraryKeepRules = "";
-    if (shrinkDesugaredLibrary && keepRuleConsumer.get() != null) {
-      // Collection keep rules is only implemented in the DEX writer.
-      assertEquals(0, keepRuleConsumer.get().length());
-      desugaredLibraryKeepRules = "-keep class * { *; }";
-    }
-    if (parameters.getRuntime().isDex()) {
-      testForD8()
-          .addProgramFiles(jar)
-          .setMinApi(parameters.getApiLevel())
-          .disableDesugaring()
-          .compile()
-          .addDesugaredCoreLibraryRunClassPath(
-              this::buildDesugaredLibrary,
-              parameters.getApiLevel(),
-              desugaredLibraryKeepRules,
-              shrinkDesugaredLibrary)
-          .run(parameters.getRuntime(), Executor.class)
-          .assertSuccessWithOutput(EXPECTED_RESULT);
-    } else {
-      testForJvm()
-          .addProgramFiles(jar)
-          .addRunClasspathFiles(getDesugaredLibraryInCF(parameters, options -> {}))
-          .run(parameters.getRuntime(), Executor.class)
-          .assertSuccessWithOutput(EXPECTED_RESULT);
-    }
-  }
-
-  @Test
-  public void testCustomCollectionR8() throws Exception {
-    Assume.assumeTrue(parameters.getRuntime().isDex());
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForR8(Backend.DEX)
-        .addLibraryFiles(getLibraryFile())
-        .addInnerClasses(ConcurrentHashMapSubclassTest.class)
-        .setMinApi(parameters.getApiLevel())
-        .addKeepClassAndMembersRules(Executor.class)
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-        .compile()
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
+  public void test() throws Exception {
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+        .addInnerClasses(getClass())
+        .addKeepMainRule(Executor.class)
         .run(parameters.getRuntime(), Executor.class)
         .assertSuccessWithOutput(EXPECTED_RESULT);
   }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionForwardingTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionForwardingTest.java
index f2beac6..48c1d63 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionForwardingTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionForwardingTest.java
@@ -4,8 +4,12 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.SPECIFICATIONS_WITH_CF2CF;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
+
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.StringUtils;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -23,53 +27,31 @@
 public class CustomCollectionForwardingTest extends DesugaredLibraryTestBase {
 
   private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
 
-  @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+        getJdk8Jdk11(),
+        SPECIFICATIONS_WITH_CF2CF);
   }
 
-  public CustomCollectionForwardingTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+  public CustomCollectionForwardingTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   @Test
-  public void testCustomCollectionD8() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForD8()
-        .addLibraryFiles(getLibraryFile())
-        .addInnerClasses(CustomCollectionForwardingTest.class)
-        .setMinApi(parameters.getApiLevel())
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-        .compile()
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
-        .run(parameters.getRuntime(), Executor.class)
-        .assertSuccessWithOutput(
-            StringUtils.lines("false", "false", "false", "false", "false", "false"));
-  }
-
-  @Test
-  public void testCustomCollectionR8() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForR8(parameters.getBackend())
-        .addLibraryFiles(getLibraryFile())
-        .addInnerClasses(CustomCollectionForwardingTest.class)
+  public void testCollection() throws Exception {
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+        .addInnerClasses(getClass())
         .addKeepMainRule(Executor.class)
-        .setMinApi(parameters.getApiLevel())
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-        .compile()
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
         .run(parameters.getRuntime(), Executor.class)
         .assertSuccessWithOutput(
             StringUtils.lines("false", "false", "false", "false", "false", "false"));
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionInterfaceSuperTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionInterfaceSuperTest.java
index 371b114..5d35c07 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionInterfaceSuperTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionInterfaceSuperTest.java
@@ -4,10 +4,12 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
-import static org.junit.Assume.assumeTrue;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.StringUtils;
 import java.util.Collection;
 import java.util.Collections;
@@ -22,21 +24,6 @@
 @RunWith(Parameterized.class)
 public class CustomCollectionInterfaceSuperTest extends DesugaredLibraryTestBase {
 
-  private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
-
-  @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
-  public static List<Object[]> data() {
-    return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimes().withAllApiLevels().build());
-  }
-
-  public CustomCollectionInterfaceSuperTest(
-      boolean shrinkDesugaredLibrary, TestParameters parameters) {
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
-    this.parameters = parameters;
-  }
-
   private static final String EXPECTED_OUTPUT =
       StringUtils.lines(
           "removeIf from MyCol1",
@@ -46,51 +33,32 @@
           "removeIf from MyCol2",
           "removeIf from MyCol1");
 
-  @Test
-  public void testCustomCollectionD8() throws Exception {
-    if (parameters.isCfRuntime()) {
-      testForJvm()
-          .addInnerClasses(CustomCollectionInterfaceSuperTest.class)
-          .run(parameters.getRuntime(), Main.class)
-          .assertSuccessWithOutput(EXPECTED_OUTPUT);
-      return;
-    }
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForD8()
-        .addLibraryFiles(getLibraryFile())
-        .addInnerClasses(CustomCollectionInterfaceSuperTest.class)
-        .setMinApi(parameters.getApiLevel())
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-        .compile()
-        .assertNoMessages()
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
-        .run(parameters.getRuntime(), Main.class)
-        .assertSuccessWithOutput(EXPECTED_OUTPUT);
+  private final TestParameters parameters;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+
+  @Parameters(name = "{0}, spec: {1}, {2}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+        getJdk8Jdk11(),
+        DEFAULT_SPECIFICATIONS);
+  }
+
+  public CustomCollectionInterfaceSuperTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
+    this.parameters = parameters;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   @Test
-  public void testCustomCollectionR8() throws Exception {
-    // Desugared library tests do not make sense in the Cf to Cf, and the JVM is already tested
-    // in the D8 test. Just return.
-    assumeTrue(parameters.isDexRuntime());
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForR8(parameters.getBackend())
-        .addLibraryFiles(getLibraryFile())
-        .addInnerClasses(CustomCollectionInterfaceSuperTest.class)
+  public void testCollection() throws Exception {
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+        .addInnerClasses(getClass())
         .addKeepMainRule(Main.class)
-        .setMinApi(parameters.getApiLevel())
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-        .compile()
-        .assertNoMessages()
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutput(EXPECTED_OUTPUT);
   }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionSuperCallsTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionSuperCallsTest.java
index d770fdb..c597d50 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionSuperCallsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionSuperCallsTest.java
@@ -4,13 +4,12 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
-import static org.junit.Assert.assertEquals;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.SPECIFICATIONS_WITH_CF2CF;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 
-import com.android.tools.r8.D8TestRunResult;
-import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.BooleanUtils;
-import java.nio.file.Path;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Spliterator;
@@ -24,101 +23,37 @@
 public class CustomCollectionSuperCallsTest extends DesugaredLibraryTestBase {
 
   private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
 
-  @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+        getJdk8Jdk11(),
+        SPECIFICATIONS_WITH_CF2CF);
   }
 
-  public CustomCollectionSuperCallsTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+  public CustomCollectionSuperCallsTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   @Test
-  public void testCustomCollectionSuperCallsD8() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    D8TestRunResult d8TestRunResult =
-        testForD8()
-            .addLibraryFiles(getLibraryFile())
-            .addInnerClasses(CustomCollectionSuperCallsTest.class)
-            .setMinApi(parameters.getApiLevel())
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-            .compile()
-            .addDesugaredCoreLibraryRunClassPath(
-                this::buildDesugaredLibrary,
-                parameters.getApiLevel(),
-                keepRuleConsumer.get(),
-                shrinkDesugaredLibrary)
-            .run(parameters.getRuntime(), Executor.class)
-            .assertSuccess();
-    assertLines2By2Correct(d8TestRunResult.getStdOut());
-  }
-
-  @Test
-  public void testCustomCollectionSuperCallsD8Cf2Cf() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    Path jar =
-        testForD8(Backend.CF)
-            .addInnerClasses(CustomCollectionSuperCallsTest.class)
-            .setMinApi(parameters.getApiLevel())
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-            .allowStdoutMessages()
-            .compile()
-            .writeToZip();
-    String desugaredLibraryKeepRules = "";
-    if (shrinkDesugaredLibrary && keepRuleConsumer.get() != null) {
-      // Collection keep rules is only implemented in the DEX writer.
-      assertEquals(0, keepRuleConsumer.get().length());
-      desugaredLibraryKeepRules = "-keep class * { *; }";
-    }
-    D8TestRunResult d8TestRunResult;
-    if (parameters.getRuntime().isDex()) {
-      d8TestRunResult =
-          testForD8()
-              .addProgramFiles(jar)
-              .setMinApi(parameters.getApiLevel())
-              .disableDesugaring()
-              .allowStdoutMessages()
-              .compile()
-              .addDesugaredCoreLibraryRunClassPath(
-                  this::buildDesugaredLibrary,
-                  parameters.getApiLevel(),
-                  desugaredLibraryKeepRules,
-                  shrinkDesugaredLibrary)
-              .run(parameters.getRuntime(), Executor.class)
-              .assertSuccess();
-      assertLines2By2Correct(d8TestRunResult.getStdOut());
-    } else {
-      testForJvm()
-          .addProgramFiles(jar)
-          .addRunClasspathFiles(getDesugaredLibraryInCF(parameters, options -> {}))
-          .run(parameters.getRuntime(), Executor.class)
-          .assertSuccess();
-    }
-  }
-
-  @Test
-  public void testCustomCollectionSuperCallsR8() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    R8TestRunResult r8TestRunResult =
-        testForR8(parameters.getBackend())
-            .addLibraryFiles(getLibraryFile())
-            .addInnerClasses(CustomCollectionSuperCallsTest.class)
+  public void testCollection() throws Exception {
+    String stdOut =
+        testForDesugaredLibrary(
+                parameters, libraryDesugaringSpecification, compilationSpecification)
+            .addInnerClasses(getClass())
             .addKeepMainRule(Executor.class)
-            .setMinApi(parameters.getApiLevel())
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-            .compile()
-            .addDesugaredCoreLibraryRunClassPath(
-                this::buildDesugaredLibrary,
-                parameters.getApiLevel(),
-                keepRuleConsumer.get(),
-                shrinkDesugaredLibrary)
             .run(parameters.getRuntime(), Executor.class)
-            .assertSuccess();
-    assertLines2By2Correct(r8TestRunResult.getStdOut());
+            .assertSuccess()
+            .getStdOut();
+    assertLines2By2Correct(stdOut);
   }
 
   static class Executor {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionTest.java
index 473153c..4681e27 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
@@ -4,18 +4,17 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
-import static org.junit.Assert.assertEquals;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.SPECIFICATIONS_WITH_CF2CF;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.D8TestRunResult;
-import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 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.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -33,124 +32,56 @@
 public class CustomCollectionTest extends DesugaredLibraryTestBase {
 
   private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
 
-  @Parameters(name = "machine: {0}, shrink: {1}")
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        BooleanUtils.values(),
-        getTestParameters().withDexRuntimes().withAllApiLevels().build());
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+        getJdk8Jdk11(),
+        SPECIFICATIONS_WITH_CF2CF);
   }
 
-  public CustomCollectionTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+  public CustomCollectionTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
-  private final String EXECUTOR =
-      "com.android.tools.r8.desugar.desugaredlibrary.CustomCollectionTest$Executor";
-
   @Test
-  public void testCustomCollectionD8() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    D8TestRunResult d8TestRunResult =
-        testForD8()
-            .addLibraryFiles(getLibraryFile())
-            .addInnerClasses(CustomCollectionTest.class)
-            .setMinApi(parameters.getApiLevel())
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+  public void testCollection() throws Throwable {
+    String stdOut =
+        testForDesugaredLibrary(
+                parameters, libraryDesugaringSpecification, compilationSpecification)
+            .addInnerClasses(getClass())
+            .addKeepMainRule(Executor.class)
             .compile()
-            .assertNoMessages()
             .inspect(this::assertCustomCollectionCallsCorrect)
-            .addDesugaredCoreLibraryRunClassPath(
-                this::buildDesugaredLibrary,
-                parameters.getApiLevel(),
-                keepRuleConsumer.get(),
-                shrinkDesugaredLibrary)
             .run(parameters.getRuntime(), Executor.class)
-            .assertSuccess();
-    assertResultCorrect(d8TestRunResult.getStdOut());
-  }
-
-  @Test
-  public void testCustomCollectionD8Cf2Cf() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    // Use D8 to desugar with Java classfile output.
-    Path jar =
-        testForD8(Backend.CF)
-            .addInnerClasses(CustomCollectionTest.class)
-            .setMinApi(parameters.getApiLevel())
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-            .compile()
-            .writeToZip();
-    if (parameters.getRuntime().isDex()) {
-      // Collection keep rules is only implemented in the DEX writer.
-      String desugaredLibraryKeepRules = keepRuleConsumer.get();
-      if (desugaredLibraryKeepRules != null) {
-        assertEquals(0, desugaredLibraryKeepRules.length());
-        desugaredLibraryKeepRules = "-keep class * { *; }";
-      }
-      D8TestRunResult d8TestRunResult =
-          testForD8()
-              .addProgramFiles(jar)
-              .setMinApi(parameters.getApiLevel())
-              .disableDesugaring()
-              .compile()
-              .assertNoMessages()
-              .inspect(this::assertCustomCollectionCallsCorrect)
-              .addDesugaredCoreLibraryRunClassPath(
-                  this::buildDesugaredLibrary,
-                  parameters.getApiLevel(),
-                  desugaredLibraryKeepRules,
-                  shrinkDesugaredLibrary)
-              .run(parameters.getRuntime(), EXECUTOR)
-              .assertSuccess();
-      assertResultCorrect(d8TestRunResult.getStdOut());
-    } else {
-      // Build the desugared library in class file format.
-      Path desugaredLib = getDesugaredLibraryInCF(parameters, o -> {});
-
-      // Run on the JVM with desuagred library on classpath.
-      testForJvm()
-          .addProgramFiles(jar)
-          .addRunClasspathFiles(desugaredLib)
-          .run(parameters.getRuntime(), EXECUTOR)
-          .assertSuccess();
-    }
+            .assertSuccess()
+            .getStdOut();
+    assertResultCorrect(stdOut);
   }
 
   private void assertResultCorrect(String stdOut) {
-    if (requiresEmulatedInterfaceCoreLibDesugaring(parameters) && !shrinkDesugaredLibrary) {
+    if (requiresEmulatedInterfaceCoreLibDesugaring(parameters)
+        && !compilationSpecification.isL8Shrink()) {
       // When shrinking the class names are not printed correctly anymore due to minification.
       // Expected output is emulated interfaces expected output.
       assertLines2By2Correct(stdOut);
     }
   }
 
-  @Test
-  public void testCustomCollectionR8() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    R8TestRunResult r8TestRunResult =
-        testForR8(Backend.DEX)
-            .addLibraryFiles(getLibraryFile())
-            .addInnerClasses(CustomCollectionTest.class)
-            .setMinApi(parameters.getApiLevel())
-            .addKeepClassAndMembersRules(Executor.class)
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-            .compile()
-            .inspect(this::assertCustomCollectionCallsCorrect)
-            .addDesugaredCoreLibraryRunClassPath(
-                this::buildDesugaredLibrary,
-                parameters.getApiLevel(),
-                keepRuleConsumer.get(),
-                shrinkDesugaredLibrary)
-            .run(parameters.getRuntime(), Executor.class)
-            .assertSuccess();
-    assertResultCorrect(r8TestRunResult.getStdOut());
-  }
-
   private void assertCustomCollectionCallsCorrect(CodeInspector inspector) {
-    MethodSubject direct = inspector.clazz(EXECUTOR).uniqueMethodWithName("directTypes");
+    if (compilationSpecification.isProgramShrink()) {
+      return;
+    }
+    MethodSubject direct = inspector.clazz(Executor.class).uniqueMethodWithName("directTypes");
+    System.out.println(direct);
     if (requiresEmulatedInterfaceCoreLibDesugaring(parameters)) {
       assertTrue(
           direct
@@ -164,7 +95,8 @@
     } else {
       assertTrue(direct.streamInstructions().noneMatch(instr -> instr.toString().contains("$-EL")));
     }
-    MethodSubject inherited = inspector.clazz(EXECUTOR).uniqueMethodWithName("inheritedTypes");
+    MethodSubject inherited =
+        inspector.clazz(Executor.class).uniqueMethodWithName("inheritedTypes");
     if (!requiresEmulatedInterfaceCoreLibDesugaring(parameters)) {
       assertTrue(
           inherited.streamInstructions().noneMatch(instr -> instr.toString().contains("$-EL")));
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomMapHierarchyTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomMapHierarchyTest.java
index c4e379c..7306204 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomMapHierarchyTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomMapHierarchyTest.java
@@ -4,14 +4,15 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
-import static org.junit.Assert.assertEquals;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.SPECIFICATIONS_WITH_CF2CF;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
-import java.nio.file.Path;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -28,18 +29,38 @@
       StringUtils.lines("B::getOrDefault", "default 1", "B::getOrDefault", "default 2");
 
   private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
 
-  @Parameters(name = "{0}, shrinkDesugaredLibrary: {1}")
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
         getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(),
-        BooleanUtils.values());
+        getJdk8Jdk11(),
+        SPECIFICATIONS_WITH_CF2CF);
   }
 
-  public CustomMapHierarchyTest(TestParameters parameters, boolean shrinkDesugaredLibrary) {
+  public CustomMapHierarchyTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+  }
+
+  @Test
+  public void testCollection() throws Throwable {
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+        .addInnerClasses(getClass())
+        .addKeepMainRule(Main.class)
+        .addKeepAllClassesRuleWithAllowObfuscation()
+        .addKeepAttributes(
+            ProguardKeepAttributes.SIGNATURE,
+            ProguardKeepAttributes.INNER_CLASSES,
+            ProguardKeepAttributes.ENCLOSING_METHOD)
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutput(EXPECTED);
   }
 
   @Test
@@ -55,93 +76,6 @@
         .assertSuccessWithOutput(EXPECTED);
   }
 
-  @Test
-  public void testD8() throws Exception {
-    Assume.assumeTrue(parameters.getRuntime().isDex());
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForD8()
-        .addLibraryFiles(getLibraryFile())
-        .addInnerClasses(CustomMapHierarchyTest.class)
-        .setMinApi(parameters.getApiLevel())
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-        .compile()
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
-        .run(parameters.getRuntime(), Main.class)
-        .assertSuccessWithOutput(EXPECTED);
-  }
-
-  @Test
-  public void testD8Cf2Cf() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-
-    Path jar =
-        testForD8(Backend.CF)
-            .addInnerClasses(CustomMapHierarchyTest.class)
-            .setMinApi(parameters.getApiLevel())
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-            .setIncludeClassesChecksum(true)
-            .setMinApi(parameters.getApiLevel())
-            .allowStdoutMessages()
-            .compile()
-            .writeToZip();
-    String desugaredLibraryKeepRules = "";
-    if (shrinkDesugaredLibrary && keepRuleConsumer.get() != null) {
-      // Collection keep rules is only implemented in the DEX writer.
-      assertEquals(0, keepRuleConsumer.get().length());
-      desugaredLibraryKeepRules = "-keep class * { *; }";
-    }
-    if (parameters.getRuntime().isDex()) {
-      testForD8()
-          .addProgramFiles(jar)
-          .setMinApi(parameters.getApiLevel())
-          .disableDesugaring()
-          .allowStdoutMessages()
-          .compile()
-          .addDesugaredCoreLibraryRunClassPath(
-              this::buildDesugaredLibrary,
-              parameters.getApiLevel(),
-              desugaredLibraryKeepRules,
-              shrinkDesugaredLibrary)
-          .run(parameters.getRuntime(), Main.class)
-          .assertSuccessWithOutput(EXPECTED);
-    } else {
-      testForJvm()
-          .addProgramFiles(jar)
-          .addRunClasspathFiles(getDesugaredLibraryInCF(parameters, options -> {}))
-          .run(parameters.getRuntime(), Main.class)
-          .assertSuccessWithOutput(EXPECTED);
-    }
-  }
-
-  @Test
-  public void testR8() throws Exception {
-    Assume.assumeTrue(parameters.getRuntime().isDex());
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForR8(parameters.getBackend())
-        .addLibraryFiles(getLibraryFile())
-        .addInnerClasses(CustomMapHierarchyTest.class)
-        .addKeepMainRule(Main.class)
-        .addKeepAllClassesRuleWithAllowObfuscation()
-        .addKeepAttributes(
-            ProguardKeepAttributes.SIGNATURE,
-            ProguardKeepAttributes.INNER_CLASSES,
-            ProguardKeepAttributes.ENCLOSING_METHOD)
-        .setMinApi(parameters.getApiLevel())
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-        .compile()
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
-        .run(parameters.getRuntime(), Main.class)
-        .assertSuccessWithOutput(EXPECTED);
-  }
-
   public static class Main {
     public static void main(String[] args) {
       System.out.println(new B<String>().getOrDefault("Not found", "default 1"));
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DateTimeFormatterTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DateTimeFormatterTest.java
index 2d4640a..8f725ba 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DateTimeFormatterTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DateTimeFormatterTest.java
@@ -4,10 +4,14 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
-import com.android.tools.r8.D8TestRunResult;
-import com.android.tools.r8.R8TestRunResult;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
+
+import com.android.tools.r8.SingleTestRunResult;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.StringUtils;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
@@ -22,67 +26,42 @@
 @RunWith(Parameterized.class)
 public class DateTimeFormatterTest extends DesugaredLibraryTestBase {
 
-  private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
   private static final String expectedOutputDesugaredLib =
       StringUtils.lines("2/3/01 4:05 AM - Feb 3, 1 4:05 AM");
   private static final String expectedOutput =
       StringUtils.lines("2/3/01, 4:05 AM - Feb 3, 1, 4:05 AM");
 
-  @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+  private final TestParameters parameters;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+        getJdk8Jdk11(),
+        DEFAULT_SPECIFICATIONS);
   }
 
-  public DateTimeFormatterTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+  public DateTimeFormatterTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   @Test
-  public void testD8() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    D8TestRunResult run =
-        testForD8()
-            .addLibraryFiles(getLibraryFile())
-            .addInnerClasses(DateTimeFormatterTest.class)
-            .setMinApi(parameters.getApiLevel())
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-            .setIncludeClassesChecksum(true)
-            .compile()
-            .addDesugaredCoreLibraryRunClassPath(
-                this::buildDesugaredLibrary,
-                parameters.getApiLevel(),
-                keepRuleConsumer.get(),
-                shrinkDesugaredLibrary)
-            .run(parameters.getRuntime(), TestClass.class);
-    if (requiresTimeDesugaring(parameters)) {
-      run.assertSuccessWithOutput(expectedOutputDesugaredLib);
-    } else {
-      run.assertSuccessWithOutput(expectedOutput);
-    }
-  }
-
-  @Test
-  public void testR8() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    R8TestRunResult run =
-        testForR8(parameters.getBackend())
-            .addLibraryFiles(getLibraryFile())
-            .noMinification()
+  public void testFormatter() throws Throwable {
+    SingleTestRunResult<?> run =
+        testForDesugaredLibrary(
+                parameters, libraryDesugaringSpecification, compilationSpecification)
+            .addInnerClasses(getClass())
             .addKeepMainRule(TestClass.class)
-            .addInnerClasses(DateTimeFormatterTest.class)
-            .setMinApi(parameters.getApiLevel())
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-            .compile()
-            .addDesugaredCoreLibraryRunClassPath(
-                this::buildDesugaredLibrary,
-                parameters.getApiLevel(),
-                keepRuleConsumer.get(),
-                shrinkDesugaredLibrary)
-            .run(parameters.getRuntime(), TestClass.class);
-    if (requiresTimeDesugaring(parameters)) {
+            .run(parameters.getRuntime(), TestClass.class)
+            .assertSuccess();
+    if (requiresTimeDesugaring(parameters, libraryDesugaringSpecification != JDK8)) {
       run.assertSuccessWithOutput(expectedOutputDesugaredLib);
     } else {
       run.assertSuccessWithOutput(expectedOutput);
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideConflictWithLibrary2Test.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideConflictWithLibrary2Test.java
index 7d73298..5e79404 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideConflictWithLibrary2Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideConflictWithLibrary2Test.java
@@ -3,15 +3,17 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.desugar.desugaredlibrary;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.LibraryDesugaringTestConfiguration;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.TestRunResult;
 import com.android.tools.r8.TestRuntime;
 import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.google.common.collect.ImmutableList;
 import java.io.IOException;
 import java.lang.reflect.Method;
@@ -22,6 +24,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
 
 /**
  * This test checks that if a default interface method in a library interface conflicts with a
@@ -34,14 +37,24 @@
 public class DefaultMethodOverrideConflictWithLibrary2Test extends DesugaredLibraryTestBase {
 
   private final TestParameters parameters;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
 
-  @Parameterized.Parameters(name = "{0}")
-  public static TestParametersCollection data() {
-    return getTestParameters().withAllRuntimes().withAllApiLevels().build();
+  @Parameters(name = "{0}, spec: {1}, {2}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withAllRuntimes().withAllApiLevels().build(),
+        getJdk8Jdk11(),
+        ImmutableList.of(D8_L8DEBUG));
   }
 
-  public DefaultMethodOverrideConflictWithLibrary2Test(TestParameters parameters) {
+  public DefaultMethodOverrideConflictWithLibrary2Test(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   private List<Class<?>> getClasses() {
@@ -75,14 +88,10 @@
           .run(parameters.getRuntime(), Main.class)
           .apply(this::checkResult);
     } else {
-      testForD8()
-          .addLibraryFiles(getLibraryFile())
+      testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
           .addProgramClasses(getClasses())
           .addProgramClassFileData(getTransforms())
-          .setMinApi(parameters.getApiLevel())
-          .enableCoreLibraryDesugaring(
-              LibraryDesugaringTestConfiguration.forApiLevel(parameters.getApiLevel()))
-          .compile()
+          .addKeepMainRule(Main.class)
           .run(parameters.getRuntime(), Main.class)
           .apply(this::checkResult);
     }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideConflictWithLibraryTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideConflictWithLibraryTest.java
index 21abdb5..b608d74 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideConflictWithLibraryTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideConflictWithLibraryTest.java
@@ -3,16 +3,18 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.desugar.desugaredlibrary;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-import com.android.tools.r8.LibraryDesugaringTestConfiguration;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.TestRuntime;
 import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.google.common.collect.ImmutableList;
 import java.io.IOException;
 import java.lang.reflect.Method;
@@ -24,6 +26,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
 
 /**
  * This test checks that if a default interface method in a library is not overridden by a class
@@ -44,14 +47,24 @@
   }
 
   private final TestParameters parameters;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
 
-  @Parameterized.Parameters(name = "{0}")
-  public static TestParametersCollection data() {
-    return getTestParameters().withAllRuntimes().withAllApiLevels().build();
+  @Parameters(name = "{0}, spec: {1}, {2}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withAllRuntimes().withAllApiLevels().build(),
+        getJdk8Jdk11(),
+        ImmutableList.of(D8_L8DEBUG));
   }
 
-  public DefaultMethodOverrideConflictWithLibraryTest(TestParameters parameters) {
+  public DefaultMethodOverrideConflictWithLibraryTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   @Test
@@ -77,14 +90,10 @@
           .run(parameters.getRuntime(), Main.class)
           .assertFailureWithErrorThatMatches(getExpectedError());
     } else {
-      testForD8()
-          .addLibraryFiles(getLibraryFile())
-          .setMinApi(parameters.getApiLevel())
+      testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
           .addProgramClasses(CLASSES)
           .addProgramClassFileData(getTransforms())
-          .enableCoreLibraryDesugaring(
-              LibraryDesugaringTestConfiguration.forApiLevel(parameters.getApiLevel()))
-          .compile()
+          .addKeepMainRule(Main.class)
           .run(parameters.getRuntime(), Main.class)
           .assertFailureWithErrorThatMatches(getExpectedError());
     }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideInLibraryTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideInLibraryTest.java
index 14d4f62..0230e38 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideInLibraryTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideInLibraryTest.java
@@ -3,18 +3,21 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.desugar.desugaredlibrary;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 
-import com.android.tools.r8.D8TestRunResult;
-import com.android.tools.r8.LibraryDesugaringTestConfiguration;
+import com.android.tools.r8.SingleTestRunResult;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.TestRuntime;
 import com.android.tools.r8.TestRuntime.CfVm;
 import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.List;
@@ -23,6 +26,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
 
 /**
  * This test checks that if a default interface method in a library is overridden by a class method
@@ -39,14 +43,24 @@
   static final String EXPECTED = StringUtils.lines("0", "42", "0", "0", "42", "42");
 
   private final TestParameters parameters;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
 
-  @Parameterized.Parameters(name = "{0}")
-  public static TestParametersCollection data() {
-    return getTestParameters().withAllRuntimes().withAllApiLevels().build();
+  @Parameters(name = "{0}, spec: {1}, {2}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withAllRuntimes().withAllApiLevels().build(),
+        getJdk8Jdk11(),
+        ImmutableList.of(D8_L8DEBUG));
   }
 
-  public DefaultMethodOverrideInLibraryTest(TestParameters parameters) {
+  public DefaultMethodOverrideInLibraryTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   @Test
@@ -65,19 +79,15 @@
           .run(parameters.getRuntime(), Main.class)
           .assertSuccessWithOutput(EXPECTED);
     } else {
-      testForD8()
-          .addLibraryFiles(getLibraryFile())
-          .setMinApi(parameters.getApiLevel())
-          .addInnerClasses(DefaultMethodOverrideInLibraryTest.class)
-          .enableCoreLibraryDesugaring(
-              LibraryDesugaringTestConfiguration.forApiLevel(parameters.getApiLevel()))
-          .compile()
+      testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+          .addInnerClasses(getClass())
+          .addKeepMainRule(Main.class)
           .run(parameters.getRuntime(), Main.class)
           .apply(this::checkResult);
     }
   }
 
-  private void checkResult(D8TestRunResult result) {
+  private void checkResult(SingleTestRunResult<?> result) {
     // TODO(b/145504401): Execution on Art 7.0.0 has the wrong runtime behavior (non-desugared).
     if (parameters.isDexRuntime()
         && parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredGenericSignatureTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredGenericSignatureTest.java
index 912e353..02e844e 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredGenericSignatureTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredGenericSignatureTest.java
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.SPECIFICATIONS_WITH_CF2CF;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
@@ -11,22 +13,21 @@
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import java.io.Serializable;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
-import java.nio.file.Path;
 import java.time.LocalDate;
 import java.util.AbstractSequentialList;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.function.UnaryOperator;
-import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -36,91 +37,30 @@
 public class DesugaredGenericSignatureTest extends DesugaredLibraryTestBase {
 
   private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
 
-  @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
         getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(),
-        BooleanUtils.values());
+        getJdk8Jdk11(),
+        SPECIFICATIONS_WITH_CF2CF);
   }
 
-  public DesugaredGenericSignatureTest(TestParameters parameters, boolean shrinkDesugaredLibrary) {
+  public DesugaredGenericSignatureTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   @Test
-  public void testD8() throws Exception {
-    Assume.assumeTrue(parameters.getRuntime().isDex());
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForD8()
-        .addLibraryFiles(getLibraryFile())
-        .addInnerClasses(DesugaredGenericSignatureTest.class)
-        .setMinApi(parameters.getApiLevel())
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-        .setIncludeClassesChecksum(true)
-        .compile()
-        .inspect(this::checkRewrittenSignature)
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
-        .run(parameters.getRuntime(), Main.class)
-        .assertSuccessWithOutput(expected(parameters, false));
-  }
-
-  @Test
-  public void testD8Cf2Cf() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-
-    Path jar =
-        testForD8(Backend.CF)
-            .addInnerClasses(DesugaredGenericSignatureTest.class)
-            .setMinApi(parameters.getApiLevel())
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-            .setIncludeClassesChecksum(true)
-            .setMinApi(parameters.getApiLevel())
-            .allowStdoutMessages()
-            .compile()
-            .writeToZip();
-    String desugaredLibraryKeepRules = "";
-    if (shrinkDesugaredLibrary && keepRuleConsumer.get() != null) {
-      // Collection keep rules is only implemented in the DEX writer.
-      assertEquals(0, keepRuleConsumer.get().length());
-      desugaredLibraryKeepRules = "-keep class * { *; }";
-    }
-    if (parameters.getRuntime().isDex()) {
-      testForD8()
-          .addProgramFiles(jar)
-          .setMinApi(parameters.getApiLevel())
-          .disableDesugaring()
-          .allowStdoutMessages()
-          .compile()
-          .addDesugaredCoreLibraryRunClassPath(
-              this::buildDesugaredLibrary,
-              parameters.getApiLevel(),
-              desugaredLibraryKeepRules,
-              shrinkDesugaredLibrary)
-          .run(parameters.getRuntime(), Main.class)
-          .assertSuccessWithOutput(expected(parameters, true));
-    } else {
-      testForJvm()
-          .addProgramFiles(jar)
-          .addRunClasspathFiles(getDesugaredLibraryInCF(parameters, options -> {}))
-          .run(parameters.getRuntime(), Main.class)
-          .assertSuccessWithOutput(expected(parameters, true));
-    }
-  }
-
-  @Test
-  public void testR8() throws Exception {
-    Assume.assumeTrue(parameters.getRuntime().isDex());
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForR8(parameters.getBackend())
-        .addLibraryFiles(getLibraryFile())
-        .addInnerClasses(DesugaredGenericSignatureTest.class)
+  public void testGenericSignature() throws Throwable {
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+        .addInnerClasses(getClass())
         .addKeepMainRule(Main.class)
         .addKeepAllClassesRuleWithAllowObfuscation()
         .addKeepAttributes(
@@ -128,17 +68,10 @@
             ProguardKeepAttributes.INNER_CLASSES,
             ProguardKeepAttributes.ENCLOSING_METHOD)
         .enableInliningAnnotations()
-        .setMinApi(parameters.getApiLevel())
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
         .compile()
         .inspect(this::checkRewrittenSignature)
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
         .run(parameters.getRuntime(), Main.class)
-        .assertSuccessWithOutput(expected(parameters, false));
+        .assertSuccessWithOutput(expected(parameters, compilationSpecification.isCfToCf()));
   }
 
   private void checkRewrittenSignature(CodeInspector inspector) {
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 4d87dbf..24969a0 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
@@ -4,76 +4,54 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
-import com.android.tools.r8.StringResource;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8SHRINK;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11_CHM_ONLY;
+
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser;
-import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import java.nio.file.Path;
-import java.util.Collections;
-import org.junit.Assume;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class DesugaredLibraryCHMOnlyContentTest extends DesugaredLibraryTestBase {
 
-  private final TestParameters parameters;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
 
-  @Parameterized.Parameters(name = "{0}")
-  public static TestParametersCollection data() {
-    return getTestParameters().withDexRuntimes().withAllApiLevels().build();
+  @Parameters(name = "{0}, spec: {1}, {2}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withNoneRuntime().build(),
+        ImmutableList.of(JDK11_CHM_ONLY),
+        ImmutableList.of(D8_L8DEBUG, D8_L8SHRINK));
   }
 
-  public DesugaredLibraryCHMOnlyContentTest(TestParameters parameters) {
-    this.parameters = parameters;
+  public DesugaredLibraryCHMOnlyContentTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   @Test
-  public void testDesugaredLibraryContentCHMOnlyD8() throws Exception {
-    Assume.assumeTrue(requiresEmulatedInterfaceCoreLibDesugaring(parameters));
-    Assume.assumeTrue(isJDK11DesugaredLibrary());
-    Path desugaredLib =
-        buildDesugaredLibrary(
-            parameters.getApiLevel(),
-            "",
-            false,
-            Collections.emptyList(),
-            options ->
-                setDesugaredLibrarySpecificationForTesting(
-                    options, chmOnlyConfiguration(options, true, parameters)));
-    CodeInspector inspector = new CodeInspector(desugaredLib);
-    assert inspector.clazz("j$.util.concurrent.ConcurrentHashMap").isPresent();
-  }
-
-  @Test
-  public void testDesugaredLibraryContentCHMOnlyR8() throws Exception {
-    Assume.assumeTrue(requiresEmulatedInterfaceCoreLibDesugaring(parameters));
-    Assume.assumeTrue(isJDK11DesugaredLibrary());
-    Path desugaredLib =
-        buildDesugaredLibrary(
-            parameters.getApiLevel(),
-            "-keep class * { *; }",
-            true,
-            Collections.emptyList(),
-            options ->
-                setDesugaredLibrarySpecificationForTesting(
-                    options, chmOnlyConfiguration(options, true, parameters)));
-    CodeInspector inspector = new CodeInspector(desugaredLib);
-    assert inspector.clazz("j$.util.concurrent.ConcurrentHashMap").isPresent();
-  }
-
-  DesugaredLibrarySpecification chmOnlyConfiguration(
-      InternalOptions options, boolean libraryCompilation, TestParameters parameters) {
-    return DesugaredLibrarySpecificationParser.parseDesugaredLibrarySpecification(
-        StringResource.fromFile(ToolHelper.getCHMOnlyDesugarLibJsonForTesting()),
-        options.dexItemFactory(),
-        options.reporter,
-        libraryCompilation,
-        parameters.getApiLevel().getLevel());
+  public void testDesugaredLibraryContentCHMOnly() throws Throwable {
+    testForL8(AndroidApiLevel.B)
+        .apply(
+            b ->
+                libraryDesugaringSpecification.configureL8TestBuilder(
+                    b, compilationSpecification.isL8Shrink(), "-keep class * { *; }"))
+        .compile()
+        .inspect(
+            inspector -> {
+              assert inspector.clazz("j$.util.concurrent.ConcurrentHashMap").isPresent();
+            });
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryChecksumsTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryChecksumsTest.java
index e2565d6..506cb9c 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryChecksumsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryChecksumsTest.java
@@ -3,52 +3,53 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.desugar.desugaredlibrary;
 
-import com.android.tools.r8.CompilationMode;
-import com.android.tools.r8.L8;
-import com.android.tools.r8.L8Command;
-import com.android.tools.r8.OutputMode;
-import com.android.tools.r8.StringResource;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
+
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
-import java.nio.file.Path;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class DesugaredLibraryChecksumsTest extends DesugaredLibraryTestBase {
 
-  @Parameterized.Parameters(name = "{0}")
-  public static TestParametersCollection data() {
-    return getTestParameters().withNoneRuntime().build();
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+
+  @Parameters(name = "{0}, spec: {1}, {2}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withNoneRuntime().build(),
+        getJdk8Jdk11(),
+        ImmutableList.of(D8_L8DEBUG));
   }
 
-  public DesugaredLibraryChecksumsTest(TestParameters parameters) {
-    parameters.assertNoneRuntime();
+  public DesugaredLibraryChecksumsTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   @Test
   public void test() throws Exception {
-    Path out = temp.newFolder().toPath().resolve("out.jar");
-    L8.run(
-        L8Command.builder()
-            .setIncludeClassesChecksum(true)
-            .addLibraryFiles(getLibraryFile())
-            .addProgramFiles(ToolHelper.getDesugarJDKLibs())
-            .addProgramFiles(ToolHelper.DESUGAR_LIB_CONVERSIONS)
-            .setMode(CompilationMode.DEBUG)
-            .addDesugaredLibraryConfiguration(
-                StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
-            .setMinApiLevel(AndroidApiLevel.B.getLevel())
-            .setOutput(out, OutputMode.DexIndexed)
-            .build());
-    CodeInspector inspector = new CodeInspector(out);
-    for (FoundClassSubject clazz : inspector.allClasses()) {
-      clazz.getDexProgramClass().getChecksum();
-    }
+    testForL8(AndroidApiLevel.B)
+        .apply(libraryDesugaringSpecification::configureL8TestBuilder)
+        .compile()
+        .inspect(
+            inspector -> {
+              for (FoundClassSubject clazz : inspector.allClasses()) {
+                clazz.getDexProgramClass().getChecksum();
+              }
+            });
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCloneTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCloneTest.java
index b7a9374..9a8b258 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCloneTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCloneTest.java
@@ -4,8 +4,12 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
+
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import java.time.DayOfWeek;
 import java.util.List;
 import org.junit.Test;
@@ -16,54 +20,34 @@
 @RunWith(Parameterized.class)
 public class DesugaredLibraryCloneTest extends DesugaredLibraryTestBase {
 
-  private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
-  private final String EXPECTED = "Just another manic MONDAY";
+  private static final String EXPECTED = "Just another manic MONDAY";
 
-  @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+  private final TestParameters parameters;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        getTestParameters().withDexRuntimes().withAllApiLevels().build(), BooleanUtils.values());
+        getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(),
+        getJdk8Jdk11(),
+        DEFAULT_SPECIFICATIONS);
   }
 
-  public DesugaredLibraryCloneTest(TestParameters parameters, boolean shrinkDesugaredLibrary) {
+  public DesugaredLibraryCloneTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   @Test
-  public void testD8() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForD8()
-        .addLibraryFiles(getLibraryFile())
-        .addInnerClasses(getClass())
-        .setMinApi(parameters.getApiLevel())
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-        .compile()
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
-        .run(parameters.getRuntime(), Main.class)
-        .assertSuccessWithOutputLines(EXPECTED);
-  }
-
-  @Test
-  public void testR8() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForR8(parameters.getBackend())
-        .addLibraryFiles(getLibraryFile())
+  public void testClone() throws Throwable {
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
         .addInnerClasses(getClass())
         .addKeepMainRule(Main.class)
-        .setMinApi(parameters.getApiLevel())
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-        .compile()
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines(EXPECTED);
   }
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 6ce91e1..38845cc 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,6 +5,9 @@
 package com.android.tools.r8.desugar.desugaredlibrary;
 
 import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static junit.framework.TestCase.assertTrue;
 import static org.hamcrest.CoreMatchers.startsWith;
@@ -14,52 +17,70 @@
 import static org.junit.Assert.assertNotEquals;
 
 import com.android.tools.r8.D8TestBuilder;
-import com.android.tools.r8.L8Command;
 import com.android.tools.r8.LibraryDesugaringTestConfiguration;
-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;
 import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.google.common.collect.ImmutableList;
 import java.nio.file.Path;
 import java.util.ArrayList;
+import java.util.List;
 import org.hamcrest.CoreMatchers;
 import org.junit.Assume;
 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 DesugaredLibraryContentTest extends DesugaredLibraryTestBase {
 
   private final TestParameters parameters;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
 
-  @Parameterized.Parameters(name = "{0}")
-  public static TestParametersCollection data() {
-    return getTestParameters().withDexRuntimes().withAllApiLevels().build();
+  @Parameters(name = "{0}, spec: {1}, {2}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(),
+        getJdk8Jdk11(),
+        ImmutableList.of(D8_L8DEBUG));
   }
 
-  public DesugaredLibraryContentTest(TestParameters parameters) {
+  public DesugaredLibraryContentTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   @Test
   public void testInvalidLibrary() {
     Assume.assumeTrue(requiresAnyCoreLibDesugaring(parameters));
+    // This is handwritten since this is really a special case: library desugaring with an
+    // invalid library file passed.
     D8TestBuilder testBuilder =
         testForD8()
             .setMinApi(parameters.getApiLevel())
             .addProgramClasses(GuineaPig.class)
             .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.L))
             .enableCoreLibraryDesugaring(
-                LibraryDesugaringTestConfiguration.forApiLevel(parameters.getApiLevel()));
+                LibraryDesugaringTestConfiguration.builder()
+                    .setMinApi(parameters.getApiLevel())
+                    .addDesugaredLibraryConfiguration(
+                        StringResource.fromFile(libraryDesugaringSpecification.getSpecification()))
+                    .dontAddRunClasspath()
+                    .build());
     try {
       testBuilder.compile();
     } catch (Throwable t) {
@@ -77,19 +98,12 @@
   }
 
   @Test
-  public void testDesugaredLibraryContentD8() throws Exception {
+  public void testDesugaredLibraryContent() throws Exception {
     Assume.assumeTrue(requiresAnyCoreLibDesugaring(parameters));
-    CodeInspector inspector = new CodeInspector(buildDesugaredLibrary(parameters.getApiLevel()));
-    assertCorrect(inspector);
-  }
-
-  @Test
-  public void testDesugaredLibraryContentR8() throws Exception {
-    Assume.assumeTrue(requiresAnyCoreLibDesugaring(parameters));
-    CodeInspector inspector =
-        new CodeInspector(
-            buildDesugaredLibrary(parameters.getApiLevel(), "-keep class * { *; }", true));
-    assertCorrect(inspector);
+    testForL8(parameters.getApiLevel())
+        .apply(libraryDesugaringSpecification::configureL8TestBuilder)
+        .compile()
+        .inspect(this::assertCorrect);
   }
 
   @Test
@@ -97,37 +111,31 @@
     Assume.assumeTrue(requiresAnyCoreLibDesugaring(parameters));
     ArrayList<Path> coreLambdaStubs = new ArrayList<>();
     coreLambdaStubs.add(ToolHelper.getCoreLambdaStubs());
-    CodeInspector inspector =
-        new CodeInspector(
-            buildDesugaredLibrary(parameters.getApiLevel(), "", false, coreLambdaStubs));
-    assertCorrect(inspector);
+    testForL8(parameters.getApiLevel())
+        .apply(libraryDesugaringSpecification::configureL8TestBuilder)
+        .addProgramFiles(coreLambdaStubs)
+        .compile()
+        .inspect(this::assertCorrect);
   }
 
   @Test
   public void testDesugaredLibraryContentWithCoreLambdaStubsAsLibrary() throws Exception {
     Assume.assumeTrue(requiresAnyCoreLibDesugaring(parameters));
-    TestDiagnosticMessagesImpl diagnosticsHandler = new TestDiagnosticMessagesImpl();
-    Path desugaredLib = temp.newFolder().toPath().resolve("desugar_jdk_libs_dex.zip");
-    L8Command.Builder l8Builder =
-        L8Command.builder(diagnosticsHandler)
-            .addLibraryFiles(getLibraryFile())
-            .addProgramFiles(ToolHelper.getDesugarJDKLibs())
-            .addProgramFiles(ToolHelper.DESUGAR_LIB_CONVERSIONS)
-            .addLibraryFiles(ToolHelper.getCoreLambdaStubs())
-            .addDesugaredLibraryConfiguration(
-                StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
-            .setMinApiLevel(parameters.getApiLevel().getLevel())
-            .setOutput(desugaredLib, OutputMode.DexIndexed);
-    ToolHelper.runL8(l8Builder.build(), options -> {});
-    CodeInspector codeInspector = new CodeInspector(desugaredLib);
-    assertCorrect(codeInspector);
-    if (isJDK11DesugaredLibrary()) {
-      diagnosticsHandler.assertNoErrors();
-      diagnosticsHandler.assertAllWarningsMatch(
-          diagnosticMessage(containsString("Specification conversion")));
-    } else {
-      diagnosticsHandler.assertNoMessages();
-    }
+    testForL8(parameters.getApiLevel())
+        .apply(libraryDesugaringSpecification::configureL8TestBuilder)
+        .addLibraryFiles(ToolHelper.getCoreLambdaStubs())
+        .compile()
+        .inspect(this::assertCorrect)
+        .inspectDiagnosticMessages(
+            diagnosticsHandler -> {
+              if (libraryDesugaringSpecification == JDK8) {
+                diagnosticsHandler.assertNoMessages();
+              } else {
+                diagnosticsHandler.assertNoErrors();
+                diagnosticsHandler.assertAllWarningsMatch(
+                    diagnosticMessage(containsString("Specification conversion")));
+              }
+            });
   }
 
   private void assertCorrect(CodeInspector inspector) {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryDeterminismTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryDeterminismTest.java
index bc0be98..810f1d0 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryDeterminismTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryDeterminismTest.java
@@ -3,15 +3,20 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.desugar.desugaredlibrary;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.DeterminismChecker;
 import com.android.tools.r8.utils.InternalOptions;
+import com.google.common.collect.ImmutableList;
 import java.nio.file.Path;
+import java.util.List;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Consumer;
@@ -19,18 +24,30 @@
 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 DesugaredLibraryDeterminismTest extends DesugaredLibraryTestBase {
-  private final TestParameters parameters;
 
-  @Parameterized.Parameters(name = "{0}")
-  public static TestParametersCollection data() {
-    return getTestParameters().withDexRuntimes().build();
+  private final TestParameters parameters;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+
+  @Parameters(name = "{0}, spec: {1}, {2}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+        getJdk8Jdk11(),
+        ImmutableList.of(D8_L8DEBUG));
   }
 
-  public DesugaredLibraryDeterminismTest(TestParameters parameters) {
+  public DesugaredLibraryDeterminismTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   private void setDeterminismChecks(
@@ -44,23 +61,34 @@
     Set<String> contextsRoundOne = ConcurrentHashMap.newKeySet();
     Set<String> contextsRoundTwo = ConcurrentHashMap.newKeySet();
     Path determinismLogDir = temp.newFolder().toPath();
-    AndroidApiLevel minApiLevel = parameters.getRuntime().asDex().getMinApiLevel();
-    Assume.assumeTrue(minApiLevel.isLessThan(AndroidApiLevel.O));
+    Assume.assumeTrue(
+        requiresAnyCoreLibDesugaring(
+            parameters.getApiLevel(), libraryDesugaringSpecification != JDK8));
+
     Path libDexFile1 =
-        buildDesugaredLibrary(
-            minApiLevel, o -> setDeterminismChecks(o, determinismLogDir, contextsRoundOne::add));
+        testForL8(parameters.getApiLevel())
+            .apply(libraryDesugaringSpecification::configureL8TestBuilder)
+            .addOptionsModifier(
+                o -> setDeterminismChecks(o, determinismLogDir, contextsRoundOne::add))
+            .compile()
+            .writeToZip();
     Path libDexFile2 =
-        buildDesugaredLibrary(
-            minApiLevel,
-            o ->
-                setDeterminismChecks(
-                    o,
-                    determinismLogDir,
-                    context -> {
-                      assertTrue(
-                          "Did not find context: " + context, contextsRoundOne.contains(context));
-                      contextsRoundTwo.add(context);
-                    }));
+        testForL8(parameters.getApiLevel())
+            .apply(libraryDesugaringSpecification::configureL8TestBuilder)
+            .addOptionsModifier(
+                o ->
+                    setDeterminismChecks(
+                        o,
+                        determinismLogDir,
+                        context -> {
+                          assertTrue(
+                              "Did not find context: " + context,
+                              contextsRoundOne.contains(context));
+                          contextsRoundTwo.add(context);
+                        }))
+            .compile()
+            .writeToZip();
+
     assertEquals(contextsRoundOne, contextsRoundTwo);
     uploadJarsToCloudStorageIfTestFails(
         (file1, file2) -> {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryDumpInputsTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryDumpInputsTest.java
index 92e689b..46743c8 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryDumpInputsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryDumpInputsTest.java
@@ -3,15 +3,18 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.desugar.desugaredlibrary;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import com.android.tools.r8.DiagnosticsMatcher;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.ZipUtils;
-import com.google.common.collect.ImmutableList;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -22,78 +25,47 @@
 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 DesugaredLibraryDumpInputsTest extends DesugaredLibraryTestBase {
 
   private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
 
-  @Parameterized.Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+        getJdk8Jdk11(),
+        DEFAULT_SPECIFICATIONS);
   }
 
-  public DesugaredLibraryDumpInputsTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+  public DesugaredLibraryDumpInputsTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   @Test
-  public void testD8DumpToDirectory() throws Exception {
+  public void testDumpToDirectory() throws Exception {
     Assume.assumeTrue(requiresAnyCoreLibDesugaring(parameters));
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     Path dumpDir = temp.newFolder().toPath();
-    testForD8(parameters.getBackend())
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
         .addProgramClasses(TestClass.class)
-        .addLibraryFiles(getLibraryFile())
-        .setMinApi(parameters.getApiLevel())
-        .addOptionsModification(options -> options.dumpInputToDirectory = dumpDir.toString())
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-        .compile()
-        .addDesugaredCoreLibraryRunClassPath(
-            (minAPILevel, keepRules, shrink) ->
-                this.buildDesugaredLibrary(
-                    minAPILevel,
-                    keepRules,
-                    shrink,
-                    ImmutableList.of(),
-                    opt -> opt.dumpInputToDirectory = dumpDir.toString()),
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
-        .run(parameters.getRuntime(), TestClass.class)
-        .assertSuccessWithOutputLines("PT42S");
-    verifyDumpDir(dumpDir);
-  }
-
-  @Test
-  public void testR8DumpToDirectory() throws Exception {
-    Assume.assumeTrue(requiresAnyCoreLibDesugaring(parameters));
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    Path dumpDir = temp.newFolder().toPath();
-    testForR8(parameters.getBackend())
-        .addProgramClasses(TestClass.class)
-        .addLibraryFiles(getLibraryFile())
-        .setMinApi(parameters.getApiLevel())
         .addKeepMainRule(TestClass.class)
         .addOptionsModification(options -> options.dumpInputToDirectory = dumpDir.toString())
         .allowDiagnosticInfoMessages()
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
         .compile()
-        .addDesugaredCoreLibraryRunClassPath(
-            (minAPILevel, keepRules, shrink) ->
-                this.buildDesugaredLibrary(
-                    minAPILevel,
-                    keepRules,
-                    shrink,
-                    ImmutableList.of(),
-                    opt -> opt.dumpInputToDirectory = dumpDir.toString()),
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
-        .assertAllInfoMessagesMatch(containsString("Dumped compilation inputs to:"))
+        .inspectDiagnosticMessages(
+            diagnosticMessages ->
+                diagnosticMessages.assertAllInfosMatch(
+                    DiagnosticsMatcher.diagnosticMessage(
+                        containsString("Dumped compilation inputs to:"))))
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutputLines("PT42S");
     verifyDumpDir(dumpDir);
@@ -102,7 +74,7 @@
   private void verifyDumpDir(Path dumpDir) throws IOException {
     assertTrue(Files.isDirectory(dumpDir));
     List<Path> paths = Files.walk(dumpDir, 1).collect(Collectors.toList());
-    assertEquals(3, paths.size());
+    assertEquals(2, paths.size());
     boolean hasVerified = false;
     for (Path path : paths) {
       if (!path.equals(dumpDir)) {
@@ -128,7 +100,7 @@
     assertTrue(buildProperties.get(0).startsWith("tool="));
     boolean isD8 = buildProperties.get(0).equals("tool=D8");
     boolean isR8 = buildProperties.get(0).equals("tool=R8");
-    if ((shrinkDesugaredLibrary || isR8) && !isD8) {
+    if ((compilationSpecification.isL8Shrink() || isR8) && !isD8) {
       assertTrue(Files.exists(unzipped.resolve("proguard.config")));
     } else {
       assertFalse(Files.exists(unzipped.resolve("proguard.config")));
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryMismatchTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryMismatchTest.java
index 6ade9c9..91fa3d5 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryMismatchTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryMismatchTest.java
@@ -6,6 +6,9 @@
 
 import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
 import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 import static org.hamcrest.CoreMatchers.allOf;
 import static org.hamcrest.CoreMatchers.containsString;
 
@@ -13,13 +16,16 @@
 import com.android.tools.r8.LibraryDesugaringTestConfiguration;
 import com.android.tools.r8.StringResource;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.errors.DesugaredLibraryMismatchDiagnostic;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
 import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.Box;
+import com.google.common.collect.ImmutableList;
 import java.nio.file.Path;
-import java.util.Collection;
+import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -29,20 +35,30 @@
 public class DesugaredLibraryMismatchTest extends DesugaredLibraryTestBase {
 
   private final TestParameters parameters;
-  private final AndroidApiLevel apiLevel;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
 
-  @Parameters(name = "API level: {1}")
-  public static Collection<Object[]> data() {
+  @Parameters(name = "{0}, spec: {1}, {2}")
+  public static List<Object[]> data() {
     return buildParameters(
-        getTestParameters().withNoneRuntime().build(),
-        new AndroidApiLevel[] {
-          AndroidApiLevel.LATEST, AndroidApiLevel.O, AndroidApiLevel.N_MR1, AndroidApiLevel.B
-        });
+        getTestParameters()
+            .withDexRuntime(Version.first())
+            .withDexRuntime(Version.V7_0_0)
+            .withDexRuntime(Version.V8_1_0)
+            .withDexRuntime(Version.last())
+            .withOnlyDexRuntimeApiLevel()
+            .build(),
+        getJdk8Jdk11(),
+        ImmutableList.of(D8_L8DEBUG));
   }
 
-  public DesugaredLibraryMismatchTest(TestParameters parameters, AndroidApiLevel apiLevel) {
+  public DesugaredLibraryMismatchTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
-    this.apiLevel = apiLevel;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   @Test
@@ -51,21 +67,19 @@
     Path libraryDex =
         testForD8(Backend.DEX)
             .addProgramClasses(Library.class)
-            .setMinApi(apiLevel)
+            .setMinApi(parameters.getApiLevel())
             .compile()
             .writeToZip();
 
     // Combine DEX input without library desugaring with dexing with library desugaring.
     try {
-      testForD8()
-          .addLibraryFiles(getLibraryFile())
+      testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
           .addProgramFiles(libraryDex)
           .addProgramClasses(TestRunner.class)
-          .setMinApi(apiLevel)
-          .enableCoreLibraryDesugaring(LibraryDesugaringTestConfiguration.forApiLevel(apiLevel))
           .compileWithExpectedDiagnostics(
               diagnostics -> {
-                if (requiresAnyCoreLibDesugaring(apiLevel)) {
+                if (requiresAnyCoreLibDesugaring(
+                    parameters.getApiLevel(), libraryDesugaringSpecification != JDK8)) {
                   diagnostics.assertNoInfos();
                   diagnostics.assertAllWarningsMatch(
                       diagnosticMessage(
@@ -89,17 +103,14 @@
     Path desugaredLibrary =
         testForD8(Backend.CF)
             .addProgramClasses(Library.class)
-            .setMinApi(apiLevel)
+            .setMinApi(parameters.getApiLevel())
             .compile()
             .writeToZip();
 
     // Combine CF desugared input without library desugaring with dexing with library desugaring.
-    testForD8()
-        .addLibraryFiles(getLibraryFile())
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
         .addProgramFiles(desugaredLibrary)
         .addProgramClasses(TestRunner.class)
-        .setMinApi(apiLevel)
-        .enableCoreLibraryDesugaring(LibraryDesugaringTestConfiguration.forApiLevel(apiLevel))
         .compile();
   }
 
@@ -109,7 +120,7 @@
     Path desugaredLibrary =
         testForD8(Backend.CF)
             .addProgramClasses(Library.class)
-            .setMinApi(apiLevel)
+            .setMinApi(parameters.getApiLevel())
             .compile()
             .writeToZip();
 
@@ -117,17 +128,14 @@
     Path desugaredLibraryDex =
         testForD8(Backend.DEX)
             .addProgramFiles(desugaredLibrary)
-            .setMinApi(apiLevel)
+            .setMinApi(parameters.getApiLevel())
             .disableDesugaring()
             .compile()
             .writeToZip();
 
-    testForD8()
-        .addLibraryFiles(getLibraryFile())
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
         .addProgramFiles(desugaredLibraryDex)
         .addProgramClasses(TestRunner.class)
-        .setMinApi(apiLevel)
-        .enableCoreLibraryDesugaring(LibraryDesugaringTestConfiguration.forApiLevel(apiLevel))
         .compile();
   }
 
@@ -137,8 +145,9 @@
     Path desugaredLibrary =
         testForD8(Backend.CF)
             .addProgramClasses(Library.class)
-            .setMinApi(apiLevel)
-            .enableCoreLibraryDesugaring(LibraryDesugaringTestConfiguration.forApiLevel(apiLevel))
+            .setMinApi(parameters.getApiLevel())
+            .enableCoreLibraryDesugaring(
+                LibraryDesugaringTestConfiguration.forApiLevel(parameters.getApiLevel()))
             .compile()
             .writeToZip();
 
@@ -147,10 +156,10 @@
       testForD8()
           .addProgramFiles(desugaredLibrary)
           .addProgramClasses(TestRunner.class)
-          .setMinApi(apiLevel)
+          .setMinApi(parameters.getApiLevel())
           .compileWithExpectedDiagnostics(
               diagnostics -> {
-                if (requiresAnyCoreLibDesugaring(apiLevel)) {
+                if (requiresAnyCoreLibDesugaring(parameters.getApiLevel())) {
                   diagnostics.assertOnlyErrors();
                   diagnostics.assertErrorsMatch(
                       diagnosticType(DesugaredLibraryMismatchDiagnostic.class));
@@ -166,11 +175,9 @@
   public void testMergeLibraryDesugaredWithNotLibraryDesugared() throws Exception {
     // DEX code with library desugaring.
     Path libraryDex =
-        testForD8(Backend.DEX)
-            .addLibraryFiles(getLibraryFile())
+        testForDesugaredLibrary(
+                parameters, libraryDesugaringSpecification, compilationSpecification)
             .addProgramClasses(Library.class)
-            .setMinApi(apiLevel)
-            .enableCoreLibraryDesugaring(LibraryDesugaringTestConfiguration.forApiLevel(apiLevel))
             .compile()
             .writeToZip();
 
@@ -178,7 +185,7 @@
     Path programDex =
         testForD8(Backend.DEX)
             .addProgramClasses(TestRunner.class)
-            .setMinApi(apiLevel)
+            .setMinApi(parameters.getApiLevel())
             .compile()
             .writeToZip();
 
@@ -186,10 +193,11 @@
       testForD8()
           .addProgramFiles(libraryDex)
           .addProgramFiles(programDex)
-          .setMinApi(apiLevel)
+          .setMinApi(parameters.getApiLevel())
           .compileWithExpectedDiagnostics(
               diagnostics -> {
-                if (requiresAnyCoreLibDesugaring(apiLevel)) {
+                if (requiresAnyCoreLibDesugaring(
+                    parameters.getApiLevel(), libraryDesugaringSpecification != JDK8)) {
                   diagnostics.assertOnlyErrors();
                   diagnostics.assertErrorsMatch(
                       diagnosticType(DesugaredLibraryMismatchDiagnostic.class));
@@ -209,10 +217,10 @@
     Path libraryDex =
         testForD8(Backend.DEX)
             .addProgramClasses(Library.class)
-            .setMinApi(apiLevel)
+            .setMinApi(parameters.getApiLevel())
             .enableCoreLibraryDesugaring(
                 LibraryDesugaringTestConfiguration.builder()
-                    .setMinApi(apiLevel)
+                    .setMinApi(parameters.getApiLevel())
                     // Minimal configuration with a different identifier.
                     // The j$.time is rewritten because empty flags are equivalent to an empty
                     // specification, and no marker is set for empty specifications.
@@ -241,7 +249,7 @@
     Path programDex =
         testForD8(Backend.DEX)
             .addProgramClasses(TestRunner.class)
-            .setMinApi(apiLevel)
+            .setMinApi(parameters.getApiLevel())
             .compile()
             .writeToZip();
 
@@ -249,7 +257,7 @@
       testForD8()
           .addProgramFiles(libraryDex)
           .addProgramFiles(programDex)
-          .setMinApi(apiLevel)
+          .setMinApi(parameters.getApiLevel())
           .compileWithExpectedDiagnostics(
               diagnostics -> {
                 diagnostics.assertOnlyErrors();
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 9bac396..6024ccb 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
@@ -107,20 +107,26 @@
     return parameters.getApiLevel().isLessThan(apiLevelWithDefaultInterfaceMethodsSupport());
   }
 
-  protected boolean requiresTimeDesugaring(TestParameters parameters) {
+  protected boolean requiresTimeDesugaring(TestParameters parameters, boolean isJDK11) {
     return parameters.getApiLevel().getLevel()
-        < (isJDK11DesugaredLibrary() ? AndroidApiLevel.S.getLevel() : AndroidApiLevel.O.getLevel());
+        < (isJDK11 ? AndroidApiLevel.S.getLevel() : AndroidApiLevel.O.getLevel());
+  }
+
+  protected boolean requiresTimeDesugaring(TestParameters parameters) {
+    return requiresTimeDesugaring(parameters, isJDK11DesugaredLibrary());
   }
 
   protected boolean requiresAnyCoreLibDesugaring(TestParameters parameters) {
     return requiresAnyCoreLibDesugaring(parameters.getApiLevel());
   }
 
-  protected boolean requiresAnyCoreLibDesugaring(AndroidApiLevel apiLevel) {
+  protected boolean requiresAnyCoreLibDesugaring(AndroidApiLevel apiLevel, boolean isJDK11) {
     return apiLevel.getLevel()
-        <= (isJDK11DesugaredLibrary()
-            ? AndroidApiLevel.Sv2.getLevel()
-            : AndroidApiLevel.N_MR1.getLevel());
+        <= (isJDK11 ? AndroidApiLevel.Sv2.getLevel() : AndroidApiLevel.N_MR1.getLevel());
+  }
+
+  protected boolean requiresAnyCoreLibDesugaring(AndroidApiLevel apiLevel) {
+    return requiresAnyCoreLibDesugaring(apiLevel, isJDK11DesugaredLibrary());
   }
 
   protected DesugaredLibraryTestBuilder<?> testForDesugaredLibrary(
@@ -223,7 +229,7 @@
     }
   }
 
-  protected static Path[] getAllFilesWithSuffixInDirectory(Path directory, String suffix)
+  public static Path[] getAllFilesWithSuffixInDirectory(Path directory, String suffix)
       throws IOException {
     return Files.walk(directory)
         .filter(path -> path.toString().endsWith(suffix))
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 1a7981a..2bd0f31 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
@@ -5,23 +5,21 @@
 package com.android.tools.r8.desugar.desugaredlibrary;
 
 import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8SHRINK;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 import static org.hamcrest.core.StringContains.containsString;
 
-import com.android.tools.r8.CompilationMode;
-import com.android.tools.r8.L8Command;
-import com.android.tools.r8.OutputMode;
-import com.android.tools.r8.StringResource;
-import com.android.tools.r8.TestDiagnosticMessagesImpl;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.utils.BooleanUtils;
-import java.nio.file.Path;
-import java.util.Arrays;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
+import com.google.common.collect.ImmutableList;
 import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class DesugaredLibraryWarningTest extends DesugaredLibraryTestBase {
@@ -36,44 +34,44 @@
           + "-keep class j$.util.function.Function { *; }";
 
   private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
 
-  @Parameterized.Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+        getJdk8Jdk11(),
+        ImmutableList.of(D8_L8DEBUG, D8_L8SHRINK));
   }
 
-  public DesugaredLibraryWarningTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+  public DesugaredLibraryWarningTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   @Test
   public void testDesugaredLibraryContent() throws Exception {
-    TestDiagnosticMessagesImpl diagnosticsHandler = new TestDiagnosticMessagesImpl();
-    Path desugaredLib = temp.newFolder().toPath().resolve("desugar_jdk_libs_dex.zip");
-    L8Command.Builder l8Builder =
-        L8Command.builder(diagnosticsHandler)
-            .addLibraryFiles(getLibraryFile())
-            .addProgramFiles(ToolHelper.getDesugarJDKLibs())
-            .addProgramFiles(ToolHelper.DESUGAR_LIB_CONVERSIONS)
-            .setMode(shrinkDesugaredLibrary ? CompilationMode.RELEASE : CompilationMode.DEBUG)
-            .addDesugaredLibraryConfiguration(
-                StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
-            .setMinApiLevel(parameters.getApiLevel().getLevel())
-            .setOutput(desugaredLib, OutputMode.DexIndexed);
-    if (shrinkDesugaredLibrary) {
-      l8Builder.addProguardConfiguration(
-          Arrays.asList(FUNCTION_KEEP.split(System.lineSeparator())), Origin.unknown());
-    }
-    ToolHelper.runL8(l8Builder.build(), options -> {});
-    if (isJDK11DesugaredLibrary()) {
-      diagnosticsHandler.assertNoErrors();
-      diagnosticsHandler.assertAllWarningsMatch(
-          diagnosticMessage(containsString("Specification conversion")));
-    } else {
-      diagnosticsHandler.assertNoMessages();
-    }
+    testForL8(parameters.getApiLevel())
+        .apply(
+            l8TestBuilder ->
+                libraryDesugaringSpecification.configureL8TestBuilder(
+                    l8TestBuilder, compilationSpecification.isL8Shrink(), FUNCTION_KEEP))
+        .compile()
+        .inspectDiagnosticMessages(
+            diagnosticsHandler -> {
+              if (libraryDesugaringSpecification != JDK8) {
+                diagnosticsHandler.assertNoErrors();
+                diagnosticsHandler.assertAllWarningsMatch(
+                    diagnosticMessage(containsString("Specification conversion")));
+              } else {
+
+                diagnosticsHandler.assertNoMessages();
+              }
+            });
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLocalDateReflectedTypePassedToStaticType.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLocalDateReflectedTypePassedToStaticType.java
index 1245c7e..2505e7f 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLocalDateReflectedTypePassedToStaticType.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLocalDateReflectedTypePassedToStaticType.java
@@ -4,12 +4,15 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 import static org.hamcrest.core.StringContains.containsString;
 
-import com.android.tools.r8.D8TestRunResult;
-import com.android.tools.r8.R8TestRunResult;
+import com.android.tools.r8.SingleTestRunResult;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.StringUtils;
 import java.time.LocalDate;
 import java.util.List;
@@ -21,69 +24,42 @@
 @RunWith(Parameterized.class)
 public class DesugaredLocalDateReflectedTypePassedToStaticType extends DesugaredLibraryTestBase {
 
-  private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
   private static final String EXPECTED = StringUtils.lines("1992");
 
-  @Parameters(name = "{0}, shrinkDesugaredLibrary: {1}")
+  private final TestParameters parameters;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        getTestParameters().withDexRuntimes().withAllApiLevels().build(), BooleanUtils.values());
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+        getJdk8Jdk11(),
+        DEFAULT_SPECIFICATIONS);
   }
 
   public DesugaredLocalDateReflectedTypePassedToStaticType(
-      TestParameters parameters, boolean shrinkDesugaredLibrary) {
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   @Test
-  public void testD8() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    D8TestRunResult runResult =
-        testForD8()
-            .addLibraryFiles(getLibraryFile())
-            .addInnerClasses(DesugaredLocalDateReflectedTypePassedToStaticType.class)
-            .setMinApi(parameters.getApiLevel())
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-            .setIncludeClassesChecksum(true)
-            .compile()
-            .addDesugaredCoreLibraryRunClassPath(
-                this::buildDesugaredLibrary,
-                parameters.getApiLevel(),
-                keepRuleConsumer.get(),
-                shrinkDesugaredLibrary)
-            .run(parameters.getRuntime(), Main.class);
-    if (shrinkDesugaredLibrary && requiresTimeDesugaring(parameters)) {
-      runResult.assertFailureWithErrorThatMatches(
-          containsString("java.lang.NoSuchMethodException"));
-    } else {
-      runResult.assertSuccessWithOutput(EXPECTED);
-    }
-  }
-
-  @Test
-  public void testR8() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    R8TestRunResult runResult =
-        testForR8(parameters.getBackend())
-            .addLibraryFiles(getLibraryFile())
+  public void testDate() throws Exception {
+    SingleTestRunResult<?> run =
+        testForDesugaredLibrary(
+                parameters, libraryDesugaringSpecification, compilationSpecification)
             .addInnerClasses(DesugaredLocalDateReflectedTypePassedToStaticType.class)
             .addKeepMainRule(Main.class)
-            .setMinApi(parameters.getApiLevel())
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-            .compile()
-            .addDesugaredCoreLibraryRunClassPath(
-                this::buildDesugaredLibrary,
-                parameters.getApiLevel(),
-                keepRuleConsumer.get(),
-                shrinkDesugaredLibrary)
             .run(parameters.getRuntime(), Main.class);
-    if (shrinkDesugaredLibrary && requiresTimeDesugaring(parameters)) {
-      runResult.assertFailureWithErrorThatMatches(
-          containsString("java.lang.NoSuchMethodException"));
+    if (compilationSpecification.isL8Shrink()
+        && requiresTimeDesugaring(parameters, libraryDesugaringSpecification != JDK8)) {
+      run.assertFailureWithErrorThatMatches(containsString("java.lang.NoSuchMethodException"));
     } else {
-      runResult.assertSuccessWithOutput(EXPECTED);
+      run.assertSuccessWithOutput(EXPECTED);
     }
   }
 
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLocalDateReflectionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLocalDateReflectionTest.java
index ebc0f68..43dc91b 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLocalDateReflectionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLocalDateReflectionTest.java
@@ -4,13 +4,15 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 import static org.hamcrest.core.StringContains.containsString;
 
-import com.android.tools.r8.D8TestRunResult;
-import com.android.tools.r8.R8TestRunResult;
+import com.android.tools.r8.SingleTestRunResult;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.ToolHelper.DexVm;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.StringUtils;
 import java.util.List;
 import org.junit.Test;
@@ -21,63 +23,36 @@
 @RunWith(Parameterized.class)
 public class DesugaredLocalDateReflectionTest extends DesugaredLibraryTestBase {
 
-  private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
   private static final String EXPECTED = StringUtils.lines("1992");
 
-  @Parameters(name = "{0}, shrinkDesugaredLibrary: {1}")
+  private final TestParameters parameters;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        getTestParameters().withDexRuntimes().withAllApiLevels().build(), BooleanUtils.values());
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+        getJdk8Jdk11(),
+        DEFAULT_SPECIFICATIONS);
   }
 
   public DesugaredLocalDateReflectionTest(
-      TestParameters parameters, boolean shrinkDesugaredLibrary) {
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   @Test
-  public void testD8() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    D8TestRunResult runResult =
-        testForD8()
-            .addLibraryFiles(getLibraryFile())
-            .addInnerClasses(DesugaredLocalDateReflectionTest.class)
-            .setMinApi(parameters.getApiLevel())
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-            .setIncludeClassesChecksum(true)
-            .compile()
-            .addDesugaredCoreLibraryRunClassPath(
-                this::buildDesugaredLibrary,
-                parameters.getApiLevel(),
-                keepRuleConsumer.get(),
-                shrinkDesugaredLibrary)
-            .run(parameters.getRuntime(), Main.class);
-    if (parameters.getRuntime().asDex().getVm().isNewerThan(DexVm.ART_7_0_0_HOST)) {
-      runResult.assertSuccessWithOutput(EXPECTED);
-    } else {
-      runResult.assertFailureWithErrorThatMatches(
-          containsString("java.lang.ClassNotFoundException: java.time.LocalDate"));
-    }
-  }
-
-  @Test
-  public void testR8() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    R8TestRunResult runResult =
-        testForR8(parameters.getBackend())
-            .addLibraryFiles(getLibraryFile())
-            .addInnerClasses(DesugaredLocalDateReflectionTest.class)
+  public void testDate() throws Exception {
+    SingleTestRunResult<?> runResult =
+        testForDesugaredLibrary(
+                parameters, libraryDesugaringSpecification, compilationSpecification)
+            .addInnerClasses(getClass())
             .addKeepMainRule(Main.class)
-            .setMinApi(parameters.getApiLevel())
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-            .compile()
-            .addDesugaredCoreLibraryRunClassPath(
-                this::buildDesugaredLibrary,
-                parameters.getApiLevel(),
-                keepRuleConsumer.get(),
-                shrinkDesugaredLibrary)
             .run(parameters.getRuntime(), Main.class);
     if (parameters.getRuntime().asDex().getVm().isNewerThan(DexVm.ART_7_0_0_HOST)) {
       runResult.assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredReflectedDesugaredTypePassedToStaticTypeTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredReflectedDesugaredTypePassedToStaticTypeTest.java
index 139103d..6c1f23f 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredReflectedDesugaredTypePassedToStaticTypeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredReflectedDesugaredTypePassedToStaticTypeTest.java
@@ -4,12 +4,15 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 import static org.hamcrest.core.StringContains.containsString;
 
-import com.android.tools.r8.D8TestRunResult;
-import com.android.tools.r8.R8TestRunResult;
+import com.android.tools.r8.SingleTestRunResult;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.StringUtils;
 import java.time.LocalDate;
 import java.util.List;
@@ -22,65 +25,37 @@
 public class DesugaredReflectedDesugaredTypePassedToStaticTypeTest
     extends DesugaredLibraryTestBase {
 
-  private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
   private static final String EXPECTED = StringUtils.lines("1992", "1992");
+  private final TestParameters parameters;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
 
-  @Parameters(name = "{0}, shrinkDesugaredLibrary: {1}")
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        getTestParameters().withDexRuntimes().withAllApiLevels().build(), BooleanUtils.values());
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+        getJdk8Jdk11(),
+        DEFAULT_SPECIFICATIONS);
   }
 
   public DesugaredReflectedDesugaredTypePassedToStaticTypeTest(
-      TestParameters parameters, boolean shrinkDesugaredLibrary) {
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   @Test
-  public void testD8() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    D8TestRunResult runResult =
-        testForD8()
-            .addLibraryFiles(getLibraryFile())
-            .addInnerClasses(DesugaredReflectedDesugaredTypePassedToStaticTypeTest.class)
-            .setMinApi(parameters.getApiLevel())
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-            .setIncludeClassesChecksum(true)
-            .compile()
-            .addDesugaredCoreLibraryRunClassPath(
-                this::buildDesugaredLibrary,
-                parameters.getApiLevel(),
-                keepRuleConsumer.get(),
-                shrinkDesugaredLibrary)
-            .run(parameters.getRuntime(), Main.class);
-    if (!requiresTimeDesugaring(parameters)) {
-      runResult.assertFailureWithErrorThatMatches(
-          containsString("java.lang.ClassNotFoundException: j$.time.LocalDate"));
-    } else {
-      runResult.assertSuccessWithOutput(EXPECTED);
-    }
-  }
-
-  @Test
-  public void testR8() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    R8TestRunResult runResult =
-        testForR8(parameters.getBackend())
-            .addLibraryFiles(getLibraryFile())
-            .addInnerClasses(DesugaredReflectedDesugaredTypePassedToStaticTypeTest.class)
+  public void testDate() throws Exception {
+    SingleTestRunResult<?> runResult =
+        testForDesugaredLibrary(
+                parameters, libraryDesugaringSpecification, compilationSpecification)
+            .addInnerClasses(getClass())
             .addKeepMainRule(Main.class)
-            .setMinApi(parameters.getApiLevel())
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-            .compile()
-            .addDesugaredCoreLibraryRunClassPath(
-                this::buildDesugaredLibrary,
-                parameters.getApiLevel(),
-                keepRuleConsumer.get(),
-                shrinkDesugaredLibrary)
             .run(parameters.getRuntime(), Main.class);
-    if (!requiresTimeDesugaring(parameters)) {
+    if (!requiresTimeDesugaring(parameters, libraryDesugaringSpecification != JDK8)) {
       runResult.assertFailureWithErrorThatMatches(
           containsString("java.lang.ClassNotFoundException: j$.time.LocalDate"));
     } else {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DisableDesugarTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DisableDesugarTest.java
index f686167..7fecd40 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DisableDesugarTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DisableDesugarTest.java
@@ -4,16 +4,18 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.fail;
 
 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.TestParametersCollection;
-import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
+import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -23,14 +25,39 @@
 public class DisableDesugarTest extends DesugaredLibraryTestBase {
 
   private final TestParameters parameters;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
 
-  @Parameters(name = "{0}")
-  public static TestParametersCollection data() {
-    return getTestParameters().withDexRuntimes().withAllApiLevels().build();
+  @Parameters(name = "{0}, spec: {1}, {2}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+        getJdk8Jdk11(),
+        DEFAULT_SPECIFICATIONS);
   }
 
-  public DisableDesugarTest(TestParameters parameters) {
+  public DisableDesugarTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+  }
+
+  @Test
+  public void testDisableDesugar() throws Exception {
+    try {
+      testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+          .addInnerClasses(getClass())
+          .addKeepMainRule(TestClass.class)
+          .disableDesugaring()
+          .compileWithExpectedDiagnostics(this::checkExpectedDiagnostics);
+    } catch (CompilationFailedException e) {
+      // Expected compilation failed.
+      return;
+    }
+    fail("Expected test to fail with CompilationFailedException");
   }
 
   private void checkExpectedDiagnostics(TestDiagnosticMessages messages) {
@@ -42,41 +69,6 @@
         containsString("Using desugared library configuration requires desugaring to be enabled"));
   }
 
-  @Test
-  public void testDisableDesugarD8() throws Exception {
-    try {
-      testForD8()
-          .addInnerClasses(DisableDesugarTest.class)
-          .setMinApi(parameters.getApiLevel())
-          .disableDesugaring()
-          .enableCoreLibraryDesugaring(
-              LibraryDesugaringTestConfiguration.forApiLevel(AndroidApiLevel.B))
-          .compileWithExpectedDiagnostics(this::checkExpectedDiagnostics);
-    } catch (CompilationFailedException e) {
-      // Expected compilation failed.
-      return;
-    }
-    fail("Expected test to fail with CompilationFailedException");
-  }
-
-  @Test
-  public void testDisableDesugarR8() throws Exception {
-    try {
-      testForR8(parameters.getBackend())
-          .addInnerClasses(DisableDesugarTest.class)
-          .addKeepMainRule(TestClass.class)
-          .setMinApi(parameters.getApiLevel())
-          .disableDesugaring()
-          .enableCoreLibraryDesugaring(
-              LibraryDesugaringTestConfiguration.forApiLevel(AndroidApiLevel.B))
-          .compileWithExpectedDiagnostics(this::checkExpectedDiagnostics);
-    } catch (CompilationFailedException e) {
-      // Expected compilation failed.
-      return;
-    }
-    fail("Expected test to fail with CompilationFailedException");
-  }
-
   static class TestClass {
 
     public static void main(String[] args) {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DontKeepBootstrapClassesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DontKeepBootstrapClassesTest.java
index 7e94671..70554a0 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DontKeepBootstrapClassesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DontKeepBootstrapClassesTest.java
@@ -3,49 +3,70 @@
 // 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 static org.hamcrest.MatcherAssert.assertThat;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
+import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.LibraryDesugaringTestConfiguration.PresentKeepRuleConsumer;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CustomLibrarySpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import java.util.Arrays;
+import java.util.List;
 import java.util.function.Consumer;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class DontKeepBootstrapClassesTest extends DesugaredLibraryTestBase {
 
-  @Parameterized.Parameters(name = "{0}")
-  public static TestParametersCollection data() {
-    return getTestParameters().withNoneRuntime().build();
+  private final TestParameters parameters;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+
+  @Parameters(name = "{0}, spec: {1}, {2}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+        getJdk8Jdk11(),
+        DEFAULT_SPECIFICATIONS);
   }
 
-  final AndroidApiLevel minApiLevel = AndroidApiLevel.B;
-
-  public DontKeepBootstrapClassesTest(TestParameters parameters) {
-    parameters.assertNoneRuntime();
+  public DontKeepBootstrapClassesTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
+    this.parameters = parameters;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   @Test
-  public void test() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = new PresentKeepRuleConsumer();
-    testForD8()
-        .addLibraryFiles(getLibraryFile())
+  public void testDontKeep() throws Throwable {
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
         .addProgramClasses(TestClass.class)
-        .setMinApi(minApiLevel)
-        .addLibraryClasses(CustomLibClass.class)
-        .enableCoreLibraryDesugaring(minApiLevel, keepRuleConsumer)
-        .compile();
-    assertThat(keepRuleConsumer.get(), containsString("-keep class j$.util.function.Consumer"));
-    // TODO(b/158635415): Don't generate keep rules targeting items outside desugared library.
-    assertThat(keepRuleConsumer.get(), containsString("-keep class java.util"));
+        .addKeepMainRule(TestClass.class)
+        .setCustomLibrarySpecification(
+            new CustomLibrarySpecification(CustomLibClass.class, AndroidApiLevel.N))
+        .compile()
+        .inspectKeepRules(
+            keepRule -> {
+              if (requiresEmulatedInterfaceCoreLibDesugaring(parameters)) {
+                assertTrue(
+                    keepRule.stream()
+                        .anyMatch(kr -> kr.contains("-keep class j$.util.function.Consumer")));
+                // TODO(b/158635415): Don't generate keep rules targeting items outside desugared
+                // library.
+                assertTrue(keepRule.stream().anyMatch(kr -> kr.contains("-keep class java.util")));
+              }
+            });
   }
 
   static class CustomLibClass {
+
     public static <T> Consumer<T> id(Consumer<T> fn) {
       return fn;
     }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DoubleUtilityClassTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DoubleUtilityClassTest.java
index 89b293f..d366e33 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DoubleUtilityClassTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DoubleUtilityClassTest.java
@@ -4,45 +4,55 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 import static org.hamcrest.core.IsNot.not;
 import static org.hamcrest.core.StringContains.containsString;
 
-import com.android.tools.r8.LibraryDesugaringTestConfiguration;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
 import java.time.zone.ZoneOffsetTransition;
+import java.util.List;
 import java.util.Objects;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
 
 // In this test both the desugared library and the program have the same utility class.
 @RunWith(Parameterized.class)
 public class DoubleUtilityClassTest extends DesugaredLibraryTestBase {
 
   private final TestParameters parameters;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
 
-  @Parameterized.Parameters(name = "{0}")
-  public static TestParametersCollection data() {
-    return getTestParameters().withDexRuntimes().withAllApiLevels().build();
+  @Parameters(name = "{0}, spec: {1}, {2}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+        getJdk8Jdk11(),
+        DEFAULT_SPECIFICATIONS);
   }
 
-  public DoubleUtilityClassTest(TestParameters parameters) {
+  public DoubleUtilityClassTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   @Test
   public void testDoubleUtility() throws Exception {
     for (Class<?> executor : new Class<?>[] {ExecutorV1.class, ExecutorV2.class}) {
-      testForD8()
-          .addLibraryFiles(getLibraryFile())
+      testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
           .addProgramClasses(executor)
-          .enableCoreLibraryDesugaring(
-              LibraryDesugaringTestConfiguration.forApiLevel(parameters.getApiLevel()))
-          .setMinApi(parameters.getApiLevel())
-          .compile()
+          .addKeepMainRule(executor)
           .run(parameters.getRuntime(), executor)
           .assertSuccess()
           // Verification error on some Dalvik VMs (4,api 1;4,api 15;4.4,api 1).
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmptyDesugaredLibrary.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmptyDesugaredLibrary.java
index 874d45a..2e09671 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmptyDesugaredLibrary.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmptyDesugaredLibrary.java
@@ -4,22 +4,24 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.ByteDataView;
 import com.android.tools.r8.DexIndexedConsumer;
 import com.android.tools.r8.DiagnosticsHandler;
-import com.android.tools.r8.L8Command;
-import com.android.tools.r8.OutputMode;
-import com.android.tools.r8.StringResource;
+import com.android.tools.r8.L8TestBuilder;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.AndroidApiLevel;
+import com.google.common.collect.ImmutableList;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 import java.util.zip.ZipFile;
@@ -31,39 +33,30 @@
 @RunWith(Parameterized.class)
 public class EmptyDesugaredLibrary extends DesugaredLibraryTestBase {
 
-  private final AndroidApiLevel apiLevel;
+  private final TestParameters parameters;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
 
-  @Parameters(name = "api: {0}")
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        range(AndroidApiLevel.K, AndroidApiLevel.LATEST),
-        getTestParameters().withNoneRuntime().build());
+        getTestParameters().withDexRuntimes().withOnlyDexRuntimeApiLevel().build(),
+        getJdk8Jdk11(),
+        ImmutableList.of(D8_L8DEBUG));
   }
 
-  private static List<AndroidApiLevel> range(
-      AndroidApiLevel fromIncluding, AndroidApiLevel toIncluding) {
-    ArrayList<AndroidApiLevel> result = new ArrayList<>();
-    for (AndroidApiLevel apiLevel : AndroidApiLevel.values()) {
-      if (apiLevel.isGreaterThanOrEqualTo(fromIncluding)
-          && apiLevel.isLessThanOrEqualTo(toIncluding)) {
-        result.add(apiLevel);
-      }
-    }
-    return result;
+  public EmptyDesugaredLibrary(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
+    this.parameters = parameters;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
-  public EmptyDesugaredLibrary(AndroidApiLevel apiLevel, TestParameters parameters) {
-    parameters.assertNoneRuntime();
-    this.apiLevel = apiLevel;
-  }
-
-  private L8Command.Builder prepareL8Builder(AndroidApiLevel minApiLevel) {
-    return L8Command.builder()
-        .addLibraryFiles(getLibraryFile())
-        .addProgramFiles(ToolHelper.getDesugarJDKLibs())
-        .addDesugaredLibraryConfiguration(
-            StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
-        .setMinApiLevel(minApiLevel.getLevel());
+  private L8TestBuilder prepareL8() {
+    return testForL8(parameters.getApiLevel())
+        .apply(libraryDesugaringSpecification::configureL8TestBuilder);
   }
 
   static class CountingProgramConsumer extends DexIndexedConsumer.ForwardingConsumer {
@@ -82,38 +75,26 @@
   }
 
   private boolean expectsEmptyDesugaredLibrary(AndroidApiLevel apiLevel) {
+    if (libraryDesugaringSpecification != JDK8) {
+      return apiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.S);
+    }
     return !requiresAnyCoreLibDesugaring(apiLevel);
   }
 
   @Test
   public void testEmptyDesugaredLibrary() throws Exception {
     CountingProgramConsumer programConsumer = new CountingProgramConsumer();
-    ToolHelper.runL8(prepareL8Builder(apiLevel).setProgramConsumer(programConsumer).build());
-    assertEquals(expectsEmptyDesugaredLibrary(apiLevel) ? 0 : 1, programConsumer.count);
+    prepareL8().setProgramConsumer(programConsumer).compile();
+    assertEquals(
+        expectsEmptyDesugaredLibrary(parameters.getApiLevel()) ? 0 : 1, programConsumer.count);
   }
 
   @Test
   public void testEmptyDesugaredLibraryDexZip() throws Exception {
-    Path desugaredLibraryZip = temp.newFolder().toPath().resolve("desugar_jdk_libs_dex.zip");
-    ToolHelper.runL8(
-        prepareL8Builder(apiLevel).setOutput(desugaredLibraryZip, OutputMode.DexIndexed).build());
+    Path desugaredLibraryZip = prepareL8().compile().writeToZip();
     assertTrue(Files.exists(desugaredLibraryZip));
     assertEquals(
-        expectsEmptyDesugaredLibrary(apiLevel) ? 0 : 1,
+        expectsEmptyDesugaredLibrary(parameters.getApiLevel()) ? 0 : 1,
         new ZipFile(desugaredLibraryZip.toFile(), StandardCharsets.UTF_8).size());
   }
-
-  @Test
-  public void testEmptyDesugaredLibraryDexDirectory() throws Exception {
-    Path desugaredLibraryDirectory = temp.newFolder().toPath();
-    ToolHelper.runL8(
-        prepareL8Builder(apiLevel)
-            .setOutput(desugaredLibraryDirectory, OutputMode.DexIndexed)
-            .build());
-    assertEquals(
-        expectsEmptyDesugaredLibrary(apiLevel) ? 0 : 1,
-        Files.walk(desugaredLibraryDirectory)
-            .filter(path -> path.toString().endsWith(".dex"))
-            .count());
-  }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmulatedInterfacesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmulatedInterfacesTest.java
index b3d3ddd..1ca61c5 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmulatedInterfacesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmulatedInterfacesTest.java
@@ -4,6 +4,9 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8SHRINK;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 import static com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringForTesting.getEmulateLibraryClassNameSuffix;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static junit.framework.TestCase.assertEquals;
@@ -12,13 +15,15 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.code.Instruction;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
+import com.android.tools.r8.dex.code.DexInstruction;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.google.common.collect.ImmutableList;
 import java.util.List;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
@@ -32,26 +37,37 @@
 public class EmulatedInterfacesTest extends DesugaredLibraryTestBase {
 
   private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
 
-  @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+        getJdk8Jdk11(),
+        ImmutableList.of(D8_L8DEBUG, D8_L8SHRINK));
   }
 
-  public EmulatedInterfacesTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+  public EmulatedInterfacesTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   @Test
   public void testEmulatedInterface() throws Exception {
     Assume.assumeTrue(requiresEmulatedInterfaceCoreLibDesugaring(parameters));
     CodeInspector inspector =
-        new CodeInspector(
-            buildDesugaredLibrary(
-                parameters.getApiLevel(), "-keep class **$-EL", shrinkDesugaredLibrary));
+        testForL8(parameters.getApiLevel())
+            .apply(
+                l8Builder ->
+                    libraryDesugaringSpecification.configureL8TestBuilder(
+                        l8Builder, compilationSpecification.isL8Shrink(), "-keep class **$-EL"))
+            .compile()
+            .inspector();
     assertEmulateInterfaceClassesPresentWithDispatchMethods(inspector);
     assertCollectionMethodsPresentWithCorrectDispatch(inspector);
   }
@@ -85,7 +101,7 @@
       int numCheckCast =
           (int)
               Stream.of(method.getCode().asDexCode().instructions)
-                  .filter(Instruction::isCheckCast)
+                  .filter(DexInstruction::isCheckCast)
                   .count();
       if (method.qualifiedName().contains("spliterator")) {
         assertEquals(5, numCheckCast);
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 0c4d6f6..f0be12b 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
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.desugar.desugaredlibrary;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 import static com.android.tools.r8.utils.DescriptorUtils.descriptorToJavaType;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -11,8 +12,8 @@
 import com.android.tools.r8.GenerateLintFiles;
 import com.android.tools.r8.StringResource;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
@@ -47,6 +48,7 @@
 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 ExtractWrapperTypesTest extends DesugaredLibraryTestBase {
@@ -94,19 +96,23 @@
           // TODO(b/159304624): Does this need custom conversion?
           "java.time.Period");
 
-  @Parameterized.Parameters(name = "{0}")
-  public static TestParametersCollection data() {
-    return getTestParameters().withNoneRuntime().build();
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+
+  @Parameters(name = "{0}, spec: {1}, {2}")
+  public static List<Object[]> data() {
+    return buildParameters(getTestParameters().withNoneRuntime().build(), getJdk8Jdk11());
+  }
+
+  public ExtractWrapperTypesTest(
+      TestParameters parameters, LibraryDesugaringSpecification libraryDesugaringSpecification) {
+    parameters.assertNoneRuntime();
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   // TODO: parameterize to check both api<=23 as well as 23<api<26 for which the spec differs.
   private final AndroidApiLevel minApi = AndroidApiLevel.B;
   private final AndroidApiLevel targetApi = AndroidApiLevel.Q;
 
-  public ExtractWrapperTypesTest(TestParameters parameters) {
-    parameters.assertNoneRuntime();
-  }
-
   @Test
   public void checkConsistency() {
     List<Set<String>> sets =
@@ -134,7 +140,7 @@
     DexItemFactory factory = new DexItemFactory();
     DesugaredLibrarySpecification spec =
         DesugaredLibrarySpecificationParser.parseDesugaredLibrarySpecification(
-            StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()),
+            StringResource.fromFile(libraryDesugaringSpecification.getSpecification()),
             factory,
             null,
             false,
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/FeatureSplitTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/FeatureSplitTest.java
index 88580f5..42ee197 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/FeatureSplitTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/FeatureSplitTest.java
@@ -4,28 +4,32 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.R8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.R8_L8SHRINK;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 import static junit.framework.TestCase.assertEquals;
 import static junit.framework.TestCase.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
-import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestRuntime;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.ArtCommandBuilder;
 import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.DesugaredLibraryTestCompileResult;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.dexsplitter.SplitterTestBase;
 import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableList;
 import dalvik.system.PathClassLoader;
 import java.io.IOException;
 import java.net.MalformedURLException;
 import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.concurrent.ExecutionException;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -35,21 +39,28 @@
 public class FeatureSplitTest extends DesugaredLibraryTestBase {
 
   private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
 
-  @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+        getJdk8Jdk11(),
+        ImmutableList.of(R8_L8DEBUG, R8_L8SHRINK));
   }
 
-  public FeatureSplitTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+  public FeatureSplitTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   @Test
-  public void testTwoFeatures() throws CompilationFailedException, IOException, ExecutionException {
+  public void testTwoFeatures() throws Throwable {
     CompiledWithFeature compiledWithFeature = new CompiledWithFeature().invoke(this);
     Path basePath = compiledWithFeature.getBasePath();
     Path feature1Path = compiledWithFeature.getFeature1Path();
@@ -72,6 +83,9 @@
     if (parameters.getApiLevel().getLevel() >= AndroidApiLevel.N.getLevel()) {
       return;
     }
+    if (!compilationSpecification.isL8Shrink()) {
+      return;
+    }
     // Ensure count, toArray and forEach are kept.
     assertTrue(
         keepRules.contains(
@@ -84,8 +98,7 @@
                 + "    java.lang.Object[] toArray();"));
   }
 
-  private void assertClassPresent(Path appPath, Class<?> present)
-      throws IOException, ExecutionException {
+  private void assertClassPresent(Path appPath, Class<?> present) throws IOException {
     CodeInspector inspector = new CodeInspector(appPath);
     assertTrue(inspector.clazz(present).isPresent());
   }
@@ -227,38 +240,36 @@
       return keepRules;
     }
 
-    public CompiledWithFeature invoke(FeatureSplitTest tester)
-        throws IOException, CompilationFailedException {
+    public CompiledWithFeature invoke(FeatureSplitTest tester) throws Throwable {
 
       basePath = temp.newFile("base.zip").toPath();
       feature1Path = temp.newFile("feature1.zip").toPath();
       feature2Path = temp.newFile("feature2.zip").toPath();
 
-      KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-      testForR8(parameters.getBackend())
-          .addLibraryFiles(getLibraryFile())
-          .addProgramClasses(BaseClass.class, RunInterface.class, SplitRunner.class)
-          .setMinApi(parameters.getApiLevel())
-          .addFeatureSplit(
-              builder ->
-                  SplitterTestBase.simpleSplitProvider(
-                      builder, feature1Path, temp, FeatureClass.class))
-          .addFeatureSplit(
-              builder ->
-                  SplitterTestBase.simpleSplitProvider(
-                      builder, feature2Path, temp, FeatureClass2.class))
-          .addKeepAllClassesRule()
-          .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-          .compile()
-          .writeToZip(basePath);
+      DesugaredLibraryTestCompileResult<?> compileResult =
+          tester
+              .testForDesugaredLibrary(
+                  parameters, libraryDesugaringSpecification, compilationSpecification)
+              .addProgramClasses(BaseClass.class, RunInterface.class, SplitRunner.class)
+              .addFeatureSplit(
+                  builder ->
+                      SplitterTestBase.simpleSplitProvider(
+                          builder, feature1Path, temp, FeatureClass.class))
+              .addFeatureSplit(
+                  builder ->
+                      SplitterTestBase.simpleSplitProvider(
+                          builder, feature2Path, temp, FeatureClass2.class))
+              .addKeepAllClassesRule()
+              .compile()
+              .writeToZip(basePath);
+
       // Stream desugaring is not needed >= N.
       if (parameters.getApiLevel().getLevel() >= AndroidApiLevel.N.getLevel()) {
         return this;
       }
-      desugaredLibrary =
-          tester.buildDesugaredLibrary(
-              parameters.getApiLevel(), keepRuleConsumer.get(), shrinkDesugaredLibrary);
-      keepRules = keepRuleConsumer.get();
+
+      desugaredLibrary = compileResult.writeL8ToZip();
+      compileResult.inspectKeepRules(kr -> keepRules = StringUtils.join("\n", kr));
       return this;
     }
   }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/FreezePeriodTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/FreezePeriodTest.java
index 8a04ae3..4ac3eaa 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/FreezePeriodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/FreezePeriodTest.java
@@ -3,17 +3,18 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.desugar.desugaredlibrary.conversiontests;
 
-import static org.junit.Assert.assertEquals;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.SPECIFICATIONS_WITH_CF2CF;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CustomLibrarySpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
-import java.nio.file.Path;
 import java.time.MonthDay;
 import java.util.List;
-import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -23,7 +24,9 @@
 public class FreezePeriodTest extends DesugaredLibraryTestBase {
 
   private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+  private final CompilationSpecification compilationSpecification;
+
   private static final AndroidApiLevel MIN_SUPPORTED = AndroidApiLevel.O;
   private static final String EXPECTED_RESULT =
       StringUtils.lines(
@@ -31,109 +34,31 @@
           "FP:--05-05;--06-06",
           "FP:--05-05;--06-0601",
           "MFP:--05-05;--06-06");
-  private static Path CUSTOM_LIB;
 
-  @Parameters(name = "{0}, shrinkDesugaredLibrary: {1}")
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        getConversionParametersUpToExcluding(MIN_SUPPORTED), BooleanUtils.values());
+        getConversionParametersUpToExcluding(MIN_SUPPORTED),
+        getJdk8Jdk11(),
+        SPECIFICATIONS_WITH_CF2CF);
   }
 
-  public FreezePeriodTest(TestParameters parameters, boolean shrinkDesugaredLibrary) {
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+  public FreezePeriodTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
-  }
-
-  @BeforeClass
-  public static void compileCustomLib() throws Exception {
-    CUSTOM_LIB =
-        testForD8(getStaticTemp())
-            .addProgramClasses(FreezePeriod.class)
-            .setMinApi(MIN_SUPPORTED)
-            .compile()
-            .writeToZip();
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+    this.compilationSpecification = compilationSpecification;
   }
 
   @Test
-  public void testD8() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForD8()
-        .addLibraryFiles(getLibraryFile())
-        .setMinApi(parameters.getApiLevel())
+  public void testFreezePeriod() throws Exception {
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
         .addProgramClasses(Executor.class, MyFreezePeriod.class)
-        .addLibraryClasses(FreezePeriod.class)
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-        .compile()
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
-        .addRunClasspathFiles(CUSTOM_LIB)
-        .run(parameters.getRuntime(), Executor.class)
-        .assertSuccessWithOutput(EXPECTED_RESULT);
-  }
-
-  @Test
-  public void testD8CfToCf() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    Path jar =
-        testForD8(Backend.CF)
-            .addLibraryFiles(getLibraryFile())
-            .setMinApi(parameters.getApiLevel())
-            .addProgramClasses(Executor.class, MyFreezePeriod.class)
-            .addLibraryClasses(FreezePeriod.class)
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-            .compile()
-            .writeToZip();
-    String desugaredLibraryKeepRules = "";
-    if (shrinkDesugaredLibrary && keepRuleConsumer.get() != null) {
-      // Collection keep rules is only implemented in the DEX writer.
-      assertEquals(0, keepRuleConsumer.get().length());
-      desugaredLibraryKeepRules = "-keep class * { *; }";
-    }
-    if (parameters.getRuntime().isDex()) {
-      testForD8()
-          .addProgramFiles(jar)
-          .setMinApi(parameters.getApiLevel())
-          .disableDesugaring()
-          .compile()
-          .addDesugaredCoreLibraryRunClassPath(
-              this::buildDesugaredLibrary,
-              parameters.getApiLevel(),
-              desugaredLibraryKeepRules,
-              shrinkDesugaredLibrary)
-          .addRunClasspathFiles(CUSTOM_LIB)
-          .run(parameters.getRuntime(), Executor.class)
-          .assertSuccessWithOutput(EXPECTED_RESULT);
-    } else {
-      testForJvm()
-          .addProgramFiles(jar)
-          .addRunClasspathFiles(getDesugaredLibraryInCF(parameters, options -> {}))
-          .addRunClasspathFiles(CUSTOM_LIB)
-          .run(parameters.getRuntime(), Executor.class)
-          .assertSuccessWithOutput(EXPECTED_RESULT);
-    }
-  }
-
-  @Test
-  public void testR8() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForR8(parameters.getBackend())
-        .addLibraryFiles(getLibraryFile())
-        .setMinApi(parameters.getApiLevel())
+        .setCustomLibrarySpecification(
+            new CustomLibrarySpecification(FreezePeriod.class, MIN_SUPPORTED))
         .addKeepMainRule(Executor.class)
-        .addProgramClasses(Executor.class, MyFreezePeriod.class)
-        .addLibraryClasses(FreezePeriod.class)
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-        .allowStdoutMessages()
-        .compile()
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
-        .addRunClasspathFiles(CUSTOM_LIB)
         .run(parameters.getRuntime(), Executor.class)
         .assertSuccessWithOutput(EXPECTED_RESULT);
   }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/FunctionOnlyTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/FunctionOnlyTest.java
index 0b443a8..12ff1ae 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/FunctionOnlyTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/FunctionOnlyTest.java
@@ -4,28 +4,18 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
-import static org.junit.Assert.assertEquals;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.SPECIFICATIONS_WITH_CF2CF;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11_MINIMAL;
 
-import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.CompilationMode;
-import com.android.tools.r8.L8Command;
-import com.android.tools.r8.LibraryDesugaringTestConfiguration;
-import com.android.tools.r8.OutputMode;
-import com.android.tools.r8.StringResource;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser;
-import com.android.tools.r8.utils.BooleanUtils;
-import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.StringUtils;
 import com.google.common.collect.ImmutableList;
-import java.io.IOException;
-import java.nio.file.Path;
 import java.util.List;
 import java.util.function.BiFunction;
 import java.util.function.BinaryOperator;
 import java.util.function.BooleanSupplier;
-import java.util.function.Consumer;
 import java.util.function.DoublePredicate;
 import java.util.function.DoubleSupplier;
 import java.util.function.Function;
@@ -33,7 +23,6 @@
 import java.util.function.LongConsumer;
 import java.util.function.LongSupplier;
 import java.util.function.Supplier;
-import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -42,139 +31,35 @@
 @RunWith(Parameterized.class)
 public class FunctionOnlyTest extends DesugaredLibraryTestBase {
 
-  private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
   private static final String EXPECTED_RESULT =
       StringUtils.lines(" true true true", "2", "false", "3", "true", "5", "42.0");
 
-  @Parameters(name = "{0}, shrinkDesugaredLibrary: {1}")
+  private final TestParameters parameters;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
         getTestParameters().withDexRuntimes().withAllApiLevelsAlsoForCf().build(),
-        BooleanUtils.values());
+        ImmutableList.of(JDK11_MINIMAL),
+        SPECIFICATIONS_WITH_CF2CF);
   }
 
-  public FunctionOnlyTest(TestParameters parameters, boolean shrinkDesugaredLibrary) {
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+  public FunctionOnlyTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   @Test
-  public void testFunctionCompositionD8() throws Exception {
-    testForD8()
-        .addLibraryFiles(getLibraryFile())
-        .setMinApi(parameters.getApiLevel())
+  public void testFunction() throws Exception {
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
         .addInnerClasses(getClass())
-        .enableCoreLibraryDesugaring(minimalConfiguration())
-        .compile()
-        .run(parameters.getRuntime(), Executor.class)
-        .assertSuccessWithOutput(EXPECTED_RESULT);
-  }
-
-  private LibraryDesugaringTestConfiguration minimalConfiguration() {
-    if (!isJDK11DesugaredLibrary()) {
-      return LibraryDesugaringTestConfiguration.builder()
-          .setMinApi(parameters.getApiLevel())
-          .setMode(CompilationMode.RELEASE)
-          .withKeepRuleConsumer()
-          .build();
-    }
-    return LibraryDesugaringTestConfiguration.builder()
-        .setMinApi(parameters.getApiLevel())
-        .addDesugaredLibraryConfiguration(
-            StringResource.fromFile(ToolHelper.getDesugarLibJsonMinimalForTesting()))
-        .setMode(shrinkDesugaredLibrary ? CompilationMode.RELEASE : CompilationMode.DEBUG)
-        .withKeepRuleConsumer()
-        .build();
-  }
-
-  @Test
-  public void testFunctionCompositionD8Cf2Cf() throws Exception {
-    Assume.assumeTrue(isJDK11DesugaredLibrary());
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    Path jar =
-        testForD8(Backend.CF)
-            .addLibraryFiles(getLibraryFile())
-            .setMinApi(parameters.getApiLevel())
-            .addInnerClasses(FunctionOnlyTest.class)
-            .enableCoreLibraryDesugaring(
-                parameters.getApiLevel(),
-                keepRuleConsumer,
-                StringResource.fromFile(ToolHelper.getDesugarLibJsonMinimalForTesting()))
-            .compile()
-            .writeToZip();
-    String desugaredLibraryKeepRules = "";
-    if (shrinkDesugaredLibrary && keepRuleConsumer.get() != null) {
-      // Collection keep rules is only implemented in the DEX writer.
-      assertEquals(0, keepRuleConsumer.get().length());
-      desugaredLibraryKeepRules = "-keep class java.util.function.* { *; }";
-    }
-    if (parameters.getRuntime().isDex()) {
-      testForD8()
-          .addProgramFiles(jar)
-          .setMinApi(parameters.getApiLevel())
-          .disableDesugaring()
-          .compile()
-          .addDesugaredCoreLibraryRunClassPath(
-              (api, keep, shrink) ->
-                  buildDesugaredLibrary(
-                      api,
-                      keep,
-                      shrink,
-                      ImmutableList.of(),
-                      opt ->
-                          opt.setDesugaredLibrarySpecification(
-                              DesugaredLibrarySpecificationParser
-                                  .parseDesugaredLibrarySpecification(
-                                      StringResource.fromFile(
-                                          ToolHelper.getDesugarLibJsonMinimalForTesting()),
-                                      opt.itemFactory,
-                                      opt.reporter,
-                                      true,
-                                      parameters.getApiLevel().getLevel()))),
-              parameters.getApiLevel(),
-              desugaredLibraryKeepRules,
-              shrinkDesugaredLibrary)
-          .run(parameters.getRuntime(), Executor.class)
-          .assertSuccessWithOutput(EXPECTED_RESULT);
-
-    } else {
-      testForJvm()
-          .addProgramFiles(jar)
-          .addRunClasspathFiles(getDesugaredLibraryInCFMinimal(parameters, options -> {}))
-          .run(parameters.getRuntime(), Executor.class)
-          .assertSuccessWithOutput(EXPECTED_RESULT);
-    }
-  }
-
-  public Path getDesugaredLibraryInCFMinimal(
-      TestParameters parameters, Consumer<InternalOptions> configurationForLibraryCompilation)
-      throws IOException, CompilationFailedException {
-    Path desugaredLib = temp.newFolder().toPath().resolve("desugar_jdk_libs.jar");
-    L8Command.Builder l8Builder =
-        L8Command.builder()
-            .addLibraryFiles(getLibraryFile())
-            .addProgramFiles(ToolHelper.getDesugarJDKLibs())
-            .addProgramFiles(ToolHelper.DESUGAR_LIB_CONVERSIONS)
-            .setMode(CompilationMode.DEBUG)
-            .addDesugaredLibraryConfiguration(
-                StringResource.fromFile(ToolHelper.getDesugarLibJsonMinimalForTesting()))
-            .setMinApiLevel(parameters.getApiLevel().getLevel())
-            .setOutput(desugaredLib, OutputMode.ClassFile);
-    ToolHelper.runL8(l8Builder.build(), configurationForLibraryCompilation);
-    return desugaredLib;
-  }
-
-  @Test
-  public void testFunctionCompositionR8() throws Exception {
-    testForR8(parameters.getBackend())
-        .addLibraryFiles(getLibraryFile())
-        .setMinApi(parameters.getApiLevel())
         .addKeepMainRule(Executor.class)
-        .addInnerClasses(getClass())
-        .enableCoreLibraryDesugaring(minimalConfiguration())
-        .allowStdoutMessages()
-        .compile()
         .run(parameters.getRuntime(), Executor.class)
         .assertSuccessWithOutput(EXPECTED_RESULT);
   }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ImplementedInterfacesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ImplementedInterfacesTest.java
index 90a302f..f4caa40 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ImplementedInterfacesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ImplementedInterfacesTest.java
@@ -4,14 +4,20 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8SHRINK;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static junit.framework.TestCase.assertFalse;
 import static junit.framework.TestCase.assertTrue;
 import static org.hamcrest.MatcherAssert.assertThat;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableList;
 import java.io.Serializable;
 import java.util.Collection;
 import java.util.List;
@@ -26,22 +32,39 @@
 public class ImplementedInterfacesTest extends DesugaredLibraryTestBase {
 
   private final TestParameters parameters;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+  private final CompilationSpecification compilationSpecification;
   private final boolean canUseDefaultAndStaticInterfaceMethods;
 
-  @Parameters(name = "{0}")
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build());
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+        getJdk8Jdk11(),
+        ImmutableList.of(D8_L8DEBUG, D8_L8SHRINK));
   }
 
-  public ImplementedInterfacesTest(TestParameters parameters) {
+  public ImplementedInterfacesTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+    this.compilationSpecification = compilationSpecification;
     this.canUseDefaultAndStaticInterfaceMethods =
         parameters
             .getApiLevel()
             .isGreaterThanOrEqualTo(apiLevelWithDefaultInterfaceMethodsSupport());
   }
 
+  @Test
+  public void testImplementedInterfaces() throws Throwable {
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+        .addInnerClasses(getClass())
+        .compile()
+        .inspect(this::checkInterfaces);
+  }
+
   private String desugaredJavaTypeNameFor(Class<?> clazz) {
     return clazz.getTypeName().replace("java.", "j$.");
   }
@@ -63,18 +86,6 @@
     }
   }
 
-  @Test
-  public void testInterfaces() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForD8(parameters.getBackend())
-        .addLibraryFiles(getLibraryFile())
-        .addInnerClasses(ImplementedInterfacesTest.class)
-        .setMinApi(parameters.getApiLevel())
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-        .compile()
-        .inspect(this::checkInterfaces);
-  }
-
   abstract static class MultipleInterfaces<T> implements List<T>, Serializable, Set<T> {
 
     // Disambiguate between default methods List.spliterator() and Set.spliterator()
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InstantTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InstantTest.java
index d3c8a4d..e16b428 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InstantTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InstantTest.java
@@ -4,8 +4,12 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
+
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import java.time.Instant;
 import java.time.ZoneOffset;
 import java.util.List;
@@ -18,52 +22,31 @@
 public class InstantTest extends DesugaredLibraryTestBase {
 
   private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+  private final CompilationSpecification compilationSpecification;
 
-  @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+        getJdk8Jdk11(),
+        DEFAULT_SPECIFICATIONS);
   }
 
-  public InstantTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+  public InstantTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+    this.compilationSpecification = compilationSpecification;
   }
 
   @Test
-  public void testInstantD8() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForD8()
-        .addLibraryFiles(getLibraryFile())
-        .addInnerClasses(InstantTest.class)
-        .setMinApi(parameters.getApiLevel())
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-        .compile()
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
-        .run(parameters.getRuntime(), Executor.class)
-        .assertSuccessWithOutputLines("1970-01-02T10:17:36.789Z");
-  }
-
-  @Test
-  public void testInstantR8() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForR8(parameters.getBackend())
-        .addLibraryFiles(getLibraryFile())
-        .addInnerClasses(InstantTest.class)
-        .setMinApi(parameters.getApiLevel())
-        .addKeepClassAndMembersRules(Executor.class)
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-        .compile()
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
+  public void testInstant() throws Exception {
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+        .addInnerClasses(getClass())
+        .addKeepMainRule(Executor.class)
         .run(parameters.getRuntime(), Executor.class)
         .assertSuccessWithOutputLines("1970-01-02T10:17:36.789Z");
   }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InvalidLibraryTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InvalidLibraryTest.java
index 760fc1c..397a46f 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InvalidLibraryTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InvalidLibraryTest.java
@@ -4,104 +4,95 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8SHRINK;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 import static org.hamcrest.core.StringContains.containsString;
 
+import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CustomLibrarySpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.errors.InvalidLibrarySuperclassDiagnostic;
 import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
+import java.io.IOException;
 import java.nio.file.Path;
 import java.time.Instant;
 import java.util.Date;
 import java.util.List;
 import org.junit.Assume;
-import org.junit.BeforeClass;
 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 InvalidLibraryTest extends DesugaredLibraryTestBase {
 
-  private static Path customLib;
-  private static Path superclassAsClasspath;
   private static final String EXPECTED_RESULT =
       StringUtils.lines("1970-01-02T10:17:36.789Z", "1970-01-12T10:20:54.321123456Z");
   private static final String INVALID_RESULT =
       StringUtils.lines("1970-01-02T10:17:36.789Z", "1970-01-12T10:20:54.321Z");
 
   private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+  private final CompilationSpecification compilationSpecification;
 
-  @Parameterized.Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+        getJdk8Jdk11(),
+        ImmutableList.of(D8_L8DEBUG, D8_L8SHRINK));
   }
 
-  public InvalidLibraryTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+  public InvalidLibraryTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+    this.compilationSpecification = compilationSpecification;
   }
 
-  @BeforeClass
-  public static void compileCustomLib() throws Exception {
-    customLib =
-        testForD8(getStaticTemp())
-            .addProgramClasses(CustomLibraryClass.class)
-            .setMinApi(AndroidApiLevel.B)
-            .compile()
-            .writeToZip();
-    superclassAsClasspath =
-        testForD8(getStaticTemp())
-            .addProgramClasses(SuperLibraryClass.class)
-            .setMinApi(AndroidApiLevel.B)
-            .compile()
-            .writeToZip();
+  private Path getSuperclassAsClasspath() throws CompilationFailedException, IOException {
+    return testForD8(getStaticTemp())
+        .addProgramClasses(SuperLibraryClass.class)
+        .setMinApi(AndroidApiLevel.B)
+        .compile()
+        .writeToZip();
   }
 
   @Test
   public void testProgramSupertype() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForD8()
-        .addLibraryFiles(getLibraryFile())
-        .setMinApi(parameters.getApiLevel())
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
         .addProgramClasses(
             Executor.class, SuperLibraryClass.class, LocalClass.class, LocalClassOverride.class)
-        .addLibraryClasses(CustomLibraryClass.class)
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-        .compile()
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
-        .addRunClasspathFiles(customLib)
+        .setCustomLibrarySpecification(
+            new CustomLibrarySpecification(CustomLibraryClass.class, AndroidApiLevel.B))
+        .addKeepMainRule(Executor.class)
         .run(parameters.getRuntime(), Executor.class)
         .assertSuccessWithOutput(EXPECTED_RESULT);
   }
 
   @Test
   public void testClasspathSupertype() throws Exception {
-    Assume.assumeTrue(requiresAnyCoreLibDesugaring(parameters));
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForD8()
-        .addLibraryFiles(getLibraryFile())
-        .setMinApi(parameters.getApiLevel())
+    Assume.assumeTrue(
+        requiresAnyCoreLibDesugaring(
+            parameters.getApiLevel(), libraryDesugaringSpecification != JDK8));
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
         .addProgramClasses(Executor.class, LocalClass.class, LocalClassOverride.class)
         .addClasspathClasses(SuperLibraryClass.class)
-        .addLibraryClasses(CustomLibraryClass.class)
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+        .setCustomLibrarySpecification(
+            new CustomLibrarySpecification(CustomLibraryClass.class, AndroidApiLevel.B))
+        .addKeepMainRule(Executor.class)
         .compile()
-        .inspectDiagnosticMessages(this::assertWarningInvalidLibrary)
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
-        .addRunClasspathFiles(customLib, superclassAsClasspath)
+        .addRunClasspathFiles(getSuperclassAsClasspath())
         .run(parameters.getRuntime(), Executor.class)
         // The code requires desugaring to be run correctly, but with the classpath superclass,
         // desugaring is incorrectly performed. The code therefore falls-backs to the default
@@ -112,22 +103,17 @@
 
   @Test
   public void testNullSupertype() throws Exception {
-    Assume.assumeTrue(requiresAnyCoreLibDesugaring(parameters));
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForD8()
-        .addLibraryFiles(getLibraryFile())
-        .setMinApi(parameters.getApiLevel())
+    Assume.assumeTrue(
+        requiresAnyCoreLibDesugaring(
+            parameters.getApiLevel(), libraryDesugaringSpecification != JDK8));
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
         .addProgramClasses(Executor.class, LocalClass.class, LocalClassOverride.class)
-        .addLibraryClasses(CustomLibraryClass.class)
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+        .setCustomLibrarySpecification(
+            new CustomLibrarySpecification(CustomLibraryClass.class, AndroidApiLevel.B))
+        .addKeepMainRule(Executor.class)
         .compile()
         .inspectDiagnosticMessages(this::assertWarningInvalidLibrary)
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
-        .addRunClasspathFiles(customLib, superclassAsClasspath)
+        .addRunClasspathFiles(getSuperclassAsClasspath())
         .run(parameters.getRuntime(), Executor.class)
         // The code requires desugaring to be run correctly, but with the missing supertype,
         // desugaring could not be performed and the code cannot simply run (Warning was raised).
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IterableTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IterableTest.java
index 8fd4cd4..5389a79 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IterableTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IterableTest.java
@@ -4,17 +4,16 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.SPECIFICATIONS_WITH_CF2CF;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 import static org.hamcrest.MatcherAssert.assertThat;
 
-import com.android.tools.r8.LibraryDesugaringTestConfiguration;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestRuntime.CfVm;
-import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.CodeMatchers;
-import java.nio.file.Path;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Iterator;
@@ -22,7 +21,6 @@
 import java.util.function.Consumer;
 import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
-import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -31,24 +29,45 @@
 @RunWith(Parameterized.class)
 public class IterableTest extends DesugaredLibraryTestBase {
 
-  private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
   private static final String EXPECTED_OUTPUT =
       StringUtils.lines("1", "2", "3", "4", "5", "Count: 4", "1", "2", "3", "4", "5");
 
-  @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+  private final TestParameters parameters;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+  private final CompilationSpecification compilationSpecification;
+
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        BooleanUtils.values(),
-        getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build());
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+        getJdk8Jdk11(),
+        SPECIFICATIONS_WITH_CF2CF);
   }
 
-  public IterableTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+  public IterableTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+    this.compilationSpecification = compilationSpecification;
+  }
+
+  @Test
+  public void testIterable() throws Throwable {
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+        .addInnerClasses(getClass())
+        .addKeepMainRule(Main.class)
+        .compile()
+        .inspect(this::inspect)
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
   }
 
   private void inspect(CodeInspector inspector) {
+    if (compilationSpecification.isProgramShrink()) {
+      return;
+    }
     if (parameters
         .getApiLevel()
         .isGreaterThanOrEqualTo(apiLevelWithDefaultInterfaceMethodsSupport())) {
@@ -62,71 +81,6 @@
     }
   }
 
-  @Test
-  public void testIterableD8Cf() throws Exception {
-    // Only test without shrinking desugared library.
-    Assume.assumeFalse(shrinkDesugaredLibrary);
-    // Use D8 to desugar with Java classfile output.
-    Path jar =
-        testForD8(Backend.CF)
-            .addInnerClasses(IterableTest.class)
-            .setMinApi(parameters.getApiLevel())
-            .enableCoreLibraryDesugaring(
-                LibraryDesugaringTestConfiguration.forApiLevel(parameters.getApiLevel()))
-            .compile()
-            .inspect(this::inspect)
-            .writeToZip();
-
-    if (parameters.getRuntime().isDex()) {
-      // Convert to DEX without desugaring and run.
-      testForD8()
-          .addProgramFiles(jar)
-          .setMinApi(parameters.getApiLevel())
-          .disableDesugaring()
-          .compile()
-          .addRunClasspathFiles(buildDesugaredLibrary(parameters.getApiLevel()))
-          .run(parameters.getRuntime(), Main.class)
-          .assertSuccessWithOutput(EXPECTED_OUTPUT);
-    } else {
-      // Run on the JVM with desugared library on classpath.
-      testForJvm()
-          .addProgramFiles(jar)
-          .addRunClasspathFiles(buildDesugaredLibraryClassFile(parameters.getApiLevel()))
-          .run(parameters.getRuntime(), Main.class)
-          .applyIf(
-              // TODO(b/227161271): Figure out the cause and resolution for this issue.
-              parameters.isCfRuntime(CfVm.JDK17)
-                  && parameters.getApiLevel().equals(AndroidApiLevel.B),
-              r -> r.assertFailureWithErrorThatThrows(ExceptionInInitializerError.class),
-              r -> r.assertSuccessWithOutput(EXPECTED_OUTPUT));
-    }
-  }
-
-  @Test
-  public void testIterable() throws Exception {
-    if (parameters.isCfRuntime()) {
-      testForJvm()
-          .addInnerClasses(IterableTest.class)
-          .run(parameters.getRuntime(), Main.class)
-          .assertSuccessWithOutput(EXPECTED_OUTPUT);
-      return;
-    }
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForD8()
-        .addLibraryFiles(getLibraryFile())
-        .addInnerClasses(IterableTest.class)
-        .setMinApi(parameters.getApiLevel())
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-        .compile()
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
-        .run(parameters.getRuntime(), Main.class)
-        .assertSuccessWithOutput(EXPECTED_OUTPUT);
-  }
-
   static class Main {
 
     public static void main(String[] args) {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IterateTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IterateTest.java
index daa7978..d69ebe8 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IterateTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IterateTest.java
@@ -4,14 +4,15 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
-import com.android.tools.r8.LibraryDesugaringTestConfiguration;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.SPECIFICATIONS_WITH_CF2CF;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
+
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.StringUtils;
-import java.nio.file.Path;
 import java.util.List;
 import java.util.stream.IntStream;
-import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -20,77 +21,34 @@
 @RunWith(Parameterized.class)
 public class IterateTest extends DesugaredLibraryTestBase {
 
-  private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
   private static final String EXPECTED_OUTPUT = StringUtils.lines("1");
 
-  @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+  private final TestParameters parameters;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+  private final CompilationSpecification compilationSpecification;
+
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        BooleanUtils.values(),
-        getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build());
+        getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(),
+        getJdk8Jdk11(),
+        SPECIFICATIONS_WITH_CF2CF);
   }
 
-  public IterateTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+  public IterateTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+    this.compilationSpecification = compilationSpecification;
   }
 
   @Test
-  public void testIterateD8Cf() throws Exception {
-    // Only test without shrinking desugared library.
-    Assume.assumeFalse(shrinkDesugaredLibrary);
-    // Use D8 to desugar with Java classfile output.
-    Path jar =
-        testForD8(Backend.CF)
-            .addInnerClasses(IterateTest.class)
-            .setMinApi(parameters.getApiLevel())
-            .enableCoreLibraryDesugaring(
-                LibraryDesugaringTestConfiguration.forApiLevel(parameters.getApiLevel()))
-            .compile()
-            .writeToZip();
-
-    if (parameters.getRuntime().isDex()) {
-      // Convert to DEX without desugaring and run.
-      testForD8()
-          .addProgramFiles(jar)
-          .setMinApi(parameters.getApiLevel())
-          .disableDesugaring()
-          .compile()
-          .addRunClasspathFiles(buildDesugaredLibrary(parameters.getApiLevel()))
-          .run(parameters.getRuntime(), Main.class)
-          .assertSuccessWithOutput(EXPECTED_OUTPUT);
-    } else {
-      // Run on the JVM with desugared library on classpath.
-      testForJvm()
-          .addProgramFiles(jar)
-          .addRunClasspathFiles(buildDesugaredLibraryClassFile(parameters.getApiLevel()))
-          .run(parameters.getRuntime(), Main.class)
-          .assertSuccessWithOutput(EXPECTED_OUTPUT);
-    }
-  }
-
-  @Test
-  public void testIterate() throws Exception {
-    if (parameters.isCfRuntime()) {
-      testForJvm()
-          .addInnerClasses(IterateTest.class)
-          .run(parameters.getRuntime(), Main.class)
-          .assertSuccessWithOutput(EXPECTED_OUTPUT);
-      return;
-    }
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForD8()
-        .addLibraryFiles(getLibraryFile())
-        .addInnerClasses(IterateTest.class)
-        .setMinApi(parameters.getApiLevel())
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-        .compile()
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
+  public void testIterable() throws Throwable {
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+        .addInnerClasses(getClass())
+        .addKeepMainRule(Main.class)
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutput(EXPECTED_OUTPUT);
   }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IteratorTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IteratorTest.java
index 3664076..605854a 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IteratorTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IteratorTest.java
@@ -4,20 +4,19 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
-import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8CF2CF_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8SHRINK;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 import static junit.framework.TestCase.assertEquals;
-import static junit.framework.TestCase.fail;
-import static org.hamcrest.CoreMatchers.containsString;
 
-import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.LibraryDesugaringTestConfiguration.AbsentKeepRuleConsumer;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.BooleanUtils;
-import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.StringUtils;
-import com.android.tools.r8.utils.ZipUtils;
-import java.nio.file.Path;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.function.Consumer;
@@ -29,22 +28,28 @@
 @RunWith(Parameterized.class)
 public class IteratorTest extends DesugaredLibraryTestBase {
 
-  private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
-  private final boolean canUseDefaultAndStaticInterfaceMethods;
-
   private static final String EXPECTED_OUTPUT = StringUtils.lines("1", "2", "3");
 
-  @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+  private final TestParameters parameters;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+  private final CompilationSpecification compilationSpecification;
+  private final boolean canUseDefaultAndStaticInterfaceMethods;
+
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        BooleanUtils.values(),
-        getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build());
+        getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(),
+        getJdk8Jdk11(),
+        ImmutableList.of(D8_L8DEBUG, D8_L8SHRINK, D8CF2CF_L8DEBUG));
   }
 
-  public IteratorTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+  public IteratorTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+    this.compilationSpecification = compilationSpecification;
     this.canUseDefaultAndStaticInterfaceMethods =
         parameters
             .getApiLevel()
@@ -52,126 +57,28 @@
   }
 
   @Test
-  public void testIterator() throws Exception {
-    if (parameters.isCfRuntime()) {
-      testForJvm()
-          .addInnerClasses(IteratorTest.class)
-          .run(parameters.getRuntime(), Main.class)
-          .assertSuccessWithOutput(EXPECTED_OUTPUT);
-      return;
-    }
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForD8()
-        .addLibraryFiles(getLibraryFile())
-        .addInnerClasses(IteratorTest.class)
-        .setMinApi(parameters.getApiLevel())
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+  public void testIterator() throws Throwable {
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+        .addInnerClasses(getClass())
+        .addKeepMainRule(Main.class)
         .compile()
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
+        .inspect(this::assertInterface)
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutput(EXPECTED_OUTPUT);
   }
 
-  @Test
-  public void testD8Cf() throws Exception {
-    // Use D8 to desugar with Java classfile output.
-    Path firstJar =
-        testForD8(Backend.CF)
-            .setMinApi(parameters.getApiLevel())
-            .addProgramClasses(Main.class, MyIterator.class)
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), new AbsentKeepRuleConsumer())
-            .compile()
-            .writeToZip();
-
-    ClassFileInfo info =
-        extractClassFileInfo(
-            ZipUtils.readSingleEntry(firstJar, ZipUtils.zipEntryNameForClass(MyIterator.class)));
-    assertEquals(
-        MyIterator.class.getTypeName(),
-        DescriptorUtils.getJavaTypeFromBinaryName(info.getClassBinaryName()));
+  private void assertInterface(CodeInspector inspector) {
+    ClassSubject clazz = inspector.clazz(MyIterator.class);
     assertEquals(
         canUseDefaultAndStaticInterfaceMethods ? 0 : 1,
-        info.getInterfaces().stream().filter(name -> name.equals("j$/util/Iterator")).count());
+        clazz.getDexProgramClass().getInterfaces().stream()
+            .filter(name -> name.toString().equals("j$.util.Iterator"))
+            .count());
     assertEquals(
         canUseDefaultAndStaticInterfaceMethods ? 1 : 2,
-        info.getMethodNames().stream().filter(name -> name.equals("forEachRemaining")).count());
-
-    AndroidApiLevel apiLevelNotRequiringDesugaring = AndroidApiLevel.N;
-    if (parameters.getApiLevel().isLessThan(apiLevelNotRequiringDesugaring)) {
-      try {
-        // Use D8 to desugar with Java classfile output.
-        testForD8(Backend.CF)
-            .setMinApi(parameters.getApiLevel())
-            .addProgramFiles(firstJar)
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), new AbsentKeepRuleConsumer())
-            .compileWithExpectedDiagnostics(
-                diagnostics ->
-                    diagnostics.assertErrorsMatch(
-                        diagnosticMessage(
-                            containsString(
-                                "Code has already been library desugared. "
-                                    + "Interface Lj$/util/Iterator; is already implemented by "
-                                    + "Lcom/android/tools/r8/desugar/desugaredlibrary/"
-                                    + "IteratorTest$MyIterator;"))));
-        fail("Expected failure");
-      } catch (CompilationFailedException e) {
-        // Expected.
-      }
-    }
-
-    // Use D8 to desugar with Java classfile output.
-    Path secondJar =
-        testForD8(Backend.CF)
-            .addOptionsModification(
-                options ->
-                    options.desugarSpecificOptions().allowAllDesugaredInput =
-                        parameters.getApiLevel().isLessThan(apiLevelNotRequiringDesugaring))
-            .setMinApi(parameters.getApiLevel())
-            .addProgramFiles(firstJar)
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), new AbsentKeepRuleConsumer())
-            .compile()
-            .writeToZip();
-
-    info =
-        extractClassFileInfo(
-            ZipUtils.readSingleEntry(secondJar, ZipUtils.zipEntryNameForClass(MyIterator.class)));
-    assertEquals(
-        MyIterator.class.getTypeName(),
-        DescriptorUtils.getJavaTypeFromBinaryName(info.getClassBinaryName()));
-    assertEquals(
-        canUseDefaultAndStaticInterfaceMethods ? 0 : 1,
-        info.getInterfaces().stream().filter(name -> name.equals("j$/util/Iterator")).count());
-    assertEquals(
-        canUseDefaultAndStaticInterfaceMethods ? 1 : 2,
-        info.getMethodNames().stream().filter(name -> name.equals("forEachRemaining")).count());
-
-    if (parameters.getRuntime().isDex()) {
-      // Convert to DEX without desugaring and run.
-      testForD8()
-          .addProgramFiles(firstJar)
-          .setMinApi(parameters.getApiLevel())
-          .disableDesugaring()
-          .compile()
-          .addDesugaredCoreLibraryRunClassPath(
-              this::buildDesugaredLibrary,
-              parameters.getApiLevel(),
-              collectKeepRulesWithTraceReferences(
-                  firstJar, buildDesugaredLibraryClassFile(parameters.getApiLevel())),
-              shrinkDesugaredLibrary)
-          .run(parameters.getRuntime(), Main.class)
-          .assertSuccessWithOutput(EXPECTED_OUTPUT);
-    } else {
-      // Run on the JVM with desugared library on classpath.
-      testForJvm()
-          .addProgramFiles(firstJar)
-          .addRunClasspathFiles(buildDesugaredLibraryClassFile(parameters.getApiLevel()))
-          .run(parameters.getRuntime(), Main.class)
-          .assertSuccessWithOutput(EXPECTED_OUTPUT);
-    }
+        clazz.getDexProgramClass().allMethodsSorted().stream()
+            .filter(m -> m.getReference().getName().toString().equals("forEachRemaining"))
+            .count());
   }
 
   static class Main {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/J$ExtensionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/J$ExtensionTest.java
index 371443d..18d1613 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
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 import static junit.framework.TestCase.assertTrue;
 
 import com.android.tools.r8.TestParameters;
@@ -11,6 +13,9 @@
 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.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
+import com.google.common.collect.ImmutableList;
 import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileWriter;
@@ -27,8 +32,6 @@
 @RunWith(Parameterized.class)
 public class J$ExtensionTest extends DesugaredLibraryTestBase {
 
-  private final TestParameters parameters;
-
   private static final String MAIN_CLASS_NAME = "Main";
   private static final String MAIN_CLASS =
       "import java.time.LocalTimeAccess;\n"
@@ -51,13 +54,25 @@
           + "}";
   private static Path[] compiledClasses = new Path[2];
 
-  @Parameters(name = "{0}")
+  private final TestParameters parameters;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+  private final CompilationSpecification compilationSpecification;
+
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
-    return buildParameters(getTestParameters().withAllRuntimes().withAllApiLevels().build());
+    return buildParameters(
+        getTestParameters().withAllRuntimes().withAllApiLevels().build(),
+        getJdk8Jdk11(),
+        ImmutableList.of(D8_L8DEBUG));
   }
 
-  public J$ExtensionTest(TestParameters parameters) {
+  public J$ExtensionTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+    this.compilationSpecification = compilationSpecification;
   }
 
   @BeforeClass
@@ -134,21 +149,13 @@
   }
 
   @Test
-  public void testJ$ExtensionDesugaring() throws Exception {
+  public void testJ$ExtensionDesugaring() throws Throwable {
     Assume.assumeFalse(parameters.isCfRuntime());
-    // Above O no desugaring is required.
     Assume.assumeTrue(requiresTimeDesugaring(parameters));
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-
     String stdErr =
-        testForD8()
-            .addLibraryFiles(getLibraryFile())
+        testForDesugaredLibrary(
+                parameters, libraryDesugaringSpecification, compilationSpecification)
             .addProgramFiles(compiledClasses)
-            .setMinApi(parameters.getApiLevel())
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-            .compile()
-            .addDesugaredCoreLibraryRunClassPath(
-                this::buildDesugaredLibrary, parameters.getApiLevel())
             .run(parameters.getRuntime(), MAIN_CLASS_NAME)
             .assertFailure()
             .getStdErr();
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LocaleDateGetEraTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LocaleDateGetEraTest.java
new file mode 100644
index 0000000..6aa9243
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LocaleDateGetEraTest.java
@@ -0,0 +1,134 @@
+// 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.desugar.desugaredlibrary;
+
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.SPECIFICATIONS_WITH_CF2CF;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
+import static org.hamcrest.CoreMatchers.containsString;
+
+import com.android.tools.r8.SingleTestRunResult;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
+import com.android.tools.r8.transformers.MethodTransformer;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
+import java.io.IOException;
+import java.time.LocalDate;
+import java.time.chrono.ChronoLocalDate;
+import java.time.chrono.Era;
+import java.time.chrono.IsoEra;
+import java.util.Collection;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.objectweb.asm.Opcodes;
+
+@RunWith(Parameterized.class)
+public class LocaleDateGetEraTest extends DesugaredLibraryTestBase {
+
+  private static final String EXPECTED_RESULT = StringUtils.lines("CE");
+
+  private final TestParameters parameters;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+  private final Class<?> eraClass;
+
+  @Parameters(name = "{0}, spec: {1}, {2}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters()
+            .withAllRuntimes()
+            .withAllApiLevelsAlsoForCf()
+            .withApiLevel(AndroidApiLevel.N)
+            .build(),
+        getJdk8Jdk11(),
+        SPECIFICATIONS_WITH_CF2CF,
+        ImmutableList.of(IsoEra.class, Era.class));
+  }
+
+  public LocaleDateGetEraTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification,
+      Class<?> eraClass) {
+    this.parameters = parameters;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+    this.eraClass = eraClass;
+  }
+
+  @Test
+  public void testLocaleDate() throws Throwable {
+    SingleTestRunResult<?> run =
+        testForDesugaredLibrary(
+                parameters, libraryDesugaringSpecification, compilationSpecification)
+            .addProgramClassFileData(getProgramClassFileData())
+            .addKeepMainRule(Executor.class)
+            .run(parameters.getRuntime(), Executor.class);
+    if (parameters.getRuntime().isCf()
+        && parameters.getRuntime().asCf().isOlderThan(CfVm.JDK9)
+        && eraClass == IsoEra.class
+        // We desugar up to 30 at this point...
+        && parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.S)) {
+      // The method with the covariant return type is present only from JDK9.
+      run.assertFailureWithErrorThatMatches(
+          containsString(
+              "java.lang.NoSuchMethodError:"
+                  + " java.time.LocalDate.getEra()Ljava/time/chrono/IsoEra;"));
+    } else if (parameters.getRuntime().isDex()
+        && eraClass == IsoEra.class
+        && parameters.getApiLevel().betweenBothIncluded(AndroidApiLevel.O, AndroidApiLevel.S)
+        && libraryDesugaringSpecification == JDK8) {
+      // No support for this desugaring in JDK8 desugared library.
+      run.assertFailureWithErrorThatMatches(containsString("java.lang.NoSuchMethodError"));
+    } else {
+      run.assertSuccessWithOutput(EXPECTED_RESULT);
+    }
+  }
+
+  private Collection<byte[]> getProgramClassFileData() throws IOException {
+    return ImmutableList.of(
+        transformer(Executor.class)
+            .addMethodTransformer(
+                new MethodTransformer() {
+                  @Override
+                  public void visitMethodInsn(
+                      int opcode,
+                      String owner,
+                      String name,
+                      String descriptor,
+                      boolean isInterface) {
+                    if (opcode == Opcodes.INVOKEINTERFACE && name.equals("getEra")) {
+                      super.visitMethodInsn(
+                          Opcodes.INVOKEVIRTUAL,
+                          "java/time/LocalDate",
+                          name,
+                          "()" + DescriptorUtils.javaTypeToDescriptor(eraClass.getTypeName()),
+                          false);
+                      return;
+                    }
+                    if (opcode == Opcodes.CHECKCAST) {
+                      return;
+                    }
+                    super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+                  }
+                })
+            .transform());
+  }
+
+  static class Executor {
+
+    public static void main(String[] args) {
+      System.out.println(((ChronoLocalDate) LocalDate.ofEpochDay(123456789L)).getEra());
+    }
+  }
+}
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 568de28..ccef7e8 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
@@ -5,6 +5,7 @@
 package com.android.tools.r8.desugar.desugaredlibrary;
 
 import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
+import static com.android.tools.r8.desugar.desugaredlibrary.jdktests.Jdk11TestLibraryDesugaringSpecification.EXTENSION_PATH;
 import static junit.framework.TestCase.assertNotNull;
 import static junit.framework.TestCase.assertTrue;
 import static org.hamcrest.CoreMatchers.containsString;
@@ -22,7 +23,7 @@
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.desugar.desugaredlibrary.jdktests.Jdk11DesugaredLibraryTestBase;
+import com.android.tools.r8.desugar.desugaredlibrary.jdktests.Jdk11TestLibraryDesugaringSpecification;
 import com.android.tools.r8.errors.DuplicateTypesDiagnostic;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -30,13 +31,14 @@
 import com.google.common.collect.ImmutableMap;
 import java.nio.file.Path;
 import java.util.List;
+import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
-public class MergingJ$Test extends Jdk11DesugaredLibraryTestBase {
+public class MergingJ$Test extends DesugaredLibraryTestBase {
 
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
@@ -118,12 +120,16 @@
   }
 
   private Path buildSplitDesugaredLibraryPart2() throws Exception {
+    Assume.assumeFalse(
+        "getAllFilesWithSuffixInDirectory() seems to find different files on Windows",
+        ToolHelper.isWindows());
     Path outputDex = temp.newFolder().toPath().resolve("merger-input-split-dex.zip");
+    Jdk11TestLibraryDesugaringSpecification.setUp();
     L8.run(
         L8Command.builder()
             .addLibraryFiles(getLibraryFile())
             .addLibraryFiles(ToolHelper.getDesugarJDKLibs())
-            .addProgramFiles(JDK_11_JAVA_BASE_EXTENSION_COMPILED_FILES)
+            .addProgramFiles(EXTENSION_PATH)
             .addDesugaredLibraryConfiguration(
                 StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
             .setMinApiLevel(AndroidApiLevel.B.getLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingWithDesugaredLibraryTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingWithDesugaredLibraryTest.java
index 6eeabe2..cfb5b67 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingWithDesugaredLibraryTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingWithDesugaredLibraryTest.java
@@ -26,7 +26,6 @@
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.desugar.desugaredlibrary.jdktests.Jdk11DesugaredLibraryTestBase;
 import com.android.tools.r8.dex.Marker;
 import com.android.tools.r8.dex.Marker.Tool;
 import com.android.tools.r8.utils.AndroidApiLevel;
@@ -40,7 +39,7 @@
 import org.junit.runners.Parameterized;
 
 @RunWith(Parameterized.class)
-public class MergingWithDesugaredLibraryTest extends Jdk11DesugaredLibraryTestBase {
+public class MergingWithDesugaredLibraryTest extends DesugaredLibraryTestBase {
 
   private static final String JAVA_RESULT = "java.util.stream.ReferencePipeline$Head";
   private static final String J$_RESULT = "j$.util.stream.ReferencePipeline$Head";
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ReleasedVersionsSmokeTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ReleasedVersionsSmokeTest.java
index 44625b1..a343168 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ReleasedVersionsSmokeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ReleasedVersionsSmokeTest.java
@@ -4,12 +4,18 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
-import com.android.tools.r8.CompilationMode;
-import com.android.tools.r8.LibraryDesugaringTestConfiguration;
-import com.android.tools.r8.LibraryDesugaringTestConfiguration.Configuration;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11_LEGACY;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11_PATH;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8;
+
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
 import java.time.Clock;
 import java.time.Duration;
 import java.time.ZoneId;
@@ -22,73 +28,60 @@
 @RunWith(Parameterized.class)
 public class ReleasedVersionsSmokeTest extends DesugaredLibraryTestBase {
 
+  private static final String EXPECTED_OUTPUT =
+      StringUtils.lines(
+          "true",
+          "Caught java.time.format.DateTimeParseException",
+          "true",
+          "1970-01-02T10:17:36.789Z",
+          "GMT",
+          "GMT",
+          "1000",
+          "Hello, world");
+  private static final String EXPECTED_OUTPUT_1_0_9 =
+      StringUtils.lines(
+          "true",
+          "Caught java.time.format.DateTimeParseException",
+          "true",
+          "1970-01-02T10:17:36.789Z",
+          "1000",
+          "Hello, world");
+
   private final TestParameters parameters;
-  private final Configuration configuration;
-  private static final String expectedOutput =
-      StringUtils.lines(
-          "true",
-          "Caught java.time.format.DateTimeParseException",
-          "true",
-          "1970-01-02T10:17:36.789Z",
-          "GMT",
-          "GMT",
-          "1000",
-          "Hello, world");
-  private static final String expectedOutput_1_0_9 =
-      StringUtils.lines(
-          "true",
-          "Caught java.time.format.DateTimeParseException",
-          "true",
-          "1970-01-02T10:17:36.789Z",
-          "1000",
-          "Hello, world");
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
 
-  @Parameters(name = "{0}, {1}")
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
+    ImmutableList.Builder<LibraryDesugaringSpecification> builder = ImmutableList.builder();
+    builder.addAll(LibraryDesugaringSpecification.getReleased());
+    builder.add(JDK8, JDK11, JDK11_LEGACY, JDK11_PATH);
     return buildParameters(
-        Configuration.getReleased(),
-        getTestParameters().withDexRuntimes().withApiLevel(AndroidApiLevel.B).build());
+        getTestParameters().withDexRuntimes().withApiLevel(AndroidApiLevel.B).build(),
+        builder.build(),
+        DEFAULT_SPECIFICATIONS);
   }
 
-  public ReleasedVersionsSmokeTest(Configuration configuration, TestParameters parameters) {
-    this.configuration = configuration;
+  public ReleasedVersionsSmokeTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   @Test
-  public void testD8() throws Exception {
-    testForD8()
-        .addLibraryFiles(getLibraryFile())
-        .addInnerClasses(ReleasedVersionsSmokeTest.class)
-        .setMinApi(parameters.getApiLevel())
-        .enableCoreLibraryDesugaring(
-            LibraryDesugaringTestConfiguration.builder()
-                .setMinApi(parameters.getApiLevel())
-                .setConfiguration(configuration)
-                .withKeepRuleConsumer()
-                .setMode(CompilationMode.DEBUG)
-                .build())
-        .run(parameters.getRuntime(), TestClass.class, configuration.name())
-        .assertSuccessWithOutput(
-            configuration != Configuration.RELEASED_1_0_9 ? expectedOutput : expectedOutput_1_0_9);
-  }
-
-  @Test
-  public void testR8() throws Exception {
-    testForR8(parameters.getBackend())
-        .addLibraryFiles(getLibraryFile())
-        .addInnerClasses(ReleasedVersionsSmokeTest.class)
+  public void testSmoke() throws Throwable {
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+        .addInnerClasses(getClass())
         .addKeepMainRule(TestClass.class)
-        .setMinApi(parameters.getApiLevel())
-        .enableCoreLibraryDesugaring(
-            LibraryDesugaringTestConfiguration.builder()
-                .setMinApi(parameters.getApiLevel())
-                .withKeepRuleConsumer()
-                .setMode(CompilationMode.RELEASE)
-                .build())
-        .run(parameters.getRuntime(), TestClass.class, configuration.name())
+        .ignoreL8FinalPrefixVerification()
+        .run(parameters.getRuntime(), TestClass.class, libraryDesugaringSpecification.toString())
         .assertSuccessWithOutput(
-            configuration != Configuration.RELEASED_1_0_9 ? expectedOutput : expectedOutput_1_0_9);
+            libraryDesugaringSpecification != LibraryDesugaringSpecification.RELEASED_1_0_9
+                ? EXPECTED_OUTPUT
+                : EXPECTED_OUTPUT_1_0_9);
   }
 
   static class TestClass {
@@ -106,7 +99,7 @@
           java.util.Date.from(new java.util.Date(123456789).toInstant()).toInstant());
 
       // Support for this was added in 1.0.10.
-      if (!configurationVersion.equals("RELEASED_1_0_9")) {
+      if (!configurationVersion.equals("RELEASED_1.0.9")) {
         java.util.TimeZone timeZone = java.util.TimeZone.getTimeZone(ZoneId.of("GMT"));
         System.out.println(timeZone.getID());
         System.out.println(timeZone.toZoneId().getId());
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RequiredNonNullWithSupplierTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RequiredNonNullWithSupplierTest.java
index 5780701..6a957ef 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RequiredNonNullWithSupplierTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RequiredNonNullWithSupplierTest.java
@@ -4,8 +4,12 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
+
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.StringUtils;
 import java.util.List;
 import java.util.Objects;
@@ -13,6 +17,7 @@
 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 RequiredNonNullWithSupplierTest extends DesugaredLibraryTestBase {
@@ -20,41 +25,31 @@
   private static final String EXPECTED_OUTPUT = StringUtils.lines("SuppliedString2", "OK");
 
   private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
 
-  @Parameterized.Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+        getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(),
+        getJdk8Jdk11(),
+        DEFAULT_SPECIFICATIONS);
   }
 
   public RequiredNonNullWithSupplierTest(
-      boolean shrinkDesugaredLibrary, TestParameters parameters) {
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   @Test
-  public void testRequiredNonNullWithSupplierTest() throws Exception {
-    if (parameters.isCfRuntime()) {
-      testForJvm()
-          .addInnerClasses(RequiredNonNullWithSupplierTest.class)
-          .run(parameters.getRuntime(), Executor.class)
-          .assertSuccessWithOutput(EXPECTED_OUTPUT);
-      return;
-    }
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForD8()
-        .addLibraryFiles(getLibraryFile())
-        .addInnerClasses(RequiredNonNullWithSupplierTest.class)
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-        .setMinApi(parameters.getApiLevel())
-        .compile()
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
+  public void testRequireNonNull() throws Throwable {
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+        .addInnerClasses(getClass())
+        .addKeepMainRule(Executor.class)
         .run(parameters.getRuntime(), Executor.class)
         .assertSuccessWithOutput(EXPECTED_OUTPUT);
   }
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 50f2ce7..6d0d72f 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,9 @@
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.TestParameters;
+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.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;
@@ -27,15 +30,16 @@
 @RunWith(Parameterized.class)
 public class RetargetAndBackportTest extends DesugaredLibraryTestBase implements Opcodes {
 
-  Backend backend;
+  private final TestParameters parameters;
 
   @Parameters(name = "{0} {1}")
   public static List<Object[]> data() {
-    return buildParameters(getTestParameters().withNoneRuntime().build(), Backend.values());
+    return buildParameters(
+        getTestParameters().withDexRuntime(Version.DEFAULT).withCfRuntime(CfVm.JDK11).build());
   }
 
-  public RetargetAndBackportTest(TestParameters parameters, Backend backend) {
-    this.backend = backend;
+  public RetargetAndBackportTest(TestParameters parameters) {
+    this.parameters = parameters;
   }
 
   /**
@@ -60,10 +64,10 @@
 
   @Test
   public void test() throws Exception {
-    testForL8(AndroidApiLevel.B, backend)
+    testForL8(AndroidApiLevel.B, parameters.getBackend())
         .noDefaultDesugarJDKLibs()
         .addProgramClassFileData(dump())
-        .addLibraryFiles(getLibraryFile())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P.getLevel()))
         .addOptionsModifier(RetargetAndBackportTest::specifyDesugaredLibrary)
         .compile()
         .inspect(
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 5d9cf31..10f3ada 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
@@ -4,9 +4,12 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.SPECIFICATIONS_WITH_CF2CF;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
+
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.BooleanUtils;
-import java.nio.file.Path;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import java.time.Instant;
 import java.time.ZonedDateTime;
 import java.util.Date;
@@ -14,7 +17,6 @@
 import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.IntUnaryOperator;
-import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -24,119 +26,33 @@
 public class RetargetOverrideTest extends DesugaredLibraryTestBase {
 
   private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
 
-  @Parameters(name = "{1}, shrink: {0}")
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        BooleanUtils.values(),
-        getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build());
+        getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(),
+        getJdk8Jdk11(),
+        SPECIFICATIONS_WITH_CF2CF);
   }
 
-  public RetargetOverrideTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+  public RetargetOverrideTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   @Test
-  public void testRetargetOverrideCf() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    Path desugaredTwice =
-        testForD8(Backend.CF)
-            .addLibraryFiles(getLibraryFile())
-            .addProgramFiles(
-                testForD8(Backend.CF)
-                    .addLibraryFiles(getLibraryFile())
-                    .addInnerClasses(RetargetOverrideTest.class)
-                    .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-                    .setMinApi(parameters.getApiLevel())
-                    .compile()
-                    .writeToZip())
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-            .setMinApi(parameters.getApiLevel())
-            .addOptionsModification(
-                options -> options.desugarSpecificOptions().allowAllDesugaredInput = true)
-            .compile()
-            .writeToZip();
-
-    String stdout;
-    if (parameters.getRuntime().isDex()) {
-      // Convert to DEX without desugaring and run.
-      stdout =
-          testForD8(Backend.DEX)
-              .addProgramFiles(desugaredTwice)
-              .setMinApi(parameters.getApiLevel())
-              .disableDesugaring()
-              .compile()
-              .addDesugaredCoreLibraryRunClassPath(
-                  this::buildDesugaredLibrary,
-                  parameters.getApiLevel(),
-                  keepRuleConsumer.get(),
-                  shrinkDesugaredLibrary)
-              .run(
-                  parameters.getRuntime(),
-                  Executor.class,
-                  Boolean.toString(parameters.getRuntime().isCf()))
-              .assertSuccess()
-              .getStdOut();
-    } else {
-      // Run on the JVM with desugared library on classpath.
-      stdout =
-          testForJvm()
-              .addProgramFiles(desugaredTwice)
-              .addRunClasspathFiles(buildDesugaredLibraryClassFile(parameters.getApiLevel()))
-              .run(
-                  parameters.getRuntime(),
-                  Executor.class,
-                  Boolean.toString(parameters.getRuntime().isCf()))
-              .assertSuccess()
-              .getStdOut();
-    }
-    assertLines2By2Correct(stdout);
-  }
-
-  @Test
-  public void testRetargetOverrideD8() throws Exception {
-    Assume.assumeTrue(parameters.getRuntime().isDex());
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
+  public void testRetargetOverride() throws Throwable {
     String stdout =
-        testForD8()
-            .addLibraryFiles(getLibraryFile())
-            .addInnerClasses(RetargetOverrideTest.class)
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-            .setMinApi(parameters.getApiLevel())
-            .compile()
-            .addDesugaredCoreLibraryRunClassPath(
-                this::buildDesugaredLibrary,
-                parameters.getApiLevel(),
-                keepRuleConsumer.get(),
-                shrinkDesugaredLibrary)
-            .run(
-                parameters.getRuntime(),
-                Executor.class,
-                Boolean.toString(parameters.getRuntime().isCf()))
-            .assertSuccess()
-            .getStdOut();
-    assertLines2By2Correct(stdout);
-  }
-
-  @Test
-  public void testRetargetOverrideR8() throws Exception {
-    Assume.assumeTrue(parameters.getRuntime().isDex());
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    String stdout =
-        testForR8(Backend.DEX)
-            .addLibraryFiles(getLibraryFile())
+        testForDesugaredLibrary(
+                parameters, libraryDesugaringSpecification, compilationSpecification)
+            .addInnerClasses(getClass())
             .addKeepMainRule(Executor.class)
-            .addInnerClasses(RetargetOverrideTest.class)
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-            .setMinApi(parameters.getApiLevel())
-            .compile()
-            .addDesugaredCoreLibraryRunClassPath(
-                this::buildDesugaredLibrary,
-                parameters.getApiLevel(),
-                keepRuleConsumer.get(),
-                shrinkDesugaredLibrary)
             .run(
                 parameters.getRuntime(),
                 Executor.class,
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/SimpleStreamTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/SimpleStreamTest.java
index ffd4166..3cdfedb 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/SimpleStreamTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/SimpleStreamTest.java
@@ -4,12 +4,17 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
+
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.StringUtils;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
+import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -21,52 +26,32 @@
   private static final String EXPECTED_RESULT = StringUtils.lines("3");
 
   private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
 
-  @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+        getJdk8Jdk11(),
+        DEFAULT_SPECIFICATIONS);
   }
 
-  public SimpleStreamTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+  public SimpleStreamTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   @Test
-  public void testStreamD8() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForD8()
-        .addLibraryFiles(getLibraryFile())
-        .addInnerClasses(SimpleStreamTest.class)
-        .setMinApi(parameters.getApiLevel())
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-        .compile()
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
-        .run(parameters.getRuntime(), Executor.class)
-        .assertSuccessWithOutput(EXPECTED_RESULT);
-  }
-
-  @Test
-  public void testStreamR8() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForR8(Backend.DEX)
-        .addLibraryFiles(getLibraryFile())
-        .addInnerClasses(SimpleStreamTest.class)
-        .setMinApi(parameters.getApiLevel())
-        .addKeepClassAndMembersRules(Executor.class)
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-        .compile()
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
+  public void testSimpleStream() throws Throwable {
+    Assume.assumeTrue(requiresEmulatedInterfaceCoreLibDesugaring(parameters));
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+        .addInnerClasses(getClass())
+        .addKeepMainRule(Executor.class)
         .run(parameters.getRuntime(), Executor.class)
         .assertSuccessWithOutput(EXPECTED_RESULT);
   }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/SpliteratorTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/SpliteratorTest.java
index 1fc77de..7b45541 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/SpliteratorTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/SpliteratorTest.java
@@ -4,12 +4,17 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 import static junit.framework.TestCase.assertTrue;
 
-import com.android.tools.r8.LibraryDesugaringTestConfiguration;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableList;
 import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.LinkedList;
@@ -23,7 +28,6 @@
 @RunWith(Parameterized.class)
 public class SpliteratorTest extends DesugaredLibraryTestBase {
 
-  private final TestParameters parameters;
   private static final String EXPECTED_OUTPUT_JDK11 =
       StringUtils.lines(
           "j$.util.AbstractList$RandomAccessSpliterator",
@@ -37,29 +41,37 @@
           "j$.util.Spliterators$IteratorSpliterator",
           "j$.util.Spliterators$IteratorSpliterator");
 
-  @Parameters(name = "{0}")
+  private final TestParameters parameters;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
-    return buildParameters(getTestParameters().withDexRuntimes().withAllApiLevels().build());
+    return buildParameters(
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+        getJdk8Jdk11(),
+        ImmutableList.of(D8_L8DEBUG));
   }
 
-  public SpliteratorTest(TestParameters parameters) {
+  public SpliteratorTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   @Test
-  public void testSpliterator() throws Exception {
+  public void testSpliterator() throws Throwable {
     Assume.assumeTrue(requiresEmulatedInterfaceCoreLibDesugaring(parameters));
-    testForD8()
-        .addLibraryFiles(getLibraryFile())
-        .addInnerClasses(SpliteratorTest.class)
-        .setMinApi(parameters.getApiLevel())
-        .enableCoreLibraryDesugaring(
-            LibraryDesugaringTestConfiguration.forApiLevel(parameters.getApiLevel()))
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+        .addInnerClasses(getClass())
         .compile()
         .inspect(this::validateInterfaces)
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutput(
-            isJDK11DesugaredLibrary() ? EXPECTED_OUTPUT_JDK11 : EXPECTED_OUTPUT_JDK8);
+            libraryDesugaringSpecification != JDK8 ? EXPECTED_OUTPUT_JDK11 : EXPECTED_OUTPUT_JDK8);
   }
 
   private void validateInterfaces(CodeInspector inspector) {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/StaticInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/StaticInterfaceMethodTest.java
index f36ae99..d8f056b 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/StaticInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/StaticInterfaceMethodTest.java
@@ -4,16 +4,16 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
-import static org.junit.Assert.assertEquals;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.SPECIFICATIONS_WITH_CF2CF;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.StringUtils;
-import java.nio.file.Path;
 import java.time.chrono.Chronology;
 import java.util.List;
 import java.util.Map;
-import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -25,102 +25,31 @@
   private static final String EXPECTED_OUTPUT = StringUtils.lines("false", "java.util.HashSet");
 
   private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
 
-  @Parameters(name = "{0}, shrinkDesugaredLibrary: {1}")
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
         getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(),
-        BooleanUtils.values());
+        getJdk8Jdk11(),
+        SPECIFICATIONS_WITH_CF2CF);
   }
 
-  public StaticInterfaceMethodTest(TestParameters parameters, boolean shrinkDesugaredLibrary) {
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+  public StaticInterfaceMethodTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   @Test
-  public void testStaticInterfaceMethodsD8() throws Exception {
-    if (parameters.isCfRuntime()) {
-      testForJvm()
-          .addInnerClasses(StaticInterfaceMethodTest.class)
-          .run(parameters.getRuntime(), Executor.class)
-          .assertSuccessWithOutput(EXPECTED_OUTPUT);
-      return;
-    }
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForD8()
-        .addLibraryFiles(getLibraryFile())
-        .addInnerClasses(StaticInterfaceMethodTest.class)
-        .setMinApi(parameters.getApiLevel())
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-        .compile()
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
-        .run(parameters.getRuntime(), Executor.class)
-        .assertSuccessWithOutput(EXPECTED_OUTPUT);
-  }
-
-  @Test
-  public void testStaticInterfaceMethodsD8CfToCf() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    Path jar =
-        testForD8(Backend.CF)
-            .addInnerClasses(StaticInterfaceMethodTest.class)
-            .setMinApi(parameters.getApiLevel())
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-            .compile()
-            .writeToZip();
-
-    String desugaredLibraryKeepRules = "";
-    if (shrinkDesugaredLibrary && keepRuleConsumer.get() != null) {
-      // Collection keep rules is only implemented in the DEX writer.
-      assertEquals(0, keepRuleConsumer.get().length());
-      desugaredLibraryKeepRules = "-keep class * { *; }";
-    }
-    if (parameters.getRuntime().isDex()) {
-      testForD8()
-          .addProgramFiles(jar)
-          .setMinApi(parameters.getApiLevel())
-          .disableDesugaring()
-          .compile()
-          .addDesugaredCoreLibraryRunClassPath(
-              this::buildDesugaredLibrary,
-              parameters.getApiLevel(),
-              desugaredLibraryKeepRules,
-              shrinkDesugaredLibrary)
-          .run(parameters.getRuntime(), Executor.class)
-          .assertSuccessWithOutput(EXPECTED_OUTPUT);
-    } else {
-      testForJvm()
-          .addProgramFiles(jar)
-          .addRunClasspathFiles(getDesugaredLibraryInCF(parameters, options -> {}))
-          .run(parameters.getRuntime(), Executor.class)
-          .assertSuccessWithOutput(EXPECTED_OUTPUT);
-    }
-  }
-
-  @Test
-  public void testStaticInterfaceMethodsR8() throws Exception {
-    // Desugared library tests do not make sense in the Cf to Cf, and the JVM is already tested
-    // in the D8 test. Just return.
-    Assume.assumeFalse(parameters.isCfRuntime());
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForR8(parameters.getBackend())
-        .addLibraryFiles(getLibraryFile())
+  public void testStaticInterfaceMethods() throws Throwable {
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+        .addInnerClasses(getClass())
         .addKeepMainRule(Executor.class)
-        .addInnerClasses(StaticInterfaceMethodTest.class)
-        .setMinApi(parameters.getApiLevel())
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-        .compile()
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
         .run(parameters.getRuntime(), Executor.class)
         .assertSuccessWithOutput(EXPECTED_OUTPUT);
   }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/SynchronizedCollectionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/SynchronizedCollectionTest.java
index 025740b..3bff859 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/SynchronizedCollectionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/SynchronizedCollectionTest.java
@@ -4,15 +4,18 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
+
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestRuntime.CfVm;
 import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.StringUtils;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.List;
-import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -28,9 +31,10 @@
   private static final String MAIN_CLASS = "desugaredlib.SynchronizedCollectionMain";
 
   private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
 
-  @Parameters(name = "{0}, shrinkDesugaredLibrary: {1}")
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
         getTestParameters()
@@ -38,57 +42,24 @@
             .withAllApiLevels()
             .withCfRuntimesStartingFromIncluding(CfVm.JDK9)
             .build(),
-        BooleanUtils.values());
+        getJdk8Jdk11(),
+        DEFAULT_SPECIFICATIONS);
   }
 
-  public SynchronizedCollectionTest(TestParameters parameters, boolean shrinkDesugaredLibrary) {
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+  public SynchronizedCollectionTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
   }
 
   @Test
-  public void testExecutionD8() throws Exception {
-    if (parameters.isCfRuntime()) {
-      testForJvm()
-          .addProgramFiles(INPUT_JAR)
-          .run(parameters.getRuntime(), MAIN_CLASS)
-          .assertSuccessWithOutput(EXPECTED_OUTPUT);
-      return;
-    }
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForD8()
-        .addLibraryFiles(getLibraryFile())
-        .addProgramFiles(INPUT_JAR)
-        .setMinApi(parameters.getApiLevel())
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-        .compile()
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
-        .run(parameters.getRuntime(), MAIN_CLASS)
-        .assertSuccessWithOutput(EXPECTED_OUTPUT);
-  }
-
-  @Test
-  public void testExecutionR8() throws Exception {
-    // Desugared library tests do not make sense in the Cf to Cf, and the JVM is already tested
-    // in the D8 test. Just return.
-    Assume.assumeFalse(parameters.isCfRuntime());
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForR8(parameters.getBackend())
-        .addLibraryFiles(getLibraryFile())
+  public void testExecution() throws Throwable {
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
         .addProgramFiles(INPUT_JAR)
         .addKeepMainRule(MAIN_CLASS)
-        .setMinApi(parameters.getApiLevel())
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-        .compile()
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
         .run(parameters.getRuntime(), MAIN_CLASS)
         .assertSuccessWithOutput(EXPECTED_OUTPUT);
   }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/APIConversionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/APIConversionTest.java
index 44ef579..367d791 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/APIConversionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/APIConversionTest.java
@@ -5,8 +5,10 @@
 
 import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
 import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11_LEGACY;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11_PATH;
 import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8;
-import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
 import static org.hamcrest.CoreMatchers.endsWith;
 import static org.hamcrest.core.StringContains.containsString;
 
@@ -16,6 +18,7 @@
 import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Random;
@@ -42,7 +45,7 @@
   public static List<Object[]> data() {
     return buildParameters(
         getConversionParametersUpToExcluding(MIN_SUPPORTED),
-        getJdk8Jdk11(),
+        ImmutableList.of(JDK8, JDK11, JDK11_LEGACY, JDK11_PATH),
         DEFAULT_SPECIFICATIONS);
   }
 
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionsPresentTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionsPresentTest.java
index 3ae7873..24169b1 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionsPresentTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionsPresentTest.java
@@ -8,7 +8,6 @@
 import static junit.framework.TestCase.assertEquals;
 import static junit.framework.TestCase.assertTrue;
 
-import com.android.tools.r8.StringResource;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
 import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
@@ -44,11 +43,7 @@
   @Test
   public void testConversionsDex() throws Exception {
     testForL8(parameters.getApiLevel())
-        .addLibraryFiles(libraryDesugaringSpecification.getAndroidJar())
-        .noDefaultDesugarJDKLibs()
-        .addProgramFiles(libraryDesugaringSpecification.getDesugarJdkLibs())
-        .setDesugaredLibraryConfiguration(
-            StringResource.fromFile(libraryDesugaringSpecification.getSpecification()))
+        .apply(libraryDesugaringSpecification::configureL8TestBuilder)
         .compile()
         .apply(c -> checkConversionGeneratedDex(c.inspector()));
   }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GetGenericInterfaceTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GetGenericInterfaceTest.java
index a6eafe8..366e029 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GetGenericInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GetGenericInterfaceTest.java
@@ -83,8 +83,9 @@
     String[] lines = stdOut.split("\n");
     for (int i = 0; i < lines.length; i += 4) {
       String className = lines[i];
-      String[] interfaces1 = lines[i + 1].split("(, com|, interface|, j)");
-      String[] interfaces2 = lines[i + 2].split("(, com|, interface|, j)");
+      String[] interfaces1 = lines[i + 1].substring(1, lines[i + 1].length() - 1).split(",");
+      String[] interfaces2 =
+          lines[i + 2].substring(1, lines[i + 2].length() - 1).split("(>, |, interface)");
       assertEquals(
           "Invalid number of interfaces in "
               + className
@@ -95,7 +96,7 @@
           interfaces1.length,
           interfaces2.length);
       // Ignore the empty list of interface case.
-      if (!interfaces1[0].equals("[]")) {
+      if (!interfaces1[0].isEmpty()) {
         for (int j = 0; j < interfaces1.length; j++) {
           String interfaceName = interfaces1[j].substring("interface ".length()).trim();
           while (interfaceName.charAt(interfaceName.length() - 1) == ']') {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11AtomicTests.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11AtomicTests.java
index cf2a39c..f586605 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11AtomicTests.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11AtomicTests.java
@@ -5,6 +5,8 @@
 package com.android.tools.r8.desugar.desugaredlibrary.jdktests;
 
 import static com.android.tools.r8.ToolHelper.JDK_TESTS_BUILD_DIR;
+import static com.android.tools.r8.desugar.desugaredlibrary.jdktests.Jdk11Paths.getPathsFiles;
+import static com.android.tools.r8.desugar.desugaredlibrary.jdktests.Jdk11Paths.testNGSupportProgramFiles;
 import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
 import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8SHRINK;
 import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11;
@@ -18,6 +20,7 @@
 import com.android.tools.r8.TestRuntime;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
 import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
 import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.StringUtils;
@@ -33,7 +36,7 @@
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
-public class Jdk11AtomicTests extends Jdk11DesugaredLibraryTestBase {
+public class Jdk11AtomicTests extends DesugaredLibraryTestBase {
 
   private static final Path ATOMIC_TESTS_FOLDER =
       Paths.get(ToolHelper.JDK_11_TESTS_DIR + "java/util/concurrent/atomic/");
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11ConcurrentMapTests.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11ConcurrentMapTests.java
index 0aa3ab9..0c4e38a 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11ConcurrentMapTests.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11ConcurrentMapTests.java
@@ -5,6 +5,8 @@
 package com.android.tools.r8.desugar.desugaredlibrary.jdktests;
 
 import static com.android.tools.r8.ToolHelper.JDK_TESTS_BUILD_DIR;
+import static com.android.tools.r8.desugar.desugaredlibrary.jdktests.Jdk11Paths.getPathsFiles;
+import static com.android.tools.r8.desugar.desugaredlibrary.jdktests.Jdk11Paths.testNGSupportProgramFiles;
 import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
 import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8SHRINK;
 import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11;
@@ -18,6 +20,7 @@
 import com.android.tools.r8.TestRuntime;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
 import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
 import com.android.tools.r8.desugar.desugaredlibrary.test.DesugaredLibraryTestCompileResult;
 import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
@@ -35,7 +38,7 @@
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
-public class Jdk11ConcurrentMapTests extends Jdk11DesugaredLibraryTestBase {
+public class Jdk11ConcurrentMapTests extends DesugaredLibraryTestBase {
 
   private static final Path CONCURRENT_TESTS_FOLDER =
       Paths.get(ToolHelper.JDK_11_TESTS_DIR + "java/util/concurrent/ConcurrentMap/");
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11DesugaredLibraryTestBase.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11DesugaredLibraryTestBase.java
deleted file mode 100644
index 248302a..0000000
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11DesugaredLibraryTestBase.java
+++ /dev/null
@@ -1,114 +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.jdktests;
-
-import static com.android.tools.r8.ToolHelper.JDK_TESTS_BUILD_DIR;
-import static com.android.tools.r8.utils.FileUtils.CLASS_EXTENSION;
-import static com.android.tools.r8.utils.FileUtils.JAVA_EXTENSION;
-
-import com.android.tools.r8.TestRuntime;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
-import com.android.tools.r8.utils.AndroidApiLevel;
-import com.google.common.collect.ImmutableList;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import org.junit.BeforeClass;
-
-// Provides convenience to use Paths/SafeVarargs which are missing on old Android but
-// required by some Jdk tests, and for java.base extensions.
-
-public class Jdk11DesugaredLibraryTestBase extends DesugaredLibraryTestBase {
-
-  protected static Path[] JDK_11_JAVA_BASE_EXTENSION_COMPILED_FILES;
-  static Path JDK_11_JAVA_BASE_EXTENSION_CLASSES_DIR;
-  private static final Path JDK_11_JAVA_BASE_EXTENSION_FILES_DIR =
-      Paths.get("third_party/openjdk/jdk-11-test/lib/testlibrary/bootlib/java.base");
-
-  private static final Path ANDROID_PATHS_FILES_DIR =
-      Paths.get("third_party/android_jar/lib-v26/xxx/");
-  private static final Path ANDROID_SAFE_VAR_ARGS_LOCATION =
-      Paths.get("third_party/android_jar/lib-v26/java/lang/SafeVarargs.class");
-  private static final Path[] ANDROID_PATHS_FILES =
-      new Path[] {
-        Paths.get("java/nio/file/Files.class"),
-        Paths.get("java/nio/file/OpenOption.class"),
-        Paths.get("java/nio/file/Watchable.class"),
-        Paths.get("java/nio/file/Path.class"),
-        Paths.get("java/nio/file/Paths.class")
-      };
-
-  protected static Path[] getPathsFiles() {
-    return Arrays.stream(ANDROID_PATHS_FILES)
-        .map(ANDROID_PATHS_FILES_DIR::resolve)
-        .toArray(Path[]::new);
-  }
-
-  protected static Path getSafeVarArgsFile() {
-    return ANDROID_SAFE_VAR_ARGS_LOCATION;
-  }
-
-  protected static Path[] testNGSupportProgramFiles() {
-    return new Path[] {
-      Paths.get(JDK_TESTS_BUILD_DIR + "testng-6.10.jar"),
-      Paths.get(JDK_TESTS_BUILD_DIR + "jcommander-1.48.jar"),
-      Paths.get(ToolHelper.JAVA_CLASSES_DIR + "examplesTestNGRunner/TestNGMainRunner.class")
-    };
-  }
-
-  private static Path[] getJavaBaseExtensionsFiles() throws Exception {
-    Path[] files =
-        getAllFilesWithSuffixInDirectory(JDK_11_JAVA_BASE_EXTENSION_FILES_DIR, JAVA_EXTENSION);
-    assert files.length > 0;
-    return files;
-  }
-
-  @BeforeClass
-  public static void compileJavaBaseExtensions() throws Exception {
-    JDK_11_JAVA_BASE_EXTENSION_CLASSES_DIR = getStaticTemp().newFolder("jdk11JavaBaseExt").toPath();
-    List<String> options =
-        Arrays.asList(
-            "--add-reads",
-            "java.base=ALL-UNNAMED",
-            "--patch-module",
-            "java.base=" + JDK_11_JAVA_BASE_EXTENSION_FILES_DIR);
-    javac(TestRuntime.getCheckedInJdk11(), getStaticTemp())
-        .addOptions(options)
-        .addClasspathFiles(
-            Collections.singletonList(Paths.get(JDK_TESTS_BUILD_DIR + "testng-6.10.jar")))
-        .addSourceFiles(getJavaBaseExtensionsFiles())
-        .setOutputPath(JDK_11_JAVA_BASE_EXTENSION_CLASSES_DIR)
-        .compile();
-    JDK_11_JAVA_BASE_EXTENSION_COMPILED_FILES =
-        getAllFilesWithSuffixInDirectory(JDK_11_JAVA_BASE_EXTENSION_CLASSES_DIR, CLASS_EXTENSION);
-    assert JDK_11_JAVA_BASE_EXTENSION_COMPILED_FILES.length > 0;
-  }
-
-  private String getTestNGKeepRules() {
-    // Keep data providers and their annotations.
-    return "-keepclasseswithmembers class * {\n"
-        + "    @org.testng.annotations.DataProvider <methods>;\n"
-        + "}\n"
-        + "-keepattributes *Annotation*\n"
-        // Do not even attempt to shrink testNG (unrelated to desugared lib shrinking goal).
-        + "-keep class org.testng.** { *; }\n"
-        // There are missing classes in testNG.
-        + "-dontwarn";
-  }
-
-  protected Path buildDesugaredLibraryWithJavaBaseExtension(
-      AndroidApiLevel apiLevel, String keepRules, boolean shrink) {
-    // there are missing classes from testNG.
-    keepRules = getTestNGKeepRules() + keepRules;
-    return buildDesugaredLibrary(
-        apiLevel,
-        keepRules,
-        shrink,
-        ImmutableList.copyOf(JDK_11_JAVA_BASE_EXTENSION_COMPILED_FILES));
-  }
-}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11Paths.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11Paths.java
new file mode 100644
index 0000000..1409b1b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11Paths.java
@@ -0,0 +1,49 @@
+// 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.desugar.desugaredlibrary.jdktests;
+
+import static com.android.tools.r8.ToolHelper.JDK_TESTS_BUILD_DIR;
+
+import com.android.tools.r8.ToolHelper;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+
+// Provides convenience to use Paths/SafeVarargs which are missing on old Android but
+// required by some Jdk tests, and for java.base extensions.
+
+public class Jdk11Paths {
+
+  private static final Path ANDROID_PATHS_FILES_DIR =
+      Paths.get("third_party/android_jar/lib-v26/xxx/");
+  private static final Path ANDROID_SAFE_VAR_ARGS_LOCATION =
+      Paths.get("third_party/android_jar/lib-v26/java/lang/SafeVarargs.class");
+  private static final Path[] ANDROID_PATHS_FILES =
+      new Path[] {
+        Paths.get("java/nio/file/Files.class"),
+        Paths.get("java/nio/file/OpenOption.class"),
+        Paths.get("java/nio/file/Watchable.class"),
+        Paths.get("java/nio/file/Path.class"),
+        Paths.get("java/nio/file/Paths.class")
+      };
+
+  public static Path[] getPathsFiles() {
+    return Arrays.stream(ANDROID_PATHS_FILES)
+        .map(ANDROID_PATHS_FILES_DIR::resolve)
+        .toArray(Path[]::new);
+  }
+
+  public static Path getSafeVarArgsFile() {
+    return ANDROID_SAFE_VAR_ARGS_LOCATION;
+  }
+
+  public static Path[] testNGSupportProgramFiles() {
+    return new Path[] {
+      Paths.get(JDK_TESTS_BUILD_DIR + "testng-6.10.jar"),
+      Paths.get(JDK_TESTS_BUILD_DIR + "jcommander-1.48.jar"),
+      Paths.get(ToolHelper.JAVA_CLASSES_DIR + "examplesTestNGRunner/TestNGMainRunner.class")
+    };
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11Stream1Tests.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11Stream1Tests.java
new file mode 100644
index 0000000..c11f498
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11Stream1Tests.java
@@ -0,0 +1,28 @@
+// 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.desugar.desugaredlibrary.jdktests;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class Jdk11Stream1Tests extends Jdk11StreamAbstractTests {
+
+  public Jdk11Stream1Tests(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
+    super(parameters, libraryDesugaringSpecification, compilationSpecification);
+  }
+
+  @Test
+  public void testStream() throws Throwable {
+    testStream(firstHalf(getSuccessfulTests()), firstHalf(getFailingTests()));
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11Stream2Tests.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11Stream2Tests.java
new file mode 100644
index 0000000..607e0ad
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11Stream2Tests.java
@@ -0,0 +1,28 @@
+// 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.desugar.desugaredlibrary.jdktests;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class Jdk11Stream2Tests extends Jdk11StreamAbstractTests {
+
+  public Jdk11Stream2Tests(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
+    super(parameters, libraryDesugaringSpecification, compilationSpecification);
+  }
+
+  @Test
+  public void testStream() throws Throwable {
+    testStream(secondHalf(getSuccessfulTests()), secondHalf(getFailingTests()));
+  }
+}
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/Jdk11StreamAbstractTests.java
similarity index 66%
rename from src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11StreamTests.java
rename to src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11StreamAbstractTests.java
index 3b6ae0a..b6b3cb1 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/Jdk11StreamAbstractTests.java
@@ -1,65 +1,88 @@
-// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// 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.desugar.desugaredlibrary.jdktests;
 
 import static com.android.tools.r8.ToolHelper.JDK_TESTS_BUILD_DIR;
+import static com.android.tools.r8.desugar.desugaredlibrary.jdktests.Jdk11Paths.getPathsFiles;
+import static com.android.tools.r8.desugar.desugaredlibrary.jdktests.Jdk11Paths.getSafeVarArgsFile;
+import static com.android.tools.r8.desugar.desugaredlibrary.jdktests.Jdk11Paths.testNGSupportProgramFiles;
+import static com.android.tools.r8.desugar.desugaredlibrary.jdktests.Jdk11TestLibraryDesugaringSpecification.EXTENSION_PATH;
+import static com.android.tools.r8.desugar.desugaredlibrary.jdktests.Jdk11TestLibraryDesugaringSpecification.JDK11_PATH_JAVA_BASE_EXT;
+import static com.android.tools.r8.desugar.desugaredlibrary.jdktests.Jdk11TestLibraryDesugaringSpecification.JDK8_JAVA_BASE_EXT;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8CF2CF_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8SHRINK;
 import static com.android.tools.r8.utils.FileUtils.CLASS_EXTENSION;
 import static com.android.tools.r8.utils.FileUtils.JAVA_EXTENSION;
-import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-import com.android.tools.r8.D8TestCompileResult;
-import com.android.tools.r8.D8TestRunResult;
+import com.android.tools.r8.SingleTestRunResult;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestRuntime;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.DesugaredLibraryTestCompileResult;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
 import java.util.IdentityHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
 import org.junit.Assume;
 import org.junit.BeforeClass;
-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 Jdk11StreamTests extends Jdk11DesugaredLibraryTestBase {
+public abstract class Jdk11StreamAbstractTests extends DesugaredLibraryTestBase {
 
-  private final boolean useCf2Cf;
-  private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
+  final TestParameters parameters;
+  final LibraryDesugaringSpecification libraryDesugaringSpecification;
+  final CompilationSpecification compilationSpecification;
 
-  @Parameters(name = "{2}, shrinkDesugaredLibrary: {0}, useCf2Cf: {1}")
-  public static List<Object[]> data() {
-    // TODO(134732760): Support Dalvik VMs, currently fails because libjavacrypto is required and
-    // present only in ART runtimes.
+  @Parameters(name = "{0}, spec: {1}, {2}")
+  public static List<Object[]> data() throws Exception {
+    List<LibraryDesugaringSpecification> specs;
+    if (ToolHelper.isWindows()) {
+      // The library configuration is not available on windows. Do not run anything.
+      specs = ImmutableList.of();
+    } else {
+      Jdk11TestLibraryDesugaringSpecification.setUp();
+      specs = ImmutableList.of(JDK8_JAVA_BASE_EXT, JDK11_PATH_JAVA_BASE_EXT);
+    }
     return buildParameters(
-        BooleanUtils.values(),
-        BooleanUtils.values(),
+        // TODO(134732760): Support Dalvik VMs, currently fails because libjavacrypto is required
+        // and present only in ART runtimes.
         getTestParameters()
             .withDexRuntimesStartingFromIncluding(Version.V5_1_1)
             .withAllApiLevels()
-            .build());
+            .withApiLevel(AndroidApiLevel.N)
+            .build(),
+        specs,
+        ImmutableList.of(D8_L8DEBUG, D8_L8SHRINK, D8CF2CF_L8DEBUG));
   }
 
-  public Jdk11StreamTests(
-      boolean shrinkDesugaredLibrary, boolean useCf2Cf, TestParameters parameters) {
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
-    this.useCf2Cf = useCf2Cf;
+  public Jdk11StreamAbstractTests(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+    this.compilationSpecification = compilationSpecification;
   }
 
   private static Path JDK_11_STREAM_TEST_CLASSES_DIR;
@@ -154,7 +177,7 @@
       };
 
   private boolean streamCloseTestShouldSucceed() {
-    if (!isJDK11DesugaredLibrary()) {
+    if (libraryDesugaringSpecification == JDK8_JAVA_BASE_EXT) {
       return false;
     }
     // TODO(b/216047740): Investigate if this runs on Dalvik VMs.
@@ -162,9 +185,9 @@
     return parameters.getDexRuntimeVersion().isNewerThan(Version.V4_4_4);
   }
 
-  private Map<String, String> getSuccessfulTests() {
+  Map<String, String> getSuccessfulTests() {
     Map<String, String> runnableTests = getRunnableTests(SUCCESSFUL_RUNNABLE_TESTS);
-    if (isJDK11DesugaredLibrary()) {
+    if (libraryDesugaringSpecification != JDK8_JAVA_BASE_EXT) {
       runnableTests.putAll(getRunnableTests(SUCCESSFUL_RUNNABLE_TESTS_ON_JDK11_ONLY));
       if (parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V7_0_0)) {
         runnableTests.putAll(getRunnableTests(SUCCESSFUL_RUNNABLE_TESTS_ON_JDK11_AND_V7));
@@ -176,9 +199,9 @@
     return runnableTests;
   }
 
-  private Map<String, String> getFailingTests() {
+  Map<String, String> getFailingTests() {
     Map<String, String> runnableTests = getRunnableTests(FAILING_RUNNABLE_TESTS);
-    if (!isJDK11DesugaredLibrary()) {
+    if (libraryDesugaringSpecification == JDK8_JAVA_BASE_EXT) {
       runnableTests.putAll(getRunnableTests(SUCCESSFUL_RUNNABLE_TESTS_ON_JDK11_ONLY));
       runnableTests.putAll(getRunnableTests(SUCCESSFUL_RUNNABLE_TESTS_ON_JDK11_AND_V7));
     } else if (!parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V7_0_0)) {
@@ -227,11 +250,11 @@
             "--add-reads",
             "java.base=ALL-UNNAMED",
             "--patch-module",
-            "java.base=" + JDK_11_JAVA_BASE_EXTENSION_CLASSES_DIR);
+            "java.base=" + EXTENSION_PATH);
     javac(TestRuntime.getCheckedInJdk11(), getStaticTemp())
         .addOptions(options)
         .addClasspathFiles(
-            Collections.singletonList(Paths.get(JDK_TESTS_BUILD_DIR + "testng-6.10.jar")))
+            ImmutableList.of(EXTENSION_PATH, Paths.get(JDK_TESTS_BUILD_DIR + "testng-6.10.jar")))
         .addSourceFiles(getJdk11StreamTestFiles())
         .setOutputPath(JDK_11_STREAM_TEST_CLASSES_DIR)
         .compile();
@@ -240,8 +263,29 @@
     assert JDK_11_STREAM_TEST_COMPILED_FILES.length > 0;
   }
 
-  @Test
-  public void testStream() throws Exception {
+  Map<String, String> firstHalf(Map<String, String> input) {
+    return half(input, true);
+  }
+
+  Map<String, String> secondHalf(Map<String, String> input) {
+    return half(input, false);
+  }
+
+  private Map<String, String> half(Map<String, String> input, boolean first) {
+    ArrayList<String> keys = new ArrayList<>(input.keySet());
+    keys.sort(Comparator.naturalOrder());
+    int length = keys.size();
+    int middle = length / 2 + length % 2;
+    List<String> half = first ? keys.subList(0, middle) : keys.subList(middle, length);
+    HashMap<String, String> newMap = new HashMap<>();
+    for (String key : half) {
+      newMap.put(key, input.get(key));
+    }
+    return newMap;
+  }
+
+  public void testStream(Map<String, String> successes, Map<String, String> failures)
+      throws Throwable {
     Assume.assumeFalse(
         "getAllFilesWithSuffixInDirectory() seems to find different files on Windows",
         ToolHelper.isWindows());
@@ -249,102 +293,58 @@
         "Requires Java base extensions, should add it when not desugaring",
         parameters.getApiLevel().getLevel() < AndroidApiLevel.N.getLevel());
 
-    D8TestCompileResult compileResult = compileStreamTestsToDex(useCf2Cf);
-    runSuccessfulTests(compileResult);
-    runFailingTests(compileResult);
+    DesugaredLibraryTestCompileResult<?> compileResult = compileStreamTestsToDex();
+    runSuccessfulTests(compileResult, successes);
+    runFailingTests(compileResult, failures);
   }
 
-  private D8TestCompileResult compileStreamTestsToDex(boolean cf2cf) throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
+  DesugaredLibraryTestCompileResult<?> compileStreamTestsToDex() throws Exception {
     List<Path> filesToCompile =
         Arrays.stream(JDK_11_STREAM_TEST_COMPILED_FILES)
             .filter(file -> !file.toString().contains("lang/invoke"))
             .collect(Collectors.toList());
-
-    if (cf2cf) {
-      Path jar =
-          testForD8(Backend.CF)
-              .addProgramFiles(filesToCompile)
-              .addProgramFiles(getPathsFiles())
-              .addProgramFiles(getSafeVarArgsFile())
-              .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()
-              .compile()
-              .writeToZip();
-      // Collection keep rules is only implemented in the DEX writer.
-      String desugaredLibraryKeepRules = keepRuleConsumer.get();
-      if (desugaredLibraryKeepRules != null) {
-        assertEquals(0, desugaredLibraryKeepRules.length());
-        desugaredLibraryKeepRules = "-keep class * { *; }";
-      }
-      return testForD8()
-          .addProgramFiles(jar)
-          .setMinApi(parameters.getApiLevel())
-          .disableDesugaring()
-          .compile()
-          .addDesugaredCoreLibraryRunClassPath(
-              this::buildDesugaredLibraryWithJavaBaseExtension,
-              parameters.getApiLevel(),
-              desugaredLibraryKeepRules,
-              shrinkDesugaredLibrary)
-          .withArtFrameworks()
-          .withArt6Plus64BitsLib();
-
-    } else {
-
-      return testForD8()
-          .addProgramFiles(filesToCompile)
-          .addProgramFiles(getPathsFiles())
-          .addProgramFiles(getSafeVarArgsFile())
-          .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()
-          .addDesugaredCoreLibraryRunClassPath(
-              this::buildDesugaredLibraryWithJavaBaseExtension,
-              parameters.getApiLevel(),
-              keepRuleConsumer.get(),
-              shrinkDesugaredLibrary)
-          .withArtFrameworks()
-          .withArt6Plus64BitsLib();
-    }
+    return testForDesugaredLibrary(
+            parameters, libraryDesugaringSpecification, compilationSpecification)
+        .addProgramFiles(filesToCompile)
+        .applyIf(
+            libraryDesugaringSpecification != JDK11_PATH_JAVA_BASE_EXT,
+            b -> b.addProgramFiles(getPathsFiles()))
+        .addProgramFiles(getSafeVarArgsFile())
+        .addProgramFiles(testNGSupportProgramFiles())
+        .addOptionsModification(opt -> opt.testing.trackDesugaredAPIConversions = true)
+        .disableL8AnnotationRemoval()
+        .compile()
+        .withArt6Plus64BitsLib();
   }
 
-  private void runSuccessfulTests(D8TestCompileResult compileResult) throws Exception {
-    String verbosity = "2"; // Increase verbosity for debugging.
-    Map<String, String> runnableTests = getSuccessfulTests();
-    for (String path : runnableTests.keySet()) {
-      assert runnableTests.get(path) != null;
-      D8TestRunResult result =
+  private void runSuccessfulTests(
+      DesugaredLibraryTestCompileResult<?> compileResult, Map<String, String> successes)
+      throws Exception {
+    String verbosity = "2"; // Increase verbosity for debugging.DesugaredLibraryTestBuilder
+    for (String path : successes.keySet()) {
+      assert successes.get(path) != null;
+      SingleTestRunResult<?> result =
           compileResult.run(
-              parameters.getRuntime(), "TestNGMainRunner", verbosity, runnableTests.get(path));
+              parameters.getRuntime(), "TestNGMainRunner", verbosity, successes.get(path));
       assertTrue(
           "Failure in " + path + "\n" + result,
           result
               .getStdOut()
-              .endsWith(
-                  StringUtils.lines("Tests result in " + runnableTests.get(path) + ": SUCCESS")));
+              .endsWith(StringUtils.lines("Tests result in " + successes.get(path) + ": SUCCESS")));
     }
   }
 
-  private void runFailingTests(D8TestCompileResult compileResult) throws Exception {
+  private void runFailingTests(
+      DesugaredLibraryTestCompileResult<?> compileResult, Map<String, String> failures)
+      throws Exception {
     // For failing runnable tests, we just ensure that they do not fail due to desugaring, but
     // due to an expected failure (missing API, etc.).
     String verbosity = "2"; // Increase verbosity for debugging.
-    Map<String, String> runnableTests = getFailingTests();
-    for (String path : runnableTests.keySet()) {
-      assert runnableTests.get(path) != null;
-      D8TestRunResult result =
+    for (String path : failures.keySet()) {
+      assert failures.get(path) != null;
+      SingleTestRunResult<?> result =
           compileResult.run(
-              parameters.getRuntime(), "TestNGMainRunner", verbosity, runnableTests.get(path));
+              parameters.getRuntime(), "TestNGMainRunner", verbosity, failures.get(path));
       String stdout = result.getStdOut();
       if (stdout.contains("java.lang.NoSuchMethodError")
           && Arrays.stream(missingDesugaredMethods()).anyMatch(stdout::contains)) {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TestLibraryDesugaringSpecification.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TestLibraryDesugaringSpecification.java
new file mode 100644
index 0000000..c208900
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TestLibraryDesugaringSpecification.java
@@ -0,0 +1,132 @@
+// 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.desugar.desugaredlibrary.jdktests;
+
+import static com.android.tools.r8.ToolHelper.JDK_TESTS_BUILD_DIR;
+import static com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase.getAllFilesWithSuffixInDirectory;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11_PATH;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8;
+import static com.android.tools.r8.utils.FileUtils.CLASS_EXTENSION;
+import static com.android.tools.r8.utils.FileUtils.JAVA_EXTENSION;
+
+import com.android.tools.r8.JavaCompilerTool;
+import com.android.tools.r8.TestRuntime;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.junit.rules.TemporaryFolder;
+
+public class Jdk11TestLibraryDesugaringSpecification {
+
+  private static final String EXTENSION_STRING = "build/libs/java_base_extension.jar";
+
+  private static Path[] JDK_11_JAVA_BASE_EXTENSION_COMPILED_FILES;
+  private static Path JDK_11_JAVA_BASE_EXTENSION_CLASSES_DIR;
+  private static final Path JDK_11_JAVA_BASE_EXTENSION_FILES_DIR =
+      Paths.get("third_party/openjdk/jdk-11-test/lib/testlibrary/bootlib/java.base");
+
+  public static Path EXTENSION_PATH;
+
+  public static LibraryDesugaringSpecification JDK8_JAVA_BASE_EXT;
+  public static LibraryDesugaringSpecification JDK11_JAVA_BASE_EXT;
+  public static LibraryDesugaringSpecification JDK11_PATH_JAVA_BASE_EXT;
+
+  private static Path[] getJavaBaseExtensionsFiles() throws Exception {
+    Path[] files =
+        getAllFilesWithSuffixInDirectory(JDK_11_JAVA_BASE_EXTENSION_FILES_DIR, JAVA_EXTENSION);
+    assert files.length > 0;
+    return files;
+  }
+
+  public static void setUp() throws Exception {
+    EXTENSION_PATH = Paths.get(EXTENSION_STRING);
+    ensureJavaBaseExtensionsCompiled();
+    JDK8_JAVA_BASE_EXT = createSpecification("JDK8_JAVA_BASE_EXT", JDK8);
+    JDK11_JAVA_BASE_EXT = createSpecification("JDK11_JAVA_BASE_EXT", JDK11);
+    JDK11_PATH_JAVA_BASE_EXT = createSpecification("JDK11_PATH_JAVA_BASE_EXT", JDK11_PATH);
+  }
+
+  private static LibraryDesugaringSpecification createSpecification(
+      String name, LibraryDesugaringSpecification template) {
+    Set<Path> desugaredJDKLibFiles = new HashSet<>(template.getDesugarJdkLibs());
+    desugaredJDKLibFiles.add(EXTENSION_PATH);
+    Set<Path> libFiles = new HashSet<>(template.getLibraryFiles());
+    libFiles.add(EXTENSION_PATH);
+    return new LibraryDesugaringSpecification(
+        name, desugaredJDKLibFiles, template.getSpecification(), libFiles, getTestNGKeepRules());
+  }
+
+  private static synchronized void ensureJavaBaseExtensionsCompiled() throws Exception {
+    if (Files.exists(EXTENSION_PATH)) {
+      return;
+    }
+
+    TemporaryFolder folder =
+        new TemporaryFolder(ToolHelper.isLinux() ? null : Paths.get("build", "tmp").toFile());
+    folder.create();
+    JDK_11_JAVA_BASE_EXTENSION_CLASSES_DIR = folder.newFolder("jdk11JavaBaseExt").toPath();
+    List<String> options =
+        Arrays.asList(
+            "--add-reads",
+            "java.base=ALL-UNNAMED",
+            "--patch-module",
+            "java.base=" + JDK_11_JAVA_BASE_EXTENSION_FILES_DIR);
+    JavaCompilerTool.create(TestRuntime.getCheckedInJdk11(), folder)
+        .addOptions(options)
+        .addClasspathFiles(
+            Collections.singletonList(Paths.get(JDK_TESTS_BUILD_DIR + "testng-6.10.jar")))
+        .addSourceFiles(getJavaBaseExtensionsFiles())
+        .setOutputPath(JDK_11_JAVA_BASE_EXTENSION_CLASSES_DIR)
+        .compile();
+    JDK_11_JAVA_BASE_EXTENSION_COMPILED_FILES =
+        getAllFilesWithSuffixInDirectory(JDK_11_JAVA_BASE_EXTENSION_CLASSES_DIR, CLASS_EXTENSION);
+    assert JDK_11_JAVA_BASE_EXTENSION_COMPILED_FILES.length > 0;
+
+    // Jar the contents.
+    List<String> cmdline = new ArrayList<>();
+    cmdline.add(TestRuntime.getCheckedInJdk11().getJavaExecutable().getParent() + "/jar");
+    cmdline.add("cf");
+    cmdline.add("tmp.jar");
+    for (Path compile : JDK_11_JAVA_BASE_EXTENSION_COMPILED_FILES) {
+      cmdline.add(JDK_11_JAVA_BASE_EXTENSION_CLASSES_DIR.relativize(compile).toString());
+    }
+    ProcessBuilder builder = new ProcessBuilder(cmdline);
+    builder.directory(JDK_11_JAVA_BASE_EXTENSION_CLASSES_DIR.toFile());
+    ProcessResult result = ToolHelper.runProcess(builder);
+    assert result.exitCode == 0;
+
+    // Move the result into the build/libs folder.
+    List<String> cmdlineMv = new ArrayList<>();
+    cmdlineMv.add("mv");
+    cmdlineMv.add(JDK_11_JAVA_BASE_EXTENSION_CLASSES_DIR.resolve("tmp.jar").toString());
+    cmdlineMv.add(EXTENSION_STRING);
+    ProcessResult resultMv = ToolHelper.runProcess(new ProcessBuilder(cmdlineMv));
+    assert resultMv.exitCode == 0;
+
+    folder.delete();
+  }
+
+  private static String getTestNGKeepRules() {
+    // Keep data providers and their annotations.
+    return "-keepclasseswithmembers class * {\n"
+        + "    @org.testng.annotations.DataProvider <methods>;\n"
+        + "}\n"
+        + "-keepattributes *Annotation*\n"
+        // Do not even attempt to shrink testNG (unrelated to desugared lib shrinking goal).
+        + "-keep class org.testng.** { *; }\n"
+        // There are missing classes in testNG.
+        + "-dontwarn";
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeTests.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeAbstractTests.java
similarity index 70%
rename from src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeTests.java
rename to src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeAbstractTests.java
index 9d4ad7e..bc89176 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeTests.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeAbstractTests.java
@@ -1,23 +1,31 @@
-// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// 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.desugar.desugaredlibrary.jdktests;
 
 import static com.android.tools.r8.ToolHelper.JDK_TESTS_BUILD_DIR;
+import static com.android.tools.r8.desugar.desugaredlibrary.jdktests.Jdk11Paths.getPathsFiles;
+import static com.android.tools.r8.desugar.desugaredlibrary.jdktests.Jdk11Paths.testNGSupportProgramFiles;
+import static com.android.tools.r8.desugar.desugaredlibrary.jdktests.Jdk11TestLibraryDesugaringSpecification.EXTENSION_PATH;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8SHRINK;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11_PATH;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8;
 import static com.android.tools.r8.utils.FileUtils.CLASS_EXTENSION;
 import static com.android.tools.r8.utils.FileUtils.JAVA_EXTENSION;
 import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.D8TestCompileResult;
-import com.android.tools.r8.D8TestRunResult;
+import com.android.tools.r8.SingleTestRunResult;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestRuntime;
 import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.DexVm;
 import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.DesugaredLibraryTestCompileResult;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
 import com.google.common.collect.ImmutableList;
 import java.nio.file.Files;
@@ -28,34 +36,12 @@
 import java.util.List;
 import java.util.stream.Collectors;
 import org.junit.BeforeClass;
-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 Jdk11TimeTests extends Jdk11DesugaredLibraryTestBase {
-
-  private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
-
-  @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
-  public static List<Object[]> data() {
-    // TODO(134732760): Support Dalvik VMs, currently fails because libjavacrypto is required and
-    // present only in ART runtimes.
-    return buildParameters(
-        BooleanUtils.values(),
-        getTestParameters()
-            .withDexRuntimesStartingFromIncluding(Version.V5_1_1)
-            .withAllApiLevels()
-            .withApiLevel(AndroidApiLevel.N)
-            .build());
-  }
-
-  public Jdk11TimeTests(boolean shrinkDesugaredLibrary, TestParameters parameters) {
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
-    this.parameters = parameters;
-  }
+public abstract class Jdk11TimeAbstractTests extends DesugaredLibraryTestBase {
 
   private static final Path JDK_11_TCK_TEST_FILES_DIR =
       Paths.get(ToolHelper.JDK_11_TIME_TESTS_DIR).resolve("tck");
@@ -64,6 +50,33 @@
   private static final String JDK_11_TIME_TEST_EXCLUDE = "TestZoneTextPrinterParser.java";
   private static Path[] JDK_11_TIME_TEST_COMPILED_FILES;
 
+  final TestParameters parameters;
+  final LibraryDesugaringSpecification libraryDesugaringSpecification;
+  final CompilationSpecification compilationSpecification;
+
+  @Parameters(name = "{0}, spec: {1}, {2}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        // TODO(134732760): Support Dalvik VMs, currently fails because libjavacrypto is required
+        // and present only in ART runtimes.
+        getTestParameters()
+            .withDexRuntimesStartingFromIncluding(Version.V5_1_1)
+            .withAllApiLevels()
+            .withApiLevel(AndroidApiLevel.N)
+            .build(),
+        ImmutableList.of(JDK8, JDK11_PATH),
+        ImmutableList.of(D8_L8DEBUG, D8_L8SHRINK));
+  }
+
+  public Jdk11TimeAbstractTests(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
+    this.parameters = parameters;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+    this.compilationSpecification = compilationSpecification;
+  }
+
   private static List<Path> getJdk11TimeTestFiles() throws Exception {
     List<Path> tckFiles =
         Files.walk(JDK_11_TCK_TEST_FILES_DIR)
@@ -83,14 +96,14 @@
   }
 
   @BeforeClass
-  public static void compileJdk11StreamTests() throws Exception {
+  public static void compileJdk11TimeTests() throws Exception {
     Path tmpDirectory = getStaticTemp().newFolder("time").toPath();
     List<String> options =
         Arrays.asList(
             "--add-reads",
             "java.base=ALL-UNNAMED",
             "--patch-module",
-            "java.base=" + JDK_11_JAVA_BASE_EXTENSION_CLASSES_DIR);
+            "java.base=" + EXTENSION_PATH);
     javac(TestRuntime.getCheckedInJdk11(), getStaticTemp())
         .addOptions(options)
         .addClasspathFiles(
@@ -107,7 +120,7 @@
 
   // Following tests are also failing on the Bazel build, they cannot be run easily on
   // Android (difference in time precision, iAndroid printing, etc.).
-  private static String[] wontFixFailures =
+  private static final String[] WONT_FIX_FAILURES =
       new String[] {
         "test.java.time.TestZoneTextPrinterParser.java",
         // Removed by gradle (compile-time error).
@@ -132,12 +145,11 @@
         "test.java.time.chrono.TestEraDisplayName",
         "test.java.time.format.TestDateTimeFormatter",
         "test.java.time.TestLocalDate",
-      };
-  private static String[] formattingProblem =
-      new String[] {
+        // Formatting problem
         "test.java.time.format.TestNarrowMonthNamesAndDayNames",
       };
-  private static String[] successes = new String[] {
+  static final String[] RAW_TEMPORAL_SUCCESSES =
+      new String[] {
         "test.java.time.TestYearMonth",
         "test.java.time.TestZonedDateTime",
         "test.java.time.TestClock_Tick",
@@ -148,10 +160,6 @@
         "test.java.time.TestDuration",
         "test.java.time.TestZoneOffset",
         "test.java.time.TestLocalDateTime",
-        "test.java.time.temporal.TestDateTimeBuilderCombinations",
-        "test.java.time.temporal.TestJulianFields",
-        "test.java.time.temporal.TestChronoUnit",
-        "test.java.time.temporal.TestDateTimeValueRange",
         "test.java.time.TestClock_Fixed",
         "test.java.time.TestYear",
         "test.java.time.TestLocalTime",
@@ -159,6 +167,19 @@
         "test.java.time.TestOffsetTime",
         "test.java.time.TestClock_Offset",
         "test.java.time.TestPeriod",
+        "test.java.time.TestClock_System",
+        "test.java.time.TestOffsetDateTime_instants",
+        "test.java.time.temporal.TestDateTimeBuilderCombinations",
+        "test.java.time.temporal.TestJulianFields",
+        "test.java.time.temporal.TestChronoUnit",
+        "test.java.time.temporal.TestDateTimeValueRange"
+      };
+  static final String[] RAW_TEMPORAL_SUCCESSES_IF_BRIDGE =
+      new String[] {"tck.java.time.TestIsoChronology"};
+  static final String[] RAW_TEMPORAL_SUCCESSES_BUT_12 =
+      new String[] {"test.java.time.temporal.TestIsoWeekFields"};
+  static final String[] FORMAT_CHRONO_SUCCESSES =
+      new String[] {
         "test.java.time.format.TestFractionPrinterParser",
         "test.java.time.format.TestStringLiteralParser",
         "test.java.time.format.TestZoneOffsetPrinter",
@@ -170,56 +191,40 @@
         "test.java.time.format.TestZoneOffsetParser",
         "test.java.time.format.TestReducedParser",
         "test.java.time.format.TestDateTimeParsing",
-        "test.java.time.format.TestDateTimeTextProviderWithLocale",
         "test.java.time.format.TestSettingsParser",
         "test.java.time.format.TestNumberParser",
-        "test.java.time.format.TestTextParserWithLocale",
-        "test.java.time.format.TestTextPrinterWithLocale",
         "test.java.time.format.TestReducedPrinter",
         "test.java.time.format.TestCharLiteralParser",
-        "test.java.time.TestOffsetDateTime_instants",
         "test.java.time.chrono.TestChronologyPerf",
         "test.java.time.chrono.TestExampleCode",
         "test.java.time.chrono.TestJapaneseChronology",
         "test.java.time.chrono.TestChronoLocalDate",
         "test.java.time.chrono.TestIsoChronoImpl",
-        "tck.java.time.TestIsoChronology",
-        "test.java.time.TestClock_System",
-        "test.java.time.chrono.TestUmmAlQuraChronology",
-        "test.java.time.temporal.TestIsoWeekFields",
+      };
+  static final String[] FORMAT_CHRONO_SUCCESSES_UP_TO_11 =
+      new String[] {
+        "test.java.time.format.TestDateTimeTextProviderWithLocale",
         "test.java.time.format.TestUnicodeExtension",
         "test.java.time.format.TestDateTimeFormatterBuilderWithLocale",
+        "test.java.time.format.TestTextParserWithLocale",
+        "test.java.time.format.TestTextPrinterWithLocale",
+        "test.java.time.chrono.TestUmmAlQuraChronology",
       };
 
-  @Test
-  public void testTime() throws Exception {
-    if (parameters.getRuntime().asDex().getVm().isEqualTo(DexVm.ART_12_0_0_HOST)) {
-      // TODO(b/197078988): Many additional tests fails with Android 12.
-      return;
-    }
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
+  void testTime(String[] toRun) throws Exception {
     String verbosity = "2";
-    D8TestCompileResult compileResult =
-        testForD8()
-            .addLibraryFiles(getLibraryFile())
-            .addProgramFiles(getPathsFiles())
+    DesugaredLibraryTestCompileResult<?> compileResult =
+        testForDesugaredLibrary(
+                parameters, libraryDesugaringSpecification, compilationSpecification)
             .addProgramFiles(JDK_11_TIME_TEST_COMPILED_FILES)
-            .addProgramFiles(Paths.get(JDK_TESTS_BUILD_DIR + "testng-6.10.jar"))
-            .addProgramFiles(Paths.get(JDK_TESTS_BUILD_DIR + "jcommander-1.48.jar"))
-            .addProgramFiles(
-                Paths.get(
-                    ToolHelper.JAVA_CLASSES_DIR + "examplesTestNGRunner/TestNGMainRunner.class"))
-            .setMinApi(parameters.getApiLevel())
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+            .addProgramFiles(testNGSupportProgramFiles())
+            .applyIf(
+                libraryDesugaringSpecification != JDK11_PATH,
+                b -> b.addProgramFiles(getPathsFiles()))
             .compile()
-            .withArt6Plus64BitsLib()
-            .addDesugaredCoreLibraryRunClassPath(
-                this::buildDesugaredLibrary,
-                parameters.getApiLevel(),
-                keepRuleConsumer.get(),
-                shrinkDesugaredLibrary);
-    for (String success : successes) {
-      D8TestRunResult result =
+            .withArt6Plus64BitsLib();
+    for (String success : toRun) {
+      SingleTestRunResult<?> result =
           compileResult.run(parameters.getRuntime(), "TestNGMainRunner", verbosity, success);
       if (result.getStdErr().contains("Couldn't find any tzdata")) {
         // TODO(b/134732760): fix missing time zone data.
@@ -231,15 +236,5 @@
             result.getStdOut().contains(StringUtils.lines(success + ": SUCCESS")));
       }
     }
-    for (String issue : formattingProblem) {
-      D8TestRunResult result =
-          compileResult.run(parameters.getRuntime(), "TestNGMainRunner", verbosity, issue);
-      if (requiresTimeDesugaring(parameters)) {
-        // Fails due to formatting differences in desugared library.
-        assertTrue(result.getStdOut().contains("for style NARROW"));
-      } else {
-        assertTrue(result.getStdOut().contains(StringUtils.lines(issue + ": SUCCESS")));
-      }
-    }
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeFormatChronoTests.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeFormatChronoTests.java
new file mode 100644
index 0000000..772308e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeFormatChronoTests.java
@@ -0,0 +1,33 @@
+// 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.desugar.desugaredlibrary.jdktests;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class Jdk11TimeFormatChronoTests extends Jdk11TimeAbstractTests {
+
+  public Jdk11TimeFormatChronoTests(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
+    super(parameters, libraryDesugaringSpecification, compilationSpecification);
+  }
+
+  @Test
+  public void testTime() throws Exception {
+    testTime(FORMAT_CHRONO_SUCCESSES);
+    if (parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0)) {
+      // Formatting issues starting from 12.
+      testTime(FORMAT_CHRONO_SUCCESSES_UP_TO_11);
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeRawTemporalTests.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeRawTemporalTests.java
new file mode 100644
index 0000000..2b9b95c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeRawTemporalTests.java
@@ -0,0 +1,42 @@
+// 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.desugar.desugaredlibrary.jdktests;
+
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class Jdk11TimeRawTemporalTests extends Jdk11TimeAbstractTests {
+
+  public Jdk11TimeRawTemporalTests(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
+    super(parameters, libraryDesugaringSpecification, compilationSpecification);
+  }
+
+  @Test
+  public void testTime() throws Exception {
+    testTime(RAW_TEMPORAL_SUCCESSES);
+    if (!parameters.getDexRuntimeVersion().isEqualTo(Version.V12_0_0)) {
+      // In 12 some ISO is supported that other versions do not support.
+      testTime(RAW_TEMPORAL_SUCCESSES_BUT_12);
+    }
+    // The bridge is always present with JDK11 due to partial desugaring between 26 and 33.
+    // On JDK8 the bridge is absent in between 26 and 33.
+    if (libraryDesugaringSpecification != JDK8
+        || !parameters.getApiLevel().betweenBothIncluded(AndroidApiLevel.O, AndroidApiLevel.Sv2)) {
+      testTime(RAW_TEMPORAL_SUCCESSES_IF_BRIDGE);
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/legacy/L8TestWithLegacySpecification.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/legacy/L8TestWithLegacySpecification.java
new file mode 100644
index 0000000..3a6fd81
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/legacy/L8TestWithLegacySpecification.java
@@ -0,0 +1,186 @@
+// 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.desugar.desugaredlibrary.legacy;
+
+import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.L8;
+import com.android.tools.r8.L8Command;
+import com.android.tools.r8.OutputMode;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.FileUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class L8TestWithLegacySpecification extends TestBase {
+
+  @Parameter(0)
+  public AndroidApiLevel apiLevel;
+
+  @Parameter(1)
+  public CompilationMode mode;
+
+  @Parameter(2)
+  public L8KeepRules l8KeepRules;
+
+  @Parameter(3)
+  public TestParameters none;
+
+  @Parameters(name = "{0}, {1}, {2}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        Arrays.stream(AndroidApiLevel.values())
+            .sorted()
+            .filter(apiLevel -> apiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.L))
+            .filter(apiLevel -> apiLevel.isLessThan(AndroidApiLevel.ANDROID_PLATFORM))
+            .collect(Collectors.toList()),
+        CompilationMode.values(),
+        ImmutableList.of(
+            new L8KeepRules("AGP", agp73KeepRules),
+            new L8KeepRules("j$", ImmutableList.of("-keep class j$.** { *; }")),
+            new L8KeepRules("java", ImmutableList.of("-keep class java.** { *; }")),
+            new L8KeepRules(
+                "both",
+                ImmutableList.of("-keep class j$.** { *; }", "-keep class java.** { *; }"))),
+        getTestParameters().withNoneRuntime().build());
+  }
+
+  private static class L8KeepRules {
+
+    private String name;
+    private List<String> keepRules;
+
+    L8KeepRules(String name, List<String> keepRules) {
+      this.name = name;
+      this.keepRules = keepRules;
+    }
+
+    @Override
+    public String toString() {
+      return name;
+    }
+  }
+
+  // Keep rules generated by D8 for an empty app with AGP 7.3.0-aplha09.
+  private static List<String> agp73KeepRules =
+      StringUtils.splitLines(
+          "-keep class j$.util.DesugarTimeZone {\n"
+              + "    java.util.TimeZone getTimeZone(java.lang.String);\n"
+              + "}\n"
+              + "-keep class java.util.function.IntFunction\n"
+              + "-keep class j$.util.concurrent.ConcurrentHashMap {\n"
+              + "    void <init>();\n"
+              + "    java.lang.Object get(java.lang.Object);\n"
+              + "    java.lang.Object put(java.lang.Object, java.lang.Object);\n"
+              + "}\n"
+              + "-keep class j$.util.function.IntFunction$Wrapper {\n"
+              + "    java.util.function.IntFunction convert(j$.util.function.IntFunction);\n"
+              + "}\n"
+              + "-keep class j$.util.function.IntFunction { *; }\n"
+              + "-keep class j$.util.DesugarCollections {\n"
+              + "    java.util.Map synchronizedMap(java.util.Map);\n"
+              + "}\n"
+              + "-keep class java.util.function.Supplier\n"
+              + "-keep class j$.util.function.Supplier$Wrapper {\n"
+              + "    java.util.function.Supplier convert(j$.util.function.Supplier);\n"
+              + "}\n"
+              + "-keep class j$.util.function.Supplier { *; }\n"
+              + "-keep class java.util.function.Consumer\n"
+              + "-keep class j$.util.Collection$-EL {\n"
+              + "    boolean removeIf(java.util.Collection, j$.util.function.Predicate);\n"
+              + "}\n"
+              + "-keep class j$.util.concurrent.ConcurrentHashMap {\n"
+              + "    void <init>();\n"
+              + "    java.lang.Object get(java.lang.Object);\n"
+              + "    java.lang.Object put(java.lang.Object, java.lang.Object);\n"
+              + "}\n"
+              + "-keep class j$.util.function.Consumer$-CC {\n"
+              + "    j$.util.function.Consumer $default$andThen(j$.util.function.Consumer,"
+              + " j$.util.function.Consumer);\n"
+              + "}\n"
+              + "-keep class j$.util.function.Consumer$Wrapper {\n"
+              + "    java.util.function.Consumer convert(j$.util.function.Consumer);\n"
+              + "}\n"
+              + "-keep class j$.util.function.Consumer { *; }\n"
+              + "-keep class j$.util.function.Predicate$-CC {\n"
+              + "    j$.util.function.Predicate $default$and(j$.util.function.Predicate,"
+              + " j$.util.function.Predicate);\n"
+              + "    j$.util.function.Predicate $default$negate(j$.util.function.Predicate);\n"
+              + "    j$.util.function.Predicate $default$or(j$.util.function.Predicate,"
+              + " j$.util.function.Predicate);\n"
+              + "}\n"
+              + "-keep class j$.util.function.Predicate { *; }\n"
+              + "-keep class java.util.function.BiConsumer\n"
+              + "-keep class java.util.function.BiFunction\n"
+              + "-keep class java.util.function.Consumer\n"
+              + "-keep class java.util.function.Function\n"
+              + "-keep class j$.util.Iterator { *; }\n"
+              + "-keep class j$.util.Map$Entry { *; }\n"
+              + "-keep class j$.util.Map { *; }\n"
+              + "-keep class j$.util.Iterator$-CC {\n"
+              + "    void $default$forEachRemaining(java.util.Iterator,"
+              + " j$.util.function.Consumer);\n"
+              + "}\n"
+              + "-keep class j$.util.Map$-CC {\n"
+              + "    java.lang.Object $default$compute(java.util.Map, java.lang.Object,"
+              + " j$.util.function.BiFunction);\n"
+              + "    java.lang.Object $default$computeIfAbsent(java.util.Map, java.lang.Object,"
+              + " j$.util.function.Function);\n"
+              + "    java.lang.Object $default$computeIfPresent(java.util.Map, java.lang.Object,"
+              + " j$.util.function.BiFunction);\n"
+              + "    void $default$forEach(java.util.Map, j$.util.function.BiConsumer);\n"
+              + "    java.lang.Object $default$merge(java.util.Map, java.lang.Object,"
+              + " java.lang.Object, j$.util.function.BiFunction);\n"
+              + "    void $default$replaceAll(java.util.Map, j$.util.function.BiFunction);\n"
+              + "}\n"
+              + "-keep class j$.util.function.BiConsumer$VivifiedWrapper {\n"
+              + "    j$.util.function.BiConsumer convert(java.util.function.BiConsumer);\n"
+              + "}\n"
+              + "-keep class j$.util.function.BiConsumer\n"
+              + "-keep class j$.util.function.BiFunction$VivifiedWrapper {\n"
+              + "    j$.util.function.BiFunction convert(java.util.function.BiFunction);\n"
+              + "}\n"
+              + "-keep class j$.util.function.BiFunction\n"
+              + "-keep class j$.util.function.Consumer$VivifiedWrapper {\n"
+              + "    j$.util.function.Consumer convert(java.util.function.Consumer);\n"
+              + "}\n"
+              + "-keep class j$.util.function.Consumer\n"
+              + "-keep class j$.util.function.Function$VivifiedWrapper {\n"
+              + "    j$.util.function.Function convert(java.util.function.Function);\n"
+              + "}\n"
+              + "-keep class j$.util.function.Function\n");
+
+  @Test
+  public void testL8WithLegacyConfigurationAndStudioKeepRules() throws Exception {
+    L8Command.Builder builder = L8Command.builder();
+    L8Command command =
+        builder
+            .addLibraryFiles(LibraryDesugaringSpecification.JDK11_LEGACY.getLibraryFiles())
+            .addProgramFiles(LibraryDesugaringSpecification.JDK11_LEGACY.getDesugarJdkLibs())
+            .addDesugaredLibraryConfiguration(
+                FileUtils.readTextFile(
+                    LibraryDesugaringSpecification.JDK11_LEGACY.getSpecification(),
+                    StandardCharsets.UTF_8))
+            .addProguardConfiguration(l8KeepRules.keepRules, Origin.unknown())
+            .setMode(mode)
+            .setOutput(temp.newFolder().toPath().resolve("out.jar"), OutputMode.DexIndexed)
+            .setMinApiLevel(apiLevel.getLevel())
+            .build();
+    // TODO(b/231925782): This should succeed for all API levels.
+    L8.run(command);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/EnumSetTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/EnumSetTest.java
index 0752227..6c691dd 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/EnumSetTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/EnumSetTest.java
@@ -4,9 +4,13 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary.shrinkingtests;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
+
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.StringUtils;
 import java.time.DayOfWeek;
 import java.time.chrono.IsoEra;
@@ -22,33 +26,31 @@
 public class EnumSetTest extends DesugaredLibraryTestBase {
 
   private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+  private final CompilationSpecification compilationSpecification;
 
-  @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+        getJdk8Jdk11(),
+        DEFAULT_SPECIFICATIONS);
   }
 
-  public EnumSetTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+  public EnumSetTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+    this.compilationSpecification = compilationSpecification;
   }
 
   @Test
   public void testEnum() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForD8()
-        .addLibraryFiles(getLibraryFile())
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
         .addProgramClasses(EnumSetUser.class)
-        .setMinApi(parameters.getApiLevel())
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-        .compile()
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
+        .addKeepMainRule(EnumSetUser.class)
         .run(parameters.getRuntime(), EnumSetUser.class)
         .assertSuccessWithOutput(StringUtils.lines("2", "0", "1"));
   }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/FieldAccessTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/FieldAccessTest.java
index 7da38d7..3f1c8cb 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/FieldAccessTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/FieldAccessTest.java
@@ -4,9 +4,13 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary.shrinkingtests;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
+
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.StringUtils;
 import java.time.ZoneId;
 import java.util.List;
@@ -19,33 +23,31 @@
 public class FieldAccessTest extends DesugaredLibraryTestBase {
 
   private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+  private final CompilationSpecification compilationSpecification;
 
-  @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+        getJdk8Jdk11(),
+        DEFAULT_SPECIFICATIONS);
   }
 
-  public FieldAccessTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+  public FieldAccessTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+    this.compilationSpecification = compilationSpecification;
   }
 
   @Test
   public void testField() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForD8()
-        .addLibraryFiles(getLibraryFile())
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
         .addProgramClasses(Executor.class)
-        .setMinApi(parameters.getApiLevel())
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-        .compile()
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
+        .addKeepMainRule(Executor.class)
         .run(parameters.getRuntime(), Executor.class)
         .assertSuccessWithOutput(StringUtils.lines("Australia/Darwin"));
   }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/InheritanceTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/InheritanceTest.java
index fd81f26..899bd19 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/InheritanceTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/InheritanceTest.java
@@ -4,9 +4,13 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary.shrinkingtests;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
+
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.utils.StringUtils;
 import java.time.Clock;
 import java.time.Instant;
@@ -21,33 +25,31 @@
 public class InheritanceTest extends DesugaredLibraryTestBase {
 
   private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+  private final CompilationSpecification compilationSpecification;
 
-  @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+        getJdk8Jdk11(),
+        DEFAULT_SPECIFICATIONS);
   }
 
-  public InheritanceTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+  public InheritanceTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+    this.compilationSpecification = compilationSpecification;
   }
 
   @Test
   public void testInheritance() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    testForD8()
-        .addLibraryFiles(getLibraryFile())
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
         .addProgramClasses(Impl.class)
-        .setMinApi(parameters.getApiLevel())
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-        .compile()
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            keepRuleConsumer.get(),
-            shrinkDesugaredLibrary)
+        .addKeepMainRule(Impl.class)
         .run(parameters.getRuntime(), Impl.class)
         .assertSuccessWithOutput(StringUtils.lines("123456"));
   }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/KeepRuleShrinkTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/KeepRuleShrinkTest.java
index 26ccf56..573fd89 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/KeepRuleShrinkTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/KeepRuleShrinkTest.java
@@ -4,10 +4,13 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary.shrinkingtests;
 
-import com.android.tools.r8.D8TestRunResult;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
+
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
@@ -22,37 +25,37 @@
 public class KeepRuleShrinkTest extends DesugaredLibraryTestBase {
 
   private final TestParameters parameters;
-  private final boolean shrinkDesugaredLibrary;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+  private final CompilationSpecification compilationSpecification;
 
-  @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+  @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+        getJdk8Jdk11(),
+        DEFAULT_SPECIFICATIONS);
   }
 
-  public KeepRuleShrinkTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
-    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+  public KeepRuleShrinkTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
     this.parameters = parameters;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+    this.compilationSpecification = compilationSpecification;
   }
 
   @Test
   public void testMapProblem() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    D8TestRunResult d8TestRunResult =
-        testForD8()
-            .addLibraryFiles(getLibraryFile())
+    String stdOut =
+        testForDesugaredLibrary(
+                parameters, libraryDesugaringSpecification, compilationSpecification)
             .addInnerClasses(KeepRuleShrinkTest.class)
-            .setMinApi(parameters.getApiLevel())
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-            .compile()
-            .addDesugaredCoreLibraryRunClassPath(
-                this::buildDesugaredLibrary,
-                parameters.getApiLevel(),
-                keepRuleConsumer.get(),
-                shrinkDesugaredLibrary)
+            .addKeepMainRule(Executor.class)
             .run(parameters.getRuntime(), Executor.class)
-            .assertSuccess();
-    assertLines2By2Correct(d8TestRunResult.getStdOut());
+            .assertSuccess()
+            .getStdOut();
+    assertLines2By2Correct(stdOut);
   }
 
   static class Executor {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/CompilationSpecification.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/CompilationSpecification.java
index 0efcc59..3aecfba 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/CompilationSpecification.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/CompilationSpecification.java
@@ -19,14 +19,12 @@
   R8_L8SHRINK(true, true, false, RELEASE),
   // The D8CFTOCF specifications can run either in CF or be dexed afterwards.
   D8CF2CF_L8DEBUG(false, false, true, DEBUG),
-  // D8CF2CF_L8SHRINK is to be implemented (Only the dex back-end outputs the keep rule).
   D8CF2CF_L8SHRINK(false, true, true, RELEASE);
 
   public static Set<CompilationSpecification> DEFAULT_SPECIFICATIONS =
       ImmutableSet.of(D8_L8DEBUG, D8_L8SHRINK, R8_L8SHRINK);
-  // Add D8CF2CF_L8SHRINK when tracereference is supported.
   public static Set<CompilationSpecification> SPECIFICATIONS_WITH_CF2CF =
-      ImmutableSet.of(D8_L8DEBUG, D8_L8SHRINK, R8_L8SHRINK, D8CF2CF_L8DEBUG);
+      ImmutableSet.of(D8_L8DEBUG, D8_L8SHRINK, R8_L8SHRINK, D8CF2CF_L8DEBUG, D8CF2CF_L8SHRINK);
 
   private final boolean programShrink;
   private final boolean l8Shrink;
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/DesugaredLibraryTestBuilder.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/DesugaredLibraryTestBuilder.java
index 6d777c5..7e11cc5 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/DesugaredLibraryTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/DesugaredLibraryTestBuilder.java
@@ -4,8 +4,11 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary.test;
 
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8CF2CF_L8SHRINK;
+
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.D8TestCompileResult;
+import com.android.tools.r8.FeatureSplit;
 import com.android.tools.r8.L8TestBuilder;
 import com.android.tools.r8.L8TestCompileResult;
 import com.android.tools.r8.LibraryDesugaringTestConfiguration;
@@ -15,17 +18,24 @@
 import com.android.tools.r8.TestBase.Backend;
 import com.android.tools.r8.TestCompileResult;
 import com.android.tools.r8.TestCompilerBuilder;
+import com.android.tools.r8.TestCompilerBuilder.DiagnosticsConsumer;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestRunResult;
 import com.android.tools.r8.TestRuntime;
+import com.android.tools.r8.TestShrinkerBuilder;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
+import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase.KeepRuleConsumer;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser;
+import com.android.tools.r8.tracereferences.TraceReferences;
 import com.android.tools.r8.utils.ConsumerUtils;
+import com.android.tools.r8.utils.FileUtils;
 import com.android.tools.r8.utils.InternalOptions;
+import com.google.common.base.Charsets;
 import java.io.IOException;
 import java.nio.file.Path;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.function.Consumer;
+import java.util.function.Function;
 import org.junit.Assume;
 
 public class DesugaredLibraryTestBuilder<T extends DesugaredLibraryTestBase> {
@@ -35,9 +45,10 @@
   private final LibraryDesugaringSpecification libraryDesugaringSpecification;
   private final CompilationSpecification compilationSpecification;
   private final TestCompilerBuilder<?, ?, ?, ? extends SingleTestRunResult<?>, ?> builder;
+  private Consumer<InternalOptions> l8OptionModifier = ConsumerUtils.emptyConsumer();
+  private boolean l8FinalPrefixVerification = true;
 
   private CustomLibrarySpecification customLibrarySpecification = null;
-  private Consumer<InternalOptions> l8OptionModifier = ConsumerUtils.emptyConsumer();
   private TestingKeepRuleConsumer keepRuleConsumer = null;
 
   public DesugaredLibraryTestBuilder(
@@ -55,15 +66,16 @@
 
   private void setUp() {
     builder
-        .addLibraryFiles(libraryDesugaringSpecification.getAndroidJar())
-        .setMinApi(parameters.getApiLevel());
+        .addLibraryFiles(libraryDesugaringSpecification.getLibraryFiles())
+        .setMinApi(parameters.getApiLevel())
+        .setMode(compilationSpecification.getProgramCompilationMode());
     LibraryDesugaringTestConfiguration.Builder libraryConfBuilder =
         LibraryDesugaringTestConfiguration.builder()
             .setMinApi(parameters.getApiLevel())
             .addDesugaredLibraryConfiguration(
                 StringResource.fromFile(libraryDesugaringSpecification.getSpecification()))
             .dontAddRunClasspath();
-    if (compilationSpecification.isL8Shrink()) {
+    if (compilationSpecification.isL8Shrink() && !compilationSpecification.isCfToCf()) {
       keepRuleConsumer = new TestingKeepRuleConsumer();
       libraryConfBuilder.setKeepRuleConsumer(keepRuleConsumer);
     }
@@ -73,6 +85,10 @@
   private TestCompilerBuilder<?, ?, ?, ? extends SingleTestRunResult<?>, ?> generateBuilder() {
     if (compilationSpecification.isCfToCf()) {
       assert !compilationSpecification.isProgramShrink();
+      if (compilationSpecification.isL8Shrink()) {
+        // L8 with Cf backend and shrinking is not a supported pipeline.
+        Assume.assumeTrue(parameters.getBackend().isDex());
+      }
       return test.testForD8(Backend.CF);
     }
     // Cf back-end is only allowed in Cf to cf compilations.
@@ -113,16 +129,37 @@
     return this;
   }
 
+  public DesugaredLibraryTestBuilder<T> addClasspathClasses(Class<?>... clazz) throws IOException {
+    builder.addClasspathClasses(clazz);
+    return this;
+  }
+
   public DesugaredLibraryTestBuilder<T> addProgramClasses(Class<?>... clazz) throws IOException {
     builder.addProgramClasses(clazz);
     return this;
   }
 
+  public DesugaredLibraryTestBuilder<T> addProgramClasses(Collection<Class<?>> clazz)
+      throws IOException {
+    builder.addProgramClasses(clazz);
+    return this;
+  }
+
   public DesugaredLibraryTestBuilder<T> addProgramFiles(Path... files) {
     builder.addProgramFiles(files);
     return this;
   }
 
+  public DesugaredLibraryTestBuilder<T> addProgramFiles(Collection<Path> files) {
+    builder.addProgramFiles(files);
+    return this;
+  }
+
+  public DesugaredLibraryTestBuilder<T> ignoreL8FinalPrefixVerification() {
+    l8FinalPrefixVerification = false;
+    return this;
+  }
+
   public DesugaredLibraryTestBuilder<T> addProgramClassFileData(
       Collection<byte[]> programClassFileData) {
     builder.addProgramClassFileData(programClassFileData);
@@ -151,11 +188,31 @@
     return this;
   }
 
+  public DesugaredLibraryTestBuilder<T> allowDiagnosticInfoMessages() {
+    withR8TestBuilder(R8TestBuilder::allowDiagnosticInfoMessages);
+    return this;
+  }
+
   public DesugaredLibraryTestBuilder<T> allowDiagnosticWarningMessages() {
     withR8TestBuilder(R8TestBuilder::allowDiagnosticWarningMessages);
     return this;
   }
 
+  public DesugaredLibraryTestBuilder<T> addKeepAttributes(String... attributes) {
+    withR8TestBuilder(b -> b.addKeepAttributes(attributes));
+    return this;
+  }
+
+  public DesugaredLibraryTestBuilder<T> addKeepAllClassesRuleWithAllowObfuscation() {
+    withR8TestBuilder(TestShrinkerBuilder::addKeepAllClassesRuleWithAllowObfuscation);
+    return this;
+  }
+
+  public DesugaredLibraryTestBuilder<T> addKeepAllClassesRule() {
+    withR8TestBuilder(TestShrinkerBuilder::addKeepAllClassesRule);
+    return this;
+  }
+
   public DesugaredLibraryTestBuilder<T> addKeepMainRule(Class<?> clazz) {
     withR8TestBuilder(b -> b.addKeepMainRule(clazz));
     return this;
@@ -171,6 +228,12 @@
     return this;
   }
 
+  public DesugaredLibraryTestBuilder<T> addFeatureSplit(
+      Function<FeatureSplit.Builder, FeatureSplit> featureSplitBuilder) {
+    withR8TestBuilder(b -> b.addFeatureSplit(featureSplitBuilder));
+    return this;
+  }
+
   public DesugaredLibraryTestBuilder<T> enableInliningAnnotations() {
     withR8TestBuilder(R8TestBuilder::enableInliningAnnotations);
     return this;
@@ -189,11 +252,27 @@
     return this;
   }
 
+  public DesugaredLibraryTestBuilder<T> disableL8AnnotationRemoval() {
+    l8OptionModifier =
+        l8OptionModifier.andThen(options -> options.disableL8AnnotationRemoval = true);
+    return this;
+  }
+
   public DesugaredLibraryTestCompileResult<T> compile() throws Exception {
-    // We compile first to generate the keep rules for the l8 compilation.
     TestCompileResult<?, ? extends SingleTestRunResult<?>> compile = builder.compile();
-    String keepRule = keepRuleConsumer == null ? null : keepRuleConsumer.get();
-    L8TestCompileResult l8Compile = compileDesugaredLibrary(keepRule);
+    return internalCompile(compile);
+  }
+
+  public DesugaredLibraryTestCompileResult<T> compileWithExpectedDiagnostics(
+      DiagnosticsConsumer consumer) throws Exception {
+    TestCompileResult<?, ? extends SingleTestRunResult<?>> compile =
+        builder.compileWithExpectedDiagnostics(consumer);
+    return internalCompile(compile);
+  }
+
+  private DesugaredLibraryTestCompileResult<T> internalCompile(
+      TestCompileResult<?, ? extends SingleTestRunResult<?>> compile) throws Exception {
+    L8TestCompileResult l8Compile = compileDesugaredLibrary(compile, keepRuleConsumer);
     D8TestCompileResult customLibCompile = compileCustomLib();
     return new DesugaredLibraryTestCompileResult<>(
         test,
@@ -209,36 +288,81 @@
     if (customLibrarySpecification == null) {
       return null;
     }
-    return test.testForD8()
+    return test.testForD8(parameters.getBackend())
         .addProgramClasses(customLibrarySpecification.getClasses())
         .setMinApi(customLibrarySpecification.getMinApi())
         .compile();
   }
 
+  private L8TestCompileResult compileDesugaredLibrary(
+      TestCompileResult<?, ? extends SingleTestRunResult<?>> compile,
+      KeepRuleConsumer keepRuleConsumer)
+      throws Exception {
+    if (!compilationSpecification.isL8Shrink()) {
+      return compileDesugaredLibrary(null);
+    }
+    if (!compilationSpecification.isCfToCf()) {
+      // When going to dex we can get the generated keep rule through the keep rule consumer.
+      assert keepRuleConsumer != null;
+      return compileDesugaredLibrary(keepRuleConsumer.get());
+    }
+    // In D8CF2CF_L8SHRINK, we use trace reference to extract the keep rules.
+    assert compilationSpecification == D8CF2CF_L8SHRINK;
+    L8TestCompileResult nonShrunk =
+        test.testForL8(parameters.getApiLevel(), Backend.CF)
+            .apply(libraryDesugaringSpecification::configureL8TestBuilder)
+            .apply(this::configure)
+            .compile();
+    String keepRules =
+        collectKeepRulesWithTraceReferences(compile.writeToZip(), nonShrunk.writeToZip());
+    return compileDesugaredLibrary(keepRules);
+  }
+
   private L8TestCompileResult compileDesugaredLibrary(String keepRule) throws Exception {
+    assert !compilationSpecification.isL8Shrink() || keepRule != null;
     return test.testForL8(parameters.getApiLevel(), parameters.getBackend())
-        .addProgramFiles(libraryDesugaringSpecification.getDesugarJdkLibs())
-        .addLibraryFiles(libraryDesugaringSpecification.getAndroidJar())
-        .setDesugaredLibraryConfiguration(libraryDesugaringSpecification.getSpecification())
-        .noDefaultDesugarJDKLibs()
-        .applyIf(
-            compilationSpecification.isL8Shrink(),
-            builder -> {
-              if (keepRule != null && !keepRule.trim().isEmpty()) {
-                builder.addGeneratedKeepRules(keepRule);
-              }
-            },
-            L8TestBuilder::setDebug)
-        .addOptionsModifier(l8OptionModifier)
+        .apply(
+            b ->
+                libraryDesugaringSpecification.configureL8TestBuilder(
+                    b, compilationSpecification.isL8Shrink(), keepRule))
+        .apply(this::configure)
         .compile();
   }
 
-  public TestRunResult<?> run(TestRuntime runtime, Class<?> mainClass, String... args)
+  private void configure(L8TestBuilder l8Builder) {
+    l8Builder
+        .applyIf(!l8FinalPrefixVerification, L8TestBuilder::ignoreFinalPrefixVerification)
+        .addOptionsModifier(l8OptionModifier);
+  }
+
+  public String collectKeepRulesWithTraceReferences(
+      Path desugaredProgramClassFile, Path desugaredLibraryClassFile) throws Exception {
+    Path generatedKeepRules = test.temp.newFile().toPath();
+    ArrayList<String> args = new ArrayList<>();
+    args.add("--keep-rules");
+    for (Path libraryFile : libraryDesugaringSpecification.getLibraryFiles()) {
+      args.add("--lib");
+      args.add(libraryFile.toString());
+    }
+    args.add("--target");
+    args.add(desugaredLibraryClassFile.toString());
+    args.add("--source");
+    args.add(desugaredProgramClassFile.toString());
+    args.add("--output");
+    args.add(generatedKeepRules.toString());
+    args.add("--map-diagnostics");
+    args.add("error");
+    args.add("info");
+    TraceReferences.run(args.toArray(new String[0]));
+    return FileUtils.readTextFile(generatedKeepRules, Charsets.UTF_8);
+  }
+
+  public SingleTestRunResult<?> run(TestRuntime runtime, Class<?> mainClass, String... args)
       throws Exception {
     return compile().run(runtime, mainClass.getTypeName(), args);
   }
 
-  public TestRunResult<?> run(TestRuntime runtime, String mainClass, String... args)
+  public SingleTestRunResult<?> run(TestRuntime runtime, String mainClass, String... args)
       throws Exception {
     return compile().run(runtime, mainClass, args);
   }
@@ -269,4 +393,9 @@
     builder.addAndroidBuildVersion();
     return this;
   }
+
+  public DesugaredLibraryTestBuilder<T> disableDesugaring() {
+    builder.disableDesugaring();
+    return this;
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/DesugaredLibraryTestCompileResult.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/DesugaredLibraryTestCompileResult.java
index ec53bdf..bd11465 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/DesugaredLibraryTestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/DesugaredLibraryTestCompileResult.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary.test;
 
+import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.D8TestCompileResult;
 import com.android.tools.r8.L8TestCompileResult;
 import com.android.tools.r8.SingleTestRunResult;
@@ -16,8 +17,6 @@
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import java.io.IOException;
 import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 import java.util.function.Consumer;
 
@@ -30,7 +29,9 @@
   private final CompilationSpecification compilationSpecification;
   private final D8TestCompileResult customLibCompile;
   private final L8TestCompileResult l8Compile;
-  private final List<Path> runClasspathFiles = new ArrayList<>();
+  // In case of Cf2Cf desugaring the run on dex, the compileResult is the Cf desugaring result
+  // while the runnableCompiledResult is the dexed compiledResult used to run on dex.
+  private final TestCompileResult<?, ? extends SingleTestRunResult<?>> runnableCompiledResult;
 
   public DesugaredLibraryTestCompileResult(
       T test,
@@ -39,7 +40,8 @@
       LibraryDesugaringSpecification libraryDesugaringSpecification,
       CompilationSpecification compilationSpecification,
       D8TestCompileResult customLibCompile,
-      L8TestCompileResult l8Compile) {
+      L8TestCompileResult l8Compile)
+      throws Exception {
     this.test = test;
     this.compileResult = compileResult;
     this.parameters = parameters;
@@ -47,6 +49,7 @@
     this.compilationSpecification = compilationSpecification;
     this.customLibCompile = customLibCompile;
     this.l8Compile = l8Compile;
+    this.runnableCompiledResult = computeRunnableCompiledResult();
   }
 
   public <E extends Throwable> DesugaredLibraryTestCompileResult<T> inspectCustomLib(
@@ -68,6 +71,14 @@
     return this;
   }
 
+  public <E extends Throwable> DesugaredLibraryTestCompileResult<T> inspectKeepRules(
+      ThrowingConsumer<List<String>, E> consumer) throws Throwable {
+    if (compilationSpecification.isL8Shrink()) {
+      l8Compile.inspectKeepRules(consumer);
+    }
+    return this;
+  }
+
   public <E extends Throwable> DesugaredLibraryTestCompileResult<T> apply(
       ThrowingConsumer<DesugaredLibraryTestCompileResult<T>, E> consumer) throws Throwable {
     consumer.accept(this);
@@ -100,48 +111,52 @@
 
   public SingleTestRunResult<?> run(TestRuntime runtime, String mainClassName, String... args)
       throws Exception {
-
-    Path desugaredLibrary = l8Compile.writeToZip();
-
-    if (runtime.getBackend().isCf()) {
-      assert compilationSpecification.isCfToCf();
-      return compileResult.addRunClasspathFiles(desugaredLibrary).run(runtime, mainClassName);
-    }
-
-    TestCompileResult<?, ? extends SingleTestRunResult<?>> actualCompileResult =
-        compilationSpecification.isCfToCf() ? convertCompileResultToDex() : compileResult;
-
-    if (customLibCompile != null) {
-      actualCompileResult.addRunClasspathFiles(customLibCompile.writeToZip());
-    }
-
-    actualCompileResult
-        .addRunClasspathFiles(desugaredLibrary)
-        .addRunClasspathFiles(runClasspathFiles);
-
-    return actualCompileResult.run(runtime, mainClassName, args);
+    return runnableCompiledResult.run(runtime, mainClassName, args);
   }
 
-  private TestCompileResult<?, ? extends SingleTestRunResult<?>> convertCompileResultToDex()
+  private TestCompileResult<?, ? extends SingleTestRunResult<?>> computeRunnableCompiledResult()
       throws Exception {
+    TestCompileResult<?, ? extends SingleTestRunResult<?>> runnable = convertToDexIfNeeded();
+    if (customLibCompile != null) {
+      runnable.addRunClasspathFiles(customLibCompile.writeToZip());
+    }
+    runnable.addRunClasspathFiles(l8Compile.writeToZip());
+    return runnable;
+  }
+
+  private TestCompileResult<?, ? extends SingleTestRunResult<?>> convertToDexIfNeeded()
+      throws CompilationFailedException, IOException {
+    if (!(compilationSpecification.isCfToCf() && parameters.getBackend().isDex())) {
+      return compileResult;
+    }
     return test.testForD8()
-        .addProgramFiles(compileResult.writeToZip())
+        .addProgramFiles(this.compileResult.writeToZip())
         .setMinApi(parameters.getApiLevel())
+        .setMode(compilationSpecification.getProgramCompilationMode())
         .disableDesugaring()
         .compile();
   }
 
   public Path writeToZip() throws IOException {
-    return compileResult.writeToZip();
+    return runnableCompiledResult.writeToZip();
+  }
+
+  public DesugaredLibraryTestCompileResult<T> writeToZip(Path path) throws IOException {
+    runnableCompiledResult.writeToZip(path);
+    return this;
+  }
+
+  public Path writeL8ToZip() throws IOException {
+    return l8Compile.writeToZip();
   }
 
   public DesugaredLibraryTestCompileResult<T> addRunClasspathFiles(Path... classpathFiles) {
-    Collections.addAll(runClasspathFiles, classpathFiles);
+    runnableCompiledResult.addRunClasspathFiles(classpathFiles);
     return this;
   }
 
   public DesugaredLibraryTestCompileResult<T> withArt6Plus64BitsLib() {
-    compileResult.withArt6Plus64BitsLib();
+    runnableCompiledResult.withArt6Plus64BitsLib();
     return this;
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java
index 81415f7..d4e8e32 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java
@@ -1,9 +1,12 @@
 // 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.desugar.desugaredlibrary.test;
 
+import static com.android.tools.r8.ToolHelper.DESUGARED_JDK_8_LIB_JAR;
+import static com.android.tools.r8.ToolHelper.DESUGARED_LIB_RELEASES_DIR;
+
+import com.android.tools.r8.L8TestBuilder;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.jdk11.DesugaredLibraryJDK11Undesugarer;
 import com.android.tools.r8.utils.AndroidApiLevel;
@@ -17,79 +20,103 @@
 public class LibraryDesugaringSpecification {
 
   private static final String RELEASES_DIR = "third_party/openjdk/desugar_jdk_libs_releases/";
-  private static final Path DESUGARED_JDK_11_LIB_JAR =
+  private static final Path UNDESUGARED_JDK_11_LIB_JAR =
       DesugaredLibraryJDK11Undesugarer.undesugaredJarJDK11(
           Paths.get("third_party/openjdk/desugar_jdk_libs_11/desugar_jdk_libs.jar"));
 
   // Main head specifications.
   public static LibraryDesugaringSpecification JDK8 =
       new LibraryDesugaringSpecification(
-          "JDK8",
-          Paths.get("third_party/openjdk/desugar_jdk_libs/desugar_jdk_libs.jar"),
-          Paths.get("src/library_desugar/desugar_jdk_libs.json"));
+          "JDK8", DESUGARED_JDK_8_LIB_JAR, "desugar_jdk_libs.json", AndroidApiLevel.P);
   public static LibraryDesugaringSpecification JDK11 =
       new LibraryDesugaringSpecification(
-          "JDK11",
-          DESUGARED_JDK_11_LIB_JAR,
-          Paths.get("src/library_desugar/jdk11/desugar_jdk_libs.json"));
+          "JDK11", UNDESUGARED_JDK_11_LIB_JAR, "jdk11/desugar_jdk_libs.json", AndroidApiLevel.R);
   public static LibraryDesugaringSpecification JDK11_MINIMAL =
       new LibraryDesugaringSpecification(
           "JDK11_MINIMAL",
-          DESUGARED_JDK_11_LIB_JAR,
-          Paths.get("src/library_desugar/jdk11/desugar_jdk_libs_minimal.json"));
+          UNDESUGARED_JDK_11_LIB_JAR,
+          "jdk11/desugar_jdk_libs_minimal.json",
+          AndroidApiLevel.R);
   public static LibraryDesugaringSpecification JDK11_PATH =
       new LibraryDesugaringSpecification(
           "JDK11_PATH",
-          DESUGARED_JDK_11_LIB_JAR,
-          Paths.get("src/library_desugar/jdk11/desugar_jdk_libs_path.json"));
+          UNDESUGARED_JDK_11_LIB_JAR,
+          "jdk11/desugar_jdk_libs_path.json",
+          AndroidApiLevel.R);
 
   // Legacy specifications.
   public static LibraryDesugaringSpecification JDK11_PATH_ALTERNATIVE_3 =
       new LibraryDesugaringSpecification(
           "JDK11_PATH_ALTERNATIVE_3",
-          DESUGARED_JDK_11_LIB_JAR,
-          Paths.get("src/library_desugar/jdk11/desugar_jdk_libs_path_alternative_3.json"));
+          UNDESUGARED_JDK_11_LIB_JAR,
+          "jdk11/desugar_jdk_libs_path_alternative_3.json",
+          AndroidApiLevel.R);
+  public static LibraryDesugaringSpecification JDK11_CHM_ONLY =
+      new LibraryDesugaringSpecification(
+          "JDK11_CHM_ONLY",
+          UNDESUGARED_JDK_11_LIB_JAR,
+          "jdk11/chm_only_desugar_jdk_libs.json",
+          AndroidApiLevel.R);
   public static LibraryDesugaringSpecification JDK11_LEGACY =
       new LibraryDesugaringSpecification(
-          "DESUGARED_JDK_11_LIB_JAR",
-          DESUGARED_JDK_11_LIB_JAR,
-          Paths.get("src/library_desugar/jdk11/desugar_jdk_libs_legacy.json"));
-  private static final LibraryDesugaringSpecification RELEASED_1_0_9 =
-      new LibraryDesugaringSpecification("1.0.9");
-  private static final LibraryDesugaringSpecification RELEASED_1_0_10 =
-      new LibraryDesugaringSpecification("1.0.10");
-  private static final LibraryDesugaringSpecification RELEASED_1_1_0 =
-      new LibraryDesugaringSpecification("1.1.0");
-  private static final LibraryDesugaringSpecification RELEASED_1_1_1 =
-      new LibraryDesugaringSpecification("1.1.1");
-  private static final LibraryDesugaringSpecification RELEASED_1_1_5 =
-      new LibraryDesugaringSpecification("1.1.5");
-
+          "JDK11_LEGACY",
+          // The legacy specification is not using the undesugared JAR.
+          Paths.get("third_party/openjdk/desugar_jdk_libs_11/desugar_jdk_libs.jar"),
+          "jdk11/desugar_jdk_libs_legacy.json",
+          AndroidApiLevel.R);
+  public static final LibraryDesugaringSpecification RELEASED_1_0_9 =
+      new LibraryDesugaringSpecification("1.0.9", AndroidApiLevel.P);
+  public static final LibraryDesugaringSpecification RELEASED_1_0_10 =
+      new LibraryDesugaringSpecification("1.0.10", AndroidApiLevel.P);
+  public static final LibraryDesugaringSpecification RELEASED_1_1_0 =
+      new LibraryDesugaringSpecification("1.1.0", AndroidApiLevel.P);
+  public static final LibraryDesugaringSpecification RELEASED_1_1_1 =
+      new LibraryDesugaringSpecification("1.1.1", AndroidApiLevel.P);
+  public static final LibraryDesugaringSpecification RELEASED_1_1_5 =
+      new LibraryDesugaringSpecification("1.1.5", AndroidApiLevel.P);
   private final String name;
   private final Set<Path> desugarJdkLibs;
   private final Path specification;
+  private final Set<Path> libraryFiles;
+  private final String extraKeepRules;
 
-  LibraryDesugaringSpecification(String name, Path desugarJdkLibs, Path specification) {
-    this(name, ImmutableSet.of(desugarJdkLibs, ToolHelper.DESUGAR_LIB_CONVERSIONS), specification);
+  private LibraryDesugaringSpecification(
+      String name, Path desugarJdkLibs, String specificationPath, AndroidApiLevel androidJarLevel) {
+    this(
+        name,
+        ImmutableSet.of(desugarJdkLibs, ToolHelper.DESUGAR_LIB_CONVERSIONS),
+        Paths.get("src/library_desugar/" + specificationPath),
+        ToolHelper.getAndroidJar(androidJarLevel));
   }
 
-  public LibraryDesugaringSpecification(String name, Path specification) {
-    this(name, DESUGARED_JDK_11_LIB_JAR, specification);
+  // This can be used to build custom specifications for testing purposes.
+  public LibraryDesugaringSpecification(
+      String name, Set<Path> desugarJdkLibs, Path specification, Path androidJar) {
+    this(name, desugarJdkLibs, specification, ImmutableSet.of(androidJar), "");
   }
 
-  public LibraryDesugaringSpecification(String name, Set<Path> desugarJdkLibs, Path specification) {
+  // This can be used to build custom specifications for testing purposes.
+  public LibraryDesugaringSpecification(
+      String name,
+      Set<Path> desugarJdkLibs,
+      Path specification,
+      Set<Path> libraryFiles,
+      String extraKeepRules) {
     this.name = name;
     this.desugarJdkLibs = desugarJdkLibs;
     this.specification = specification;
+    this.libraryFiles = libraryFiles;
+    this.extraKeepRules = extraKeepRules;
   }
 
-  LibraryDesugaringSpecification(String version) {
+  private LibraryDesugaringSpecification(String version, AndroidApiLevel androidJarLevel) {
     this(
-        "Release_" + version,
+        "RELEASED_" + version,
         ImmutableSet.of(
-            Paths.get(RELEASES_DIR, version, "desugar_jdk_libs.jar"),
-            Paths.get(RELEASES_DIR, version, "desugar_jdk_libs_configuration.jar")),
-        Paths.get(RELEASES_DIR, version, "desugar.json"));
+            Paths.get(DESUGARED_LIB_RELEASES_DIR, version, "desugar_jdk_libs.jar"),
+            Paths.get(DESUGARED_LIB_RELEASES_DIR, version, "desugar_jdk_libs_configuration.jar")),
+        Paths.get(DESUGARED_LIB_RELEASES_DIR, version, "desugar.json"),
+        ToolHelper.getAndroidJar(androidJarLevel));
   }
 
   @Override
@@ -105,11 +132,34 @@
     return specification;
   }
 
-  public Path getAndroidJar() {
-    if (this == JDK8) {
-      return ToolHelper.getAndroidJar(AndroidApiLevel.P);
-    }
-    return ToolHelper.getAndroidJar(AndroidApiLevel.R);
+  public Set<Path> getLibraryFiles() {
+    return libraryFiles;
+  }
+
+  public String getExtraKeepRules() {
+    return extraKeepRules;
+  }
+
+  public void configureL8TestBuilder(L8TestBuilder l8TestBuilder) {
+    configureL8TestBuilder(l8TestBuilder, false, "");
+  }
+
+  public void configureL8TestBuilder(
+      L8TestBuilder l8TestBuilder, boolean l8Shrink, String keepRule) {
+    l8TestBuilder
+        .addProgramFiles(getDesugarJdkLibs())
+        .addLibraryFiles(getLibraryFiles())
+        .setDesugaredLibraryConfiguration(getSpecification())
+        .noDefaultDesugarJDKLibs()
+        .applyIf(
+            l8Shrink,
+            builder -> {
+              if (keepRule != null && !keepRule.trim().isEmpty()) {
+                String totalKeepRules = keepRule + "\n" + getExtraKeepRules();
+                builder.addGeneratedKeepRules(totalKeepRules);
+              }
+            },
+            L8TestBuilder::setDebug);
   }
 
   public static List<LibraryDesugaringSpecification> getReleased() {
diff --git a/src/test/java/com/android/tools/r8/desugar/twr/CheckTwrOutputForJavaCompilersTest.java b/src/test/java/com/android/tools/r8/desugar/twr/CheckTwrOutputForJavaCompilersTest.java
new file mode 100644
index 0000000..baf39e2
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/twr/CheckTwrOutputForJavaCompilersTest.java
@@ -0,0 +1,105 @@
+// 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.desugar.twr;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.google.common.collect.ImmutableSet;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class CheckTwrOutputForJavaCompilersTest extends TestBase {
+
+  static final String EXPECTED = StringUtils.lines("no file", "no file");
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withCfRuntimes().build();
+  }
+
+  public CheckTwrOutputForJavaCompilersTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  /**
+   * Test to document that the special $closeResource synthesis is only being done in JDK9.
+   *
+   * <p>If this ever fails we will need to verify if the same AutoClosable issues might occur and
+   * amend the tests in the source-sets specific to that JDK version.
+   *
+   * <p>This test is not parameterized over DEX VMs as it primarily to check the javac behavior. The
+   * testing of the JDK9 code and its desugaring on the DEX VM and API level matrix is thus confined
+   * to just the JDK9 input defined in the source-set tests for JDK9.
+   */
+  @Test
+  public void test() throws Exception {
+    Path javacOut =
+        javac(parameters.getRuntime().asCf())
+            .addSourceFiles(ToolHelper.getSourceFileForTestClass(TwrTestSource.class))
+            .compile();
+    testForJvm()
+        .addProgramFiles(javacOut)
+        .run(parameters.getRuntime(), TwrTestSource.class)
+        .assertSuccessWithOutput(EXPECTED)
+        .inspect(this::checkUseOfCloseResource);
+    testForD8(parameters.getBackend())
+        .setMinApi(AndroidApiLevel.B)
+        .addProgramFiles(javacOut)
+        .run(parameters.getRuntime(), TwrTestSource.class)
+        .assertSuccessWithOutput(EXPECTED)
+        .inspect(this::checkNoUseOfCloseResource);
+  }
+
+  private void checkUseOfCloseResource(CodeInspector inspector) {
+    Set<String> methods =
+        inspector.clazz(TwrTestSource.class).allMethods().stream()
+            .map(m -> m.getMethod().getName().toString())
+            .collect(Collectors.toSet());
+    Set<InstructionSubject> callsToCloseResource = getCallsToCloseResource(inspector);
+    if (parameters.isCfRuntime(CfVm.JDK9)) {
+      assertEquals(ImmutableSet.of("<init>", "main", "$closeResource"), methods);
+      assertEquals(4, callsToCloseResource.size());
+    } else {
+      assertEquals(ImmutableSet.of("<init>", "main"), methods);
+      assertEquals(Collections.emptySet(), callsToCloseResource);
+    }
+  }
+
+  private void checkNoUseOfCloseResource(CodeInspector inspector) {
+    Set<InstructionSubject> callsToCloseResource = getCallsToCloseResource(inspector);
+    assertEquals(Collections.emptySet(), callsToCloseResource);
+  }
+
+  private Set<InstructionSubject> getCallsToCloseResource(CodeInspector inspector) {
+    Set<InstructionSubject> callsToCloseResource = new HashSet<>();
+    inspector.forAllClasses(
+        c ->
+            c.forAllMethods(
+                m ->
+                    callsToCloseResource.addAll(
+                        m.streamInstructions()
+                            .filter(InstructionSubject::isInvoke)
+                            .filter(i -> i.getMethod().qualifiedName().contains("$closeResource"))
+                            .collect(Collectors.toSet()))));
+    return callsToCloseResource;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/twr/TwrCloseResourceDuplicationTest.java b/src/test/java/com/android/tools/r8/desugar/twr/TwrCloseResourceDuplicationTest.java
index de907e5..dd43eb9 100644
--- a/src/test/java/com/android/tools/r8/desugar/twr/TwrCloseResourceDuplicationTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/twr/TwrCloseResourceDuplicationTest.java
@@ -11,6 +11,7 @@
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.TestRuntime.CfVm;
 import com.android.tools.r8.examples.JavaExampleClassProxy;
+import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.ZipUtils;
 import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
@@ -32,11 +33,11 @@
   private static final String PKG = "twrcloseresourceduplication";
   private static final String EXAMPLE = "examplesJava9/" + PKG;
   private final JavaExampleClassProxy MAIN =
-      new JavaExampleClassProxy(EXAMPLE, PKG + ".TwrCloseResourceDuplication");
+      new JavaExampleClassProxy(EXAMPLE, PKG + "/TwrCloseResourceDuplication");
   private final JavaExampleClassProxy FOO =
-      new JavaExampleClassProxy(EXAMPLE, PKG + ".TwrCloseResourceDuplication$Foo");
+      new JavaExampleClassProxy(EXAMPLE, PKG + "/TwrCloseResourceDuplication$Foo");
   private final JavaExampleClassProxy BAR =
-      new JavaExampleClassProxy(EXAMPLE, PKG + ".TwrCloseResourceDuplication$Bar");
+      new JavaExampleClassProxy(EXAMPLE, PKG + "/TwrCloseResourceDuplication$Bar");
 
   static final int INPUT_CLASSES = 3;
 
@@ -139,9 +140,13 @@
                   ImmutableSet.of(FOO.typeName(), BAR.typeName(), MAIN.typeName());
               if (parameters.getApiLevel().isLessThan(apiLevelWithTwrCloseResourceSupport())) {
                 Set<String> classOutputWithSynthetics = new HashSet<>(nonSyntheticClassOutput);
-                classOutputWithSynthetics.add(BAR.typeName() + "$$ExternalSyntheticBackport0");
                 classOutputWithSynthetics.add(
-                    BAR.typeName() + "$$ExternalSyntheticTwrCloseResource1");
+                    SyntheticItemsTestUtils.syntheticBackportClass(BAR.getClassReference(), 0)
+                        .getTypeName());
+                classOutputWithSynthetics.add(
+                    SyntheticItemsTestUtils.syntheticTwrCloseResourceClass(
+                            BAR.getClassReference(), 1)
+                        .getTypeName());
                 assertEquals(classOutputWithSynthetics, foundClasses);
               } else {
                 assertEquals(nonSyntheticClassOutput, foundClasses);
diff --git a/src/test/java/com/android/tools/r8/desugar/twr/TwrTestSource.java b/src/test/java/com/android/tools/r8/desugar/twr/TwrTestSource.java
new file mode 100644
index 0000000..c256929
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/twr/TwrTestSource.java
@@ -0,0 +1,24 @@
+// 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.desugar.twr;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.jar.JarFile;
+
+public class TwrTestSource {
+
+  public static void main(String[] args) throws IOException {
+    try (JarFile f = new JarFile(args.length > 0 ? args[0] : "")) {
+      System.out.println(f.stream().count());
+    } catch (FileNotFoundException e) {
+      System.out.println("no file");
+    }
+    try (JarFile f = new JarFile(args.length > 0 ? args[0] : "")) {
+      System.out.println(f.stream().count());
+    } catch (FileNotFoundException e) {
+      System.out.println("no file");
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java b/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java
index 066e758..90cf068 100644
--- a/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java
+++ b/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java
@@ -18,7 +18,6 @@
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.synthesis.SyntheticItems.GlobalSyntheticsStrategy;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.Reporter;
@@ -52,7 +51,6 @@
                 GlobalSyntheticsStrategy.forNonSynthesizing()));
     return new ObjectToOffsetMapping(
         appView,
-        NamingLens.getIdentityLens(),
         new LensCodeRewriterUtils(appView),
         Collections.emptyList(),
         Collections.emptyList(),
diff --git a/src/test/java/com/android/tools/r8/dex/JumboStringProcessing.java b/src/test/java/com/android/tools/r8/dex/JumboStringProcessing.java
index ce5a517..bf49805 100644
--- a/src/test/java/com/android/tools/r8/dex/JumboStringProcessing.java
+++ b/src/test/java/com/android/tools/r8/dex/JumboStringProcessing.java
@@ -7,16 +7,16 @@
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.code.Const4;
-import com.android.tools.r8.code.ConstString;
-import com.android.tools.r8.code.ConstStringJumbo;
-import com.android.tools.r8.code.Goto32;
-import com.android.tools.r8.code.IfEq;
-import com.android.tools.r8.code.IfEqz;
-import com.android.tools.r8.code.IfNe;
-import com.android.tools.r8.code.IfNez;
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.ReturnVoid;
+import com.android.tools.r8.dex.code.DexConst4;
+import com.android.tools.r8.dex.code.DexConstString;
+import com.android.tools.r8.dex.code.DexConstStringJumbo;
+import com.android.tools.r8.dex.code.DexGoto32;
+import com.android.tools.r8.dex.code.DexIfEq;
+import com.android.tools.r8.dex.code.DexIfEqz;
+import com.android.tools.r8.dex.code.DexIfNe;
+import com.android.tools.r8.dex.code.DexIfNez;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexReturnVoid;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.graph.DexCode.Try;
 import com.android.tools.r8.graph.DexCode.TryHandler;
@@ -42,15 +42,15 @@
   public void branching() {
     DexItemFactory factory = new DexItemFactory();
     DexString string = factory.createString("turn into jumbo");
-    Instruction[] instructions = buildInstructions(string, false);
+    DexInstruction[] instructions = buildInstructions(string, false);
     DexCode code = jumboStringProcess(factory, string, instructions);
-    Instruction[] rewrittenInstructions = code.instructions;
-    assert rewrittenInstructions[1] instanceof IfEq;
-    IfEq condition = (IfEq) rewrittenInstructions[1];
+    DexInstruction[] rewrittenInstructions = code.instructions;
+    assert rewrittenInstructions[1] instanceof DexIfEq;
+    DexIfEq condition = (DexIfEq) rewrittenInstructions[1];
     assert condition.getOffset() + condition.CCCC == rewrittenInstructions[3].getOffset();
-    assert rewrittenInstructions[2] instanceof Goto32;
-    Goto32 jump = (Goto32) rewrittenInstructions[2];
-    Instruction lastInstruction = rewrittenInstructions[rewrittenInstructions.length - 1];
+    assert rewrittenInstructions[2] instanceof DexGoto32;
+    DexGoto32 jump = (DexGoto32) rewrittenInstructions[2];
+    DexInstruction lastInstruction = rewrittenInstructions[rewrittenInstructions.length - 1];
     assert jump.getOffset() + jump.AAAAAAAA == lastInstruction.getOffset();
   }
 
@@ -58,58 +58,58 @@
   public void branching2() {
     DexItemFactory factory = new DexItemFactory();
     DexString string = factory.createString("turn into jumbo");
-    Instruction[] instructions = buildInstructions(string, true);
+    DexInstruction[] instructions = buildInstructions(string, true);
     DexCode code = jumboStringProcess(factory, string, instructions);
-    Instruction[] rewrittenInstructions = code.instructions;
-    assert rewrittenInstructions[1] instanceof IfEqz;
-    IfEqz condition = (IfEqz) rewrittenInstructions[1];
+    DexInstruction[] rewrittenInstructions = code.instructions;
+    assert rewrittenInstructions[1] instanceof DexIfEqz;
+    DexIfEqz condition = (DexIfEqz) rewrittenInstructions[1];
     assert condition.getOffset() + condition.BBBB == rewrittenInstructions[3].getOffset();
-    assert rewrittenInstructions[2] instanceof Goto32;
-    Goto32 jump = (Goto32) rewrittenInstructions[2];
-    Instruction lastInstruction = rewrittenInstructions[rewrittenInstructions.length - 1];
+    assert rewrittenInstructions[2] instanceof DexGoto32;
+    DexGoto32 jump = (DexGoto32) rewrittenInstructions[2];
+    DexInstruction lastInstruction = rewrittenInstructions[rewrittenInstructions.length - 1];
     assert jump.getOffset() + jump.AAAAAAAA == lastInstruction.getOffset();
   }
 
-  private Instruction[] buildInstructions(DexString string, boolean zeroCondition) {
-    List<Instruction> instructions = new ArrayList<>();
+  private DexInstruction[] buildInstructions(DexString string, boolean zeroCondition) {
+    List<DexInstruction> instructions = new ArrayList<>();
     int offset = 0;
-    Instruction instr = new Const4(0, 0);
+    DexInstruction instr = new DexConst4(0, 0);
     instr.setOffset(offset);
     instructions.add(instr);
     offset += instr.getSize();
     int lastInstructionOffset = 15000 * 2 + 2 + offset;
     if (zeroCondition) {
-      instr = new IfNez(0, lastInstructionOffset - offset);
+      instr = new DexIfNez(0, lastInstructionOffset - offset);
     } else {
-      instr = new IfNe(0, 0, lastInstructionOffset - offset);
+      instr = new DexIfNe(0, 0, lastInstructionOffset - offset);
     }
     instr.setOffset(offset);
     instructions.add(instr);
     offset += instr.getSize();
     for (int i = 0; i < 15000; i++) {
-      instr = new ConstString(0, string);
+      instr = new DexConstString(0, string);
       instr.setOffset(offset);
       instructions.add(instr);
       offset += instr.getSize();
     }
-    instr = new ReturnVoid();
+    instr = new DexReturnVoid();
     instr.setOffset(offset);
     instructions.add(instr);
     assert instr.getOffset() == lastInstructionOffset;
-    return instructions.toArray(Instruction.EMPTY_ARRAY);
+    return instructions.toArray(DexInstruction.EMPTY_ARRAY);
   }
 
-  private int countJumboStrings(Instruction[] instructions) {
+  private int countJumboStrings(DexInstruction[] instructions) {
     int count = 0;
-    for (Instruction instruction : instructions) {
-      count += instruction instanceof ConstStringJumbo ? 1 : 0;
+    for (DexInstruction instruction : instructions) {
+      count += instruction instanceof DexConstStringJumbo ? 1 : 0;
     }
     return count;
   }
 
-  private int countSimpleNops(Instruction[] instructions) {
+  private int countSimpleNops(DexInstruction[] instructions) {
     int count = 0;
-    for (Instruction instruction : instructions) {
+    for (DexInstruction instruction : instructions) {
       count += instruction.isSimpleNop() ? 1 : 0;
     }
     return count;
@@ -135,20 +135,20 @@
             "getDataBinder",
             ImmutableList.of(
                 "android.databinding.DataBindingComponent", "android.view.View", "int"));
-    Instruction[] instructions = method.getDefinition().getCode().asDexCode().instructions;
+    DexInstruction[] instructions = method.getDefinition().getCode().asDexCode().instructions;
     assertEquals(0, countJumboStrings(instructions));
     assertEquals(1, countSimpleNops(instructions));
 
     DexItemFactory factory = inspector.getFactory();
     DexString string = factory.createString("view must have a tag");
     DexCode code = jumboStringProcess(factory, string, instructions);
-    Instruction[] rewrittenInstructions = code.instructions;
+    DexInstruction[] rewrittenInstructions = code.instructions;
     assertEquals(289, countJumboStrings(rewrittenInstructions));
     assertEquals(0, countSimpleNops(rewrittenInstructions));
   }
 
   private DexCode jumboStringProcess(
-      DexItemFactory factory, DexString string, Instruction[] instructions) {
+      DexItemFactory factory, DexString string, DexInstruction[] instructions) {
     DexCode code = new DexCode(1, 0, 0, instructions, new Try[0], new TryHandler[0], null);
     MethodAccessFlags flags = MethodAccessFlags.fromSharedAccessFlags(Constants.ACC_PUBLIC, false);
     DexEncodedMethod method =
diff --git a/src/test/java/com/android/tools/r8/examples/JavaExampleClassProxy.java b/src/test/java/com/android/tools/r8/examples/JavaExampleClassProxy.java
index 6bbbfd1..6eb4ae4 100644
--- a/src/test/java/com/android/tools/r8/examples/JavaExampleClassProxy.java
+++ b/src/test/java/com/android/tools/r8/examples/JavaExampleClassProxy.java
@@ -5,6 +5,8 @@
 package com.android.tools.r8.examples;
 
 import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.StringUtils;
 import com.google.common.io.ByteStreams;
@@ -50,4 +52,8 @@
   public String typeName() {
     return DescriptorUtils.getJavaTypeFromBinaryName(binaryName);
   }
+
+  public ClassReference getClassReference() {
+    return Reference.classFromBinaryName(binaryName);
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/RemoveCheckCastAfterClassInlining.java b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/RemoveCheckCastAfterClassInlining.java
index 7a44d53..53d28eb 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/RemoveCheckCastAfterClassInlining.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/RemoveCheckCastAfterClassInlining.java
@@ -14,7 +14,7 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.code.Instruction;
+import com.android.tools.r8.dex.code.DexInstruction;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -58,7 +58,7 @@
 
     DexCode code = method.getCode().asDexCode();
     int numberOfConstStringInstructions = 0;
-    for (Instruction instruction : code.instructions) {
+    for (DexInstruction instruction : code.instructions) {
       // Make sure that we do not load a const-string and then subsequently use a check-cast
       // instruction to check if it is actually a string.
       assertFalse(instruction.isCheckCast());
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/b111893131/B111893131.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/b111893131/B111893131.java
index f19dea9..7ba5906 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/b111893131/B111893131.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/b111893131/B111893131.java
@@ -14,8 +14,8 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.ProcessResult;
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.InvokeVirtual;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexInvokeVirtual;
 import com.android.tools.r8.graph.Code;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexCode;
@@ -98,10 +98,10 @@
     });
   }
 
-  private void verifyAbsenceOfStringBuilderAppend(Instruction[] instructions) {
-    for (Instruction instr : instructions) {
-      if (instr instanceof InvokeVirtual) {
-        InvokeVirtual invokeVirtual = (InvokeVirtual) instr;
+  private void verifyAbsenceOfStringBuilderAppend(DexInstruction[] instructions) {
+    for (DexInstruction instr : instructions) {
+      if (instr instanceof DexInvokeVirtual) {
+        DexInvokeVirtual invokeVirtual = (DexInvokeVirtual) instr;
         DexMethod invokedMethod = invokeVirtual.getMethod();
         if (invokedMethod.holder.getName().endsWith("StringBuilder")) {
           assertNotEquals("append", invokedMethod.name.toString());
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java
index 7688f9b..9cd0f5f 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java
@@ -18,12 +18,12 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.InvokeDirect;
-import com.android.tools.r8.code.InvokeStatic;
-import com.android.tools.r8.code.InvokeVirtual;
-import com.android.tools.r8.code.SgetObject;
-import com.android.tools.r8.code.SputObject;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexInvokeDirect;
+import com.android.tools.r8.dex.code.DexInvokeStatic;
+import com.android.tools.r8.dex.code.DexInvokeVirtual;
+import com.android.tools.r8.dex.code.DexSgetObject;
+import com.android.tools.r8.dex.code.DexSputObject;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexType;
@@ -358,29 +358,29 @@
     MethodSignature signature = new MethodSignature(methodName, retValue, params);
     DexCode code = clazz.method(signature).getMethod().getCode().asDexCode();
     return Streams.concat(
-        filterInstructionKind(code, SgetObject.class)
-            .map(Instruction::getField)
-            .filter(fld -> isTypeOfInterest(fld.holder))
-            .map(DexField::toSourceString),
-        filterInstructionKind(code, SputObject.class)
-            .map(Instruction::getField)
-            .filter(fld -> isTypeOfInterest(fld.holder))
-            .map(DexField::toSourceString),
-        filterInstructionKind(code, InvokeStatic.class)
-            .map(insn -> (InvokeStatic) insn)
-            .map(InvokeStatic::getMethod)
-            .filter(method -> isTypeOfInterest(method.holder))
-            .map(method -> "STATIC: " + method.toSourceString()),
-        filterInstructionKind(code, InvokeVirtual.class)
-            .map(insn -> (InvokeVirtual) insn)
-            .map(InvokeVirtual::getMethod)
-            .filter(method -> isTypeOfInterest(method.holder))
-            .map(method -> "VIRTUAL: " + method.toSourceString()),
-        filterInstructionKind(code, InvokeDirect.class)
-            .map(insn -> (InvokeDirect) insn)
-            .map(InvokeDirect::getMethod)
-            .filter(method -> isTypeOfInterest(method.holder))
-            .map(method -> "DIRECT: " + method.toSourceString()))
+            filterInstructionKind(code, DexSgetObject.class)
+                .map(DexInstruction::getField)
+                .filter(fld -> isTypeOfInterest(fld.holder))
+                .map(DexField::toSourceString),
+            filterInstructionKind(code, DexSputObject.class)
+                .map(DexInstruction::getField)
+                .filter(fld -> isTypeOfInterest(fld.holder))
+                .map(DexField::toSourceString),
+            filterInstructionKind(code, DexInvokeStatic.class)
+                .map(insn -> (DexInvokeStatic) insn)
+                .map(DexInvokeStatic::getMethod)
+                .filter(method -> isTypeOfInterest(method.holder))
+                .map(method -> "STATIC: " + method.toSourceString()),
+            filterInstructionKind(code, DexInvokeVirtual.class)
+                .map(insn -> (DexInvokeVirtual) insn)
+                .map(DexInvokeVirtual::getMethod)
+                .filter(method -> isTypeOfInterest(method.holder))
+                .map(method -> "VIRTUAL: " + method.toSourceString()),
+            filterInstructionKind(code, DexInvokeDirect.class)
+                .map(insn -> (DexInvokeDirect) insn)
+                .map(DexInvokeDirect::getMethod)
+                .filter(method -> isTypeOfInterest(method.holder))
+                .map(method -> "DIRECT: " + method.toSourceString()))
         .map(txt -> txt.replace("java.lang.", ""))
         .map(txt -> txt.replace("com.android.tools.r8.ir.optimize.staticizer.trivial.", ""))
         .map(txt -> txt.replace("com.android.tools.r8.ir.optimize.staticizer.", ""))
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/StringBuilderTests.java b/src/test/java/com/android/tools/r8/ir/optimize/string/StringBuilderTests.java
new file mode 100644
index 0000000..f908b95
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/string/StringBuilderTests.java
@@ -0,0 +1,525 @@
+// 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.optimize.string;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.R8TestCompileResult;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CodeMatchers;
+import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.function.Function;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class StringBuilderTests extends TestBase {
+
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameter(1)
+  public StringBuilderResult stringBuilderTest;
+
+  @Parameters(name = "{0}, configuration: {1}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withAllRuntimesAndApiLevels().build(), getTestExpectations());
+  }
+
+  private static class StringBuilderResult {
+
+    private final Method method;
+    private final String expected;
+    private final int stringBuilders;
+    private final int appends;
+    private final int toStrings;
+
+    private StringBuilderResult(
+        Method method, String expected, int stringBuilders, int appends, int toStrings) {
+      this.method = method;
+      this.expected = expected;
+      this.stringBuilders = stringBuilders;
+      this.appends = appends;
+      this.toStrings = toStrings;
+    }
+
+    private static StringBuilderResult create(
+        Method method, String expected, int stringBuilders, int appends, int toStrings) {
+      return new StringBuilderResult(method, expected, stringBuilders, appends, toStrings);
+    }
+
+    @Override
+    public String toString() {
+      return getMethodName();
+    }
+
+    String getMethodName() {
+      return method.getName();
+    }
+  }
+
+  private static StringBuilderResult[] getTestExpectations() {
+    try {
+      return new StringBuilderResult[] {
+        StringBuilderResult.create(
+            Main.class.getMethod("emptyStringTest"), StringUtils.lines(""), 0, 0, 0),
+        StringBuilderResult.create(
+            Main.class.getMethod("simpleStraightLineTest"),
+            StringUtils.lines("Hello World"),
+            0,
+            0,
+            0),
+        StringBuilderResult.create(
+            Main.class.getMethod("notMaterializing"), StringUtils.lines("Hello World"), 0, 0, 0),
+        StringBuilderResult.create(
+            Main.class.getMethod("materializingWithAdditionalUnObservedAppend"),
+            StringUtils.lines("Hello World"),
+            0,
+            0,
+            0),
+        StringBuilderResult.create(
+            Main.class.getMethod("materializingWithAdditionalAppend"),
+            StringUtils.lines("Hello World", "Hello WorldObservable"),
+            1,
+            3,
+            2),
+        StringBuilderResult.create(
+            Main.class.getMethod("appendWithNonConstant"),
+            StringUtils.lines("Hello World, Hello World"),
+            1,
+            3,
+            1),
+        StringBuilderResult.create(
+            Main.class.getMethod("simpleLoopTest"),
+            StringUtils.lines("Hello WorldHello World"),
+            1,
+            1,
+            1),
+        // TODO(b/222437581): Should not remove StringBuilder
+        StringBuilderResult.create(
+            Main.class.getMethod("simpleLoopTest2"),
+            StringUtils.lines("Hello World", "Hello WorldHello World"),
+            0,
+            0,
+            0),
+        StringBuilderResult.create(
+            Main.class.getMethod("simpleLoopWithStringBuilderInBodyTest"),
+            StringUtils.lines("Hello World"),
+            0,
+            0,
+            0),
+        StringBuilderResult.create(
+            Main.class.getMethod("simpleDiamondTest"),
+            StringUtils.lines("Message: Hello World"),
+            0,
+            0,
+            0),
+        StringBuilderResult.create(
+            Main.class.getMethod("diamondWithUseTest"), StringUtils.lines("Hello World"), 1, 3, 1),
+        StringBuilderResult.create(
+            Main.class.getMethod("diamondsWithSingleUseTest"),
+            StringUtils.lines("Hello World"),
+            1,
+            3,
+            1),
+        StringBuilderResult.create(
+            Main.class.getMethod("escapeTest"), StringUtils.lines("Hello World"), 2, 2, 1),
+        StringBuilderResult.create(
+            Main.class.getMethod("intoPhiTest"), StringUtils.lines("Hello World"), 2, 2, 1),
+        StringBuilderResult.create(
+            Main.class.getMethod("optimizePartial"), StringUtils.lines("Hello World.."), 1, 4, 1),
+        StringBuilderResult.create(
+            Main.class.getMethod("multipleToStrings"),
+            StringUtils.lines("Hello World", "Hello World.."),
+            1,
+            4,
+            2),
+        StringBuilderResult.create(
+            Main.class.getMethod("changeAppendType"), StringUtils.lines("1 World"), 1, 3, 1),
+        StringBuilderResult.create(
+            Main.class.getMethod("checkCapacity"), StringUtils.lines("true"), 2, 1, 0),
+        StringBuilderResult.create(
+            Main.class.getMethod("checkHashCode"), StringUtils.lines("false"), 1, 0, 0),
+        StringBuilderResult.create(
+            Main.class.getMethod("stringBuilderWithStringBuilderToString"),
+            StringUtils.lines("Hello World"),
+            1,
+            1,
+            1),
+        StringBuilderResult.create(
+            Main.class.getMethod("stringBuilderWithStringBuilder"),
+            StringUtils.lines("Hello World"),
+            2,
+            2,
+            1),
+        StringBuilderResult.create(
+            Main.class.getMethod("stringBuilderInStringBuilderConstructor"),
+            StringUtils.lines("Hello World"),
+            2,
+            1,
+            1),
+        StringBuilderResult.create(
+            Main.class.getMethod("interDependencyTest"),
+            StringUtils.lines("World Hello World "),
+            2,
+            2,
+            1),
+        StringBuilderResult.create(
+            Main.class.getMethod("stringBuilderSelfReference"), StringUtils.lines(""), 1, 1, 1),
+        StringBuilderResult.create(
+            Main.class.getMethod("unknownStringBuilderInstruction"),
+            StringUtils.lines("Hello World"),
+            1,
+            2,
+            1),
+      };
+    } catch (Exception e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  private static final Function<TestParameters, R8TestCompileResult> compilationResults =
+      memoizeFunction(StringBuilderTests::compileR8);
+
+  private static R8TestCompileResult compileR8(TestParameters parameters) throws Exception {
+    return testForR8(getStaticTemp(), parameters.getBackend())
+        .addProgramClasses(Main.class)
+        .setMinApi(parameters.getApiLevel())
+        .addKeepClassAndMembersRules(Main.class)
+        .enableInliningAnnotations()
+        .compile();
+  }
+
+  @Test
+  public void testRuntime() throws Exception {
+    testForRuntime(parameters)
+        .addProgramClasses(Main.class)
+        .run(parameters.getRuntime(), Main.class, stringBuilderTest.getMethodName())
+        .assertSuccessWithOutput(stringBuilderTest.expected);
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    boolean hasError =
+        stringBuilderTest.getMethodName().equals("simpleLoopTest2") && parameters.isDexRuntime();
+    compilationResults
+        .apply(parameters)
+        .inspect(
+            inspector -> {
+              if (parameters.isCfRuntime()) {
+                // TODO(b/114002137): for now, string concatenation depends on rewriteMoveResult.
+                return;
+              }
+              MethodSubject method = inspector.method(stringBuilderTest.method);
+              assertThat(method, isPresent());
+              FoundMethodSubject foundMethodSubject = method.asFoundMethodSubject();
+              assertEquals(
+                  stringBuilderTest.stringBuilders, countStringBuilderInits(foundMethodSubject));
+              assertEquals(
+                  stringBuilderTest.appends, countStringBuilderAppends(foundMethodSubject));
+              assertEquals(
+                  stringBuilderTest.toStrings, countStringBuilderToStrings(foundMethodSubject));
+            })
+        .run(parameters.getRuntime(), Main.class, stringBuilderTest.getMethodName())
+        // TODO(b/222437581): Incorrect result for string builder inside loop.
+        .assertSuccessWithOutputLinesIf(hasError, "Hello World", "Hello World")
+        .assertSuccessWithOutputIf(!hasError, stringBuilderTest.expected);
+  }
+
+  private long countStringBuilderInits(FoundMethodSubject method) {
+    return countInstructionsOnStringBuilder(method, "<init>");
+  }
+
+  private long countStringBuilderAppends(FoundMethodSubject method) {
+    return countInstructionsOnStringBuilder(method, "append");
+  }
+
+  private long countStringBuilderToStrings(FoundMethodSubject method) {
+    return countInstructionsOnStringBuilder(method, "toString");
+  }
+
+  private long countInstructionsOnStringBuilder(FoundMethodSubject method, String methodName) {
+    return method
+        .streamInstructions()
+        .filter(
+            instructionSubject ->
+                CodeMatchers.isInvokeWithTarget(typeName(StringBuilder.class), methodName)
+                    .test(instructionSubject))
+        .count();
+  }
+
+  public static class Main {
+
+    @NeverInline
+    public static void emptyStringTest() {
+      StringBuilder sb = new StringBuilder();
+      System.out.println(sb.toString());
+    }
+
+    @NeverInline
+    public static void simpleStraightLineTest() {
+      StringBuilder sb = new StringBuilder();
+      sb = sb.append("Hello ");
+      sb.append("World");
+      System.out.println(sb.toString());
+    }
+
+    @NeverInline
+    public static void notMaterializing() {
+      StringBuilder sb = new StringBuilder();
+      sb.append("foo");
+      if (System.currentTimeMillis() > 0) {
+        sb.append("bar");
+      }
+      System.out.println("Hello World");
+    }
+
+    @NeverInline
+    public static void materializingWithAdditionalUnObservedAppend() {
+      StringBuilder sb = new StringBuilder();
+      sb.append("Hello ");
+      sb.append("World");
+      System.out.println(sb.toString());
+      sb.append("Not observable");
+    }
+
+    @NeverInline
+    public static void materializingWithAdditionalAppend() {
+      StringBuilder sb = new StringBuilder();
+      sb.append("Hello ");
+      sb.append("World");
+      System.out.println(sb.toString());
+      sb.append("Observable");
+      System.out.println(sb.toString());
+    }
+
+    @NeverInline
+    public static void appendWithNonConstant() {
+      StringBuilder sb = new StringBuilder();
+      sb.append("Hello ");
+      String other;
+      if (System.currentTimeMillis() > 0) {
+        other = "World, Hello ";
+      } else {
+        other = "Hello World";
+      }
+      sb.append(other);
+      sb.append("World");
+      System.out.println(sb.toString());
+    }
+
+    @NeverInline
+    public static void simpleLoopTest() {
+      int count = System.currentTimeMillis() > 0 ? 2 : 0;
+      StringBuilder sb = new StringBuilder();
+      for (int i = 0; i < count; i++) {
+        sb.append("Hello World");
+      }
+      System.out.println(sb.toString());
+    }
+
+    @NeverInline
+    public static void simpleLoopTest2() {
+      int count = System.currentTimeMillis() > 0 ? 2 : 0;
+      StringBuilder sb = new StringBuilder();
+      for (int i = 0; i < count; i++) {
+        sb.append("Hello World");
+        System.out.println(sb.toString());
+      }
+    }
+
+    @NeverInline
+    public static void simpleLoopWithStringBuilderInBodyTest() {
+      int count = System.currentTimeMillis() > 0 ? 1 : 0;
+      while (count > 0) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("Hello ");
+        sb.append("World");
+        System.out.println(sb.toString());
+        count--;
+      }
+    }
+
+    @NeverInline
+    public static void simpleDiamondTest() {
+      StringBuilder sb = new StringBuilder();
+      sb.append("Hello ");
+      if (System.currentTimeMillis() > 0) {
+        System.out.print("Message: ");
+      } else {
+        throw new RuntimeException();
+      }
+      sb.append("World");
+      System.out.println(sb.toString());
+    }
+
+    @NeverInline
+    public static void diamondWithUseTest() {
+      StringBuilder sb = new StringBuilder();
+      sb.append("Hello");
+      if (System.currentTimeMillis() > 0) {
+        sb.append(" ");
+      } else {
+        sb.append("Planet");
+      }
+      sb.append("World");
+      System.out.println(sb.toString());
+    }
+
+    @NeverInline
+    public static void diamondsWithSingleUseTest() {
+      StringBuilder sb = new StringBuilder();
+      sb.append("Hello");
+      if (System.currentTimeMillis() > 0) {
+        sb.append(" ");
+      }
+      sb.append("World");
+      System.out.println(sb.toString());
+    }
+
+    @NeverInline
+    public static void escapeTest() {
+      StringBuilder sb = new StringBuilder();
+      sb.append("Hello");
+      StringBuilder sbObject;
+      if (System.currentTimeMillis() > 0) {
+        sbObject = sb;
+      } else {
+        sbObject = new StringBuilder();
+      }
+      escape(sbObject);
+      sb.append("World");
+      System.out.println(sb.toString());
+    }
+
+    @NeverInline
+    public static void escape(Object obj) {
+      ((StringBuilder) obj).append(" ");
+    }
+
+    @NeverInline
+    public static void intoPhiTest() {
+      StringBuilder sb;
+      if (System.currentTimeMillis() > 0) {
+        sb = new StringBuilder();
+        sb.append("Hello ");
+      } else {
+        sb = new StringBuilder();
+        sb.append("Other ");
+      }
+      sb.append("World");
+      System.out.println(sb.toString());
+    }
+
+    @NeverInline
+    public static void optimizePartial() {
+      StringBuilder sb = new StringBuilder();
+      sb.append("Hello ");
+      if (System.currentTimeMillis() > 0) {
+        sb.append("World");
+      }
+      sb.append(".");
+      sb.append(".");
+      System.out.println(sb.toString());
+    }
+
+    @NeverInline
+    public static void multipleToStrings() {
+      StringBuilder sb = new StringBuilder();
+      sb.append("Hello ");
+      sb.append("World");
+      System.out.println(sb.toString());
+      sb.append(".");
+      sb.append(".");
+      System.out.println(sb.toString());
+    }
+
+    @NeverInline
+    public static void changeAppendType() {
+      StringBuilder sb = new StringBuilder();
+      if (System.currentTimeMillis() == 0) {
+        sb.append("foo");
+      }
+      sb.append(1);
+      sb.append(" World");
+      System.out.println(sb.toString());
+    }
+
+    @NeverInline
+    public static void checkCapacity() {
+      StringBuilder stringBuilder = new StringBuilder();
+      stringBuilder.append("foo");
+      StringBuilder otherBuilder = new StringBuilder("foo");
+      System.out.println(stringBuilder.capacity() != otherBuilder.capacity());
+    }
+
+    @NeverInline
+    public static void checkHashCode() {
+      StringBuilder sb = new StringBuilder();
+      System.out.println(sb.hashCode() == 0);
+    }
+
+    @NeverInline
+    public static void stringBuilderWithStringBuilderToString() {
+      System.out.println(
+          new StringBuilder()
+              .append(new StringBuilder().append("Hello World").toString())
+              .toString());
+    }
+
+    @NeverInline
+    public static void stringBuilderWithStringBuilder() {
+      System.out.println(
+          new StringBuilder().append(new StringBuilder().append("Hello World")).toString());
+    }
+
+    @NeverInline
+    public static void stringBuilderInStringBuilderConstructor() {
+      System.out.println(new StringBuilder(new StringBuilder().append("Hello World")).toString());
+    }
+
+    @NeverInline
+    public static void interDependencyTest() {
+      StringBuilder sb1 = new StringBuilder("Hello ");
+      StringBuilder sb2 = new StringBuilder("World ");
+      sb1.append(sb2);
+      sb2.append(sb1);
+      System.out.println(sb2.toString());
+    }
+
+    @NeverInline
+    public static void stringBuilderSelfReference() {
+      StringBuilder sb = new StringBuilder();
+      sb.append(sb);
+      System.out.println(sb.toString());
+    }
+
+    @NeverInline
+    public static void unknownStringBuilderInstruction() {
+      StringBuilder sb = new StringBuilder();
+      sb.append("Helloo ");
+      sb.deleteCharAt(5);
+      sb.append("World");
+      System.out.println(sb.toString());
+    }
+
+    public static void main(String[] args) throws Exception {
+      Method method = Main.class.getMethod(args[0]);
+      method.invoke(null);
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
index 12fe431..b7fe293 100644
--- a/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
@@ -20,9 +20,9 @@
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.cf.code.CfNew;
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.NewInstance;
-import com.android.tools.r8.code.SgetObject;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexNewInstance;
+import com.android.tools.r8.dex.code.DexSgetObject;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
 import com.android.tools.r8.utils.IntBox;
@@ -293,11 +293,11 @@
                   return instruction.getField().getHolderType();
                 }
               } else {
-                Instruction baseInstruction = instruction.asDexInstruction().getInstruction();
-                if (baseInstruction instanceof SgetObject) {
+                DexInstruction baseInstruction = instruction.asDexInstruction().getInstruction();
+                if (baseInstruction instanceof DexSgetObject) {
                   return baseInstruction.getField().getHolderType();
-                } else if (baseInstruction instanceof NewInstance) {
-                  return ((NewInstance) baseInstruction).getType();
+                } else if (baseInstruction instanceof DexNewInstance) {
+                  return ((DexNewInstance) baseInstruction).getType();
                 }
               }
               return null;
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
index a540713..ed70ece 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -67,7 +67,6 @@
 import com.android.tools.r8.ir.regalloc.RegisterAllocator;
 import com.android.tools.r8.ir.synthetic.SynthesizedCode;
 import com.android.tools.r8.jasmin.JasminBuilder;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.origin.SynthesizedOrigin;
 import com.android.tools.r8.synthesis.SyntheticItems.GlobalSyntheticsStrategy;
@@ -892,8 +891,7 @@
             AppView.createForD8(
                 AppInfo.createInitialAppInfo(
                     application, GlobalSyntheticsStrategy.forNonSynthesizing())),
-            null,
-            NamingLens.getIdentityLens());
+            null);
     ExecutorService executor = ThreadUtils.getExecutorService(options);
     AndroidAppConsumers compatSink = new AndroidAppConsumers(options);
     try {
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingArrayTest.java b/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingArrayTest.java
new file mode 100644
index 0000000..62de8e6
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingArrayTest.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.memberrebinding;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class MemberRebindingArrayTest extends TestBase {
+
+  private final TestParameters parameters;
+  private final String[] EXPECTED = new String[] {"hashCode", "equals"};
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public MemberRebindingArrayTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testRuntime() throws Exception {
+    testForRuntime(parameters)
+        .addProgramClassFileData(getMainWithRewrittenEqualsAndHashCode())
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines(EXPECTED);
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramClassFileData(getMainWithRewrittenEqualsAndHashCode())
+        .addKeepMainRule(Main.class)
+        .setMinApi(parameters.getApiLevel())
+        .addOptionsModification(
+            options -> options.apiModelingOptions().disableApiCallerIdentification())
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines(EXPECTED);
+  }
+
+  private byte[] getMainWithRewrittenEqualsAndHashCode() throws Exception {
+    return transformer(Main.class)
+        .transformMethodInsnInMethod(
+            "main",
+            (opcode, owner, name, descriptor, isInterface, visitor) -> {
+              if (owner.equals(binaryName(Object.class))) {
+                visitor.visitMethodInsn(
+                    opcode, "[" + descriptor(String.class), name, descriptor, isInterface);
+              } else {
+                visitor.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+              }
+            })
+        .transform();
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) {
+      System.out.println(args.hashCode() != 0 ? "hashCode" : "error_hashCode");
+      System.out.println(args.equals(args.clone()) ? "error_equals" : "equals");
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/naming/IdentifierNameStringMarkerTest.java b/src/test/java/com/android/tools/r8/naming/IdentifierNameStringMarkerTest.java
index df6d1a5..039ba9a 100644
--- a/src/test/java/com/android/tools/r8/naming/IdentifierNameStringMarkerTest.java
+++ b/src/test/java/com/android/tools/r8/naming/IdentifierNameStringMarkerTest.java
@@ -12,18 +12,18 @@
 import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.R8TestCompileResult;
 import com.android.tools.r8.ThrowableConsumer;
-import com.android.tools.r8.code.AputObject;
-import com.android.tools.r8.code.Const4;
-import com.android.tools.r8.code.ConstClass;
-import com.android.tools.r8.code.ConstString;
-import com.android.tools.r8.code.InvokeDirect;
-import com.android.tools.r8.code.InvokeStatic;
-import com.android.tools.r8.code.InvokeVirtual;
-import com.android.tools.r8.code.IputObject;
-import com.android.tools.r8.code.NewArray;
-import com.android.tools.r8.code.ReturnVoid;
-import com.android.tools.r8.code.SgetObject;
-import com.android.tools.r8.code.SputObject;
+import com.android.tools.r8.dex.code.DexAputObject;
+import com.android.tools.r8.dex.code.DexConst4;
+import com.android.tools.r8.dex.code.DexConstClass;
+import com.android.tools.r8.dex.code.DexConstString;
+import com.android.tools.r8.dex.code.DexInvokeDirect;
+import com.android.tools.r8.dex.code.DexInvokeStatic;
+import com.android.tools.r8.dex.code.DexInvokeVirtual;
+import com.android.tools.r8.dex.code.DexIputObject;
+import com.android.tools.r8.dex.code.DexNewArray;
+import com.android.tools.r8.dex.code.DexReturnVoid;
+import com.android.tools.r8.dex.code.DexSgetObject;
+import com.android.tools.r8.dex.code.DexSputObject;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.smali.SmaliBuilder;
@@ -67,8 +67,8 @@
     checkInstructions(
         code,
         ImmutableList.of(
-            InvokeDirect.class, ConstString.class, IputObject.class, ReturnVoid.class));
-    ConstString constString = (ConstString) code.instructions[1];
+            DexInvokeDirect.class, DexConstString.class, DexIputObject.class, DexReturnVoid.class));
+    DexConstString constString = (DexConstString) code.instructions[1];
     assertEquals(BOO, constString.getString().toString());
   }
 
@@ -100,16 +100,16 @@
     checkInstructions(
         code,
         ImmutableList.of(
-            InvokeDirect.class,
-            SgetObject.class,
-            ConstString.class,
-            InvokeVirtual.class,
-            ConstString.class,
-            IputObject.class,
-            ReturnVoid.class));
-    ConstString constString = (ConstString) code.instructions[2];
+            DexInvokeDirect.class,
+            DexSgetObject.class,
+            DexConstString.class,
+            DexInvokeVirtual.class,
+            DexConstString.class,
+            DexIputObject.class,
+            DexReturnVoid.class));
+    DexConstString constString = (DexConstString) code.instructions[2];
     assertEquals(BOO, constString.getString().toString());
-    constString = (ConstString) code.instructions[4];
+    constString = (DexConstString) code.instructions[4];
     assertEquals(BOO, constString.getString().toString());
   }
 
@@ -143,16 +143,16 @@
     checkInstructions(
         code,
         ImmutableList.of(
-            InvokeDirect.class,
-            SgetObject.class,
-            ConstString.class,
-            InvokeVirtual.class,
-            ConstString.class,
-            IputObject.class,
-            ReturnVoid.class));
-    ConstString constString = (ConstString) code.instructions[2];
+            DexInvokeDirect.class,
+            DexSgetObject.class,
+            DexConstString.class,
+            DexInvokeVirtual.class,
+            DexConstString.class,
+            DexIputObject.class,
+            DexReturnVoid.class));
+    DexConstString constString = (DexConstString) code.instructions[2];
     assertEquals(BOO, constString.getString().toString());
-    constString = (ConstString) code.instructions[4];
+    constString = (DexConstString) code.instructions[4];
     assertNotEquals(BOO, constString.getString().toString());
   }
 
@@ -180,11 +180,9 @@
     assertNotNull(method);
 
     DexCode code = method.getCode().asDexCode();
-    checkInstructions(code, ImmutableList.of(
-        ConstString.class,
-        SputObject.class,
-        ReturnVoid.class));
-    ConstString constString = (ConstString) code.instructions[0];
+    checkInstructions(
+        code, ImmutableList.of(DexConstString.class, DexSputObject.class, DexReturnVoid.class));
+    DexConstString constString = (DexConstString) code.instructions[0];
     assertEquals(BOO, constString.getString().toString());
   }
 
@@ -212,16 +210,18 @@
     assertNotNull(method);
 
     DexCode code = method.getCode().asDexCode();
-    checkInstructions(code, ImmutableList.of(
-        SgetObject.class,
-        ConstString.class,
-        InvokeVirtual.class,
-        ConstString.class,
-        SputObject.class,
-        ReturnVoid.class));
-    ConstString constString = (ConstString) code.instructions[1];
+    checkInstructions(
+        code,
+        ImmutableList.of(
+            DexSgetObject.class,
+            DexConstString.class,
+            DexInvokeVirtual.class,
+            DexConstString.class,
+            DexSputObject.class,
+            DexReturnVoid.class));
+    DexConstString constString = (DexConstString) code.instructions[1];
     assertEquals(BOO, constString.getString().toString());
-    constString = (ConstString) code.instructions[3];
+    constString = (DexConstString) code.instructions[3];
     assertEquals(BOO, constString.getString().toString());
   }
 
@@ -251,16 +251,18 @@
     assertNotNull(method);
 
     DexCode code = method.getCode().asDexCode();
-    checkInstructions(code, ImmutableList.of(
-        SgetObject.class,
-        ConstString.class,
-        InvokeVirtual.class,
-        ConstString.class,
-        SputObject.class,
-        ReturnVoid.class));
-    ConstString constString = (ConstString) code.instructions[1];
+    checkInstructions(
+        code,
+        ImmutableList.of(
+            DexSgetObject.class,
+            DexConstString.class,
+            DexInvokeVirtual.class,
+            DexConstString.class,
+            DexSputObject.class,
+            DexReturnVoid.class));
+    DexConstString constString = (DexConstString) code.instructions[1];
     assertEquals(BOO, constString.getString().toString());
-    constString = (ConstString) code.instructions[3];
+    constString = (DexConstString) code.instructions[3];
     assertNotEquals(BOO, constString.getString().toString());
   }
 
@@ -395,13 +397,13 @@
     checkInstructions(
         code,
         ImmutableList.of(
-            InvokeDirect.class,
-            ConstString.class,
-            ConstString.class,
-            InvokeStatic.class,
-            ReturnVoid.class));
-    String s1 = ((ConstString) code.instructions[1]).getString().toString();
-    String s2 = ((ConstString) code.instructions[2]).getString().toString();
+            DexInvokeDirect.class,
+            DexConstString.class,
+            DexConstString.class,
+            DexInvokeStatic.class,
+            DexReturnVoid.class));
+    String s1 = ((DexConstString) code.instructions[1]).getString().toString();
+    String s2 = ((DexConstString) code.instructions[2]).getString().toString();
     assertTrue(BOO.equals(s1) || BOO.equals(s2));
     assertTrue("Mixed/form.Boo".equals(s1) || "Mixed/form.Boo".equals(s2));
   }
@@ -439,16 +441,16 @@
     checkInstructions(
         code,
         ImmutableList.of(
-            InvokeDirect.class,
-            SgetObject.class,
-            ConstString.class,
-            InvokeVirtual.class,
-            ConstString.class,
-            InvokeStatic.class,
-            ReturnVoid.class));
-    ConstString constString = (ConstString) code.instructions[2];
+            DexInvokeDirect.class,
+            DexSgetObject.class,
+            DexConstString.class,
+            DexInvokeVirtual.class,
+            DexConstString.class,
+            DexInvokeStatic.class,
+            DexReturnVoid.class));
+    DexConstString constString = (DexConstString) code.instructions[2];
     assertEquals(BOO, constString.getString().toString());
-    constString = (ConstString) code.instructions[4];
+    constString = (DexConstString) code.instructions[4];
     assertEquals(BOO, constString.getString().toString());
   }
 
@@ -487,16 +489,16 @@
     checkInstructions(
         code,
         ImmutableList.of(
-            InvokeDirect.class,
-            SgetObject.class,
-            ConstString.class,
-            InvokeVirtual.class,
-            ConstString.class,
-            InvokeStatic.class,
-            ReturnVoid.class));
-    ConstString constString = (ConstString) code.instructions[2];
+            DexInvokeDirect.class,
+            DexSgetObject.class,
+            DexConstString.class,
+            DexInvokeVirtual.class,
+            DexConstString.class,
+            DexInvokeStatic.class,
+            DexReturnVoid.class));
+    DexConstString constString = (DexConstString) code.instructions[2];
     assertEquals(BOO, constString.getString().toString());
-    constString = (ConstString) code.instructions[4];
+    constString = (DexConstString) code.instructions[4];
     assertNotEquals(BOO, constString.getString().toString());
   }
 
@@ -541,12 +543,12 @@
     checkInstructions(
         code,
         ImmutableList.of(
-            InvokeDirect.class,
-            ConstClass.class,
-            ConstString.class,
-            InvokeStatic.class,
-            ReturnVoid.class));
-    ConstString constString = (ConstString) code.instructions[2];
+            DexInvokeDirect.class,
+            DexConstClass.class,
+            DexConstString.class,
+            DexInvokeStatic.class,
+            DexReturnVoid.class));
+    DexConstString constString = (DexConstString) code.instructions[2];
     assertEquals("foo", constString.getString().toString());
   }
 
@@ -591,12 +593,12 @@
     checkInstructions(
         code,
         ImmutableList.of(
-            InvokeDirect.class,
-            ConstClass.class,
-            ConstString.class,
-            InvokeStatic.class,
-            ReturnVoid.class));
-    ConstString constString = (ConstString) code.instructions[2];
+            DexInvokeDirect.class,
+            DexConstClass.class,
+            DexConstString.class,
+            DexInvokeStatic.class,
+            DexReturnVoid.class));
+    DexConstString constString = (DexConstString) code.instructions[2];
     assertNotEquals("foo", constString.getString().toString());
   }
 
@@ -648,16 +650,16 @@
     checkInstructions(
         code,
         ImmutableList.of(
-            InvokeDirect.class,
-            ConstClass.class,
-            Const4.class,
-            NewArray.class,
-            Const4.class,
-            AputObject.class,
-            ConstString.class,
-            InvokeStatic.class,
-            ReturnVoid.class));
-    ConstString constString = (ConstString) code.instructions[6];
+            DexInvokeDirect.class,
+            DexConstClass.class,
+            DexConst4.class,
+            DexNewArray.class,
+            DexConst4.class,
+            DexAputObject.class,
+            DexConstString.class,
+            DexInvokeStatic.class,
+            DexReturnVoid.class));
+    DexConstString constString = (DexConstString) code.instructions[6];
     assertEquals("foo", constString.getString().toString());
   }
 
@@ -709,16 +711,16 @@
     checkInstructions(
         code,
         ImmutableList.of(
-            InvokeDirect.class,
-            ConstClass.class,
-            Const4.class,
-            NewArray.class,
-            Const4.class,
-            AputObject.class,
-            ConstString.class,
-            InvokeStatic.class,
-            ReturnVoid.class));
-    ConstString constString = (ConstString) code.instructions[6];
+            DexInvokeDirect.class,
+            DexConstClass.class,
+            DexConst4.class,
+            DexNewArray.class,
+            DexConst4.class,
+            DexAputObject.class,
+            DexConstString.class,
+            DexInvokeStatic.class,
+            DexReturnVoid.class));
+    DexConstString constString = (DexConstString) code.instructions[6];
     assertNotEquals("foo", constString.getString().toString());
   }
 
diff --git a/src/test/java/com/android/tools/r8/reachabilitysensitive/ReachabilitySensitiveTest.java b/src/test/java/com/android/tools/r8/reachabilitysensitive/ReachabilitySensitiveTest.java
index c09e451..c435b84 100644
--- a/src/test/java/com/android/tools/r8/reachabilitysensitive/ReachabilitySensitiveTest.java
+++ b/src/test/java/com/android/tools/r8/reachabilitysensitive/ReachabilitySensitiveTest.java
@@ -12,10 +12,10 @@
 import com.android.tools.r8.CompilationMode;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.code.AddIntLit8;
-import com.android.tools.r8.code.Const4;
-import com.android.tools.r8.code.Instruction;
 import com.android.tools.r8.dex.Marker.Tool;
+import com.android.tools.r8.dex.code.DexAddIntLit8;
+import com.android.tools.r8.dex.code.DexConst4;
+import com.android.tools.r8.dex.code.DexInstruction;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.graph.DexDebugEvent.StartLocal;
 import com.android.tools.r8.utils.AndroidApiLevel;
@@ -145,16 +145,16 @@
   private void checkAnnotatedCode(DexCode code) {
     // All live at the same time: receiver, i, j, k, System.out.
     assertEquals(5, code.registerSize);
-    Instruction first = code.instructions[0];
-    Instruction second = code.instructions[1];
-    Instruction third = code.instructions[2];
+    DexInstruction first = code.instructions[0];
+    DexInstruction second = code.instructions[1];
+    DexInstruction third = code.instructions[2];
     // None of the local declarations overwrite other locals.
-    assertTrue(first instanceof Const4);
-    assertTrue(second instanceof AddIntLit8);
-    assertTrue(third instanceof AddIntLit8);
-    int firstRegister = ((Const4) first).A;
-    int secondRegister = ((AddIntLit8) second).AA;
-    int thirdRegister = ((AddIntLit8) third).AA;
+    assertTrue(first instanceof DexConst4);
+    assertTrue(second instanceof DexAddIntLit8);
+    assertTrue(third instanceof DexAddIntLit8);
+    int firstRegister = ((DexConst4) first).A;
+    int secondRegister = ((DexAddIntLit8) second).AA;
+    int thirdRegister = ((DexAddIntLit8) third).AA;
     assertFalse(firstRegister == secondRegister);
     assertFalse(firstRegister == thirdRegister);
     assertFalse(secondRegister == thirdRegister);
diff --git a/src/test/java/com/android/tools/r8/regress/b111250398/B111250398.java b/src/test/java/com/android/tools/r8/regress/b111250398/B111250398.java
index 33bef6d..535da71 100644
--- a/src/test/java/com/android/tools/r8/regress/b111250398/B111250398.java
+++ b/src/test/java/com/android/tools/r8/regress/b111250398/B111250398.java
@@ -9,9 +9,9 @@
 import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.code.Iget;
-import com.android.tools.r8.code.IgetObject;
-import com.android.tools.r8.code.Sget;
+import com.android.tools.r8.dex.code.DexIget;
+import com.android.tools.r8.dex.code.DexIgetObject;
+import com.android.tools.r8.dex.code.DexSget;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.utils.AndroidApp;
@@ -214,24 +214,24 @@
 
   private long countIget(DexCode code, DexField field) {
     return Arrays.stream(code.instructions)
-        .filter(instruction -> instruction instanceof Iget)
-        .map(instruction -> (Iget) instruction)
+        .filter(instruction -> instruction instanceof DexIget)
+        .map(instruction -> (DexIget) instruction)
         .filter(get -> get.getField() == field)
         .count();
   }
 
   private long countSget(DexCode code, DexField field) {
     return Arrays.stream(code.instructions)
-        .filter(instruction -> instruction instanceof Sget)
-        .map(instruction -> (Sget) instruction)
+        .filter(instruction -> instruction instanceof DexSget)
+        .map(instruction -> (DexSget) instruction)
         .filter(get -> get.getField() == field)
         .count();
   }
 
   private long countIgetObject(MethodSubject method, FieldSubject field) {
     return Arrays.stream(method.getMethod().getCode().asDexCode().instructions)
-        .filter(instruction -> instruction instanceof IgetObject)
-        .map(instruction -> (IgetObject) instruction)
+        .filter(instruction -> instruction instanceof DexIgetObject)
+        .map(instruction -> (DexIgetObject) instruction)
         .filter(get -> get.getField() == field.getField().getReference())
         .count();
   }
diff --git a/src/test/java/com/android/tools/r8/regress/b113326860/B113326860.java b/src/test/java/com/android/tools/r8/regress/b113326860/B113326860.java
index 294dbbc..b6f3d94 100644
--- a/src/test/java/com/android/tools/r8/regress/b113326860/B113326860.java
+++ b/src/test/java/com/android/tools/r8/regress/b113326860/B113326860.java
@@ -13,9 +13,9 @@
 import com.android.tools.r8.CompilationMode;
 import com.android.tools.r8.D8Command;
 import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.code.Sput;
-import com.android.tools.r8.code.SputBoolean;
-import com.android.tools.r8.code.SputObject;
+import com.android.tools.r8.dex.code.DexSput;
+import com.android.tools.r8.dex.code.DexSputBoolean;
+import com.android.tools.r8.dex.code.DexSputObject;
 import com.android.tools.r8.ir.code.SingleConstant;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AndroidApp;
@@ -113,10 +113,12 @@
     assertThat(clazz, isPresent());
     MethodSubject method = clazz.method("void", "<clinit>", ImmutableList.of());
     assertThat(method, isPresent());
-    assertFalse(Arrays.stream(method.getMethod().getCode().asDexCode().instructions)
-        .anyMatch(i -> i instanceof SputBoolean || i instanceof Sput));
-    assertTrue(Arrays.stream(method.getMethod().getCode().asDexCode().instructions)
-        .anyMatch(i -> i instanceof SputObject));
+    assertFalse(
+        Arrays.stream(method.getMethod().getCode().asDexCode().instructions)
+            .anyMatch(i -> i instanceof DexSputBoolean || i instanceof DexSput));
+    assertTrue(
+        Arrays.stream(method.getMethod().getCode().asDexCode().instructions)
+            .anyMatch(i -> i instanceof DexSputObject));
   }
 
   @Test
@@ -128,8 +130,9 @@
     assertThat(clazz, isPresent());
     MethodSubject method = clazz.method("void", "<clinit>", ImmutableList.of());
     assertThat(method, isPresent());
-    assertTrue(Arrays.stream(method.getMethod().getCode().asDexCode().instructions)
-        .anyMatch(i -> i instanceof SputBoolean));
+    assertTrue(
+        Arrays.stream(method.getMethod().getCode().asDexCode().instructions)
+            .anyMatch(i -> i instanceof DexSputBoolean));
   }
 
   @Test
@@ -141,8 +144,9 @@
     assertThat(clazz, isPresent());
     MethodSubject method = clazz.method("void", "<clinit>", ImmutableList.of());
     assertThat(method, isPresent());
-    assertTrue(Arrays.stream(method.getMethod().getCode().asDexCode().instructions)
-        .anyMatch(i -> i instanceof SputBoolean));
+    assertTrue(
+        Arrays.stream(method.getMethod().getCode().asDexCode().instructions)
+            .anyMatch(i -> i instanceof DexSputBoolean));
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/regress/b115552239/B115552239.java b/src/test/java/com/android/tools/r8/regress/b115552239/B115552239.java
index 5aa5d24..0703498 100644
--- a/src/test/java/com/android/tools/r8/regress/b115552239/B115552239.java
+++ b/src/test/java/com/android/tools/r8/regress/b115552239/B115552239.java
@@ -12,9 +12,9 @@
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.D8Command;
 import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.code.CmpgFloat;
-import com.android.tools.r8.code.IfGez;
-import com.android.tools.r8.code.Instruction;
+import com.android.tools.r8.dex.code.DexCmpgFloat;
+import com.android.tools.r8.dex.code.DexIfGez;
+import com.android.tools.r8.dex.code.DexInstruction;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
@@ -58,14 +58,14 @@
       throws IOException, CompilationFailedException, ExecutionException {
     MethodSubject method = compileTestClassAndGetMethod(AndroidApiLevel.L.getLevel());
     boolean previousWasCmp = false;
-    Instruction[] instructions = method.getMethod().getCode().asDexCode().instructions;
-    assertTrue(Arrays.stream(instructions).anyMatch(i -> i instanceof CmpgFloat));
-    for (Instruction instruction : instructions) {
-      if (instruction instanceof CmpgFloat) {
+    DexInstruction[] instructions = method.getMethod().getCode().asDexCode().instructions;
+    assertTrue(Arrays.stream(instructions).anyMatch(i -> i instanceof DexCmpgFloat));
+    for (DexInstruction instruction : instructions) {
+      if (instruction instanceof DexCmpgFloat) {
         previousWasCmp = true;
         continue;
       } else if (previousWasCmp) {
-        assertTrue(instruction instanceof IfGez);
+        assertTrue(instruction instanceof DexIfGez);
       }
       previousWasCmp = false;
     }
@@ -76,15 +76,15 @@
       throws IOException, CompilationFailedException, ExecutionException {
     MethodSubject method = compileTestClassAndGetMethod(AndroidApiLevel.M.getLevel());
     boolean previousWasCmp = false;
-    Instruction[] instructions = method.getMethod().getCode().asDexCode().instructions;
-    assertTrue(Arrays.stream(instructions).anyMatch(i -> i instanceof CmpgFloat));
-    for (Instruction instruction : instructions) {
-      if (instruction instanceof CmpgFloat) {
+    DexInstruction[] instructions = method.getMethod().getCode().asDexCode().instructions;
+    assertTrue(Arrays.stream(instructions).anyMatch(i -> i instanceof DexCmpgFloat));
+    for (DexInstruction instruction : instructions) {
+      if (instruction instanceof DexCmpgFloat) {
         previousWasCmp = true;
         continue;
       } else if (previousWasCmp) {
         // We lowered the const instruction as close to its use as possible.
-        assertFalse(instruction instanceof IfGez);
+        assertFalse(instruction instanceof DexIfGez);
       }
       previousWasCmp = false;
     }
diff --git a/src/test/java/com/android/tools/r8/regress/b117907456/B117907456.java b/src/test/java/com/android/tools/r8/regress/b117907456/B117907456.java
index 4c092ce..4da22f8 100644
--- a/src/test/java/com/android/tools/r8/regress/b117907456/B117907456.java
+++ b/src/test/java/com/android/tools/r8/regress/b117907456/B117907456.java
@@ -11,12 +11,9 @@
 
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.code.Goto;
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.Return;
-import com.android.tools.r8.code.ReturnVoid;
-import com.android.tools.r8.code.ReturnWide;
-import com.android.tools.r8.code.Throw;
+import com.android.tools.r8.dex.code.DexGoto;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexThrow;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -37,17 +34,17 @@
 
 public class B117907456 extends TestBase {
 
-  private boolean isGoto(Instruction lastInstruction) {
-    return lastInstruction instanceof Goto;
+  private boolean isGoto(DexInstruction lastInstruction) {
+    return lastInstruction instanceof DexGoto;
   }
 
   @Test
   public void testNopDupInsertionForDalvikTracingBug()
       throws IOException, CompilationFailedException, ExecutionException {
     MethodSubject method = getMethodSubject(AndroidApiLevel.K);
-    Instruction[] instructions = method.getMethod().getCode().asDexCode().instructions;
-    Instruction lastInstruction = instructions[instructions.length - 1];
-    assertFalse(lastInstruction instanceof Throw);
+    DexInstruction[] instructions = method.getMethod().getCode().asDexCode().instructions;
+    DexInstruction lastInstruction = instructions[instructions.length - 1];
+    assertFalse(lastInstruction instanceof DexThrow);
     assertTrue(isGoto(lastInstruction));
   }
 
@@ -55,9 +52,9 @@
   public void testNoNopDupInsertionForDalvikTracingBug()
       throws IOException, CompilationFailedException, ExecutionException {
     MethodSubject method = getMethodSubject(AndroidApiLevel.L);
-    Instruction[] instructions = method.getMethod().getCode().asDexCode().instructions;
-    Instruction lastInstruction = instructions[instructions.length - 1];
-    assertTrue(lastInstruction instanceof Throw);
+    DexInstruction[] instructions = method.getMethod().getCode().asDexCode().instructions;
+    DexInstruction lastInstruction = instructions[instructions.length - 1];
+    assertTrue(lastInstruction instanceof DexThrow);
   }
 
   private MethodSubject getMethodSubject(AndroidApiLevel level)
diff --git a/src/test/java/com/android/tools/r8/regress/b142682636/Regress142682636Runner.java b/src/test/java/com/android/tools/r8/regress/b142682636/Regress142682636Runner.java
index d3604b6..78694ea 100644
--- a/src/test/java/com/android/tools/r8/regress/b142682636/Regress142682636Runner.java
+++ b/src/test/java/com/android/tools/r8/regress/b142682636/Regress142682636Runner.java
@@ -10,7 +10,7 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.code.MoveWide;
+import com.android.tools.r8.dex.code.DexMoveWide;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
@@ -54,8 +54,9 @@
   }
 
   private void checkNoMoveWide(MethodSubject m) {
-    assertTrue(Arrays.stream(m.getMethod().getCode().asDexCode().instructions)
-        .noneMatch(i -> i instanceof MoveWide));
+    assertTrue(
+        Arrays.stream(m.getMethod().getCode().asDexCode().instructions)
+            .noneMatch(i -> i instanceof DexMoveWide));
   }
 
 }
diff --git a/src/test/java/com/android/tools/r8/regress/b77496850/B77496850.java b/src/test/java/com/android/tools/r8/regress/b77496850/B77496850.java
index 7fb7e88..375b845 100644
--- a/src/test/java/com/android/tools/r8/regress/b77496850/B77496850.java
+++ b/src/test/java/com/android/tools/r8/regress/b77496850/B77496850.java
@@ -7,8 +7,8 @@
 import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.code.InvokeStatic;
 import com.android.tools.r8.dex.Marker.Tool;
+import com.android.tools.r8.dex.code.DexInvokeStatic;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
@@ -419,8 +419,8 @@
         factory.booleanDescriptor,
         new DexString[]{factory.doubleDescriptor});
     for (int i = 0; i < code.instructions.length; i++) {
-      if (code.instructions[i] instanceof InvokeStatic) {
-        InvokeStatic invoke = (InvokeStatic) code.instructions[i];
+      if (code.instructions[i] instanceof DexInvokeStatic) {
+        DexInvokeStatic invoke = (DexInvokeStatic) code.instructions[i];
         if (invoke.getMethod() == doubleIsNaN) {
           count++;
         }
diff --git a/src/test/java/com/android/tools/r8/regress/b80262475/B80262475.java b/src/test/java/com/android/tools/r8/regress/b80262475/B80262475.java
index b3fc08f..1d70128 100644
--- a/src/test/java/com/android/tools/r8/regress/b80262475/B80262475.java
+++ b/src/test/java/com/android/tools/r8/regress/b80262475/B80262475.java
@@ -5,18 +5,13 @@
 package com.android.tools.r8.regress.b80262475;
 
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static junit.framework.TestCase.assertTrue;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertFalse;
 
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.LongToInt;
-import com.android.tools.r8.code.Return;
-import com.android.tools.r8.code.ReturnVoid;
-import com.android.tools.r8.code.ReturnWide;
-import com.android.tools.r8.code.Throw;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexLongToInt;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -35,9 +30,9 @@
 
 public class B80262475 extends TestBase {
 
-  private boolean overlappingLongToIntInputAndOutput(Instruction instruction) {
-    if (instruction instanceof LongToInt) {
-      LongToInt longToInt = (LongToInt) instruction;
+  private boolean overlappingLongToIntInputAndOutput(DexInstruction instruction) {
+    if (instruction instanceof DexLongToInt) {
+      DexLongToInt longToInt = (DexLongToInt) instruction;
       return longToInt.A == longToInt.B;
     }
     return false;
@@ -47,8 +42,8 @@
   public void testLongToIntOverlap()
       throws IOException, CompilationFailedException, ExecutionException {
     MethodSubject method = getMethodSubject(AndroidApiLevel.L);
-    Instruction[] instructions = method.getMethod().getCode().asDexCode().instructions;
-    for (Instruction instruction : instructions) {
+    DexInstruction[] instructions = method.getMethod().getCode().asDexCode().instructions;
+    for (DexInstruction instruction : instructions) {
       assertFalse(overlappingLongToIntInputAndOutput(instruction));
     }
   }
diff --git a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificAbstractOnIncompletePathTest.java b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificAbstractOnIncompletePathTest.java
new file mode 100644
index 0000000..cf882a8
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificAbstractOnIncompletePathTest.java
@@ -0,0 +1,151 @@
+// 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.resolution.duplicatedefinitions;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestCompilerBuilder;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.MethodResolutionResult;
+import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
+import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.ZipUtils.ZipBuilder;
+import java.nio.file.Path;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * Reproduction of b/231928368. This is testing resolving Main.f for:
+ *
+ * <pre>
+ * I: I_L { abstract f }, I_P { }
+ * class Main implements I
+ * </pre>
+ */
+@RunWith(Parameterized.class)
+public class MaximallySpecificAbstractOnIncompletePathTest extends TestBase {
+
+  @Parameter() public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  private Path libraryClasses;
+
+  @Before
+  public void setup() throws Exception {
+    libraryClasses = temp.newFile("lib.jar").toPath();
+    ZipBuilder.builder(libraryClasses)
+        .addFilesRelative(
+            ToolHelper.getClassPathForTests(), ToolHelper.getClassFileForTestClass(I.class))
+        .build();
+  }
+
+  @Test
+  public void testResolution() throws Exception {
+    assumeTrue(parameters.isOrSimulateNoneRuntime());
+    AppView<AppInfoWithClassHierarchy> appView =
+        computeAppViewWithClassHierarchy(
+            AndroidApp.builder()
+                .addClassProgramData(getMainWithoutFoo(), getIOnProgram())
+                .addLibraryFiles(parameters.getDefaultRuntimeLibrary(), libraryClasses)
+                .build(),
+            null,
+            options -> options.loadAllClassDefinitions = true);
+    AppInfoWithClassHierarchy appInfo = appView.appInfo();
+    DexMethod method = buildNullaryVoidMethod(Main.class, "foo", appInfo.dexItemFactory());
+    MethodResolutionResult methodResolutionResult =
+        appInfo.unsafeResolveMethodDueToDexFormat(method);
+    assertTrue(methodResolutionResult.isSingleResolution());
+    SingleResolutionResult<?> resolution = methodResolutionResult.asSingleResolution();
+    assertTrue(resolution.getResolvedHolder().isLibraryClass());
+    assertEquals(
+        "void " + typeName(I.class) + ".foo()", resolution.getResolvedMethod().toSourceString());
+  }
+
+  @Test
+  public void testJvm() throws Exception {
+    assumeTrue(parameters.isCfRuntime());
+    testForJvm()
+        .addRunClasspathFiles(libraryClasses)
+        .addProgramClassFileData(getMainWithoutFoo(), getIOnProgram())
+        .run(parameters.getRuntime(), Main.class)
+        .assertFailureWithErrorThatThrows(AbstractMethodError.class);
+  }
+
+  @Test
+  public void testD8() throws Exception {
+    assumeTrue(parameters.isDexRuntime());
+    Version dexRuntime = parameters.getDexRuntimeVersion();
+    testForD8(parameters.getBackend())
+        .apply(this::setupTestBuilder)
+        .compile()
+        .addBootClasspathFiles(buildOnDexRuntime(parameters, libraryClasses))
+        .run(parameters.getRuntime(), Main.class)
+        .assertFailureWithErrorThatThrowsIf(dexRuntime.isDalvik(), VerifyError.class)
+        .assertFailureWithErrorThatThrowsIf(!dexRuntime.isDalvik(), AbstractMethodError.class);
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
+        .addKeepMainRule(Main.class)
+        .apply(this::setupTestBuilder)
+        .compile()
+        .addBootClasspathFiles(buildOnDexRuntime(parameters, libraryClasses))
+        .run(parameters.getRuntime(), Main.class)
+        // TODO(b/230289235): Extend to support multiple definition results.
+        .assertFailureWithErrorThatThrows(NoSuchMethodError.class);
+  }
+
+  private void setupTestBuilder(TestCompilerBuilder<?, ?, ?, ?, ?> testBuilder) throws Exception {
+    testBuilder
+        .addProgramClassFileData(getMainWithoutFoo(), getIOnProgram())
+        .addDefaultRuntimeLibrary(parameters)
+        .addLibraryFiles(libraryClasses)
+        .setMinApi(parameters.getApiLevel())
+        .addOptionsModification(options -> options.loadAllClassDefinitions = true);
+  }
+
+  private byte[] getMainWithoutFoo() throws Exception {
+    return transformer(Main.class).removeMethods(MethodPredicate.onName("foo")).transform();
+  }
+
+  private byte[] getIOnProgram() throws Exception {
+    return transformer(I.class).removeMethods(MethodPredicate.all()).transform();
+  }
+
+  public interface I {
+    void foo();
+  }
+
+  public static class Main implements I {
+
+    public static void main(String[] args) {
+      new Main().foo();
+    }
+
+    @Override
+    public void foo() {
+      System.out.println("Should have been removed");
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/rewrite/staticvalues/StaticValuesTest.java b/src/test/java/com/android/tools/r8/rewrite/staticvalues/StaticValuesTest.java
index 662b22e..eb4bb23 100644
--- a/src/test/java/com/android/tools/r8/rewrite/staticvalues/StaticValuesTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/staticvalues/StaticValuesTest.java
@@ -9,8 +9,8 @@
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.ToolHelper.ProcessResult;
-import com.android.tools.r8.code.IfEqz;
-import com.android.tools.r8.code.SgetBoolean;
+import com.android.tools.r8.dex.code.DexIfEqz;
+import com.android.tools.r8.dex.code.DexSgetBoolean;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.graph.DexValue;
 import com.android.tools.r8.smali.SmaliBuilder;
@@ -393,8 +393,8 @@
     assertEquals(("5"), value.asDexValueString().getValue().toString());
 
     DexCode code = inspector.clazz("Test").clinit().getMethod().getCode().asDexCode();
-    assertTrue(code.instructions[0] instanceof SgetBoolean);
-    assertTrue(code.instructions[1] instanceof IfEqz);
+    assertTrue(code.instructions[0] instanceof DexSgetBoolean);
+    assertTrue(code.instructions[1] instanceof DexIfEqz);
 
     String result = runArt(processedApplication);
 
diff --git a/src/test/java/com/android/tools/r8/rewrite/switches/SwitchRewritingTest.java b/src/test/java/com/android/tools/r8/rewrite/switches/SwitchRewritingTest.java
index bcd4063..03275f0 100644
--- a/src/test/java/com/android/tools/r8/rewrite/switches/SwitchRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/switches/SwitchRewritingTest.java
@@ -8,14 +8,14 @@
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.code.Const;
-import com.android.tools.r8.code.Const4;
-import com.android.tools.r8.code.ConstHigh16;
-import com.android.tools.r8.code.IfEq;
-import com.android.tools.r8.code.IfEqz;
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.PackedSwitch;
-import com.android.tools.r8.code.SparseSwitch;
+import com.android.tools.r8.dex.code.DexConst;
+import com.android.tools.r8.dex.code.DexConst4;
+import com.android.tools.r8.dex.code.DexConstHigh16;
+import com.android.tools.r8.dex.code.DexIfEq;
+import com.android.tools.r8.dex.code.DexIfEqz;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexPackedSwitch;
+import com.android.tools.r8.dex.code.DexSparseSwitch;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.smali.SmaliBuilder;
@@ -30,10 +30,10 @@
 
 public class SwitchRewritingTest extends SmaliTestBase {
 
-  private boolean some16BitConst(Instruction instruction) {
-    return instruction instanceof Const4
-        || instruction instanceof ConstHigh16
-        || instruction instanceof Const;
+  private boolean some16BitConst(DexInstruction instruction) {
+    return instruction instanceof DexConst4
+        || instruction instanceof DexConstHigh16
+        || instruction instanceof DexConst;
   }
 
   private void runSingleCaseDexTest(boolean packed, int key) throws CompilationFailedException {
@@ -88,11 +88,11 @@
 
     if (key == 0) {
       assertEquals(5, code.instructions.length);
-      assertTrue(code.instructions[0] instanceof IfEqz);
+      assertTrue(code.instructions[0] instanceof DexIfEqz);
     } else {
       assertEquals(6, code.instructions.length);
       assertTrue(some16BitConst(code.instructions[0]));
-      assertTrue(code.instructions[1] instanceof IfEq);
+      assertTrue(code.instructions[1] instanceof DexIfEq);
     }
   }
 
@@ -158,13 +158,13 @@
     DexEncodedMethod method = getMethod(processedApplication, signature);
     DexCode code = method.getCode().asDexCode();
     if (keyStep <= 2) {
-      assertTrue(code.instructions[0] instanceof PackedSwitch);
+      assertTrue(code.instructions[0] instanceof DexPackedSwitch);
     } else {
       if (additionalLastKey != null && additionalLastKey == Integer.MAX_VALUE) {
-        assertTrue(code.instructions[0] instanceof Const);
-        assertTrue(code.instructions[1] instanceof IfEq);
+        assertTrue(code.instructions[0] instanceof DexConst);
+        assertTrue(code.instructions[1] instanceof DexIfEq);
       } else {
-        assertTrue(code.instructions[0] instanceof SparseSwitch);
+        assertTrue(code.instructions[0] instanceof DexSparseSwitch);
       }
     }
   }
diff --git a/src/test/java/com/android/tools/r8/smali/BinopLiteralTest.java b/src/test/java/com/android/tools/r8/smali/BinopLiteralTest.java
index 7429b43..afd71b9 100644
--- a/src/test/java/com/android/tools/r8/smali/BinopLiteralTest.java
+++ b/src/test/java/com/android/tools/r8/smali/BinopLiteralTest.java
@@ -7,11 +7,11 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.code.Const16;
-import com.android.tools.r8.code.Format22b;
-import com.android.tools.r8.code.Format22s;
-import com.android.tools.r8.code.Return;
 import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.code.DexConst16;
+import com.android.tools.r8.dex.code.DexFormat22b;
+import com.android.tools.r8.dex.code.DexFormat22s;
+import com.android.tools.r8.dex.code.DexReturn;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import java.util.Arrays;
@@ -63,9 +63,9 @@
         );
         DexCode code = method.getCode().asDexCode();
         assertEquals(2, code.instructions.length);
-        assertTrue(code.instructions[0] instanceof Format22b);
-        assertEquals(lit8Value, ((Format22b) code.instructions[0]).CC);
-        assertTrue(code.instructions[1] instanceof Return);
+        assertTrue(code.instructions[0] instanceof DexFormat22b);
+        assertEquals(lit8Value, ((DexFormat22b) code.instructions[0]).CC);
+        assertTrue(code.instructions[1] instanceof DexReturn);
       }
     }
   }
@@ -88,9 +88,9 @@
         );
         DexCode code = method.getCode().asDexCode();
         assertEquals(2, code.instructions.length);
-        assertTrue(code.instructions[0] instanceof Format22s);
-        assertEquals(lit16Value, ((Format22s) code.instructions[0]).CCCC);
-        assertTrue(code.instructions[1] instanceof Return);
+        assertTrue(code.instructions[0] instanceof DexFormat22s);
+        assertEquals(lit16Value, ((DexFormat22s) code.instructions[0]).CCCC);
+        assertTrue(code.instructions[1] instanceof DexReturn);
       }
     }
   }
@@ -111,9 +111,9 @@
         );
         DexCode code = method.getCode().asDexCode();
         assertEquals(3, code.instructions.length);
-        assertTrue(code.instructions[0] instanceof Const16);
-        assertEquals(lit16Value, ((Const16) code.instructions[0]).BBBB);
-        assertTrue(code.instructions[2] instanceof Return);
+        assertTrue(code.instructions[0] instanceof DexConst16);
+        assertEquals(lit16Value, ((DexConst16) code.instructions[0]).BBBB);
+        assertTrue(code.instructions[2] instanceof DexReturn);
       }
     }
   }
diff --git a/src/test/java/com/android/tools/r8/smali/ConstantFoldingTest.java b/src/test/java/com/android/tools/r8/smali/ConstantFoldingTest.java
index b9a9dc8..54fe690 100644
--- a/src/test/java/com/android/tools/r8/smali/ConstantFoldingTest.java
+++ b/src/test/java/com/android/tools/r8/smali/ConstantFoldingTest.java
@@ -6,12 +6,12 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.code.Const4;
-import com.android.tools.r8.code.DivIntLit8;
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.RemIntLit8;
-import com.android.tools.r8.code.Return;
-import com.android.tools.r8.code.ReturnWide;
+import com.android.tools.r8.dex.code.DexConst4;
+import com.android.tools.r8.dex.code.DexDivIntLit8;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexRemIntLit8;
+import com.android.tools.r8.dex.code.DexReturn;
+import com.android.tools.r8.dex.code.DexReturnWide;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.graph.DexEncodedMethod;
@@ -135,13 +135,13 @@
       assertTrue(code.instructions[0] instanceof WideConstant);
       assertEquals(test.result.longValue(),
           ((WideConstant) code.instructions[0]).decodedValue());
-      assertTrue(code.instructions[1] instanceof ReturnWide);
+      assertTrue(code.instructions[1] instanceof DexReturnWide);
     } else {
       assertTrue(code.instructions[0] instanceof SingleConstant);
       assertEquals(
           test.result.longValue(),
           (long) ((SingleConstant) code.instructions[0]).decodedValue());
-      assertTrue(code.instructions[1] instanceof Return);
+      assertTrue(code.instructions[1] instanceof DexReturn);
     }
   }
 
@@ -211,50 +211,50 @@
     testBuilder.addTest(
         (builder, name, parameters) -> {
           builder.addStaticMethod(
-              "int", name, Collections.singletonList("int"),
+              "int",
+              name,
+              Collections.singletonList("int"),
               2,
               "    const/4 v0, 1           ",
               "    const/4 v1, 0           ",
               "    div-int/2addr v0, v1    ",
-              "    return v0\n             "
-          );
+              "    return v0\n             ");
         },
         (method, parameters) -> {
           DexCode code = method.getCode().asDexCode();
           // Division by zero is not folded, but div-int/lit8 is used.
           assertEquals(3, code.instructions.length);
-          assertTrue(code.instructions[0] instanceof Const4);
-          assertTrue(code.instructions[1] instanceof DivIntLit8);
-          assertEquals(0, ((DivIntLit8) code.instructions[1]).CC);
-          assertTrue(code.instructions[2] instanceof Return);
+          assertTrue(code.instructions[0] instanceof DexConst4);
+          assertTrue(code.instructions[1] instanceof DexDivIntLit8);
+          assertEquals(0, ((DexDivIntLit8) code.instructions[1]).CC);
+          assertTrue(code.instructions[2] instanceof DexReturn);
         },
-        null
-    );
+        null);
   }
 
   private void addDivIntFoldRemByZero(SmaliBuilderWithCheckers testBuilder) {
     testBuilder.addTest(
         (builder, name, parameters) -> {
           builder.addStaticMethod(
-            "int", name, Collections.singletonList("int"),
-            2,
-            "    const/4 v0, 1           ",
-            "    const/4 v1, 0           ",
-            "    rem-int/2addr v0, v1    ",
-            "    return v0\n             "
-          );
+              "int",
+              name,
+              Collections.singletonList("int"),
+              2,
+              "    const/4 v0, 1           ",
+              "    const/4 v1, 0           ",
+              "    rem-int/2addr v0, v1    ",
+              "    return v0\n             ");
         },
         (method, parameters) -> {
           DexCode code = method.getCode().asDexCode();
           // Division by zero is not folded, but rem-int/lit8 is used.
           assertEquals(3, code.instructions.length);
-          assertTrue(code.instructions[0] instanceof Const4);
-          assertTrue(code.instructions[1] instanceof RemIntLit8);
-          assertEquals(0, ((RemIntLit8) code.instructions[1]).CC);
-          assertTrue(code.instructions[2] instanceof Return);
+          assertTrue(code.instructions[0] instanceof DexConst4);
+          assertTrue(code.instructions[1] instanceof DexRemIntLit8);
+          assertEquals(0, ((DexRemIntLit8) code.instructions[1]).CC);
+          assertTrue(code.instructions[2] instanceof DexReturn);
         },
-        null
-    );
+        null);
   }
 
   public class UnopTestData {
@@ -302,12 +302,12 @@
     if (wide) {
       assertTrue(code.instructions[0] instanceof WideConstant);
       assertEquals(test.result.longValue(), ((WideConstant) code.instructions[0]).decodedValue());
-      assertTrue(code.instructions[1] instanceof ReturnWide);
+      assertTrue(code.instructions[1] instanceof DexReturnWide);
     } else {
       assertTrue(code.instructions[0] instanceof SingleConstant);
       assertEquals(
           test.result.longValue(), (long) ((SingleConstant) code.instructions[0]).decodedValue());
-      assertTrue(code.instructions[1] instanceof Return);
+      assertTrue(code.instructions[1] instanceof DexReturn);
     }
   }
 
@@ -330,12 +330,12 @@
     addUnopTest(testBuilder, new UnopTestData("double", "neg", doubleBits(-0.0), doubleBits(0.0)));
   }
 
-  private void assertConstValue(int expected, Instruction insn) {
+  private void assertConstValue(int expected, DexInstruction insn) {
     assertTrue(insn instanceof SingleConstant);
     assertEquals(expected, ((SingleConstant) insn).decodedValue());
   }
 
-  private void assertConstValue(long expected, Instruction insn) {
+  private void assertConstValue(long expected, DexInstruction insn) {
     assertTrue(insn instanceof WideConstant);
     assertEquals(expected, ((WideConstant) insn).decodedValue());
   }
@@ -393,7 +393,7 @@
     // Test that this just returns a constant.
     assertEquals(2, code.instructions.length);
     assertConstValue(test.expected, code.instructions[0]);
-    assertTrue(code.instructions[1] instanceof Return);
+    assertTrue(code.instructions[1] instanceof DexReturn);
   }
 
   private void addLogicalOperatorsFoldTests(SmaliBuilderWithCheckers testBuilder) {
@@ -476,7 +476,7 @@
     // Test that this just returns a constant.
     assertEquals(2, code.instructions.length);
     assertConstValue(data.expected, code.instructions[0]);
-    assertTrue(code.instructions[1] instanceof Return);
+    assertTrue(code.instructions[1] instanceof DexReturn);
   }
 
   public void addShiftOperatorsFolding(SmaliBuilderWithCheckers testBuilder) {
@@ -560,7 +560,7 @@
     // Test that this just returns a constant.
     assertEquals(2, code.instructions.length);
     assertConstValue(data.expected, code.instructions[0]);
-    assertTrue(code.instructions[1] instanceof ReturnWide);
+    assertTrue(code.instructions[1] instanceof DexReturnWide);
   }
 
   public void addShiftOperatorsFoldingWide(SmaliBuilderWithCheckers testBuilder) {
@@ -598,7 +598,7 @@
     DexCode code = method.getCode().asDexCode();
     assertEquals(2, code.instructions.length);
     assertConstValue(~value, code.instructions[0]);
-    assertTrue(code.instructions[1] instanceof Return);
+    assertTrue(code.instructions[1] instanceof DexReturn);
   }
 
   private void addNotIntFoldTests(SmaliBuilderWithCheckers testBuilder) throws Exception {
@@ -620,7 +620,7 @@
     DexCode code = method.getCode().asDexCode();
     assertEquals(2, code.instructions.length);
     assertConstValue(~value, code.instructions[0]);
-    assertTrue(code.instructions[1] instanceof ReturnWide);
+    assertTrue(code.instructions[1] instanceof DexReturnWide);
   }
 
 
@@ -650,7 +650,7 @@
     DexCode code = method.getCode().asDexCode();
     assertEquals(2, code.instructions.length);
     assertConstValue(-value, code.instructions[0]);
-    assertTrue(code.instructions[1] instanceof Return);
+    assertTrue(code.instructions[1] instanceof DexReturn);
   }
 
   private void addNegIntFoldTests(SmaliBuilderWithCheckers testBuilder) throws Exception {
@@ -673,7 +673,7 @@
     DexCode code = method.getCode().asDexCode();
     assertEquals(2, code.instructions.length);
     assertConstValue(-value, code.instructions[0]);
-    assertTrue(code.instructions[1] instanceof ReturnWide);
+    assertTrue(code.instructions[1] instanceof DexReturnWide);
   }
 
   private void addNegLongFoldTests(SmaliBuilderWithCheckers testBuilder) throws Exception {
@@ -748,7 +748,7 @@
     DexCode code = method.getCode().asDexCode();
     assertEquals(2, code.instructions.length);
     assertConstValue(test.expected ? 1: 0, code.instructions[0]);
-    assertTrue(code.instructions[1] instanceof Return);
+    assertTrue(code.instructions[1] instanceof DexReturn);
   }
 
   private void addCmpFloatFoldTests(SmaliBuilderWithCheckers testBuilder) throws Exception {
@@ -856,7 +856,7 @@
     DexCode code = method.getCode().asDexCode();
     assertEquals(2, code.instructions.length);
     assertConstValue(test.expected ? 1: 0, code.instructions[0]);
-    assertTrue(code.instructions[1] instanceof Return);
+    assertTrue(code.instructions[1] instanceof DexReturn);
   }
 
 
@@ -920,7 +920,7 @@
     DexCode code = method.getCode().asDexCode();
     assertEquals(2, code.instructions.length);
     assertConstValue(Long.compare(values[0], values[1]), code.instructions[0]);
-    assertTrue(code.instructions[1] instanceof Return);
+    assertTrue(code.instructions[1] instanceof DexReturn);
   }
 
   private void addCmpLongFold(SmaliBuilderWithCheckers testBuilder) throws Exception {
diff --git a/src/test/java/com/android/tools/r8/smali/IfSimplificationTest.java b/src/test/java/com/android/tools/r8/smali/IfSimplificationTest.java
index d42de0f..35dee6e 100644
--- a/src/test/java/com/android/tools/r8/smali/IfSimplificationTest.java
+++ b/src/test/java/com/android/tools/r8/smali/IfSimplificationTest.java
@@ -7,16 +7,16 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.code.Const4;
-import com.android.tools.r8.code.IfEqz;
-import com.android.tools.r8.code.IfGez;
-import com.android.tools.r8.code.IfGtz;
-import com.android.tools.r8.code.IfLez;
-import com.android.tools.r8.code.IfLtz;
-import com.android.tools.r8.code.IfNez;
-import com.android.tools.r8.code.InvokeVirtual;
-import com.android.tools.r8.code.Return;
-import com.android.tools.r8.code.ReturnObject;
+import com.android.tools.r8.dex.code.DexConst4;
+import com.android.tools.r8.dex.code.DexIfEqz;
+import com.android.tools.r8.dex.code.DexIfGez;
+import com.android.tools.r8.dex.code.DexIfGtz;
+import com.android.tools.r8.dex.code.DexIfLez;
+import com.android.tools.r8.dex.code.DexIfLtz;
+import com.android.tools.r8.dex.code.DexIfNez;
+import com.android.tools.r8.dex.code.DexInvokeVirtual;
+import com.android.tools.r8.dex.code.DexReturn;
+import com.android.tools.r8.dex.code.DexReturnObject;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.ir.code.If.Type;
@@ -55,9 +55,9 @@
         "  goto :label_1");
     DexCode code = method.getCode().asDexCode();
     assertEquals(2, code.instructions.length);
-    assertTrue(code.instructions[0] instanceof Const4);
-    assertEquals(0, ((Const4) code.instructions[0]).B);
-    assertTrue(code.instructions[1] instanceof Return);
+    assertTrue(code.instructions[0] instanceof DexConst4);
+    assertEquals(0, ((DexConst4) code.instructions[0]).B);
+    assertTrue(code.instructions[1] instanceof DexReturn);
   }
 
   @Test
@@ -75,9 +75,9 @@
         "  goto :label_1");
     DexCode code = method.getCode().asDexCode();
     assertEquals(2, code.instructions.length);
-    assertTrue(code.instructions[0] instanceof Const4);
-    assertEquals(2, ((Const4) code.instructions[0]).B);
-    assertTrue(code.instructions[1] instanceof Return);
+    assertTrue(code.instructions[0] instanceof DexConst4);
+    assertEquals(2, ((DexConst4) code.instructions[0]).B);
+    assertTrue(code.instructions[1] instanceof DexReturn);
   }
 
   @Test
@@ -99,9 +99,9 @@
         "  goto :label_1");
     DexCode code = method.getCode().asDexCode();
     assertEquals(2, code.instructions.length);
-    assertTrue(code.instructions[0] instanceof Const4);
-    assertEquals(0, ((Const4) code.instructions[0]).B);
-    assertTrue(code.instructions[1] instanceof Return);
+    assertTrue(code.instructions[0] instanceof DexConst4);
+    assertEquals(0, ((DexConst4) code.instructions[0]).B);
+    assertTrue(code.instructions[1] instanceof DexReturn);
   }
 
   @Test
@@ -123,9 +123,9 @@
         "  goto :label_2");
     DexCode code = method.getCode().asDexCode();
     assertEquals(2, code.instructions.length);
-    assertTrue(code.instructions[0] instanceof Const4);
-    assertEquals(0, ((Const4) code.instructions[0]).B);
-    assertTrue(code.instructions[1] instanceof Return);
+    assertTrue(code.instructions[0] instanceof DexConst4);
+    assertEquals(0, ((DexConst4) code.instructions[0]).B);
+    assertTrue(code.instructions[1] instanceof DexReturn);
   }
 
   @Test
@@ -154,9 +154,9 @@
         "  goto :label_2");
     DexCode code = method.getCode().asDexCode();
     assertEquals(2, code.instructions.length);
-    assertTrue(code.instructions[0] instanceof Const4);
-    assertEquals(0, ((Const4) code.instructions[0]).B);
-    assertTrue(code.instructions[1] instanceof Return);
+    assertTrue(code.instructions[0] instanceof DexConst4);
+    assertEquals(0, ((DexConst4) code.instructions[0]).B);
+    assertTrue(code.instructions[1] instanceof DexReturn);
   }
 
   @Test
@@ -181,7 +181,7 @@
         "  return v0");
     DexCode code = method.getCode().asDexCode();
     assertEquals(10, code.instructions.length);
-    assertTrue(code.instructions[9] instanceof Return);
+    assertTrue(code.instructions[9] instanceof DexReturn);
   }
 
   @Test
@@ -199,9 +199,9 @@
         "  goto :label_2");
     DexCode code = method.getCode().asDexCode();
     assertEquals(2, code.instructions.length);
-    assertTrue(code.instructions[0] instanceof Const4);
-    assertEquals(0, ((Const4) code.instructions[0]).B);
-    assertTrue(code.instructions[1] instanceof Return);
+    assertTrue(code.instructions[0] instanceof DexConst4);
+    assertEquals(0, ((DexConst4) code.instructions[0]).B);
+    assertTrue(code.instructions[1] instanceof DexReturn);
   }
 
   @Test
@@ -257,10 +257,10 @@
             "  goto :label_1");
         DexCode code = method.getCode().asDexCode();
         assertEquals(2, code.instructions.length);
-        assertTrue(code.instructions[0] instanceof Const4);
+        assertTrue(code.instructions[0] instanceof DexConst4);
         int expected = test.results[type.ordinal()] ? 1 : 0;
-        assertEquals(expected, ((Const4) code.instructions[0]).B);
-        assertTrue(code.instructions[1] instanceof Return);
+        assertEquals(expected, ((DexConst4) code.instructions[0]).B);
+        assertTrue(code.instructions[1] instanceof DexReturn);
       }
     }
   }
@@ -288,113 +288,121 @@
     DexCode code = method.getCode().asDexCode();
     assertEquals(5, code.instructions.length);
     assertTrue(expected.isInstance(code.instructions[0]));
-    assertTrue(code.instructions[4] instanceof Return);
+    assertTrue(code.instructions[4] instanceof DexReturn);
   }
 
   @Test
   public void testRewriteIfWithConstZero() {
-    runRewriteIfWithConstZeroTest(Type.EQ, true, IfEqz.class);
-    runRewriteIfWithConstZeroTest(Type.NE, true, IfNez.class);
-    runRewriteIfWithConstZeroTest(Type.LE, true, IfGez.class);
-    runRewriteIfWithConstZeroTest(Type.GE, true, IfLez.class);
-    runRewriteIfWithConstZeroTest(Type.LT, true, IfGtz.class);
-    runRewriteIfWithConstZeroTest(Type.GT, true, IfLtz.class);
+    runRewriteIfWithConstZeroTest(Type.EQ, true, DexIfEqz.class);
+    runRewriteIfWithConstZeroTest(Type.NE, true, DexIfNez.class);
+    runRewriteIfWithConstZeroTest(Type.LE, true, DexIfGez.class);
+    runRewriteIfWithConstZeroTest(Type.GE, true, DexIfLez.class);
+    runRewriteIfWithConstZeroTest(Type.LT, true, DexIfGtz.class);
+    runRewriteIfWithConstZeroTest(Type.GT, true, DexIfLtz.class);
 
-    runRewriteIfWithConstZeroTest(Type.EQ, false, IfEqz.class);
-    runRewriteIfWithConstZeroTest(Type.NE, false, IfNez.class);
-    runRewriteIfWithConstZeroTest(Type.LE, false, IfLez.class);
-    runRewriteIfWithConstZeroTest(Type.GE, false, IfGez.class);
-    runRewriteIfWithConstZeroTest(Type.LT, false, IfLtz.class);
-    runRewriteIfWithConstZeroTest(Type.GT, false, IfGtz.class);
+    runRewriteIfWithConstZeroTest(Type.EQ, false, DexIfEqz.class);
+    runRewriteIfWithConstZeroTest(Type.NE, false, DexIfNez.class);
+    runRewriteIfWithConstZeroTest(Type.LE, false, DexIfLez.class);
+    runRewriteIfWithConstZeroTest(Type.GE, false, DexIfGez.class);
+    runRewriteIfWithConstZeroTest(Type.LT, false, DexIfLtz.class);
+    runRewriteIfWithConstZeroTest(Type.GT, false, DexIfGtz.class);
   }
 
   @Test
   public void x() {
-    DexEncodedMethod method = oneMethodApplication(
-        "Test",
-        Lists.newArrayList("Test", "java.lang.String[]", "java.lang.String",
-            "java.lang.String[]", "java.lang.String"),
-        10,
-        "          const/4             v4, 0x00  # 0",
-        "          invoke-virtual      { v10 }, LTest;->a()LTest;",
-        "          if-nez              v4, :label_8",
-        "          move-object         v0, v4",
-        "      :label_7",
-        "          return-object       v0",
-        "      :label_8",
-        "          invoke-static       { v14 }, LTest;->a([Ljava/lang/String;)LTest;",
-        "          move-result-object  v2",
-        "          invoke-virtual      { v2 }, LTest;->a()Z",
-        "          move-result         v0",
-        "          if-nez              v0, :label_20",
-        "          move-object         v0, v4",
-        "          goto                :label_7",
-        "      :label_20",
-        "          iget-wide           v0, v2, LTest;->a:J",
-        "          iget-wide           v6, v2, LTest;->b:J",
-        "          invoke-virtual      { v2 }, LTest;->c()Z",
-        "          move-result         v2",
-        "          if-eqz              v2, :label_33",
-        "          invoke-virtual      { v4 }, LTest;->a()V",
-        "      :label_33",
-        "          new-instance        v5, LTest;",
-        "          sget-object         v2, LTest;->a:[Ljava/lang/String;",
-        "          invoke-direct       { v5, v2 }, LTest;-><init>([Ljava/lang/String;)V",
-        "          invoke-virtual      { v10 }, LTest;->a()LTest;",
-        "          invoke-virtual      { v4, v0, v1, v6, v7 }, LTest;->a(JJ)Ljava/util/List;",
-        "          move-result-object  v2",
-        "          invoke-interface    { v2 }, Ljava/util/List;->iterator()Ljava/util/Iterator;",
-        "          move-result-object  v6",
-        "          move-wide           v2, v0",
-        "      :label_52",
-        "          invoke-interface    { v6 }, Ljava/util/Iterator;->hasNext()Z",
-        "          move-result         v0",
-        "          if-eqz              v0, :label_107",
-        "          invoke-interface    { v6 }, Ljava/util/Iterator;->next()Ljava/lang/Object;",
-        "          move-result-object  v0",
-        "          check-cast          v0, LTest;",
-        "          const-wide/16       v8, 0x0000000000000001  # 1",
-        "          add-long/2addr      v2, v8",
-        "          invoke-virtual      { v5 }, LTest;->newRow()LTest;",
-        "          move-result-object  v1",
-        "          invoke-static       { v2, v3 }, Ljava/lang/Long;->valueOf(J)Ljava/lang/Long;",
-        "          move-result-object  v7",
-        "          invoke-virtual      { v1, v7 }, LTest;->a(Ljava/lang/Object;)LTest;",
-        "          move-result-object  v1",
-        "          const-string        v7, \"add\"",
-        "          invoke-virtual      { v1, v7 }, LTest;->a(Ljava/lang/Object;)LTest;",
-        "          move-result-object  v1",
-        "          iget-object         v7, v0, LTest;->a:Ljava/lang/String;",
-        "          invoke-virtual      { v1, v7 }, LTest;->a(Ljava/lang/Object;)LTest;",
-        "          move-result-object  v1",
-        "          iget                v7, v0, LTest;->b:I",
-        "          invoke-static       { v7 }, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;",
-        "          move-result-object  v7",
-        "          invoke-virtual      { v1, v7 }, LTest;->add(Ljava/lang/Object;)LTest;",
-        "          move-result-object  v1",
-        "          iget-object         v0, v0, LTest;->a:Ljava/lang/String;",
-        "          invoke-virtual      { v1, v0 }, LTest;->add(Ljava/lang/Object;)LTest;",
-        "          goto                :label_52",
-        "      :label_107",
-        "          iget-object         v0, v4, LTest;->a:LTest;",
-        "          const-string        v1, \"text 1\"",
-        "          const/4             v2, 0x00  # 0",
-        "          invoke-virtual      { v0, v1, v2 }, LTest;->a(Ljava/lang/String;I)LTest;",
-        "          move-result-object  v0",
-        "          const-string        v1, \"text 2\"",
-        "          const-string        v2, \"\"",
-        "          invoke-interface    { v0, v1, v2 }, LTest;->getString(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
-        "          move-result-object  v0",
-        "          invoke-static       { v5, v0 }, LTest;->a(LTest;Ljava/lang/String;)LTest;",
-        "          move-result-object  v0",
-        "          goto                :label_7"
-    );
+    DexEncodedMethod method =
+        oneMethodApplication(
+            "Test",
+            Lists.newArrayList(
+                "Test",
+                "java.lang.String[]",
+                "java.lang.String",
+                "java.lang.String[]",
+                "java.lang.String"),
+            10,
+            "          const/4             v4, 0x00  # 0",
+            "          invoke-virtual      { v10 }, LTest;->a()LTest;",
+            "          if-nez              v4, :label_8",
+            "          move-object         v0, v4",
+            "      :label_7",
+            "          return-object       v0",
+            "      :label_8",
+            "          invoke-static       { v14 }, LTest;->a([Ljava/lang/String;)LTest;",
+            "          move-result-object  v2",
+            "          invoke-virtual      { v2 }, LTest;->a()Z",
+            "          move-result         v0",
+            "          if-nez              v0, :label_20",
+            "          move-object         v0, v4",
+            "          goto                :label_7",
+            "      :label_20",
+            "          iget-wide           v0, v2, LTest;->a:J",
+            "          iget-wide           v6, v2, LTest;->b:J",
+            "          invoke-virtual      { v2 }, LTest;->c()Z",
+            "          move-result         v2",
+            "          if-eqz              v2, :label_33",
+            "          invoke-virtual      { v4 }, LTest;->a()V",
+            "      :label_33",
+            "          new-instance        v5, LTest;",
+            "          sget-object         v2, LTest;->a:[Ljava/lang/String;",
+            "          invoke-direct       { v5, v2 }, LTest;-><init>([Ljava/lang/String;)V",
+            "          invoke-virtual      { v10 }, LTest;->a()LTest;",
+            "          invoke-virtual      { v4, v0, v1, v6, v7 }, LTest;->a(JJ)Ljava/util/List;",
+            "          move-result-object  v2",
+            "          invoke-interface    { v2 },"
+                + " Ljava/util/List;->iterator()Ljava/util/Iterator;",
+            "          move-result-object  v6",
+            "          move-wide           v2, v0",
+            "      :label_52",
+            "          invoke-interface    { v6 }, Ljava/util/Iterator;->hasNext()Z",
+            "          move-result         v0",
+            "          if-eqz              v0, :label_107",
+            "          invoke-interface    { v6 }, Ljava/util/Iterator;->next()Ljava/lang/Object;",
+            "          move-result-object  v0",
+            "          check-cast          v0, LTest;",
+            "          const-wide/16       v8, 0x0000000000000001  # 1",
+            "          add-long/2addr      v2, v8",
+            "          invoke-virtual      { v5 }, LTest;->newRow()LTest;",
+            "          move-result-object  v1",
+            "          invoke-static       { v2, v3 },"
+                + " Ljava/lang/Long;->valueOf(J)Ljava/lang/Long;",
+            "          move-result-object  v7",
+            "          invoke-virtual      { v1, v7 }, LTest;->a(Ljava/lang/Object;)LTest;",
+            "          move-result-object  v1",
+            "          const-string        v7, \"add\"",
+            "          invoke-virtual      { v1, v7 }, LTest;->a(Ljava/lang/Object;)LTest;",
+            "          move-result-object  v1",
+            "          iget-object         v7, v0, LTest;->a:Ljava/lang/String;",
+            "          invoke-virtual      { v1, v7 }, LTest;->a(Ljava/lang/Object;)LTest;",
+            "          move-result-object  v1",
+            "          iget                v7, v0, LTest;->b:I",
+            "          invoke-static       { v7 },"
+                + " Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;",
+            "          move-result-object  v7",
+            "          invoke-virtual      { v1, v7 }, LTest;->add(Ljava/lang/Object;)LTest;",
+            "          move-result-object  v1",
+            "          iget-object         v0, v0, LTest;->a:Ljava/lang/String;",
+            "          invoke-virtual      { v1, v0 }, LTest;->add(Ljava/lang/Object;)LTest;",
+            "          goto                :label_52",
+            "      :label_107",
+            "          iget-object         v0, v4, LTest;->a:LTest;",
+            "          const-string        v1, \"text 1\"",
+            "          const/4             v2, 0x00  # 0",
+            "          invoke-virtual      { v0, v1, v2 }, LTest;->a(Ljava/lang/String;I)LTest;",
+            "          move-result-object  v0",
+            "          const-string        v1, \"text 2\"",
+            "          const-string        v2, \"\"",
+            "          invoke-interface    { v0, v1, v2 },"
+                + " LTest;->getString(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
+            "          move-result-object  v0",
+            "          invoke-static       { v5, v0 }, LTest;->a(LTest;Ljava/lang/String;)LTest;",
+            "          move-result-object  v0",
+            "          goto                :label_7");
     DexCode code = method.getCode().asDexCode();
     assertEquals(3, code.instructions.length);
-    assertTrue(code.instructions[0] instanceof InvokeVirtual);
-    assertTrue(code.instructions[1] instanceof Const4);
-    assertEquals(0, ((Const4) code.instructions[1]).B);
-    assertTrue(code.instructions[2] instanceof ReturnObject);
+    assertTrue(code.instructions[0] instanceof DexInvokeVirtual);
+    assertTrue(code.instructions[1] instanceof DexConst4);
+    assertEquals(0, ((DexConst4) code.instructions[1]).B);
+    assertTrue(code.instructions[2] instanceof DexReturnObject);
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/smali/OutlineTest.java b/src/test/java/com/android/tools/r8/smali/OutlineTest.java
index 042bec1..10d96c1 100644
--- a/src/test/java/com/android/tools/r8/smali/OutlineTest.java
+++ b/src/test/java/com/android/tools/r8/smali/OutlineTest.java
@@ -9,24 +9,24 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.code.Const4;
-import com.android.tools.r8.code.ConstString;
-import com.android.tools.r8.code.ConstWide;
-import com.android.tools.r8.code.ConstWideHigh16;
-import com.android.tools.r8.code.DivInt;
-import com.android.tools.r8.code.DivInt2Addr;
-import com.android.tools.r8.code.Goto;
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.InvokeStatic;
-import com.android.tools.r8.code.InvokeStaticRange;
-import com.android.tools.r8.code.InvokeVirtual;
-import com.android.tools.r8.code.MoveResult;
-import com.android.tools.r8.code.MoveResultObject;
-import com.android.tools.r8.code.MoveResultWide;
-import com.android.tools.r8.code.Return;
-import com.android.tools.r8.code.ReturnObject;
-import com.android.tools.r8.code.ReturnVoid;
-import com.android.tools.r8.code.ReturnWide;
+import com.android.tools.r8.dex.code.DexConst4;
+import com.android.tools.r8.dex.code.DexConstString;
+import com.android.tools.r8.dex.code.DexConstWide;
+import com.android.tools.r8.dex.code.DexConstWideHigh16;
+import com.android.tools.r8.dex.code.DexDivInt;
+import com.android.tools.r8.dex.code.DexDivInt2Addr;
+import com.android.tools.r8.dex.code.DexGoto;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexInvokeStatic;
+import com.android.tools.r8.dex.code.DexInvokeStaticRange;
+import com.android.tools.r8.dex.code.DexInvokeVirtual;
+import com.android.tools.r8.dex.code.DexMoveResult;
+import com.android.tools.r8.dex.code.DexMoveResultObject;
+import com.android.tools.r8.dex.code.DexMoveResultWide;
+import com.android.tools.r8.dex.code.DexReturn;
+import com.android.tools.r8.dex.code.DexReturnObject;
+import com.android.tools.r8.dex.code.DexReturnVoid;
+import com.android.tools.r8.dex.code.DexReturnWide;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexItemFactory;
@@ -158,9 +158,9 @@
       DexEncodedMethod method = getMethod(processedApplication, signature);
 
       DexCode code = method.getCode().asDexCode();
-      assertTrue(code.instructions[0] instanceof ConstString);
-      assertTrue(code.instructions[1] instanceof InvokeStatic);
-      InvokeStatic invoke = (InvokeStatic) code.instructions[1];
+      assertTrue(code.instructions[0] instanceof DexConstString);
+      assertTrue(code.instructions[1] instanceof DexInvokeStatic);
+      DexInvokeStatic invoke = (DexInvokeStatic) code.instructions[1];
       assertTrue(isOutlineMethodName(invoke.getMethod()));
 
       // Run code and check result.
@@ -230,10 +230,10 @@
       // Up to 4 const instructions before the invoke of the outline.
       int firstOutlineInvoke = Math.min(i, 4);
       for (int j = 0; j < firstOutlineInvoke; j++) {
-        assertTrue(code.instructions[j] instanceof ConstString);
+        assertTrue(code.instructions[j] instanceof DexConstString);
       }
-      assertTrue(code.instructions[firstOutlineInvoke] instanceof InvokeStatic);
-      InvokeStatic invoke = (InvokeStatic) code.instructions[firstOutlineInvoke];
+      assertTrue(code.instructions[firstOutlineInvoke] instanceof DexInvokeStatic);
+      DexInvokeStatic invoke = (DexInvokeStatic) code.instructions[firstOutlineInvoke];
       assertTrue(isOutlineMethodName(invoke.getMethod()));
 
       // Run code and check result.
@@ -287,9 +287,9 @@
     DexEncodedMethod method = getMethod(processedApplication, signature);
 
     DexCode code = method.getCode().asDexCode();
-    assertTrue(code.instructions[0] instanceof ConstString);
-    assertTrue(code.instructions[1] instanceof InvokeStatic);
-    InvokeStatic invoke = (InvokeStatic) code.instructions[1];
+    assertTrue(code.instructions[0] instanceof DexConstString);
+    assertTrue(code.instructions[1] instanceof DexInvokeStatic);
+    DexInvokeStatic invoke = (DexInvokeStatic) code.instructions[1];
     assertTrue(isOutlineMethodName(invoke.getMethod()));
 
     // Run code and check result.
@@ -349,10 +349,10 @@
     DexEncodedMethod method = getMethod(processedApplication, signature);
 
     DexCode code = method.getCode().asDexCode();
-    assertTrue(code.instructions[0] instanceof ConstString);
-    assertTrue(code.instructions[1] instanceof ConstString);
-    assertTrue(code.instructions[2] instanceof InvokeStatic);
-    InvokeStatic invoke = (InvokeStatic) code.instructions[2];
+    assertTrue(code.instructions[0] instanceof DexConstString);
+    assertTrue(code.instructions[1] instanceof DexConstString);
+    assertTrue(code.instructions[2] instanceof DexInvokeStatic);
+    DexInvokeStatic invoke = (DexInvokeStatic) code.instructions[2];
     assertTrue(isOutlineMethodName(invoke.getMethod()));
 
     // Run code and check result.
@@ -414,16 +414,16 @@
       DexEncodedMethod method = getMethod(processedApplication, signature);
 
       DexCode code = method.getCode().asDexCode();
-      assertTrue(code.instructions[0] instanceof ConstWide);
+      assertTrue(code.instructions[0] instanceof DexConstWide);
       if (i < 3) {
-        assertTrue(code.instructions[1] instanceof InvokeStatic);
-        InvokeStatic invoke = (InvokeStatic) code.instructions[1];
+        assertTrue(code.instructions[1] instanceof DexInvokeStatic);
+        DexInvokeStatic invoke = (DexInvokeStatic) code.instructions[1];
         assertTrue(isOutlineMethodName(invoke.getMethod()));
       } else {
-        assertTrue(code.instructions[1] instanceof InvokeVirtual);
-        assertTrue(code.instructions[2] instanceof InvokeVirtual);
-        assertTrue(code.instructions[3] instanceof InvokeStatic);
-        InvokeStatic invoke = (InvokeStatic) code.instructions[3];
+        assertTrue(code.instructions[1] instanceof DexInvokeVirtual);
+        assertTrue(code.instructions[2] instanceof DexInvokeVirtual);
+        assertTrue(code.instructions[3] instanceof DexInvokeStatic);
+        DexInvokeStatic invoke = (DexInvokeStatic) code.instructions[3];
         assertTrue(isOutlineMethodName(invoke.getMethod()));
       }
 
@@ -491,16 +491,16 @@
       DexEncodedMethod method = getMethod(processedApplication, signature);
 
       DexCode code = method.getCode().asDexCode();
-      assertTrue(code.instructions[0] instanceof ConstWideHigh16);
+      assertTrue(code.instructions[0] instanceof DexConstWideHigh16);
       if (i < 3) {
-        assertTrue(code.instructions[1] instanceof InvokeStatic);
-        InvokeStatic invoke = (InvokeStatic) code.instructions[1];
+        assertTrue(code.instructions[1] instanceof DexInvokeStatic);
+        DexInvokeStatic invoke = (DexInvokeStatic) code.instructions[1];
         assertTrue(isOutlineMethodName(invoke.getMethod()));
       } else {
-        assertTrue(code.instructions[1] instanceof InvokeVirtual);
-        assertTrue(code.instructions[2] instanceof InvokeVirtual);
-        assertTrue(code.instructions[3] instanceof InvokeStatic);
-        InvokeStatic invoke = (InvokeStatic) code.instructions[3];
+        assertTrue(code.instructions[1] instanceof DexInvokeVirtual);
+        assertTrue(code.instructions[2] instanceof DexInvokeVirtual);
+        assertTrue(code.instructions[3] instanceof DexInvokeStatic);
+        DexInvokeStatic invoke = (DexInvokeStatic) code.instructions[3];
         assertTrue(isOutlineMethodName(invoke.getMethod()));
       }
 
@@ -572,14 +572,14 @@
         assert mainCode.instructions.length == 7;
       }
       if (i == 2) {
-        InvokeStatic invoke = (InvokeStatic) mainCode.instructions[4];
+        DexInvokeStatic invoke = (DexInvokeStatic) mainCode.instructions[4];
         assertTrue(isOutlineMethodName(invoke.getMethod()));
       } else if (i == 3) {
-        InvokeStatic invoke = (InvokeStatic) mainCode.instructions[1];
+        DexInvokeStatic invoke = (DexInvokeStatic) mainCode.instructions[1];
         assertTrue(isOutlineMethodName(invoke.getMethod()));
       } else {
         assert i == 4 || i == 5;
-        InvokeStatic invoke = (InvokeStatic) mainCode.instructions[2];
+        DexInvokeStatic invoke = (DexInvokeStatic) mainCode.instructions[2];
         assertTrue(isOutlineMethodName(invoke.getMethod()));
       }
 
@@ -661,14 +661,14 @@
 
     DexCode code1 = getMethod(processedApplication, signature1).getCode().asDexCode();
     assertEquals(4, code1.instructions.length);
-    assertTrue(code1.instructions[1] instanceof InvokeStatic);
-    InvokeStatic invoke1 = (InvokeStatic) code1.instructions[1];
+    assertTrue(code1.instructions[1] instanceof DexInvokeStatic);
+    DexInvokeStatic invoke1 = (DexInvokeStatic) code1.instructions[1];
     assertTrue(isOutlineMethodName(invoke1.getMethod()));
 
     DexCode code2 = getMethod(processedApplication, signature2).getCode().asDexCode();
     assertEquals(5, code2.instructions.length);
-    assertTrue(code2.instructions[2] instanceof InvokeStatic);
-    InvokeStatic invoke2 = (InvokeStatic) code2.instructions[2];
+    assertTrue(code2.instructions[2] instanceof DexInvokeStatic);
+    DexInvokeStatic invoke2 = (DexInvokeStatic) code2.instructions[2];
     assertTrue(isOutlineMethodName(invoke1.getMethod()));
 
     // Run code and check result.
@@ -739,12 +739,12 @@
         default:
           outlineInstructionIndex = 2;
       }
-      Instruction instruction = code.instructions[outlineInstructionIndex];
-      if (instruction instanceof InvokeStatic) {
-        InvokeStatic invoke = (InvokeStatic) instruction;
+      DexInstruction instruction = code.instructions[outlineInstructionIndex];
+      if (instruction instanceof DexInvokeStatic) {
+        DexInvokeStatic invoke = (DexInvokeStatic) instruction;
         assertTrue(isOutlineMethodName(invoke.getMethod()));
       } else {
-        InvokeStaticRange invoke = (InvokeStaticRange) instruction;
+        DexInvokeStaticRange invoke = (DexInvokeStaticRange) instruction;
         assertTrue(isOutlineMethodName(invoke.getMethod()));
       }
 
@@ -791,9 +791,9 @@
     assertEquals(2, getNumberOfProgramClasses(processedApplication));
 
     DexCode code = getMethod(processedApplication, signature1).getCode().asDexCode();
-    InvokeStatic invoke;
-    assertTrue(code.instructions[0] instanceof InvokeStatic);
-    invoke = (InvokeStatic) code.instructions[0];
+    DexInvokeStatic invoke;
+    assertTrue(code.instructions[0] instanceof DexInvokeStatic);
+    invoke = (DexInvokeStatic) code.instructions[0];
     assertTrue(isOutlineMethodName(invoke.getMethod()));
 
     // Run code and check result.
@@ -871,7 +871,7 @@
     // Collect the return types of the outlines for the body of method1 and method2.
     List<DexType> r = new ArrayList<>();
     for (DexEncodedMethod directMethod : outlineMethods) {
-      if (directMethod.getCode().asDexCode().instructions[0] instanceof InvokeVirtual) {
+      if (directMethod.getCode().asDexCode().instructions[0] instanceof DexInvokeVirtual) {
         r.add(directMethod.getReference().proto.returnType);
       }
     }
@@ -1022,10 +1022,10 @@
     // The calls to set, set and getTimeInMillis was outlined.
     DexCode code = method.getCode().asDexCode();
     assertEquals(3, code.instructions.length);
-    assertTrue(code.instructions[0] instanceof InvokeStatic);
-    assertTrue(code.instructions[1] instanceof MoveResultWide);
-    assertTrue(code.instructions[2] instanceof ReturnWide);
-    InvokeStatic invoke = (InvokeStatic) code.instructions[0];
+    assertTrue(code.instructions[0] instanceof DexInvokeStatic);
+    assertTrue(code.instructions[1] instanceof DexMoveResultWide);
+    assertTrue(code.instructions[2] instanceof DexReturnWide);
+    DexInvokeStatic invoke = (DexInvokeStatic) code.instructions[0];
     assertEquals(firstOutlineMethodName(), invoke.getMethod().qualifiedName());
 
     // Run the code and expect a parsable long.
@@ -1139,9 +1139,9 @@
     DexEncodedMethod method = getMethod(processedApplication, signature);
     DexCode code = method.getCode().asDexCode();
     assertEquals(2, code.instructions.length);
-    assertTrue(code.instructions[0] instanceof InvokeStatic);
-    assertTrue(code.instructions[1] instanceof ReturnObject);
-    InvokeStatic invoke = (InvokeStatic) code.instructions[0];
+    assertTrue(code.instructions[0] instanceof DexInvokeStatic);
+    assertTrue(code.instructions[1] instanceof DexReturnObject);
+    DexInvokeStatic invoke = (DexInvokeStatic) code.instructions[0];
     assertEquals(firstOutlineMethodName(), invoke.getMethod().qualifiedName());
 
     // Run code and check result.
@@ -1215,16 +1215,16 @@
     DexEncodedMethod method1 = getMethod(processedApplication, signature1);
     DexCode code1 = method1.getCode().asDexCode();
     assertEquals(3, code1.instructions.length);
-    assertTrue(code1.instructions[0] instanceof InvokeStatic);
-    assertTrue(code1.instructions[1] instanceof MoveResult);
-    assertTrue(code1.instructions[2] instanceof Return);
-    InvokeStatic invoke1 = (InvokeStatic) code1.instructions[0];
+    assertTrue(code1.instructions[0] instanceof DexInvokeStatic);
+    assertTrue(code1.instructions[1] instanceof DexMoveResult);
+    assertTrue(code1.instructions[2] instanceof DexReturn);
+    DexInvokeStatic invoke1 = (DexInvokeStatic) code1.instructions[0];
     assertTrue(isOutlineMethodName(invoke1.getMethod()));
 
     DexEncodedMethod method2 = getMethod(processedApplication, signature2);
     DexCode code2 = method2.getCode().asDexCode();
-    assertTrue(code2.instructions[0] instanceof InvokeStatic);
-    InvokeStatic invoke2 = (InvokeStatic) code2.instructions[0];
+    assertTrue(code2.instructions[0] instanceof DexInvokeStatic);
+    DexInvokeStatic invoke2 = (DexInvokeStatic) code2.instructions[0];
     assertEquals(invoke1.getMethod().qualifiedName(), invoke2.getMethod().qualifiedName());
 
     // Run code and check result.
@@ -1293,14 +1293,14 @@
     DexEncodedMethod method = getMethod(processedApplication, signature);
     DexCode code = method.getCode().asDexCode();
     assertEquals(7, code.instructions.length);
-    assertTrue(code.instructions[0] instanceof DivInt);
-    assertTrue(code.instructions[1] instanceof InvokeStatic);
-    assertTrue(code.instructions[2] instanceof MoveResult);
-    assertTrue(code.instructions[3] instanceof DivInt2Addr);
-    assertTrue(code.instructions[4] instanceof Goto);
-    assertTrue(code.instructions[5] instanceof Const4);
-    assertTrue(code.instructions[6] instanceof Return);
-    InvokeStatic invoke = (InvokeStatic) code.instructions[1];
+    assertTrue(code.instructions[0] instanceof DexDivInt);
+    assertTrue(code.instructions[1] instanceof DexInvokeStatic);
+    assertTrue(code.instructions[2] instanceof DexMoveResult);
+    assertTrue(code.instructions[3] instanceof DexDivInt2Addr);
+    assertTrue(code.instructions[4] instanceof DexGoto);
+    assertTrue(code.instructions[5] instanceof DexConst4);
+    assertTrue(code.instructions[6] instanceof DexReturn);
+    DexInvokeStatic invoke = (DexInvokeStatic) code.instructions[1];
     assertTrue(isOutlineMethodName(invoke.getMethod()));
 
     // Run code and check result.
@@ -1347,10 +1347,10 @@
     DexEncodedMethod method = getMethod(processedApplication, signature);
     DexCode code = method.getCode().asDexCode();
     assertEquals(3, code.instructions.length);
-    assertTrue(code.instructions[0] instanceof InvokeStatic);
-    assertTrue(code.instructions[1] instanceof MoveResultObject);
-    assertTrue(code.instructions[2] instanceof ReturnObject);
-    InvokeStatic invoke = (InvokeStatic) code.instructions[0];
+    assertTrue(code.instructions[0] instanceof DexInvokeStatic);
+    assertTrue(code.instructions[1] instanceof DexMoveResultObject);
+    assertTrue(code.instructions[2] instanceof DexReturnObject);
+    DexInvokeStatic invoke = (DexInvokeStatic) code.instructions[0];
     assertEquals(firstOutlineMethodName(), invoke.getMethod().qualifiedName());
 
     // Run code and check result.
@@ -1405,9 +1405,9 @@
     DexEncodedMethod method = getMethod(processedApplication, signature);
     DexCode code = method.getCode().asDexCode();
     assertEquals(2, code.instructions.length);
-    assertTrue(code.instructions[0] instanceof InvokeStatic);
-    assertTrue(code.instructions[1] instanceof ReturnVoid);
-    InvokeStatic invoke = (InvokeStatic) code.instructions[0];
+    assertTrue(code.instructions[0] instanceof DexInvokeStatic);
+    assertTrue(code.instructions[1] instanceof DexReturnVoid);
+    DexInvokeStatic invoke = (DexInvokeStatic) code.instructions[0];
     assertEquals(firstOutlineMethodName(), invoke.getMethod().qualifiedName());
 
     // Run code and check result.
@@ -1635,8 +1635,8 @@
     runDex2Oat(processedApplication);
   }
 
-  private static boolean isOutlineInvoke(Instruction instruction) {
-    return instruction instanceof InvokeStatic && isOutlineMethodName(instruction.getMethod());
+  private static boolean isOutlineInvoke(DexInstruction instruction) {
+    return instruction instanceof DexInvokeStatic && isOutlineMethodName(instruction.getMethod());
   }
 
   private void assertHasOutlineInvoke(DexEncodedMethod method) {
diff --git a/src/test/java/com/android/tools/r8/smali/RunArtSmokeTest.java b/src/test/java/com/android/tools/r8/smali/RunArtSmokeTest.java
index 4d13ae0..00e8d8f 100644
--- a/src/test/java/com/android/tools/r8/smali/RunArtSmokeTest.java
+++ b/src/test/java/com/android/tools/r8/smali/RunArtSmokeTest.java
@@ -8,10 +8,10 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.code.ConstString;
-import com.android.tools.r8.code.InvokeVirtual;
-import com.android.tools.r8.code.ReturnVoid;
-import com.android.tools.r8.code.SgetObject;
+import com.android.tools.r8.dex.code.DexConstString;
+import com.android.tools.r8.dex.code.DexInvokeVirtual;
+import com.android.tools.r8.dex.code.DexReturnVoid;
+import com.android.tools.r8.dex.code.DexSgetObject;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.smali.SmaliBuilder.MethodSignature;
@@ -42,10 +42,10 @@
     assertNotNull(main);
 
     DexCode code = main.getCode().asDexCode();
-    assertTrue(code.instructions[0] instanceof SgetObject);
-    assertTrue(code.instructions[1] instanceof ConstString);
-    assertTrue(code.instructions[2] instanceof InvokeVirtual);
-    assertTrue(code.instructions[3] instanceof ReturnVoid);
+    assertTrue(code.instructions[0] instanceof DexSgetObject);
+    assertTrue(code.instructions[1] instanceof DexConstString);
+    assertTrue(code.instructions[2] instanceof DexInvokeVirtual);
+    assertTrue(code.instructions[3] instanceof DexReturnVoid);
 
     // Run the generated code in Art.
     String result = runArt(processedApplication);
diff --git a/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java b/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
index b53f301..e3ad2c8 100644
--- a/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
+++ b/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
@@ -42,7 +42,7 @@
   }
 
   public static MethodReference syntheticBackportMethod(Class<?> clazz, int id, Method method) {
-    ClassReference syntheticHolder = syntheticClass(clazz, naming.BACKPORT, id);
+    ClassReference syntheticHolder = syntheticBackportClass(clazz, id);
     MethodReference originalMethod = Reference.methodFromMethod(method);
     return Reference.methodFromDescriptor(
         syntheticHolder.getDescriptor(),
@@ -62,6 +62,26 @@
     return syntheticClass(clazz, naming.LAMBDA, id);
   }
 
+  public static ClassReference syntheticApiOutlineClass(Class<?> clazz, int id) {
+    return syntheticClass(clazz, naming.API_MODEL_OUTLINE, id);
+  }
+
+  public static ClassReference syntheticBackportClass(Class<?> clazz, int id) {
+    return syntheticClass(clazz, naming.BACKPORT, id);
+  }
+
+  public static ClassReference syntheticBackportClass(ClassReference classReference, int id) {
+    return syntheticClass(classReference, naming.BACKPORT, id);
+  }
+
+  public static ClassReference syntheticTwrCloseResourceClass(Class<?> clazz, int id) {
+    return syntheticClass(clazz, naming.TWR_CLOSE_RESOURCE, id);
+  }
+
+  public static ClassReference syntheticTwrCloseResourceClass(ClassReference reference, int id) {
+    return syntheticClass(reference, naming.TWR_CLOSE_RESOURCE, id);
+  }
+
   public static MethodReference syntheticLambdaMethod(Class<?> clazz, int id, Method method) {
     ClassReference syntheticHolder = syntheticLambdaClass(clazz, id);
     MethodReference originalMethod = Reference.methodFromMethod(method);
diff --git a/src/test/java/com/android/tools/r8/tracereferences/TraceFieldResolutionWithLibraryAndProgramClassTest.java b/src/test/java/com/android/tools/r8/tracereferences/TraceFieldResolutionWithLibraryAndProgramClassTest.java
index 4b77aec..028b100 100644
--- a/src/test/java/com/android/tools/r8/tracereferences/TraceFieldResolutionWithLibraryAndProgramClassTest.java
+++ b/src/test/java/com/android/tools/r8/tracereferences/TraceFieldResolutionWithLibraryAndProgramClassTest.java
@@ -15,6 +15,7 @@
 import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.transformers.ClassFileTransformer.FieldPredicate;
 import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.ZipUtils.ZipBuilder;
 import com.google.common.collect.ImmutableSet;
 import java.nio.file.Path;
@@ -83,14 +84,18 @@
                 ToolHelper.getClassPathForTests(), ToolHelper.getClassFileForTestClass(Main.class))
             .build();
     SeenReferencesConsumer consumer = new SeenReferencesConsumer();
-    TraceReferences.run(
+    InternalOptions internalOptions = new InternalOptions();
+    internalOptions.loadAllClassDefinitions = true;
+    // TODO(b/231928368): Remove this when enabled by default.
+    TraceReferences.runForTesting(
         TraceReferencesCommand.builder()
             .addLibraryFiles(ToolHelper.getMostRecentAndroidJar())
             .addLibraryFiles(libJar)
             .addTargetFiles(targetJar)
             .addSourceFiles(sourceJar)
             .setConsumer(consumer)
-            .build());
+            .build(),
+        internalOptions);
     ImmutableSet<FieldReference> expectedSet =
         ImmutableSet.of(
             Reference.field(
diff --git a/src/test/java/com/android/tools/r8/tracereferences/TraceMethodResolutionWithMissingLibraryAndProgramClassTest.java b/src/test/java/com/android/tools/r8/tracereferences/TraceMethodResolutionWithMissingLibraryAndProgramClassTest.java
index 18ece27..f15630e 100644
--- a/src/test/java/com/android/tools/r8/tracereferences/TraceMethodResolutionWithMissingLibraryAndProgramClassTest.java
+++ b/src/test/java/com/android/tools/r8/tracereferences/TraceMethodResolutionWithMissingLibraryAndProgramClassTest.java
@@ -15,6 +15,7 @@
 import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
 import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.ZipUtils.ZipBuilder;
 import com.google.common.collect.ImmutableSet;
 import java.nio.file.Path;
@@ -83,14 +84,18 @@
                 ToolHelper.getClassPathForTests(), ToolHelper.getClassFileForTestClass(Main.class))
             .build();
     SeenReferencesConsumer consumer = new SeenReferencesConsumer();
-    TraceReferences.run(
+    InternalOptions internalOptions = new InternalOptions();
+    internalOptions.loadAllClassDefinitions = true;
+    // TODO(b/231928368): Remove this when enabled by default.
+    TraceReferences.runForTesting(
         TraceReferencesCommand.builder()
             .addLibraryFiles(ToolHelper.getMostRecentAndroidJar())
             .addLibraryFiles(libJar)
             .addTargetFiles(targetJar)
             .addSourceFiles(sourceJar)
             .setConsumer(consumer)
-            .build());
+            .build(),
+        internalOptions);
     ImmutableSet<MethodReference> foundSet =
         ImmutableSet.of(
             Reference.methodFromMethod(A.class.getMethod("foo")),
diff --git a/src/test/java/com/android/tools/r8/tracereferences/TraceSuperMethodResolutionWithLibraryAndProgramClassTest.java b/src/test/java/com/android/tools/r8/tracereferences/TraceSuperMethodResolutionWithLibraryAndProgramClassTest.java
new file mode 100644
index 0000000..fbfe603
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/tracereferences/TraceSuperMethodResolutionWithLibraryAndProgramClassTest.java
@@ -0,0 +1,124 @@
+// 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.tracereferences;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.ZipUtils.ZipBuilder;
+import com.google.common.collect.ImmutableSet;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+/* This is regression test for b/226170842. */
+public class TraceSuperMethodResolutionWithLibraryAndProgramClassTest extends TestBase {
+
+  @Parameter() public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withNoneRuntime().build();
+  }
+
+  static class SeenReferencesConsumer implements TraceReferencesConsumer {
+
+    private final Set<MethodReference> seenMethods = new HashSet<>();
+    private final Set<MethodReference> seenMissingMethods = new HashSet<>();
+
+    @Override
+    public void acceptType(TracedClass tracedClass, DiagnosticsHandler handler) {}
+
+    @Override
+    public void acceptField(TracedField tracedField, DiagnosticsHandler handler) {}
+
+    @Override
+    public void acceptMethod(TracedMethod tracedMethod, DiagnosticsHandler handler) {
+      if (tracedMethod.isMissingDefinition()) {
+        seenMissingMethods.add(tracedMethod.getReference());
+      } else {
+        seenMethods.add(tracedMethod.getReference());
+      }
+    }
+  }
+
+  @Test
+  public void testValidResolution() throws Exception {
+    Path dir = temp.newFolder().toPath();
+    Path libJar =
+        ZipBuilder.builder(dir.resolve("lib.jar"))
+            .addFilesRelative(
+                ToolHelper.getClassPathForTests(), ToolHelper.getClassFileForTestClass(A.class))
+            .build();
+    Path targetJar =
+        ZipBuilder.builder(dir.resolve("target.jar"))
+            .addFilesRelative(
+                ToolHelper.getClassPathForTests(), ToolHelper.getClassFileForTestClass(A.class))
+            .build();
+    Path sourceJar =
+        ZipBuilder.builder(dir.resolve("source.jar"))
+            .addFilesRelative(
+                ToolHelper.getClassPathForTests(),
+                ToolHelper.getClassFileForTestClass(Main.class),
+                ToolHelper.getClassFileForTestClass(ProgramClass.class))
+            .build();
+    SeenReferencesConsumer consumer = new SeenReferencesConsumer();
+    InternalOptions internalOptions = new InternalOptions();
+    internalOptions.loadAllClassDefinitions = true;
+    // TODO(b/231928368): Remove this when enabled by default.
+    TraceReferences.runForTesting(
+        TraceReferencesCommand.builder()
+            .addLibraryFiles(ToolHelper.getMostRecentAndroidJar())
+            .addLibraryFiles(libJar)
+            .addTargetFiles(targetJar)
+            .addSourceFiles(sourceJar)
+            .setConsumer(consumer)
+            .build(),
+        internalOptions);
+    ImmutableSet<MethodReference> foundSet =
+        ImmutableSet.of(
+            Reference.methodFromMethod(A.class.getMethod("foo")),
+            Reference.methodFromMethod(A.class.getConstructor()));
+    assertEquals(foundSet, consumer.seenMethods);
+    assertEquals(Collections.emptySet(), consumer.seenMissingMethods);
+  }
+
+  // A is added to both library and program.
+  public static class A {
+
+    public void foo() {
+      System.out.println("A::foo");
+    }
+  }
+
+  public static class ProgramClass extends A {
+
+    @Override
+    public void foo() {
+      super.foo();
+    }
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) {
+      new ProgramClass().foo();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/Smali.java b/src/test/java/com/android/tools/r8/utils/Smali.java
index ebfd956..30274f0 100644
--- a/src/test/java/com/android/tools/r8/utils/Smali.java
+++ b/src/test/java/com/android/tools/r8/utils/Smali.java
@@ -11,7 +11,6 @@
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexApplication;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.synthesis.SyntheticItems.GlobalSyntheticsStrategy;
 import com.google.common.collect.ImmutableList;
@@ -117,8 +116,7 @@
               AppView.createForD8(
                   AppInfo.createInitialAppInfo(
                       dexApp, GlobalSyntheticsStrategy.forNonSynthesizing())),
-              null,
-              NamingLens.getIdentityLens());
+              null);
       writer.write(executor);
       return consumer.contents;
     } finally {
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CheckCastDexInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CheckCastDexInstructionSubject.java
index ea10ad4..671ec25 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/CheckCastDexInstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CheckCastDexInstructionSubject.java
@@ -4,20 +4,20 @@
 
 package com.android.tools.r8.utils.codeinspector;
 
-import com.android.tools.r8.code.CheckCast;
-import com.android.tools.r8.code.Instruction;
+import com.android.tools.r8.dex.code.DexCheckCast;
+import com.android.tools.r8.dex.code.DexInstruction;
 import com.android.tools.r8.graph.DexType;
 
 public class CheckCastDexInstructionSubject extends DexInstructionSubject
     implements CheckCastInstructionSubject {
-  public CheckCastDexInstructionSubject(Instruction instruction, MethodSubject method) {
+  public CheckCastDexInstructionSubject(DexInstruction instruction, MethodSubject method) {
     super(instruction, method);
     assert isCheckCast();
   }
 
   @Override
   public DexType getType() {
-    return ((CheckCast) instruction).getType();
+    return ((DexCheckCast) instruction).getType();
   }
 
   @Override
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
index d9869b2..44942ab 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
@@ -8,9 +8,9 @@
 import com.android.tools.r8.TestDiagnosticMessagesImpl;
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.cf.code.CfTryCatch;
-import com.android.tools.r8.code.Instruction;
 import com.android.tools.r8.dex.ApplicationReader;
 import com.android.tools.r8.dex.Marker;
+import com.android.tools.r8.dex.code.DexInstruction;
 import com.android.tools.r8.errors.Unimplemented;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.Code;
@@ -391,7 +391,9 @@
   }
 
   InstructionSubject createInstructionSubject(
-      Instruction instruction, MethodSubject method, SwitchPayloadResolver switchPayloadResolver) {
+      DexInstruction instruction,
+      MethodSubject method,
+      SwitchPayloadResolver switchPayloadResolver) {
     DexInstructionSubject dexInst = new DexInstructionSubject(instruction, method);
     if (dexInst.isInvoke()) {
       return new InvokeDexInstructionSubject(this, instruction, method);
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeMatchers.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeMatchers.java
index 76427a3..50a77fe 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeMatchers.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeMatchers.java
@@ -194,6 +194,11 @@
   }
 
   public static Predicate<InstructionSubject> isInvokeWithTarget(
+      String holderType, String methodName) {
+    return isInvokeWithTarget(null, holderType, methodName, (List<String>) null);
+  }
+
+  public static Predicate<InstructionSubject> isInvokeWithTarget(
       String returnType, String holderType, String methodName, List<String> parameterTypes) {
     return instruction -> {
       if (!instruction.isInvoke()) {
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/ConstStringDexInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/ConstStringDexInstructionSubject.java
index ddff370..62da578 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/ConstStringDexInstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/ConstStringDexInstructionSubject.java
@@ -4,25 +4,25 @@
 
 package com.android.tools.r8.utils.codeinspector;
 
-import com.android.tools.r8.code.ConstString;
-import com.android.tools.r8.code.ConstStringJumbo;
-import com.android.tools.r8.code.Instruction;
+import com.android.tools.r8.dex.code.DexConstString;
+import com.android.tools.r8.dex.code.DexConstStringJumbo;
+import com.android.tools.r8.dex.code.DexInstruction;
 import com.android.tools.r8.graph.DexString;
 
 public class ConstStringDexInstructionSubject extends DexInstructionSubject
     implements ConstStringInstructionSubject {
-  public ConstStringDexInstructionSubject(Instruction instruction, MethodSubject method) {
+  public ConstStringDexInstructionSubject(DexInstruction instruction, MethodSubject method) {
     super(instruction, method);
     assert isConstString(JumboStringMode.ALLOW);
   }
 
   @Override
   public DexString getString() {
-    if (instruction instanceof ConstString) {
-      return ((ConstString) instruction).getString();
+    if (instruction instanceof DexConstString) {
+      return ((DexConstString) instruction).getString();
     } else {
-      assert (instruction instanceof ConstStringJumbo);
-      return ((ConstStringJumbo) instruction).getString();
+      assert (instruction instanceof DexConstStringJumbo);
+      return ((DexConstStringJumbo) instruction).getString();
     }
   }
 }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/DexInstructionIterator.java b/src/test/java/com/android/tools/r8/utils/codeinspector/DexInstructionIterator.java
index 1ea464c..31b85c3 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/DexInstructionIterator.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/DexInstructionIterator.java
@@ -4,8 +4,8 @@
 
 package com.android.tools.r8.utils.codeinspector;
 
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.SwitchPayload;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexSwitchPayload;
 import com.android.tools.r8.graph.Code;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.ir.conversion.SwitchPayloadResolver;
@@ -49,12 +49,12 @@
   private void ensureSwitchPayloadResolver() {
     if (switchPayloadResolver == null) {
       switchPayloadResolver = new SwitchPayloadResolver();
-      for (Instruction instruction : code.instructions) {
+      for (DexInstruction instruction : code.instructions) {
         if (instruction.isIntSwitch()) {
           switchPayloadResolver.addPayloadUser(instruction);
         }
         if (instruction.isSwitchPayload()) {
-          switchPayloadResolver.resolve((SwitchPayload) instruction);
+          switchPayloadResolver.resolve((DexSwitchPayload) instruction);
         }
       }
     }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/DexInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/DexInstructionSubject.java
index 00cfc92..2785f57 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/DexInstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/DexInstructionSubject.java
@@ -4,109 +4,109 @@
 
 package com.android.tools.r8.utils.codeinspector;
 
-import com.android.tools.r8.code.Aget;
-import com.android.tools.r8.code.AgetBoolean;
-import com.android.tools.r8.code.AgetByte;
-import com.android.tools.r8.code.AgetChar;
-import com.android.tools.r8.code.AgetObject;
-import com.android.tools.r8.code.AgetShort;
-import com.android.tools.r8.code.AgetWide;
-import com.android.tools.r8.code.Aput;
-import com.android.tools.r8.code.AputBoolean;
-import com.android.tools.r8.code.AputByte;
-import com.android.tools.r8.code.AputChar;
-import com.android.tools.r8.code.AputObject;
-import com.android.tools.r8.code.AputShort;
-import com.android.tools.r8.code.AputWide;
-import com.android.tools.r8.code.ArrayLength;
-import com.android.tools.r8.code.CheckCast;
-import com.android.tools.r8.code.Const;
-import com.android.tools.r8.code.Const16;
-import com.android.tools.r8.code.Const4;
-import com.android.tools.r8.code.ConstClass;
-import com.android.tools.r8.code.ConstHigh16;
-import com.android.tools.r8.code.ConstString;
-import com.android.tools.r8.code.ConstStringJumbo;
-import com.android.tools.r8.code.ConstWide;
-import com.android.tools.r8.code.ConstWide16;
-import com.android.tools.r8.code.ConstWide32;
-import com.android.tools.r8.code.ConstWideHigh16;
-import com.android.tools.r8.code.Goto;
-import com.android.tools.r8.code.IfEq;
-import com.android.tools.r8.code.IfEqz;
-import com.android.tools.r8.code.IfGe;
-import com.android.tools.r8.code.IfGez;
-import com.android.tools.r8.code.IfGt;
-import com.android.tools.r8.code.IfGtz;
-import com.android.tools.r8.code.IfLe;
-import com.android.tools.r8.code.IfLez;
-import com.android.tools.r8.code.IfLt;
-import com.android.tools.r8.code.IfLtz;
-import com.android.tools.r8.code.IfNe;
-import com.android.tools.r8.code.IfNez;
-import com.android.tools.r8.code.Iget;
-import com.android.tools.r8.code.IgetBoolean;
-import com.android.tools.r8.code.IgetByte;
-import com.android.tools.r8.code.IgetChar;
-import com.android.tools.r8.code.IgetObject;
-import com.android.tools.r8.code.IgetShort;
-import com.android.tools.r8.code.IgetWide;
-import com.android.tools.r8.code.InstanceOf;
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.InvokeCustom;
-import com.android.tools.r8.code.InvokeCustomRange;
-import com.android.tools.r8.code.InvokeDirect;
-import com.android.tools.r8.code.InvokeDirectRange;
-import com.android.tools.r8.code.InvokeInterface;
-import com.android.tools.r8.code.InvokeInterfaceRange;
-import com.android.tools.r8.code.InvokeStatic;
-import com.android.tools.r8.code.InvokeStaticRange;
-import com.android.tools.r8.code.InvokeSuper;
-import com.android.tools.r8.code.InvokeSuperRange;
-import com.android.tools.r8.code.InvokeVirtual;
-import com.android.tools.r8.code.InvokeVirtualRange;
-import com.android.tools.r8.code.Iput;
-import com.android.tools.r8.code.IputBoolean;
-import com.android.tools.r8.code.IputByte;
-import com.android.tools.r8.code.IputChar;
-import com.android.tools.r8.code.IputObject;
-import com.android.tools.r8.code.IputShort;
-import com.android.tools.r8.code.IputWide;
-import com.android.tools.r8.code.MonitorEnter;
-import com.android.tools.r8.code.MonitorExit;
-import com.android.tools.r8.code.MulDouble;
-import com.android.tools.r8.code.MulDouble2Addr;
-import com.android.tools.r8.code.MulFloat;
-import com.android.tools.r8.code.MulFloat2Addr;
-import com.android.tools.r8.code.MulInt;
-import com.android.tools.r8.code.MulInt2Addr;
-import com.android.tools.r8.code.MulIntLit16;
-import com.android.tools.r8.code.MulIntLit8;
-import com.android.tools.r8.code.MulLong;
-import com.android.tools.r8.code.MulLong2Addr;
-import com.android.tools.r8.code.NewArray;
-import com.android.tools.r8.code.NewInstance;
-import com.android.tools.r8.code.Nop;
-import com.android.tools.r8.code.PackedSwitch;
-import com.android.tools.r8.code.Return;
-import com.android.tools.r8.code.ReturnObject;
-import com.android.tools.r8.code.ReturnVoid;
-import com.android.tools.r8.code.Sget;
-import com.android.tools.r8.code.SgetBoolean;
-import com.android.tools.r8.code.SgetByte;
-import com.android.tools.r8.code.SgetChar;
-import com.android.tools.r8.code.SgetObject;
-import com.android.tools.r8.code.SgetShort;
-import com.android.tools.r8.code.SgetWide;
-import com.android.tools.r8.code.SparseSwitch;
-import com.android.tools.r8.code.Sput;
-import com.android.tools.r8.code.SputBoolean;
-import com.android.tools.r8.code.SputByte;
-import com.android.tools.r8.code.SputChar;
-import com.android.tools.r8.code.SputObject;
-import com.android.tools.r8.code.SputShort;
-import com.android.tools.r8.code.SputWide;
-import com.android.tools.r8.code.Throw;
+import com.android.tools.r8.dex.code.DexAget;
+import com.android.tools.r8.dex.code.DexAgetBoolean;
+import com.android.tools.r8.dex.code.DexAgetByte;
+import com.android.tools.r8.dex.code.DexAgetChar;
+import com.android.tools.r8.dex.code.DexAgetObject;
+import com.android.tools.r8.dex.code.DexAgetShort;
+import com.android.tools.r8.dex.code.DexAgetWide;
+import com.android.tools.r8.dex.code.DexAput;
+import com.android.tools.r8.dex.code.DexAputBoolean;
+import com.android.tools.r8.dex.code.DexAputByte;
+import com.android.tools.r8.dex.code.DexAputChar;
+import com.android.tools.r8.dex.code.DexAputObject;
+import com.android.tools.r8.dex.code.DexAputShort;
+import com.android.tools.r8.dex.code.DexAputWide;
+import com.android.tools.r8.dex.code.DexArrayLength;
+import com.android.tools.r8.dex.code.DexCheckCast;
+import com.android.tools.r8.dex.code.DexConst;
+import com.android.tools.r8.dex.code.DexConst16;
+import com.android.tools.r8.dex.code.DexConst4;
+import com.android.tools.r8.dex.code.DexConstClass;
+import com.android.tools.r8.dex.code.DexConstHigh16;
+import com.android.tools.r8.dex.code.DexConstString;
+import com.android.tools.r8.dex.code.DexConstStringJumbo;
+import com.android.tools.r8.dex.code.DexConstWide;
+import com.android.tools.r8.dex.code.DexConstWide16;
+import com.android.tools.r8.dex.code.DexConstWide32;
+import com.android.tools.r8.dex.code.DexConstWideHigh16;
+import com.android.tools.r8.dex.code.DexGoto;
+import com.android.tools.r8.dex.code.DexIfEq;
+import com.android.tools.r8.dex.code.DexIfEqz;
+import com.android.tools.r8.dex.code.DexIfGe;
+import com.android.tools.r8.dex.code.DexIfGez;
+import com.android.tools.r8.dex.code.DexIfGt;
+import com.android.tools.r8.dex.code.DexIfGtz;
+import com.android.tools.r8.dex.code.DexIfLe;
+import com.android.tools.r8.dex.code.DexIfLez;
+import com.android.tools.r8.dex.code.DexIfLt;
+import com.android.tools.r8.dex.code.DexIfLtz;
+import com.android.tools.r8.dex.code.DexIfNe;
+import com.android.tools.r8.dex.code.DexIfNez;
+import com.android.tools.r8.dex.code.DexIget;
+import com.android.tools.r8.dex.code.DexIgetBoolean;
+import com.android.tools.r8.dex.code.DexIgetByte;
+import com.android.tools.r8.dex.code.DexIgetChar;
+import com.android.tools.r8.dex.code.DexIgetObject;
+import com.android.tools.r8.dex.code.DexIgetShort;
+import com.android.tools.r8.dex.code.DexIgetWide;
+import com.android.tools.r8.dex.code.DexInstanceOf;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexInvokeCustom;
+import com.android.tools.r8.dex.code.DexInvokeCustomRange;
+import com.android.tools.r8.dex.code.DexInvokeDirect;
+import com.android.tools.r8.dex.code.DexInvokeDirectRange;
+import com.android.tools.r8.dex.code.DexInvokeInterface;
+import com.android.tools.r8.dex.code.DexInvokeInterfaceRange;
+import com.android.tools.r8.dex.code.DexInvokeStatic;
+import com.android.tools.r8.dex.code.DexInvokeStaticRange;
+import com.android.tools.r8.dex.code.DexInvokeSuper;
+import com.android.tools.r8.dex.code.DexInvokeSuperRange;
+import com.android.tools.r8.dex.code.DexInvokeVirtual;
+import com.android.tools.r8.dex.code.DexInvokeVirtualRange;
+import com.android.tools.r8.dex.code.DexIput;
+import com.android.tools.r8.dex.code.DexIputBoolean;
+import com.android.tools.r8.dex.code.DexIputByte;
+import com.android.tools.r8.dex.code.DexIputChar;
+import com.android.tools.r8.dex.code.DexIputObject;
+import com.android.tools.r8.dex.code.DexIputShort;
+import com.android.tools.r8.dex.code.DexIputWide;
+import com.android.tools.r8.dex.code.DexMonitorEnter;
+import com.android.tools.r8.dex.code.DexMonitorExit;
+import com.android.tools.r8.dex.code.DexMulDouble;
+import com.android.tools.r8.dex.code.DexMulDouble2Addr;
+import com.android.tools.r8.dex.code.DexMulFloat;
+import com.android.tools.r8.dex.code.DexMulFloat2Addr;
+import com.android.tools.r8.dex.code.DexMulInt;
+import com.android.tools.r8.dex.code.DexMulInt2Addr;
+import com.android.tools.r8.dex.code.DexMulIntLit16;
+import com.android.tools.r8.dex.code.DexMulIntLit8;
+import com.android.tools.r8.dex.code.DexMulLong;
+import com.android.tools.r8.dex.code.DexMulLong2Addr;
+import com.android.tools.r8.dex.code.DexNewArray;
+import com.android.tools.r8.dex.code.DexNewInstance;
+import com.android.tools.r8.dex.code.DexNop;
+import com.android.tools.r8.dex.code.DexPackedSwitch;
+import com.android.tools.r8.dex.code.DexReturn;
+import com.android.tools.r8.dex.code.DexReturnObject;
+import com.android.tools.r8.dex.code.DexReturnVoid;
+import com.android.tools.r8.dex.code.DexSget;
+import com.android.tools.r8.dex.code.DexSgetBoolean;
+import com.android.tools.r8.dex.code.DexSgetByte;
+import com.android.tools.r8.dex.code.DexSgetChar;
+import com.android.tools.r8.dex.code.DexSgetObject;
+import com.android.tools.r8.dex.code.DexSgetShort;
+import com.android.tools.r8.dex.code.DexSgetWide;
+import com.android.tools.r8.dex.code.DexSparseSwitch;
+import com.android.tools.r8.dex.code.DexSput;
+import com.android.tools.r8.dex.code.DexSputBoolean;
+import com.android.tools.r8.dex.code.DexSputByte;
+import com.android.tools.r8.dex.code.DexSputChar;
+import com.android.tools.r8.dex.code.DexSputObject;
+import com.android.tools.r8.dex.code.DexSputShort;
+import com.android.tools.r8.dex.code.DexSputWide;
+import com.android.tools.r8.dex.code.DexThrow;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.ir.code.SingleConstant;
@@ -114,10 +114,10 @@
 
 public class DexInstructionSubject implements InstructionSubject {
 
-  protected final Instruction instruction;
+  protected final DexInstruction instruction;
   protected final MethodSubject method;
 
-  public DexInstructionSubject(Instruction instruction, MethodSubject method) {
+  public DexInstructionSubject(DexInstruction instruction, MethodSubject method) {
     this.instruction = instruction;
     this.method = method;
   }
@@ -149,46 +149,46 @@
 
   @Override
   public boolean isInstanceGet() {
-    return instruction instanceof Iget
-        || instruction instanceof IgetBoolean
-        || instruction instanceof IgetByte
-        || instruction instanceof IgetShort
-        || instruction instanceof IgetChar
-        || instruction instanceof IgetWide
-        || instruction instanceof IgetObject;
+    return instruction instanceof DexIget
+        || instruction instanceof DexIgetBoolean
+        || instruction instanceof DexIgetByte
+        || instruction instanceof DexIgetShort
+        || instruction instanceof DexIgetChar
+        || instruction instanceof DexIgetWide
+        || instruction instanceof DexIgetObject;
   }
 
   @Override
   public boolean isInstancePut() {
-    return instruction instanceof Iput
-        || instruction instanceof IputBoolean
-        || instruction instanceof IputByte
-        || instruction instanceof IputShort
-        || instruction instanceof IputChar
-        || instruction instanceof IputWide
-        || instruction instanceof IputObject;
+    return instruction instanceof DexIput
+        || instruction instanceof DexIputBoolean
+        || instruction instanceof DexIputByte
+        || instruction instanceof DexIputShort
+        || instruction instanceof DexIputChar
+        || instruction instanceof DexIputWide
+        || instruction instanceof DexIputObject;
   }
 
   @Override
   public boolean isStaticGet() {
-    return instruction instanceof Sget
-        || instruction instanceof SgetBoolean
-        || instruction instanceof SgetByte
-        || instruction instanceof SgetShort
-        || instruction instanceof SgetChar
-        || instruction instanceof SgetWide
-        || instruction instanceof SgetObject;
+    return instruction instanceof DexSget
+        || instruction instanceof DexSgetBoolean
+        || instruction instanceof DexSgetByte
+        || instruction instanceof DexSgetShort
+        || instruction instanceof DexSgetChar
+        || instruction instanceof DexSgetWide
+        || instruction instanceof DexSgetObject;
   }
 
   @Override
   public boolean isStaticPut() {
-    return instruction instanceof Sput
-        || instruction instanceof SputBoolean
-        || instruction instanceof SputByte
-        || instruction instanceof SputShort
-        || instruction instanceof SputChar
-        || instruction instanceof SputWide
-        || instruction instanceof SputObject;
+    return instruction instanceof DexSput
+        || instruction instanceof DexSputBoolean
+        || instruction instanceof DexSputByte
+        || instruction instanceof DexSputShort
+        || instruction instanceof DexSputChar
+        || instruction instanceof DexSputWide
+        || instruction instanceof DexSputObject;
   }
 
   @Override
@@ -208,17 +208,18 @@
 
   @Override
   public boolean isInvokeVirtual() {
-    return instruction instanceof InvokeVirtual || instruction instanceof InvokeVirtualRange;
+    return instruction instanceof DexInvokeVirtual || instruction instanceof DexInvokeVirtualRange;
   }
 
   @Override
   public boolean isInvokeInterface() {
-    return instruction instanceof InvokeInterface || instruction instanceof InvokeInterfaceRange;
+    return instruction instanceof DexInvokeInterface
+        || instruction instanceof DexInvokeInterfaceRange;
   }
 
   @Override
   public boolean isInvokeStatic() {
-    return instruction instanceof InvokeStatic || instruction instanceof InvokeStaticRange;
+    return instruction instanceof DexInvokeStatic || instruction instanceof DexInvokeStaticRange;
   }
 
   @Override
@@ -227,15 +228,15 @@
   }
 
   public boolean isInvokeCustom() {
-    return instruction instanceof InvokeCustom || instruction instanceof InvokeCustomRange;
+    return instruction instanceof DexInvokeCustom || instruction instanceof DexInvokeCustomRange;
   }
 
   public boolean isInvokeSuper() {
-    return instruction instanceof InvokeSuper || instruction instanceof InvokeSuperRange;
+    return instruction instanceof DexInvokeSuper || instruction instanceof DexInvokeSuperRange;
   }
 
   public boolean isInvokeDirect() {
-    return instruction instanceof InvokeDirect || instruction instanceof InvokeDirectRange;
+    return instruction instanceof DexInvokeDirect || instruction instanceof DexInvokeDirectRange;
   }
 
   @Override
@@ -246,19 +247,19 @@
 
   @Override
   public boolean isNop() {
-    return instruction instanceof Nop;
+    return instruction instanceof DexNop;
   }
 
   @Override
   public boolean isConstNumber() {
-    return instruction instanceof Const
-        || instruction instanceof Const4
-        || instruction instanceof Const16
-        || instruction instanceof ConstHigh16
-        || instruction instanceof ConstWide
-        || instruction instanceof ConstWide16
-        || instruction instanceof ConstWide32
-        || instruction instanceof ConstWideHigh16;
+    return instruction instanceof DexConst
+        || instruction instanceof DexConst4
+        || instruction instanceof DexConst16
+        || instruction instanceof DexConstHigh16
+        || instruction instanceof DexConstWide
+        || instruction instanceof DexConstWide16
+        || instruction instanceof DexConstWide32
+        || instruction instanceof DexConstWideHigh16;
   }
 
   @Override
@@ -273,22 +274,22 @@
 
   @Override
   public boolean isConstString(JumboStringMode jumboStringMode) {
-    return instruction instanceof ConstString
-        || (jumboStringMode == JumboStringMode.ALLOW && instruction instanceof ConstStringJumbo);
+    return instruction instanceof DexConstString
+        || (jumboStringMode == JumboStringMode.ALLOW && instruction instanceof DexConstStringJumbo);
   }
 
   @Override
   public boolean isConstString(String value, JumboStringMode jumboStringMode) {
-    return (instruction instanceof ConstString
-            && ((ConstString) instruction).BBBB.toSourceString().equals(value))
+    return (instruction instanceof DexConstString
+            && ((DexConstString) instruction).BBBB.toSourceString().equals(value))
         || (jumboStringMode == JumboStringMode.ALLOW
-            && instruction instanceof ConstStringJumbo
-            && ((ConstStringJumbo) instruction).BBBBBBBB.toSourceString().equals(value));
+            && instruction instanceof DexConstStringJumbo
+            && ((DexConstStringJumbo) instruction).BBBBBBBB.toSourceString().equals(value));
   }
 
   @Override
   public boolean isJumboString() {
-    return instruction instanceof ConstStringJumbo;
+    return instruction instanceof DexConstStringJumbo;
   }
 
   @Override public long getConstNumber() {
@@ -302,44 +303,44 @@
 
   @Override
   public String getConstString() {
-    if (instruction instanceof ConstString) {
-      return ((ConstString) instruction).BBBB.toSourceString();
+    if (instruction instanceof DexConstString) {
+      return ((DexConstString) instruction).BBBB.toSourceString();
     }
-    if (instruction instanceof ConstStringJumbo) {
-      return ((ConstStringJumbo) instruction).BBBBBBBB.toSourceString();
+    if (instruction instanceof DexConstStringJumbo) {
+      return ((DexConstStringJumbo) instruction).BBBBBBBB.toSourceString();
     }
     return null;
   }
 
   @Override
   public boolean isConstClass() {
-    return instruction instanceof ConstClass;
+    return instruction instanceof DexConstClass;
   }
 
   @Override
   public boolean isConstClass(String type) {
-    return isConstClass() && ((ConstClass) instruction).getType().toString().equals(type);
+    return isConstClass() && ((DexConstClass) instruction).getType().toString().equals(type);
   }
 
   @Override
   public boolean isGoto() {
 
-    return instruction instanceof Goto;
+    return instruction instanceof DexGoto;
   }
 
   @Override
   public boolean isIfNez() {
-    return instruction instanceof IfNez;
+    return instruction instanceof DexIfNez;
   }
 
   @Override
   public boolean isIfEq() {
-    return instruction instanceof IfEq;
+    return instruction instanceof DexIfEq;
   }
 
   @Override
   public boolean isIfEqz() {
-    return instruction instanceof IfEqz;
+    return instruction instanceof DexIfEqz;
   }
 
   @Override
@@ -356,73 +357,72 @@
 
   @Override
   public boolean isReturn() {
-    return instruction instanceof Return;
+    return instruction instanceof DexReturn;
   }
 
   @Override
   public boolean isReturnVoid() {
-    return instruction instanceof ReturnVoid;
+    return instruction instanceof DexReturnVoid;
   }
 
   @Override
   public boolean isReturnObject() {
-    return instruction instanceof ReturnObject;
+    return instruction instanceof DexReturnObject;
   }
 
   @Override
   public boolean isThrow() {
-    return instruction instanceof Throw;
+    return instruction instanceof DexThrow;
   }
 
   @Override
   public boolean isNewInstance() {
-    return instruction instanceof NewInstance;
+    return instruction instanceof DexNewInstance;
   }
 
   @Override
   public boolean isNewInstance(String type) {
-    return isNewInstance()
-        && ((NewInstance) instruction).getType().toString().equals(type);
+    return isNewInstance() && ((DexNewInstance) instruction).getType().toString().equals(type);
   }
 
   @Override
   public boolean isCheckCast() {
-    return instruction instanceof CheckCast;
+    return instruction instanceof DexCheckCast;
   }
 
   @Override
   public boolean isCheckCast(String type) {
-    return isCheckCast() && ((CheckCast) instruction).getType().toString().equals(type);
+    return isCheckCast() && ((DexCheckCast) instruction).getType().toString().equals(type);
   }
 
   @Override
   public boolean isInstanceOf() {
-    return instruction instanceof InstanceOf;
+    return instruction instanceof DexInstanceOf;
   }
 
   @Override
   public boolean isInstanceOf(String type) {
-    return isInstanceOf() && ((InstanceOf) instruction).getType().toString().equals(type);
+    return isInstanceOf() && ((DexInstanceOf) instruction).getType().toString().equals(type);
   }
 
   public boolean isConst4() {
-    return instruction instanceof Const4;
+    return instruction instanceof DexConst4;
   }
 
   @Override
   public boolean isIf() {
-    return instruction instanceof IfEq
-        || instruction instanceof IfEqz
-        || instruction instanceof IfGe
-        || instruction instanceof IfGez
-        || instruction instanceof IfGt
-        || instruction instanceof IfGtz
-        || instruction instanceof IfLe
-        || instruction instanceof IfLez
-        || instruction instanceof IfLt
-        || instruction instanceof IfLtz
-        || instruction instanceof IfNe
-        || instruction instanceof IfNez;
+    return instruction instanceof DexIfEq
+        || instruction instanceof DexIfEqz
+        || instruction instanceof DexIfGe
+        || instruction instanceof DexIfGez
+        || instruction instanceof DexIfGt
+        || instruction instanceof DexIfGtz
+        || instruction instanceof DexIfLe
+        || instruction instanceof DexIfLez
+        || instruction instanceof DexIfLt
+        || instruction instanceof DexIfLtz
+        || instruction instanceof DexIfNe
+        || instruction instanceof DexIfNez;
   }
 
   @Override
@@ -432,68 +432,68 @@
 
   @Override
   public boolean isPackedSwitch() {
-    return instruction instanceof PackedSwitch;
+    return instruction instanceof DexPackedSwitch;
   }
 
   @Override
   public boolean isSparseSwitch() {
-    return instruction instanceof SparseSwitch;
+    return instruction instanceof DexSparseSwitch;
   }
 
   @Override
   public boolean isMultiplication() {
-    return instruction instanceof MulInt
-        || instruction instanceof MulIntLit8
-        || instruction instanceof MulIntLit16
-        || instruction instanceof MulInt2Addr
-        || instruction instanceof MulFloat
-        || instruction instanceof MulFloat2Addr
-        || instruction instanceof MulLong
-        || instruction instanceof MulLong2Addr
-        || instruction instanceof MulDouble
-        || instruction instanceof MulDouble2Addr;
+    return instruction instanceof DexMulInt
+        || instruction instanceof DexMulIntLit8
+        || instruction instanceof DexMulIntLit16
+        || instruction instanceof DexMulInt2Addr
+        || instruction instanceof DexMulFloat
+        || instruction instanceof DexMulFloat2Addr
+        || instruction instanceof DexMulLong
+        || instruction instanceof DexMulLong2Addr
+        || instruction instanceof DexMulDouble
+        || instruction instanceof DexMulDouble2Addr;
   }
 
   @Override
   public boolean isNewArray() {
-    return instruction instanceof NewArray;
+    return instruction instanceof DexNewArray;
   }
 
   @Override
   public boolean isArrayLength() {
-    return instruction instanceof ArrayLength;
+    return instruction instanceof DexArrayLength;
   }
 
   @Override
   public boolean isArrayGet() {
-    return instruction instanceof Aget
-        || instruction instanceof AgetBoolean
-        || instruction instanceof AgetByte
-        || instruction instanceof AgetChar
-        || instruction instanceof AgetObject
-        || instruction instanceof AgetShort
-        || instruction instanceof AgetWide;
+    return instruction instanceof DexAget
+        || instruction instanceof DexAgetBoolean
+        || instruction instanceof DexAgetByte
+        || instruction instanceof DexAgetChar
+        || instruction instanceof DexAgetObject
+        || instruction instanceof DexAgetShort
+        || instruction instanceof DexAgetWide;
   }
 
   @Override
   public boolean isArrayPut() {
-    return instruction instanceof Aput
-        || instruction instanceof AputBoolean
-        || instruction instanceof AputByte
-        || instruction instanceof AputChar
-        || instruction instanceof AputObject
-        || instruction instanceof AputShort
-        || instruction instanceof AputWide;
+    return instruction instanceof DexAput
+        || instruction instanceof DexAputBoolean
+        || instruction instanceof DexAputByte
+        || instruction instanceof DexAputChar
+        || instruction instanceof DexAputObject
+        || instruction instanceof DexAputShort
+        || instruction instanceof DexAputWide;
   }
 
   @Override
   public boolean isMonitorEnter() {
-    return instruction instanceof MonitorEnter;
+    return instruction instanceof DexMonitorEnter;
   }
 
   @Override
   public boolean isMonitorExit() {
-    return instruction instanceof MonitorExit;
+    return instruction instanceof DexMonitorExit;
   }
 
   @Override
@@ -527,7 +527,7 @@
     return instruction.toString();
   }
 
-  public Instruction getInstruction() {
+  public DexInstruction getInstruction() {
     return instruction;
   }
 }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FieldAccessDexInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FieldAccessDexInstructionSubject.java
index fcfdbbe..64880f5 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FieldAccessDexInstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FieldAccessDexInstructionSubject.java
@@ -4,7 +4,7 @@
 
 package com.android.tools.r8.utils.codeinspector;
 
-import com.android.tools.r8.code.Instruction;
+import com.android.tools.r8.dex.code.DexInstruction;
 
 public class FieldAccessDexInstructionSubject extends DexInstructionSubject
     implements FieldAccessInstructionSubject {
@@ -12,7 +12,7 @@
   private final CodeInspector codeInspector;
 
   public FieldAccessDexInstructionSubject(
-      CodeInspector codeInspector, Instruction instruction, MethodSubject method) {
+      CodeInspector codeInspector, DexInstruction instruction, MethodSubject method) {
     super(instruction, method);
     this.codeInspector = codeInspector;
     assert isFieldAccess();
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
index c8014e7..8a27919 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
@@ -8,7 +8,7 @@
 
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.cf.code.CfPosition;
-import com.android.tools.r8.code.Instruction;
+import com.android.tools.r8.dex.code.DexInstruction;
 import com.android.tools.r8.errors.Unimplemented;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfo;
@@ -317,7 +317,7 @@
     DexDebugPositionState state =
         new DexDebugPositionState(info.startLine, getMethod().getReference());
     Iterator<DexDebugEvent> iterator = Arrays.asList(info.events).iterator();
-    for (Instruction insn : code.instructions) {
+    for (DexInstruction insn : code.instructions) {
       int offset = insn.getOffset();
       while (state.getCurrentPc() < offset && iterator.hasNext()) {
         iterator.next().accept(state);
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/InvokeDexInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/InvokeDexInstructionSubject.java
index 7f5c6ff..5788846 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/InvokeDexInstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/InvokeDexInstructionSubject.java
@@ -4,7 +4,7 @@
 
 package com.android.tools.r8.utils.codeinspector;
 
-import com.android.tools.r8.code.Instruction;
+import com.android.tools.r8.dex.code.DexInstruction;
 import com.android.tools.r8.graph.DexMethod;
 
 public class InvokeDexInstructionSubject extends DexInstructionSubject
@@ -13,7 +13,7 @@
   private final CodeInspector codeInspector;
 
   public InvokeDexInstructionSubject(
-      CodeInspector codeInspector, Instruction instruction, MethodSubject method) {
+      CodeInspector codeInspector, DexInstruction instruction, MethodSubject method) {
     super(instruction, method);
     this.codeInspector = codeInspector;
     assert isInvoke();
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/NewInstanceDexInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/NewInstanceDexInstructionSubject.java
index ef883fa..ff925b5 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/NewInstanceDexInstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/NewInstanceDexInstructionSubject.java
@@ -4,18 +4,18 @@
 
 package com.android.tools.r8.utils.codeinspector;
 
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.NewInstance;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexNewInstance;
 import com.android.tools.r8.graph.DexType;
 
 public class NewInstanceDexInstructionSubject extends DexInstructionSubject
     implements NewInstanceInstructionSubject {
-  public NewInstanceDexInstructionSubject(Instruction instruction, MethodSubject method) {
+  public NewInstanceDexInstructionSubject(DexInstruction instruction, MethodSubject method) {
     super(instruction, method);
   }
 
   @Override
   public DexType getType() {
-    return ((NewInstance) instruction).getType();
+    return ((DexNewInstance) instruction).getType();
   }
 }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/SwitchDexInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/SwitchDexInstructionSubject.java
index a49553f..6f94d8c 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/SwitchDexInstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/SwitchDexInstructionSubject.java
@@ -4,9 +4,9 @@
 
 package com.android.tools.r8.utils.codeinspector;
 
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.PackedSwitch;
-import com.android.tools.r8.code.SparseSwitch;
+import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexPackedSwitch;
+import com.android.tools.r8.dex.code.DexSparseSwitch;
 import com.android.tools.r8.ir.conversion.SwitchPayloadResolver;
 import it.unimi.dsi.fastutil.ints.IntArrayList;
 import java.util.List;
@@ -17,7 +17,9 @@
   private final SwitchPayloadResolver switchPayloadResolver;
 
   public SwitchDexInstructionSubject(
-      Instruction instruction, MethodSubject method, SwitchPayloadResolver switchPayloadResolver) {
+      DexInstruction instruction,
+      MethodSubject method,
+      SwitchPayloadResolver switchPayloadResolver) {
     super(instruction, method);
     assert isSwitch();
     assert instruction.isIntSwitch();
@@ -27,7 +29,7 @@
 
   @Override
   public List<Integer> getKeys() {
-    if (instruction instanceof PackedSwitch) {
+    if (instruction instanceof DexPackedSwitch) {
       assert switchPayloadResolver.getKeys(instruction.getOffset() + instruction.getPayloadOffset())
               .length
           == 1;
@@ -44,7 +46,7 @@
       }
       return keys;
     } else {
-      assert instruction instanceof SparseSwitch;
+      assert instruction instanceof DexSparseSwitch;
       return new IntArrayList(
           switchPayloadResolver.getKeys(instruction.getOffset() + instruction.getPayloadOffset()));
     }
diff --git a/tools/compare_apk_sizes.py b/tools/compare_apk_sizes.py
index 895633e..1890283 100755
--- a/tools/compare_apk_sizes.py
+++ b/tools/compare_apk_sizes.py
@@ -164,7 +164,7 @@
 def Main():
   (options, args) = parse_options()
   if len(args) is not 2:
-    print args
+    print(args)
     print('Takes exactly two arguments, the two apps to compare')
     return 1
   app1 = args[0]
diff --git a/tools/desugar_jdk_libs_repository.py b/tools/desugar_jdk_libs_repository.py
index 4cace6a..55db5b6 100755
--- a/tools/desugar_jdk_libs_repository.py
+++ b/tools/desugar_jdk_libs_repository.py
@@ -4,6 +4,7 @@
 # BSD-style license that can be found in the LICENSE file.
 
 import argparse
+from enum import Enum
 import os
 from os.path import join
 import shutil
@@ -13,14 +14,30 @@
 import utils
 import create_maven_release
 
+class Configuration(Enum):
+    jdk8 = 'jdk8'
+    jdk11_legacy = 'jdk11-legacy'
+
+    def __str__(self):
+        return self.value
+
 def parse_options():
-  result = argparse.ArgumentParser(
-    description='Local desugared library repository for JDK 11 legacy configuration')
-  result.add_argument('--repo-root', '--repo_root',
+  parser = argparse.ArgumentParser(
+    description='Local desugared library repository for desugared library configurations')
+  parser.add_argument('--repo-root', '--repo_root',
                       default='/tmp/repo',
                       metavar=('<path>'),
                       help='Location for Maven repository.')
-  args = result.parse_args()
+  parser.add_argument('--clear-repo', '--clear_repo',
+                      default=False,
+                      action='store_true',
+                      help='Clear the Maven repository so it only has one version present')
+  parser.add_argument('--configuration', default='jdk8', type=Configuration, choices=list(Configuration))
+  parser.add_argument('--desugar-jdk-libs-checkout', '--desugar_jdk_libs_checkout',
+                      default=None,
+                      metavar=('<path>'),
+                      help='Use existing checkout of github.com/google/desugar_jdk_libs.')
+  args = parser.parse_args()
   return args
 
 def jar_or_pom_file(unzip_dir, artifact, version, extension):
@@ -41,16 +58,29 @@
 
 def main():
   args = parse_options()
-  shutil.rmtree(args.repo_root, ignore_errors=True)
+  if args.clear_repo:
+    shutil.rmtree(args.repo_root, ignore_errors=True)
   utils.makedirs_if_needed(args.repo_root)
+  configuration = (utils.DESUGAR_CONFIGURATION
+                   if args.configuration is Configuration.jdk8
+                   else utils.DESUGAR_CONFIGURATION_JDK11_LEGACY)
+  implementation = (utils.DESUGAR_IMPLEMENTATION
+                    if args.configuration is Configuration.jdk8
+                    else utils.DESUGAR_IMPLEMENTATION_JDK11)
+  version_file = ('VERSION.txt'
+                  if args.configuration is Configuration.jdk8 else
+                  'VERSION_JDK11.txt')
   with utils.TempDir() as tmp_dir:
-    version = utils.desugar_configuration_version(utils.DESUGAR_CONFIGURATION_JDK11_LEGACY)
-
+    version = utils.desugar_configuration_version(configuration)
     # Checkout desugar_jdk_libs from GitHub
-    checkout_dir = join(tmp_dir, 'desugar_jdk_libs')
-    utils.RunCmd(['git', 'clone', 'https://github.com/google/desugar_jdk_libs.git', checkout_dir])
+    use_existing_checkout = args.desugar_jdk_libs_checkout != None
+    checkout_dir = (args.desugar_jdk_libs_checkout
+                    if use_existing_checkout
+                    else join(tmp_dir, 'desugar_jdk_libs'))
+    if (not use_existing_checkout):
+      utils.RunCmd(['git', 'clone', 'https://github.com/google/desugar_jdk_libs.git', checkout_dir])
     with utils.ChangedWorkingDirectory(checkout_dir):
-      with open('VERSION_JDK11.txt') as version_file:
+      with open(version_file) as version_file:
         version_file_lines = version_file.readlines()
         for line in version_file_lines:
           if not line.startswith('#'):
@@ -68,8 +98,8 @@
     maven_zip = join(tmp_dir, 'desugar_configuration.zip')
     create_maven_release.generate_desugar_configuration_maven_zip(
       maven_zip,
-      utils.DESUGAR_CONFIGURATION_JDK11_LEGACY,
-      utils.DESUGAR_IMPLEMENTATION_JDK11)
+      configuration,
+      implementation)
     unzip_dir = join(tmp_dir, 'desugar_jdk_libs_configuration_unzipped')
     cmd = ['unzip', '-q', maven_zip, '-d', unzip_dir]
     utils.RunCmd(cmd)
@@ -91,12 +121,18 @@
           'build',
           '--spawn_strategy=local',
           '--verbose_failures',
-          ':maven_release_jdk11'])
+          (':maven_release'
+            if args.configuration is Configuration.jdk8
+          else ':maven_release_jdk11')])
     unzip_dir = join(tmp_dir, 'desugar_jdk_libs_unzipped')
     cmd = [
         'unzip',
         '-q',
-        join(checkout_dir, 'bazel-bin', 'desugar_jdk_libs_jdk11.zip'),
+        join(checkout_dir,
+            'bazel-bin',
+            ('desugar_jdk_libs.zip'
+              if args.configuration is Configuration.jdk8
+              else 'desugar_jdk_libs_jdk11.zip')),
         '-d',
         unzip_dir]
     utils.RunCmd(cmd)
@@ -122,11 +158,17 @@
     print("    url uri('file://" + args.repo_root + "')")
     print("  }")
     print()
-    print("to dependencyResolutionManagement.repositories in settings.gradle.")
+    print("to dependencyResolutionManagement.repositories in settings.gradle, and use")
+    print('the "changing" property of the coreLibraryDesugaring dependency:')
     print()
-    print("Remember to run gradle with --refresh-dependencies "
-      + "(./gradlew --refresh-dependencies ...) "
-      + "to ensure the cache is not used when the same version is published.")
+    print("  coreLibraryDesugaring('com.android.tools:desugar_jdk_libs:" +  version + "') {")
+    print("    changing = true")
+    print("  }")
+    print()
+    print('If not using the !changing" propertyRemember to run gradle with '
+      + " --refresh-dependencies (./gradlew --refresh-dependencies ...) "
+      + "to ensure the cache is not used when the same version is published."
+      + "multiple times.")
 
 if __name__ == '__main__':
   sys.exit(main())
diff --git a/tools/retrace.py b/tools/retrace.py
index a2df6ef..a7ff23d 100755
--- a/tools/retrace.py
+++ b/tools/retrace.py
@@ -122,6 +122,9 @@
     else:
       args.commit_hash = r8_version_or_hash
     map_path = None
+    if get_hash_from_map_file(utils.R8LIB_MAP) == maphash:
+      return utils.R8LIB_MAP
+
     try:
       map_path = utils.find_cloud_storage_file_from_options(
         'r8lib' + ('-exclude-deps' if is_excldeps else '') + '.jar.map', args)
@@ -134,23 +137,25 @@
       return map_path
 
   # If no other map file was found, use the local mapping file.
-  return utils.R8LIB_JAR + '.map'
+  return utils.R8LIB_MAP
 
 
 def check_maphash(mapping_path, maphash, args):
+  infile_maphash = get_hash_from_map_file(mapping_path)
+  if infile_maphash != maphash:
+    print('ERROR: The mapping file hash does not match the R8 line')
+    print('  In mapping file: ' + infile_maphash)
+    print('  In source file:  ' + maphash)
+    if (not args.exclude_deps):
+      print('If this could be a version without internalized dependencies '
+            + 'try passing --exclude-deps')
+    sys.exit(1)
+
+def get_hash_from_map_file(mapping_path):
   map_hash_header = "# pg_map_hash: SHA-256 "
   for line in open(mapping_path, 'r'):
     if line.startswith(map_hash_header):
-      infile_maphash = line[len(map_hash_header):].strip()
-      if infile_maphash != maphash:
-        print('ERROR: The mapping file hash does not match the R8 line')
-        print('  In mapping file: ' + infile_maphash)
-        print('  In source file:  ' + maphash)
-        if (not args.exclude_deps):
-          print('If this could be a version without internalized dependencies '
-              + 'try passing --exclude-deps')
-        sys.exit(1)
-
+      return line[len(map_hash_header):].strip()
 
 def main():
   args = parse_arguments()
diff --git a/tools/startup/adb_utils.py b/tools/startup/adb_utils.py
index 7f1d3bc..b5e2af2 100644
--- a/tools/startup/adb_utils.py
+++ b/tools/startup/adb_utils.py
@@ -95,6 +95,16 @@
       ['shell', 'echo 3 > /proc/sys/vm/drop_caches'], device_id)
   subprocess.check_call(cmd, stdout=DEVNULL, stderr=DEVNULL)
 
+def ensure_screen_on(device_id=None):
+  if get_screen_state(device_id).is_off():
+    toggle_screen(device_id)
+  assert get_screen_state(device_id).is_on()
+
+def ensure_screen_off(device_id=None):
+  if get_screen_state(device_id).is_on():
+    toggle_screen(device_id)
+  assert get_screen_state(device_id).is_off()
+
 def force_compilation(app_id, device_id=None):
   print('Applying AOT (full)')
   cmd = create_adb_cmd(
@@ -268,10 +278,10 @@
   # Unlock device.
   unlock(device_id, device_pin)
 
-  tear_down_options = {
+  teardown_options = {
     'previous_screen_off_timeout': previous_screen_off_timeout
   }
-  return tear_down_options
+  return teardown_options
 
 def root(device_id=None):
   cmd = create_adb_cmd('root', device_id)
@@ -308,12 +318,15 @@
   cmd = create_adb_cmd('shell am force-stop %s' % app_id, device_id)
   subprocess.check_call(cmd, stdout=DEVNULL, stderr=DEVNULL)
 
-def tear_down_after_interaction_with_device(tear_down_options, device_id=None):
+def teardown_after_interaction_with_device(teardown_options, device_id=None):
   # Reset screen off timeout.
   set_screen_off_timeout(
-      tear_down_options['previous_screen_off_timeout'],
+      teardown_options['previous_screen_off_timeout'],
       device_id)
 
+def toggle_screen(device_id=None):
+  issue_key_event('KEYCODE_POWER', device_id)
+
 def uninstall(app_id, device_id=None):
   print('Uninstalling %s' % app_id)
   cmd = create_adb_cmd('uninstall %s' % app_id, device_id)
@@ -329,10 +342,8 @@
         or expected_error in stderr
 
 def unlock(device_id=None, device_pin=None):
+  ensure_screen_on(device_id)
   screen_state = get_screen_state(device_id)
-  if screen_state.is_off():
-    issue_key_event('KEYCODE_POWER', device_id)
-    screen_state = get_screen_state(device_id)
   assert screen_state.is_on(), 'was %s' % screen_state
   if screen_state.is_on_and_locked():
     if device_pin is not None:
diff --git a/tools/startup/measure_startup.py b/tools/startup/measure_startup.py
index f0b2ce9..04076ec 100755
--- a/tools/startup/measure_startup.py
+++ b/tools/startup/measure_startup.py
@@ -5,6 +5,7 @@
 
 import argparse
 import os
+import statistics
 import sys
 import time
 
@@ -35,47 +36,76 @@
   # Unlock device.
   adb_utils.unlock(options.device_id, options.device_pin)
 
-  tear_down_options = {
+  teardown_options = {
     'previous_screen_off_timeout': previous_screen_off_timeout
   }
-  return tear_down_options
+  return teardown_options
 
-def tear_down(options, tear_down_options):
+def teardown(options, teardown_options):
   # Reset screen off timeout.
   adb_utils.set_screen_off_timeout(
-      tear_down_options['previous_screen_off_timeout'],
+      teardown_options['previous_screen_off_timeout'],
       options.device_id)
 
 def run_all(apk, options, tmp_dir):
   # Launch app while collecting information.
-  data_avg = {}
-  for iteration in range(options.iterations):
+  data_total = {}
+  for iteration in range(1, options.iterations + 1):
     print('Starting iteration %i' % iteration)
     out_dir = os.path.join(options.out_dir, str(iteration))
-    prepare_for_run(apk, out_dir, options)
+    teardown_options = setup_for_run(apk, out_dir, options)
     data = run(out_dir, options, tmp_dir)
-    add_data(data_avg, data)
-    print("Result:")
+    teardown_for_run(options, teardown_options)
+    add_data(data_total, data)
+    print('Result:')
     print(data)
-    print("Done")
-  for key, value in data_avg.items():
-    if isinstance(value, int):
-      data_avg[key] = value / options.iterations
-  print("Average result:")
-  print(data_avg)
-  write_data(options.out_dir, data_avg)
+    print(compute_data_summary(data_total))
+    print('Done')
+  print('Average result:')
+  data_summary = compute_data_summary(data_total)
+  print(data_summary)
+  write_data(options.out_dir, data_summary)
 
-def prepare_for_run(apk, out_dir, options):
+def compute_data_summary(data_total):
+  data_summary = {}
+  for key, value in data_total.items():
+    if not isinstance(value, list):
+      data_summary[key] = value
+      continue
+    data_summary['%s_avg' % key] = round(statistics.mean(value), 1)
+    data_summary['%s_med' % key] = statistics.median(value)
+  return data_summary
+
+def setup_for_run(apk, out_dir, options):
   adb_utils.root(options.device_id)
+
+  print('Installing')
   adb_utils.uninstall(options.app_id, options.device_id)
   adb_utils.install(apk, options.device_id)
+  os.makedirs(out_dir, exist_ok=True)
+
+  # AOT compile.
   if options.aot:
+    print('AOT compiling')
     if options.baseline_profile:
       adb_utils.clear_profile_data(options.app_id, options.device_id)
       adb_utils.install_profile(options.app_id, options.device_id)
     else:
       adb_utils.force_compilation(options.app_id, options.device_id)
+
+  # Cooldown and then unlock device.
+  if options.cooldown > 0:
+    print('Cooling down for %i seconds' % options.cooldown)
+    assert adb_utils.get_screen_state(options.device_id).is_off()
+    time.sleep(options.cooldown)
+    teardown_options = adb_utils.prepare_for_interaction_with_device(
+        options.device_id, options.device_pin)
+  else:
+    teardown_options = None
+
+  # Prelaunch for hot startup.
   if options.hot_startup:
+    print('Prelaunching')
     adb_utils.launch_activity(
         options.app_id,
         options.main_activity,
@@ -84,8 +114,20 @@
     time.sleep(options.startup_duration)
     adb_utils.navigate_to_home_screen(options.device_id)
     time.sleep(1)
+
+  # Drop caches before run.
   adb_utils.drop_caches(options.device_id)
-  os.makedirs(out_dir, exist_ok=True)
+  return teardown_options
+
+def teardown_for_run(options, teardown_options):
+  assert adb_utils.get_screen_state(options.device_id).is_on_and_unlocked()
+
+  if options.cooldown > 0:
+    adb_utils.teardown_after_interaction_with_device(
+        teardown_options, options.device_id)
+    adb_utils.ensure_screen_off(options.device_id)
+  else:
+    assert teardown_options is None
 
 def run(out_dir, options, tmp_dir):
   assert adb_utils.get_screen_state(options.device_id).is_on_and_unlocked()
@@ -113,20 +155,24 @@
   write_data(out_dir, data)
   return data
 
-def add_data(sum_data, data):
+def add_data(data_total, data):
   for key, value in data.items():
+    if key == 'app_id':
+      assert data_total.get(key, value) == value
+      data_total[key] = value
     if key == 'time':
       continue
-    if key in sum_data:
+    if key in data_total:
       if key == 'app_id':
-        assert sum_data[key] == value
+        assert data_total[key] == value
       else:
-        existing_value = sum_data[key]
+        existing_value = data_total[key]
         assert isinstance(value, int)
-        assert isinstance(existing_value, int)
-        sum_data[key] = existing_value + value
+        assert isinstance(existing_value, list)
+        existing_value.append(value)
     else:
-      sum_data[key] = value
+      assert isinstance(value, int), key
+      data_total[key] = [value]
 
 def compute_data(launch_activity_result, perfetto_trace_path, options):
   minfl, majfl = adb_utils.get_minor_major_page_faults(
@@ -202,6 +248,10 @@
   result.add_argument('--apk',
                       help='Path to the APK',
                       required=True)
+  result.add_argument('--cooldown',
+                      help='Seconds to wait before running each iteration',
+                      default=0,
+                      type=int)
   result.add_argument('--device-id',
                       help='Device id (e.g., emulator-5554).')
   result.add_argument('--device-pin',
@@ -236,16 +286,33 @@
   assert options.aot or not options.baseline_profile
   return options, args
 
+def global_setup(options):
+  # If there is no cooldown then unlock the screen once. Otherwise we turn off
+  # the screen during the cooldown and unlock the screen before each iteration.
+  teardown_options = None
+  if options.cooldown == 0:
+    teardown_options = adb_utils.prepare_for_interaction_with_device(
+        options.device_id, options.device_pin)
+    assert adb_utils.get_screen_state(options.device_id).is_on()
+  else:
+    adb_utils.ensure_screen_off(options.device_id)
+  return teardown_options
+
+def global_teardown(options, teardown_options):
+  if options.cooldown == 0:
+    adb_utils.teardown_after_interaction_with_device(
+        teardown_options, options.device_id)
+  else:
+    assert teardown_options is None
+
 def main(argv):
   (options, args) = parse_options(argv)
   with utils.TempDir() as tmp_dir:
     apk = apk_utils.add_baseline_profile_to_apk(
         options.apk, options.baseline_profile, tmp_dir)
-    tear_down_options = adb_utils.prepare_for_interaction_with_device(
-        options.device_id, options.device_pin)
+    teardown_options = global_setup(options)
     run_all(apk, options, tmp_dir)
-    adb_utils.tear_down_after_interaction_with_device(
-        tear_down_options, options.device_id)
+    global_teardown(options, teardown_options)
 
 if __name__ == '__main__':
   sys.exit(main(sys.argv[1:]))
\ No newline at end of file
diff --git a/tools/utils.py b/tools/utils.py
index 27a8feb..85fda69 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -54,7 +54,7 @@
 R8_JAR = os.path.join(LIBS, 'r8.jar')
 R8_WITH_RELOCATED_DEPS_JAR = os.path.join(LIBS, 'r8_with_relocated_deps.jar')
 R8LIB_JAR = os.path.join(LIBS, 'r8lib.jar')
-R8LIB_MAP = os.path.join(LIBS, 'r8lib.jar.map')
+R8LIB_MAP = '%s.map' % R8LIB_JAR
 R8_SRC_JAR = os.path.join(LIBS, 'r8-src.jar')
 R8LIB_EXCLUDE_DEPS_JAR = os.path.join(LIBS, 'r8lib-exclude-deps.jar')
 R8_FULL_EXCLUDE_DEPS_JAR = os.path.join(LIBS, 'r8-full-exclude-deps.jar')