Merge commit '2d4b80a04683884aa3a71fe18b81e32b8d01412f' into dev-release
diff --git a/.gitignore b/.gitignore
index 405e837..59981e8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -130,6 +130,8 @@
 third_party/kotlin/kotlin-compiler-dev
 third_party/kotlinx-coroutines-1.3.6.tar.gz
 third_party/kotlinx-coroutines-1.3.6
+third_party/multidex
+third_party/multidex.tar.gz
 third_party/nest/*
 third_party/openjdk/desugar_jdk_libs
 third_party/openjdk/desugar_jdk_libs.tar.gz
diff --git a/build.gradle b/build.gradle
index 812b438..eca19a7 100644
--- a/build.gradle
+++ b/build.gradle
@@ -8,8 +8,8 @@
 import dx.DxTask
 import net.ltgt.gradle.errorprone.CheckSeverity
 import org.gradle.internal.os.OperatingSystem
-import smali.SmaliTask
 import tasks.DownloadDependency
+import smali.SmaliTask
 import tasks.GetJarsFromConfiguration
 import utils.Utils
 
@@ -378,6 +378,7 @@
                 "kotlin/kotlin-compiler-1.6.0",
                 "kotlin/kotlin-compiler-1.7.0",
                 "kotlinx-coroutines-1.3.6",
+                "multidex",
                 "openjdk/openjdk-rt-1.8",
                 "openjdk/desugar_jdk_libs",
                 "openjdk/desugar_jdk_libs_11",
diff --git a/src/library_desugar/java/j$/nio/file/Path.java b/src/library_desugar/java/j$/nio/file/Path.java
index 781ab5f..6030764 100644
--- a/src/library_desugar/java/j$/nio/file/Path.java
+++ b/src/library_desugar/java/j$/nio/file/Path.java
@@ -9,4 +9,8 @@
   public static j$.nio.file.Path wrap_convert(java.nio.file.Path path) {
     return null;
   }
+
+  public static java.nio.file.Path wrap_convert(j$.nio.file.Path path) {
+    return null;
+  }
 }
diff --git a/src/library_desugar/java/java/nio/file/PathApiFlips.java b/src/library_desugar/java/java/nio/file/PathApiFlips.java
new file mode 100644
index 0000000..7314b7f
--- /dev/null
+++ b/src/library_desugar/java/java/nio/file/PathApiFlips.java
@@ -0,0 +1,137 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package java.nio.file;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.function.Consumer;
+
+/** For all wrappers, the spliterator is based on the iterator so no need to wrap it. */
+public class PathApiFlips {
+
+  public static Iterator<?> flipIteratorPath(Iterator<?> iterator) {
+    return new IteratorPathWrapper<>(iterator);
+  }
+
+  public static Iterable<?> flipIterablePath(Iterable<?> iterable) {
+    return new IterablePathWrapper<>(iterable);
+  }
+
+  public static java.nio.file.DirectoryStream<?> flipDirectoryStreamPath(
+      java.nio.file.DirectoryStream<?> directoryStream) {
+    return new DirectoryStreamPathWrapper<>(directoryStream);
+  }
+
+  public static java.nio.file.DirectoryStream.Filter<?> flipDirectoryStreamFilterPath(
+      java.nio.file.DirectoryStream.Filter<?> filter) {
+    return new DirectoryStreamFilterWrapper<>(filter);
+  }
+
+  /**
+   * The generic types inherit from java.lang.Object even if in practice it seems they are
+   * exclusively used with Path. To be conservative, we return the parameter if it's not a path so
+   * the code works for non Path objects.
+   */
+  @SuppressWarnings("unchecked")
+  public static <T> T convertPath(T maybePath) {
+    if (maybePath == null) {
+      return null;
+    }
+    if (maybePath instanceof java.nio.file.Path) {
+      return (T) j$.nio.file.Path.wrap_convert((java.nio.file.Path) maybePath);
+    }
+    if (maybePath instanceof j$.nio.file.Path) {
+      return (T) j$.nio.file.Path.wrap_convert((j$.nio.file.Path) maybePath);
+    }
+    return maybePath;
+  }
+
+  public static class DirectoryStreamFilterWrapper<T>
+      implements java.nio.file.DirectoryStream.Filter<T> {
+
+    private final java.nio.file.DirectoryStream.Filter<T> filter;
+
+    public DirectoryStreamFilterWrapper(java.nio.file.DirectoryStream.Filter<T> filter) {
+      this.filter = filter;
+    }
+
+    @Override
+    public boolean accept(T t) throws IOException {
+      return filter.accept(convertPath(t));
+    }
+  }
+
+  public static class IterablePathWrapper<T> implements Iterable<T> {
+
+    private final Iterable<T> iterable;
+
+    public IterablePathWrapper(Iterable<T> iterable) {
+      this.iterable = iterable;
+    }
+
+    @Override
+    public Iterator<T> iterator() {
+      return new IteratorPathWrapper<>(iterable.iterator());
+    }
+
+    @Override
+    public void forEach(Consumer<? super T> action) {
+      iterable.forEach(path -> action.accept(convertPath(path)));
+    }
+  }
+
+  public static class IteratorPathWrapper<T> implements Iterator<T> {
+
+    private final Iterator<T> iterator;
+
+    public IteratorPathWrapper(Iterator<T> iterator) {
+      this.iterator = iterator;
+    }
+
+    @Override
+    public boolean hasNext() {
+      return iterator.hasNext();
+    }
+
+    @Override
+    public T next() {
+      return convertPath(iterator.next());
+    }
+
+    @Override
+    public void remove() {
+      iterator.remove();
+    }
+
+    @Override
+    public void forEachRemaining(Consumer<? super T> action) {
+      iterator.forEachRemaining(path -> action.accept(convertPath(path)));
+    }
+  }
+
+  public static class DirectoryStreamPathWrapper<T> implements DirectoryStream<T> {
+
+    private final DirectoryStream<T> directoryStream;
+
+    public DirectoryStreamPathWrapper(DirectoryStream<T> directoryStream) {
+      this.directoryStream = directoryStream;
+    }
+
+    @Override
+    public Iterator<T> iterator() {
+      return new IteratorPathWrapper<>(directoryStream.iterator());
+    }
+
+    @Override
+    public void forEach(Consumer<? super T> action) {
+      directoryStream.forEach(path -> action.accept(convertPath(path)));
+    }
+
+    @Override
+    public void close() throws IOException {
+      directoryStream.close();
+    }
+  }
+}
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs.json b/src/library_desugar/jdk11/desugar_jdk_libs.json
index 9cc01cc..f47fe72 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs.json
@@ -6,6 +6,22 @@
   "support_all_callbacks_from_library": true,
   "common_flags": [
     {
+      "api_level_below_or_equal": 10000,
+      "api_level_greater_or_equal": 24,
+      "rewrite_prefix": {
+        "java.util.stream.DesugarDoubleStream": "j$.util.stream.DesugarDoubleStream",
+        "java.util.stream.DesugarIntStream": "j$.util.stream.DesugarIntStream",
+        "java.util.stream.DesugarLongStream": "j$.util.stream.DesugarLongStream",
+        "java.util.stream.DesugarStream": "j$.util.stream.DesugarStream"
+      },
+      "retarget_method": {
+        "java.util.stream.DoubleStream java.util.stream.DoubleStream#iterate(double, java.util.function.DoublePredicate, java.util.function.DoubleUnaryOperator)":  "java.util.stream.DesugarDoubleStream",
+        "java.util.stream.IntStream java.util.stream.IntStream#iterate(int, java.util.function.IntPredicate, java.util.function.IntUnaryOperator)":  "java.util.stream.DesugarIntStream",
+        "java.util.stream.LongStream java.util.stream.LongStream#iterate(long, java.util.function.LongPredicate, java.util.function.LongUnaryOperator)":  "java.util.stream.DesugarLongStream",
+        "java.util.stream.Stream java.util.stream.Stream#iterate(java.lang.Object, java.util.function.Predicate, java.util.function.UnaryOperator)":  "java.util.stream.DesugarStream"
+      }
+    },
+    {
       "api_level_below_or_equal": 32,
       "rewrite_prefix": {
         "java.util.concurrent.DesugarTimeUnit": "j$.util.concurrent.DesugarTimeUnit"
@@ -229,6 +245,15 @@
   ],
   "program_flags": [
     {
+      "api_level_below_or_equal": 10000,
+      "amend_library_method": [
+        "public static java.util.stream.DoubleStream java.util.stream.DoubleStream#iterate(double, java.util.function.DoublePredicate, java.util.function.DoubleUnaryOperator)",
+        "public static java.util.stream.IntStream java.util.stream.IntStream#iterate(int, java.util.function.IntPredicate, java.util.function.IntUnaryOperator)",
+        "public static java.util.stream.LongStream java.util.stream.LongStream#iterate(long, java.util.function.LongPredicate, java.util.function.LongUnaryOperator)",
+        "public static java.util.stream.Stream java.util.stream.Stream#iterate(java.lang.Object, java.util.function.Predicate, java.util.function.UnaryOperator)"
+      ]
+    },
+    {
       "api_level_below_or_equal": 33,
       "amend_library_method": [
         "public java.lang.Object[] java.util.Collection#toArray(java.util.function.IntFunction)"
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_nio.json b/src/library_desugar/jdk11/desugar_jdk_libs_nio.json
index c62cb34..ff05a80 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs_nio.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs_nio.json
@@ -6,6 +6,22 @@
   "support_all_callbacks_from_library": true,
   "common_flags": [
     {
+      "api_level_below_or_equal": 10000,
+      "api_level_greater_or_equal": 24,
+      "rewrite_prefix": {
+        "java.util.stream.DesugarDoubleStream": "j$.util.stream.DesugarDoubleStream",
+        "java.util.stream.DesugarIntStream": "j$.util.stream.DesugarIntStream",
+        "java.util.stream.DesugarLongStream": "j$.util.stream.DesugarLongStream",
+        "java.util.stream.DesugarStream": "j$.util.stream.DesugarStream"
+      },
+      "retarget_method": {
+        "java.util.stream.DoubleStream java.util.stream.DoubleStream#iterate(double, java.util.function.DoublePredicate, java.util.function.DoubleUnaryOperator)":  "java.util.stream.DesugarDoubleStream",
+        "java.util.stream.IntStream java.util.stream.IntStream#iterate(int, java.util.function.IntPredicate, java.util.function.IntUnaryOperator)":  "java.util.stream.DesugarIntStream",
+        "java.util.stream.LongStream java.util.stream.LongStream#iterate(long, java.util.function.LongPredicate, java.util.function.LongUnaryOperator)":  "java.util.stream.DesugarLongStream",
+        "java.util.stream.Stream java.util.stream.Stream#iterate(java.lang.Object, java.util.function.Predicate, java.util.function.UnaryOperator)":  "java.util.stream.DesugarStream"
+      }
+    },
+    {
       "api_level_below_or_equal": 32,
       "rewrite_prefix": {
         "java.net.URLDecoder": "j$.net.URLDecoder",
@@ -152,6 +168,7 @@
         "java.nio.file.ClosedWatchServiceException",
         "java.nio.file.DirectoryIteratorException",
         "java.nio.file.DirectoryNotEmptyException",
+        "java.nio.file.DirectoryStream",
         "java.nio.file.FileAlreadyExistsException",
         "java.nio.file.FileSystemAlreadyExistsException",
         "java.nio.file.FileSystemException",
@@ -173,6 +190,7 @@
         "java.nio.file.ClosedWatchServiceException",
         "java.nio.file.DirectoryIteratorException",
         "java.nio.file.DirectoryNotEmptyException",
+        "java.nio.file.DirectoryStream",
         "java.nio.file.FileAlreadyExistsException",
         "java.nio.file.FileSystemAlreadyExistsException",
         "java.nio.file.FileSystemException",
@@ -199,7 +217,10 @@
         "java.nio.file.attribute.BasicFileAttributes java.nio.file.spi.FileSystemProvider#readAttributes(java.nio.file.Path, java.lang.Class, java.nio.file.LinkOption[])": [1, "java.lang.Class java.nio.file.FileApiFlips#flipFileAttributes(java.lang.Class)"],
         "java.util.Set java.nio.file.attribute.PosixFileAttributes#permissions()": [-1, "java.util.Set java.nio.file.FileApiFlips#flipPosixPermissionSet(java.util.Set)"],
         "void java.nio.file.attribute.PosixFileAttributeView#setPermissions(java.util.Set)": [0, "java.util.Set java.nio.file.FileApiFlips#flipPosixPermissionSet(java.util.Set)"],
-        "java.util.Map java.nio.file.spi.FileSystemProvider#readAttributes(java.nio.file.Path, java.lang.String, java.nio.file.LinkOption[])" : [-1, "java.util.Map java.nio.file.FileApiFlips#flipMapWithMaybeFileTimeValues(java.util.Map)"]
+        "java.util.Map java.nio.file.spi.FileSystemProvider#readAttributes(java.nio.file.Path, java.lang.String, java.nio.file.LinkOption[])" : [-1, "java.util.Map java.nio.file.FileApiFlips#flipMapWithMaybeFileTimeValues(java.util.Map)"],
+        "java.lang.Iterable java.nio.file.FileSystem#getRootDirectories()": [-1, "java.lang.Iterable java.nio.file.PathApiFlips#flipIterablePath(java.lang.Iterable)"],
+        "java.util.Iterator java.nio.file.Path#iterator()": [-1, "java.util.Iterator java.nio.file.PathApiFlips#flipIteratorPath(java.util.Iterator)"],
+        "java.nio.file.DirectoryStream java.nio.file.spi.FileSystemProvider#newDirectoryStream(java.nio.file.Path, java.nio.file.DirectoryStream$Filter)": [-1, "java.nio.file.DirectoryStream java.nio.file.PathApiFlips#flipDirectoryStreamPath(java.nio.file.DirectoryStream)", 1, "java.nio.file.DirectoryStream$Filter java.nio.file.PathApiFlips#flipDirectoryStreamFilterPath(java.nio.file.DirectoryStream$Filter)"]
       },
       "wrapper_conversion": [
         "java.nio.channels.CompletionHandler",
@@ -219,13 +240,12 @@
         "java.nio.file.StandardOpenOption",
         "java.nio.file.LinkOption",
         "java.nio.file.CopyOption",
+        "java.nio.file.StandardCopyOption",
         "java.nio.file.attribute.GroupPrincipal",
         "java.nio.file.attribute.FileAttribute",
         "java.nio.file.attribute.UserPrincipal",
         "java.nio.file.FileStore",
         "java.nio.file.attribute.FileStoreAttributeView",
-        "java.nio.file.DirectoryStream$Filter",
-        "java.nio.file.DirectoryStream",
         "java.nio.file.attribute.PosixFilePermission",
         "java.nio.file.attribute.BasicFileAttributes",
         "java.nio.file.attribute.PosixFileAttributes",
@@ -374,6 +394,15 @@
   ],
   "program_flags": [
     {
+      "api_level_below_or_equal": 10000,
+      "amend_library_method": [
+        "public static java.util.stream.DoubleStream java.util.stream.DoubleStream#iterate(double, java.util.function.DoublePredicate, java.util.function.DoubleUnaryOperator)",
+        "public static java.util.stream.IntStream java.util.stream.IntStream#iterate(int, java.util.function.IntPredicate, java.util.function.IntUnaryOperator)",
+        "public static java.util.stream.LongStream java.util.stream.LongStream#iterate(long, java.util.function.LongPredicate, java.util.function.LongUnaryOperator)",
+        "public static java.util.stream.Stream java.util.stream.Stream#iterate(java.lang.Object, java.util.function.Predicate, java.util.function.UnaryOperator)"
+      ]
+    },
+    {
       "api_level_below_or_equal": 33,
       "amend_library_method": [
         "public java.lang.Object[] java.util.Collection#toArray(java.util.function.IntFunction)"
@@ -418,12 +447,6 @@
       }
     },
     {
-      "api_level_below_or_equal": 19,
-      "dont_retarget": [
-        "android.support.multidex.MultiDexExtractor$ExtractedDex"
-      ]
-    },
-    {
       "api_level_below_or_equal": 18,
       "rewrite_prefix": {
         "java.lang.DesugarCharacter": "j$.lang.DesugarCharacter"
@@ -556,6 +579,11 @@
       "rewrite_prefix": {
         "java.lang.DesugarCharacter": "j$.lang.DesugarCharacter"
       },
+      "retarget_method" : {
+        "boolean java.lang.Character#isSurrogate(char)" : "java.lang.DesugarCharacter",
+        "char java.lang.Character#highSurrogate(int)" : "java.lang.DesugarCharacter",
+        "char java.lang.Character#lowSurrogate(int)" : "java.lang.DesugarCharacter"
+      },
       "retarget_static_field": {
         "sun.nio.cs.US_ASCII sun.nio.cs.US_ASCII#INSTANCE": "java.nio.charset.Charset java.nio.charset.StandardCharsets#US_ASCII",
         "sun.nio.cs.ISO_8859_1 sun.nio.cs.ISO_8859_1#INSTANCE": "java.nio.charset.Charset java.nio.charset.StandardCharsets#ISO_8859_1",
diff --git a/src/main/java/com/android/tools/r8/dex/CodeToKeep.java b/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
index a5d6098..24d6362 100644
--- a/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
+++ b/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
@@ -98,7 +98,7 @@
       DexType baseType = method.holder.toBaseType(appView.dexItemFactory());
       if (shouldKeep(baseType)) {
         keepClass(baseType);
-        if (!method.holder.isArrayType()) {
+        if (!method.holder.isArrayType() && !isVivifiedType(baseType)) {
           toKeep.get(method.holder).methods.add(method);
         }
       }
@@ -117,7 +117,7 @@
       DexType baseType = field.holder.toBaseType(appView.dexItemFactory());
       if (shouldKeep(baseType)) {
         keepClass(baseType);
-        if (!field.holder.isArrayType()) {
+        if (!field.holder.isArrayType() && !isVivifiedType(baseType)) {
           toKeep.get(field.holder).fields.add(field);
         }
       }
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 b8613b8..ad59604 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -11,7 +11,6 @@
 import com.android.tools.r8.dex.code.DexInstruction;
 import com.android.tools.r8.dex.code.DexReturnVoid;
 import com.android.tools.r8.dex.code.DexSwitchPayload;
-import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DexCode.TryHandler.TypeAddrPair;
 import com.android.tools.r8.graph.DexDebugEvent.SetPositionFrame;
 import com.android.tools.r8.graph.DexDebugEvent.StartLocal;
@@ -508,7 +507,11 @@
       DexInstruction lastInstruction = ArrayUtils.last(instructions);
       debugInfo = advanceToOffset(lastInstruction.getOffset(), debugInfo, debugInfoIterator);
       if (debugInfo != null) {
-        throw new Unreachable("Could not print all debug information.");
+        builder
+            .append("(warning: has unhandled debug events @ pc:")
+            .append(debugInfo.address)
+            .append(", line:")
+            .append(debugInfo.line);
       } else {
         builder.append("(has debug events past last pc)\n");
       }
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 3ee7c50..d838596 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -469,6 +469,45 @@
           floatBufferType,
           doubleBufferType);
 
+  private static final List<String> MULTIDEX_PREFIXES =
+      ImmutableList.of("androidx/", "android/support/");
+  private static final List<String> MULTIDEX_SUFFIXES =
+      ImmutableList.of(
+          "multidex/MultiDex$V14$ElementConstructor;",
+          "multidex/MultiDex$V14$ICSElementConstructor;",
+          "multidex/MultiDex$V14$JBMR11ElementConstructor;",
+          "multidex/MultiDex$V14$JBMR2ElementConstructor;",
+          "multidex/MultiDex$V14;",
+          "multidex/MultiDex$V19;",
+          "multidex/MultiDex$V21_PLUS;",
+          "multidex/MultiDex$V4;",
+          "multidex/MultiDexApplication;",
+          "multidex/MultiDexExtractor$1;",
+          "multidex/MultiDexExtractor$ExtractedDex;",
+          "multidex/MultiDexExtractor;",
+          "multidex/MultiDex;",
+          "multidex/ZipUtil;",
+          "multidex/ZipUtil$CentralDirectory;");
+  private static final List<String> MULTIDEX_INSTRUMENTATION =
+      ImmutableList.of(
+          "Landroid/support/multidex/instrumentation/BuildConfig;",
+          "Landroid/test/runner/MultiDexTestRunner;");
+
+  private List<DexType> createMultiDexTypes() {
+    ImmutableList.Builder<DexType> builder = ImmutableList.builder();
+    for (String prefix : MULTIDEX_PREFIXES) {
+      for (String suffix : MULTIDEX_SUFFIXES) {
+        builder.add(createType("L" + prefix + suffix));
+      }
+    }
+    for (String typeString : MULTIDEX_INSTRUMENTATION) {
+      builder.add(createType(typeString));
+    }
+    return builder.build();
+  }
+
+  public List<DexType> multiDexTypes = createMultiDexTypes();
+
   public final DexType doubleConsumer =
       createStaticallyKnownType("Ljava/util/function/DoubleConsumer;");
   public final DexType longConsumer =
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java
index 09b456b..8770cd1 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPICallbackSynthesizer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.disabledesugarer.DesugaredLibraryDisableDesugarerPostProcessor;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeterPostProcessor;
 import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade;
 import com.android.tools.r8.ir.desugar.records.RecordDesugaring;
@@ -72,6 +73,11 @@
       if (recordRewriter != null) {
         desugarings.add(recordRewriter);
       }
+      DesugaredLibraryDisableDesugarerPostProcessor disableDesugarer =
+          DesugaredLibraryDisableDesugarerPostProcessor.create(appView);
+      if (disableDesugarer != null) {
+        desugarings.add(disableDesugarer);
+      }
       if (desugarings.isEmpty()) {
         return empty();
       }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
index a42d6e5..54837a8 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
@@ -17,6 +17,7 @@
 import com.android.tools.r8.ir.desugar.apimodel.ApiInvokeOutlinerDesugaring;
 import com.android.tools.r8.ir.desugar.constantdynamic.ConstantDynamicInstructionDesugaring;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.disabledesugarer.DesugaredLibraryDisableDesugarer;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeter;
 import com.android.tools.r8.ir.desugar.icce.AlwaysThrowingInstructionDesugaring;
 import com.android.tools.r8.ir.desugar.invokespecial.InvokeSpecialToSelfDesugaring;
@@ -57,6 +58,7 @@
   private final DesugaredLibraryRetargeter desugaredLibraryRetargeter;
   private final InterfaceMethodRewriter interfaceMethodRewriter;
   private final DesugaredLibraryAPIConverter desugaredLibraryAPIConverter;
+  private final DesugaredLibraryDisableDesugarer disableDesugarer;
   private final AndroidApiLevelCompute apiLevelCompute;
 
   NonEmptyCfInstructionDesugaringCollection(
@@ -76,6 +78,7 @@
       this.desugaredLibraryRetargeter = null;
       this.interfaceMethodRewriter = null;
       this.desugaredLibraryAPIConverter = null;
+      this.disableDesugarer = null;
       return;
     }
     this.nestBasedAccessDesugaring = NestBasedAccessDesugaring.create(appView);
@@ -87,6 +90,10 @@
     if (desugaredLibraryRetargeter != null) {
       desugarings.add(desugaredLibraryRetargeter);
     }
+    disableDesugarer = DesugaredLibraryDisableDesugarer.create(appView);
+    if (disableDesugarer != null) {
+      desugarings.add(disableDesugarer);
+    }
     if (appView.options().apiModelingOptions().enableOutliningOfMethods) {
       yieldingDesugarings.add(new ApiInvokeOutlinerDesugaring(appView, apiLevelCompute));
     }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java
index eeebd32..2d72b93 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java
@@ -103,6 +103,9 @@
     if (isAPIConversionSyntheticType(context.getHolderType(), wrapperSynthesizor, appView)) {
       return false;
     }
+    if (appView.dexItemFactory().multiDexTypes.contains(context.getHolderType())) {
+      return false;
+    }
     return shouldRewriteInvoke(instruction.asInvoke(), context);
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/disabledesugarer/DesugaredLibraryDisableDesugarer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/disabledesugarer/DesugaredLibraryDisableDesugarer.java
new file mode 100644
index 0000000..bd4b771
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/disabledesugarer/DesugaredLibraryDisableDesugarer.java
@@ -0,0 +1,101 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.desugar.desugaredlibrary.disabledesugarer;
+
+import com.android.tools.r8.cf.code.CfFieldInstruction;
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.cf.code.CfTypeInstruction;
+import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaringCollection;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
+import com.android.tools.r8.ir.desugar.FreshLocalProvider;
+import com.android.tools.r8.ir.desugar.LocalStackAllocator;
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * Disables the rewriting of types in specific classes declared in the desugared library
+ * specification, typically classes that are used pre-native multidex.
+ */
+public class DesugaredLibraryDisableDesugarer implements CfInstructionDesugaring {
+
+  private final AppView<?> appView;
+  private final DesugaredLibraryDisableDesugarerHelper helper;
+
+  public DesugaredLibraryDisableDesugarer(AppView<?> appView) {
+    this.appView = appView;
+    this.helper = new DesugaredLibraryDisableDesugarerHelper(appView);
+  }
+
+  public static DesugaredLibraryDisableDesugarer create(AppView<?> appView) {
+    return DesugaredLibraryDisableDesugarerHelper.shouldCreate(appView)
+        ? new DesugaredLibraryDisableDesugarer(appView)
+        : null;
+  }
+
+  @Override
+  public Collection<CfInstruction> desugarInstruction(
+      CfInstruction instruction,
+      FreshLocalProvider freshLocalProvider,
+      LocalStackAllocator localStackAllocator,
+      CfInstructionDesugaringEventConsumer eventConsumer,
+      ProgramMethod context,
+      MethodProcessingContext methodProcessingContext,
+      CfInstructionDesugaringCollection desugaringCollection,
+      DexItemFactory dexItemFactory) {
+    CfInstruction replacement = rewriteInstruction(instruction, context);
+    return replacement == null ? null : Collections.singleton(replacement);
+  }
+
+  @Override
+  public boolean needsDesugaring(CfInstruction instruction, ProgramMethod context) {
+    return rewriteInstruction(instruction, context) != null;
+  }
+
+  private CfInstruction rewriteInstruction(CfInstruction instruction, ProgramMethod context) {
+    if (!appView.dexItemFactory().multiDexTypes.contains(context.getHolderType())) {
+      return null;
+    }
+    if (instruction.isTypeInstruction()) {
+      return rewriteTypeInstruction(instruction.asTypeInstruction());
+    }
+    if (instruction.isFieldInstruction()) {
+      return rewriteFieldInstruction(instruction.asFieldInstruction(), context);
+    }
+    if (instruction.isInvoke()) {
+      return rewriteInvokeInstruction(instruction.asInvoke(), context);
+    }
+    return null;
+  }
+
+  private CfInstruction rewriteInvokeInstruction(CfInvoke invoke, ProgramMethod context) {
+    DexMethod rewrittenMethod =
+        helper.rewriteMethod(invoke.getMethod(), invoke.isInterface(), context);
+    return rewrittenMethod != null
+        ? new CfInvoke(invoke.getOpcode(), rewrittenMethod, invoke.isInterface())
+        : null;
+  }
+
+  private CfFieldInstruction rewriteFieldInstruction(
+      CfFieldInstruction fieldInstruction, ProgramMethod context) {
+    DexField rewrittenField = helper.rewriteField(fieldInstruction.getField(), context);
+    return rewrittenField != null ? fieldInstruction.createWithField(rewrittenField) : null;
+  }
+
+  private CfInstruction rewriteTypeInstruction(CfTypeInstruction typeInstruction) {
+    DexType rewrittenType = helper.rewriteType(typeInstruction.getType());
+    return rewrittenType != typeInstruction.getType()
+        ? typeInstruction.withType(rewrittenType)
+        : null;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/disabledesugarer/DesugaredLibraryDisableDesugarerHelper.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/disabledesugarer/DesugaredLibraryDisableDesugarerHelper.java
new file mode 100644
index 0000000..f4526ae
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/disabledesugarer/DesugaredLibraryDisableDesugarerHelper.java
@@ -0,0 +1,118 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.desugar.desugaredlibrary.disabledesugarer;
+
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter.methodWithVivifiedTypeInSignature;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter.vivifiedTypeFor;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMember;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.FieldResolutionResult;
+import com.android.tools.r8.graph.MemberResolutionResult;
+import com.android.tools.r8.graph.MethodResolutionResult;
+import com.android.tools.r8.graph.ProgramDefinition;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.SuccessfulMemberResolutionResult;
+
+public class DesugaredLibraryDisableDesugarerHelper {
+
+  private final AppView<?> appView;
+
+  public DesugaredLibraryDisableDesugarerHelper(AppView<?> appView) {
+    this.appView = appView;
+  }
+
+  static boolean shouldCreate(AppView<?> appView) {
+    for (DexType multiDexType : appView.dexItemFactory().multiDexTypes) {
+      if (appView.appInfo().definitionForWithoutExistenceAssert(multiDexType) != null) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  DexMethod rewriteMethod(DexMethod method, boolean isInterface, ProgramMethod context) {
+    DexType newHolder = rewriteType(method.getHolderType());
+    DexMethod rewrittenMethod = methodWithVivifiedTypeInSignature(method, newHolder, appView);
+    if (rewrittenMethod == method) {
+      return null;
+    }
+    MethodResolutionResult methodResolutionResult =
+        appView.appInfoForDesugaring().resolveMethodLegacy(method, isInterface);
+    warnIfInvalidResolution(methodResolutionResult, method, context);
+    return rewrittenMethod;
+  }
+
+  DexField rewriteField(DexField field, ProgramDefinition context) {
+    if (isRewrittenType(field.getHolderType())) {
+      // This case never happens within the supported set of classes. We can support it if required.
+      appView
+          .options()
+          .reporter
+          .error("Cannot prevent the desugaring of " + field + " in " + context);
+      return null;
+    }
+    DexType rewrittenFieldType = rewriteType(field.getType());
+    if (rewrittenFieldType == field.getType()) {
+      return null;
+    }
+    FieldResolutionResult fieldResolutionResult =
+        appView.appInfoForDesugaring().resolveField(field);
+    warnIfInvalidResolution(fieldResolutionResult, field, context);
+    return field.withType(rewrittenFieldType, appView.dexItemFactory());
+  }
+
+  /**
+   * All rewritings should apply within private members of multidex types or with library accesses,
+   * else we are leaving escapes of non rewritten types in the program which will lead to runtime
+   * errors. Note that this is conservative and we could allow more escapes if required.
+   */
+  private boolean isValidResolution(MemberResolutionResult<?, ?> resolutionResult) {
+    if (resolutionResult == null || !resolutionResult.isSuccessfulMemberResolutionResult()) {
+      return false;
+    }
+    SuccessfulMemberResolutionResult<?, ?> successfulResult =
+        resolutionResult.asSuccessfulMemberResolutionResult();
+    if (successfulResult.getResolvedHolder().isLibraryClass()) {
+      return true;
+    }
+    return appView
+            .dexItemFactory()
+            .multiDexTypes
+            .contains(successfulResult.getResolvedHolder().getType())
+        && successfulResult.getResolvedMember().isPrivate();
+  }
+
+  private void warnIfInvalidResolution(
+      MemberResolutionResult<?, ?> resolutionResult,
+      DexMember<?, ?> member,
+      ProgramDefinition context) {
+    if (isValidResolution(resolutionResult)) {
+      return;
+    }
+    appView
+        .reporter()
+        .warning(
+            "Preventing the desugaring of "
+                + member
+                + " in "
+                + context
+                + " which could be an invalid escape into the program. ");
+  }
+
+  DexType rewriteType(DexType type) {
+    if (isRewrittenType(type)) {
+      return vivifiedTypeFor(type, appView);
+    }
+    return type;
+  }
+
+  boolean isRewrittenType(DexType type) {
+    return appView.typeRewriter.hasRewrittenType(type, appView);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/disabledesugarer/DesugaredLibraryDisableDesugarerPostProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/disabledesugarer/DesugaredLibraryDisableDesugarerPostProcessor.java
new file mode 100644
index 0000000..2e26d1e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/disabledesugarer/DesugaredLibraryDisableDesugarerPostProcessor.java
@@ -0,0 +1,69 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.desugar.desugaredlibrary.disabledesugarer;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedField;
+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.ir.desugar.CfPostProcessingDesugaring;
+import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+
+public class DesugaredLibraryDisableDesugarerPostProcessor implements CfPostProcessingDesugaring {
+
+  private final AppView<?> appView;
+  private final DesugaredLibraryDisableDesugarerHelper helper;
+
+  public DesugaredLibraryDisableDesugarerPostProcessor(AppView<?> appView) {
+    this.appView = appView;
+    this.helper = new DesugaredLibraryDisableDesugarerHelper(appView);
+  }
+
+  public static DesugaredLibraryDisableDesugarerPostProcessor create(AppView<?> appView) {
+    return DesugaredLibraryDisableDesugarerHelper.shouldCreate(appView)
+        ? new DesugaredLibraryDisableDesugarerPostProcessor(appView)
+        : null;
+  }
+
+  @Override
+  public void postProcessingDesugaring(
+      Collection<DexProgramClass> programClasses,
+      CfPostProcessingDesugaringEventConsumer eventConsumer,
+      ExecutorService executorService)
+      throws ExecutionException {
+    for (DexType multiDexType : appView.dexItemFactory().multiDexTypes) {
+      DexClass clazz =
+          appView.appInfoForDesugaring().definitionForWithoutExistenceAssert(multiDexType);
+      if (clazz != null && clazz.isProgramClass()) {
+        rewriteMultiDexProgramClass(clazz.asProgramClass());
+      }
+    }
+  }
+
+  private void rewriteMultiDexProgramClass(DexProgramClass multiDexProgramClass) {
+    multiDexProgramClass.setInstanceFields(
+        rewriteFields(multiDexProgramClass.instanceFields(), multiDexProgramClass));
+    multiDexProgramClass.setStaticFields(
+        rewriteFields(multiDexProgramClass.staticFields(), multiDexProgramClass));
+  }
+
+  private DexEncodedField[] rewriteFields(
+      List<DexEncodedField> fields, DexProgramClass multiDexProgramClass) {
+    List<DexEncodedField> newFields = new ArrayList<>();
+    for (DexEncodedField field : fields) {
+      DexField rewrittenField = helper.rewriteField(field.getReference(), multiDexProgramClass);
+      newFields.add(
+          rewrittenField != null ? field.toTypeSubstitutedField(appView, rewrittenField) : field);
+    }
+    return newFields.toArray(DexEncodedField[]::new);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationJsonExporter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationJsonExporter.java
index d77a0bc..736632a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationJsonExporter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationJsonExporter.java
@@ -6,6 +6,7 @@
 
 import static com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser.CONFIGURATION_FORMAT_VERSION_KEY;
 import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.AMEND_LIBRARY_METHOD_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.API_GENERIC_TYPES_CONVERSION;
 import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.API_LEVEL_BELOW_OR_EQUAL_KEY;
 import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.API_LEVEL_GREATER_OR_EQUAL_KEY;
 import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.BACKPORT_KEY;
@@ -14,13 +15,17 @@
 import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.CUSTOM_CONVERSION_KEY;
 import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.DONT_RETARGET_KEY;
 import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.DONT_REWRITE_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.DONT_REWRITE_PREFIX_KEY;
 import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.EMULATE_INTERFACE_KEY;
 import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.IDENTIFIER_KEY;
 import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.LIBRARY_FLAGS_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.MAINTAIN_PREFIX_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.NEVER_OUTLINE_API_KEY;
 import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.PROGRAM_FLAGS_KEY;
 import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.REQUIRED_COMPILATION_API_LEVEL_KEY;
 import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.RETARGET_METHOD_EMULATED_DISPATCH_KEY;
 import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.RETARGET_METHOD_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.RETARGET_STATIC_FIELD_KEY;
 import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.REWRITE_DERIVED_PREFIX_KEY;
 import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.REWRITE_PREFIX_KEY;
 import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.SHRINKER_CONFIG_KEY;
@@ -32,13 +37,15 @@
 import com.android.tools.r8.DiagnosticsHandler;
 import com.android.tools.r8.StringConsumer;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AccessFlags;
+import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexItem;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.ApiLevelRange;
 import com.google.gson.Gson;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -102,12 +109,21 @@
             .forEach((k, v) -> rewriteDerivedPrefix.put(k, new TreeMap<>(v)));
         toJson.put(REWRITE_DERIVED_PREFIX_KEY, rewriteDerivedPrefix);
       }
+      if (!flags.getDontRewritePrefix().isEmpty()) {
+        toJson.put(DONT_REWRITE_PREFIX_KEY, stringSetToString(flags.getDontRewritePrefix()));
+      }
+      if (!flags.getMaintainPrefix().isEmpty()) {
+        toJson.put(MAINTAIN_PREFIX_KEY, stringSetToString(flags.getMaintainPrefix()));
+      }
       if (!flags.getEmulatedInterfaces().isEmpty()) {
         toJson.put(EMULATE_INTERFACE_KEY, mapToString(flags.getEmulatedInterfaces()));
       }
       if (!flags.getDontRewriteInvocation().isEmpty()) {
         toJson.put(DONT_REWRITE_KEY, setToString(flags.getDontRewriteInvocation()));
       }
+      if (!flags.getRetargetStaticField().isEmpty()) {
+        toJson.put(RETARGET_STATIC_FIELD_KEY, mapToString(flags.getRetargetStaticField()));
+      }
       if (!flags.getRetargetMethod().isEmpty()) {
         toJson.put(RETARGET_METHOD_KEY, mapToString(flags.getRetargetMethod()));
       }
@@ -122,15 +138,24 @@
       if (!flags.getLegacyBackport().isEmpty()) {
         toJson.put(BACKPORT_KEY, mapToString(flags.getLegacyBackport()));
       }
+      if (!flags.getApiGenericConversion().isEmpty()) {
+        toJson.put(API_GENERIC_TYPES_CONVERSION, mapArrayToString(flags.getApiGenericConversion()));
+      }
       if (!flags.getWrapperConversions().isEmpty()) {
         registerWrapperConversions(toJson, flags.getWrapperConversions());
       }
       if (!flags.getCustomConversions().isEmpty()) {
         toJson.put(CUSTOM_CONVERSION_KEY, mapToString(flags.getCustomConversions()));
       }
+      if (!flags.getNeverOutlineApi().isEmpty()) {
+        toJson.put(NEVER_OUTLINE_API_KEY, setToString(flags.getNeverOutlineApi()));
+      }
       if (!flags.getAmendLibraryMethod().isEmpty()) {
         toJson.put(AMEND_LIBRARY_METHOD_KEY, amendLibraryToString(flags.getAmendLibraryMethod()));
       }
+      if (!flags.getAmendLibraryField().isEmpty()) {
+        toJson.put(AMEND_LIBRARY_METHOD_KEY, amendLibraryToString(flags.getAmendLibraryField()));
+      }
       list.add(toJson);
     }
     return list;
@@ -148,20 +173,32 @@
             stringMap.put(toString(k), setToString(v));
           }
         });
-    toJson.put(WRAPPER_CONVERSION_KEY, stringSet);
-    toJson.put(WRAPPER_CONVERSION_EXCLUDING_KEY, stringMap);
+    if (!stringSet.isEmpty()) {
+      toJson.put(WRAPPER_CONVERSION_KEY, stringSet);
+    }
+    if (!stringMap.isEmpty()) {
+      toJson.put(WRAPPER_CONVERSION_EXCLUDING_KEY, stringMap);
+    }
   }
 
-  private List<String> amendLibraryToString(Map<DexMethod, MethodAccessFlags> amendLibraryMembers) {
+  private List<String> amendLibraryToString(
+      Map<? extends DexItem, ? extends AccessFlags<?>> amendLibraryMembers) {
     List<String> stringSet = new ArrayList<>();
     amendLibraryMembers.forEach(
         (member, flags) -> stringSet.add(flags.toString() + " " + toString(member)));
     return stringSet;
   }
 
+  private List<String> stringSetToString(Set<String> set) {
+    List<String> stringSet = new ArrayList<>(set);
+    Collections.sort(stringSet);
+    return stringSet;
+  }
+
   private List<String> setToString(Set<? extends DexItem> set) {
     List<String> stringSet = new ArrayList<>();
     set.forEach(e -> stringSet.add(toString(e)));
+    Collections.sort(stringSet);
     return stringSet;
   }
 
@@ -171,10 +208,36 @@
     return stringMap;
   }
 
+  private Map<String, Object[]> mapArrayToString(Map<? extends DexItem, DexMethod[]> map) {
+    Map<String, Object[]> stringMap = new TreeMap<>();
+    map.forEach((k, v) -> stringMap.put(toString(k), arrayToString(v)));
+    return stringMap;
+  }
+
+  private Object[] arrayToString(DexMethod[] array) {
+    List<Object> res = new ArrayList<>();
+    int last = array.length - 1;
+    if (array[last] != null) {
+      res.add(-1);
+      res.add(toString(array[last]));
+    }
+    for (int i = 0; i < array.length - 1; i++) {
+      if (array[i] != null) {
+        res.add(i);
+        res.add(toString(array[i]));
+      }
+    }
+    return res.toArray();
+  }
+
   private String toString(DexItem o) {
     if (o instanceof DexType) {
       return o.toString();
     }
+    if (o instanceof DexField) {
+      DexField field = (DexField) o;
+      return field.getType() + " " + field.getHolderType() + "#" + field.getName();
+    }
     if (o instanceof DexMethod) {
       DexMethod method = (DexMethod) o;
       StringBuilder sb =
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
index 302c08c..11f9c1b 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
@@ -100,8 +100,9 @@
     assert invokeRetargetingResult.hasNewInvokeTarget();
     DexMethod newInvokeTarget =
         invokeRetargetingResult.getNewInvokeTarget(eventConsumer, methodProcessingContext);
-    return Collections.singletonList(
-        new CfInvoke(Opcodes.INVOKESTATIC, newInvokeTarget, invoke.isInterface()));
+    assert appView.definitionFor(newInvokeTarget.getHolderType()) != null;
+    assert !appView.definitionFor(newInvokeTarget.getHolderType()).isInterface();
+    return Collections.singletonList(new CfInvoke(Opcodes.INVOKESTATIC, newInvokeTarget, false));
   }
 
   @Override
@@ -175,11 +176,7 @@
 
   private InvokeRetargetingResult computeNewInvokeTarget(
       CfInvoke instruction, ProgramMethod context) {
-    if (appView
-        .options()
-        .machineDesugaredLibrarySpecification
-        .getDontRetarget()
-        .contains(context.getContextType())) {
+    if (appView.dexItemFactory().multiDexTypes.contains(context.getContextType())) {
       return NO_REWRITING;
     }
     CfInvoke cfInvoke = instruction.asInvoke();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java
index bfbf6a8..53b8207 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java
@@ -125,11 +125,7 @@
         // The class has already been desugared.
         continue;
       }
-      if (appView
-          .options()
-          .machineDesugaredLibrarySpecification
-          .getDontRetarget()
-          .contains(clazz.getType())) {
+      if (appView.dexItemFactory().multiDexTypes.contains(clazz.getType())) {
         continue;
       }
       clazz.addExtraInterfaces(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/DesugaredLibraryConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/DesugaredLibraryConverter.java
index 34a8e9d..02a5e5a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/DesugaredLibraryConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/DesugaredLibraryConverter.java
@@ -46,14 +46,18 @@
         jsonFile,
         ImmutableSet.of(desugaredLibraryJar, customConversionsJar),
         ImmutableSet.of(androidJar),
-        output);
+        output,
+        new InternalOptions());
   }
 
-  public static void convertMultiLevelAnythingToMachineSpecification(
-      Path jsonSpec, Set<Path> desugaredLibraryFiles, Set<Path> libraryFiles, Path output)
-      throws IOException {
-
-    InternalOptions options = new InternalOptions();
+  public static MultiAPILevelHumanDesugaredLibrarySpecification
+      convertMultiLevelAnythingToMachineSpecification(
+          Path jsonSpec,
+          Set<Path> desugaredLibraryFiles,
+          Set<Path> libraryFiles,
+          Path output,
+          InternalOptions options)
+          throws IOException {
 
     FileResource jsonResource = StringResource.fromFile(jsonSpec);
     JsonObject jsonConfig = parseJsonConfig(options, jsonResource);
@@ -61,7 +65,7 @@
     if (isMachineSpecification(jsonConfig, options.reporter, jsonResource.getOrigin())) {
       // Nothing to convert;
       Files.copy(jsonSpec, output);
-      return;
+      return null;
     }
 
     DexApplication appForConversion =
@@ -71,6 +75,8 @@
     String outputString = convertToMachineSpecification(options, appForConversion, humanSpec);
 
     Files.write(output, Collections.singleton(outputString));
+
+    return humanSpec;
   }
 
   private static String convertToMachineSpecification(
@@ -126,7 +132,7 @@
         .parseMultiLevelConfiguration(jsonResource);
   }
 
-  public static DexApplication getAppForConversion(
+  private static DexApplication getAppForConversion(
       InternalOptions options, Set<Path> androidJar, Set<Path> desugaredlibJar) throws IOException {
     AndroidApp.Builder builder = AndroidApp.builder();
     builder.addProgramFiles(desugaredlibJar);
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java b/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
index 0f09fdf..2f5c0f9 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
@@ -253,12 +253,8 @@
       return partitionedMappings;
     }
 
-    public MemberNaming getMemberNaming(
-        ClassNamingForNameMapper classNamingForNameMapper, boolean hasMultipleResults) {
+    public MemberNaming getMemberNaming(ClassNamingForNameMapper classNamingForNameMapper) {
       MappedRange lastMappedRange = ListUtils.last(mappedRanges);
-      if (hasMultipleResults) {
-        return null;
-      }
       MethodSignature signature = lastMappedRange.getResidualSignature();
       MemberNaming memberNaming = classNamingForNameMapper.methodMembers.get(signature);
       assert memberNaming != null;
diff --git a/src/main/java/com/android/tools/r8/naming/ComposingBuilder.java b/src/main/java/com/android/tools/r8/naming/ComposingBuilder.java
index cc7f927..b6ea11b 100644
--- a/src/main/java/com/android/tools/r8/naming/ComposingBuilder.java
+++ b/src/main/java/com/android/tools/r8/naming/ComposingBuilder.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.naming;
 
-import static com.android.tools.r8.naming.MappedRangeUtils.addAllInlineFramesUntilOutermostCaller;
 import static com.android.tools.r8.naming.MappedRangeUtils.isInlineMappedRange;
 import static com.android.tools.r8.utils.FunctionUtils.ignoreArgument;
 
@@ -486,16 +485,23 @@
       Map<String, String> inverseClassMapping =
           classNameMapper.getObfuscatedToOriginalMapping().inverse;
       for (Entry<String, MappedRangesOfName> entry : mapper.mappedRangesByRenamedName.entrySet()) {
-        MappedRangesOfName value = entry.getValue();
-        List<MappedRange> mappedRanges = value.getMappedRanges();
-        MappedRangeResult mappedRangeResult;
-        int index = 0;
-        while ((mappedRangeResult = getMappedRangesForMethod(mappedRanges, index)) != null) {
-          index = mappedRangeResult.endIndex;
-          MappedRange newMappedRange = mappedRangeResult.lastRange;
-          MethodSignature originalSignature = newMappedRange.signature;
-          List<MappedRange> existingMappedRanges = null;
+        MappedRangesOfName mappedRangesOfName = entry.getValue();
+        for (MappedRangesOfName rangesOfName : mappedRangesOfName.partitionOnMethodSignature()) {
+          MemberNaming memberNaming = rangesOfName.getMemberNaming(mapper);
+          List<MappedRange> newMappedRanges = rangesOfName.getMappedRanges();
+          RangeBuilder minified = new RangeBuilder();
+          RangeBuilder original = new RangeBuilder();
+          for (MappedRange mappedRange : newMappedRanges) {
+            minified.addRange(mappedRange.minifiedRange);
+            original.addRange(mappedRange.originalRange);
+            // Register mapping information that is dependent on the residual naming to allow
+            // updating later on.
+            registerMappingInformationFromMappedRanges(mappedRange);
+          }
+          MethodSignature originalSignature =
+              memberNaming.getOriginalSignature().asMethodSignature();
           // Remove the existing entry if it exists.
+          List<MappedRange> existingMappedRanges = null;
           if (committedPreviousClassBuilder != null) {
             SegmentTree<List<MappedRange>> listSegmentTree =
                 committedPreviousClassBuilder.methodsWithPosition.get(originalSignature);
@@ -505,33 +511,29 @@
               // emits `1:1:void foo() -> a` instead of `1:1:void foo():1:1 -> a`, so R8 must
               // capture the preamble position by explicitly inserting 0 as original range.
               Entry<Integer, List<MappedRange>> existingEntry =
-                  listSegmentTree.findEntry(mappedRangeResult.startOriginalPosition);
+                  listSegmentTree.findEntry(original.getStartOrNoRangeFrom());
               // We assume that all new minified ranges for a method are rewritten in the new map
               // such that no previous existing positions exists.
               if (existingEntry != null) {
                 listSegmentTree.removeSegment(existingEntry.getKey());
                 existingMappedRanges = existingEntry.getValue();
               } else {
-                Range originalRange = newMappedRange.originalRange;
                 // The original can be discarded if it no longer exists or if the method is
                 // non-throwing.
-                if (mappedRangeResult.startOriginalPosition > 0
-                    && (originalRange == null || !newMappedRange.originalRange.isPreamble())
+                if (original.hasValue()
+                    && !original.isPreamble()
                     && !options.mappingComposeOptions().allowNonExistingOriginalRanges) {
                   throw new MappingComposeException(
                       "Could not find original starting position of '"
-                          + mappedRangeResult.lastRange
+                          + minified.start
                           + "' which should be "
-                          + mappedRangeResult.startOriginalPosition);
+                          + original.start);
                 }
               }
-              assert newMappedRange.minifiedRange != null;
+              assert minified.hasValue();
             } else {
               MappedRange existingMappedRange =
-                  committedPreviousClassBuilder.methodsWithoutPosition.get(originalSignature);
-              if (existingMappedRange != null) {
-                committedPreviousClassBuilder.methodsWithoutPosition.remove(originalSignature);
-              }
+                  committedPreviousClassBuilder.methodsWithoutPosition.remove(originalSignature);
               existingMappedRanges =
                   existingMappedRange == null
                       ? null
@@ -539,18 +541,18 @@
             }
           }
           List<MappedRange> composedRanges =
-              composeMappedRangesForMethod(existingMappedRanges, mappedRangeResult.allRanges);
+              composeMappedRangesForMethod(existingMappedRanges, newMappedRanges);
           MappedRange lastComposedRange = ListUtils.last(composedRanges);
           MethodSignature residualSignature =
-              newMappedRange
+              memberNaming
                   .computeResidualSignature(type -> inverseClassMapping.getOrDefault(type, type))
                   .asMethodSignature();
           if (lastComposedRange.minifiedRange != null) {
             methodsWithPosition
                 .computeIfAbsent(residualSignature, ignored -> new SegmentTree<>(false))
                 .add(
-                    mappedRangeResult.startMinifiedPosition,
-                    newMappedRange.minifiedRange.to,
+                    minified.getStartOrNoRangeFrom(),
+                    minified.getEndOrNoRangeFrom(),
                     composedRanges);
           } else {
             assert composedRanges.size() == 1;
@@ -560,78 +562,32 @@
       }
     }
 
-    /***
-     * Iterates over mapped ranges in order, starting from index, and adds to an internal result as
-     * long as the current mapped range is the same method and return a mapped range result
-     * containing all ranges for a method along with some additional information.
-     */
-    private MappedRangeResult getMappedRangesForMethod(List<MappedRange> mappedRanges, int index)
+    private void registerMappingInformationFromMappedRanges(MappedRange mappedRange)
         throws MappingComposeException {
-      if (index >= mappedRanges.size()) {
-        return null;
-      }
-      int startIndex = index;
-      List<MappedRange> seenMappedRanges = new ArrayList<>();
-      int startMinifiedPosition = NO_RANGE_FROM;
-      int startOriginalPosition = NO_RANGE_FROM;
-      MappedRange lastOutermost = null;
-      while (index < mappedRanges.size()) {
-        List<MappedRange> mappedRangesForThisInterval = new ArrayList<>();
-        index =
-            addAllInlineFramesUntilOutermostCaller(
-                mappedRanges, index, mappedRangesForThisInterval);
-        assert mappedRangesForThisInterval.size() > 0;
-        MappedRange lastForThisInterval = ListUtils.last(mappedRangesForThisInterval);
-        if (lastOutermost == null) {
-          startMinifiedPosition =
-              lastForThisInterval.minifiedRange != null
-                  ? lastForThisInterval.minifiedRange.from
-                  : NO_RANGE_FROM;
-          startOriginalPosition =
-              lastForThisInterval.getFirstPositionOfOriginalRange(NO_RANGE_FROM);
-        }
-        if (lastOutermost != null
-            && !lastForThisInterval.signature.equals(lastOutermost.signature)) {
-          break;
-        }
-        // Register mapping information that is dependent on the residual naming to allow updating
-        // later on.
-        for (MappedRange mappedRange : mappedRangesForThisInterval) {
-          for (MappingInformation mappingInformation :
-              mappedRange.getAdditionalMappingInformation()) {
-            if (mappingInformation.isRewriteFrameMappingInformation()) {
-              RewriteFrameMappingInformation rewriteFrameMappingInformation =
-                  mappingInformation.asRewriteFrameMappingInformation();
-              rewriteFrameMappingInformation
-                  .getConditions()
-                  .forEach(
-                      condition -> {
-                        if (condition.isThrowsCondition()) {
-                          current.rewriteFrameInformation.add(rewriteFrameMappingInformation);
-                        }
-                      });
-            } else if (mappingInformation.isOutlineCallsiteInformation()) {
-              OutlineCallsiteMappingInformation outlineCallsiteInfo =
-                  mappingInformation.asOutlineCallsiteInformation();
-              MethodReference outline = outlineCallsiteInfo.getOutline();
-              if (outline == null) {
-                throw new MappingComposeException(
-                    "Unable to compose outline call site information without outline key: "
-                        + outlineCallsiteInfo.serialize());
-              }
-              current.addNewOutlineCallsiteInformation(outline, outlineCallsiteInfo);
-            }
+      for (MappingInformation mappingInformation : mappedRange.getAdditionalMappingInformation()) {
+        if (mappingInformation.isRewriteFrameMappingInformation()) {
+          RewriteFrameMappingInformation rewriteFrameMappingInformation =
+              mappingInformation.asRewriteFrameMappingInformation();
+          rewriteFrameMappingInformation
+              .getConditions()
+              .forEach(
+                  condition -> {
+                    if (condition.isThrowsCondition()) {
+                      current.rewriteFrameInformation.add(rewriteFrameMappingInformation);
+                    }
+                  });
+        } else if (mappingInformation.isOutlineCallsiteInformation()) {
+          OutlineCallsiteMappingInformation outlineCallsiteInfo =
+              mappingInformation.asOutlineCallsiteInformation();
+          MethodReference outline = outlineCallsiteInfo.getOutline();
+          if (outline == null) {
+            throw new MappingComposeException(
+                "Unable to compose outline call site information without outline key: "
+                    + outlineCallsiteInfo.serialize());
           }
-          seenMappedRanges.add(mappedRange);
+          current.addNewOutlineCallsiteInformation(outline, outlineCallsiteInfo);
         }
-        lastOutermost = lastForThisInterval;
       }
-      return new MappedRangeResult(
-          startMinifiedPosition,
-          startOriginalPosition,
-          startIndex + seenMappedRanges.size(),
-          lastOutermost,
-          seenMappedRanges);
     }
 
     private List<MappedRange> composeMappedRangesForMethod(
@@ -1090,25 +1046,32 @@
       }
     }
 
-    private static class MappedRangeResult {
+    private static class RangeBuilder {
 
-      private final int startMinifiedPosition;
-      private final int startOriginalPosition;
-      private final int endIndex;
-      private final MappedRange lastRange;
-      private final List<MappedRange> allRanges;
+      private int start = Integer.MAX_VALUE;
+      private int end = Integer.MIN_VALUE;
 
-      public MappedRangeResult(
-          int startMinifiedPosition,
-          int startOriginalPosition,
-          int endIndex,
-          MappedRange lastRange,
-          List<MappedRange> allRanges) {
-        this.startMinifiedPosition = startMinifiedPosition;
-        this.startOriginalPosition = startOriginalPosition;
-        this.endIndex = endIndex;
-        this.lastRange = lastRange;
-        this.allRanges = allRanges;
+      private void addRange(Range range) {
+        if (range != null) {
+          start = Math.min(start, range.from);
+          end = Math.max(end, range.to);
+        }
+      }
+
+      private boolean hasValue() {
+        return start < Integer.MAX_VALUE;
+      }
+
+      private int getStartOrNoRangeFrom() {
+        return hasValue() ? start : NO_RANGE_FROM;
+      }
+
+      private int getEndOrNoRangeFrom() {
+        return hasValue() ? end : NO_RANGE_FROM;
+      }
+
+      private boolean isPreamble() {
+        return hasValue() && start == end && start == 0;
       }
     }
 
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java b/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java
index cd8bd3f..eba6b53 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java
@@ -444,6 +444,8 @@
 
       if (signature.isMethodSignature()) {
         MethodSignature residualSignature = null;
+        // Propagate the active residual signature down to the next read mapped range if the
+        // original signature and name is the same - that is, there are no inline frames.
         if (activeMappedRange != null
             && activeMappedRange.signature == signature
             && activeMappedRange.renamedName.equals(renamedName)) {
@@ -452,8 +454,18 @@
         activeMappedRange =
             classNamingBuilder.addMappedRange(
                 mappedRange, signature.asMethodSignature(), originalRange, renamedName);
-        if (residualSignature != null) {
-          activeMappedRange.setResidualSignatureInternal(residualSignature);
+        if (activeMappedRange != null) {
+          if (residualSignature != null) {
+            activeMappedRange.setResidualSignatureInternal(residualSignature);
+          } else if (lastAddedNaming != null
+              && lastAddedNaming
+                  .getOriginalSignature()
+                  .equals(activeMappedRange.getOriginalSignature())) {
+            // If we already parsed a residual signature for the newly read mapped range and have
+            // lost the information about the residual signature we re-create it again.
+            activeMappedRange.setResidualSignatureInternal(
+                lastAddedNaming.getResidualSignature().asMethodSignature());
+          }
         }
       }
 
diff --git a/src/main/java/com/android/tools/r8/repackaging/Repackaging.java b/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
index f292409..3bebc24 100644
--- a/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
+++ b/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
@@ -245,9 +245,9 @@
         continue;
       }
       // Already processed packages should have been removed.
+      assert !repackagingConfiguration.isPackageInTargetLocation(pkg);
       String newPackageDescriptor =
           repackagingConfiguration.getNewPackageDescriptor(pkg, seenPackageDescriptors);
-      assert !repackagingConfiguration.isPackageInTargetLocation(pkg);
       for (DexProgramClass classToRepackage : classesToRepackage) {
         processClass(classToRepackage, pkg, newPackageDescriptor, mappings);
       }
@@ -351,7 +351,6 @@
         // Preserve full package name under destination package when not minifying
         // (no matter which package obfuscation mode is used).
         if (newPackageDescriptor.isEmpty()
-            || proguardConfiguration.getKeepPackageNamesPatterns().matches(pkg)
             || mayHavePinnedPackagePrivateOrProtectedItem(pkg)) {
           return pkg.getPackageDescriptor();
         }
@@ -360,8 +359,7 @@
         return newPackageDescriptor;
       } else if (packageObfuscationMode.isMinification()) {
         // Always keep top-level classes since their packages can never be minified.
-        if (pkg.getPackageDescriptor().equals("")
-            || proguardConfiguration.getKeepPackageNamesPatterns().matches(pkg)
+        if (pkg.getPackageDescriptor().isEmpty()
             || mayHavePinnedPackagePrivateOrProtectedItem(pkg)) {
           return pkg.getPackageDescriptor();
         }
@@ -386,9 +384,8 @@
       if (packageObfuscationMode.isRepackageClasses()) {
         return pkg.getPackageDescriptor().equals(newPackageDescriptor);
       } else if (packageObfuscationMode.isMinification()) {
-        // Always keep top-level classes since there packages can never be minified.
-        return pkg.getPackageDescriptor().equals("")
-            || proguardConfiguration.getKeepPackageNamesPatterns().matches(pkg)
+        // Always keep top-level classes since their packages can never be minified.
+        return pkg.getPackageDescriptor().isEmpty()
             || mayHavePinnedPackagePrivateOrProtectedItem(pkg);
       } else {
         assert packageObfuscationMode.isFlattenPackageHierarchy();
@@ -440,7 +437,7 @@
                   + simpleName.substring(outerClassSimpleName.length());
           repackagedDexType = repackagedDexType.withSimpleName(newSimpleName, dexItemFactory);
         } else {
-          assert false
+          assert options.disableInnerClassSeparatorValidationWhenRepackaging
               : "Unexpected name for inner class: "
                   + clazz.getType().toSourceString()
                   + " (outer class: "
diff --git a/src/main/java/com/android/tools/r8/repackaging/RepackagingUtils.java b/src/main/java/com/android/tools/r8/repackaging/RepackagingUtils.java
new file mode 100644
index 0000000..d8e571d
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/repackaging/RepackagingUtils.java
@@ -0,0 +1,30 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.repackaging;
+
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.shaking.ProguardClassFilter;
+import com.android.tools.r8.utils.InternalOptions;
+
+public class RepackagingUtils {
+
+  public static boolean isPackageNameKept(DexProgramClass clazz, InternalOptions options) {
+    String packageDescriptor = clazz.getType().getPackageDescriptor();
+    if (packageDescriptor.isEmpty()) {
+      return true;
+    }
+    ProguardClassFilter keepPackageNamesPatterns =
+        options.getProguardConfiguration().getKeepPackageNamesPatterns();
+    if (keepPackageNamesPatterns.isEmpty()) {
+      return false;
+    }
+    if (keepPackageNamesPatterns.matches(
+        options.dexItemFactory().createType("L" + packageDescriptor + ";"))) {
+      return true;
+    }
+    return !options.isForceProguardCompatibilityEnabled()
+        && keepPackageNamesPatterns.matches(clazz.getType());
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java
index 45ad91a..dc90e36 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java
@@ -131,12 +131,11 @@
                       .getResidualSignature()
                       .equals(methodSignature));
     }
-    boolean isAmbiguous = partitions.size() > 1;
     return ListUtils.map(
         partitions,
         mappedRangesOfName ->
             new MemberNamingWithMappedRangesOfName(
-                mappedRangesOfName.getMemberNaming(mapper, isAmbiguous), mappedRangesOfName));
+                mappedRangesOfName.getMemberNaming(mapper), mappedRangesOfName));
   }
 
   private static <T, D extends Definition> void lookupElement(
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceFrameResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceFrameResultImpl.java
index caefaad..b48e8c2 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetraceFrameResultImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceFrameResultImpl.java
@@ -8,6 +8,7 @@
 
 import com.android.tools.r8.DiagnosticsHandler;
 import com.android.tools.r8.naming.ClassNamingForNameMapper.MappedRange;
+import com.android.tools.r8.naming.MemberNaming;
 import com.android.tools.r8.naming.Range;
 import com.android.tools.r8.references.MethodReference;
 import com.android.tools.r8.retrace.RetraceFrameElement;
@@ -26,6 +27,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Optional;
 import java.util.OptionalInt;
 import java.util.function.Consumer;
 import java.util.stream.Stream;
@@ -98,6 +100,7 @@
                             methodDefinition.substituteHolder(
                                 classElement.getRetracedClass().getClassReference())),
                         ImmutableList.of(),
+                        Optional.empty(),
                         mappedRangeData.getPosition(),
                         retracer));
               }
@@ -116,6 +119,7 @@
                     // This is a new frame
                     separateAmbiguousOriginalPositions(
                         classElement,
+                        Optional.ofNullable(memberNamingWithMappedRangesOfName.getMemberNaming()),
                         mappedRangesForElement,
                         ambiguousFrames,
                         mappedRangeData.getPosition());
@@ -126,6 +130,7 @@
                 }
                 separateAmbiguousOriginalPositions(
                     classElement,
+                    Optional.ofNullable(memberNamingWithMappedRangesOfName.getMemberNaming()),
                     mappedRangesForElement,
                     ambiguousFrames,
                     mappedRangeData.getPosition());
@@ -136,6 +141,7 @@
 
   private void separateAmbiguousOriginalPositions(
       RetraceClassElementImpl classElement,
+      Optional<MemberNaming> memberNaming,
       List<MappedRange> frames,
       List<ElementImpl> allAmbiguousElements,
       OptionalInt obfuscatedPosition) {
@@ -145,6 +151,7 @@
       allAmbiguousElements.add(
           elementFromMappedRanges(
               ListUtils.map(frames, MappedRangeForFrame::create),
+              memberNaming,
               classElement,
               obfuscatedPosition));
       return;
@@ -172,11 +179,13 @@
     newFrames.forEach(
         ambiguousFrames ->
             allAmbiguousElements.add(
-                elementFromMappedRanges(ambiguousFrames, classElement, obfuscatedPosition)));
+                elementFromMappedRanges(
+                    ambiguousFrames, memberNaming, classElement, obfuscatedPosition)));
   }
 
   private ElementImpl elementFromMappedRanges(
       List<MappedRangeForFrame> mappedRangesForElement,
+      Optional<MemberNaming> memberNaming,
       RetraceClassElementImpl classElement,
       OptionalInt obfuscatedPosition) {
     MappedRangeForFrame topFrame = mappedRangesForElement.get(0);
@@ -188,6 +197,7 @@
         classElement,
         getRetracedMethod(methodReference, topFrame, obfuscatedPosition),
         mappedRangesForElement,
+        memberNaming,
         obfuscatedPosition,
         retracer);
   }
@@ -233,6 +243,7 @@
     private final RetraceFrameResultImpl retraceFrameResult;
     private final RetraceClassElementImpl classElement;
     private final List<MappedRangeForFrame> mappedRanges;
+    private final Optional<MemberNaming> memberNaming;
     private final OptionalInt obfuscatedPosition;
     private final RetracerImpl retracer;
 
@@ -241,17 +252,22 @@
         RetraceClassElementImpl classElement,
         RetracedMethodReferenceImpl methodReference,
         List<MappedRangeForFrame> mappedRanges,
+        Optional<MemberNaming> memberNaming,
         OptionalInt obfuscatedPosition,
         RetracerImpl retracer) {
       this.methodReference = methodReference;
       this.retraceFrameResult = retraceFrameResult;
       this.classElement = classElement;
       this.mappedRanges = mappedRanges;
+      this.memberNaming = memberNaming;
       this.obfuscatedPosition = obfuscatedPosition;
       this.retracer = retracer;
     }
 
     private boolean isOuterMostFrameCompilerSynthesized() {
+      if (memberNaming.isPresent()) {
+        return memberNaming.get().isCompilerSynthesized();
+      }
       if (mappedRanges == null || mappedRanges.isEmpty()) {
         return false;
       }
@@ -381,11 +397,21 @@
       if (mappedRanges == null
           || mappedRanges.isEmpty()
           || !obfuscatedPosition.isPresent()
-          || !ListUtils.last(mappedRanges).getMappedRange().isOutlineFrame()) {
+          || !isOutlineFrame()) {
         return RetraceStackTraceContext.empty();
       }
       return RetraceStackTraceContextImpl.builder().setRewritePosition(obfuscatedPosition).build();
     }
+
+    private boolean isOutlineFrame() {
+      if (memberNaming.isPresent()) {
+        return memberNaming.get().isOutlineFrame();
+      }
+      if (mappedRanges == null || mappedRanges.isEmpty()) {
+        return false;
+      }
+      return ListUtils.last(mappedRanges).getMappedRange().isOutlineFrame();
+    }
   }
 
   private static class MappedRangeForFrame {
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index a8058ac..387186f 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -57,6 +57,7 @@
 import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter;
 import com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringSyntheticHelper;
 import com.android.tools.r8.naming.SeedMapper;
+import com.android.tools.r8.repackaging.RepackagingUtils;
 import com.android.tools.r8.shaking.KeepInfo.Joiner;
 import com.android.tools.r8.synthesis.CommittedItems;
 import com.android.tools.r8.utils.CollectionUtils;
@@ -64,7 +65,6 @@
 import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.PredicateSet;
 import com.android.tools.r8.utils.ThreadUtils;
-import com.android.tools.r8.utils.TraversalContinuation;
 import com.android.tools.r8.utils.Visibility;
 import com.android.tools.r8.utils.WorkList;
 import com.android.tools.r8.utils.collections.ProgramMethodSet;
@@ -1089,22 +1089,14 @@
     if (!options().isRepackagingEnabled()) {
       return false;
     }
-    if (!keepInfo.getInfo(clazz).isRepackagingAllowed(clazz, options())) {
+    if (!keepInfo.getInfo(clazz).isRepackagingAllowed(options())) {
+      return false;
+    }
+    if (RepackagingUtils.isPackageNameKept(clazz, appView.options())) {
       return false;
     }
     SeedMapper applyMappingSeedMapper = appView.getApplyMappingSeedMapper();
-    if (applyMappingSeedMapper != null && applyMappingSeedMapper.hasMapping(clazz.type)) {
-      return false;
-    }
-    return clazz
-        .traverseProgramMembers(
-            member -> {
-              if (keepInfo.getInfo(member).isRepackagingAllowed(member, options())) {
-                return TraversalContinuation.doContinue();
-              }
-              return TraversalContinuation.doBreak();
-            })
-        .shouldContinue();
+    return applyMappingSeedMapper == null || !applyMappingSeedMapper.hasMapping(clazz.type);
   }
 
   public boolean isPinned(DexReference reference) {
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepClassInfo.java b/src/main/java/com/android/tools/r8/shaking/KeepClassInfo.java
index 9785028..f504792 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepClassInfo.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepClassInfo.java
@@ -7,7 +7,6 @@
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.utils.InternalOptions;
 import java.util.function.Function;
 
@@ -15,10 +14,10 @@
 public final class KeepClassInfo extends KeepInfo<KeepClassInfo.Builder, KeepClassInfo> {
 
   // Requires all aspects of a class to be kept.
-  private static final KeepClassInfo TOP = new Builder().makeTop().build();
+  private static final KeepClassInfo TOP = new Builder().makeTop().disallowRepackaging().build();
 
   // Requires no aspects of a class to be kept.
-  private static final KeepClassInfo BOTTOM = new Builder().makeBottom().build();
+  private static final KeepClassInfo BOTTOM = new Builder().makeBottom().allowRepackaging().build();
 
   public static KeepClassInfo top() {
     return TOP;
@@ -32,10 +31,12 @@
     return bottom().joiner();
   }
 
+  private final boolean allowRepackaging;
   private final boolean checkEnumUnboxed;
 
   private KeepClassInfo(Builder builder) {
     super(builder);
+    this.allowRepackaging = builder.isRepackagingAllowed();
     this.checkEnumUnboxed = builder.isCheckEnumUnboxedEnabled();
   }
 
@@ -57,13 +58,18 @@
     return new Joiner(this);
   }
 
-  @Override
-  public boolean isRepackagingAllowed(
-      ProgramDefinition definition, GlobalKeepInfoConfiguration configuration) {
-    return configuration.isRepackagingEnabled()
-        && internalIsRepackagingAllowed()
-        && (definition.getAccessFlags().isPublic()
-            || !internalIsAccessModificationRequiredForRepackaging());
+  /**
+   * True if an item may be repackaged.
+   *
+   * <p>This method requires knowledge of the global configuration as that can override the concrete
+   * value on a given item.
+   */
+  public boolean isRepackagingAllowed(GlobalKeepInfoConfiguration configuration) {
+    return configuration.isRepackagingEnabled() && internalIsRepackagingAllowed();
+  }
+
+  boolean internalIsRepackagingAllowed() {
+    return allowRepackaging;
   }
 
   public boolean isKotlinMetadataRemovalAllowed(
@@ -98,6 +104,7 @@
 
   public static class Builder extends KeepInfo.Builder<Builder, KeepClassInfo> {
 
+    private boolean allowRepackaging;
     private boolean checkEnumUnboxed;
 
     private Builder() {
@@ -106,6 +113,7 @@
 
     private Builder(KeepClassInfo original) {
       super(original);
+      allowRepackaging = original.internalIsRepackagingAllowed();
       checkEnumUnboxed = original.internalIsCheckEnumUnboxedEnabled();
     }
 
@@ -120,6 +128,23 @@
       return self();
     }
 
+    public boolean isRepackagingAllowed() {
+      return allowRepackaging;
+    }
+
+    private Builder setAllowRepackaging(boolean allowRepackaging) {
+      this.allowRepackaging = allowRepackaging;
+      return self();
+    }
+
+    public Builder allowRepackaging() {
+      return setAllowRepackaging(true);
+    }
+
+    public Builder disallowRepackaging() {
+      return setAllowRepackaging(false);
+    }
+
     public Builder setCheckEnumUnboxed() {
       return setCheckEnumUnboxed(true);
     }
@@ -151,6 +176,7 @@
     @Override
     boolean internalIsEqualTo(KeepClassInfo other) {
       return super.internalIsEqualTo(other)
+          && isRepackagingAllowed() == other.internalIsRepackagingAllowed()
           && isCheckEnumUnboxedEnabled() == other.internalIsCheckEnumUnboxedEnabled();
     }
 
@@ -161,12 +187,12 @@
 
     @Override
     public Builder makeTop() {
-      return super.makeTop().unsetCheckEnumUnboxed();
+      return super.makeTop().unsetCheckEnumUnboxed().disallowRepackaging();
     }
 
     @Override
     public Builder makeBottom() {
-      return super.makeBottom().unsetCheckEnumUnboxed();
+      return super.makeBottom().unsetCheckEnumUnboxed().allowRepackaging();
     }
   }
 
@@ -181,6 +207,11 @@
       return self();
     }
 
+    public Joiner disallowRepackaging() {
+      builder.disallowRepackaging();
+      return self();
+    }
+
     @Override
     public Joiner asClassJoiner() {
       return this;
@@ -190,7 +221,8 @@
     public Joiner merge(Joiner joiner) {
       // Should be extended to merge the fields of this class in case any are added.
       return super.merge(joiner)
-          .applyIf(joiner.builder.isCheckEnumUnboxedEnabled(), Joiner::setCheckEnumUnboxed);
+          .applyIf(joiner.builder.isCheckEnumUnboxedEnabled(), Joiner::setCheckEnumUnboxed)
+          .applyIf(!joiner.builder.isRepackagingAllowed(), Joiner::disallowRepackaging);
     }
 
     @Override
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepInfo.java b/src/main/java/com/android/tools/r8/shaking/KeepInfo.java
index d9708ce..092f4ea 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepInfo.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepInfo.java
@@ -6,7 +6,6 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.EnclosingMethodAttribute;
-import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.shaking.KeepInfo.Builder;
 import com.android.tools.r8.shaking.KeepReason.ReflectiveUseFrom;
 import com.android.tools.r8.utils.InternalOptions;
@@ -22,31 +21,25 @@
   private final boolean allowAnnotationRemoval;
   private final boolean allowMinification;
   private final boolean allowOptimization;
-  private final boolean allowRepackaging;
   private final boolean allowShrinking;
   private final boolean allowSignatureRemoval;
   private final boolean checkDiscarded;
-  private final boolean requireAccessModificationForRepackaging;
 
   private KeepInfo(
       boolean allowAccessModification,
       boolean allowAnnotationRemoval,
       boolean allowMinification,
       boolean allowOptimization,
-      boolean allowRepackaging,
       boolean allowShrinking,
       boolean allowSignatureRemoval,
-      boolean checkDiscarded,
-      boolean requireAccessModificationForRepackaging) {
+      boolean checkDiscarded) {
     this.allowAccessModification = allowAccessModification;
     this.allowAnnotationRemoval = allowAnnotationRemoval;
     this.allowMinification = allowMinification;
     this.allowOptimization = allowOptimization;
-    this.allowRepackaging = allowRepackaging;
     this.allowShrinking = allowShrinking;
     this.allowSignatureRemoval = allowSignatureRemoval;
     this.checkDiscarded = checkDiscarded;
-    this.requireAccessModificationForRepackaging = requireAccessModificationForRepackaging;
   }
 
   KeepInfo(B builder) {
@@ -55,11 +48,9 @@
         builder.isAnnotationRemovalAllowed(),
         builder.isMinificationAllowed(),
         builder.isOptimizationAllowed(),
-        builder.isRepackagingAllowed(),
         builder.isShrinkingAllowed(),
         builder.isSignatureRemovalAllowed(),
-        builder.isCheckDiscardedEnabled(),
-        builder.isAccessModificationRequiredForRepackaging());
+        builder.isCheckDiscardedEnabled());
   }
 
   public static Joiner<?, ?, ?> newEmptyJoinerFor(DexReference reference) {
@@ -164,23 +155,6 @@
   }
 
   /**
-   * True if an item may be repackaged.
-   *
-   * <p>This method requires knowledge of the global configuration as that can override the concrete
-   * value on a given item.
-   */
-  public abstract boolean isRepackagingAllowed(
-      ProgramDefinition definition, GlobalKeepInfoConfiguration configuration);
-
-  boolean internalIsRepackagingAllowed() {
-    return allowRepackaging;
-  }
-
-  boolean internalIsAccessModificationRequiredForRepackaging() {
-    return requireAccessModificationForRepackaging;
-  }
-
-  /**
    * True if an item may have its access flags modified.
    *
    * <p>This method requires knowledge of the global access modification as that will override the
@@ -242,7 +216,6 @@
         && (allowAnnotationRemoval || !other.internalIsAnnotationRemovalAllowed())
         && (allowMinification || !other.internalIsMinificationAllowed())
         && (allowOptimization || !other.internalIsOptimizationAllowed())
-        && (allowRepackaging || !other.internalIsRepackagingAllowed())
         && (allowShrinking || !other.internalIsShrinkingAllowed())
         && (allowSignatureRemoval || !other.internalIsSignatureRemovalAllowed())
         && (!checkDiscarded || other.internalIsCheckDiscardedEnabled());
@@ -265,12 +238,10 @@
     private boolean allowAccessModification;
     private boolean allowAnnotationRemoval;
     private boolean allowMinification;
-    private boolean allowRepackaging;
     private boolean allowOptimization;
     private boolean allowShrinking;
     private boolean allowSignatureRemoval;
     private boolean checkDiscarded;
-    private boolean requireAccessModificationForRepackaging;
 
     Builder() {
       // Default initialized. Use should be followed by makeTop/makeBottom.
@@ -282,12 +253,9 @@
       allowAnnotationRemoval = original.internalIsAnnotationRemovalAllowed();
       allowMinification = original.internalIsMinificationAllowed();
       allowOptimization = original.internalIsOptimizationAllowed();
-      allowRepackaging = original.internalIsRepackagingAllowed();
       allowShrinking = original.internalIsShrinkingAllowed();
       allowSignatureRemoval = original.internalIsSignatureRemovalAllowed();
       checkDiscarded = original.internalIsCheckDiscardedEnabled();
-      requireAccessModificationForRepackaging =
-          original.internalIsAccessModificationRequiredForRepackaging();
     }
 
     B makeTop() {
@@ -295,11 +263,9 @@
       disallowAnnotationRemoval();
       disallowMinification();
       disallowOptimization();
-      disallowRepackaging();
       disallowShrinking();
       disallowSignatureRemoval();
       unsetCheckDiscarded();
-      requireAccessModificationForRepackaging();
       return self();
     }
 
@@ -308,11 +274,9 @@
       allowAnnotationRemoval();
       allowMinification();
       allowOptimization();
-      allowRepackaging();
       allowShrinking();
       allowSignatureRemoval();
       unsetCheckDiscarded();
-      unsetRequireAccessModificationForRepackaging();
       return self();
     }
 
@@ -336,16 +300,9 @@
           && isAnnotationRemovalAllowed() == other.internalIsAnnotationRemovalAllowed()
           && isMinificationAllowed() == other.internalIsMinificationAllowed()
           && isOptimizationAllowed() == other.internalIsOptimizationAllowed()
-          && isRepackagingAllowed() == other.internalIsRepackagingAllowed()
           && isShrinkingAllowed() == other.internalIsShrinkingAllowed()
           && isSignatureRemovalAllowed() == other.internalIsSignatureRemovalAllowed()
-          && isCheckDiscardedEnabled() == other.internalIsCheckDiscardedEnabled()
-          && isAccessModificationRequiredForRepackaging()
-              == other.internalIsAccessModificationRequiredForRepackaging();
-    }
-
-    public boolean isAccessModificationRequiredForRepackaging() {
-      return requireAccessModificationForRepackaging;
+          && isCheckDiscardedEnabled() == other.internalIsCheckDiscardedEnabled();
     }
 
     public boolean isAccessModificationAllowed() {
@@ -368,10 +325,6 @@
       return allowOptimization;
     }
 
-    public boolean isRepackagingAllowed() {
-      return allowRepackaging;
-    }
-
     public boolean isShrinkingAllowed() {
       return allowShrinking;
     }
@@ -393,19 +346,6 @@
       return setAllowMinification(false);
     }
 
-    public B setAllowRepackaging(boolean allowRepackaging) {
-      this.allowRepackaging = allowRepackaging;
-      return self();
-    }
-
-    public B allowRepackaging() {
-      return setAllowRepackaging(true);
-    }
-
-    public B disallowRepackaging() {
-      return setAllowRepackaging(false);
-    }
-
     public B setAllowOptimization(boolean allowOptimization) {
       this.allowOptimization = allowOptimization;
       return self();
@@ -445,20 +385,6 @@
       return setCheckDiscarded(false);
     }
 
-    public B setRequireAccessModificationForRepackaging(
-        boolean requireAccessModificationForRepackaging) {
-      this.requireAccessModificationForRepackaging = requireAccessModificationForRepackaging;
-      return self();
-    }
-
-    public B requireAccessModificationForRepackaging() {
-      return setRequireAccessModificationForRepackaging(true);
-    }
-
-    public B unsetRequireAccessModificationForRepackaging() {
-      return setRequireAccessModificationForRepackaging(false);
-    }
-
     public B setAllowAccessModification(boolean allowAccessModification) {
       this.allowAccessModification = allowAccessModification;
       return self();
@@ -608,11 +534,6 @@
       return self();
     }
 
-    public J disallowRepackaging() {
-      builder.disallowRepackaging();
-      return self();
-    }
-
     public J disallowOptimization() {
       builder.disallowOptimization();
       return self();
@@ -633,24 +554,15 @@
       return self();
     }
 
-    public J requireAccessModificationForRepackaging() {
-      builder.requireAccessModificationForRepackaging();
-      return self();
-    }
-
     public J merge(J joiner) {
       Builder<B, K> builder = joiner.builder;
       applyIf(!builder.isAccessModificationAllowed(), Joiner::disallowAccessModification);
       applyIf(!builder.isAnnotationRemovalAllowed(), Joiner::disallowAnnotationRemoval);
       applyIf(!builder.isMinificationAllowed(), Joiner::disallowMinification);
       applyIf(!builder.isOptimizationAllowed(), Joiner::disallowOptimization);
-      applyIf(!builder.isRepackagingAllowed(), Joiner::disallowRepackaging);
       applyIf(!builder.isShrinkingAllowed(), Joiner::disallowShrinking);
       applyIf(!builder.isSignatureRemovalAllowed(), Joiner::disallowSignatureRemoval);
       applyIf(builder.isCheckDiscardedEnabled(), Joiner::setCheckDiscarded);
-      applyIf(
-          builder.isAccessModificationRequiredForRepackaging(),
-          Joiner::requireAccessModificationForRepackaging);
       reasons.addAll(joiner.reasons);
       rules.addAll(joiner.rules);
       return self();
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java b/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java
index 62529ed..c78e39a 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java
@@ -140,6 +140,10 @@
     throw new Unreachable();
   }
 
+  public final KeepClassInfo getInfo(DexProgramClass clazz) {
+    return getClassInfo(clazz);
+  }
+
   public final KeepInfo<?, ?> getInfo(ProgramDefinition definition) {
     if (definition.isProgramClass()) {
       return getClassInfo(definition.asProgramClass());
@@ -279,8 +283,7 @@
             assert newType == type
                 || !info.isPinned(options)
                 || info.isMinificationAllowed(options)
-                || info.isRepackagingAllowed(
-                    definitions.definitionFor(newType).asProgramClass(), options);
+                || info.isRepackagingAllowed(options);
             KeepClassInfo previous = newClassInfo.put(newType, info);
             assert previous == null;
           });
@@ -461,29 +464,6 @@
       joinMethod(method, KeepInfo.Joiner::top);
     }
 
-    public void unsetRequireAllowAccessModificationForRepackaging(ProgramDefinition definition) {
-      if (definition.isProgramClass()) {
-        DexProgramClass clazz = definition.asProgramClass();
-        KeepClassInfo info = getClassInfo(clazz);
-        keepClassInfo.put(
-            clazz.getType(), info.builder().unsetRequireAccessModificationForRepackaging().build());
-      } else if (definition.isProgramMethod()) {
-        ProgramMethod method = definition.asProgramMethod();
-        KeepMethodInfo info = getMethodInfo(method);
-        keepMethodInfo.put(
-            method.getReference(),
-            info.builder().unsetRequireAccessModificationForRepackaging().build());
-      } else if (definition.isProgramField()) {
-        ProgramField field = definition.asProgramField();
-        KeepFieldInfo info = getFieldInfo(field);
-        keepFieldInfo.put(
-            field.getReference(),
-            info.builder().unsetRequireAccessModificationForRepackaging().build());
-      } else {
-        throw new Unreachable();
-      }
-    }
-
     public void joinField(ProgramField field, Consumer<? super KeepFieldInfo.Joiner> fn) {
       KeepFieldInfo info = getFieldInfo(field);
       if (info.isTop()) {
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepMemberInfo.java b/src/main/java/com/android/tools/r8/shaking/KeepMemberInfo.java
index 2225e14..e77c27e 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepMemberInfo.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepMemberInfo.java
@@ -4,7 +4,6 @@
 package com.android.tools.r8.shaking;
 
 import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.shaking.KeepInfo.Builder;
 
 /** Immutable keep requirements for a member. */
@@ -15,14 +14,6 @@
     super(builder);
   }
 
-  @Override
-  public boolean isRepackagingAllowed(
-      ProgramDefinition definition, GlobalKeepInfoConfiguration configuration) {
-    return configuration.isRepackagingEnabled()
-        && (definition.getAccessFlags().isPublic()
-            || !internalIsAccessModificationRequiredForRepackaging());
-  }
-
   public boolean isKotlinMetadataRemovalAllowed(
       DexProgramClass holder, GlobalKeepInfoConfiguration configuration) {
     // Checking the holder for missing kotlin information relies on the holder being processed
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardClassNameList.java b/src/main/java/com/android/tools/r8/shaking/ProguardClassNameList.java
index cc5d00b..5f5ad5f 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardClassNameList.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardClassNameList.java
@@ -295,7 +295,7 @@
 
     @Override
     public boolean matches(DexType type) {
-      return classNames.stream().anyMatch(name -> name.matches(type));
+      return Iterables.any(classNames, name -> name.matches(type));
     }
 
     @Override
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
index 36bd397..b4e83f7 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
@@ -42,8 +42,8 @@
     private boolean verbose;
     private String renameSourceFileAttribute;
     private final List<String> keepAttributePatterns = new ArrayList<>();
-    private final ProguardPackageNameList.Builder keepPackageNamesPatterns =
-        ProguardPackageNameList.builder();
+    private final ProguardClassFilter.Builder keepPackageNamesPatterns =
+        ProguardClassFilter.builder();
     private final ProguardClassFilter.Builder dontWarnPatterns = ProguardClassFilter.builder();
     private final ProguardClassFilter.Builder dontNotePatterns = ProguardClassFilter.builder();
     protected final Set<ProguardConfigurationRule> rules = Sets.newLinkedHashSet();
@@ -193,8 +193,8 @@
       this.rules.add(rule);
     }
 
-    public void addKeepPackageNamesPattern(boolean isNegated, ProguardPackageMatcher pattern) {
-      keepPackageNamesPatterns.addPackageName(isNegated, pattern);
+    public void addKeepPackageNamesPattern(ProguardClassNameList pattern) {
+      keepPackageNamesPatterns.addPattern(pattern);
     }
 
     public void addDontWarnPattern(ProguardClassNameList pattern) {
@@ -395,7 +395,7 @@
   private final boolean verbose;
   private final String renameSourceFileAttribute;
   private final ProguardKeepAttributes keepAttributes;
-  private final ProguardPackageNameList keepPackageNamesPatterns;
+  private final ProguardClassFilter keepPackageNamesPatterns;
   private final ProguardClassFilter dontWarnPatterns;
   private final ProguardClassFilter dontNotePatterns;
   protected final ImmutableList<ProguardConfigurationRule> rules;
@@ -437,7 +437,7 @@
       boolean verbose,
       String renameSourceFileAttribute,
       ProguardKeepAttributes keepAttributes,
-      ProguardPackageNameList keepPackageNamesPatterns,
+      ProguardClassFilter keepPackageNamesPatterns,
       ProguardClassFilter dontWarnPatterns,
       ProguardClassFilter dontNotePatterns,
       Set<ProguardConfigurationRule> rules,
@@ -594,7 +594,7 @@
     return keepAttributes;
   }
 
-  public ProguardPackageNameList getKeepPackageNamesPatterns() {
+  public ProguardClassFilter getKeepPackageNamesPatterns() {
     return keepPackageNamesPatterns;
   }
 
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
index 526fc5f..803c78d 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -316,7 +316,7 @@
       } else if (acceptString("keepattributes")) {
         parseKeepAttributes();
       } else if (acceptString("keeppackagenames")) {
-        parsePackageFilter(configurationBuilder::addKeepPackageNamesPattern);
+        parseClassFilter(configurationBuilder::addKeepPackageNamesPattern);
       } else if (acceptString("keepparameternames")) {
         configurationBuilder.setKeepParameterNames(true, origin, getPosition(optionStart));
       } else if (acceptString("checkdiscard")) {
@@ -1146,6 +1146,8 @@
             builder.getModifiersBuilder().setAllowsObfuscation(true);
           } else if (acceptString("accessmodification")) {
             builder.getModifiersBuilder().setAllowsAccessModification(true);
+          } else if (acceptString("repackage")) {
+            builder.getModifiersBuilder().setAllowsRepackaging(true);
           } else if (options.isTestingOptionsEnabled()) {
             if (acceptString("annotationremoval")) {
               builder.getModifiersBuilder().setAllowsAnnotationRemoval(true);
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardKeepRuleModifiers.java b/src/main/java/com/android/tools/r8/shaking/ProguardKeepRuleModifiers.java
index 7535a3e..a2619f7 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardKeepRuleModifiers.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardKeepRuleModifiers.java
@@ -3,11 +3,14 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.shaking;
 
+import java.util.Objects;
+
 public class ProguardKeepRuleModifiers {
   public static class Builder {
 
     private boolean allowsAccessModification = false;
     private boolean allowsAnnotationRemoval = false;
+    private boolean allowsRepackaging = false;
     private boolean allowsShrinking = false;
     private boolean allowsOptimization = false;
     private boolean allowsObfuscation = false;
@@ -37,6 +40,14 @@
 
     public Builder setAllowsObfuscation(boolean allowsObfuscation) {
       this.allowsObfuscation = allowsObfuscation;
+      if (allowsObfuscation) {
+        this.allowsRepackaging = true;
+      }
+      return this;
+    }
+
+    public Builder setAllowsRepackaging(boolean allowsRepackaging) {
+      this.allowsRepackaging = allowsRepackaging;
       return this;
     }
 
@@ -48,6 +59,7 @@
       return new ProguardKeepRuleModifiers(
           allowsAccessModification,
           allowsAnnotationRemoval,
+          allowsRepackaging,
           allowsShrinking,
           allowsOptimization,
           allowsObfuscation,
@@ -57,6 +69,7 @@
 
   public final boolean allowsAccessModification;
   public final boolean allowsAnnotationRemoval;
+  public final boolean allowsRepackaging;
   public final boolean allowsShrinking;
   public final boolean allowsOptimization;
   public final boolean allowsObfuscation;
@@ -65,12 +78,14 @@
   private ProguardKeepRuleModifiers(
       boolean allowsAccessModification,
       boolean allowsAnnotationRemoval,
+      boolean allowsRepackaging,
       boolean allowsShrinking,
       boolean allowsOptimization,
       boolean allowsObfuscation,
       boolean includeDescriptorClasses) {
     this.allowsAccessModification = allowsAccessModification;
     this.allowsAnnotationRemoval = allowsAnnotationRemoval;
+    this.allowsRepackaging = allowsRepackaging;
     this.allowsShrinking = allowsShrinking;
     this.allowsOptimization = allowsOptimization;
     this.allowsObfuscation = allowsObfuscation;
@@ -87,6 +102,7 @@
   public boolean isBottom() {
     return allowsAccessModification
         && allowsAnnotationRemoval
+        && allowsRepackaging
         && allowsObfuscation
         && allowsOptimization
         && allowsShrinking
@@ -101,6 +117,7 @@
     ProguardKeepRuleModifiers that = (ProguardKeepRuleModifiers) o;
     return allowsAccessModification == that.allowsAccessModification
         && allowsAnnotationRemoval == that.allowsAnnotationRemoval
+        && allowsRepackaging == that.allowsRepackaging
         && allowsShrinking == that.allowsShrinking
         && allowsOptimization == that.allowsOptimization
         && allowsObfuscation == that.allowsObfuscation
@@ -109,12 +126,14 @@
 
   @Override
   public int hashCode() {
-    return (allowsAccessModification ? 1 : 0)
-        | (allowsAnnotationRemoval ? 2 : 0)
-        | (allowsShrinking ? 4 : 0)
-        | (allowsOptimization ? 8 : 0)
-        | (allowsObfuscation ? 16 : 0)
-        | (includeDescriptorClasses ? 32 : 0);
+    return Objects.hash(
+        allowsAccessModification,
+        allowsAnnotationRemoval,
+        allowsRepackaging,
+        allowsShrinking,
+        allowsOptimization,
+        allowsObfuscation,
+        includeDescriptorClasses);
   }
 
   @Override
@@ -122,6 +141,7 @@
     StringBuilder builder = new StringBuilder();
     appendWithComma(builder, allowsAccessModification, "allowaccessmodification");
     appendWithComma(builder, allowsAnnotationRemoval, "allowannotationremoval");
+    appendWithComma(builder, allowsRepackaging, "allowrepackaging");
     appendWithComma(builder, allowsObfuscation, "allowobfuscation");
     appendWithComma(builder, allowsShrinking, "allowshrinking");
     appendWithComma(builder, allowsOptimization, "allowoptimization");
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
index 3b46564..9e1f28f 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
@@ -54,6 +54,7 @@
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
 import com.android.tools.r8.ir.optimize.membervaluepropagation.assume.AssumeInfo;
 import com.android.tools.r8.logging.Log;
+import com.android.tools.r8.repackaging.RepackagingUtils;
 import com.android.tools.r8.shaking.AnnotationMatchResult.AnnotationsIgnoredMatchResult;
 import com.android.tools.r8.shaking.AnnotationMatchResult.ConcreteAnnotationMatchResult;
 import com.android.tools.r8.shaking.AnnotationMatchResult.MatchedAnnotation;
@@ -1135,6 +1136,7 @@
         dependentMinimumKeepInfo
             .getOrCreateMinimumKeepInfoFor(preconditionEvent, clazz.getReference())
             .disallowMinification()
+            .asClassJoiner()
             .disallowRepackaging();
       }
     }
@@ -1637,15 +1639,14 @@
       if (appView.options().isMinificationEnabled() && !modifiers.allowsObfuscation) {
         dependentMinimumKeepInfo
             .getOrCreateMinimumKeepInfoFor(preconditionEvent, item.getReference())
-            .disallowMinification()
-            .disallowRepackaging();
+            .disallowMinification();
         context.markAsUsed();
       }
 
-      if (appView.options().isRepackagingEnabled() && !modifiers.allowsObfuscation) {
+      if (appView.options().isRepackagingEnabled() && isRepackagingDisallowed(item, modifiers)) {
         dependentMinimumKeepInfo
             .getOrCreateMinimumKeepInfoFor(preconditionEvent, item.getReference())
-            .disallowRepackaging();
+            .applyIf(item.isProgramClass(), joiner -> joiner.asClassJoiner().disallowRepackaging());
         context.markAsUsed();
       }
 
@@ -1664,10 +1665,6 @@
                 .addRule(keepRule)
                 .disallowShrinking();
         context.markAsUsed();
-
-        if (item.getAccessFlags().isPackagePrivateOrProtected()) {
-          minimumKeepInfoForItem.requireAccessModificationForRepackaging();
-        }
       }
 
       if (modifiers.includeDescriptorClasses) {
@@ -1676,6 +1673,14 @@
       }
     }
 
+    private boolean isRepackagingDisallowed(
+        ProgramDefinition item, ProguardKeepRuleModifiers modifiers) {
+      if (!modifiers.allowsRepackaging) {
+        return true;
+      }
+      return RepackagingUtils.isPackageNameKept(item.getContextClass(), options);
+    }
+
     private void evaluateIdentifierNameStringRule(
         Definition item, ProguardConfigurationRule context, ProguardIfRule ifRule) {
       // Main dex rules should not contain -identifiernamestring rules.
@@ -1981,7 +1986,8 @@
       getDependentMinimumKeepInfo()
           .getOrCreateUnconditionalMinimumKeepInfoFor(definition.getReference())
           .disallowMinification()
-          .disallowRepackaging();
+          .applyIf(
+              definition.isProgramClass(), joiner -> joiner.asClassJoiner().disallowRepackaging());
     }
 
     public boolean verifyKeptFieldsAreAccessedAndLive(AppView<AppInfoWithLiveness> appView) {
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 68c055f..9af4f06 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -804,6 +804,7 @@
   public boolean reportMissingClassesInEnclosingMethodAttribute = false;
   public boolean reportMissingClassesInInnerClassAttributes = false;
   public boolean disableGenericSignatureValidation = false;
+  public boolean disableInnerClassSeparatorValidationWhenRepackaging = false;
 
   // EXPERIMENTAL flag to get behaviour as close to Proguard as possible.
   public boolean forceProguardCompatibility = false;
diff --git a/src/main/java/com/android/tools/r8/utils/OneShotCollectionConsumer.java b/src/main/java/com/android/tools/r8/utils/OneShotCollectionConsumer.java
new file mode 100644
index 0000000..89090e6
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/OneShotCollectionConsumer.java
@@ -0,0 +1,37 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.utils;
+
+import java.util.Collection;
+import java.util.function.Consumer;
+
+public class OneShotCollectionConsumer<T> {
+
+  private final Collection<T> collection;
+  private boolean hasBeenConsumed = false;
+
+  private OneShotCollectionConsumer(Collection<T> collection) {
+    this.collection = collection;
+  }
+
+  public void add(T t) {
+    assert !hasBeenConsumed;
+    this.collection.add(t);
+  }
+
+  public void consume(Consumer<T> consumer) {
+    hasBeenConsumed = true;
+    collection.forEach(consumer);
+    collection.clear();
+  }
+
+  public static <T> OneShotCollectionConsumer<T> wrap(Collection<T> collection) {
+    return new OneShotCollectionConsumer<>(collection);
+  }
+
+  public boolean isEmpty() {
+    return collection.isEmpty();
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/positions/ClassFilePositionToMappedRangeMapper.java b/src/main/java/com/android/tools/r8/utils/positions/ClassFilePositionToMappedRangeMapper.java
index cd6efb7..dd60a3e 100644
--- a/src/main/java/com/android/tools/r8/utils/positions/ClassFilePositionToMappedRangeMapper.java
+++ b/src/main/java/com/android/tools/r8/utils/positions/ClassFilePositionToMappedRangeMapper.java
@@ -11,8 +11,10 @@
 import com.android.tools.r8.cf.code.CfPosition;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.code.Position;
+import com.android.tools.r8.ir.code.Position.SyntheticPosition;
 import com.android.tools.r8.utils.Pair;
 import java.util.ArrayList;
 import java.util.List;
@@ -34,7 +36,7 @@
       int pcEncodingCutoff) {
     return appView.options().getTestingOptions().usePcEncodingInCfForTesting
         ? getPcEncodedPositions(method, positionRemapper)
-        : getMappedPositionsRemapped(method, positionRemapper);
+        : getMappedPositionsRemapped(method, positionRemapper, hasOverloads);
   }
 
   @Override
@@ -43,15 +45,17 @@
   }
 
   private List<MappedPosition> getMappedPositionsRemapped(
-      ProgramMethod method, PositionRemapper positionRemapper) {
+      ProgramMethod method, PositionRemapper positionRemapper, boolean hasOverloads) {
     List<MappedPosition> mappedPositions = new ArrayList<>();
     // Do the actual processing for each method.
     CfCode oldCode = method.getDefinition().getCode().asCfCode();
     List<CfInstruction> oldInstructions = oldCode.getInstructions();
     List<CfInstruction> newInstructions = new ArrayList<>(oldInstructions.size());
+    boolean seenPosition = false;
     for (CfInstruction oldInstruction : oldInstructions) {
       CfInstruction newInstruction;
       if (oldInstruction.isPosition()) {
+        seenPosition = true;
         CfPosition cfPosition = oldInstruction.asPosition();
         newInstruction =
             new CfPosition(
@@ -62,6 +66,24 @@
       }
       newInstructions.add(newInstruction);
     }
+    if (!seenPosition && hasOverloads) {
+      // If a method with overloads does not have an actual position then map it to the implicit
+      // preamble position.
+      DexMethod reference = method.getReference();
+      DexMethod original = appView.graphLens().getOriginalMethodSignature(reference);
+      CfPosition preamblePositionForOverload =
+          new CfPosition(
+              new CfLabel(),
+              remapAndAdd(
+                  SyntheticPosition.builder().setMethod(original).setLine(0).build(),
+                  positionRemapper,
+                  mappedPositions));
+      List<CfInstruction> shiftedPositions = new ArrayList<>(oldInstructions.size() + 2);
+      shiftedPositions.add(preamblePositionForOverload);
+      shiftedPositions.add(preamblePositionForOverload.getLabel());
+      shiftedPositions.addAll(newInstructions);
+      newInstructions = shiftedPositions;
+    }
     method.setCode(
         new CfCode(
             method.getHolderType(),
diff --git a/src/main/java/com/android/tools/r8/utils/positions/LineNumberOptimizer.java b/src/main/java/com/android/tools/r8/utils/positions/LineNumberOptimizer.java
index 993ca5f..c1e6850 100644
--- a/src/main/java/com/android/tools/r8/utils/positions/LineNumberOptimizer.java
+++ b/src/main/java/com/android/tools/r8/utils/positions/LineNumberOptimizer.java
@@ -118,13 +118,21 @@
 
         for (ProgramMethod method : methods) {
           DexEncodedMethod definition = method.getDefinition();
+          DexMethod methodReference = method.getReference();
+          if (methodName == method.getName()
+              && appView.graphLens().getOriginalMethodSignature(methodReference) == methodReference
+              && !mustHaveResidualDebugInfo(appView.options(), definition)
+              && !definition.isD8R8Synthesized()
+              && methods.size() <= 1) {
+            continue;
+          }
           positionRemapper.setCurrentMethod(definition);
           List<MappedPosition> mappedPositions;
           int pcEncodingCutoff =
               methods.size() == 1 ? representation.getDexPcEncodingCutoff(method) : -1;
           boolean canUseDexPc = pcEncodingCutoff > 0;
           if (definition.getCode() != null
-              && mustHaveResidualDebugInfo(appView.options(), definition)
+              && (definition.getCode().isCfCode() || definition.getCode().isDexCode())
               && !appView.isCfByteCodePassThrough(definition)) {
             mappedPositions =
                 positionToMappedRangeMapper.getMappedPositions(
@@ -229,14 +237,9 @@
       DexEncodedMethod definition = programMethod.getDefinition();
       DexMethod method = programMethod.getReference();
       DexString renamedName = appView.getNamingLens().lookupName(method);
-      if (renamedName != method.name
-          || appView.graphLens().getOriginalMethodSignature(method) != method
-          || mustHaveResidualDebugInfo(appView.options(), definition)
-          || definition.isD8R8Synthesized()) {
-        methodsByRenamedName
-            .computeIfAbsent(renamedName, key -> new ArrayList<>())
-            .add(programMethod);
-      }
+      methodsByRenamedName
+          .computeIfAbsent(renamedName, key -> new ArrayList<>())
+          .add(programMethod);
     }
     return methodsByRenamedName;
   }
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 646e09e..ae0eb0e 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
@@ -45,6 +45,7 @@
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.InternalOptions.LineNumberOptimization;
 import com.android.tools.r8.utils.ListUtils;
+import com.android.tools.r8.utils.OneShotCollectionConsumer;
 import com.android.tools.r8.utils.OriginalSourceFiles;
 import com.android.tools.r8.utils.Pair;
 import it.unimi.dsi.fastutil.ints.Int2IntArrayMap;
@@ -196,9 +197,11 @@
       MethodSignature originalSignature =
           MethodSignature.fromDexMethod(originalMethod, originalMethod.holder != originalType);
 
-      List<MappingInformation> methodMappingInfo = new ArrayList<>();
+      OneShotCollectionConsumer<MappingInformation> methodSpecificMappingInformation =
+          OneShotCollectionConsumer.wrap(new ArrayList<>());
       if (method.getDefinition().isD8R8Synthesized()) {
-        methodMappingInfo.add(CompilerSynthesizedMappingInformation.builder().build());
+        methodSpecificMappingInformation.add(
+            CompilerSynthesizedMappingInformation.builder().build());
       }
 
       DexMethod residualMethod =
@@ -208,7 +211,7 @@
       if (isIdentityMapping(
           mapFileVersion,
           mappedPositions,
-          methodMappingInfo,
+          methodSpecificMappingInformation,
           method,
           residualMethod.getName(),
           originalMethod,
@@ -221,7 +224,7 @@
       if (mapFileVersion.isGreaterThan(MapVersion.MAP_VERSION_2_1)
           && originalMethod != method.getReference()
           && !appView.graphLens().isSimpleRenaming(residualMethod)) {
-        methodMappingInfo.add(
+        methodSpecificMappingInformation.add(
             ResidualMethodSignatureMappingInformation.fromDexMethod(residualMethod));
       }
       MethodSignature residualSignature = MethodSignature.fromDexMethod(residualMethod);
@@ -233,7 +236,8 @@
       if (mappedPositions.isEmpty()) {
         MappedRange range =
             getBuilder().addMappedRange(null, originalSignature, null, residualSignature.getName());
-        methodMappingInfo.forEach(info -> range.addMappingInformation(info, Unreachable::raise));
+        methodSpecificMappingInformation.consume(
+            info -> range.addMappingInformation(info, Unreachable::raise));
         return this;
       }
 
@@ -252,7 +256,7 @@
                 outlineMethod,
                 outline -> new OutlineFixupBuilder(computeMappedMethod(outline, appView)))
             .setMappedPositionsOutline(mappedPositions);
-        methodMappingInfo.add(OutlineMappingInformation.builder().build());
+        methodSpecificMappingInformation.add(OutlineMappingInformation.builder().build());
       }
 
       // Update memberNaming with the collected positions, merging multiple positions into a
@@ -311,9 +315,8 @@
                 firstPosition.getCaller(),
                 prunedInlinedClasses,
                 cardinalRangeCache);
-        for (MappingInformation info : methodMappingInfo) {
-          lastMappedRange.addMappingInformation(info, Unreachable::raise);
-        }
+        methodSpecificMappingInformation.consume(
+            info -> lastMappedRange.addMappingInformation(info, Unreachable::raise));
         // firstPosition will contain a potential outline caller.
         if (firstPosition.getOutlineCallee() != null) {
           Int2IntMap positionMap = new Int2IntArrayMap();
@@ -427,7 +430,7 @@
     private boolean isIdentityMapping(
         MapVersion mapFileVersion,
         List<MappedPosition> mappedPositions,
-        List<MappingInformation> methodMappingInfo,
+        OneShotCollectionConsumer<MappingInformation> methodMappingInfo,
         ProgramMethod method,
         DexString obfuscatedNameDexString,
         DexMethod originalMethod,
diff --git a/src/test/examples/shaking1/print-mapping-dex.ref b/src/test/examples/shaking1/print-mapping-dex.ref
index 3635115..bb72965 100644
--- a/src/test/examples/shaking1/print-mapping-dex.ref
+++ b/src/test/examples/shaking1/print-mapping-dex.ref
@@ -1,6 +1,7 @@
 shaking1.Shaking -> shaking1.Shaking:
 shaking1.Used -> a.a:
     0:2:void <init>(java.lang.String):12:12 -> <init>
+    0:2:java.lang.String aMethodThatIsNotUsedButKept():0:0 -> aMethodThatIsNotUsedButKept
     3:5:void <init>(java.lang.String):13:13 -> <init>
     0:6:void main(java.lang.String[]):8:8 -> main
     7:21:void main(java.lang.String[]):9:9 -> main
diff --git a/src/test/java/com/android/tools/r8/CompileWithJdkClassFileProviderTest.java b/src/test/java/com/android/tools/r8/CompileWithJdkClassFileProviderTest.java
index 301cebb..fe94b93 100644
--- a/src/test/java/com/android/tools/r8/CompileWithJdkClassFileProviderTest.java
+++ b/src/test/java/com/android/tools/r8/CompileWithJdkClassFileProviderTest.java
@@ -101,7 +101,7 @@
           .compileWithExpectedDiagnostics(
               diagnostics -> {
                 diagnostics.assertWarningsMatch(
-                    // TODO(b/251482856): Unexpected unverifiable code.
+                    // The open-interfaces analysis will issue unverifiable code on missing class.
                     diagnosticType(UnverifiableCfCodeDiagnostic.class),
                     // TODO(b/175659048): This should likely be a desugar diagnostic.
                     allOf(
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineSubTypeStaticReferenceTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineSubTypeStaticReferenceTest.java
new file mode 100644
index 0000000..3e56179
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineSubTypeStaticReferenceTest.java
@@ -0,0 +1,174 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.apimodel;
+
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
+import static com.android.tools.r8.utils.codeinspector.CodeMatchers.invokesMethod;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.D8TestCompileResult;
+import com.android.tools.r8.SingleTestRunResult;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestCompilerBuilder;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.testing.AndroidBuildVersion;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import java.lang.reflect.Method;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ApiModelOutlineSubTypeStaticReferenceTest extends TestBase {
+
+  private static final AndroidApiLevel libraryApiLevel = AndroidApiLevel.M;
+
+  @Parameter() public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  private boolean willInvokeLibraryMethods() {
+    return parameters.isDexRuntime()
+        && parameters.getApiLevel().isGreaterThanOrEqualTo(libraryApiLevel);
+  }
+
+  @Test
+  public void testD8BootClassPath() throws Exception {
+    assumeTrue(parameters.isDexRuntime());
+    compileOnD8()
+        .addBootClasspathClasses(LibraryClass.class)
+        .run(parameters.getRuntime(), Main.class)
+        .apply(this::checkResultOnBootClassPath);
+  }
+
+  @Test
+  public void testD8RuntimeClasspath() throws Exception {
+    assumeTrue(parameters.isDexRuntime());
+    compileOnD8()
+        .addRunClasspathClasses(LibraryClass.class)
+        .run(parameters.getRuntime(), Main.class)
+        .apply(this::checkResultOnBootClassPath);
+  }
+
+  private D8TestCompileResult compileOnD8() throws Exception {
+    return testForD8(parameters.getBackend())
+        .addLibraryClasses(LibraryClass.class)
+        .addProgramClasses(Main.class, Sub.class)
+        .addAndroidBuildVersion()
+        .setMinApi(parameters.getApiLevel())
+        .compile();
+  }
+
+  private void setupTestBuilder(TestCompilerBuilder<?, ?, ?, ?, ?> testBuilder) throws Exception {
+    testBuilder
+        .addLibraryClasses(LibraryClass.class)
+        .addDefaultRuntimeLibrary(parameters)
+        .addProgramClasses(Main.class, Sub.class)
+        .setMinApi(parameters.getApiLevel())
+        .addAndroidBuildVersion()
+        .apply(setMockApiLevelForClass(LibraryClass.class, libraryApiLevel))
+        .apply(
+            setMockApiLevelForMethod(LibraryClass.class.getDeclaredMethod("foo"), libraryApiLevel))
+        // TODO(b/213552119): Remove when enabled by default.
+        .apply(ApiModelingTestHelper::enableApiCallerIdentification)
+        .apply(ApiModelingTestHelper::enableOutliningOfMethods)
+        .apply(ApiModelingTestHelper::disableStubbingOfClasses);
+  }
+
+  @Test
+  public void testD8Debug() throws Exception {
+    assumeTrue(parameters.isDexRuntime());
+    testForD8()
+        .setMode(CompilationMode.DEBUG)
+        .apply(this::setupTestBuilder)
+        .compile()
+        .inspect(inspector -> inspect(inspector, false))
+        .applyIf(willInvokeLibraryMethods(), b -> b.addBootClasspathClasses(LibraryClass.class))
+        .run(parameters.getRuntime(), Main.class)
+        .apply(this::checkResultOnBootClassPath);
+  }
+
+  @Test
+  public void testD8Release() throws Exception {
+    assumeTrue(parameters.isDexRuntime());
+    testForD8()
+        .apply(this::setupTestBuilder)
+        .compile()
+        .inspect(inspector -> inspect(inspector, false))
+        .applyIf(willInvokeLibraryMethods(), b -> b.addBootClasspathClasses(LibraryClass.class))
+        .run(parameters.getRuntime(), Main.class)
+        .apply(this::checkResultOnBootClassPath);
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
+        .apply(this::setupTestBuilder)
+        .addKeepMainRule(Main.class)
+        .addKeepClassAndMembersRules(Sub.class)
+        .compile()
+        .inspect(inspector -> inspect(inspector, true))
+        .applyIf(willInvokeLibraryMethods(), b -> b.addBootClasspathClasses(LibraryClass.class))
+        .run(parameters.getRuntime(), Main.class)
+        .apply(this::checkResultOnBootClassPath);
+  }
+
+  private void inspect(CodeInspector inspector, boolean isR8) throws Exception {
+    Method otherMethod = Sub.class.getMethod("otherMethod");
+    Method libraryMethod = LibraryClass.class.getMethod("foo");
+    // TODO(b/254510678): R8 should not member-rebind to a potential non-existing method.
+    if (isR8) {
+      MethodSubject method = inspector.method(otherMethod);
+      assertThat(method, isPresent());
+      assertThat(method, invokesMethod(Reference.methodFromMethod(libraryMethod)));
+    }
+    // TODO(b/254510678): We should outline this up until library api level.
+    verifyThat(inspector, parameters, libraryMethod).isNotOutlinedFrom(otherMethod);
+  }
+
+  private void checkResultOnBootClassPath(SingleTestRunResult<?> runResult) {
+    runResult
+        .assertSuccessWithOutputLinesIf(!willInvokeLibraryMethods(), "Not calling API")
+        .assertSuccessWithOutputLinesIf(willInvokeLibraryMethods(), "Base::foo");
+  }
+
+  public static class LibraryClass {
+
+    public void foo() {
+      System.out.println("Base::foo");
+    }
+  }
+
+  public static class Sub extends LibraryClass {
+
+    public void otherMethod() {
+      foo();
+    }
+  }
+
+  public static class Main {
+    public static void main(String[] args) {
+      if (AndroidBuildVersion.VERSION >= 23) {
+        new Sub().otherMethod();
+      } else {
+        System.out.println("Not calling API");
+      }
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/debug/DebugTestBase.java b/src/test/java/com/android/tools/r8/debug/DebugTestBase.java
index c0f7ea3..50a8842 100644
--- a/src/test/java/com/android/tools/r8/debug/DebugTestBase.java
+++ b/src/test/java/com/android/tools/r8/debug/DebugTestBase.java
@@ -151,11 +151,6 @@
   @Rule
   public TestDescriptionWatcher watcher = new TestDescriptionWatcher();
 
-  protected static final boolean supportsDefaultMethod(DebugTestConfig config) {
-    return config.isCfRuntime()
-        || ToolHelper.getMinApiLevelForDexVm().getLevel() >= AndroidApiLevel.N.getLevel();
-  }
-
   protected final void runDebugTest(
       DebugTestConfig config, Class<?> debuggeeClass, JUnit3Wrapper.Command... commands)
       throws Throwable {
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 e603d08..51e8ab2 100644
--- a/src/test/java/com/android/tools/r8/debug/InterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/debug/InterfaceMethodTest.java
@@ -9,16 +9,18 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assume.assumeTrue;
 
+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.debug.DebugTestBase.JUnit3Wrapper.Command;
 import com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringForTesting;
 import java.nio.file.Path;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
@@ -29,33 +31,40 @@
   private static final String INTERFACE_SOURCE_FILE = "InterfaceWithDefaultAndStaticMethods.java";
 
   @Parameters(name = "{0}")
-  public static Collection configs() {
-    return parameters()
-        .add("CF", new CfDebugTestConfig(JAR))
-        .add("D8", temp -> new D8DebugTestConfig().compileAndAdd(temp, JAR))
-        .build();
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private final DebugTestConfig config;
+  @Parameter public TestParameters parameters;
+  String debuggeeClass = "DebugInterfaceMethod";
 
-  public InterfaceMethodTest(String name, DelayedDebugTestConfig delayedConfig) {
-    this.config = delayedConfig.getConfig(temp);
+  private boolean supportsDefaultMethods() {
+    return parameters.isCfRuntime()
+        || parameters
+            .getApiLevel()
+            .isGreaterThanOrEqualTo(apiLevelWithDefaultInterfaceMethodsSupport());
   }
 
   @Test
   public void testDefaultMethod() throws Throwable {
     // TODO(b/244683447): This test fails on ART 13 when checking current method in doSomething.
     assumeTrue(
-        config.getRuntime().isCf()
-            || !config.getRuntime().asDex().getVersion().isEqualTo(Version.V13_0_0));
-    String debuggeeClass = "DebugInterfaceMethod";
+        parameters.isCfRuntime() || !parameters.getDexRuntimeVersion().isEqualTo(Version.V13_0_0));
+    testForRuntime(parameters)
+        .addProgramFiles(JAR)
+        .run(parameters.getRuntime(), debuggeeClass)
+        .debugger(this::runDefaultMethod);
+  }
+
+  private void runDefaultMethod(DebugTestConfig config) throws Throwable {
     String parameterName = "msg";
     String localVariableName = "name";
 
     final String defaultMethodContainerClass;
     final String defaultMethodName;
     final String defaultMethodThisName;
-    if (supportsDefaultMethod(config)) {
+
+    if (supportsDefaultMethods()) {
       defaultMethodContainerClass = "InterfaceWithDefaultAndStaticMethods";
       defaultMethodName = "doSomething";
       defaultMethodThisName = "this";
@@ -69,7 +78,6 @@
       defaultMethodThisName = "_this";
     }
 
-
     List<Command> commands = new ArrayList<>();
     commands.add(breakpoint(debuggeeClass, "testDefaultMethod"));
     commands.add(run());
@@ -96,7 +104,13 @@
 
   @Test
   public void testOverrideDefaultMethod() throws Throwable {
-    String debuggeeClass = "DebugInterfaceMethod";
+    testForRuntime(parameters)
+        .addProgramFiles(JAR)
+        .run(parameters.getRuntime(), debuggeeClass)
+        .debugger(this::runOverrideDefaultMethod);
+  }
+
+  private void runOverrideDefaultMethod(DebugTestConfig config) throws Throwable {
     String parameterName = "msg";
     String localVariableName = "newMsg";
 
@@ -121,12 +135,18 @@
 
   @Test
   public void testStaticMethod() throws Throwable {
-    String debuggeeClass = "DebugInterfaceMethod";
+    testForRuntime(parameters)
+        .addProgramFiles(JAR)
+        .run(parameters.getRuntime(), debuggeeClass)
+        .debugger(this::runStaticMethod);
+  }
+
+  private void runStaticMethod(DebugTestConfig config) throws Throwable {
     String parameterName = "msg";
 
     final String staticMethodContainerClass;
     final String staticMethodName = "printString";
-    if (supportsDefaultMethod(config)) {
+    if (supportsDefaultMethods()) {
       staticMethodContainerClass = "InterfaceWithDefaultAndStaticMethods";
     } else {
       staticMethodContainerClass =
diff --git a/src/test/java/com/android/tools/r8/debug/KotlinStdLibCompilationTest.java b/src/test/java/com/android/tools/r8/debug/KotlinStdLibCompilationTest.java
index cf69ff4..abe31f8 100644
--- a/src/test/java/com/android/tools/r8/debug/KotlinStdLibCompilationTest.java
+++ b/src/test/java/com/android/tools/r8/debug/KotlinStdLibCompilationTest.java
@@ -48,12 +48,18 @@
     testForD8()
         .addProgramFiles(kotlinTestParameters.getCompiler().getKotlinStdlibJar())
         .setMinApi(parameters.getApiLevel())
-        // TODO(b/248244467): Remove if fixed.
         .compileWithExpectedDiagnostics(
-            diagnostics ->
+            diagnostics -> {
+              if (kotlinTestParameters.isKotlinDev()
+                  && parameters.isDexRuntime()
+                  && parameters.getApiLevel().isLessThan(AndroidApiLevel.N)) {
+                diagnostics.assertWarningsCount(2);
                 diagnostics.assertAllWarningsMatch(
-                    DiagnosticsMatcher.diagnosticType(
-                        InterfaceDesugarMissingTypeDiagnostic.class)));
+                    DiagnosticsMatcher.diagnosticType(InterfaceDesugarMissingTypeDiagnostic.class));
+              } else {
+                diagnostics.assertNoMessages();
+              }
+            });
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/debuginfo/OverloadWithNoLineNumberTest.java b/src/test/java/com/android/tools/r8/debuginfo/OverloadWithNoLineNumberTest.java
index 47f6e4b..7a519a6 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/OverloadWithNoLineNumberTest.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/OverloadWithNoLineNumberTest.java
@@ -4,17 +4,20 @@
 
 package com.android.tools.r8.debuginfo;
 
-import static com.android.tools.r8.naming.retrace.StackTrace.isSame;
-import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
 
+import com.android.tools.r8.R8TestRunResult;
 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.debuginfo.testclasses.SimpleCallChainClassWithOverloads;
-import com.android.tools.r8.naming.retrace.StackTrace;
-import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine;
+import com.android.tools.r8.retrace.ProguardMapProducer;
+import com.android.tools.r8.retrace.ProguardMappingSupplier;
+import com.android.tools.r8.retrace.Retrace;
+import com.android.tools.r8.retrace.RetraceCommand;
 import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
+import com.android.tools.r8.utils.StringUtils;
+import java.util.stream.Collectors;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -35,68 +38,43 @@
 
   @Test
   public void testR8() throws Exception {
-    testForR8(parameters.getBackend())
-        .addProgramClassFileData(
-            transformer(SimpleCallChainClassWithOverloads.class)
-                .removeLineNumberTable(MethodPredicate.onName("test"))
-                .transform())
-        .setMinApi(parameters.getApiLevel())
-        .addKeepMainRule(SimpleCallChainClassWithOverloads.class)
-        .addKeepClassAndMembersRules(SimpleCallChainClassWithOverloads.class)
-        .addKeepAttributeLineNumberTable()
-        .run(parameters.getRuntime(), SimpleCallChainClassWithOverloads.class)
-        .assertFailureWithErrorThatThrows(RuntimeException.class)
-        .inspectStackTrace(
-            (stackTrace, inspector) -> {
-              StackTraceLine mainLine =
-                  StackTraceLine.builder()
-                      .setClassName(typeName(SimpleCallChainClassWithOverloads.class))
-                      .setMethodName("main")
-                      .setFileName(SOURCE_FILE_NAME)
-                      .setLineNumber(10)
-                      .build();
-              if (parameters.isCfRuntime()
-                  || parameters.getDexRuntimeVersion().isOlderThan(Version.V8_1_0)) {
-                StackTraceLine testStackTraceLine =
-                    StackTraceLine.builder()
-                        .setClassName(typeName(SimpleCallChainClassWithOverloads.class))
-                        .setMethodName("test")
-                        .setFileName(SOURCE_FILE_NAME)
-                        .build();
-                assertThat(
-                    stackTrace,
-                    isSame(
-                        StackTrace.builder()
-                            // TODO(b/251677184): Stack trace lines should still be distinguishable
-                            //  even if there are no original line numbers to map back two.
-                            .add(testStackTraceLine)
-                            .add(testStackTraceLine)
-                            .add(mainLine)
-                            .build()));
-              } else {
-                assertThat(
-                    stackTrace,
-                    isSame(
-                        StackTrace.builder()
-                            // TODO(b/251677184): Strange that we are able to distinguish when using
-                            //  pc mapping.
-                            .add(
-                                StackTraceLine.builder()
-                                    .setClassName(typeName(SimpleCallChainClassWithOverloads.class))
-                                    .setMethodName("test")
-                                    .setFileName(SOURCE_FILE_NAME)
-                                    .setLineNumber(11)
-                                    .build())
-                            .add(
-                                StackTraceLine.builder()
-                                    .setClassName(typeName(SimpleCallChainClassWithOverloads.class))
-                                    .setMethodName("test")
-                                    .setFileName(SOURCE_FILE_NAME)
-                                    .setLineNumber(4)
-                                    .build())
-                            .add(mainLine)
-                            .build()));
-              }
-            });
+    R8TestRunResult result =
+        testForR8(parameters.getBackend())
+            .addProgramClassFileData(
+                transformer(SimpleCallChainClassWithOverloads.class)
+                    .removeLineNumberTable(MethodPredicate.onName("test"))
+                    .transform())
+            .setMinApi(parameters.getApiLevel())
+            .addKeepMainRule(SimpleCallChainClassWithOverloads.class)
+            .addKeepClassAndMembersRules(SimpleCallChainClassWithOverloads.class)
+            .addKeepAttributeLineNumberTable()
+            .run(parameters.getRuntime(), SimpleCallChainClassWithOverloads.class)
+            .assertFailureWithErrorThatThrows(RuntimeException.class);
+    Retrace.run(
+        RetraceCommand.builder()
+            .setMappingSupplier(
+                ProguardMappingSupplier.builder()
+                    .setProguardMapProducer(ProguardMapProducer.fromString(result.proguardMap()))
+                    .build())
+            .setStackTrace(
+                result.getOriginalStackTrace().getStackTraceLines().stream()
+                    .map(line -> line.originalLine)
+                    .collect(Collectors.toList()))
+            .setRetracedStackTraceConsumer(
+                retraced -> {
+                  String className = typeName(SimpleCallChainClassWithOverloads.class);
+                  assertEquals(
+                      StringUtils.joinLines(
+                          "\tat " + className + ".void test(long)(" + SOURCE_FILE_NAME + ":0)",
+                          "\tat " + className + ".void test()(" + SOURCE_FILE_NAME + ":0)",
+                          "\tat "
+                              + className
+                              + ".void main(java.lang.String[])("
+                              + SOURCE_FILE_NAME
+                              + ":10)"),
+                      StringUtils.joinLines(retraced));
+                })
+            .setVerbose(true)
+            .build());
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java
index b5ca98b..a68f3ce 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java
@@ -123,13 +123,7 @@
 
   // TODO(b/238179854): Investigate how to fix these.
   private static final Set<String> MISSING_GENERIC_TYPE_CONVERSION_PATH =
-      ImmutableSet.of(
-          "java.lang.Iterable java.nio.file.FileSystem.getFileStores()",
-          "java.lang.Iterable java.nio.file.FileSystem.getRootDirectories()",
-          "java.util.Iterator java.nio.file.Path.iterator()",
-          "java.nio.file.DirectoryStream"
-              + " java.nio.file.spi.FileSystemProvider.newDirectoryStream(java.nio.file.Path,"
-              + " java.nio.file.DirectoryStream$Filter)");
+      ImmutableSet.of("java.lang.Iterable java.nio.file.FileSystem.getFileStores()");
 
   // TODO(b/238179854): Investigate how to fix these.
   private static final Set<String> MISSING_GENERIC_TYPE_CONVERSION_FLOW =
@@ -245,6 +239,18 @@
             .collect(Collectors.toSet());
     Set<String> maintainTypeInSet =
         specification.getMaintainType().stream().map(DexType::toString).collect(Collectors.toSet());
+    Map<String, boolean[]> genericConversionsInSpec = new HashMap<>();
+    specification
+        .getApiGenericConversion()
+        .forEach(
+            (method, generics) -> {
+              boolean[] indexes = new boolean[generics.length];
+              for (int i = 0; i < generics.length; i++) {
+                indexes[i] = generics[i] != null;
+              }
+              genericConversionsInSpec.put(method.toString(), indexes);
+            });
+
     assertEquals(
         Collections.emptySet(), Sets.intersection(wrappersInSpec, customConversionsInSpec));
 
@@ -257,6 +263,7 @@
             nonDesugaredJar,
             customConversionsInSpec,
             maintainTypeInSet,
+            genericConversionsInSpec,
             genericDependencies);
     Map<ClassReference, Set<ClassReference>> indirectWrappers =
         getIndirectlyReferencedWrapperTypes(
@@ -266,6 +273,7 @@
             customConversionsInSpec,
             maintainTypeInSet,
             specification.getWrappers(),
+            genericConversionsInSpec,
             genericDependencies);
     {
       Set<String> missingGenericDependency = new HashSet<>();
@@ -339,6 +347,7 @@
       CodeInspector nonDesugaredJar,
       Set<String> customConversions,
       Set<String> maintainType,
+      Map<String, boolean[]> genericConversionsInSpec,
       Set<DexEncodedMethod> genericDependencies) {
     Map<ClassReference, Set<MethodReference>> directWrappers = new HashMap<>();
     nonDesugaredJar.forAllClasses(
@@ -364,6 +373,7 @@
                 forEachType(
                     method,
                     t -> addType(adder, t, preDesugarTypes, customConversions, maintainType),
+                    genericConversionsInSpec,
                     genericDependencies);
               });
         });
@@ -373,12 +383,20 @@
   private void forEachType(
       FoundMethodSubject subject,
       Function<String, Boolean> process,
+      Map<String, boolean[]> genericConversionsInSpec,
       Set<DexEncodedMethod> generics) {
+    boolean[] genericConversions = genericConversionsInSpec.get(subject.toString());
     MethodSignature signature = subject.getFinalSignature().asMethodSignature();
-    process.apply(signature.type);
-    for (String parameter : signature.parameters) {
-      process.apply(parameter);
+    if (genericConversions == null || !genericConversions[genericConversions.length - 1]) {
+      process.apply(signature.type);
     }
+    for (int i = 0; i < signature.parameters.length; i++) {
+      if (genericConversions == null || !genericConversions[i]) {
+        process.apply(signature.parameters[i]);
+      }
+    }
+    // Even if the genericConversions are present, we check the generic types since conversions
+    // on such types will happen through the hand written custom wrappers.
     MethodTypeSignature genericSignature = subject.getMethod().getGenericSignature();
     if (genericSignature != null) {
       TypeSignature[] typeSignatures = new TypeSignature[signature.parameters.length + 1];
@@ -387,15 +405,17 @@
       }
       typeSignatures[signature.parameters.length] = genericSignature.returnType().typeSignature();
       for (TypeSignature typeSignature : typeSignatures) {
-        if ((typeSignature instanceof ClassTypeSignature)) {
-          for (FieldTypeSignature typeArgument :
-              ((ClassTypeSignature) typeSignature).typeArguments()) {
-            if (typeArgument instanceof ClassTypeSignature) {
-              String type = descriptorToJavaType(typeArgument.toString()).split("<")[0];
-              if (!GENERIC_NOT_NEEDED.contains(type)) {
-                boolean added = process.apply(type);
-                if (added) {
-                  generics.add(subject.getMethod());
+        if (typeSignature != null) {
+          if ((typeSignature instanceof ClassTypeSignature)) {
+            for (FieldTypeSignature typeArgument :
+                ((ClassTypeSignature) typeSignature).typeArguments()) {
+              if (typeArgument instanceof ClassTypeSignature) {
+                String type = descriptorToJavaType(typeArgument.toString()).split("<")[0];
+                if (!GENERIC_NOT_NEEDED.contains(type)) {
+                  boolean added = process.apply(type);
+                  if (added) {
+                    generics.add(subject.getMethod());
+                  }
                 }
               }
             }
@@ -412,6 +432,7 @@
       Set<String> customConversions,
       Set<String> maintainType,
       Map<DexType, WrapperDescriptor> wrapperDescriptorMap,
+      Map<String, boolean[]> genericConversionsInSpec,
       Set<DexEncodedMethod> genericDependencies) {
     Map<ClassReference, Set<ClassReference>> indirectWrappers = new HashMap<>();
     WorkList<ClassReference> worklist = WorkList.newEqualityWorkList(directWrappers.keySet());
@@ -435,6 +456,7 @@
             forEachType(
                 method,
                 t -> addType(adder, t, existing, customConversions, maintainType),
+                genericConversionsInSpec,
                 genericDependencies);
           });
       WrapperDescriptor descriptor = wrapperDescriptorMap.get(clazz.getDexProgramClass().getType());
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IterateTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IterateTest.java
index d69ebe8..4ae0d62 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IterateTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IterateTest.java
@@ -5,23 +5,45 @@
 package com.android.tools.r8.desugar.desugaredlibrary;
 
 import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.SPECIFICATIONS_WITH_CF2CF;
-import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11_PATH;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
 import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
+import com.android.tools.r8.transformers.MethodTransformer;
 import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Collection;
 import java.util.List;
+import java.util.function.DoublePredicate;
+import java.util.function.DoubleUnaryOperator;
+import java.util.function.IntPredicate;
+import java.util.function.IntUnaryOperator;
+import java.util.function.LongPredicate;
+import java.util.function.LongUnaryOperator;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
+import java.util.stream.DoubleStream;
 import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+import java.util.stream.Stream;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 import org.junit.runners.Parameterized.Parameters;
+import org.objectweb.asm.Opcodes;
 
 @RunWith(Parameterized.class)
 public class IterateTest extends DesugaredLibraryTestBase {
 
-  private static final String EXPECTED_OUTPUT = StringUtils.lines("1");
+  private static final String EXPECTED_OUTPUT =
+      StringUtils.lines("1", "2", "1.0", "3", "1", "2", "1.0", "3");
 
   private final TestParameters parameters;
   private final LibraryDesugaringSpecification libraryDesugaringSpecification;
@@ -30,8 +52,12 @@
   @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
     return buildParameters(
-        getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(),
-        getJdk8Jdk11(),
+        getTestParameters()
+            .withCfRuntime(CfVm.JDK11)
+            .withDexRuntimes()
+            .withAllApiLevelsAlsoForCf()
+            .build(),
+        ImmutableList.of(JDK11, JDK11_PATH),
         SPECIFICATIONS_WITH_CF2CF);
   }
 
@@ -47,17 +73,107 @@
   @Test
   public void testIterable() throws Throwable {
     testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
-        .addInnerClasses(getClass())
+        .addProgramClassFileData(getProgramClassFileData())
+        .addProgramFiles(getOtherProgramClasses())
         .addKeepMainRule(Main.class)
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutput(EXPECTED_OUTPUT);
   }
 
+  private Collection<Path> getOtherProgramClasses() throws IOException {
+    Collection<Path> files = ToolHelper.getClassFilesForInnerClasses(getClass());
+    files.removeIf(p -> p.toString().endsWith("Main.class"));
+    return files;
+  }
+
+  private Collection<byte[]> getProgramClassFileData() throws IOException {
+    ImmutableMap<String, String> mapping =
+        ImmutableMap.of(
+            "com/android/tools/r8/desugar/desugaredlibrary/IterateTest$IntStreamStub",
+            "java/util/stream/IntStream",
+            "com/android/tools/r8/desugar/desugaredlibrary/IterateTest$StreamStub",
+            "java/util/stream/Stream",
+            "com/android/tools/r8/desugar/desugaredlibrary/IterateTest$LongStreamStub",
+            "java/util/stream/LongStream",
+            "com/android/tools/r8/desugar/desugaredlibrary/IterateTest$DoubleStreamStub",
+            "java/util/stream/DoubleStream");
+    return ImmutableList.of(
+        transformer(Main.class)
+            .addMethodTransformer(
+                new MethodTransformer() {
+                  @Override
+                  public void visitMethodInsn(
+                      int opcode,
+                      String owner,
+                      String name,
+                      String descriptor,
+                      boolean isInterface) {
+                    if (opcode == Opcodes.INVOKESTATIC && mapping.containsKey(owner)) {
+                      super.visitMethodInsn(
+                          opcode, mapping.get(owner), name, descriptor, isInterface);
+                      return;
+                    }
+                    super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+                  }
+                })
+            .transform());
+  }
+
   static class Main {
 
     public static void main(String[] args) {
-      IntStream iterate = IntStream.iterate(1, x -> x + 3);
-      System.out.println(iterate.findFirst().getAsInt());
+      noPredicate();
+      predicate();
+    }
+
+    private static void noPredicate() {
+      IntStream iterateInt = IntStream.iterate(1, x -> x + 3);
+      System.out.println(iterateInt.findFirst().getAsInt());
+      LongStream iterateLong = LongStream.iterate(2L, x -> x + 3);
+      System.out.println(iterateLong.findFirst().getAsLong());
+      DoubleStream iterateDouble = DoubleStream.iterate(1.0, x -> x + 3);
+      System.out.println(iterateDouble.findFirst().getAsDouble());
+      Stream<Integer> iterateObject = Stream.iterate(3, x -> x + 3);
+      System.out.println(iterateObject.findFirst().get());
+    }
+
+    private static void predicate() {
+      IntStream iterateInt = IntStreamStub.iterate(1, x -> x != 0, x -> x + 3);
+      System.out.println(iterateInt.findFirst().getAsInt());
+      LongStream iterateLong = LongStreamStub.iterate(2L, x -> x != 0, x -> x + 3);
+      System.out.println(iterateLong.findFirst().getAsLong());
+      DoubleStream iterateDouble = DoubleStreamStub.iterate(1.0, x -> x != 0, x -> x + 3);
+      System.out.println(iterateDouble.findFirst().getAsDouble());
+      Stream<Integer> iterateObject = StreamStub.iterate(3, x -> x != 0, x -> x + 3);
+      System.out.println(iterateObject.findFirst().get());
+    }
+  }
+
+  private interface IntStreamStub {
+
+    static IntStream iterate(int i, IntPredicate predicate, IntUnaryOperator operator) {
+      return null;
+    }
+  }
+
+  private interface LongStreamStub {
+
+    static LongStream iterate(long i, LongPredicate predicate, LongUnaryOperator operator) {
+      return null;
+    }
+  }
+
+  private interface DoubleStreamStub {
+
+    static DoubleStream iterate(double i, DoublePredicate predicate, DoubleUnaryOperator operator) {
+      return null;
+    }
+  }
+
+  private interface StreamStub<T> {
+
+    static <T> Stream<T> iterate(T o, Predicate<T> predicate, UnaryOperator<T> operator) {
+      return null;
     }
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MultiDexTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MultiDexTest.java
new file mode 100644
index 0000000..f5d5449
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MultiDexTest.java
@@ -0,0 +1,106 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.desugar.desugaredlibrary;
+
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11_PATH;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8;
+import static org.junit.Assert.assertFalse;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.google.common.collect.ImmutableList;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class MultiDexTest extends DesugaredLibraryTestBase {
+
+  private static final String[] JAR_NAMES =
+      new String[] {
+        "multidex-1.0.3.jar",
+        "multidex-instrumentation-1.0.3.jar",
+        "multidex-2.0.1.jar",
+        "multidex-instrumentation-2.0.0.jar"
+      };
+  private static final List<Path> MULTIDEX_JARS =
+      Arrays.stream(JAR_NAMES)
+          .map(jar -> Paths.get(ToolHelper.THIRD_PARTY_DIR + "multidex/" + jar))
+          .collect(Collectors.toList());
+
+  private final TestParameters parameters;
+  private final CompilationSpecification compilationSpecification;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+  private final Path multidexJar;
+
+  @Parameters(name = "{0}, spec: {1}, {2}, {3}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+        ImmutableList.of(JDK8, JDK11, JDK11_PATH),
+        ImmutableList.of(D8_L8DEBUG),
+        MULTIDEX_JARS);
+  }
+
+  public MultiDexTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification,
+      Path multidexJar) {
+    this.parameters = parameters;
+    this.compilationSpecification = compilationSpecification;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+    this.multidexJar = multidexJar;
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+        .addProgramFiles(multidexJar)
+        .compile()
+        .inspect(this::assertNoJ$Reference);
+  }
+
+  private void assertNoJ$Reference(CodeInspector inspector) {
+    String prefix = "j$";
+    for (FoundClassSubject clazz : inspector.allClasses()) {
+      clazz.forAllFields(f -> assertFalse(f.type().toString().startsWith(prefix)));
+      clazz.forAllMethods(
+          m -> {
+            if (m.hasCode()) {
+              for (InstructionSubject instruction : m.instructions()) {
+                if (instruction.isInvoke()) {
+                  DexMethod method = instruction.getMethod();
+                  for (DexType referencedType : method.getReferencedTypes()) {
+                    assertFalse(referencedType.toString().startsWith(prefix));
+                  }
+                  assertFalse(method.getHolderType().toString().startsWith(prefix));
+                }
+                if (instruction.isFieldAccess()) {
+                  DexField field = instruction.getField();
+                  assertFalse(field.getType().toString().startsWith(prefix));
+                }
+              }
+            }
+          });
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesMoveTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesMoveTest.java
new file mode 100644
index 0000000..97feb33
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesMoveTest.java
@@ -0,0 +1,80 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.desugar.desugaredlibrary.jdk11;
+
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11_PATH;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
+import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.StandardOpenOption;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class FilesMoveTest extends DesugaredLibraryTestBase {
+
+  private static final String EXPECTED_RESULT = StringUtils.lines("Hello");
+
+  private final TestParameters parameters;
+  private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+  private final CompilationSpecification compilationSpecification;
+
+  @Parameters(name = "{0}, spec: {1}, {2}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        // Skip Android 4.4.4 due to missing libjavacrypto.
+        getTestParameters()
+            .withDexRuntime(Version.V4_0_4)
+            .withDexRuntimesStartingFromIncluding(Version.V5_1_1)
+            .withAllApiLevels()
+            .build(),
+        ImmutableList.of(JDK11_PATH),
+        DEFAULT_SPECIFICATIONS);
+  }
+
+  public FilesMoveTest(
+      TestParameters parameters,
+      LibraryDesugaringSpecification libraryDesugaringSpecification,
+      CompilationSpecification compilationSpecification) {
+    this.parameters = parameters;
+    this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+    this.compilationSpecification = compilationSpecification;
+  }
+
+  @Test
+  public void test() throws Throwable {
+    testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+        .addInnerClasses(getClass())
+        .addKeepMainRule(TestClass.class)
+        .compile()
+        .withArt6Plus64BitsLib()
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED_RESULT);
+  }
+
+  public static class TestClass {
+
+    public static void main(String[] args) throws Throwable {
+      Path src = Files.createTempFile("src", ".txt");
+      Path dest = src.getParent().resolve("dest");
+      Files.write(src, "Hello".getBytes(StandardCharsets.UTF_8), StandardOpenOption.WRITE);
+      Files.move(src, dest, StandardCopyOption.ATOMIC_MOVE);
+      System.out.println(Files.readAllLines(dest).get(0));
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesTest.java
index 9508e8c..cef3785 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesTest.java
@@ -18,6 +18,7 @@
 import java.nio.ByteBuffer;
 import java.nio.channels.FileChannel;
 import java.nio.channels.SeekableByteChannel;
+import java.nio.file.DirectoryStream;
 import java.nio.file.Files;
 import java.nio.file.LinkOption;
 import java.nio.file.OpenOption;
@@ -28,6 +29,7 @@
 import java.nio.file.attribute.PosixFileAttributes;
 import java.nio.file.attribute.PosixFilePermission;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -50,7 +52,10 @@
           "null",
           "true",
           "unsupported",
-          "j$.nio.file.attribute");
+          "j$.nio.file.attribute",
+          "tmp",
+          "/",
+          "true");
   private static final String EXPECTED_RESULT_DESUGARING_FILE_SYSTEM_PLATFORM_CHANNEL =
       StringUtils.lines(
           "bytes written: 11",
@@ -62,7 +67,10 @@
           "null",
           "true",
           "unsupported",
-          "j$.nio.file.attribute");
+          "j$.nio.file.attribute",
+          "tmp",
+          "/",
+          "true");
   private static final String EXPECTED_RESULT_PLATFORM_FILE_SYSTEM_DESUGARING =
       StringUtils.lines(
           "bytes written: 11",
@@ -74,7 +82,10 @@
           "true",
           "true",
           "true",
-          "j$.nio.file.attribute");
+          "j$.nio.file.attribute",
+          "tmp",
+          "/",
+          "true");
   private static final String EXPECTED_RESULT_PLATFORM_FILE_SYSTEM =
       StringUtils.lines(
           "bytes written: 11",
@@ -86,7 +97,10 @@
           "true",
           "true",
           "true",
-          "java.nio.file.attribute");
+          "java.nio.file.attribute",
+          "tmp",
+          "/",
+          "true");
 
   private final TestParameters parameters;
   private final LibraryDesugaringSpecification libraryDesugaringSpecification;
@@ -144,6 +158,18 @@
       readThroughFileChannelAPI(path);
       attributeAccess(path);
       fspMethodsWithGeneric(path);
+      pathGeneric();
+    }
+
+    private static void pathGeneric() throws IOException {
+      Path tmpDict = Files.createTempDirectory("tmpDict");
+      Path tmpFile = Files.createFile(tmpDict.resolve("tmpFile"));
+      Iterator<Path> iterator = tmpDict.iterator();
+      System.out.println(iterator.next());
+      Iterable<Path> rootDirectories = tmpFile.getFileSystem().getRootDirectories();
+      System.out.println(rootDirectories.iterator().next());
+      DirectoryStream<Path> paths = Files.newDirectoryStream(tmpDict);
+      System.out.println(paths.iterator().hasNext());
     }
 
     private static void fspMethodsWithGeneric(Path path) throws IOException {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java
index 468494f..2a07cfb 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java
@@ -126,11 +126,11 @@
   private void testMultiLevelUsingMain(LibraryDesugaringSpecification spec) throws IOException {
     Assume.assumeTrue(ToolHelper.isLocalDevelopment());
 
-    Path output = temp.newFile().toPath();
-    DesugaredLibraryConverter.convertMultiLevelAnythingToMachineSpecification(
-        spec.getSpecification(), spec.getDesugarJdkLibs(), spec.getLibraryFiles(), output);
-
     InternalOptions options = new InternalOptions();
+
+    Path output = temp.newFile().toPath();
+    convertMultiLevelAnythingToMachineSpecification(spec, output, options);
+
     MachineDesugaredLibrarySpecification machineSpecParsed =
         new MachineDesugaredLibrarySpecificationParser(
                 options.dexItemFactory(),
@@ -142,6 +142,33 @@
     assertFalse(machineSpecParsed.getRewriteType().isEmpty());
   }
 
+  public void convertMultiLevelAnythingToMachineSpecification(
+      LibraryDesugaringSpecification spec, Path output, InternalOptions options)
+      throws IOException {
+
+    MultiAPILevelHumanDesugaredLibrarySpecification humanSpec =
+        DesugaredLibraryConverter.convertMultiLevelAnythingToMachineSpecification(
+            spec.getSpecification(),
+            spec.getDesugarJdkLibs(),
+            spec.getLibraryFiles(),
+            output,
+            options);
+
+    if (humanSpec == null) {
+      return;
+    }
+
+    // Validate the written spec is the read spec.
+    Box<String> json = new Box<>();
+    MultiAPILevelHumanDesugaredLibrarySpecificationJsonExporter.export(
+        humanSpec, ((string, handler) -> json.set(string)));
+    MultiAPILevelHumanDesugaredLibrarySpecification writtenHumanSpec =
+        new MultiAPILevelHumanDesugaredLibrarySpecificationParser(
+                options.dexItemFactory(), options.reporter)
+            .parseMultiLevelConfiguration(StringResource.fromString(json.get(), Origin.unknown()));
+    assertSpecEquals(humanSpec, writtenHumanSpec);
+  }
+
   @Test
   public void testSingleLevel() throws IOException {
     Assume.assumeTrue(ToolHelper.isLocalDevelopment());
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java
index 8085bf6..6245fec 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java
@@ -34,9 +34,9 @@
 public class LibraryDesugaringSpecification {
 
   public static Descriptor JDK8_DESCRIPTOR = new Descriptor(24, 26, -1, 26, 24);
-  public static Descriptor JDK11_DESCRIPTOR = new Descriptor(24, 26, -1, 32, -1);
+  public static Descriptor JDK11_DESCRIPTOR = new Descriptor(24, 26, -1, 10000, -1);
   public static Descriptor EMPTY_DESCRIPTOR_24 = new Descriptor(-1, -1, -1, 24, -1);
-  public static Descriptor JDK11_PATH_DESCRIPTOR = new Descriptor(24, 26, 26, 32, -1);
+  public static Descriptor JDK11_PATH_DESCRIPTOR = new Descriptor(24, 26, 26, 10000, -1);
   public static Descriptor JDK11_LEGACY_DESCRIPTOR = new Descriptor(10000, 10000, -1, 10000, 24);
 
   private static class Descriptor {
diff --git a/src/test/java/com/android/tools/r8/graph/MissingClassThrowingTest.java b/src/test/java/com/android/tools/r8/graph/MissingClassThrowingTest.java
index 78b83da..333ab92 100644
--- a/src/test/java/com/android/tools/r8/graph/MissingClassThrowingTest.java
+++ b/src/test/java/com/android/tools/r8/graph/MissingClassThrowingTest.java
@@ -76,9 +76,7 @@
                 .compileWithExpectedDiagnostics(
                     diagnostics ->
                         diagnostics
-                            .assertNoInfos()
-                            // TODO(b/251482856): When missing class is not an error this throws
-                            //  for unverifiable code. Is that expected?
+                            .assertOnlyErrors()
                             .inspectErrors(
                                 diagnostic ->
                                     diagnostic
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/reflection/InnerClassNameTestRunner.java b/src/test/java/com/android/tools/r8/ir/optimize/reflection/InnerClassNameTestRunner.java
index 8b33acb..374fb98 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/reflection/InnerClassNameTestRunner.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/reflection/InnerClassNameTestRunner.java
@@ -225,12 +225,16 @@
     R8TestCompileResult r8CompileResult =
         testForR8(parameters.getBackend())
             .addKeepMainRule(MAIN_CLASS)
-            .addKeepRules("-keep,allowobfuscation class * { *; }")
-            .addKeepRules("-keepattributes InnerClasses,EnclosingMethod")
+            .addKeepAllClassesRuleWithAllowObfuscation()
+            .addKeepAttributeInnerClassesAndEnclosingMethod()
             .addProgramClassFileData(InnerClassNameTestDump.dump(config, parameters))
             .allowDiagnosticInfoMessages(hasMalformedInnerClassAttribute())
             .minification(minify)
-            .addOptionsModification(InternalOptions::disableNameReflectionOptimization)
+            .addOptionsModification(
+                options -> {
+                  options.disableInnerClassSeparatorValidationWhenRepackaging = true;
+                  options.disableNameReflectionOptimization();
+                })
             .setMinApi(parameters.getApiLevel())
             .compile()
             .apply(this::checkWarningsAboutMalformedAttribute);
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingFrontierTest.java b/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingFrontierTest.java
new file mode 100644
index 0000000..2584946
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingFrontierTest.java
@@ -0,0 +1,136 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.memberrebinding;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.SingleTestRunResult;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestCompileResult;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeMatchers;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class MemberRebindingFrontierTest extends TestBase {
+
+  @Parameter() public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  @Test
+  public void testD8() throws Exception {
+    assumeTrue(parameters.isDexRuntime());
+    testForD8(parameters.getBackend())
+        .addProgramClasses(Main.class, ProgramClass.class)
+        .addDefaultRuntimeLibrary(parameters)
+        .addLibraryClasses(Base.class, I.class)
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .apply(this::setupRunclasspath)
+        .run(parameters.getRuntime(), Main.class)
+        .apply(result -> checkOutput(result, false));
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramClasses(Main.class, ProgramClass.class)
+        .addProgramClassFileData()
+        .addDefaultRuntimeLibrary(parameters)
+        .addLibraryClasses(I.class)
+        .addLibraryClassFileData(removeFooMethod(Base.class))
+        .setMinApi(parameters.getApiLevel())
+        .addKeepClassRules(ProgramClass.class)
+        .addKeepMainRule(Main.class)
+        .compile()
+        .apply(this::setupRunclasspath)
+        .inspect(
+            inspector -> {
+              // TODO(b/254510678): We should not rebind to I.foo
+              ClassSubject mainClass = inspector.clazz(Main.class);
+              assertThat(mainClass, isPresent());
+              MethodSubject foo = mainClass.mainMethod();
+              assertThat(
+                  foo, CodeMatchers.invokesMethodWithHolderAndName(typeName(I.class), "foo"));
+            })
+        .run(parameters.getRuntime(), Main.class)
+        .apply(result -> checkOutput(result, true));
+  }
+
+  private byte[] removeFooMethod(Class<?> clazz) throws Exception {
+    return transformer(clazz).removeMethodsWithName("foo").transform();
+  }
+
+  private void setupRunclasspath(TestCompileResult<?, ?> compileResult) {
+    compileResult
+        .applyIf(
+            parameters.canUseDefaultAndStaticInterfaceMethods(),
+            result ->
+                result
+                    .addRunClasspathClasses(I.class)
+                    .addRunClasspathClassFileData(removeFooMethod(Base.class)))
+        .applyIf(
+            !parameters.canUseDefaultAndStaticInterfaceMethods(),
+            result ->
+                result
+                    .addRunClasspathClasses(Base.class)
+                    .addRunClasspathClassFileData(removeFooMethod(I.class)));
+  }
+
+  private void checkOutput(SingleTestRunResult<?> runResult, boolean r8) {
+    if (parameters.canUseDefaultAndStaticInterfaceMethods()) {
+      runResult.assertSuccessWithOutputLines("I::foo");
+      return;
+    }
+    // TODO(b/254510678): We should not rebind to I.foo
+    if (r8) {
+      runResult.assertFailureWithErrorThatThrows(NoSuchMethodError.class);
+    } else {
+      runResult.assertSuccessWithOutputLines("Base::foo");
+    }
+  }
+
+  private interface I {
+
+    // Introduced at a later api level.
+    default void foo() {
+      System.out.println("I::foo");
+    }
+  }
+
+  public abstract static class Base {
+
+    // Was present until moved into I at some api level.
+    public void foo() {
+      System.out.println("Base::foo");
+    }
+  }
+
+  public static class ProgramClass extends Base implements I {}
+
+  public static class Main {
+
+    public static void main(String[] args) {
+      callFoo(new ProgramClass());
+    }
+
+    private static void callFoo(ProgramClass clazz) {
+      clazz.foo();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/naming/KeepPackageNamesTest.java b/src/test/java/com/android/tools/r8/naming/KeepPackageNamesTest.java
index bb73c3f..5eb7783 100644
--- a/src/test/java/com/android/tools/r8/naming/KeepPackageNamesTest.java
+++ b/src/test/java/com/android/tools/r8/naming/KeepPackageNamesTest.java
@@ -99,4 +99,14 @@
         .compile()
         .inspect(config::inspect);
   }
+
+  @Test
+  public void testR8Compat() throws Exception {
+    testForR8Compat(Backend.DEX)
+        .addProgramClasses(CLASSES)
+        .addKeepAllClassesRuleWithAllowObfuscation()
+        .addKeepRules(config.getKeepRule())
+        .compile()
+        .inspect(config::inspect);
+  }
 }
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 487498f..fa9de18 100644
--- a/src/test/java/com/android/tools/r8/naming/PackageNamingTest.java
+++ b/src/test/java/com/android/tools/r8/naming/PackageNamingTest.java
@@ -356,13 +356,11 @@
         ba.getDexProgramClass().getType().getPackageName(),
         bb.getDexProgramClass().getType().getPackageName());
 
-    // We cannot repackage c or d since these have package-private members and a
-    // keep,allowobfuscation. For us to be able to repackage them, we have to use
-    // -allowaccesmodification.
+    // We can repackage c and d since these have no external package-private references.
     List<String> klasses = ImmutableList.of("naming101.c", "naming101.d");
     for (String klass : klasses) {
       ClassSubject k = inspector.clazz(klass);
-      assertNotEquals("naming101.a", k.getDexProgramClass().getType().getPackageName());
+      assertEquals("naming101.a", k.getDexProgramClass().getType().getPackageName());
     }
 
     // All other classes can be repackaged to naming101.a, but naming101.a.a exists to make a name
diff --git a/src/test/java/com/android/tools/r8/naming/keeppackagenames/KeepPackageNameRootTest.java b/src/test/java/com/android/tools/r8/naming/keeppackagenames/KeepPackageNameRootTest.java
index 309ab55..e7c14ff 100644
--- a/src/test/java/com/android/tools/r8/naming/keeppackagenames/KeepPackageNameRootTest.java
+++ b/src/test/java/com/android/tools/r8/naming/keeppackagenames/KeepPackageNameRootTest.java
@@ -9,7 +9,6 @@
 
 import com.android.tools.r8.ProguardVersion;
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.TestCompileResult;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.TestShrinkerBuilder;
@@ -34,22 +33,22 @@
 
   @Test
   public void testR8Compat() throws Exception {
-    run(testForR8Compat(Backend.CF));
+    run(testForR8Compat(Backend.CF), false);
   }
 
   @Test
   public void testR8Full() throws Exception {
-    run(testForR8(Backend.CF));
+    run(testForR8(Backend.CF), true);
   }
 
   @Test
   public void testR8PG() throws Exception {
-    run(testForProguard(ProguardVersion.V7_0_0).addKeepRules("-dontwarn"));
+    run(testForProguard(ProguardVersion.V7_0_0).addKeepRules("-dontwarn"), false);
   }
 
-  private TestCompileResult<?, ?> run(TestShrinkerBuilder<?, ?, ?, ?, ?> testBuilder)
+  private void run(TestShrinkerBuilder<?, ?, ?, ?, ?> testBuilder, boolean isFullMode)
       throws Exception {
-    return testBuilder
+    testBuilder
         .addProgramClassFileData(
             transformer(Main.class)
                 .setClassDescriptor("Lfoo/Main;")
@@ -64,7 +63,11 @@
               assertEquals(1, inspector.allClasses().size());
               inspector.forAllClasses(
                   clazz -> {
-                    assertNotEquals("foo", clazz.getDexProgramClass().getType().getPackageName());
+                    if (isFullMode) {
+                      assertEquals("foo", clazz.getDexProgramClass().getType().getPackageName());
+                    } else {
+                      assertNotEquals("foo", clazz.getDexProgramClass().getType().getPackageName());
+                    }
                   });
             });
   }
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/StackTrace.java b/src/test/java/com/android/tools/r8/naming/retrace/StackTrace.java
index 1619359..87698d9 100644
--- a/src/test/java/com/android/tools/r8/naming/retrace/StackTrace.java
+++ b/src/test/java/com/android/tools/r8/naming/retrace/StackTrace.java
@@ -163,6 +163,16 @@
         return this;
       }
 
+      public Builder applyIf(
+          boolean condition, Consumer<Builder> trueConsumer, Consumer<Builder> elseConsumer) {
+        if (condition) {
+          trueConsumer.accept(this);
+        } else {
+          elseConsumer.accept(this);
+        }
+        return this;
+      }
+
       public StackTraceLine build() {
         String lineNumberPart = lineNumber >= 0 ? ":" + lineNumber : "";
         String originalLine = className + '.' + methodName + '(' + fileName + lineNumberPart + ')';
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/VerticalClassMergingRetraceTest.java b/src/test/java/com/android/tools/r8/naming/retrace/VerticalClassMergingRetraceTest.java
index fc1e432..9e361e6 100644
--- a/src/test/java/com/android/tools/r8/naming/retrace/VerticalClassMergingRetraceTest.java
+++ b/src/test/java/com/android/tools/r8/naming/retrace/VerticalClassMergingRetraceTest.java
@@ -130,7 +130,6 @@
     // at com.android.tools.r8.naming.retraceproguard.MainApp.main(MainApp.java:7)
     //
     // We should instead translate to:
-    // at com.android.tools.r8.naming.retraceproguard.ResourceWrapper.foo(ResourceWrapper.java:1)
     // at com.android.tools.r8.naming.retraceproguard.ResourceWrapper.foo(ResourceWrapper.java:0)
     // at com.android.tools.r8.naming.retraceproguard.MainApp.main(MainApp.java:7)
     // since the synthetic bridge belongs to ResourceWrapper.foo.
@@ -140,12 +139,7 @@
     runTest(
         ImmutableList.of(),
         (StackTrace actualStackTrace, StackTrace retracedStackTrace) -> {
-          StackTrace reprocessedStackTrace =
-              mode == CompilationMode.DEBUG
-                  ? retracedStackTrace
-                  : retracedStackTrace.filter(this::filterSynthesizedBridgeMethod);
-          assertThat(
-              reprocessedStackTrace, isSameExceptForFileNameAndLineNumber(expectedStackTrace));
+          assertThat(retracedStackTrace, isSameExceptForFileNameAndLineNumber(expectedStackTrace));
           assertEquals(
               expectedActualStackTraceHeight(), actualStackTrace.getStackTraceLines().size());
         });
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageAllowRepackagingTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageAllowRepackagingTest.java
new file mode 100644
index 0000000..686be1d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageAllowRepackagingTest.java
@@ -0,0 +1,64 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.repackage;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.TestParameters;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class RepackageAllowRepackagingTest extends RepackageTestBase {
+
+  public RepackageAllowRepackagingTest(
+      String flattenPackageHierarchyOrRepackageClasses, TestParameters parameters) {
+    super(flattenPackageHierarchyOrRepackageClasses, parameters);
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(getClass())
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(Main.class)
+        .apply(this::configureRepackaging)
+        .addKeepRules(
+            "-keep,allowrepackage class " + typeName(ShouldStayInPackage.class) + " { *; }")
+        .addKeepRules(
+            "-keep,allowrepackage class " + typeName(ShouldBeRepackaged.class) + " { *; }")
+        .compile()
+        .inspect(
+            inspector -> {
+              assertThat(ShouldStayInPackage.class, isNotRepackaged(inspector));
+              assertThat(ShouldBeRepackaged.class, isRepackaged(inspector));
+            })
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines("ShouldStayInPackage::foo", "ShouldBeRepackaged::bar");
+  }
+
+  public static class ShouldStayInPackage {
+
+    static void foo() {
+      System.out.println("ShouldStayInPackage::foo");
+    }
+  }
+
+  public static class ShouldBeRepackaged {
+
+    public static void bar() {
+      System.out.println("ShouldBeRepackaged::bar");
+    }
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) {
+      ShouldStayInPackage.foo();
+      ShouldBeRepackaged.bar();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageKeepPackageNameTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageKeepPackageNameTest.java
new file mode 100644
index 0000000..bcffb5f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageKeepPackageNameTest.java
@@ -0,0 +1,73 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.repackage;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.R8TestCompileResult;
+import com.android.tools.r8.TestParameters;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class RepackageKeepPackageNameTest extends RepackageTestBase {
+
+  public RepackageKeepPackageNameTest(
+      String flattenPackageHierarchyOrRepackageClasses, TestParameters parameters) {
+    super(flattenPackageHierarchyOrRepackageClasses, parameters);
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    R8TestCompileResult compileLib =
+        testForR8(parameters.getBackend())
+            .addInnerClasses(getClass())
+            .setMinApi(parameters.getApiLevel())
+            .addKeepClassAndMembersRulesWithAllowObfuscation(
+                ShouldStayInPackage.class, ShouldBeRepackaged.class)
+            .addKeepPackageNamesRule(typeName(ShouldStayInPackage.class))
+            .apply(this::configureRepackaging)
+            .compile()
+            .inspect(
+                inspector -> {
+                  assertThat(ShouldStayInPackage.class, isNotRepackaged(inspector));
+                  assertThat(ShouldBeRepackaged.class, isRepackaged(inspector));
+                });
+
+    testForR8(parameters.getBackend())
+        .addProgramClasses(Runner.class)
+        .addClasspathClasses(ShouldStayInPackage.class, ShouldBeRepackaged.class)
+        .addApplyMapping(compileLib.getProguardMap())
+        .addKeepMainRule(Runner.class)
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .addRunClasspathFiles(compileLib.writeToZip())
+        .run(parameters.getRuntime(), Runner.class)
+        .assertSuccessWithOutputLines("ShouldStayInPackage::foo", "ShouldBeRepackaged::bar");
+  }
+
+  public static class ShouldStayInPackage {
+
+    static void foo() {
+      System.out.println("ShouldStayInPackage::foo");
+    }
+  }
+
+  public static class ShouldBeRepackaged {
+
+    public static void bar() {
+      System.out.println("ShouldBeRepackaged::bar");
+    }
+  }
+
+  public static class Runner {
+
+    public static void main(String[] args) {
+      ShouldStayInPackage.foo();
+      ShouldBeRepackaged.bar();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageProtectedInSamePackageTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageProtectedInSamePackageTest.java
index a6c9ea3..8152688 100644
--- a/src/test/java/com/android/tools/r8/repackage/RepackageProtectedInSamePackageTest.java
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageProtectedInSamePackageTest.java
@@ -45,7 +45,7 @@
         .addKeepMainRule(Main.class)
         .addDontWarn(RepackageProtectedInSamePackageTest.class, NeverClassInline.class)
         .run(parameters.getRuntime(), Main.class, typeName(RepackageForKeepClassMembers.class))
-        .inspect(inspector -> inspect(inspector, true))
+        .inspect(this::inspect)
         .assertSuccessWithOutputLines(EXPECTED);
   }
 
@@ -61,7 +61,7 @@
         .addKeepMainRule(Main.class)
         .enableNeverClassInliningAnnotations()
         .run(parameters.getRuntime(), Main.class)
-        .inspect(inspector -> inspect(inspector, false))
+        .inspect(this::inspect)
         .assertSuccessWithOutputLines(EXPECTED);
   }
 
@@ -82,16 +82,10 @@
         .transform();
   }
 
-  private void inspect(CodeInspector inspector, boolean isProguard) {
+  private void inspect(CodeInspector inspector) {
     ClassSubject clazz = inspector.clazz(RepackageForKeepClassMembers.class);
     assertThat(clazz, isPresent());
-    // TODO(b/250671873): We should be able to repackage the Sub class since the only reference
-    //  to Sub.class is in the same package and we have allowobfuscation.
-    if (isProguard) {
-      assertThat(RepackageForKeepClassMembers.class, isRepackaged(inspector));
-    } else {
-      assertThat(RepackageForKeepClassMembers.class, isNotRepackaged(inspector));
-    }
+    assertThat(RepackageForKeepClassMembers.class, isRepackaged(inspector));
     assertThat(clazz.uniqueFieldWithOriginalName("hashCodeCache"), isPresentAndNotRenamed());
     assertThat(clazz.uniqueMethodWithOriginalName("calculateHashCode"), isPresentAndNotRenamed());
   }
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageTest.java
index 179845d..9742b6a 100644
--- a/src/test/java/com/android/tools/r8/repackage/RepackageTest.java
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageTest.java
@@ -163,18 +163,16 @@
 
     // 3.A, 3.B, 3.C) Accessing a kept method is OK.
     markShouldAlwaysBeEligible.accept(AccessPublicKeptMethodOnReachableClass.class);
-    markEligibleWithAllowAccessModification.accept(
-        AccessPackagePrivateKeptMethodOnReachableClassDirect.class);
-    markEligibleWithAllowAccessModification.accept(
-        AccessPackagePrivateKeptMethodOnReachableClassIndirect.class);
+    markShouldAlwaysBeEligible.accept(AccessPackagePrivateKeptMethodOnReachableClassDirect.class);
+    markShouldAlwaysBeEligible.accept(AccessPackagePrivateKeptMethodOnReachableClassIndirect.class);
 
     // 4) -keepclassmembers,allowobfuscation class ReachableClassWithKeptMethod { <methods>; }
 
     // 4.A, 4.B, 4.C) Accessing a kept method is OK.
     markShouldAlwaysBeEligible.accept(AccessPublicKeptMethodAllowRenamingOnReachableClass.class);
-    markEligibleWithAllowAccessModification.accept(
+    markShouldAlwaysBeEligible.accept(
         AccessPackagePrivateKeptMethodAllowRenamingOnReachableClassDirect.class);
-    markEligibleWithAllowAccessModification.accept(
+    markShouldAlwaysBeEligible.accept(
         AccessPackagePrivateKeptMethodAllowRenamingOnReachableClassIndirect.class);
 
     // 5) No keep rule.
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageWithKeepPackagePrivateTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageWithKeepPackagePrivateTest.java
index 8020e78..6f79b12 100644
--- a/src/test/java/com/android/tools/r8/repackage/RepackageWithKeepPackagePrivateTest.java
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageWithKeepPackagePrivateTest.java
@@ -76,8 +76,8 @@
   }
 
   private void inspect(CodeInspector inspector) {
-    assertThat(A.class, isRepackagedIf(inspector, allowAccessModification));
-    assertThat(B.class, isRepackagedIf(inspector, allowAccessModification));
+    assertThat(A.class, isNotRepackaged(inspector));
+    assertThat(B.class, isNotRepackaged(inspector));
   }
 
   public static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/retrace/OverloadsWithoutLineNumberTest.java b/src/test/java/com/android/tools/r8/retrace/OverloadsWithoutLineNumberTest.java
index 3aa2f49..2ba06ba 100644
--- a/src/test/java/com/android/tools/r8/retrace/OverloadsWithoutLineNumberTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/OverloadsWithoutLineNumberTest.java
@@ -63,21 +63,11 @@
             .setRetracedStackTraceConsumer(box::set)
             .setVerbose(true);
     Retrace.run(builder.build());
-    // TODO(b/221015863): This should ideally be:
-    // at " + typeName(ClassWithOverload.class) + ".test(int)(OverloadsWithoutLineNumberTest.java)
-    if (parameters.canUseNativeDexPC()) {
-      assertEquals(
-          "\tat "
-              + typeName(ClassWithOverload.class)
-              + ".test(OverloadsWithoutLineNumberTest.java:0)",
-          box.get().get(1));
-    } else {
-      assertEquals(
-          "\tat "
-              + typeName(ClassWithOverload.class)
-              + ".test(OverloadsWithoutLineNumberTest.java)",
-          box.get().get(1));
-    }
+    assertEquals(
+        "\tat "
+            + typeName(ClassWithOverload.class)
+            + ".void test(int)(OverloadsWithoutLineNumberTest.java:0)",
+        box.get().get(1));
   }
 
   public static class ClassWithOverload {
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceStackTraceFunctionalCompositionTest.java b/src/test/java/com/android/tools/r8/retrace/RetraceStackTraceFunctionalCompositionTest.java
index 9d9d7a4..7513419 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceStackTraceFunctionalCompositionTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceStackTraceFunctionalCompositionTest.java
@@ -157,7 +157,7 @@
     return rewrittenR8Jar;
   }
 
-  @Ignore("b/251677184: Failing since update to target 11")
+  @Ignore("b/255292908")
   @Test
   public void testR8RetraceAndComposition() throws Exception {
     Path rewrittenR8Jar = getRewrittenR8Jar();
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceSynthesizedInnerFrameTest.java b/src/test/java/com/android/tools/r8/retrace/RetraceSynthesizedInnerFrameTest.java
new file mode 100644
index 0000000..b1ce233
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceSynthesizedInnerFrameTest.java
@@ -0,0 +1,73 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.retrace;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.references.Reference;
+import java.util.List;
+import java.util.OptionalInt;
+import java.util.stream.Collectors;
+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 RetraceSynthesizedInnerFrameTest extends TestBase {
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withNoneRuntime().build();
+  }
+
+  public RetraceSynthesizedInnerFrameTest(TestParameters parameters) {
+    parameters.assertNoneRuntime();
+  }
+
+  private static final String mapping =
+      "# { id: 'com.android.tools.r8.mapping', version: '1.0' }\n"
+          + "some.Class -> a:\n"
+          + "  3:3:int other.strawberry(int):101:101 -> a\n"
+          + "  # { id: 'com.android.tools.r8.synthesized' }\n"
+          + "  3:3:int mango(float):28 -> a";
+
+  @Test
+  public void testSyntheticClass() {
+    List<RetraceFrameElement> frameResults =
+        Retracer.createDefault(ProguardMapProducer.fromString(mapping), new DiagnosticsHandler() {})
+            .retraceClass(Reference.classFromTypeName("a"))
+            .stream()
+            .flatMap(
+                element ->
+                    element
+                        .lookupFrame(RetraceStackTraceContext.empty(), OptionalInt.of(3), "a")
+                        .stream())
+            .collect(Collectors.toList());
+    assertEquals(1, frameResults.size());
+    RetraceFrameElement retraceFrameElement = frameResults.get(0);
+    List<RetracedMethodReference> allFrames =
+        retraceFrameElement.stream()
+            .map(RetracedSingleFrame::getMethodReference)
+            .collect(Collectors.toList());
+    assertEquals(2, allFrames.size());
+    List<RetracedMethodReference> nonSyntheticFrames =
+        retraceFrameElement
+            .streamRewritten(RetraceStackTraceContext.empty())
+            .map(RetracedSingleFrame::getMethodReference)
+            .collect(Collectors.toList());
+    // The input should never have a synthesized inline frame - rater it should have been removed
+    // from the mapping output. Because of the incorrect input we now attribute the synthesized
+    // information to the entire inline block.
+    assertEquals(1, nonSyntheticFrames.size());
+    assertEquals(
+        Reference.methodFromDescriptor("Lother;", "strawberry", "(I)I"),
+        nonSyntheticFrames.get(0).asKnown().getMethodReference());
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/StackTraceWithPcAndNoLineTableTestRunner.java b/src/test/java/com/android/tools/r8/retrace/StackTraceWithPcAndNoLineTableTestRunner.java
index 6783fa7..47c1d91 100644
--- a/src/test/java/com/android/tools/r8/retrace/StackTraceWithPcAndNoLineTableTestRunner.java
+++ b/src/test/java/com/android/tools/r8/retrace/StackTraceWithPcAndNoLineTableTestRunner.java
@@ -61,24 +61,12 @@
               assertEquals(
                   "SourceFile",
                   inspector.clazz(getTestClass()).getDexProgramClass().sourceFile.toString());
-              // The stack-trace should not have line numbers unless on a VM with DEX PC support.
+              // TODO(b/202919530): The stack-trace should have line positions since they are
+              //  essentially free when compiling for dex.
               if (parameters.isDexRuntime()
                   && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V8_1_0)) {
-                if (parameters
-                    .getApiLevel()
-                    .isGreaterThanOrEqualTo(apiLevelWithPcAsLineNumberSupport())) {
-                  // TODO(b/202919530): With PC support it should retrace.
-                  assertThat(
-                      stacktrace,
-                      StackTrace.isSameExceptForLineNumbers(getExpectedStackTrace(true)));
-                } else {
-                  // Compiling for an API level before PC support it may be unfeasible to include
-                  // the mapping information due to mapping size increase. That is up for
-                  // discussion.
-                  assertThat(
-                      stacktrace,
-                      StackTrace.isSameExceptForLineNumbers(getExpectedStackTrace(true)));
-                }
+                assertThat(
+                    stacktrace, StackTrace.isSameExceptForLineNumbers(getExpectedStackTrace(true)));
               } else {
                 // Having stripped the line-number table, the raw stack will not have line info.
                 assertThat(stacktrace, StackTrace.isSame(getExpectedStackTrace(false)));
@@ -95,14 +83,30 @@
                 .setClassName(className)
                 .setFileName(sourceFile)
                 .setMethodName("foo")
-                .applyIf(withLines, b -> b.setLineNumber(10))
+                .applyIf(
+                    withLines,
+                    b -> b.setLineNumber(10),
+                    b -> {
+                      if (parameters.isDexRuntime()) {
+                        // TODO(b/255705077): Should not have position 0.
+                        b.setLineNumber(0);
+                      }
+                    })
                 .build())
         .add(
             StackTraceLine.builder()
                 .setClassName(className)
                 .setFileName(sourceFile)
                 .setMethodName("bar")
-                .applyIf(withLines, b -> b.setLineNumber(15))
+                .applyIf(
+                    withLines,
+                    b -> b.setLineNumber(15),
+                    b -> {
+                      if (parameters.isDexRuntime()) {
+                        // TODO(b/255705077): Should not have position 0.
+                        b.setLineNumber(0);
+                      }
+                    })
                 .build())
         .add(
             StackTraceLine.builder()
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiSynthesizedInnerFrameTest.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiSynthesizedInnerFrameTest.java
deleted file mode 100644
index 1b10739..0000000
--- a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiSynthesizedInnerFrameTest.java
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.retrace.api;
-
-import static org.junit.Assert.assertEquals;
-
-import com.android.tools.r8.DiagnosticsHandler;
-import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.references.Reference;
-import com.android.tools.r8.retrace.ProguardMapProducer;
-import com.android.tools.r8.retrace.RetraceFrameElement;
-import com.android.tools.r8.retrace.RetraceStackTraceContext;
-import com.android.tools.r8.retrace.RetracedMethodReference;
-import com.android.tools.r8.retrace.RetracedSingleFrame;
-import com.android.tools.r8.retrace.Retracer;
-import java.util.List;
-import java.util.OptionalInt;
-import java.util.stream.Collectors;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-@RunWith(Parameterized.class)
-public class RetraceApiSynthesizedInnerFrameTest extends RetraceApiTestBase {
-
-  public RetraceApiSynthesizedInnerFrameTest(TestParameters parameters) {
-    super(parameters);
-  }
-
-  @Override
-  protected Class<? extends RetraceApiBinaryTest> binaryTestClass() {
-    return ApiTest.class;
-  }
-
-  public static class ApiTest implements RetraceApiBinaryTest {
-
-    private final String mapping =
-        "# { id: 'com.android.tools.r8.mapping', version: '1.0' }\n"
-            + "some.Class -> a:\n"
-            + "  3:3:int other.strawberry(int):101:101 -> a\n"
-            + "  # { id: 'com.android.tools.r8.synthesized' }\n"
-            + "  3:3:int mango(float):28 -> a";
-
-    @Test
-    public void testSyntheticClass() {
-      List<RetraceFrameElement> frameResults =
-          Retracer.createDefault(
-                  ProguardMapProducer.fromString(mapping), new DiagnosticsHandler() {})
-              .retraceClass(Reference.classFromTypeName("a"))
-              .stream()
-              .flatMap(
-                  element ->
-                      element
-                          .lookupFrame(RetraceStackTraceContext.empty(), OptionalInt.of(3), "a")
-                          .stream())
-              .collect(Collectors.toList());
-      assertEquals(1, frameResults.size());
-      RetraceFrameElement retraceFrameElement = frameResults.get(0);
-      List<RetracedMethodReference> allFrames =
-          retraceFrameElement.stream()
-              .map(RetracedSingleFrame::getMethodReference)
-              .collect(Collectors.toList());
-      assertEquals(2, allFrames.size());
-      List<RetracedMethodReference> nonSyntheticFrames =
-          retraceFrameElement
-              .streamRewritten(RetraceStackTraceContext.empty())
-              .map(RetracedSingleFrame::getMethodReference)
-              .collect(Collectors.toList());
-      assertEquals(allFrames, nonSyntheticFrames);
-    }
-  }
-}
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestCollection.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestCollection.java
index 5b20d00..c233d49 100644
--- a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestCollection.java
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestCollection.java
@@ -28,7 +28,6 @@
           RetraceApiSynthesizedFieldTest.ApiTest.class,
           RetraceApiSynthesizedMethodTest.ApiTest.class,
           RetraceApiSynthesizedFrameTest.ApiTest.class,
-          RetraceApiSynthesizedInnerFrameTest.ApiTest.class,
           RetraceApiUnknownJsonTest.ApiTest.class,
           RetraceApiRewriteFrameInlineNpeTest.ApiTest.class,
           RetraceApiAmbiguousOriginalRangeTest.ApiTest.class,
diff --git a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
index 2b8d68b..8149c5b 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
@@ -1513,48 +1513,30 @@
     testKeepattributes(expected, config);
   }
 
-  private void testKeeppackagenames(ProguardPackageNameList expected, String config) {
+  private void testKeeppackagenames(String config) {
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(createConfigurationForTesting(ImmutableList.of(config)));
     verifyParserEndsCleanly();
-    assertEquals(expected, parser.getConfigRawForTesting().getKeepPackageNamesPatterns());
   }
 
   @Test
   public void parseKeeppackagenames() {
-    ProguardPackageNameList xxxYYY =
-        ProguardPackageNameList.builder()
-            .addPackageName(false, new ProguardPackageMatcher("xxx"))
-            .addPackageName(false, new ProguardPackageMatcher("yyy"))
-            .build();
-    testKeeppackagenames(xxxYYY, "-keeppackagenames xxx,yyy");
-    testKeeppackagenames(xxxYYY, "-keeppackagenames xxx, yyy");
-    testKeeppackagenames(xxxYYY, "-keeppackagenames xxx ,yyy");
-    testKeeppackagenames(xxxYYY, "-keeppackagenames xxx   ,   yyy");
-    testKeeppackagenames(xxxYYY, "-keeppackagenames       xxx   ,   yyy     ");
-    testKeeppackagenames(xxxYYY, "-keeppackagenames       xxx   ,   yyy     \n");
-    testKeeppackagenames(xxxYYY, "-keeppackagenames \"xxx\",\"yyy\"");
+    testKeeppackagenames("-keeppackagenames xxx,yyy");
+    testKeeppackagenames("-keeppackagenames xxx, yyy");
+    testKeeppackagenames("-keeppackagenames xxx ,yyy");
+    testKeeppackagenames("-keeppackagenames xxx   ,   yyy");
+    testKeeppackagenames("-keeppackagenames       xxx   ,   yyy     ");
+    testKeeppackagenames("-keeppackagenames       xxx   ,   yyy     \n");
+    testKeeppackagenames("-keeppackagenames \"xxx\",\"yyy\"");
 
     testKeeppackagenames(
-        ProguardPackageNameList.builder()
-            .addPackageName(false, new ProguardPackageMatcher("com.**"))
-            .addPackageName(false, new ProguardPackageMatcher("org.*"))
-            .build(),
         "-keeppackagenames com.**, org.*");
 
     testKeeppackagenames(
-        ProguardPackageNameList.builder()
-            .addPackageName(false, new ProguardPackageMatcher("c?m.**"))
-            .addPackageName(false, new ProguardPackageMatcher("?r?.*"))
-            .build(),
         "-keeppackagenames c?m.**, ?r?.*");
 
     testKeeppackagenames(
-        ProguardPackageNameList.builder()
-            .addPackageName(true, new ProguardPackageMatcher("c?m.**"))
-            .addPackageName(true, new ProguardPackageMatcher("?r?.*"))
-            .build(),
         "-keeppackagenames !c?m.**, !?r?.*");
   }
 
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 47c49fc..63efc58 100644
--- a/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
+++ b/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
@@ -1282,12 +1282,17 @@
 
   public ClassFileTransformer transformMethodInsnInMethod(
       String methodName, MethodInsnTransform transform) {
+    return transformMethodInsnInMethod(MethodPredicate.onName(methodName), transform);
+  }
+
+  public ClassFileTransformer transformMethodInsnInMethod(
+      MethodPredicate predicate, MethodInsnTransform transform) {
     return addMethodTransformer(
         new MethodTransformer() {
           @Override
           public void visitMethodInsn(
               int opcode, String owner, String name, String descriptor, boolean isInterface) {
-            if (getContext().method.getMethodName().equals(methodName)) {
+            if (MethodPredicate.testContext(predicate, getContext())) {
               transform.visitMethodInsn(
                   opcode,
                   owner,
diff --git a/third_party/multidex.tar.gz.sha1 b/third_party/multidex.tar.gz.sha1
new file mode 100644
index 0000000..7d22fb6
--- /dev/null
+++ b/third_party/multidex.tar.gz.sha1
@@ -0,0 +1 @@
+f0ea06be076aa1fc45ea5451188121d8e8b992e2
\ No newline at end of file
diff --git a/third_party/retrace/binary_compatibility.tar.gz.sha1 b/third_party/retrace/binary_compatibility.tar.gz.sha1
index 5d61558..023f1c9 100644
--- a/third_party/retrace/binary_compatibility.tar.gz.sha1
+++ b/third_party/retrace/binary_compatibility.tar.gz.sha1
@@ -1 +1 @@
-189692be996b34e4ba4a069c148b20d7ff99abe7
\ No newline at end of file
+ec4f1b68e126b5b5e8a53078c74c79c65e190cf2
\ No newline at end of file
diff --git a/tools/run_on_app_dump.py b/tools/run_on_app_dump.py
index 4d19948..0f90ab1 100755
--- a/tools/run_on_app_dump.py
+++ b/tools/run_on_app_dump.py
@@ -1045,7 +1045,7 @@
   print('// AUTOGENERATED FILE from tools/run_on_app_dump.py in R8 repo')
   print('part of r8_config;')
   print('')
-  print('final Suite dumpsSuite = new Suite("OpenSourceAppDumps");')
+  print('final Suite dumpsSuite = Suite("OpenSourceAppDumps");')
   print('')
   print('createOpenSourceAppBenchmarks() {')
   print_indented('final cpus = ["Lenovo M90"];', 2)