Merge commit '2d30ea640b430b21798176dbdfde18b8dc855841' into dev-release
diff --git a/build.gradle b/build.gradle
index e614057..fe2980a 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1027,6 +1027,7 @@
             input,
             "--output", output,
             "--pg-map-output", output + ".map",
+            "--partition-map-output", output + "_map.zip",
             "--lib", org.gradle.internal.jvm.Jvm.current().javaHome,
     ] + args + libs.collectMany { ["--lib", it] } + pgConfs.collectMany { ["--pg-conf", it] }
     return baseR8CommandLine(allArgs)
diff --git a/infra/config/global/generated/luci-milo.cfg b/infra/config/global/generated/luci-milo.cfg
index 4073c3d..b1481fe 100644
--- a/infra/config/global/generated/luci-milo.cfg
+++ b/infra/config/global/generated/luci-milo.cfg
@@ -126,11 +126,6 @@
     short_name: "kotlin_old"
   }
   builders {
-    name: "buildbucket/luci.r8.ci/smali"
-    category: "R8"
-    short_name: "smali"
-  }
-  builders {
     name: "buildbucket/luci.r8.ci/lib_desugar-archive-jdk11"
     category: "library_desugar"
     short_name: "jdk11"
diff --git a/infra/config/global/generated/luci-notify.cfg b/infra/config/global/generated/luci-notify.cfg
index 5417911..fa8d5b0 100644
--- a/infra/config/global/generated/luci-notify.cfg
+++ b/infra/config/global/generated/luci-notify.cfg
@@ -540,18 +540,6 @@
   }
   builders {
     bucket: "ci"
-    name: "smali"
-    repository: "https://r8.googlesource.com/r8"
-  }
-}
-notifiers {
-  notifications {
-    on_failure: true
-    on_new_failure: true
-    notify_blamelist {}
-  }
-  builders {
-    bucket: "ci"
     name: "windows"
     repository: "https://r8.googlesource.com/r8"
   }
diff --git a/infra/config/global/generated/luci-scheduler.cfg b/infra/config/global/generated/luci-scheduler.cfg
index 982d085..e59d20c 100644
--- a/infra/config/global/generated/luci-scheduler.cfg
+++ b/infra/config/global/generated/luci-scheduler.cfg
@@ -820,7 +820,6 @@
   triggers: "linux-kotlin_old"
   triggers: "linux-none"
   triggers: "linux-run-on-app-dump"
-  triggers: "smali"
   triggers: "windows"
   gitiles {
     repo: "https://r8.googlesource.com/r8"
diff --git a/infra/config/global/main.star b/infra/config/global/main.star
index 1e374ed..d9201a8 100755
--- a/infra/config/global/main.star
+++ b/infra/config/global/main.star
@@ -147,7 +147,6 @@
     refs = ["refs/heads/.*"]
 )
 
-
 view_builders = []
 
 def builder_view(name, category, short_name):
@@ -412,6 +411,8 @@
 
 r8_builder(
     "smali",
+    category = "aux",
+    trigger = False,
     dimensions = get_dimensions(smali=True),
     triggering_policy = scheduler.policy(
         kind = scheduler.GREEDY_BATCHING_KIND,
@@ -434,9 +435,15 @@
   "Release|R8",
 ]
 
+categories_with_no_console = [
+  "aux",
+]
+
 def add_view_entries():
   # Ensure that all categories are ordered
   for v in view_builders:
+    if v[1] in categories_with_no_console:
+      continue
     if not v[1] in order_of_categories:
       fail()
   for category in order_of_categories:
diff --git a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
index cc62da7..890f3f9 100644
--- a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
+++ b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
@@ -401,7 +401,7 @@
      *
      * @param partitionMapOutput File-system path to write output at.
      */
-    B setPartitionMapOutputPath(Path partitionMapOutput) {
+    public B setPartitionMapOutputPath(Path partitionMapOutput) {
       assert partitionMapOutput != null;
       return setPartitionMapConsumer(MapConsumerUtils.createZipConsumer(partitionMapOutput));
     }
@@ -414,7 +414,7 @@
      *
      * @param partitionMapConsumer Consumer to receive the content once produced.
      */
-    B setPartitionMapConsumer(PartitionMapConsumer partitionMapConsumer) {
+    public B setPartitionMapConsumer(PartitionMapConsumer partitionMapConsumer) {
       this.partitionMapConsumer = partitionMapConsumer;
       return self();
     }
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index a97ec22..e2c826a 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8;
 
 import static com.android.tools.r8.utils.InternalOptions.DETERMINISTIC_DEBUGGING;
+import static com.android.tools.r8.utils.MapConsumerUtils.wrapExistingMapConsumerIfNotNull;
 
 import com.android.tools.r8.dex.Marker.Tool;
 import com.android.tools.r8.dump.DumpOptions;
@@ -12,6 +13,7 @@
 import com.android.tools.r8.inspector.Inspector;
 import com.android.tools.r8.inspector.internal.InspectorImpl;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
+import com.android.tools.r8.naming.MapConsumer;
 import com.android.tools.r8.naming.ProguardMapStringConsumer;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.profile.art.ArtProfileForRewriting;
@@ -88,7 +90,7 @@
 
     private boolean intermediate = false;
     private GlobalSyntheticsConsumer globalSyntheticsConsumer = null;
-    private List<GlobalSyntheticsResourceProvider> globalSyntheticsResourceProviders =
+    private final List<GlobalSyntheticsResourceProvider> globalSyntheticsResourceProviders =
         new ArrayList<>();
     private DesugarGraphConsumer desugarGraphConsumer = null;
     private SyntheticInfoConsumer syntheticInfoConsumer = null;
@@ -186,6 +188,43 @@
     }
 
     /**
+     * Set an output destination to which partition-map content should be written.
+     *
+     * <p>Note that when a proguard-map output is specified for a release build, the compiler will
+     * optimize the line-number information and obtaining a source-level stacktrace will require the
+     * use of a retrace tool exactly as is needed for programs built by R8.
+     *
+     * <p>This is a short-hand for setting a {@link PartitionMapConsumer} using {@link
+     * #setPartitionMapConsumer}. Note that any subsequent call to this method or {@link
+     * #setPartitionMapConsumer} will override the previous setting.
+     *
+     * @param partitionMapOutput File-system path to write output at.
+     */
+    @Override
+    public Builder setPartitionMapOutputPath(Path partitionMapOutput) {
+      assert partitionMapOutput != null;
+      return super.setPartitionMapOutputPath(partitionMapOutput);
+    }
+
+    /**
+     * Set a consumer for receiving the partition map content.
+     *
+     * <p>Note that when a proguard-map output is specified for a release build, the compiler will
+     * optimize the line-number information and obtaining a source-level stacktrace will require the
+     * use of a retrace tool exactly as is needed for programs built by R8.
+     *
+     * <p>Note that any subsequent call to this method or {@link #setPartitionMapOutputPath} will
+     * override the previous setting.
+     *
+     * @param partitionMapConsumer Consumer to receive the content once produced.
+     */
+    @Override
+    public Builder setPartitionMapConsumer(PartitionMapConsumer partitionMapConsumer) {
+      assert partitionMapConsumer != null;
+      return super.setPartitionMapConsumer(partitionMapConsumer);
+    }
+
+    /**
      * Indicate if compilation is to intermediate results, i.e., intended for later merging.
      *
      * <p>When compiling to intermediate mode, the compiler will avoid sharing of synthetic items,
@@ -482,6 +521,7 @@
           getDumpInputFlags(),
           getMapIdProvider(),
           proguardMapConsumer,
+          partitionMapConsumer,
           enableMissingLibraryApiModeling,
           getAndroidPlatformBuild(),
           getArtProfilesForRewriting(),
@@ -503,6 +543,7 @@
   private final boolean minimalMainDex;
   private final ImmutableList<ProguardConfigurationRule> mainDexKeepRules;
   private final StringConsumer proguardMapConsumer;
+  private final PartitionMapConsumer partitionMapConsumer;
   private final boolean enableMissingLibraryApiModeling;
   private final DexItemFactory factory;
 
@@ -578,6 +619,7 @@
       DumpInputFlags dumpInputFlags,
       MapIdProvider mapIdProvider,
       StringConsumer proguardMapConsumer,
+      PartitionMapConsumer partitionMapConsumer,
       boolean enableMissingLibraryApiModeling,
       boolean isAndroidPlatformBuild,
       List<ArtProfileForRewriting> artProfilesForRewriting,
@@ -618,6 +660,7 @@
     this.minimalMainDex = minimalMainDex;
     this.mainDexKeepRules = mainDexKeepRules;
     this.proguardMapConsumer = proguardMapConsumer;
+    this.partitionMapConsumer = partitionMapConsumer;
     this.enableMissingLibraryApiModeling = enableMissingLibraryApiModeling;
     this.factory = factory;
   }
@@ -635,6 +678,7 @@
     minimalMainDex = false;
     mainDexKeepRules = null;
     proguardMapConsumer = null;
+    partitionMapConsumer = null;
     enableMissingLibraryApiModeling = false;
     factory = null;
   }
@@ -665,10 +709,15 @@
     internal.setSyntheticInfoConsumer(syntheticInfoConsumer);
     internal.desugarGraphConsumer = desugarGraphConsumer;
     internal.mainDexKeepRules = mainDexKeepRules;
+    MapConsumer mapConsumer =
+        wrapExistingMapConsumerIfNotNull(
+            internal.mapConsumer, partitionMapConsumer, MapConsumerToPartitionMapConsumer::new);
     internal.mapConsumer =
-        proguardMapConsumer == null
-            ? null
-            : ProguardMapStringConsumer.builder().setStringConsumer(proguardMapConsumer).build();
+        wrapExistingMapConsumerIfNotNull(
+            mapConsumer,
+            proguardMapConsumer,
+            nonNullStringConsumer ->
+                ProguardMapStringConsumer.builder().setStringConsumer(proguardMapConsumer).build());
     internal.lineNumberOptimization =
         !internal.debug && proguardMapConsumer != null
             ? LineNumberOptimization.ON
diff --git a/src/main/java/com/android/tools/r8/D8CommandParser.java b/src/main/java/com/android/tools/r8/D8CommandParser.java
index 7485cc8..fa30c4f 100644
--- a/src/main/java/com/android/tools/r8/D8CommandParser.java
+++ b/src/main/java/com/android/tools/r8/D8CommandParser.java
@@ -34,6 +34,7 @@
           "--classpath",
           "--pg-map",
           "--pg-map-output",
+          "--partition-map-output",
           MIN_API_FLAG,
           "--main-dex-rules",
           "--main-dex-list",
@@ -60,6 +61,8 @@
                 "--pg-map", "<file>", "Use <file> as a mapping file for distribution."))
         // TODO(b/183125319): Add help info once supported.
         // "  --pg-map-output <file>  # Enable line optimization and output mapping to <file>.",
+        // "  --partition-map-output <file>  # Enable line optimization and output mapping to
+        //   <file>.",
         .add(
             ParseFlagInfoImpl.flag0(
                 "--intermediate", "Compile an intermediate result intended for later", "merging."))
@@ -265,6 +268,8 @@
         builder.setProguardInputMapFile(Paths.get(nextArg));
       } else if (arg.equals("--pg-map-output")) {
         builder.setProguardMapOutputPath(Paths.get(nextArg));
+      } else if (arg.equals("--partition-map-output")) {
+        builder.setPartitionMapOutputPath(Paths.get(nextArg));
       } else if (arg.equals("--output")) {
         if (outputPath != null) {
           builder.error(
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index 6eb01b6..7847c1d 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -309,7 +309,7 @@
      * @param proguardMapOutput File-system path to write output at.
      */
     @Override
-    public L8Command.Builder setProguardMapOutputPath(Path proguardMapOutput) {
+    public Builder setProguardMapOutputPath(Path proguardMapOutput) {
       return super.setProguardMapOutputPath(proguardMapOutput);
     }
 
@@ -322,7 +322,7 @@
      * @param proguardMapConsumer Consumer to receive the content once produced.
      */
     @Override
-    public L8Command.Builder setProguardMapConsumer(StringConsumer proguardMapConsumer) {
+    public Builder setProguardMapConsumer(StringConsumer proguardMapConsumer) {
       return super.setProguardMapConsumer(proguardMapConsumer);
     }
 
@@ -351,7 +351,7 @@
       if (isShrinking() && getProgramConsumer() instanceof ClassFileConsumer) {
         reporter.error("L8 does not support shrinking when generating class files");
       }
-      if (!isShrinking() && proguardMapConsumer != null) {
+      if (!isShrinking() && (proguardMapConsumer != null || partitionMapConsumer != null)) {
         reporter.error("L8 does not support defining a map consumer when not shrinking");
       }
       super.validate();
@@ -403,6 +403,9 @@
         if (proguardMapConsumer != null) {
           r8Builder.setProguardMapConsumer(proguardMapConsumer);
         }
+        if (partitionMapConsumer != null) {
+          r8Builder.setPartitionMapConsumer(partitionMapConsumer);
+        }
         r8Builder.addProguardConfiguration(
             desugaredLibrarySpecification.getExtraKeepRules(), Origin.unknown());
         // TODO(b/180903899): Remove rule when -dontwarn sun.misc.Unsafe is part of config.
diff --git a/src/main/java/com/android/tools/r8/L8CommandParser.java b/src/main/java/com/android/tools/r8/L8CommandParser.java
index af389fe..72d1d34 100644
--- a/src/main/java/com/android/tools/r8/L8CommandParser.java
+++ b/src/main/java/com/android/tools/r8/L8CommandParser.java
@@ -29,6 +29,7 @@
           THREAD_COUNT_FLAG,
           "--pg-conf",
           "--pg-map-output",
+          "--partition-map-output",
           ART_PROFILE_FLAG);
 
   // Note: this must be a subset of OPTIONS_WITH_ONE_PARAMETER.
@@ -64,6 +65,7 @@
         .add(ParseFlagInfoImpl.getMinApi())
         .add(ParseFlagInfoImpl.getPgConf())
         .add(ParseFlagInfoImpl.getPgMapOutput())
+        .add(ParseFlagInfoImpl.getPartitionMapOutput())
         .add(ParseFlagInfoImpl.getDesugaredLib())
         .addAll(ParseFlagInfoImpl.getAssertionsFlags())
         .add(ParseFlagInfoImpl.getThreadCount())
@@ -175,6 +177,8 @@
         builder.addProguardConfigurationFiles(Paths.get(nextArg));
       } else if (arg.equals("--pg-map-output")) {
         builder.setProguardMapOutputPath(Paths.get(nextArg));
+      } else if (arg.equals("--partition-map-output")) {
+        builder.setPartitionMapOutputPath(Paths.get(nextArg));
       } else if (arg.equals("--desugared-lib")) {
         builder.addDesugaredLibraryConfiguration(StringResource.fromFile(Paths.get(nextArg)));
       } else if (arg.equals("--classfile")) {
diff --git a/src/main/java/com/android/tools/r8/ParseFlagInfoImpl.java b/src/main/java/com/android/tools/r8/ParseFlagInfoImpl.java
index ef42ebd..91da498 100644
--- a/src/main/java/com/android/tools/r8/ParseFlagInfoImpl.java
+++ b/src/main/java/com/android/tools/r8/ParseFlagInfoImpl.java
@@ -104,6 +104,11 @@
         "--pg-map-output", "<file>", "Output the resulting name and line mapping to <file>.");
   }
 
+  public static ParseFlagInfoImpl getPartitionMapOutput() {
+    return ParseFlagInfoImpl.flag1(
+        "--partition-map-output", "<file>", "Output the resulting mapping to <file>.");
+  }
+
   public static List<ParseFlagInfoImpl> getAssertionsFlags() {
     return ImmutableList.of(
         flag0a1(
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 39e7996..7ec72c1 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -301,34 +301,6 @@
     }
 
     /**
-     * Set an output destination to which r8-map content should be written.
-     *
-     * <p>This is a short-hand for setting a {@link MapConsumerToPartitionMapConsumer} using {@link
-     * #setPartitionMapConsumer}. Note that any subsequent call to this method or {@link
-     * #setPartitionMapConsumer} will override the previous setting.
-     *
-     * @param partitionMapOutput File-system path to write output at.
-     */
-    @Override
-    public Builder setPartitionMapOutputPath(Path partitionMapOutput) {
-      assert partitionMapOutput != null;
-      return super.setPartitionMapOutputPath(partitionMapOutput);
-    }
-
-    /**
-     * Set a consumer for receiving the r8-map content.
-     *
-     * <p>Note that any subsequent call to this method or {@link #setPartitionMapOutputPath} will
-     * override the previous setting.
-     *
-     * @param partitionMapConsumer Consumer to receive the content once produced.
-     */
-    @Override
-    public Builder setPartitionMapConsumer(PartitionMapConsumer partitionMapConsumer) {
-      return super.setPartitionMapConsumer(partitionMapConsumer);
-    }
-
-    /**
      * Set a consumer for receiving the keep rules to use when compiling the desugared library for
      * the program being compiled in this compilation.
      *
diff --git a/src/main/java/com/android/tools/r8/R8CommandParser.java b/src/main/java/com/android/tools/r8/R8CommandParser.java
index f3fd1b8..f5f22bf 100644
--- a/src/main/java/com/android/tools/r8/R8CommandParser.java
+++ b/src/main/java/com/android/tools/r8/R8CommandParser.java
@@ -43,6 +43,7 @@
           "--pg-conf",
           "--pg-conf-output",
           "--pg-map-output",
+          "--partition-map-output",
           "--desugared-lib",
           "--desugared-lib-pg-conf-output",
           "--map-id-template",
@@ -71,6 +72,7 @@
         .add(ParseFlagInfoImpl.getPgConf())
         .add(flag1("--pg-conf-output", "<file>", "Output the collective configuration to <file>."))
         .add(ParseFlagInfoImpl.getPgMapOutput())
+        .add(ParseFlagInfoImpl.getPartitionMapOutput())
         .add(ParseFlagInfoImpl.getDesugaredLib())
         .add(
             flag1(
@@ -294,6 +296,8 @@
         builder.setProguardConfigurationConsumer(consumer);
       } else if (arg.equals("--pg-map-output")) {
         builder.setProguardMapOutputPath(Paths.get(nextArg));
+      } else if (arg.equals("--partition-map-output")) {
+        builder.setPartitionMapOutputPath(Paths.get(nextArg));
       } else if (arg.equals("--desugared-lib")) {
         builder.addDesugaredLibraryConfiguration(StringResource.fromFile(Paths.get(nextArg)));
       } else if (arg.equals("--desugared-lib-pg-conf-output")) {
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 b71e8d2..dbed84f 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -419,24 +419,18 @@
 
   private static class PrunePreambleMethodVisitor extends MethodVisitor {
 
-    private final AppView<?> appView;
     private boolean inPreamble = true;
 
-    public PrunePreambleMethodVisitor(MethodVisitor methodVisitor, AppView<?> appView) {
+    public PrunePreambleMethodVisitor(MethodVisitor methodVisitor) {
       super(InternalOptions.ASM_VERSION, methodVisitor);
-      this.appView = appView;
     }
 
     @Override
     public void visitLineNumber(int line, Label start) {
-      if (line == 0) {
-        if (inPreamble) {
-          inPreamble = false;
-          return;
-        }
-        // We must be in R8 if inserting a zero-line entry outside the method preamble.
-        assert appView.enableWholeProgramOptimizations();
+      if (line == 0 && inPreamble) {
+        return;
       }
+      inPreamble = false;
       super.visitLineNumber(line, start);
     }
   }
@@ -466,8 +460,7 @@
             || (appView.enableWholeProgramOptimizations()
                 && classFileVersion.isEqualTo(CfVersion.V1_6)
                 && !options.shouldKeepStackMapTable());
-    PrunePreambleMethodVisitor prunePreambleVisitor =
-        new PrunePreambleMethodVisitor(visitor, appView);
+    PrunePreambleMethodVisitor prunePreambleVisitor = new PrunePreambleMethodVisitor(visitor);
     for (CfInstruction instruction : instructions) {
       if (discardFrames && instruction instanceof CfFrame) {
         continue;
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 42dc600..a76bdf5 100644
--- a/src/main/java/com/android/tools/r8/graph/Code.java
+++ b/src/main/java/com/android/tools/r8/graph/Code.java
@@ -169,7 +169,7 @@
   }
 
   @Override
-  void collectMixedSectionItems(MixedSectionCollection collection) {
+  protected void collectMixedSectionItems(MixedSectionCollection collection) {
     throw new Unreachable();
   }
 
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 25a5a97..968863a 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
@@ -128,7 +128,7 @@
   }
 
   @Override
-  void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+  protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
     mixedItems.add(this);
   }
 
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 aa6aaec..6274296 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotationElement.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotationElement.java
@@ -66,7 +66,7 @@
   }
 
   @Override
-  void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+  protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
     // Should never be visited.
     assert false;
   }
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 1cd2f4b..5dfb273 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java
@@ -129,7 +129,7 @@
   }
 
   @Override
-  void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+  protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
     mixedItems.add(this);
     collectAll(mixedItems, annotations);
   }
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 e3b49d1..f5d8cea 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCallSite.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCallSite.java
@@ -172,7 +172,7 @@
   }
 
   @Override
-  void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+  protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
     getEncodedArray().collectMixedSectionItems(mixedItems);
   }
 
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 342a214..c79cb1b 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -253,7 +253,7 @@
   }
 
   @Override
-  void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+  protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
     throw new Unreachable();
   }
 
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 9532f1e..4cb2a24 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -919,7 +919,7 @@
     }
 
     @Override
-    void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+    protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
       // Should never be visited.
       assert false;
     }
@@ -971,7 +971,7 @@
     }
 
     @Override
-    void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+    protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
       // Should never be visited.
       assert false;
     }
@@ -1034,7 +1034,7 @@
       }
 
       @Override
-      void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+      protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
         // Should never be visited.
         assert false;
       }
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 a7cd5d1..8826ec4 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java
@@ -60,7 +60,7 @@
   }
 
   @Override
-  abstract void collectMixedSectionItems(MixedSectionCollection collection);
+  protected abstract void collectMixedSectionItems(MixedSectionCollection collection);
 
   @Override
   public abstract DexDebugInfo self();
@@ -275,7 +275,7 @@
     }
 
     @Override
-    void collectMixedSectionItems(MixedSectionCollection collection) {
+    protected void collectMixedSectionItems(MixedSectionCollection collection) {
       // Only writable info should be iterated for collection.
       throw new Unreachable();
     }
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 0d4f388..19aad9e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java
@@ -63,7 +63,7 @@
   }
 
   @Override
-  void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+  protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
     // Should never be called.
     assert false;
   }
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 4192720..663a2e5 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedArray.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedArray.java
@@ -22,7 +22,7 @@
   }
 
   @Override
-  void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+  protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
     mixedItems.add(this);
   }
 
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
index 2b7a222..c6f2634 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
@@ -145,7 +145,7 @@
   }
 
   @Override
-  void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+  protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
     annotations().collectMixedSectionItems(mixedItems);
   }
 
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 1c502d5..a45d542 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -786,7 +786,7 @@
   }
 
   @Override
-  void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+  protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
     mixedItems.visit(this);
   }
 
diff --git a/src/main/java/com/android/tools/r8/graph/DexItem.java b/src/main/java/com/android/tools/r8/graph/DexItem.java
index f26e41a..928673f 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItem.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItem.java
@@ -6,7 +6,6 @@
 import com.android.tools.r8.dex.MixedSectionCollection;
 import java.util.Collection;
 import java.util.function.Consumer;
-import java.util.stream.Stream;
 
 public abstract class DexItem {
 
@@ -34,7 +33,7 @@
     }
   }
 
-  abstract void collectMixedSectionItems(MixedSectionCollection collection);
+  protected abstract void collectMixedSectionItems(MixedSectionCollection collection);
 
   protected void flushCachedValues() {
     // Overwritten in subclasses.
@@ -48,7 +47,4 @@
     return toString();
   }
 
-  static <T extends DexItem> Stream<T> filter(Stream<DexItem> stream, Class<T> clazz) {
-    return stream.filter(clazz::isInstance).map(clazz::cast);
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index cfa8347..ae3f0ac 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -1991,8 +1991,9 @@
       return field == nameField || field == ordinalField;
     }
 
-    public boolean isEnumField(DexEncodedField staticField, DexType enumType) {
-      return isEnumField(staticField, enumType, ImmutableSet.of());
+    public boolean isEnumFieldCandidate(DexEncodedField staticField) {
+      assert staticField.isStatic();
+      return staticField.isEnum() && staticField.isFinal();
     }
 
     // In some case, the enum field may be respecialized to an enum subtype. In this case, one
@@ -2001,8 +2002,7 @@
         DexEncodedField staticField, DexType enumType, Set<DexType> subtypes) {
       assert staticField.isStatic();
       return (staticField.getType() == enumType || subtypes.contains(staticField.getType()))
-          && staticField.isEnum()
-          && staticField.isFinal();
+          && isEnumFieldCandidate(staticField);
     }
 
     public boolean isValuesFieldCandidate(DexEncodedField staticField, DexType enumType) {
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 5bac75e..2679186 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMemberAnnotation.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMemberAnnotation.java
@@ -17,7 +17,7 @@
   }
 
   @Override
-  void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+  protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
     annotations.collectMixedSectionItems(mixedItems);
   }
 
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 a448af0..fc4c4a6 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -471,7 +471,7 @@
   }
 
   @Override
-  void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+  protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
     assert getEnclosingMethodAttribute() == null;
     assert getInnerClasses().isEmpty();
     assert !classSignature.hasSignature();
diff --git a/src/main/java/com/android/tools/r8/graph/DexTypeAnnotation.java b/src/main/java/com/android/tools/r8/graph/DexTypeAnnotation.java
index 99dadb8..c343889 100644
--- a/src/main/java/com/android/tools/r8/graph/DexTypeAnnotation.java
+++ b/src/main/java/com/android/tools/r8/graph/DexTypeAnnotation.java
@@ -38,7 +38,7 @@
   }
 
   @Override
-  void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+  protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
     throw new Unreachable("Should not collect type annotation in DEX");
   }
 
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 7be2dce..3716f4e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexTypeList.java
+++ b/src/main/java/com/android/tools/r8/graph/DexTypeList.java
@@ -130,7 +130,7 @@
   }
 
   @Override
-  void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+  protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
     mixedItems.add(this);
   }
 
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 5271c0a..0dc1d16 100644
--- a/src/main/java/com/android/tools/r8/graph/DexValue.java
+++ b/src/main/java/com/android/tools/r8/graph/DexValue.java
@@ -355,7 +355,7 @@
   }
 
   @Override
-  void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+  protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
     // Should never be visited.
     throw new Unreachable();
   }
diff --git a/src/main/java/com/android/tools/r8/graph/IndexedDexItem.java b/src/main/java/com/android/tools/r8/graph/IndexedDexItem.java
index 96bfb47..f668585 100644
--- a/src/main/java/com/android/tools/r8/graph/IndexedDexItem.java
+++ b/src/main/java/com/android/tools/r8/graph/IndexedDexItem.java
@@ -9,7 +9,7 @@
 public abstract class IndexedDexItem extends CachedHashValueDexItem {
 
   @Override
-  void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+  protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
     // Should never be visited.
     assert false;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
index d9158fc..8cb3ed0 100644
--- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -36,7 +36,6 @@
 import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
 import com.android.tools.r8.jar.CfApplicationWriter;
 import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.synthesis.SyntheticMarker;
 import com.android.tools.r8.utils.AsmUtils;
 import com.android.tools.r8.utils.DescriptorUtils;
@@ -116,16 +115,6 @@
     ClassReader reader = new ClassReader(bytes);
 
     int parsingOptions = SKIP_FRAMES | SKIP_CODE;
-
-    // If the source-file and source-debug-extension attributes are not kept we can skip all debug
-    // related attributes when parsing the class structure.
-    if (application.options.getProguardConfiguration() != null) {
-      ProguardKeepAttributes keep =
-          application.options.getProguardConfiguration().getKeepAttributes();
-      if (!keep.sourceFile && !keep.sourceDebugExtension && !keep.methodParameters) {
-        parsingOptions |= SKIP_DEBUG;
-      }
-    }
     if (classKind != ClassKind.PROGRAM) {
       parsingOptions |= SKIP_DEBUG;
     }
diff --git a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
index e54e691..b3b5680 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
@@ -1195,7 +1195,8 @@
             || keep.localVariableTable
             || keep.localVariableTypeTable
             || reachabilitySensitive;
-    boolean lineInfo = keep.lineNumberTable;
+    boolean lineInfo =
+        (keep.lineNumberTable || application.options.canUseNativeDexPcInsteadOfDebugInfo());
     boolean methodParaeters = keep.methodParameters;
 
     if (!localsInfo && !lineInfo && !methodParaeters) {
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 5f7c865..7e21357 100644
--- a/src/main/java/com/android/tools/r8/graph/ParameterAnnotationsList.java
+++ b/src/main/java/com/android/tools/r8/graph/ParameterAnnotationsList.java
@@ -126,7 +126,7 @@
   }
 
   @Override
-  void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+  protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
     // Collect values first so that the annotation sets have sorted themselves before adding this.
     collectAll(mixedItems, values);
     mixedItems.add(this);
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValues.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValues.java
index 0f40f03..8e5b4ca 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValues.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValues.java
@@ -79,7 +79,7 @@
             enumObjectStateBuilder.put(
                 staticField.getReference(), value.asSingleFieldValue().getObjectState());
           }
-        } else if (factory.enumMembers.isEnumField(staticField, staticField.getHolderType())) {
+        } else if (factory.enumMembers.isEnumFieldCandidate(staticField)) {
           if (value.isSingleFieldValue()
               && !value.asSingleFieldValue().getObjectState().isEmpty()) {
             enumObjectStateBuilder.put(
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
index 9acf109..b78f18b 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
@@ -145,11 +145,9 @@
   public SingleValue rewrittenWithLens(
       AppView<AppInfoWithLiveness> appView, GraphLens lens, GraphLens codeLens) {
     AbstractValueFactory factory = appView.abstractValueFactory();
-    if (field.holder == field.type) {
-      EnumDataMap enumDataMap = appView.unboxedEnums();
-      if (enumDataMap.hasUnboxedValueFor(field)) {
-        return factory.createSingleNumberValue(enumDataMap.getUnboxedValue(field));
-      }
+    EnumDataMap enumDataMap = appView.unboxedEnums();
+    if (enumDataMap.hasUnboxedValueFor(field)) {
+      return factory.createSingleNumberValue(enumDataMap.getUnboxedValue(field));
     }
     DexField rewrittenField = lens.lookupField(field, codeLens);
     ObjectState rewrittenObjectState = getObjectState().rewrittenWithLens(appView, lens, codeLens);
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 2dfbc18..a42e312 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
@@ -25,6 +25,7 @@
 import com.android.tools.r8.ir.conversion.DexBuilder;
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
+import com.android.tools.r8.lightir.LirBuilder;
 
 public class ConstClass extends ConstInstruction {
 
@@ -220,6 +221,11 @@
     registry.registerConstClass(clazz, null, ignoreCompatRules);
   }
 
+  @Override
+  public void buildLir(LirBuilder<Value, ?> builder) {
+    builder.addConstClass(getType());
+  }
+
   public static class Builder extends BuilderBase<Builder, ConstClass> {
 
     private DexType type;
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 52d38b3..ba020a4 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
@@ -26,6 +26,7 @@
 import com.android.tools.r8.ir.conversion.DexBuilder;
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
+import com.android.tools.r8.lightir.LirBuilder;
 import java.util.List;
 
 public class InvokeNewArray extends Invoke {
@@ -226,4 +227,9 @@
   public int size() {
     return inValues.size();
   }
+
+  @Override
+  public void buildLir(LirBuilder<Value, ?> builder) {
+    builder.addInvokeNewArray(getArrayType(), arguments());
+  }
 }
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 15f7224..ddf7cba 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
@@ -18,6 +18,7 @@
 import com.android.tools.r8.ir.conversion.DexBuilder;
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
+import com.android.tools.r8.lightir.LirBuilder;
 import java.util.Arrays;
 
 public class NewArrayFilledData extends Instruction {
@@ -66,6 +67,11 @@
   }
 
   @Override
+  public void buildLir(LirBuilder<Value, ?> builder) {
+    builder.addNewArrayFilledData(element_width, size, data, src());
+  }
+
+  @Override
   public boolean identicalNonValueNonPositionParts(Instruction other) {
     if (!other.isNewArrayFilledData()) {
       return false;
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 98c55cc..ed5958c 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
@@ -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.ir.regalloc.RegisterAllocator;
+import com.android.tools.r8.lightir.LirBuilder;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 public class StaticPut extends FieldInstruction implements FieldPut, StaticFieldInstruction {
@@ -235,6 +236,11 @@
   }
 
   @Override
+  public void buildLir(LirBuilder<Value, ?> builder) {
+    builder.addStaticPut(getField(), value());
+  }
+
+  @Override
   public boolean definitelyTriggersClassInitialization(
       DexType clazz,
       ProgramMethod context,
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumDataMap.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumDataMap.java
index 6672c87..06cb686 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumDataMap.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumDataMap.java
@@ -4,18 +4,23 @@
 
 package com.android.tools.r8.ir.optimize.enums;
 
+import static com.android.tools.r8.ir.optimize.enums.EnumUnboxerImpl.ordinalToUnboxedInt;
+
 import com.android.tools.r8.errors.CheckEnumUnboxedDiagnostic;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.ProgramField;
+import com.android.tools.r8.ir.analysis.value.AbstractValueFactory;
+import com.android.tools.r8.ir.analysis.value.SingleNumberValue;
 import com.android.tools.r8.ir.optimize.enums.EnumInstanceFieldData.EnumInstanceFieldKnownData;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceMap.Entry;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
@@ -76,6 +81,15 @@
     return map.containsKey(type);
   }
 
+  public SingleNumberValue getSingleNumberValueFromEnumType(
+      AbstractValueFactory factory, DexType enumType) {
+    assert isUnboxedEnum(enumType);
+    EnumData enumData = get(enumType);
+    return isSuperUnboxedEnum(enumType)
+        ? enumData.superEnumTypeSingleValue(factory, enumType)
+        : enumData.subEnumTypeSingleValue(factory, enumType);
+  }
+
   public boolean isUnboxedEnum(DexProgramClass clazz) {
     return isUnboxedEnum(clazz.getType());
   }
@@ -84,7 +98,7 @@
     return map.containsKey(representativeType(type));
   }
 
-  private EnumData get(DexType type) {
+  public EnumData get(DexType type) {
     EnumData enumData = map.get(representativeType(type));
     assert enumData != null;
     return enumData;
@@ -112,17 +126,19 @@
   }
 
   public boolean hasUnboxedValueFor(DexField enumStaticField) {
-    return isUnboxedEnum(enumStaticField.getHolderType())
-        && get(enumStaticField.getHolderType()).hasUnboxedValueFor(enumStaticField);
+    DexType representative = representativeType(enumStaticField.getHolderType());
+    return isSuperUnboxedEnum(representative)
+        && get(representative).hasUnboxedValueFor(enumStaticField);
   }
 
   public int getUnboxedValue(DexField enumStaticField) {
     assert isUnboxedEnum(enumStaticField.getHolderType());
-    return get(enumStaticField.getHolderType()).getUnboxedValue(enumStaticField);
+    return get(representativeType(enumStaticField.getHolderType()))
+        .getUnboxedValue(enumStaticField);
   }
 
   public int getValuesSize(DexType enumType) {
-    assert isUnboxedEnum(enumType);
+    assert isSuperUnboxedEnum(enumType);
     return get(enumType).getValuesSize();
   }
 
@@ -137,7 +153,7 @@
   }
 
   public boolean matchesValuesField(DexField staticField) {
-    assert isUnboxedEnum(staticField.getHolderType());
+    assert isSuperUnboxedEnum(staticField.getHolderType());
     return get(staticField.getHolderType()).matchesValuesField(staticField);
   }
 
@@ -202,5 +218,28 @@
       assert hasValues();
       return valuesSize;
     }
+
+    public SingleNumberValue superEnumTypeSingleValue(AbstractValueFactory factory, DexType type) {
+      // If there is a single live enum instance, then return the unboxed value for this one.
+      if (hasValues()) {
+        if (valuesSize == 1) {
+          return factory.createSingleNumberValue(ordinalToUnboxedInt(0));
+        }
+      } else if (unboxedValues.size() == 1) {
+        Integer next = unboxedValues.values().iterator().next();
+        return factory.createSingleNumberValue(ordinalToUnboxedInt(next));
+      }
+      return null;
+    }
+
+    public SingleNumberValue subEnumTypeSingleValue(AbstractValueFactory factory, DexType type) {
+      assert valuesTypes.values().stream().filter(t -> t == type).count() <= 1;
+      for (Entry<DexType> entry : valuesTypes.int2ReferenceEntrySet()) {
+        if (entry.getValue() == type) {
+          return factory.createSingleNumberValue(ordinalToUnboxedInt(entry.getIntKey()));
+        }
+      }
+      return null;
+    }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
index 12e1f1e..df5d6b1 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
@@ -181,6 +181,10 @@
         appView.appInfo().resolveField(factory.enumMembers.ordinalField).getResolutionPair();
   }
 
+  public static int unboxedIntToOrdinal(int unboxedInt) {
+    return unboxedInt - 1;
+  }
+
   public static int ordinalToUnboxedInt(int ordinal) {
     return ordinal + 1;
   }
@@ -1280,7 +1284,8 @@
           : Reason.ASSIGNMENT_OUTSIDE_INIT;
     }
     // The put value has to be of the field type.
-    if (field.getReference().type.toBaseType(factory) != enumClass.type) {
+    if (!enumUnboxingCandidatesInfo.isAssignableTo(
+        field.getReference().type.toBaseType(factory), enumClass.type)) {
       return Reason.TYPE_MISMATCH_FIELD_PUT;
     }
     return Reason.ELIGIBLE;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java
index 3aaff49..53f7f63 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.ir.optimize.enums;
 
+import static com.android.tools.r8.ir.optimize.enums.EnumUnboxerImpl.unboxedIntToOrdinal;
+
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexItemFactory;
@@ -16,8 +18,10 @@
 import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
 import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
 import com.android.tools.r8.graph.proto.RewrittenTypeInfo;
+import com.android.tools.r8.ir.analysis.value.AbstractValue;
 import com.android.tools.r8.ir.analysis.value.AbstractValueFactory;
 import com.android.tools.r8.ir.analysis.value.SingleFieldValue;
+import com.android.tools.r8.ir.analysis.value.SingleNumberValue;
 import com.android.tools.r8.ir.analysis.value.SingleValue;
 import com.android.tools.r8.ir.code.InvokeType;
 import com.android.tools.r8.ir.conversion.ExtraUnusedNullParameter;
@@ -41,6 +45,7 @@
   private final AbstractValueFactory abstractValueFactory;
   private final Map<DexMethod, RewrittenPrototypeDescription> prototypeChangesPerMethod;
   private final EnumDataMap unboxedEnums;
+  private final Set<DexMethod> dispatchMethods;
 
   EnumUnboxingLens(
       AppView<?> appView,
@@ -48,12 +53,14 @@
       BidirectionalOneToManyRepresentativeMap<DexMethod, DexMethod> renamedSignatures,
       Map<DexType, DexType> typeMap,
       Map<DexMethod, DexMethod> methodMap,
-      Map<DexMethod, RewrittenPrototypeDescription> prototypeChangesPerMethod) {
+      Map<DexMethod, RewrittenPrototypeDescription> prototypeChangesPerMethod,
+      Set<DexMethod> dispatchMethods) {
     super(appView, fieldMap, methodMap, typeMap, renamedSignatures);
     assert !appView.unboxedEnums().isEmpty();
     this.abstractValueFactory = appView.abstractValueFactory();
     this.prototypeChangesPerMethod = prototypeChangesPerMethod;
     this.unboxedEnums = appView.unboxedEnums();
+    this.dispatchMethods = dispatchMethods;
   }
 
   @Override
@@ -94,6 +101,35 @@
     return true;
   }
 
+  public DexMethod lookupRefinedDispatchMethod(
+      DexMethod method,
+      DexMethod context,
+      InvokeType type,
+      GraphLens codeLens,
+      AbstractValue unboxedEnumValue,
+      DexType enumType) {
+    assert codeLens == getPrevious();
+    DexMethod reference = lookupMethod(method, context, type, codeLens).getReference();
+    if (!dispatchMethods.contains(reference) || !unboxedEnumValue.isSingleNumberValue()) {
+      return null;
+    }
+    // We know the exact type of enum, so there is no need to go for the dispatch method. Instead,
+    // we compute the exact target from the enum instance.
+    int unboxedEnum = unboxedEnumValue.asSingleNumberValue().getIntValue();
+    DexType instanceType =
+        unboxedEnums
+            .get(enumType)
+            .valuesTypes
+            .getOrDefault(unboxedIntToOrdinal(unboxedEnum), enumType);
+    DexMethod specializedMethod = method.withHolder(instanceType, dexItemFactory());
+    DexMethod superEnumMethod = method.withHolder(enumType, dexItemFactory());
+    DexMethod refined =
+        newMethodSignatures.getRepresentativeValueOrDefault(
+            specializedMethod, newMethodSignatures.getRepresentativeValue(superEnumMethod));
+    assert refined != null;
+    return refined;
+  }
+
   @Override
   public MethodLookupResult internalDescribeLookupMethod(
       MethodLookupResult previous, DexMethod context, GraphLens codeLens) {
@@ -187,13 +223,15 @@
     return type;
   }
 
-  public static Builder enumUnboxingLensBuilder(AppView<AppInfoWithLiveness> appView) {
-    return new Builder(appView);
+  public static Builder enumUnboxingLensBuilder(
+      AppView<AppInfoWithLiveness> appView, EnumDataMap enumDataMap) {
+    return new Builder(appView, enumDataMap);
   }
 
   static class Builder {
 
     private final DexItemFactory dexItemFactory;
+    private final AbstractValueFactory abstractValueFactory;
     private final Map<DexType, DexType> typeMap = new IdentityHashMap<>();
     private final MutableBidirectionalOneToOneMap<DexField, DexField> newFieldSignatures =
         new BidirectionalOneToOneHashMap<>();
@@ -204,8 +242,12 @@
     private final Map<DexMethod, RewrittenPrototypeDescription> prototypeChangesPerMethod =
         new IdentityHashMap<>();
 
-    Builder(AppView<AppInfoWithLiveness> appView) {
+    private final EnumDataMap enumDataMap;
+
+    Builder(AppView<AppInfoWithLiveness> appView, EnumDataMap enumDataMap) {
       this.dexItemFactory = appView.dexItemFactory();
+      this.abstractValueFactory = appView.abstractValueFactory();
+      this.enumDataMap = enumDataMap;
     }
 
     public Builder mapUnboxedEnums(Set<DexType> enumsToUnbox) {
@@ -279,14 +321,17 @@
         assert toStatic;
         offsetDiff = 1;
         if (!virtualReceiverAlreadyRemapped) {
-          builder
-              .addArgumentInfo(
-                  0,
-                  RewrittenTypeInfo.builder()
-                      .setOldType(from.getHolderType())
-                      .setNewType(to.getParameter(0))
-                      .build())
-              .setIsConvertedToStaticMethod();
+          RewrittenTypeInfo.Builder typeInfoBuilder =
+              RewrittenTypeInfo.builder()
+                  .setOldType(from.getHolderType())
+                  .setNewType(to.getParameter(0));
+          SingleNumberValue singleValue =
+              enumDataMap.getSingleNumberValueFromEnumType(
+                  abstractValueFactory, from.getHolderType());
+          if (singleValue != null) {
+            typeInfoBuilder.setSingleValue(singleValue);
+          }
+          builder.addArgumentInfo(0, typeInfoBuilder.build()).setIsConvertedToStaticMethod();
         } else {
           assert to.getParameter(0).isIntType();
           assert !fromStatic;
@@ -327,7 +372,7 @@
           originalCheckNotNullMethodSignature, checkNotNullMethod.getReference());
     }
 
-    public EnumUnboxingLens build(AppView<?> appView) {
+    public EnumUnboxingLens build(AppView<?> appView, Set<DexMethod> dispatchMethods) {
       assert !typeMap.isEmpty();
       return new EnumUnboxingLens(
           appView,
@@ -335,7 +380,8 @@
           newMethodSignatures,
           typeMap,
           methodMap,
-          ImmutableMap.copyOf(prototypeChangesPerMethod));
+          ImmutableMap.copyOf(prototypeChangesPerMethod),
+          dispatchMethods);
     }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
index cbbd4b9..789c542 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
@@ -37,6 +37,7 @@
 import com.android.tools.r8.ir.code.NewUnboxedEnumInstance;
 import com.android.tools.r8.ir.code.Phi;
 import com.android.tools.r8.ir.code.StaticGet;
+import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.ir.conversion.MethodProcessor;
 import com.android.tools.r8.ir.optimize.enums.EnumInstanceFieldData.EnumInstanceFieldKnownData;
@@ -46,9 +47,9 @@
 import com.android.tools.r8.utils.InternalOptions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Sets;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.IdentityHashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -87,9 +88,10 @@
   }
 
   private Map<Instruction, DexType> createInitialConvertedEnums(
-      IRCode code, RewrittenPrototypeDescription prototypeChanges) {
+      IRCode code, RewrittenPrototypeDescription prototypeChanges, Set<Phi> affectedPhis) {
     Map<Instruction, DexType> convertedEnums = new IdentityHashMap<>();
-    Iterator<Instruction> iterator = code.entryBlock().iterator();
+    List<Instruction> extraConstants = new ArrayList<>();
+    InstructionListIterator iterator = code.entryBlock().listIterator(code);
     int originalNumberOfArguments =
         code.getNumberOfArguments()
             + prototypeChanges.getArgumentInfoCollection().numberOfRemovedArguments();
@@ -105,11 +107,36 @@
         RewrittenTypeInfo rewrittenTypeInfo = argumentInfo.asRewrittenTypeInfo();
         DexType enumType =
             getEnumClassTypeOrNull(rewrittenTypeInfo.getOldType().toBaseType(factory));
-        if (enumType != null) {
+        if (rewrittenTypeInfo.hasSingleValue()
+            && rewrittenTypeInfo.getSingleValue().isSingleNumberValue()) {
+          assert rewrittenTypeInfo
+              .getSingleValue()
+              .isMaterializableInContext(appView, code.context());
+          Instruction materializingInstruction =
+              rewrittenTypeInfo
+                  .getSingleValue()
+                  .createMaterializingInstruction(
+                      appView,
+                      code,
+                      TypeAndLocalInfoSupplier.create(
+                          rewrittenTypeInfo.getNewType().toTypeElement(appView),
+                          next.getLocalInfo()));
+          materializingInstruction.setPosition(next.getPosition());
+          extraConstants.add(materializingInstruction);
+          affectedPhis.addAll(next.outValue().uniquePhiUsers());
+          next.outValue().replaceUsers(materializingInstruction.outValue());
+          convertedEnums.put(materializingInstruction, enumType);
+        } else if (enumType != null) {
           convertedEnums.put(next, enumType);
         }
       }
     }
+    if (!extraConstants.isEmpty()) {
+      assert extraConstants.size() == 1; // So far this is used only for unboxed enums "this".
+      for (Instruction extraConstant : extraConstants) {
+        iterator.add(extraConstant);
+      }
+    }
     return convertedEnums;
   }
 
@@ -125,8 +152,9 @@
     assert code.isConsistentSSABeforeTypesAreCorrect(appView);
     ProgramMethod context = code.context();
     EnumUnboxerMethodProcessorEventConsumer eventConsumer = methodProcessor.getEventConsumer();
-    Map<Instruction, DexType> convertedEnums = createInitialConvertedEnums(code, prototypeChanges);
     Set<Phi> affectedPhis = Sets.newIdentityHashSet();
+    Map<Instruction, DexType> convertedEnums =
+        createInitialConvertedEnums(code, prototypeChanges, affectedPhis);
     BasicBlockIterator blocks = code.listIterator();
     Set<BasicBlock> seenBlocks = Sets.newIdentityHashSet();
     Set<Instruction> instructionsToRemove = Sets.newIdentityHashSet();
@@ -237,6 +265,23 @@
             } else if (invokedMethod == factory.objectMembers.getClass) {
               rewriteNullCheck(iterator, invoke, context, eventConsumer);
               continue;
+            } else if (invoke.isInvokeVirtual() || invoke.isInvokeInterface()) {
+              DexMethod refinedDispatchMethodReference =
+                  enumUnboxingLens.lookupRefinedDispatchMethod(
+                      invokedMethod,
+                      context.getReference(),
+                      invoke.getType(),
+                      enumUnboxingLens.getPrevious(),
+                      invoke.getArgument(0).getAbstractValue(appView, context),
+                      enumType);
+              if (refinedDispatchMethodReference != null) {
+                DexClassAndMethod refinedDispatchMethod =
+                    appView.definitionFor(refinedDispatchMethodReference);
+                assert refinedDispatchMethod != null;
+                assert refinedDispatchMethod.isProgramMethod();
+                replaceEnumInvoke(iterator, invoke, refinedDispatchMethod.asProgramMethod());
+              }
+              continue;
             }
           } else if (invokedMethod == factory.stringBuilderMethods.appendObject
               || invokedMethod == factory.stringBufferMethods.appendObject) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
index 07a54e2..6ac7697 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
@@ -56,6 +56,7 @@
 import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfo;
 import com.android.tools.r8.ir.synthetic.EnumUnboxingCfCodeProvider.EnumUnboxingMethodDispatchCfCodeProvider;
 import com.android.tools.r8.ir.synthetic.EnumUnboxingCfCodeProvider.EnumUnboxingMethodDispatchCfCodeProvider.CfCodeWithLens;
+import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.ImmutableArrayUtils;
 import com.android.tools.r8.utils.OptionalBool;
@@ -100,6 +101,7 @@
   private final ProgramMethodMap<CfCodeWithLens> dispatchMethods =
       ProgramMethodMap.createConcurrent();
   private final PrunedItems.Builder prunedItemsBuilder;
+  private final ProfileCollectionAdditions profileCollectionAdditions;
 
   EnumUnboxingTreeFixer(
       AppView<AppInfoWithLiveness> appView,
@@ -113,9 +115,11 @@
     this.factory = appView.dexItemFactory();
     this.unboxedEnumHierarchy = unboxedEnums;
     this.lensBuilder =
-        EnumUnboxingLens.enumUnboxingLensBuilder(appView).mapUnboxedEnums(getUnboxedEnums());
+        EnumUnboxingLens.enumUnboxingLensBuilder(appView, enumDataMap)
+            .mapUnboxedEnums(getUnboxedEnums());
     this.utilityClasses = utilityClasses;
     this.prunedItemsBuilder = PrunedItems.concurrentBuilder();
+    this.profileCollectionAdditions = ProfileCollectionAdditions.create(appView);
   }
 
   private Set<DexProgramClass> computeUnboxedEnumClasses() {
@@ -143,7 +147,9 @@
         .fixupClassesConcurrentlyByConnectedProgramComponents(Timing.empty(), executorService);
 
     // Install the new graph lens before processing any checkNotZero() methods.
-    EnumUnboxingLens lens = lensBuilder.build(appView);
+    Set<DexMethod> dispatchMethodReferences = Sets.newIdentityHashSet();
+    dispatchMethods.forEach((method, code) -> dispatchMethodReferences.add(method.getReference()));
+    EnumUnboxingLens lens = lensBuilder.build(appView, dispatchMethodReferences);
     appView.rewriteWithLens(lens);
 
     // Rewrite outliner with lens.
@@ -160,6 +166,10 @@
           code.setCodeLens(lens);
         });
 
+    profileCollectionAdditions
+        .setArtProfileCollection(appView.getArtProfileCollection())
+        .commit(appView);
+
     return new Result(
         checkNotNullToCheckNotZeroMapping, dispatchMethodSet, lens, prunedItemsBuilder.build());
   }
@@ -666,11 +676,14 @@
       assert subEnumLocalUtilityMethod != null;
       overrideToUtilityMethods.put(subMethod.getReference(), subEnumLocalUtilityMethod);
     }
+    if (superMethod.isProgramMethod()) {
+      sortedSubimplementations.add(superMethod.asProgramMethod());
+    }
     DexMethod dispatch =
         installDispatchMethod(
                 localUtilityClass,
                 localUtilityMethods,
-                sortedSubimplementations.iterator().next(),
+                sortedSubimplementations,
                 superUtilityMethod,
                 overrideToUtilityMethods)
             .getReference();
@@ -713,10 +726,11 @@
   private DexEncodedMethod installDispatchMethod(
       LocalEnumUnboxingUtilityClass localUtilityClass,
       Map<DexMethod, DexEncodedMethod> localUtilityMethods,
-      ProgramMethod representative,
+      List<ProgramMethod> contexts,
       DexMethod superUtilityMethod,
       Map<DexMethod, DexMethod> map) {
     assert !map.isEmpty();
+    ProgramMethod representative = contexts.iterator().next();
     DexMethod newLocalUtilityMethodReference =
         factory.createFreshMethodNameWithoutHolder(
             "_dispatch_" + representative.getName().toString(),
@@ -752,8 +766,12 @@
             .setApiLevelForDefinition(representative.getDefinition().getApiLevelForDefinition())
             .setApiLevelForCode(representative.getDefinition().getApiLevelForCode())
             .build();
-    dispatchMethods.put(
-        newLocalUtilityMethod.asProgramMethod(localUtilityClass.getDefinition()), codeWithLens);
+    ProgramMethod dispatchMethod =
+        newLocalUtilityMethod.asProgramMethod(localUtilityClass.getDefinition());
+    dispatchMethods.put(dispatchMethod, codeWithLens);
+    for (ProgramMethod context : contexts) {
+      profileCollectionAdditions.addMethodIfContextIsInProfile(dispatchMethod, context);
+    }
     assert !localUtilityMethods.containsKey(newLocalUtilityMethodReference);
     localUtilityMethods.put(newLocalUtilityMethodReference, newLocalUtilityMethod);
     return newLocalUtilityMethod;
diff --git a/src/main/java/com/android/tools/r8/lightir/Lir2IRConverter.java b/src/main/java/com/android/tools/r8/lightir/Lir2IRConverter.java
index 6d6d497..6dcfe40 100644
--- a/src/main/java/com/android/tools/r8/lightir/Lir2IRConverter.java
+++ b/src/main/java/com/android/tools/r8/lightir/Lir2IRConverter.java
@@ -24,6 +24,7 @@
 import com.android.tools.r8.ir.code.CheckCast;
 import com.android.tools.r8.ir.code.Cmp;
 import com.android.tools.r8.ir.code.Cmp.Bias;
+import com.android.tools.r8.ir.code.ConstClass;
 import com.android.tools.r8.ir.code.ConstNumber;
 import com.android.tools.r8.ir.code.ConstString;
 import com.android.tools.r8.ir.code.DebugLocalWrite;
@@ -38,6 +39,7 @@
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InvokeDirect;
 import com.android.tools.r8.ir.code.InvokeInterface;
+import com.android.tools.r8.ir.code.InvokeNewArray;
 import com.android.tools.r8.ir.code.InvokeStatic;
 import com.android.tools.r8.ir.code.InvokeSuper;
 import com.android.tools.r8.ir.code.InvokeVirtual;
@@ -47,6 +49,7 @@
 import com.android.tools.r8.ir.code.MoveException;
 import com.android.tools.r8.ir.code.Mul;
 import com.android.tools.r8.ir.code.NewArrayEmpty;
+import com.android.tools.r8.ir.code.NewArrayFilledData;
 import com.android.tools.r8.ir.code.NewInstance;
 import com.android.tools.r8.ir.code.NumberConversion;
 import com.android.tools.r8.ir.code.NumberGenerator;
@@ -57,6 +60,7 @@
 import com.android.tools.r8.ir.code.Rem;
 import com.android.tools.r8.ir.code.Return;
 import com.android.tools.r8.ir.code.StaticGet;
+import com.android.tools.r8.ir.code.StaticPut;
 import com.android.tools.r8.ir.code.Sub;
 import com.android.tools.r8.ir.code.Throw;
 import com.android.tools.r8.ir.code.Value;
@@ -421,6 +425,14 @@
     }
 
     @Override
+    public void onConstClass(DexType type) {
+      Value dest =
+          getOutValueForNextInstruction(
+              type.toTypeElement(appView, Nullability.definitelyNotNull()));
+      addInstruction(new ConstClass(dest, type));
+    }
+
+    @Override
     public void onNumberConversion(NumericType from, NumericType to, EV value) {
       Value dest =
           getOutValueForNextInstruction(
@@ -523,6 +535,11 @@
     }
 
     @Override
+    public void onStaticPut(DexField field, EV value) {
+      addInstruction(new StaticPut(getValue(value), field));
+    }
+
+    @Override
     public void onInstanceGet(DexField field, EV object) {
       Value dest = getOutValueForNextInstruction(field.getTypeElement(appView));
       addInstruction(new InstanceGet(dest, getValue(object), field));
@@ -602,6 +619,19 @@
     }
 
     @Override
+    public void onInvokeNewArray(DexType type, List<EV> arguments) {
+      Value dest =
+          getOutValueForNextInstruction(
+              type.toTypeElement(appView, Nullability.definitelyNotNull()));
+      addInstruction(new InvokeNewArray(type, dest, getValues(arguments)));
+    }
+
+    @Override
+    public void onNewArrayFilledData(int elementWidth, long size, short[] data, EV src) {
+      addInstruction(new NewArrayFilledData(getValue(src), elementWidth, size, data));
+    }
+
+    @Override
     public void onCmpInstruction(int opcode, EV leftIndex, EV rightIndex) {
       NumericType type;
       Bias bias;
diff --git a/src/main/java/com/android/tools/r8/lightir/LirBuilder.java b/src/main/java/com/android/tools/r8/lightir/LirBuilder.java
index 8f41773..1239c11 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirBuilder.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirBuilder.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.cf.code.CfArithmeticBinop.Opcode;
 import com.android.tools.r8.cf.code.CfLogicalBinop;
 import com.android.tools.r8.cf.code.CfNumberConversion;
+import com.android.tools.r8.dex.MixedSectionCollection;
 import com.android.tools.r8.errors.Unimplemented;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DebugLocalInfo;
@@ -78,9 +79,32 @@
 
   // TODO(b/225838009): Reconsider this fixed space as the operand count for phis is much larger.
   // Pre-allocated space for caching value indexes when writing instructions.
-  private static final int MAX_VALUE_COUNT = 10;
+  private static final int MAX_VALUE_COUNT = 256;
   private int[] valueIndexBuffer = new int[MAX_VALUE_COUNT];
 
+  /**
+   * Internal "DexItem" for the fill-array payloads such that they can be put in the pool.
+   *
+   * <p>The instruction encoding assumes the instruction operand payload size is u1, so the data
+   * payload is stored in the constant pool instead.
+   */
+  public static class FillArrayPayload extends DexItem {
+    public final int element_width;
+    public final long size;
+    public final short[] data;
+
+    public FillArrayPayload(int element_width, long size, short[] data) {
+      this.element_width = element_width;
+      this.size = size;
+      this.data = data;
+    }
+
+    @Override
+    protected void collectMixedSectionItems(MixedSectionCollection collection) {
+      throw new Unreachable();
+    }
+  }
+
   public LirBuilder(DexMethod method, LirEncodingStrategy<V, EV> strategy, DexItemFactory factory) {
     this.factory = factory;
     constants = new Reference2IntOpenHashMap<>();
@@ -331,6 +355,10 @@
     return addOneItemInstruction(LirOpcodes.LDC, string);
   }
 
+  public LirBuilder<V, EV> addConstClass(DexType type) {
+    return addOneItemInstruction(LirOpcodes.LDC, type);
+  }
+
   public LirBuilder<V, EV> addDiv(NumericType type, V leftValue, V rightValue) {
     int opcode;
     switch (type) {
@@ -377,6 +405,11 @@
     return addOneItemInstruction(LirOpcodes.GETSTATIC, field);
   }
 
+  public LirBuilder<V, EV> addStaticPut(DexField field, V value) {
+    return addInstructionTemplate(
+        LirOpcodes.PUTSTATIC, Collections.singletonList(field), ImmutableList.of(value));
+  }
+
   public LirBuilder<V, EV> addInstanceGet(DexField field, V object) {
     return addInstructionTemplate(
         LirOpcodes.GETFIELD, Collections.singletonList(field), Collections.singletonList(object));
@@ -605,6 +638,19 @@
         LirOpcodes.NEWARRAY, Collections.singletonList(type), Collections.singletonList(size));
   }
 
+  public LirBuilder<V, EV> addInvokeNewArray(DexType type, List<V> arguments) {
+    return addInstructionTemplate(
+        LirOpcodes.INVOKENEWARRAY, Collections.singletonList(type), arguments);
+  }
+
+  public LirBuilder<V, EV> addNewArrayFilledData(int elementWidth, long size, short[] data, V src) {
+    FillArrayPayload payloadConstant = new FillArrayPayload(elementWidth, size, data);
+    return addInstructionTemplate(
+        LirOpcodes.NEWARRAYFILLEDDATA,
+        Collections.singletonList(payloadConstant),
+        Collections.singletonList(src));
+  }
+
   public LirBuilder<V, EV> addNumberConversion(NumericType from, NumericType to, V value) {
     int opcode = new CfNumberConversion(from, to).getAsmOpcode();
     assert LirOpcodes.I2L <= opcode;
diff --git a/src/main/java/com/android/tools/r8/lightir/LirOpcodes.java b/src/main/java/com/android/tools/r8/lightir/LirOpcodes.java
index 302e85d..c4f2076 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirOpcodes.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirOpcodes.java
@@ -194,6 +194,8 @@
   int FALLTHROUGH = 211;
   int MOVEEXCEPTION = 212;
   int DEBUGLOCALWRITE = 213;
+  int INVOKENEWARRAY = 214;
+  int NEWARRAYFILLEDDATA = 215;
 
   static String toString(int opcode) {
     switch (opcode) {
@@ -506,6 +508,10 @@
         return "MOVEEXCEPTION";
       case DEBUGLOCALWRITE:
         return "DEBUGLOCALWRITE";
+      case INVOKENEWARRAY:
+        return "INVOKENEWARRAY";
+      case NEWARRAYFILLEDDATA:
+        return "NEWARRAYFILLEDDATA";
 
       default:
         throw new Unreachable("Unexpected LIR opcode: " + opcode);
diff --git a/src/main/java/com/android/tools/r8/lightir/LirParsedInstructionCallback.java b/src/main/java/com/android/tools/r8/lightir/LirParsedInstructionCallback.java
index 1fca6a6..8d81728 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirParsedInstructionCallback.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirParsedInstructionCallback.java
@@ -14,6 +14,7 @@
 import com.android.tools.r8.ir.code.IfType;
 import com.android.tools.r8.ir.code.MemberType;
 import com.android.tools.r8.ir.code.NumericType;
+import com.android.tools.r8.lightir.LirBuilder.FillArrayPayload;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -85,6 +86,10 @@
     onInstruction();
   }
 
+  public void onConstClass(DexType type) {
+    onInstruction();
+  }
+
   private void onArrayGetInternal(MemberType type, LirInstructionView view) {
     if (type.isObject()) {
       DexType destType = (DexType) getConstantItem(view.getNextConstantOperand());
@@ -295,6 +300,14 @@
     onInstruction();
   }
 
+  public void onInvokeNewArray(DexType type, List<EV> arguments) {
+    onInstruction();
+  }
+
+  public void onNewArrayFilledData(int elementWidth, long size, short[] data, EV src) {
+    onInstruction();
+  }
+
   public void onInvokeMethodInstruction(DexMethod method, List<EV> arguments) {
     onInstruction();
   }
@@ -331,6 +344,10 @@
     onFieldInstruction(field);
   }
 
+  public void onStaticPut(DexField field, EV value) {
+    onFieldInstruction(field);
+  }
+
   public abstract void onInstanceGet(DexField field, EV object);
 
   public abstract void onInstancePut(DexField field, EV object, EV value);
@@ -392,6 +409,10 @@
             onConstString((DexString) item);
             return;
           }
+          if (item instanceof DexType) {
+            onConstClass((DexType) item);
+            return;
+          }
           throw new Unimplemented();
         }
       case LirOpcodes.ICONST_M1:
@@ -859,6 +880,13 @@
           onStaticGet(field);
           return;
         }
+      case LirOpcodes.PUTSTATIC:
+        {
+          DexField field = (DexField) getConstantItem(view.getNextConstantOperand());
+          EV value = getNextValueOperand(view);
+          onStaticPut(field, value);
+          return;
+        }
       case LirOpcodes.GETFIELD:
         {
           DexField field = (DexField) getConstantItem(view.getNextConstantOperand());
@@ -954,6 +982,21 @@
           onDebugLocalWrite(srcIndex);
           return;
         }
+      case LirOpcodes.INVOKENEWARRAY:
+        {
+          DexType type = getNextDexTypeOperand(view);
+          List<EV> arguments = getInvokeInstructionArguments(view);
+          onInvokeNewArray(type, arguments);
+          return;
+        }
+      case LirOpcodes.NEWARRAYFILLEDDATA:
+        {
+          FillArrayPayload payload =
+              (FillArrayPayload) getConstantItem(view.getNextConstantOperand());
+          EV src = getNextValueOperand(view);
+          onNewArrayFilledData(payload.element_width, payload.size, payload.data, src);
+          return;
+        }
       case LirOpcodes.LCMP:
       case LirOpcodes.FCMPL:
       case LirOpcodes.FCMPG:
diff --git a/src/main/java/com/android/tools/r8/lightir/LirPrinter.java b/src/main/java/com/android/tools/r8/lightir/LirPrinter.java
index 132fc61..58ac9b2 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirPrinter.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirPrinter.java
@@ -150,6 +150,11 @@
   }
 
   @Override
+  public void onConstClass(DexType type) {
+    appendOutValue().append("class(").append(type).append(")");
+  }
+
+  @Override
   public void onAdd(NumericType type, EV leftValueIndex, EV rightValueIndex) {
     appendOutValue();
     appendValueArguments(leftValueIndex, rightValueIndex);
@@ -212,6 +217,19 @@
   }
 
   @Override
+  public void onInvokeNewArray(DexType type, List<EV> arguments) {
+    appendOutValue();
+    appendValueArguments(arguments);
+    builder.append(type);
+  }
+
+  @Override
+  public void onNewArrayFilledData(int elementWidth, long size, short[] data, EV src) {
+    appendValueArguments(src);
+    builder.append("w:").append(elementWidth).append(",s:").append(size);
+  }
+
+  @Override
   public void onNewInstance(DexType clazz) {
     appendOutValue();
     builder.append(clazz);
@@ -227,14 +245,15 @@
   }
 
   @Override
-  public void onFieldInstruction(DexField field) {
-    builder.append(field);
+  public void onStaticGet(DexField field) {
+    appendOutValue();
+    builder.append(field).append(' ');
   }
 
   @Override
-  public void onStaticGet(DexField field) {
-    appendOutValue();
-    super.onStaticGet(field);
+  public void onStaticPut(DexField field, EV value) {
+    builder.append(field).append(' ');
+    appendValueArguments(value);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java b/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java
index d5fd889..cfd7b32 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java
@@ -83,6 +83,10 @@
       }
     }
 
+    public boolean hasMapping(String obfuscatedName) {
+      return mapping.containsKey(obfuscatedName);
+    }
+
     @Override
     public ClassNameMapper build() {
       return new ClassNameMapper(
diff --git a/src/main/java/com/android/tools/r8/naming/SeedMapper.java b/src/main/java/com/android/tools/r8/naming/SeedMapper.java
index dd2d150..536fd49 100644
--- a/src/main/java/com/android/tools/r8/naming/SeedMapper.java
+++ b/src/main/java/com/android/tools/r8/naming/SeedMapper.java
@@ -6,6 +6,7 @@
 import static com.android.tools.r8.utils.DescriptorUtils.descriptorToInternalName;
 import static com.android.tools.r8.utils.DescriptorUtils.descriptorToJavaType;
 import static com.android.tools.r8.utils.DescriptorUtils.javaTypeToDescriptor;
+import static com.android.tools.r8.utils.positions.MappedPositionToClassNameMapperBuilder.getPrunedInlinedClassObfuscatedPrefix;
 
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.naming.MemberNaming.Signature;
@@ -56,8 +57,11 @@
       ClassNamingForMapApplier.Builder classNamingBuilder =
           ClassNamingForMapApplier.builder(
               renamedDescriptorName, originalDescriptor, position, reporter);
-      if (map.put(originalDescriptor, classNamingBuilder) != null) {
-        reporter.error(ProguardMapError.duplicateSourceClass(originalDescriptor, position));
+      // Disallow renaming to a synthetic chosen name for pruned classes.
+      if (!renamedName.startsWith(getPrunedInlinedClassObfuscatedPrefix())) {
+        if (map.put(originalDescriptor, classNamingBuilder) != null) {
+          reporter.error(ProguardMapError.duplicateSourceClass(originalDescriptor, position));
+        }
       }
       return classNamingBuilder;
     }
diff --git a/src/main/java/com/android/tools/r8/position/TextPosition.java b/src/main/java/com/android/tools/r8/position/TextPosition.java
index dcbc695..ebfd33a 100644
--- a/src/main/java/com/android/tools/r8/position/TextPosition.java
+++ b/src/main/java/com/android/tools/r8/position/TextPosition.java
@@ -24,9 +24,7 @@
   private final int column;
 
   public TextPosition(long offset, int line, int column) {
-    assert (offset >= 0)
-        && (line >= 1)
-        && (column >= 1 || column == UNKNOWN_COLUMN);
+    assert (offset >= 0) && (line >= 0) && (column >= 1 || column == UNKNOWN_COLUMN);
     this.offset = offset;
     this.line = line;
     this.column = column;
diff --git a/src/main/java/com/android/tools/r8/profile/art/ArtProfileCompletenessChecker.java b/src/main/java/com/android/tools/r8/profile/art/ArtProfileCompletenessChecker.java
index 06464c7..d7fde7d 100644
--- a/src/main/java/com/android/tools/r8/profile/art/ArtProfileCompletenessChecker.java
+++ b/src/main/java/com/android/tools/r8/profile/art/ArtProfileCompletenessChecker.java
@@ -85,9 +85,7 @@
       ProgramDefinition definition,
       Set<CompletenessExceptions> completenessExceptions,
       List<DexReference> missing) {
-    // TODO(b/274030968): Fix profile for enum unboxing with subtypes.
-    if (appView.options().testing.enableEnumWithSubtypesUnboxing
-        || completenessExceptions.contains(ALLOW_MISSING_ENUM_UNBOXING_UTILITY_METHODS)) {
+    if (completenessExceptions.contains(ALLOW_MISSING_ENUM_UNBOXING_UTILITY_METHODS)) {
       DexType contextType = definition.getContextType();
       SyntheticItems syntheticItems = appView.getSyntheticItems();
       if (syntheticItems.isSynthetic(contextType)) {
diff --git a/src/main/java/com/android/tools/r8/retrace/Retrace.java b/src/main/java/com/android/tools/r8/retrace/Retrace.java
index 5cca6e8..0150f83 100644
--- a/src/main/java/com/android/tools/r8/retrace/Retrace.java
+++ b/src/main/java/com/android/tools/r8/retrace/Retrace.java
@@ -9,6 +9,9 @@
 import com.android.tools.r8.Diagnostic;
 import com.android.tools.r8.DiagnosticsHandler;
 import com.android.tools.r8.Keep;
+import com.android.tools.r8.ParseFlagInfo;
+import com.android.tools.r8.ParseFlagInfoImpl;
+import com.android.tools.r8.ParseFlagPrinter;
 import com.android.tools.r8.Version;
 import com.android.tools.r8.retrace.internal.RetraceAbortException;
 import com.android.tools.r8.retrace.internal.RetraceBase;
@@ -21,6 +24,7 @@
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.Timing;
 import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableList;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.PrintStream;
@@ -42,11 +46,29 @@
 @Keep
 public class Retrace<T, ST extends StackTraceElementProxy<T, ST>> extends RetraceBase<T, ST> {
 
-  public static final String USAGE_MESSAGE =
+  private static final String USAGE_MESSAGE =
       StringUtils.lines(
-          "Usage: retrace <proguard-map> [stack-trace-file] "
-              + "[--regex <regexp>, --verbose, --info, --quiet, --verify-mapping-file-hash]",
-          "  where <proguard-map> is an r8 generated mapping file.");
+          "Usage: retrace [options] <proguard-map> [stack-trace-file] "
+              + "where <proguard-map> is a generated mapping file and options are:");
+
+  public static List<ParseFlagInfo> getFlags() {
+    return ImmutableList.<ParseFlagInfo>builder()
+        .add(
+            ParseFlagInfoImpl.flag1(
+                "--regex", "<regexp>", "Regular expression for parsing stack-trace-file as lines"))
+        .add(ParseFlagInfoImpl.flag0("--verbose", "Get verbose retraced output"))
+        .add(ParseFlagInfoImpl.flag0("--info", "Write information messages to stdout"))
+        .add(ParseFlagInfoImpl.flag0("--quiet", "Silence ordinary messages printed to stdout"))
+        .add(ParseFlagInfoImpl.flag0("--verify-mapping-file-hash", "Verify the mapping file hash"))
+        .build();
+  }
+
+  static String getUsageMessage() {
+    StringBuilder builder = new StringBuilder();
+    StringUtils.appendLines(builder, USAGE_MESSAGE);
+    new ParseFlagPrinter().addFlags(getFlags()).appendLinesToBuilder(builder);
+    return builder.toString();
+  }
 
   private static RetraceCommand.Builder parseArguments(
       String[] args, DiagnosticsHandler diagnosticsHandler) {
@@ -102,7 +124,7 @@
         diagnosticsHandler.error(
             new StringDiagnostic(
                 String.format("Too many arguments specified for builder at '%s'", context.head())));
-        diagnosticsHandler.error(new StringDiagnostic(USAGE_MESSAGE));
+        diagnosticsHandler.error(new StringDiagnostic(getUsageMessage()));
         throw new RetraceAbortException();
       }
     }
@@ -323,7 +345,7 @@
       }
       assert Arrays.asList(args).contains("--help");
       System.out.println("Retrace " + Version.getVersionString());
-      System.out.print(USAGE_MESSAGE);
+      System.out.print(getUsageMessage());
       return;
     }
     builder.setRetracedStackTraceConsumer(
diff --git a/src/main/java/com/android/tools/r8/utils/positions/MappedPositionToClassNameMapperBuilder.java b/src/main/java/com/android/tools/r8/utils/positions/MappedPositionToClassNameMapperBuilder.java
index b4ec7c9..5578b1f 100644
--- a/src/main/java/com/android/tools/r8/utils/positions/MappedPositionToClassNameMapperBuilder.java
+++ b/src/main/java/com/android/tools/r8/utils/positions/MappedPositionToClassNameMapperBuilder.java
@@ -44,6 +44,7 @@
 import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.synthesis.SyntheticItems;
 import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.IntBox;
 import com.android.tools.r8.utils.InternalOptions.LineNumberOptimization;
 import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.OneShotCollectionConsumer;
@@ -65,6 +66,7 @@
 public class MappedPositionToClassNameMapperBuilder {
 
   private static final int MAX_LINE_NUMBER = 65535;
+  private static final String PRUNED_INLINED_CLASS_OBFUSCATED_PREFIX = "R8$$REMOVED$$CLASS$$";
 
   private final OriginalSourceFiles originalSourceFiles;
   private final AppView<?> appView;
@@ -87,6 +89,10 @@
         appView.options().getMapFileVersion().toMapVersionMappingInformation());
   }
 
+  public static String getPrunedInlinedClassObfuscatedPrefix() {
+    return PRUNED_INLINED_CLASS_OBFUSCATED_PREFIX;
+  }
+
   public static int getMaxLineNumber() {
     return MAX_LINE_NUMBER;
   }
@@ -106,16 +112,24 @@
   private void addSourceFileLinesForPrunedClasses() {
     // Add all pruned inline classes to the mapping to recover source files.
     List<Entry<DexType, String>> prunedEntries = new ArrayList<>(prunedInlinedClasses.entrySet());
+    IntBox counter = new IntBox();
     prunedEntries.sort(Entry.comparingByKey());
     prunedEntries.forEach(
         entry -> {
           DexType holder = entry.getKey();
-          assert appView.appInfo().definitionForWithoutExistenceAssert(holder) == null;
+          assert appView.appInfo().definitionForWithoutExistenceAssert(holder) == null
+              || !appView.appInfo().definitionForWithoutExistenceAssert(holder).isProgramClass();
           String typeName = holder.toSourceString();
           String sourceFile = entry.getValue();
+          // We have to pick a right-hand side destination that does not overlap with an existing
+          // mapping.
+          String renamedName;
+          do {
+            renamedName = PRUNED_INLINED_CLASS_OBFUSCATED_PREFIX + counter.getAndIncrement();
+          } while (classNameMapperBuilder.hasMapping(renamedName));
           classNameMapperBuilder
               .classNamingBuilder(
-                  typeName, typeName, com.android.tools.r8.position.Position.UNKNOWN)
+                  renamedName, typeName, com.android.tools.r8.position.Position.UNKNOWN)
               .addMappingInformation(FileNameInformation.build(sourceFile), Unreachable::raise);
         });
   }
diff --git a/src/test/java/com/android/tools/r8/R8RunExamplesTest.java b/src/test/java/com/android/tools/r8/R8RunExamplesTest.java
index c2a1ba2..2a5bb6c 100644
--- a/src/test/java/com/android/tools/r8/R8RunExamplesTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunExamplesTest.java
@@ -26,11 +26,6 @@
   public static Collection<String[]> data() {
     String[] tests = {
         "arithmetic.Arithmetic",
-        "constants.Constants",
-        "controlflow.ControlFlow",
-        "conversions.Conversions",
-        "floating_point_annotations.FloatingPointValuedAnnotationTest",
-        "filledarray.FilledArray",
         "hello.Hello",
         "ifstatements.IfStatements",
         "inlining.Inlining",
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTest.java
index 3d2be09..5264b18 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTest.java
@@ -9,7 +9,6 @@
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
@@ -117,6 +116,14 @@
       "classmerging.SuperClass"
   );
 
+  private static void assertAbsentOrIdentity(ClassNameMapper mapper, String className) {
+    // The mapping should be absent or identity.
+    ClassNamingForNameMapper classNaming = mapper.getClassNaming(className);
+    if (classNaming != null) {
+      assertEquals(classNaming.originalName, classNaming.renamedName);
+    }
+  }
+
   @Test
   public void testClassesHaveNotBeenMerged() throws Throwable {
     runR8(DONT_OPTIMIZE, null);
@@ -526,7 +533,7 @@
 
     ClassNameMapper mappingWithClassMerging =
         ClassNameMapper.mapperFromString(compileResultWithClassMerging.getProguardMap());
-    assertNull(mappingWithClassMerging.getClassNaming("classmerging.ProguardFieldMapTest$A"));
+    assertAbsentOrIdentity(mappingWithClassMerging, "classmerging.ProguardFieldMapTest$A");
 
     ClassNamingForNameMapper mappingsForClassBWithClassMerging =
         mappingWithClassMerging.getClassNaming("classmerging.ProguardFieldMapTest$B");
@@ -607,7 +614,7 @@
 
     ClassNameMapper mappingWithClassMerging =
         ClassNameMapper.mapperFromString(compileResultWithClassMerging.getProguardMap());
-    assertNull(mappingWithClassMerging.getClassNaming("classmerging.ProguardMethodMapTest$A"));
+    assertAbsentOrIdentity(mappingWithClassMerging, "classmerging.ProguardMethodMapTest$A");
 
     ClassNamingForNameMapper mappingsForClassBWithClassMerging =
         mappingWithClassMerging.getClassNaming("classmerging.ProguardMethodMapTest$B");
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 71c9dc4..c59fda4 100644
--- a/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestCollection.java
+++ b/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestCollection.java
@@ -23,6 +23,7 @@
 import com.android.tools.r8.compilerapi.mockdata.MockClass;
 import com.android.tools.r8.compilerapi.mockdata.MockClassWithAssertion;
 import com.android.tools.r8.compilerapi.mockdata.PostStartupMockClass;
+import com.android.tools.r8.compilerapi.partitionmap.PartitionMapCommandTest;
 import com.android.tools.r8.compilerapi.sourcefile.CustomSourceFileTest;
 import com.android.tools.r8.compilerapi.startupprofile.StartupProfileApiTest;
 import com.android.tools.r8.compilerapi.syntheticscontexts.SyntheticContextsConsumerTest;
@@ -60,7 +61,8 @@
           ClassConflictResolverTest.ApiTest.class,
           ProguardKeepRuleDiagnosticsApiTest.ApiTest.class,
           SyntheticContextsConsumerTest.ApiTest.class,
-          ExtractMarkerApiTest.ApiTest.class);
+          ExtractMarkerApiTest.ApiTest.class,
+          PartitionMapCommandTest.ApiTest.class);
 
   private static final List<Class<? extends CompilerApiTest>> CLASSES_PENDING_BINARY_COMPATIBILITY =
       ImmutableList.of(CancelCompilationCheckerTest.ApiTest.class);
diff --git a/src/test/java/com/android/tools/r8/compilerapi/partitionmap/PartitionMapCommandTest.java b/src/test/java/com/android/tools/r8/compilerapi/partitionmap/PartitionMapCommandTest.java
new file mode 100644
index 0000000..47cb0c9
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/compilerapi/partitionmap/PartitionMapCommandTest.java
@@ -0,0 +1,158 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use 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.partitionmap;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.D8;
+import com.android.tools.r8.D8Command;
+import com.android.tools.r8.DexIndexedConsumer;
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.PartitionMapConsumer;
+import com.android.tools.r8.ProgramConsumer;
+import com.android.tools.r8.R8;
+import com.android.tools.r8.R8Command;
+import com.android.tools.r8.StringConsumer;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.compilerapi.CompilerApiTest;
+import com.android.tools.r8.compilerapi.CompilerApiTestRunner;
+import com.android.tools.r8.compilerapi.partitionmap.PartitionMapCommandTest.ApiTest.EnsurePartitionMapOutputConsumer;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.retrace.MappingPartition;
+import com.android.tools.r8.retrace.MappingPartitionMetadata;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Test;
+
+public class PartitionMapCommandTest extends CompilerApiTestRunner {
+
+  private static final int FIRST_API_LEVEL_WITH_NATIVE_MULTIDEX = 21;
+
+  public PartitionMapCommandTest(TestParameters parameters) {
+    super(parameters);
+  }
+
+  @Override
+  public Class<? extends CompilerApiTest> binaryTestClass() {
+    return ApiTest.class;
+  }
+
+  private interface Runner {
+    void run(
+        ProgramConsumer programConsumer,
+        StringConsumer pgMapConsumer,
+        PartitionMapConsumer partitionMapConsumer)
+        throws Exception;
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    runTest(new ApiTest(CompilerApiTest.PARAMETERS)::runR8);
+  }
+
+  @Test
+  public void testD8() throws Exception {
+    runTest(new ApiTest(CompilerApiTest.PARAMETERS)::runD8);
+  }
+
+  private void runTest(Runner test) throws Exception {
+    EnsurePartitionMapOutputConsumer partitionConsumer = EnsurePartitionMapOutputConsumer.get();
+    test.run(DexIndexedConsumer.emptyConsumer(), StringConsumer.emptyConsumer(), partitionConsumer);
+    assertTrue(partitionConsumer.hasOutput());
+  }
+
+  public static class ApiTest extends CompilerApiTest {
+
+    public ApiTest(Object parameters) {
+      super(parameters);
+    }
+
+    public void runD8(
+        ProgramConsumer programConsumer,
+        StringConsumer pgMapConsumer,
+        PartitionMapConsumer partitionMapConsumer)
+        throws Exception {
+      D8.run(
+          D8Command.builder()
+              .addClassProgramData(getBytesForClass(getMockClass()), Origin.unknown())
+              .addClassProgramData(getBytesForClass(getPostStartupMockClass()), Origin.unknown())
+              .addLibraryFiles(getJava8RuntimeJar())
+              .setMinApiLevel(FIRST_API_LEVEL_WITH_NATIVE_MULTIDEX)
+              .setProguardMapConsumer(pgMapConsumer)
+              .setProgramConsumer(programConsumer)
+              .setPartitionMapConsumer(partitionMapConsumer)
+              .build());
+    }
+
+    public void runR8(
+        ProgramConsumer programConsumer,
+        StringConsumer pgMapConsumer,
+        PartitionMapConsumer partitionMapConsumer)
+        throws Exception {
+      R8.run(
+          R8Command.builder()
+              .addClassProgramData(getBytesForClass(getMockClass()), Origin.unknown())
+              .addProguardConfiguration(getKeepMainRules(getMockClass()), Origin.unknown())
+              .addLibraryFiles(getJava8RuntimeJar())
+              .setMinApiLevel(FIRST_API_LEVEL_WITH_NATIVE_MULTIDEX)
+              .setProgramConsumer(programConsumer)
+              .setProguardMapConsumer(pgMapConsumer)
+              .setPartitionMapConsumer(partitionMapConsumer)
+              .build());
+    }
+
+    @Test
+    public void testR8() throws Exception {
+      EnsurePartitionMapOutputConsumer ensurePartitionMapOutputConsumer =
+          EnsurePartitionMapOutputConsumer.get();
+      runR8(
+          DexIndexedConsumer.emptyConsumer(),
+          StringConsumer.emptyConsumer(),
+          ensurePartitionMapOutputConsumer);
+    }
+
+    @Test
+    public void testD8() throws Exception {
+      EnsurePartitionMapOutputConsumer ensurePartitionMapOutputConsumer =
+          EnsurePartitionMapOutputConsumer.get();
+      runD8(
+          DexIndexedConsumer.emptyConsumer(),
+          StringConsumer.emptyConsumer(),
+          ensurePartitionMapOutputConsumer);
+    }
+
+    public static class EnsurePartitionMapOutputConsumer implements PartitionMapConsumer {
+
+      private final List<String> keys = new ArrayList<>();
+      private boolean finished = false;
+
+      private EnsurePartitionMapOutputConsumer() {}
+
+      private boolean hasOutput() {
+        return finished && !keys.isEmpty();
+      }
+
+      public static EnsurePartitionMapOutputConsumer get() {
+        return new EnsurePartitionMapOutputConsumer();
+      }
+
+      @Override
+      public void acceptMappingPartition(MappingPartition mappingPartition) {
+        keys.add(mappingPartition.getKey());
+      }
+
+      @Override
+      public void acceptMappingPartitionMetadata(
+          MappingPartitionMetadata mappingPartitionMetadata) {
+        keys.add("METADATA");
+      }
+
+      @Override
+      public void finished(DiagnosticsHandler handler) {
+        finished = true;
+      }
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/debug/ExamplesDebugTest.java b/src/test/java/com/android/tools/r8/debug/ExamplesDebugTest.java
index 563fc09..7696491 100644
--- a/src/test/java/com/android/tools/r8/debug/ExamplesDebugTest.java
+++ b/src/test/java/com/android/tools/r8/debug/ExamplesDebugTest.java
@@ -60,31 +60,6 @@
   }
 
   @Test
-  public void testConstants() throws Exception {
-    testDebugging("constants", "Constants");
-  }
-
-  @Test
-  public void testControlFlow() throws Exception {
-    testDebugging("controlflow", "ControlFlow");
-  }
-
-  @Test
-  public void testConversions() throws Exception {
-    testDebugging("conversions", "Conversions");
-  }
-
-  @Test
-  public void testFloatingPointValuedAnnotation() throws Exception {
-    testDebugging("floating_point_annotations", "FloatingPointValuedAnnotationTest");
-  }
-
-  @Test
-  public void testFilledArray() throws Exception {
-    testDebugging("filledarray", "FilledArray");
-  }
-
-  @Test
   public void testHello() throws Exception {
     testDebugging("hello", "Hello");
   }
diff --git a/src/test/java/com/android/tools/r8/debug/InterfaceMethodTest.java b/src/test/java/com/android/tools/r8/debug/InterfaceMethodTest.java
index 7a73a31..3a0a0f6 100644
--- a/src/test/java/com/android/tools/r8/debug/InterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/debug/InterfaceMethodTest.java
@@ -7,7 +7,7 @@
 import static com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringForTesting.getCompanionClassNameSuffix;
 import static com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringForTesting.getDefaultMethodPrefix;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assume.assumeTrue;
+import static org.junit.Assume.assumeFalse;
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -47,12 +47,10 @@
 
   @Test
   public void testDefaultMethod() throws Throwable {
-    // TODO(b/244683447): This test fails on Art 13 and Art 14 when checking current method in
-    //  doSomething.
-    assumeTrue(
-        parameters.isCfRuntime()
-            || !(parameters.getDexRuntimeVersion().isEqualTo(Version.V13_0_0)
-                || parameters.getDexRuntimeVersion().isEqualTo(Version.V14_0_0)));
+    assumeFalse(
+        "b/244683447: Incorrect behavior on Art 13 and 14",
+        parameters.isDexRuntimeVersion(Version.V13_0_0)
+            || parameters.isDexRuntimeVersion(Version.V14_0_0));
     testForRuntime(parameters)
         .addProgramFiles(JAR)
         .run(parameters.getRuntime(), debuggeeClass)
diff --git a/src/test/java/com/android/tools/r8/debuginfo/NoKeepLineAttributeTest.java b/src/test/java/com/android/tools/r8/debuginfo/NoKeepLineAttributeTest.java
new file mode 100644
index 0000000..35ae932
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debuginfo/NoKeepLineAttributeTest.java
@@ -0,0 +1,71 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use 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.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+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.naming.retrace.StackTrace.StackTraceLine;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class NoKeepLineAttributeTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters()
+        // Only run the test on VMs that have native pc support.
+        .withDexRuntimesStartingFromExcluding(Version.V7_0_0)
+        .withAllApiLevels()
+        .build();
+  }
+
+  public NoKeepLineAttributeTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(NoKeepLineAttributeTest.class)
+        .addKeepMainRule(TestClass.class)
+        .setMinApi(parameters)
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertFailureWithErrorThatThrows(RuntimeException.class)
+        .inspectStackTrace(
+            stacktrace -> {
+              List<StackTraceLine> stackTraceLines = stacktrace.getStackTraceLines();
+              assertEquals(1, stackTraceLines.size());
+              StackTraceLine stackTraceLine = stackTraceLines.get(0);
+              // The frame will always have a line as the VM is reporting the PC.
+              assertTrue(stackTraceLine.hasLineNumber());
+              if (parameters.getApiLevel().isLessThan(apiLevelWithPcAsLineNumberSupport())) {
+                // If the compile-time API is before native support then no line info is present.
+                // The "line" will be the PC and thus small.
+                assertTrue(stackTraceLine.lineNumber < 10);
+              } else {
+                // If the compile-time API is after native support then the compiler will retain and
+                // emit the mapping from PC to original line. Here line 50 is to ensure it is not a
+                // low PC value.
+                assertTrue(stackTraceLine.lineNumber > 50);
+              }
+            });
+  }
+
+  static class TestClass {
+
+    public static void main(String[] args) {
+      throw new RuntimeException("My Exception!");
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/debuginfo/NoKeepSourceFileAttributeTest.java b/src/test/java/com/android/tools/r8/debuginfo/NoKeepSourceFileAttributeTest.java
new file mode 100644
index 0000000..9a68a09
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debuginfo/NoKeepSourceFileAttributeTest.java
@@ -0,0 +1,107 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use 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.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class NoKeepSourceFileAttributeTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withDexRuntimesAndAllApiLevels().build();
+  }
+
+  public NoKeepSourceFileAttributeTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  public boolean isRuntimeWithPcAsLineNumberSupport() {
+    return parameters.isDexRuntime()
+        && parameters
+            .getRuntime()
+            .maxSupportedApiLevel()
+            .isGreaterThanOrEqualTo(apiLevelWithPcAsLineNumberSupport());
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(NoKeepSourceFileAttributeTest.class)
+        .addKeepMainRule(TestClass.class)
+        .setMinApi(parameters)
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertFailureWithErrorThatThrows(RuntimeException.class)
+        .inspectOriginalStackTrace(
+            stacktrace -> {
+              List<StackTraceLine> stackTraceLines = stacktrace.getStackTraceLines();
+              assertEquals(1, stackTraceLines.size());
+              StackTraceLine stackTraceLine = stackTraceLines.get(0);
+              if (!isRuntimeWithPcAsLineNumberSupport()) {
+                assertEquals("SourceFile", stackTraceLine.fileName);
+              } else {
+                // VMs with native PC support and no debug info print "Unknown Source".
+                // TODO(b/146565491): This will need a check for new VMs once fixed.
+                assertEquals("Unknown Source", stackTraceLine.fileName);
+              }
+            })
+        .inspectStackTrace(
+            stacktrace -> {
+              List<StackTraceLine> stackTraceLines = stacktrace.getStackTraceLines();
+              assertEquals(1, stackTraceLines.size());
+              StackTraceLine stackTraceLine = stackTraceLines.get(0);
+              assertEquals("NoKeepSourceFileAttributeTest.java", stackTraceLine.fileName);
+            });
+  }
+
+  @Test
+  public void testNoOpt() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(NoKeepSourceFileAttributeTest.class)
+        .addKeepMainRule(TestClass.class)
+        // Keeping lines and not obfuscating or optimizing will retain original lines.
+        .addDontObfuscate()
+        .addDontOptimize()
+        .addKeepAttributeLineNumberTable()
+        .setMinApi(parameters)
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertFailureWithErrorThatThrows(RuntimeException.class)
+        .inspectOriginalStackTrace(
+            stacktrace -> {
+              List<StackTraceLine> stackTraceLines = stacktrace.getStackTraceLines();
+              assertEquals(1, stackTraceLines.size());
+              StackTraceLine stackTraceLine = stackTraceLines.get(0);
+              assertEquals("SourceFile", stackTraceLine.fileName);
+              // The non-optimizing/obfuscating build will retain the original line info.
+              assertTrue(stackTraceLine.lineNumber > 50);
+            })
+        .inspectStackTrace(
+            stacktrace -> {
+              List<StackTraceLine> stackTraceLines = stacktrace.getStackTraceLines();
+              assertEquals(1, stackTraceLines.size());
+              StackTraceLine stackTraceLine = stackTraceLines.get(0);
+              assertEquals("NoKeepSourceFileAttributeTest.java", stackTraceLine.fileName);
+              assertTrue(stackTraceLine.lineNumber > 50);
+            });
+  }
+
+  static class TestClass {
+
+    public static void main(String[] args) {
+      throw new RuntimeException("My Exception!");
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/enummerging/EnumMergingInstantiatingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/enummerging/EnumMergingInstantiatingTest.java
new file mode 100644
index 0000000..074e0e9
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/enumunboxing/enummerging/EnumMergingInstantiatingTest.java
@@ -0,0 +1,190 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.enumunboxing.enummerging;
+
+import com.android.tools.r8.AlwaysInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoHorizontalClassMerging;
+import com.android.tools.r8.NoReturnTypeStrengthening;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.enumunboxing.EnumUnboxingTestBase;
+import com.android.tools.r8.utils.DescriptorUtils;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+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 EnumMergingInstantiatingTest extends EnumUnboxingTestBase {
+
+  private static Collection<byte[]> PROGRAM_CLASSES_DATA;
+
+  private final TestParameters parameters;
+  private final boolean enumValueOptimization;
+  private final EnumKeepRules enumKeepRules;
+
+  @Parameters(name = "{0} valueOpt: {1} keep: {2}")
+  public static List<Object[]> data() {
+    return enumUnboxingTestParameters();
+  }
+
+  @BeforeClass
+  public static void setup() throws IOException {
+    PROGRAM_CLASSES_DATA = tranformedInputs();
+  }
+
+  public EnumMergingInstantiatingTest(
+      TestParameters parameters, boolean enumValueOptimization, EnumKeepRules enumKeepRules) {
+    this.parameters = parameters;
+    this.enumValueOptimization = enumValueOptimization;
+    this.enumKeepRules = enumKeepRules;
+  }
+
+  @Test
+  public void testEnumUnboxing() throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramClassFileData(PROGRAM_CLASSES_DATA)
+        .addKeepMainRule(Main.class)
+        .addKeepRules(enumKeepRules.getKeepRules())
+        .addOptionsModification(opt -> opt.testing.enableEnumWithSubtypesUnboxing = true)
+        .addEnumUnboxingInspector(inspector -> inspector.assertUnboxed(InstantiatingEnum.class))
+        .enableInliningAnnotations()
+        .enableAlwaysInliningAnnotations()
+        .enableNoHorizontalClassMergingAnnotations()
+        .enableNoReturnTypeStrengtheningAnnotations()
+        .addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization))
+        .setMinApi(parameters)
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines("AC/DC", "AC/DC", "AC/DC");
+  }
+
+  private static String getNewDescriptorForName(String name, String descriptor) {
+    String descr = DescriptorUtils.javaTypeToDescriptor(InstantiatingEnum.class.getTypeName());
+    String prefix = descr.substring(0, descr.length() - 1);
+    if (name.equals("A")) {
+      return prefix + "$1;";
+    }
+    if (name.equals("D")) {
+      return prefix + "$2;";
+    }
+    return descriptor;
+  }
+
+  public static Collection<byte[]> tranformedInputs() throws IOException {
+    Collection<Path> classFilesForInnerClasses =
+        ToolHelper.getClassFilesForInnerClasses(EnumMergingInstantiatingTest.class);
+    ArrayList<byte[]> bytes = new ArrayList<>();
+    for (Path classFilesForInnerClass : classFilesForInnerClasses) {
+      bytes.add(transform(classFilesForInnerClass));
+    }
+    return bytes;
+  }
+
+  public static byte[] transform(Path path) throws IOException {
+    return transformer(path, null)
+        .changeFieldType(
+            name -> name.equals("A") || name.equals("D"),
+            EnumMergingInstantiatingTest::getNewDescriptorForName)
+        .transform();
+  }
+
+  public static class C {
+
+    @AlwaysInline
+    public static C dispatch(InstantiatingEnum theEnum) {
+      // Only after inlining can the invoke be respecialized to each of the subtype.
+      return theEnum.newEntry();
+    }
+  }
+
+  @NoHorizontalClassMerging
+  public static class AC extends C {
+
+    @Override
+    public String toString() {
+      return "AC";
+    }
+  }
+
+  @NoHorizontalClassMerging
+  public static class DC extends C {
+
+    @Override
+    public String toString() {
+      return "DC";
+    }
+  }
+
+  enum InstantiatingEnum {
+    A {
+      @NeverInline
+      @Override
+      public C newEntry() {
+        return new AC();
+      }
+
+      @NeverInline
+      @Override
+      public C newEntryThroughDispatch() {
+        return C.dispatch(this);
+      }
+    },
+    D {
+      @NeverInline
+      @Override
+      public C newEntry() {
+        return new DC();
+      }
+
+      @NeverInline
+      @Override
+      public C newEntryThroughDispatch() {
+        return C.dispatch(this);
+      }
+    };
+
+    @NeverInline
+    public abstract C newEntry();
+
+    @NeverInline
+    public abstract C newEntryThroughDispatch();
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) {
+      System.out.println(getAC() + "/" + getDC());
+      System.out.println(getC(InstantiatingEnum.A) + "/" + getC(InstantiatingEnum.D));
+      System.out.println(
+          InstantiatingEnum.A.newEntryThroughDispatch()
+              + "/"
+              + InstantiatingEnum.D.newEntryThroughDispatch());
+    }
+
+    @NeverInline
+    @NoReturnTypeStrengthening
+    private static C getAC() {
+      return InstantiatingEnum.A.newEntry();
+    }
+
+    @NeverInline
+    @NoReturnTypeStrengthening
+    private static C getDC() {
+      return InstantiatingEnum.D.newEntry();
+    }
+
+    @NeverInline
+    private static C getC(InstantiatingEnum e) {
+      return e.newEntry();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/examples/ExamplesTestBase.java b/src/test/java/com/android/tools/r8/examples/ExamplesTestBase.java
index cd9e112..11576d6 100644
--- a/src/test/java/com/android/tools/r8/examples/ExamplesTestBase.java
+++ b/src/test/java/com/android/tools/r8/examples/ExamplesTestBase.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.examples;
 
 import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestRuntime.CfRuntime;
 import com.android.tools.r8.ToolHelper;
@@ -16,8 +17,8 @@
 import java.nio.file.Path;
 import java.util.Collections;
 import java.util.List;
+import java.util.function.Consumer;
 import org.junit.Assume;
-import org.junit.Test;
 
 public abstract class ExamplesTestBase extends DebugTestBase {
 
@@ -43,12 +44,17 @@
   }
 
   public void runTestR8() throws Exception {
+    runTestR8(unused -> {});
+  }
+
+  public void runTestR8(Consumer<R8FullTestBuilder> modifier) throws Exception {
     parameters.assumeR8TestParameters();
     testForR8(parameters.getBackend())
         .addOptionsModification(o -> o.testing.roundtripThroughLir = true)
         .setMinApi(parameters)
         .addProgramClasses(getTestClasses())
         .addKeepMainRule(getMainClass())
+        .apply(modifier::accept)
         .run(parameters.getRuntime(), getMainClass())
         .assertSuccessWithOutput(getExpected());
   }
@@ -99,6 +105,8 @@
         .setMinApi(parameters)
         .addProgramClasses(getTestClasses())
         .addKeepMainRule(getMainClass())
+        .addKeepRules("-keep,allowshrinking class *")
+        .addKeepAllAttributes()
         .debug()
         .compile()
         .debugConfig(parameters.getRuntime());
diff --git a/src/test/examples/constants/Constants.java b/src/test/java/com/android/tools/r8/examples/constants/Constants.java
similarity index 97%
rename from src/test/examples/constants/Constants.java
rename to src/test/java/com/android/tools/r8/examples/constants/Constants.java
index 6349749..83aed19 100644
--- a/src/test/examples/constants/Constants.java
+++ b/src/test/java/com/android/tools/r8/examples/constants/Constants.java
@@ -4,7 +4,7 @@
 
 // This code is not run directly. It needs to be compiled to dex code.
 // 'constants.dex' is what is run.
-package constants;
+package com.android.tools.r8.examples.constants;
 
 class Constants {
 
diff --git a/src/test/java/com/android/tools/r8/examples/constants/ConstantsTestRunner.java b/src/test/java/com/android/tools/r8/examples/constants/ConstantsTestRunner.java
new file mode 100644
index 0000000..40432f5
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/examples/constants/ConstantsTestRunner.java
@@ -0,0 +1,56 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.examples.constants;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.examples.ExamplesTestBase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class ConstantsTestRunner extends ExamplesTestBase {
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().enableApiLevelsForCf().build();
+  }
+
+  public ConstantsTestRunner(TestParameters parameters) {
+    super(parameters);
+  }
+
+  @Override
+  public Class<?> getMainClass() {
+    return Constants.class;
+  }
+
+  @Override
+  public String getExpected() {
+    return "-8-1017-32768-9832767-65536-26843545625165824015728640983040-214748364865536-3276932768"
+        + "-65535-26843545525165824115728641983041-214748364765537-32768-10132767-32769"
+        + "-2147483648214748364732768-281474976710656"
+        + "-11529215046068469761080863910568919040675539944105574404222124650659840"
+        + "-92233720368547758082814749767106569223090561878065152-21474836492147483648"
+        + "-140737488355329-281474976710655"
+        + "-11529215046068469751080863910568919041675539944105574414222124650659841"
+        + "-922337203685477580728147497671065792233720368547758079223090561878065153";
+  }
+
+  @Test
+  public void testDesugaring() throws Exception {
+    runTestDesugaring();
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    runTestR8();
+  }
+
+  @Test
+  public void testDebug() throws Exception {
+    runTestDebugComparator();
+  }
+}
diff --git a/src/test/examples/controlflow/ControlFlow.java b/src/test/java/com/android/tools/r8/examples/controlflow/ControlFlow.java
similarity index 97%
rename from src/test/examples/controlflow/ControlFlow.java
rename to src/test/java/com/android/tools/r8/examples/controlflow/ControlFlow.java
index ffdabe0..5296c77 100644
--- a/src/test/examples/controlflow/ControlFlow.java
+++ b/src/test/java/com/android/tools/r8/examples/controlflow/ControlFlow.java
@@ -5,7 +5,7 @@
 // This code is not run directly. It needs to be compiled to dex code.
 // 'controlflow.dex' is what is run.
 
-package controlflow;
+package com.android.tools.r8.examples.controlflow;
 
 public class ControlFlow {
 
diff --git a/src/test/java/com/android/tools/r8/examples/controlflow/ControlFlowTestRunner.java b/src/test/java/com/android/tools/r8/examples/controlflow/ControlFlowTestRunner.java
new file mode 100644
index 0000000..770ec02
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/examples/controlflow/ControlFlowTestRunner.java
@@ -0,0 +1,82 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.examples.controlflow;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.examples.ExamplesTestBase;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class ControlFlowTestRunner extends ExamplesTestBase {
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().enableApiLevelsForCf().build();
+  }
+
+  public ControlFlowTestRunner(TestParameters parameters) {
+    super(parameters);
+  }
+
+  @Override
+  public Class<?> getMainClass() {
+    return ControlFlow.class;
+  }
+
+  @Override
+  public String getExpected() {
+    return StringUtils.lines(
+        "Fisk",
+        "Hest",
+        "Fisk 1 1.1 true",
+        "Hest 2 2.2 false",
+        "Fisk",
+        "Hep!",
+        "10",
+        "10",
+        "5",
+        "10",
+        "5",
+        "2",
+        "10",
+        "10",
+        "5",
+        "10",
+        "5",
+        "2",
+        "simpleLoop",
+        "simpleLoop",
+        "count: 0",
+        "simpleLoop",
+        "count: 0",
+        "count: 1",
+        "count: 2",
+        "count: 3",
+        "count: 4",
+        "count: 5",
+        "count: 6",
+        "count: 7",
+        "count: 8",
+        "count: 9");
+  }
+
+  @Test
+  public void testDesugaring() throws Exception {
+    runTestDesugaring();
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    runTestR8();
+  }
+
+  @Test
+  public void testDebug() throws Exception {
+    runTestDebugComparator();
+  }
+}
diff --git a/src/test/examples/conversions/Conversions.java b/src/test/java/com/android/tools/r8/examples/conversions/Conversions.java
similarity index 96%
rename from src/test/examples/conversions/Conversions.java
rename to src/test/java/com/android/tools/r8/examples/conversions/Conversions.java
index 456972d..28f3c55 100644
--- a/src/test/examples/conversions/Conversions.java
+++ b/src/test/java/com/android/tools/r8/examples/conversions/Conversions.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 conversions;
+package com.android.tools.r8.examples.conversions;
 
 public class Conversions {
 
diff --git a/src/test/java/com/android/tools/r8/examples/conversions/ConversionsTestRunner.java b/src/test/java/com/android/tools/r8/examples/conversions/ConversionsTestRunner.java
new file mode 100644
index 0000000..15ccd76
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/examples/conversions/ConversionsTestRunner.java
@@ -0,0 +1,51 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.examples.conversions;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.examples.ExamplesTestBase;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class ConversionsTestRunner extends ExamplesTestBase {
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().enableApiLevelsForCf().build();
+  }
+
+  public ConversionsTestRunner(TestParameters parameters) {
+    super(parameters);
+  }
+
+  @Override
+  public Class<?> getMainClass() {
+    return Conversions.class;
+  }
+
+  @Override
+  public String getExpected() {
+    return StringUtils.lines(
+        "1", "1.0", "1.0", "1", "1.0", "1.0", "1", "1", "1.0", "1", "1", "1.0", "1", "\u0001", "1");
+  }
+
+  @Test
+  public void testDesugaring() throws Exception {
+    runTestDesugaring();
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    runTestR8();
+  }
+
+  @Test
+  public void testDebug() throws Exception {
+    runTestDebugComparator();
+  }
+}
diff --git a/src/test/examples/filledarray/FilledArray.java b/src/test/java/com/android/tools/r8/examples/filledarray/FilledArray.java
similarity index 98%
rename from src/test/examples/filledarray/FilledArray.java
rename to src/test/java/com/android/tools/r8/examples/filledarray/FilledArray.java
index 46065e2..f25b76b 100644
--- a/src/test/examples/filledarray/FilledArray.java
+++ b/src/test/java/com/android/tools/r8/examples/filledarray/FilledArray.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 filledarray;
+package com.android.tools.r8.examples.filledarray;
 
 import java.util.Arrays;
 
diff --git a/src/test/java/com/android/tools/r8/examples/filledarray/FilledArrayTestRunner.java b/src/test/java/com/android/tools/r8/examples/filledarray/FilledArrayTestRunner.java
new file mode 100644
index 0000000..6c4deee
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/examples/filledarray/FilledArrayTestRunner.java
@@ -0,0 +1,148 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.examples.filledarray;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.examples.ExamplesTestBase;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class FilledArrayTestRunner extends ExamplesTestBase {
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().enableApiLevelsForCf().build();
+  }
+
+  public FilledArrayTestRunner(TestParameters parameters) {
+    super(parameters);
+  }
+
+  @Override
+  public Class<?> getMainClass() {
+    return FilledArray.class;
+  }
+
+  @Override
+  public String getExpected() {
+    return StringUtils.lines(
+        "booleans",
+        "true",
+        "true",
+        "false",
+        "false",
+        "false",
+        "true",
+        "false",
+        "false",
+        "bytes",
+        "0",
+        "1",
+        "2",
+        "3",
+        "4",
+        "5",
+        "6",
+        "7",
+        "8",
+        "9",
+        "10",
+        "11",
+        "12",
+        "13",
+        "14",
+        "15",
+        "16",
+        "17",
+        "18",
+        "-19",
+        "-20",
+        "-96",
+        "127",
+        "-128",
+        "21",
+        "22",
+        "-23",
+        "chars",
+        "a",
+        "b",
+        "c",
+        "d",
+        "a",
+        "b",
+        "c",
+        "d",
+        "ints",
+        "2147483647",
+        "0",
+        "-42",
+        "42",
+        "-2147483648",
+        "2147483647",
+        "0",
+        "-42",
+        "42",
+        "-2147483648",
+        "shorts",
+        "32767",
+        "0",
+        "-42",
+        "42",
+        "-32768",
+        "32767",
+        "0",
+        "-42",
+        "42",
+        "-32768",
+        "longs",
+        "9223372036854775807",
+        "1311693406324658740",
+        "-1311693406324658740",
+        "-9223372036854775808",
+        "1311747200790041140",
+        "-1311693406324671263",
+        "floats",
+        "3.4028235E38",
+        "23.23",
+        "-43.123",
+        "1.4E-45",
+        "1.1754944E-38",
+        "23.23",
+        "-43.123",
+        "doubles",
+        "1.7976931348623157E308",
+        "1.23123123123E8",
+        "-43333.123",
+        "4.9E-324",
+        "2.2250738585072014E-308",
+        "1.23123123123E8",
+        "-43333.123",
+        "i = 1",
+        "ints = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]",
+        "ints2 = [0, 1, 2, 3, 4]",
+        "i = 7",
+        "ints = [0, 1, 2, 3, 4]",
+        "Exception: class java.lang.ArithmeticException",
+        "Exception: class java.lang.ArithmeticException");
+  }
+
+  @Test
+  public void testDesugaring() throws Exception {
+    runTestDesugaring();
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    runTestR8();
+  }
+
+  @Test
+  public void testDebug() throws Exception {
+    runTestDebugComparator();
+  }
+}
diff --git a/src/test/examples/floating_point_annotations/FloatingPointValuedAnnotation.java b/src/test/java/com/android/tools/r8/examples/floating_point_annotations/FloatingPointValuedAnnotation.java
similarity index 87%
rename from src/test/examples/floating_point_annotations/FloatingPointValuedAnnotation.java
rename to src/test/java/com/android/tools/r8/examples/floating_point_annotations/FloatingPointValuedAnnotation.java
index 5d7fd8c..83b9d69 100644
--- a/src/test/examples/floating_point_annotations/FloatingPointValuedAnnotation.java
+++ b/src/test/java/com/android/tools/r8/examples/floating_point_annotations/FloatingPointValuedAnnotation.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 floating_point_annotations;
+package com.android.tools.r8.examples.floating_point_annotations;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
diff --git a/src/test/examples/floating_point_annotations/FloatingPointValuedAnnotationTest.java b/src/test/java/com/android/tools/r8/examples/floating_point_annotations/FloatingPointValuedAnnotationTest.java
similarity index 92%
rename from src/test/examples/floating_point_annotations/FloatingPointValuedAnnotationTest.java
rename to src/test/java/com/android/tools/r8/examples/floating_point_annotations/FloatingPointValuedAnnotationTest.java
index 1772f23..d787b76 100644
--- a/src/test/examples/floating_point_annotations/FloatingPointValuedAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/examples/floating_point_annotations/FloatingPointValuedAnnotationTest.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 floating_point_annotations;
+package com.android.tools.r8.examples.floating_point_annotations;
 
 public class FloatingPointValuedAnnotationTest {
 
diff --git a/src/test/java/com/android/tools/r8/examples/floating_point_annotations/FloatingPointValuedAnnotationTestRunner.java b/src/test/java/com/android/tools/r8/examples/floating_point_annotations/FloatingPointValuedAnnotationTestRunner.java
new file mode 100644
index 0000000..fb097c0
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/examples/floating_point_annotations/FloatingPointValuedAnnotationTestRunner.java
@@ -0,0 +1,78 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.examples.floating_point_annotations;
+
+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.examples.ExamplesTestBase;
+import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class FloatingPointValuedAnnotationTestRunner extends ExamplesTestBase {
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().enableApiLevelsForCf().build();
+  }
+
+  public FloatingPointValuedAnnotationTestRunner(TestParameters parameters) {
+    super(parameters);
+  }
+
+  @Override
+  public Class<?> getMainClass() {
+    return FloatingPointValuedAnnotationTest.class;
+  }
+
+  @Override
+  public List<Class<?>> getTestClasses() {
+    return ImmutableList.of(
+        FloatingPointValuedAnnotation.class,
+        FloatingPointValuedAnnotationTest.class,
+        FloatingPointValuedAnnotationTest.A.class,
+        FloatingPointValuedAnnotationTest.B.class,
+        FloatingPointValuedAnnotationTest.C.class,
+        FloatingPointValuedAnnotationTest.D.class);
+  }
+
+  @Override
+  public String getExpected() {
+    return StringUtils.lines("false", "false");
+  }
+
+  @Test
+  public void testDesugaring() throws Exception {
+    runTestDesugaring();
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    runTestR8(
+        builder ->
+            builder
+                .addKeepRuntimeVisibleAnnotations()
+                .addKeepClassAndMembersRules(
+                    FloatingPointValuedAnnotation.class,
+                    FloatingPointValuedAnnotationTest.A.class,
+                    FloatingPointValuedAnnotationTest.B.class,
+                    FloatingPointValuedAnnotationTest.C.class,
+                    FloatingPointValuedAnnotationTest.D.class));
+  }
+
+  @Test
+  public void testDebug() throws Exception {
+    Assume.assumeFalse(
+        "VMs 13 and 14 step-out to the continuation (line 28) and not the call-site (line 25).",
+        parameters.isDexRuntimeVersion(Version.V13_0_0)
+            || parameters.isDexRuntimeVersion(Version.V14_0_0));
+    runTestDebugComparator();
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java b/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java
index cba424a..d32f6f9 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java
@@ -212,8 +212,11 @@
   private boolean canSharePrintCallInSuccessorBlock() {
     // With API level >= Q we get a register assignment that allows us to share the print call in a
     // successor block. See also InternalOptions.canHaveThisJitCodeDebuggingBug().
+    // Due to including line-info (b/279555568) this is always false. Keeping the conflicting
+    // predicates here for documentation of the previously witnessed difference.
     return parameters.isDexRuntime()
-        && parameters.getApiLevel().getLevel() >= AndroidApiLevel.Q.getLevel();
+        && parameters.getApiLevel().getLevel() >= AndroidApiLevel.Q.getLevel()
+        && parameters.getApiLevel().isLessThan(apiLevelWithPcAsLineNumberSupport());
   }
 
   @Test
@@ -241,6 +244,7 @@
                                     NonNullParamAfterInvokeInterface.class,
                                     NonNullParamInterfaceImpl.class))
                     .addOptionsModification(this::disableDevirtualization)
+                    .addKeepAttributeLineNumberTable()
                     .enableAlwaysInliningAnnotations()
                     .enableInliningAnnotations()
                     .enableNeverClassInliningAnnotations()
@@ -252,8 +256,7 @@
     MethodSubject checkViaCall = mainSubject.uniqueMethodWithOriginalName("checkViaCall");
     assertThat(checkViaCall, isPresent());
     assertEquals(0, countActCall(checkViaCall));
-    // The DEX backend reuses the System.out.println invoke.
-    assertEquals(parameters.isCfRuntime() ? 2 : 1, countPrintCall(checkViaCall));
+    assertEquals(2, countPrintCall(checkViaCall));
   }
 
   private long countCallToParamNullCheck(MethodSubject method) {
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
index 7464aec..a78dbbf 100644
--- 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
@@ -222,10 +222,14 @@
               FoundMethodSubject foundMethodSubject = method.asFoundMethodSubject();
               assertEquals(
                   stringBuilderTest.stringBuilders, countStringBuilderInits(foundMethodSubject));
-              if (parameters.isCfRuntime()
+              if ((parameters.isCfRuntime()
+                      || parameters
+                          .getApiLevel()
+                          .isGreaterThanOrEqualTo(apiLevelWithPcAsLineNumberSupport()))
                   && (stringBuilderTest.getMethodName().equals("diamondWithUseTest")
                       || stringBuilderTest.getMethodName().equals("intoPhiTest"))) {
-                // We are not doing block suffix optimization in CF.
+                // We are not doing block suffix optimization in CF and line/pc info prohibits
+                // sharing.
                 assertEquals(
                     stringBuilderTest.appends + 1, countStringBuilderAppends(foundMethodSubject));
               } else {
diff --git a/src/test/java/com/android/tools/r8/naming/ClassNameMinifierOriginalClassNameTest.java b/src/test/java/com/android/tools/r8/naming/ClassNameMinifierOriginalClassNameTest.java
index 6e9067c..b28280d 100644
--- a/src/test/java/com/android/tools/r8/naming/ClassNameMinifierOriginalClassNameTest.java
+++ b/src/test/java/com/android/tools/r8/naming/ClassNameMinifierOriginalClassNameTest.java
@@ -55,6 +55,8 @@
     FileUtils.writeTextFile(dictionary, "A");
     return testForR8(getStaticTemp(), parameters.getBackend())
         .addProgramClasses(A.class, B.class)
+        // Including the source file forces an map entry for the pruned class A. See b/279702361.
+        .addKeepAttributeSourceFile()
         .addKeepClassAndMembersRulesWithAllowObfuscation(B.class)
         .addKeepRules("-classobfuscationdictionary " + dictionary.toString(), "-keeppackagenames")
         .setMinApi(parameters)
@@ -67,7 +69,7 @@
             });
   }
 
-  @Test
+  @Test()
   public void testR8() throws ExecutionException, CompilationFailedException, IOException {
     R8TestCompileResult libraryCompileResult = compilationResults.apply(parameters);
     testForR8(parameters.getBackend())
@@ -83,7 +85,7 @@
         .assertSuccessWithOutputLines("B.foo");
   }
 
-  @Test
+  @Test()
   public void testR8WithReferenceToNotMapped() {
     assumeTrue(parameters.isDexRuntime());
     R8TestCompileResult libraryCompileResult = compilationResults.apply(parameters);
diff --git a/src/test/java/com/android/tools/r8/naming/IdentityMappingFileTest.java b/src/test/java/com/android/tools/r8/naming/IdentityMappingFileTest.java
index 21ece10..6bffb78 100644
--- a/src/test/java/com/android/tools/r8/naming/IdentityMappingFileTest.java
+++ b/src/test/java/com/android/tools/r8/naming/IdentityMappingFileTest.java
@@ -4,9 +4,9 @@
 package com.android.tools.r8.naming;
 
 import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.CoreMatchers.startsWith;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import com.android.tools.r8.DexIndexedConsumer;
 import com.android.tools.r8.DiagnosticsHandler;
@@ -51,11 +51,20 @@
     assertThat(mapping, containsString("# {\"id\":\"com.android.tools.r8.mapping\",\"version\":"));
     assertThat(mapping, containsString("# pg_map_id: "));
     assertThat(mapping, containsString("# pg_map_hash: SHA-256 "));
-    // Check the mapping is the identity, e.g., only comments are defined.
-    // Note, this could change if the mapping is ever changed to be complete, in which case the
-    // mapping will have actual identity mappings.
+    // Check the mapping is the identity, e.g., only comments and identity entries are defined.
     for (String line : StringUtils.splitLines(mapping)) {
-      assertThat(line, startsWith("#"));
+      if (line.startsWith("#")) {
+        continue;
+      }
+      String[] parts = line.split(" -> ");
+      if (parts.length == 2 && line.endsWith(":")) {
+        String left = parts[0];
+        String right = parts[1];
+        if (left.equals(right.substring(0, right.length() - 1))) {
+          continue;
+        }
+      }
+      fail("Expected comment or identity, got: " + line);
     }
   }
 
diff --git a/src/test/java/com/android/tools/r8/naming/PackageNamingTest.java b/src/test/java/com/android/tools/r8/naming/PackageNamingTest.java
index fa9de18..5b85343 100644
--- a/src/test/java/com/android/tools/r8/naming/PackageNamingTest.java
+++ b/src/test/java/com/android/tools/r8/naming/PackageNamingTest.java
@@ -139,7 +139,7 @@
   private static void verifyUniqueNaming(CodeInspector inspector, List<String> klasses) {
     Set<String> renamedNames = Sets.newHashSet();
     for (String klass : klasses) {
-      String finalName = inspector.clazz(klass).getFinalName();
+      String finalName = inspector.getObfuscatedTypeName(klass);
       assertFalse(renamedNames.contains(finalName));
       renamedNames.add(finalName);
     }
diff --git a/src/test/java/com/android/tools/r8/regress/Regress160394262Test.java b/src/test/java/com/android/tools/r8/regress/Regress160394262Test.java
index d56e49c..c4fa84b 100644
--- a/src/test/java/com/android/tools/r8/regress/Regress160394262Test.java
+++ b/src/test/java/com/android/tools/r8/regress/Regress160394262Test.java
@@ -59,7 +59,13 @@
   private void checkJoinerIsClassInlined(CodeInspector inspector) {
     assertThat(inspector.clazz(Joiner.class.getTypeName() + "$1"), isAbsent());
     // TODO(b/160640028): Joiner should be class inlined.
-    assertThat(inspector.clazz(Joiner.class), isPresent());
+    //   When line info tables are kept we appear to successfully inline Joiner. Reason unknown.
+    if (parameters.isCfRuntime()
+        || parameters.getApiLevel().isLessThan(apiLevelWithPcAsLineNumberSupport())) {
+      assertThat(inspector.clazz(Joiner.class), isPresent());
+    } else {
+      assertThat(inspector.clazz(Joiner.class), isAbsent());
+    }
   }
 
   static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultiplePathsSuccessTest.java b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultiplePathsSuccessTest.java
index 2852961..9e40d0e 100644
--- a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultiplePathsSuccessTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultiplePathsSuccessTest.java
@@ -139,7 +139,10 @@
   @Test
   public void testR8() throws Exception {
     // TODO(b/230289235): Extend resolution to support multiple definition results.
-    runTest(testForR8(parameters.getBackend()).addKeepMainRule(Main.class))
+    runTest(
+            testForR8(parameters.getBackend())
+                .addKeepAttributeSourceFile()
+                .addKeepMainRule(Main.class))
         .assertFailureWithErrorThatThrowsIf(
             parameters.canUseDefaultAndStaticInterfaceMethods(), NoSuchMethodError.class)
         .assertSuccessWithOutputLinesIf(
diff --git a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleProgramPartialTest.java b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleProgramPartialTest.java
index ca57c2f..abc79b4 100644
--- a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleProgramPartialTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleProgramPartialTest.java
@@ -128,10 +128,13 @@
             !parameters.canUseDefaultAndStaticInterfaceMethods(), UNEXPECTED);
   }
 
-  @Test
+  @Test()
   public void testR8() throws Exception {
     // TODO(b/230289235): Extend to support multiple definition results.
-    runTest(testForR8(parameters.getBackend()).addKeepMainRule(Main.class))
+    runTest(
+            testForR8(parameters.getBackend())
+                .addKeepAttributeSourceFile()
+                .addKeepMainRule(Main.class))
         .assertFailureWithErrorThatThrowsIf(
             parameters.canUseDefaultAndStaticInterfaceMethods(), NoSuchMethodError.class)
         .assertSuccessWithOutputLinesIf(
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java b/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java
index b1e37b4..36cfc16 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java
@@ -185,7 +185,7 @@
   public void testHelp() throws IOException {
     ProcessResult processResult = runRetraceCommandLine(null, Arrays.asList("--help"));
     assertEquals(0, processResult.exitCode);
-    assertThat(processResult.stdout, containsString(Retrace.USAGE_MESSAGE));
+    assertThat(processResult.stdout, containsString(Retrace.getUsageMessage()));
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java b/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
index ce200a0..63573d2 100644
--- a/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
+++ b/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
@@ -37,6 +37,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.function.BiFunction;
 import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.Predicate;
@@ -887,6 +888,34 @@
         });
   }
 
+  public ClassFileTransformer changeFieldType(
+      Predicate<String> fieldPredicate,
+      BiFunction<String, String, String> newDescriptorTransformer) {
+    return addClassTransformer(
+            new ClassTransformer() {
+              @Override
+              public FieldVisitor visitField(
+                  int access, String name, String descriptor, String signature, Object value) {
+                String newDescriptor =
+                    fieldPredicate.test(name)
+                        ? newDescriptorTransformer.apply(name, descriptor)
+                        : descriptor;
+                return super.visitField(access, name, newDescriptor, signature, value);
+              }
+            })
+        .addMethodTransformer(
+            new MethodTransformer() {
+              @Override
+              public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
+                String newDescriptor =
+                    fieldPredicate.test(name)
+                        ? newDescriptorTransformer.apply(name, descriptor)
+                        : descriptor;
+                super.visitFieldInsn(opcode, owner, name, newDescriptor);
+              }
+            });
+  }
+
   public ClassFileTransformer renameAndRemapField(String oldName, String newName) {
     FieldSignaturePredicate matchPredicate = (name, signature) -> oldName.equals(name);
     remapField(matchPredicate, newName);
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 21a12a2..74bdc47 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
@@ -359,15 +359,17 @@
     String name = DescriptorUtils.descriptorToJavaType(descriptor);
     ClassNamingForNameMapper naming = null;
     if (mapping != null) {
-      String obfuscated = originalToObfuscatedMapping.get(name);
-      if (obfuscated != null) {
-        naming = mapping.getClassNaming(obfuscated);
-        name = obfuscated;
+      // Figure out if the name is an already obfuscated name. It is important to look up by
+      // residual name first to ensure that we do not accidentally find a class that has been
+      // pruned.
+      String original = obfuscatedToOriginalMapping.get(name);
+      if (original != null) {
+        naming = mapping.getClassNaming(name);
       } else {
-        // Figure out if the name is an already obfuscated name.
-        String original = obfuscatedToOriginalMapping.get(name);
-        if (original != null) {
-          naming = mapping.getClassNaming(name);
+        String obfuscated = originalToObfuscatedMapping.get(name);
+        if (obfuscated != null) {
+          naming = mapping.getClassNaming(obfuscated);
+          name = obfuscated;
         }
       }
     }
@@ -423,7 +425,7 @@
     return clazz.method(method);
   }
 
-  String getObfuscatedTypeName(String originalTypeName) {
+  public String getObfuscatedTypeName(String originalTypeName) {
     String obfuscatedTypeName = null;
     if (mapping != null) {
       obfuscatedTypeName = mapType(originalToObfuscatedMapping, originalTypeName);
@@ -431,7 +433,7 @@
     return obfuscatedTypeName != null ? obfuscatedTypeName : originalTypeName;
   }
 
-  String getOriginalTypeName(String minifiedTypeName) {
+  public String getOriginalTypeName(String minifiedTypeName) {
     String originalTypeName = null;
     if (mapping != null) {
       originalTypeName = mapType(obfuscatedToOriginalMapping, minifiedTypeName);
diff --git a/third_party/binary_compatibility_tests/compiler_api_tests.tar.gz.sha1 b/third_party/binary_compatibility_tests/compiler_api_tests.tar.gz.sha1
index b83c4a2..e5b5e41 100644
--- a/third_party/binary_compatibility_tests/compiler_api_tests.tar.gz.sha1
+++ b/third_party/binary_compatibility_tests/compiler_api_tests.tar.gz.sha1
@@ -1 +1 @@
-ae9c0faab45cba310dbe57a3ce0dcba7bed355a3
\ No newline at end of file
+2aaa39dd57bf8c1c21393ae6b3181ae3a10da88e
\ No newline at end of file
diff --git a/tools/archive.py b/tools/archive.py
index 6a39594..d724b18 100755
--- a/tools/archive.py
+++ b/tools/archive.py
@@ -217,10 +217,12 @@
       utils.R8_JAR,
       utils.R8LIB_JAR,
       utils.R8LIB_JAR + '.map',
+      utils.R8LIB_JAR + '_map.zip',
       utils.R8_SRC_JAR,
       utils.R8_FULL_EXCLUDE_DEPS_JAR,
       utils.R8LIB_EXCLUDE_DEPS_JAR,
       utils.R8LIB_EXCLUDE_DEPS_JAR + '.map',
+      utils.R8LIB_EXCLUDE_DEPS_JAR + '_map.zip',
       utils.R8RETRACE_JAR,
       utils.R8RETRACE_EXCLUDE_DEPS_JAR,
       utils.MAVEN_ZIP,
diff --git a/tools/build_r8lib.py b/tools/build_r8lib.py
index 8dc0cb8..54cf915 100755
--- a/tools/build_r8lib.py
+++ b/tools/build_r8lib.py
@@ -58,6 +58,7 @@
   if output_path is None:
     output_path = target + 'lib.jar'
   output_map_path = output_path + '.map'
+  r8_output_map_path = output_path + '_map.zip'
   toolhelper.run(
       'r8',
       ('--release',
@@ -67,7 +68,8 @@
        temp_lib,
        '--output', output_path,
        '--pg-conf', keep_rules_path,
-       '--pg-map-output', output_map_path),
+       '--pg-map-output', output_map_path,
+       '--partition-map-output', r8_output_map_path),
       **kwargs)
   if exclude_deps:
     return [output_path, temp_deps]
diff --git a/tools/create_r8lib.py b/tools/create_r8lib.py
index b6189e6..51e2fd6 100755
--- a/tools/create_r8lib.py
+++ b/tools/create_r8lib.py
@@ -96,6 +96,7 @@
   cmd.extend(['--source-file-template', source_file_template])
   cmd.extend(['--output', args.output])
   cmd.extend(['--pg-map-output', args.output + '.map'])
+  cmd.extend(['--partition-map-output', args.output + '_map.zip'])
   cmd.extend(['--lib', jdk.GetJdkHome()])
   if args.pg_conf:
     for pgconf in args.pg_conf:
diff --git a/tools/trigger.py b/tools/trigger.py
index 0fd8b64..b3e09f2 100755
--- a/tools/trigger.py
+++ b/tools/trigger.py
@@ -104,7 +104,7 @@
       'add',
       'r8/ci/%s' % SMALI_BOT,
       '-p',
-      '\'test_options=["--version", "%s"]\'' % version
+      'test_options=["--version", "%s"]' % version
   ]
   subprocess.check_call(cmd)