Merge commit 'e139309308ffc3cb030bc705f6e2496cd423a35a' into dev-release
diff --git a/.gitignore b/.gitignore
index 8534e4c..28f7415 100644
--- a/.gitignore
+++ b/.gitignore
@@ -111,6 +111,8 @@
 third_party/nest/*
 third_party/openjdk/desugar_jdk_libs
 third_party/openjdk/desugar_jdk_libs.tar.gz
+third_party/openjdk/desugar_jdk_libs_11
+third_party/openjdk/desugar_jdk_libs_11.tar.gz
 third_party/openjdk/jdk-15/linux
 third_party/openjdk/jdk-15/linux.tar.gz
 third_party/openjdk/jdk-15/osx
diff --git a/build.gradle b/build.gradle
index 323256b..2e908a5 100644
--- a/build.gradle
+++ b/build.gradle
@@ -329,6 +329,7 @@
                 "kotlinx-coroutines-1.3.6",
                 "openjdk/openjdk-rt-1.8",
                 "openjdk/desugar_jdk_libs",
+                "openjdk/desugar_jdk_libs_11",
                 "openjdk/jdk-11-test",
                 "proguard/proguard5.2.1",
                 "proguard/proguard6.0.1",
@@ -566,7 +567,9 @@
         if (OperatingSystem.current().isLinux()) {
             options.forkOptions.javaHome = file(jdkDir + 'linux')
         } else if (OperatingSystem.current().isMacOsX()) {
-            options.forkOptions.javaHome = file(jdkDir + 'osx')
+            options.forkOptions.javaHome = compatibility > JavaVersion.VERSION_1_9
+                    ? file(jdkDir + 'osx/Contents/Home')
+                    : file(jdkDir + 'osx')
         } else {
             options.forkOptions.javaHome = file(jdkDir + 'windows')
         }
@@ -997,6 +1000,16 @@
     ])
 }
 
+task buildDesugaredLibrary(type: Exec) {
+    def outputDir = "build/libs"
+    def script = "tools/create_jctf_tests.py"
+    inputs.file script
+    outputs.dir outputDir
+    dependsOn downloadDeps
+    commandLine "python", script
+    workingDir = projectDir
+}
+
 task generateR8LibKeepRules(type: Exec) {
     doFirst {
         // TODO(b/154785341): We should remove this.
diff --git a/infra/config/global/luci-scheduler.cfg b/infra/config/global/luci-scheduler.cfg
index 5e0355e..b782dbe 100644
--- a/infra/config/global/luci-scheduler.cfg
+++ b/infra/config/global/luci-scheduler.cfg
@@ -19,11 +19,11 @@
 # The format of this file is important, we have a hackish parsing to trigger
 # builds in tools/trigger.py
 trigger {
-  id: "master-gitiles-trigger"
+  id: "main-gitiles-trigger"
   acl_sets: "default"
   gitiles: {
     repo: "https://r8.googlesource.com/r8"
-    refs: "refs/heads/master"
+    refs: "refs/heads/main"
   }
   triggers: "archive"
   triggers: "linux"
diff --git a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
index f0cb3e8..555713b 100644
--- a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
+++ b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
@@ -206,6 +206,7 @@
     private BiPredicate<String, Long> dexClassChecksumFilter = (name, checksum) -> true;
     private List<AssertionsConfiguration> assertionsConfiguration = new ArrayList<>();
     private List<Consumer<Inspector>> outputInspections = new ArrayList<>();
+    protected StringConsumer proguardMapConsumer = null;
 
     abstract CompilationMode defaultCompilationMode();
 
@@ -278,6 +279,33 @@
     }
 
     /**
+     * Set an output destination to which proguard-map content should be written.
+     *
+     * <p>This is a short-hand for setting a {@link StringConsumer.FileConsumer} using {@link
+     * #setProguardMapConsumer}. Note that any subsequent call to this method or {@link
+     * #setProguardMapConsumer} will override the previous setting.
+     *
+     * @param proguardMapOutput File-system path to write output at.
+     */
+    B setProguardMapOutputPath(Path proguardMapOutput) {
+      assert proguardMapOutput != null;
+      return setProguardMapConsumer(new StringConsumer.FileConsumer(proguardMapOutput));
+    }
+
+    /**
+     * Set a consumer for receiving the proguard-map content.
+     *
+     * <p>Note that any subsequent call to this method or {@link #setProguardMapOutputPath} will
+     * override the previous setting.
+     *
+     * @param proguardMapConsumer Consumer to receive the content once produced.
+     */
+    B setProguardMapConsumer(StringConsumer proguardMapConsumer) {
+      this.proguardMapConsumer = proguardMapConsumer;
+      return self();
+    }
+
+    /**
      * Get the main dex list consumer that will receive the final complete main dex list.
      */
     public StringConsumer getMainDexListConsumer() {
diff --git a/src/main/java/com/android/tools/r8/DumpOptions.java b/src/main/java/com/android/tools/r8/DumpOptions.java
index 3feeee3..f923ffa 100644
--- a/src/main/java/com/android/tools/r8/DumpOptions.java
+++ b/src/main/java/com/android/tools/r8/DumpOptions.java
@@ -143,7 +143,7 @@
   }
 
   public boolean hasMainDexKeepRules() {
-    return mainDexKeepRules != null;
+    return mainDexKeepRules != null && !mainDexKeepRules.isEmpty();
   }
 
   public List<ProguardConfigurationRule> getMainDexKeepRules() {
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index 4c235d9..1fc7689 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -253,6 +253,33 @@
       return self();
     }
 
+    /**
+     * Set an output destination to which proguard-map content should be written.
+     *
+     * <p>This is a short-hand for setting a {@link StringConsumer.FileConsumer} using {@link
+     * #setProguardMapConsumer}. Note that any subsequent call to this method or {@link
+     * #setProguardMapConsumer} will override the previous setting.
+     *
+     * @param proguardMapOutput File-system path to write output at.
+     */
+    @Override
+    public L8Command.Builder setProguardMapOutputPath(Path proguardMapOutput) {
+      return super.setProguardMapOutputPath(proguardMapOutput);
+    }
+
+    /**
+     * Set a consumer for receiving the proguard-map content.
+     *
+     * <p>Note that any subsequent call to this method or {@link #setProguardMapOutputPath} will
+     * override the previous setting.
+     *
+     * @param proguardMapConsumer Consumer to receive the content once produced.
+     */
+    @Override
+    public L8Command.Builder setProguardMapConsumer(StringConsumer proguardMapConsumer) {
+      return super.setProguardMapConsumer(proguardMapConsumer);
+    }
+
     @Override
     void validate() {
       if (isPrintHelp()) {
@@ -273,6 +300,9 @@
       if (isShrinking() && getProgramConsumer() instanceof ClassFileConsumer) {
         reporter.error("L8 does not support shrinking when generating class files");
       }
+      if (!isShrinking() && proguardMapConsumer != null) {
+        reporter.error("L8 does not support defining a map consumer when not shrinking");
+      }
       super.validate();
     }
 
@@ -294,7 +324,7 @@
       D8Command d8Command = null;
 
       AndroidApp inputs = getAppBuilder().build();
-      ProgramConsumer l8CfConsumer = null;
+      ProgramConsumer l8CfConsumer;
       if (isShrinking()) {
         l8CfConsumer = new InMemoryJarContent();
         R8Command.Builder r8Builder =
@@ -314,6 +344,9 @@
         for (Pair<List<String>, Origin> proguardConfig : proguardConfigStrings) {
           r8Builder.addProguardConfiguration(proguardConfig.getFirst(), proguardConfig.getSecond());
         }
+        if (proguardMapConsumer != null) {
+          r8Builder.setProguardMapConsumer(proguardMapConsumer);
+        }
         r8Builder.addProguardConfiguration(
             libraryConfiguration.getExtraKeepRules(), Origin.unknown());
         // TODO(b/180903899): Remove rule when -dontwarn sun.misc.Unsafe is part of config.
diff --git a/src/main/java/com/android/tools/r8/L8CommandParser.java b/src/main/java/com/android/tools/r8/L8CommandParser.java
index 3dac9dc..402e59a 100644
--- a/src/main/java/com/android/tools/r8/L8CommandParser.java
+++ b/src/main/java/com/android/tools/r8/L8CommandParser.java
@@ -18,8 +18,15 @@
 
 public class L8CommandParser extends BaseCompilerCommandParser<L8Command, L8Command.Builder> {
 
-  private static final Set<String> OPTIONS_WITH_PARAMETER = ImmutableSet.of(
-      "--output", "--lib", MIN_API_FLAG, "--desugared-lib", THREAD_COUNT_FLAG, "--pg-conf");
+  private static final Set<String> OPTIONS_WITH_PARAMETER =
+      ImmutableSet.of(
+          "--output",
+          "--lib",
+          MIN_API_FLAG,
+          "--desugared-lib",
+          THREAD_COUNT_FLAG,
+          "--pg-conf",
+          "--pg-map-output");
 
   public static void main(String[] args) throws CompilationFailedException {
     L8Command command = parse(args, Origin.root()).build();
@@ -50,6 +57,8 @@
                       + AndroidApiLevel.getDefault().getLevel()
                       + ".",
                   "  --pg-conf <file>        # Proguard configuration <file>.",
+                  "  --pg-map-output <file>  # Output the resulting name and line mapping to"
+                      + " <file>.",
                   "  --desugared-lib <file>  # Specify desugared library configuration.",
                   "                          # <file> is a desugared library configuration"
                       + " (json)."),
@@ -149,6 +158,8 @@
         addLibraryArgument(builder, origin, nextArg);
       } else if (arg.equals("--pg-conf")) {
         builder.addProguardConfigurationFiles(Paths.get(nextArg));
+      } else if (arg.equals("--pg-map-output")) {
+        builder.setProguardMapOutputPath(Paths.get(nextArg));
       } else if (arg.equals("--desugared-lib")) {
         builder.addDesugaredLibraryConfiguration(StringResource.fromFile(Paths.get(nextArg)));
       } else if (arg.equals("--classfile")) {
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 9663d3f..2b3f988 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -102,7 +102,6 @@
     private boolean disableVerticalClassMerging = false;
     private boolean forceProguardCompatibility = false;
     private Optional<Boolean> includeDataResources = Optional.empty();
-    private StringConsumer proguardMapConsumer = null;
     private StringConsumer proguardUsageConsumer = null;
     private StringConsumer proguardSeedsConsumer = null;
     private StringConsumer proguardConfigurationConsumer = null;
@@ -237,10 +236,9 @@
      *
      * @param proguardMapOutput File-system path to write output at.
      */
+    @Override
     public Builder setProguardMapOutputPath(Path proguardMapOutput) {
-      assert proguardMapOutput != null;
-      this.proguardMapConsumer = new StringConsumer.FileConsumer(proguardMapOutput);
-      return self();
+      return super.setProguardMapOutputPath(proguardMapOutput);
     }
 
     /**
@@ -251,9 +249,9 @@
      *
      * @param proguardMapConsumer Consumer to receive the content once produced.
      */
+    @Override
     public Builder setProguardMapConsumer(StringConsumer proguardMapConsumer) {
-      this.proguardMapConsumer = proguardMapConsumer;
-      return self();
+      return super.setProguardMapConsumer(proguardMapConsumer);
     }
 
     /**
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 8a28e9f..062c572 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -31,7 +31,7 @@
   }
 
   static int getMajorVersion(String label) {
-    if (label.equals("master")) {
+    if (label.equals("main")) {
       return -1;
     }
     int start = 0;
@@ -49,7 +49,7 @@
   }
 
   static int getMinorVersion(String label) {
-    if (label.equals("master")) {
+    if (label.equals("main")) {
       return -1;
     }
     int start = label.indexOf('.') + 1;
@@ -67,7 +67,7 @@
   }
 
   static int getPatchVersion(String label) {
-    if (label.equals("master")) {
+    if (label.equals("main")) {
       return -1;
     }
     int skip = label.indexOf('.') + 1;
@@ -87,7 +87,7 @@
   }
 
   static String getPreReleaseString(String label) {
-    if (label.equals("master")) {
+    if (label.equals("main")) {
       return null;
     }
     int start = label.indexOf('-') + 1;
@@ -107,6 +107,6 @@
   }
 
   static boolean isDevelopmentVersion(String label, boolean isEngineering) {
-    return label.equals("master") || label.endsWith("-dev") || isEngineering;
+    return label.equals("main") || label.endsWith("-dev") || isEngineering;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/contexts/CompilationContext.java b/src/main/java/com/android/tools/r8/contexts/CompilationContext.java
index b2cc211..f037883 100644
--- a/src/main/java/com/android/tools/r8/contexts/CompilationContext.java
+++ b/src/main/java/com/android/tools/r8/contexts/CompilationContext.java
@@ -8,8 +8,8 @@
 import com.android.tools.r8.utils.InternalOptions;
 import com.google.common.hash.Hasher;
 import com.google.common.hash.Hashing;
-import java.util.HashSet;
-import java.util.Set;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Consumer;
 
 public class CompilationContext {
@@ -35,7 +35,7 @@
   }
 
   private final Consumer<String> testingConsumer;
-  private final Set<String> seenSetForTesting = new HashSet<>();
+  private final Map<String, String> seenSetForTesting = new ConcurrentHashMap<>();
   private int nextProcessorId = 0;
 
   private CompilationContext(InternalOptions options) {
@@ -49,7 +49,7 @@
     if (testingConsumer != null) {
       testingConsumer.accept(descriptor);
     }
-    assert seenSetForTesting.add(descriptor)
+    assert seenSetForTesting.put(descriptor, descriptor) == null
         : "Duplicated use of context descriptor: " + descriptor;
     return true;
   }
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 8ba291b..86b96e8 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -27,6 +27,7 @@
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.code.Position;
 import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.desugar.LambdaClass;
 import com.android.tools.r8.kotlin.Kotlin;
 import com.android.tools.r8.utils.ArrayUtils;
 import com.android.tools.r8.utils.DescriptorUtils;
@@ -299,6 +300,8 @@
 
   public final DexString thisName = createString("this");
   public final DexString lambdaInstanceFieldName = createString(LAMBDA_INSTANCE_FIELD_NAME);
+  public final DexString javacLambdaMethodPrefix =
+      createString(LambdaClass.JAVAC_EXPECTED_LAMBDA_METHOD_PREFIX);
 
   // As much as possible, R8 should rely on the content of the static enum field, using
   // enumMembers.isValuesFieldCandidate or checking the object state in the optimization info.
diff --git a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
index 0f7b951..ceac26a 100644
--- a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
@@ -143,7 +143,8 @@
         if (definitionFor(type) == null && definitionFor(renamed) != null) {
           continue;
         }
-        assert definitionFor(type).type == renamed || definitionFor(renamed) != null;
+        assert definitionFor(type).type == renamed || definitionFor(renamed) != null
+            : "The lens and app is inconsistent";
       }
     }
     return true;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaring.java
index b4cab05..864a7b4 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaring.java
@@ -12,6 +12,10 @@
 /** Interface for desugaring a single class-file instruction. */
 public interface CfInstructionDesugaring {
 
+  default void scan(ProgramMethod method, CfInstructionDesugaringEventConsumer eventConsumer) {
+    // Default scan is to do nothing.
+  }
+
   /**
    * Given an instruction, returns the list of instructions that the instruction should be desugared
    * to. If no desugaring is needed, {@code null} should be returned (for efficiency).
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
index a264d65..3b5a40b 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
@@ -18,6 +18,7 @@
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexMethodHandle;
+import com.android.tools.r8.graph.DexMethodHandle.MethodHandleType;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexString;
@@ -272,12 +273,6 @@
   // Creates a delegation target for this particular lambda class. Note that we
   // should always be able to create targets for the lambdas we support.
   private Target createTarget(ProgramMethod accessedFrom) {
-    if (appView.options().canAccessModifyLambdaImplementationMethods(appView)
-        && descriptor.delegatesToLambdaImplMethod()) {
-      return createLambdaImplMethodTarget(accessedFrom);
-    }
-
-    // Method referenced directly, without lambda$ method.
     switch (descriptor.implHandle.type) {
       case INVOKE_SUPER:
         throw new Unimplemented("Method references to super methods are not yet supported");
@@ -286,8 +281,13 @@
       case INVOKE_CONSTRUCTOR:
         return createConstructorTarget(accessedFrom);
       case INVOKE_STATIC:
-        return createStaticMethodTarget(accessedFrom);
+        return canAccessModifyLambdaImplMethod()
+            ? createLambdaImplMethodTarget(accessedFrom)
+            : createStaticMethodTarget(accessedFrom);
       case INVOKE_DIRECT:
+        return canAccessModifyLambdaImplMethod()
+            ? createLambdaImplMethodTarget(accessedFrom)
+            : createInstanceMethodTarget(accessedFrom);
       case INVOKE_INSTANCE:
         return createInstanceMethodTarget(accessedFrom);
       default:
@@ -295,12 +295,25 @@
     }
   }
 
+  private boolean doesNotNeedAccessor(ProgramMethod accessedFrom) {
+    return canAccessModifyLambdaImplMethod() || !descriptor.needsAccessor(accessedFrom);
+  }
+
+  private boolean canAccessModifyLambdaImplMethod() {
+    MethodHandleType invokeType = descriptor.implHandle.type;
+    return appView.options().canAccessModifyLambdaImplementationMethods(appView)
+        && (invokeType.isInvokeDirect() || invokeType.isInvokeStatic())
+        && descriptor.delegatesToLambdaImplMethod(appView.dexItemFactory())
+        && !desugaring.isDirectTargetedLambdaImplementationMethod(descriptor.implHandle);
+  }
+
   private Target createLambdaImplMethodTarget(ProgramMethod accessedFrom) {
     DexMethodHandle implHandle = descriptor.implHandle;
     assert implHandle != null;
     DexMethod implMethod = implHandle.asMethod();
 
     // Lambda$ method. We should always find it. If not found an ICCE can be expected to be thrown.
+    assert descriptor.delegatesToLambdaImplMethod(appView.dexItemFactory());
     assert implMethod.holder == accessedFrom.getHolderType();
     assert descriptor.verifyTargetFoundInClass(accessedFrom.getHolderType());
     if (implHandle.type.isInvokeStatic()) {
@@ -318,12 +331,10 @@
               result.getResolvedHolder().asProgramClass(), result.getResolvedMethod()));
     }
 
-    assert implHandle.type.isInvokeInstance() || implHandle.type.isInvokeDirect();
-
+    assert implHandle.type.isInvokeDirect();
     // If the lambda$ method is an instance-private method on an interface we convert it into a
     // public static method as it will be placed on the companion class.
-    if (implHandle.type.isInvokeDirect()
-        && appView.definitionFor(implMethod.holder).isInterface()) {
+    if (appView.definitionFor(implMethod.holder).isInterface()) {
       DexProto implProto = implMethod.proto;
       DexType[] implParams = implProto.parameters.values;
       DexType[] newParams = new DexType[implParams.length + 1];
@@ -356,7 +367,7 @@
     assert descriptor.implHandle.type.isInvokeInstance() ||
         descriptor.implHandle.type.isInvokeDirect();
 
-    if (!descriptor.needsAccessor(appView, accessedFrom)) {
+    if (doesNotNeedAccessor(accessedFrom)) {
       return new NoAccessorMethodTarget(Invoke.Type.VIRTUAL);
     }
     // We need to generate an accessor method in `accessedFrom` class/interface
@@ -388,7 +399,7 @@
   private Target createStaticMethodTarget(ProgramMethod accessedFrom) {
     assert descriptor.implHandle.type.isInvokeStatic();
 
-    if (!descriptor.needsAccessor(appView, accessedFrom)) {
+    if (doesNotNeedAccessor(accessedFrom)) {
       return new NoAccessorMethodTarget(Invoke.Type.STATIC);
     }
 
@@ -412,7 +423,7 @@
     assert implHandle != null;
     assert implHandle.type.isInvokeConstructor();
 
-    if (!descriptor.needsAccessor(appView, accessedFrom)) {
+    if (doesNotNeedAccessor(accessedFrom)) {
       return new NoAccessorMethodTarget(Invoke.Type.DIRECT);
     }
 
@@ -435,7 +446,7 @@
   // Create targets for interface methods.
   private Target createInterfaceMethodTarget(ProgramMethod accessedFrom) {
     assert descriptor.implHandle.type.isInvokeInterface();
-    assert !descriptor.needsAccessor(appView, accessedFrom);
+    assert doesNotNeedAccessor(accessedFrom);
     return new NoAccessorMethodTarget(Invoke.Type.INTERFACE);
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java
index 3cc480d..edfa934 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java
@@ -4,11 +4,8 @@
 
 package com.android.tools.r8.ir.desugar;
 
-import static com.android.tools.r8.ir.desugar.LambdaClass.JAVAC_EXPECTED_LAMBDA_METHOD_PREFIX;
-
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
-import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexCallSite;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedMethod;
@@ -180,14 +177,9 @@
     return targetHolder == type;
   }
 
-  public boolean canAccessModifyLambdaImplementationMethods(AppView<?> appView) {
-    return appView.enableWholeProgramOptimizations();
-  }
-
   /** If the lambda delegates to lambda$ method. */
-  public boolean delegatesToLambdaImplMethod() {
-    String methodName = implHandle.asMethod().getName().toString();
-    return methodName.startsWith(JAVAC_EXPECTED_LAMBDA_METHOD_PREFIX);
+  public boolean delegatesToLambdaImplMethod(DexItemFactory factory) {
+    return implHandle.asMethod().getName().startsWith(factory.javacLambdaMethodPrefix);
   }
 
   /** Is a stateless lambda, i.e. lambda does not capture any values */
@@ -196,12 +188,7 @@
   }
 
   /** Checks if call site needs a accessor when referenced from `accessedFrom`. */
-  boolean needsAccessor(AppView<?> appView, ProgramMethod accessedFrom) {
-    if (appView.options().canAccessModifyLambdaImplementationMethods(appView)
-        && delegatesToLambdaImplMethod()) {
-      return false;
-    }
-
+  boolean needsAccessor(ProgramMethod accessedFrom) {
     if (implHandle.type.isInvokeInterface()) {
       // Interface methods must be public.
       return false;
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 3a7a195..433e023 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
@@ -98,9 +98,7 @@
   @Override
   public void scan(ProgramMethod method, CfInstructionDesugaringEventConsumer eventConsumer) {
     ensureCfCode(method);
-    if (recordRewriter != null) {
-      recordRewriter.scan(method, eventConsumer);
-    }
+    desugarings.forEach(d -> d.scan(method, eventConsumer));
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/RecordRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/RecordRewriter.java
index 469f119..d8d47e8 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/RecordRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/RecordRewriter.java
@@ -78,6 +78,7 @@
     recordHashCodeHelperProto = factory.createProto(factory.intType, factory.recordType);
   }
 
+  @Override
   public void scan(
       ProgramMethod programMethod, CfInstructionDesugaringEventConsumer eventConsumer) {
     CfCode cfCode = programMethod.getDefinition().getCode().asCfCode();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/lambda/LambdaInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/lambda/LambdaInstructionDesugaring.java
index 34dda4e..59411a7 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/lambda/LambdaInstructionDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/lambda/LambdaInstructionDesugaring.java
@@ -15,6 +15,9 @@
 import com.android.tools.r8.cf.code.CfStore;
 import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
 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.DexMethodHandle;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexTypeList;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -28,20 +31,42 @@
 import com.android.tools.r8.synthesis.SyntheticNaming;
 import com.android.tools.r8.utils.Box;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Sets;
 import java.util.ArrayDeque;
 import java.util.Collection;
 import java.util.Deque;
+import java.util.Set;
 import org.objectweb.asm.Opcodes;
 
 public class LambdaInstructionDesugaring implements CfInstructionDesugaring {
 
   private final AppView<?> appView;
+  private final Set<DexMethod> directTargetedLambdaImplementationMethods =
+      Sets.newIdentityHashSet();
+
+  public boolean isDirectTargetedLambdaImplementationMethod(DexMethodHandle implMethod) {
+    return implMethod.type.isInvokeDirect()
+        && directTargetedLambdaImplementationMethods.contains(implMethod.asMethod());
+  }
 
   public LambdaInstructionDesugaring(AppView<?> appView) {
     this.appView = appView;
   }
 
   @Override
+  public void scan(ProgramMethod method, CfInstructionDesugaringEventConsumer eventConsumer) {
+    CfCode code = method.getDefinition().getCode().asCfCode();
+    for (CfInstruction instruction : code.getInstructions()) {
+      if (instruction.isInvokeSpecial()) {
+        DexMethod target = instruction.asInvoke().getMethod();
+        if (target.getName().startsWith(appView.dexItemFactory().javacLambdaMethodPrefix)) {
+          directTargetedLambdaImplementationMethods.add(target);
+        }
+      }
+    }
+  }
+
+  @Override
   public Collection<CfInstruction> desugarInstruction(
       CfInstruction instruction,
       FreshLocalProvider freshLocalProvider,
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java b/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
index 0cc7497..7dae8cd 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.optimize;
 
+import static com.android.tools.r8.graph.ResolutionResult.SingleResolutionResult.isOverriding;
+
 import com.android.tools.r8.graph.AccessControl;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
@@ -376,7 +378,11 @@
         || !newResolutionResult
             .getResolvedMethod()
             .getAccessFlags()
-            .isAtLeastAsVisibleAs(resolutionResult.getResolvedMethod().getAccessFlags())) {
+            .isAtLeastAsVisibleAs(resolutionResult.getResolvedMethod().getAccessFlags())
+        // isOverriding expects both arguments to be not private.
+        || (!newResolutionResult.getResolvedMethod().isPrivateMethod()
+            && !isOverriding(
+                resolutionResult.getResolvedMethod(), newResolutionResult.getResolvedMethod()))) {
       return target;
     }
 
diff --git a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
index 5ade4de..9da3a40 100644
--- a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.jar;
 
-import static com.android.tools.r8.repackaging.Repackaging.DefaultRepackagingConfiguration.TEMPORARY_PACKAGE_NAME;
 import static com.android.tools.r8.utils.InternalOptions.ASM_VERSION;
 
 import com.android.tools.r8.ByteDataView;
@@ -186,7 +185,6 @@
     }
     String desc = namingLens.lookupDescriptor(clazz.type).toString();
     String name = namingLens.lookupInternalName(clazz.type);
-    assert !name.contains(TEMPORARY_PACKAGE_NAME);
     String signature = clazz.getClassSignature().toRenamedString(namingLens, isTypeMissing);
     String superName =
         clazz.type == options.itemFactory.objectType
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
index 9ab6c15..e53f285 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
@@ -18,10 +18,8 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.InnerClassAttribute;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.shaking.ProguardPackageNameList;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.Timing;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Maps;
@@ -37,9 +35,7 @@
 
   private final AppView<AppInfoWithLiveness> appView;
   private final ClassNamingStrategy classNamingStrategy;
-  private final PackageNamingStrategy packageNamingStrategy;
   private final Iterable<? extends DexClass> classes;
-  private final Set<String> usedPackagePrefixes = Sets.newHashSet();
   private final Set<String> usedTypeNames = Sets.newHashSet();
   private final Map<DexType, DexString> renaming = Maps.newIdentityHashMap();
   private final Map<String, Namespace> states = new HashMap<>();
@@ -48,27 +44,19 @@
   private final Namespace topLevelState;
   private final boolean allowMixedCaseNaming;
   private final Predicate<String> isUsed;
-  private final ProguardPackageNameList keepPackageNames;
 
   ClassNameMinifier(
       AppView<AppInfoWithLiveness> appView,
       ClassNamingStrategy classNamingStrategy,
-      PackageNamingStrategy packageNamingStrategy,
       Iterable<? extends DexClass> classes) {
     this.appView = appView;
     this.classNamingStrategy = classNamingStrategy;
-    this.packageNamingStrategy = packageNamingStrategy;
     this.classes = classes;
     InternalOptions options = appView.options();
     this.keepInnerClassStructure = options.keepInnerClassStructure();
 
     // Initialize top-level naming state.
     topLevelState = new Namespace("");
-    String newPackageDescriptor =
-        StringUtils.replaceAll(options.getProguardConfiguration().getPackagePrefix(), ".", "/");
-    if (!newPackageDescriptor.isEmpty()) {
-      registerPackagePrefixesAsUsed(newPackageDescriptor);
-    }
     states.put("", topLevelState);
 
     if (options.getProguardConfiguration().hasDontUseMixedCaseClassnames()) {
@@ -78,7 +66,6 @@
       allowMixedCaseNaming = true;
       isUsed = usedTypeNames::contains;
     }
-    keepPackageNames = options.getProguardConfiguration().getKeepPackageNamesPatterns();
   }
 
   private void setUsedTypeName(String typeName) {
@@ -176,8 +163,6 @@
 
   private void registerClassAsUsed(DexType type, DexString descriptor) {
     renaming.put(type, descriptor);
-    registerPackagePrefixesAsUsed(
-        getParentPackagePrefix(getClassBinaryNameFromDescriptor(descriptor.toSourceString())));
     setUsedTypeName(descriptor.toString());
     if (keepInnerClassStructure) {
       DexType outerClass = getOutClassForType(type);
@@ -192,16 +177,6 @@
     }
   }
 
-  /** Registers the given package prefix and all of parent packages as used. */
-  private void registerPackagePrefixesAsUsed(String packagePrefix) {
-    String usedPrefix = packagePrefix;
-    while (usedPrefix.length() > 0) {
-      usedPackagePrefixes.add(usedPrefix);
-      states.computeIfAbsent(usedPrefix, Namespace::new);
-      usedPrefix = getParentPackagePrefix(usedPrefix);
-    }
-  }
-
   private DexType getOutClassForType(DexType type) {
     DexClass clazz = appView.definitionFor(type);
     if (clazz == null) {
@@ -249,29 +224,8 @@
 
   private Namespace getStateForClass(DexType type) {
     String packageName = getPackageBinaryNameFromJavaType(type.getPackageDescriptor());
-    // Check whether the given class should be kept.
-    // or check whether the given class belongs to a package that is kept for another class.
-    if (keepPackageNames.matches(type)) {
-      return states.computeIfAbsent(packageName, Namespace::new);
-    }
-    return getStateForPackagePrefix(packageName);
-  }
-
-  private Namespace getStateForPackagePrefix(String prefix) {
-    Namespace state = states.get(prefix);
-    if (state == null) {
-      // Calculate the parent package prefix, e.g., La/b/c -> La/b
-      String parentPackage = getParentPackagePrefix(prefix);
-      // Create a state for parent package prefix, if necessary, in a recursive manner.
-      // That recursion should end when the parent package hits the top-level, "".
-      Namespace superState = getStateForPackagePrefix(parentPackage);
-      // From the super state, get a renamed package prefix for the current level.
-      String renamedPackagePrefix = superState.nextPackagePrefix();
-      // Create a new state, which corresponds to a new name space, for the current level.
-      state = new Namespace(renamedPackagePrefix);
-      states.put(prefix, state);
-    }
-    return state;
+    // Packages are repackaged and obfuscated when doing repackaging.
+    return states.computeIfAbsent(packageName, Namespace::new);
   }
 
   private Namespace getStateForOuterClass(DexType outer, String innerClassSeparator) {
@@ -326,13 +280,6 @@
       return candidate;
     }
 
-    String nextPackagePrefix() {
-      String next = packageNamingStrategy.next(packagePrefix, this, usedPackagePrefixes::contains);
-      assert !usedPackagePrefixes.contains(next);
-      usedPackagePrefixes.add(next);
-      return next;
-    }
-
     @Override
     public int getDictionaryIndex() {
       return dictionaryIndex;
@@ -344,8 +291,7 @@
     }
 
     @Override
-    public int incrementNameIndex(boolean isDirectMethodCall) {
-      assert !isDirectMethodCall;
+    public int incrementNameIndex() {
       return nameIndex++;
     }
   }
@@ -368,10 +314,6 @@
     boolean isRenamedByApplyMapping(DexType type);
   }
 
-  protected interface PackageNamingStrategy {
-    String next(char[] packagePrefix, InternalNamingState state, Predicate<String> isUsed);
-  }
-
   /**
    * Compute parent package prefix from the given package prefix.
    *
diff --git a/src/main/java/com/android/tools/r8/naming/FieldNamingState.java b/src/main/java/com/android/tools/r8/naming/FieldNamingState.java
index 35e3d3f..9e99065 100644
--- a/src/main/java/com/android/tools/r8/naming/FieldNamingState.java
+++ b/src/main/java/com/android/tools/r8/naming/FieldNamingState.java
@@ -114,8 +114,7 @@
     }
 
     @Override
-    public int incrementNameIndex(boolean isDirectMethodCall) {
-      assert !isDirectMethodCall;
+    public int incrementNameIndex() {
       return nextNameIndex++;
     }
   }
diff --git a/src/main/java/com/android/tools/r8/naming/InternalNamingState.java b/src/main/java/com/android/tools/r8/naming/InternalNamingState.java
index e5749c1..9cbacda 100644
--- a/src/main/java/com/android/tools/r8/naming/InternalNamingState.java
+++ b/src/main/java/com/android/tools/r8/naming/InternalNamingState.java
@@ -10,5 +10,5 @@
 
   int incrementDictionaryIndex();
 
-  int incrementNameIndex(boolean isDirectMethodCall);
+  int incrementNameIndex();
 }
diff --git a/src/main/java/com/android/tools/r8/naming/MemberNaming.java b/src/main/java/com/android/tools/r8/naming/MemberNaming.java
index 51c3272..4a50244 100644
--- a/src/main/java/com/android/tools/r8/naming/MemberNaming.java
+++ b/src/main/java/com/android/tools/r8/naming/MemberNaming.java
@@ -172,7 +172,7 @@
 
     public static final NoSignature NO_SIGNATURE = new NoSignature();
 
-    public NoSignature() {
+    private NoSignature() {
       super("NO SIGNATURE");
     }
 
diff --git a/src/main/java/com/android/tools/r8/naming/MethodNamingState.java b/src/main/java/com/android/tools/r8/naming/MethodNamingState.java
index 5aa368b..922c062 100644
--- a/src/main/java/com/android/tools/r8/naming/MethodNamingState.java
+++ b/src/main/java/com/android/tools/r8/naming/MethodNamingState.java
@@ -185,7 +185,7 @@
     }
 
     @Override
-    public int incrementNameIndex(boolean isDirectMethodCall) {
+    public int incrementNameIndex() {
       assert checkParentPublicNameCountIsLessThanOrEqual();
       return nameCount++;
     }
diff --git a/src/main/java/com/android/tools/r8/naming/Minifier.java b/src/main/java/com/android/tools/r8/naming/Minifier.java
index a542a2f..c5b8ced 100644
--- a/src/main/java/com/android/tools/r8/naming/Minifier.java
+++ b/src/main/java/com/android/tools/r8/naming/Minifier.java
@@ -20,7 +20,6 @@
 import com.android.tools.r8.graph.SubtypingInfo;
 import com.android.tools.r8.naming.ClassNameMinifier.ClassNamingStrategy;
 import com.android.tools.r8.naming.ClassNameMinifier.ClassRenaming;
-import com.android.tools.r8.naming.ClassNameMinifier.PackageNamingStrategy;
 import com.android.tools.r8.naming.FieldNameMinifier.FieldRenaming;
 import com.android.tools.r8.naming.MethodNameMinifier.MethodRenaming;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -55,7 +54,6 @@
         new ClassNameMinifier(
             appView,
             new MinificationClassNamingStrategy(appView),
-            new MinificationPackageNamingStrategy(appView),
             // Use deterministic class order to make sure renaming is deterministic.
             appView.appInfo().classesWithDeterministicOrder());
     ClassRenaming classRenaming = classNameMinifier.computeRenaming(timing);
@@ -106,14 +104,15 @@
     private final MixedCasing mixedCasing;
 
     BaseMinificationNamingStrategy(List<String> obfuscationDictionary, boolean dontUseMixedCasing) {
+      assert obfuscationDictionary != null;
       this.obfuscationDictionary = obfuscationDictionary;
-      this.obfuscationDictionaryForLookup = new HashSet<>(this.obfuscationDictionary);
+      this.obfuscationDictionaryForLookup = new HashSet<>(obfuscationDictionary);
       this.mixedCasing =
           dontUseMixedCasing ? MixedCasing.DONT_USE_MIXED_CASE : MixedCasing.USE_MIXED_CASE;
-      assert obfuscationDictionary != null;
     }
 
-    String nextName(char[] packagePrefix, InternalNamingState state, boolean isDirectMethodCall) {
+    /** TODO(b/182992598): using char[] could give problems with unicode */
+    String nextName(char[] packagePrefix, InternalNamingState state) {
       StringBuilder nextName = new StringBuilder();
       nextName.append(packagePrefix);
       String nextString;
@@ -123,8 +122,7 @@
         } else {
           do {
             nextString =
-                SymbolGenerationUtils.numberToIdentifier(
-                    state.incrementNameIndex(isDirectMethodCall), mixedCasing);
+                SymbolGenerationUtils.numberToIdentifier(state.incrementNameIndex(), mixedCasing);
           } while (obfuscationDictionaryForLookup.contains(nextString));
         }
       } while (PRIMITIVE_TYPE_NAMES.contains(nextString));
@@ -153,7 +151,7 @@
       String candidate = null;
       String lastName = null;
       do {
-        String newName = nextName(packagePrefix, state, false) + ";";
+        String newName = nextName(packagePrefix, state) + ";";
         if (newName.equals(lastName)) {
           throw new CompilationError(
               "Generating same name '"
@@ -187,24 +185,44 @@
     }
   }
 
-  static class MinificationPackageNamingStrategy extends BaseMinificationNamingStrategy
-      implements PackageNamingStrategy {
+  public static class MinificationPackageNamingStrategy extends BaseMinificationNamingStrategy {
 
-    MinificationPackageNamingStrategy(AppView<?> appView) {
+    private final InternalNamingState namingState =
+        new InternalNamingState() {
+
+          private int dictionaryIndex = 0;
+          private int nameIndex = 1;
+
+          @Override
+          public int getDictionaryIndex() {
+            return dictionaryIndex;
+          }
+
+          @Override
+          public int incrementDictionaryIndex() {
+            return dictionaryIndex++;
+          }
+
+          @Override
+          public int incrementNameIndex() {
+            return nameIndex++;
+          }
+        };
+
+    public MinificationPackageNamingStrategy(AppView<?> appView) {
       super(
           appView.options().getProguardConfiguration().getPackageObfuscationDictionary(),
           appView.options().getProguardConfiguration().hasDontUseMixedCaseClassnames());
     }
 
-    @Override
-    public String next(char[] packagePrefix, InternalNamingState state, Predicate<String> isUsed) {
+    public String next(String packagePrefix, Predicate<String> isUsed) {
       // Note that the differences between this method and the other variant for class renaming are
       // 1) this one uses the different dictionary and counter,
       // 2) this one does not append ';' at the end, and
-      // 3) this one removes 'L' at the beginning to make the return value a binary form.
+      // 3) this one assumes no 'L' at the beginning to make the return value a binary form.
       String nextPackageName;
       do {
-        nextPackageName = nextName(packagePrefix, state, false).substring(1);
+        nextPackageName = nextName(packagePrefix.toCharArray(), namingState);
       } while (isUsed.test(nextPackageName));
       return nextPackageName;
     }
@@ -230,10 +248,9 @@
         InternalNamingState internalState,
         BiPredicate<DexString, DexMethod> isAvailable) {
       assert checkAllowMemberRenaming(method.getHolderType());
-      boolean isDirectOrStatic = method.isDirectMethod() || method.isStatic();
       DexString candidate;
       do {
-        candidate = getNextName(internalState, isDirectOrStatic);
+        candidate = getNextName(internalState);
       } while (!isAvailable.test(candidate, method.getReference()));
       return candidate;
     }
@@ -246,13 +263,13 @@
       assert checkAllowMemberRenaming(field.getHolderType());
       DexString candidate;
       do {
-        candidate = getNextName(internalState, false);
+        candidate = getNextName(internalState);
       } while (!isAvailable.test(candidate, field));
       return candidate;
     }
 
-    private DexString getNextName(InternalNamingState internalState, boolean isDirectOrStatic) {
-      return factory.createString(nextName(EMPTY_CHAR_ARRAY, internalState, isDirectOrStatic));
+    private DexString getNextName(InternalNamingState internalState) {
+      return factory.createString(nextName(EMPTY_CHAR_ARRAY, internalState));
     }
 
     @Override
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
index a8e299a..3b2c0d5 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
@@ -29,7 +29,6 @@
 import com.android.tools.r8.naming.MemberNaming.Signature;
 import com.android.tools.r8.naming.MethodNameMinifier.MethodRenaming;
 import com.android.tools.r8.naming.Minifier.MinificationClassNamingStrategy;
-import com.android.tools.r8.naming.Minifier.MinificationPackageNamingStrategy;
 import com.android.tools.r8.naming.Minifier.MinifierMemberNamingStrategy;
 import com.android.tools.r8.position.Position;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -137,11 +136,6 @@
             appView,
             new ApplyMappingClassNamingStrategy(
                 appView, mappedNames, seedMapper.getMappedToDescriptorNames()),
-            // The package naming strategy will actually not be used since all classes and methods
-            // will be output with identity name if not found in mapping. However, there is a check
-            // in the ClassNameMinifier that the strategy should produce a "fresh" name so we just
-            // use the existing strategy.
-            new MinificationPackageNamingStrategy(appView),
             classesWithDeterministicOrder(mappedClasses));
     ClassRenaming classRenaming = classNameMinifier.computeRenaming(timing);
     timing.end();
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/CompilerSynthesizedMappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/CompilerSynthesizedMappingInformation.java
new file mode 100644
index 0000000..b0a13ba
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/CompilerSynthesizedMappingInformation.java
@@ -0,0 +1,45 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.naming.mappinginformation;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonPrimitive;
+
+public class CompilerSynthesizedMappingInformation extends MappingInformation {
+
+  public static final String ID = "com.android.tools.r8.synthesized";
+
+  public CompilerSynthesizedMappingInformation() {
+    super(NO_LINE_NUMBER);
+  }
+
+  @Override
+  public boolean isCompilerSynthesizedMappingInformation() {
+    return true;
+  }
+
+  @Override
+  public CompilerSynthesizedMappingInformation asCompilerSynthesizedMappingInformation() {
+    return this;
+  }
+
+  @Override
+  public boolean allowOther(MappingInformation information) {
+    return !information.isCompilerSynthesizedMappingInformation();
+  }
+
+  @Override
+  public String serialize() {
+    JsonObject result = new JsonObject();
+    result.add(MAPPING_ID_KEY, new JsonPrimitive(ID));
+    return result.toString();
+  }
+
+  public static CompilerSynthesizedMappingInformation deserialize(
+      JsonObject object, DiagnosticsHandler diagnosticsHandler, int lineNumber) {
+    return new CompilerSynthesizedMappingInformation();
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java
index c1c5105..cb0708f 100644
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java
@@ -50,6 +50,14 @@
     return null;
   }
 
+  public boolean isCompilerSynthesizedMappingInformation() {
+    return false;
+  }
+
+  public CompilerSynthesizedMappingInformation asCompilerSynthesizedMappingInformation() {
+    return null;
+  }
+
   public abstract boolean allowOther(MappingInformation information);
 
   public static MappingInformation fromJsonObject(
@@ -75,6 +83,9 @@
         return MethodSignatureChangedInformation.build(object, diagnosticsHandler, lineNumber);
       case FileNameInformation.ID:
         return FileNameInformation.build(object, diagnosticsHandler, lineNumber);
+      case CompilerSynthesizedMappingInformation.ID:
+        return CompilerSynthesizedMappingInformation.deserialize(
+            object, diagnosticsHandler, lineNumber);
       default:
         diagnosticsHandler.info(MappingInformationDiagnostics.noHandlerFor(lineNumber, idString));
         return null;
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 056abce..c6612c5 100644
--- a/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
+++ b/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
@@ -21,6 +21,7 @@
 import com.android.tools.r8.graph.ProgramPackageCollection;
 import com.android.tools.r8.graph.SortedProgramPackageCollection;
 import com.android.tools.r8.graph.TreeFixerBase;
+import com.android.tools.r8.naming.Minifier.MinificationPackageNamingStrategy;
 import com.android.tools.r8.repackaging.RepackagingLens.Builder;
 import com.android.tools.r8.shaking.AnnotationFixer;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -35,6 +36,7 @@
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.IdentityHashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -202,19 +204,17 @@
     Iterator<ProgramPackage> iterator = packages.iterator();
     while (iterator.hasNext()) {
       ProgramPackage pkg = iterator.next();
-      String newPackageDescriptor =
-          repackagingConfiguration.getNewPackageDescriptor(pkg, seenPackageDescriptors);
-      if (pkg.getPackageDescriptor().equals(newPackageDescriptor)) {
+      if (repackagingConfiguration.isPackageInTargetLocation(pkg)) {
         for (DexProgramClass alreadyRepackagedClass : pkg) {
           if (!appView.appInfo().isRepackagingAllowed(alreadyRepackagedClass)) {
             mappings.put(alreadyRepackagedClass.getType(), alreadyRepackagedClass.getType());
           }
         }
         for (DexProgramClass alreadyRepackagedClass : pkg) {
-          processClass(alreadyRepackagedClass, pkg, newPackageDescriptor, mappings);
+          processClass(alreadyRepackagedClass, pkg, pkg.getPackageDescriptor(), mappings);
         }
-        packageMappings.put(pkg.getPackageDescriptor(), newPackageDescriptor);
-        seenPackageDescriptors.add(newPackageDescriptor);
+        packageMappings.put(pkg.getPackageDescriptor(), pkg.getPackageDescriptor());
+        seenPackageDescriptors.add(pkg.getPackageDescriptor());
         iterator.remove();
       }
     }
@@ -228,15 +228,28 @@
       ExecutorService executorService)
       throws ExecutionException {
     // For each package, find the set of classes that can be repackaged, and move them to the
-    // desired package.
+    // desired package. We iterate all packages first to see if any classes are pinned and cannot
+    // be moved, to properly reserve their package.
+    Map<ProgramPackage, Collection<DexProgramClass>> packagesWithClassesToRepackage =
+        new IdentityHashMap<>();
     for (ProgramPackage pkg : packages) {
+      Collection<DexProgramClass> classesToRepackage =
+          computeClassesToRepackage(pkg, executorService);
+      packagesWithClassesToRepackage.put(pkg, classesToRepackage);
+      // Reserve the package name to ensure that we are not renaming to a package we cannot move.
+      if (classesToRepackage.size() != pkg.classesInPackage().size()) {
+        seenPackageDescriptors.add(pkg.getPackageDescriptor());
+      }
+    }
+    for (ProgramPackage pkg : packages) {
+      Collection<DexProgramClass> classesToRepackage = packagesWithClassesToRepackage.get(pkg);
+      if (classesToRepackage.isEmpty()) {
+        continue;
+      }
       // Already processed packages should have been removed.
       String newPackageDescriptor =
           repackagingConfiguration.getNewPackageDescriptor(pkg, seenPackageDescriptors);
-      assert !pkg.getPackageDescriptor().equals(newPackageDescriptor);
-
-      Collection<DexProgramClass> classesToRepackage =
-          computeClassesToRepackage(pkg, executorService);
+      assert !repackagingConfiguration.isPackageInTargetLocation(pkg);
       for (DexProgramClass classToRepackage : classesToRepackage) {
         processClass(classToRepackage, pkg, newPackageDescriptor, mappings);
       }
@@ -249,8 +262,6 @@
           classesToRepackage.size() == pkg.classesInPackage().size()
               ? newPackageDescriptor
               : pkg.getPackageDescriptor());
-      // TODO(b/165783399): Investigate if repackaging can lead to different dynamic dispatch. See,
-      //  for example, CrossPackageInvokeSuperToPackagePrivateMethodTest.
     }
   }
 
@@ -298,6 +309,8 @@
 
     String getNewPackageDescriptor(ProgramPackage pkg, Set<String> seenPackageDescriptors);
 
+    boolean isPackageInTargetLocation(ProgramPackage pkg);
+
     DexType getRepackagedType(
         DexProgramClass clazz,
         DexProgramClass outerClass,
@@ -310,12 +323,13 @@
     private final AppView<?> appView;
     private final DexItemFactory dexItemFactory;
     private final ProguardConfiguration proguardConfiguration;
-    public static final String TEMPORARY_PACKAGE_NAME = "TEMPORARY_PACKAGE_NAME_FOR_";
+    private final MinificationPackageNamingStrategy packageMinificationStrategy;
 
     public DefaultRepackagingConfiguration(AppView<?> appView) {
       this.appView = appView;
       this.dexItemFactory = appView.dexItemFactory();
       this.proguardConfiguration = appView.options().getProguardConfiguration();
+      this.packageMinificationStrategy = new MinificationPackageNamingStrategy(appView);
     }
 
     @Override
@@ -326,13 +340,7 @@
           proguardConfiguration.getPackageObfuscationMode();
       if (packageObfuscationMode.isRepackageClasses()) {
         return newPackageDescriptor;
-      }
-      assert packageObfuscationMode.isFlattenPackageHierarchy()
-          || packageObfuscationMode.isMinification();
-      if (!newPackageDescriptor.isEmpty()) {
-        newPackageDescriptor += DESCRIPTOR_PACKAGE_SEPARATOR;
-      }
-      if (packageObfuscationMode.isMinification()) {
+      } else if (packageObfuscationMode.isMinification()) {
         assert !proguardConfiguration.hasApplyMappingFile();
         // Always keep top-level classes since there packages can never be minified.
         if (pkg.getPackageDescriptor().equals("")
@@ -340,18 +348,37 @@
             || mayHavePinnedPackagePrivateOrProtectedItem(pkg)) {
           return pkg.getPackageDescriptor();
         }
-        // For us to rename shaking/A to a/a if we have a class shaking/Kept, we have to propose
-        // a different name than the last package name - the class will be minified in
-        // ClassNameMinifier.
-        newPackageDescriptor += TEMPORARY_PACKAGE_NAME + pkg.getLastPackageName();
+        // Plain minification do not support using a specified package prefix.
+        newPackageDescriptor = "";
       } else {
-        newPackageDescriptor += pkg.getLastPackageName();
+        assert packageObfuscationMode.isFlattenPackageHierarchy();
+        if (!newPackageDescriptor.isEmpty()) {
+          newPackageDescriptor += DESCRIPTOR_PACKAGE_SEPARATOR;
+        }
       }
-      String finalPackageDescriptor = newPackageDescriptor;
-      for (int i = 1; seenPackageDescriptors.contains(finalPackageDescriptor); i++) {
-        finalPackageDescriptor = newPackageDescriptor + INNER_CLASS_SEPARATOR + i;
+      return packageMinificationStrategy.next(
+          newPackageDescriptor, seenPackageDescriptors::contains);
+    }
+
+    @Override
+    public boolean isPackageInTargetLocation(ProgramPackage pkg) {
+      String newPackageDescriptor =
+          DescriptorUtils.getBinaryNameFromJavaType(proguardConfiguration.getPackagePrefix());
+      PackageObfuscationMode packageObfuscationMode =
+          proguardConfiguration.getPackageObfuscationMode();
+      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)
+            || mayHavePinnedPackagePrivateOrProtectedItem(pkg);
+      } else {
+        assert packageObfuscationMode.isFlattenPackageHierarchy();
+        // For flatten we will move the package into the package specified by the prefix so we can
+        // always minify the last part.
+        return false;
       }
-      return finalPackageDescriptor;
     }
 
     private boolean mayHavePinnedPackagePrivateOrProtectedItem(ProgramPackage pkg) {
@@ -400,7 +427,7 @@
       }
       // Ensure that the generated name is unique.
       DexType finalRepackagedDexType = repackagedDexType;
-      for (int i = 1; mappings.inverse().containsKey(finalRepackagedDexType); i++) {
+      for (int i = 1; isRepackageTypeUsed(finalRepackagedDexType, mappings, appView); i++) {
         finalRepackagedDexType =
             repackagedDexType.addSuffix(
                 Character.toString(INNER_CLASS_SEPARATOR) + i, dexItemFactory);
@@ -409,6 +436,12 @@
     }
   }
 
+  private static boolean isRepackageTypeUsed(
+      DexType type, BiMap<DexType, DexType> mappings, AppView<?> appView) {
+    return mappings.inverse().containsKey(type)
+        || (appView.hasLiveness() && appView.withLiveness().appInfo().wasPruned(type));
+  }
+
   /** Testing only. */
   public static class SuffixRenamingRepackagingConfiguration implements RepackagingConfiguration {
 
@@ -428,6 +461,11 @@
     }
 
     @Override
+    public boolean isPackageInTargetLocation(ProgramPackage pkg) {
+      return true;
+    }
+
+    @Override
     public DexType getRepackagedType(
         DexProgramClass clazz,
         DexProgramClass outerClass,
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 331466b..86c8ef6 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -10,6 +10,8 @@
 import static com.android.tools.r8.naming.IdentifierNameStringUtils.identifyIdentifier;
 import static com.android.tools.r8.naming.IdentifierNameStringUtils.isReflectionMethod;
 import static com.android.tools.r8.shaking.AnnotationRemover.shouldKeepAnnotation;
+import static com.android.tools.r8.utils.FunctionUtils.ignoreArgument;
+import static java.util.Collections.emptySet;
 
 import com.android.tools.r8.Diagnostic;
 import com.android.tools.r8.cf.code.CfInstruction;
@@ -114,7 +116,6 @@
 import com.android.tools.r8.utils.Action;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.IteratorUtils;
-import com.android.tools.r8.utils.MethodSignatureEquivalence;
 import com.android.tools.r8.utils.OptionalBool;
 import com.android.tools.r8.utils.Pair;
 import com.android.tools.r8.utils.SetUtils;
@@ -136,11 +137,9 @@
 import java.lang.reflect.InvocationHandler;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.Deque;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.IdentityHashMap;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
@@ -148,6 +147,7 @@
 import java.util.List;
 import java.util.ListIterator;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
@@ -351,9 +351,9 @@
   /** A set of methods that need code inspection for Java reflection in use. */
   private final ProgramMethodSet pendingReflectiveUses = ProgramMethodSet.createLinked();
 
-  /** Mapping of types to the methods reachable at that type. */
-  private final Map<DexProgramClass, Set<DexMethod>> reachableVirtualTargets =
-      new IdentityHashMap<>();
+  /** Mapping of types to the resolved methods for that type along with the context. */
+  private final Map<DexProgramClass, Map<ResolutionSearchKey, Set<DexProgramClass>>>
+      reachableVirtualTargets = new IdentityHashMap<>();
 
   /** Collection of keep requirements for the program. */
   private final MutableKeepInfoCollection keepInfo = new MutableKeepInfoCollection();
@@ -2342,16 +2342,14 @@
 
   private void transitionMethodsForInstantiatedLambda(LambdaDescriptor lambda) {
     transitionMethodsForInstantiatedObject(
-        InstantiatedObject.of(lambda),
-        appInfo().definitionFor(appInfo.dexItemFactory().objectType),
-        lambda.interfaces);
+        InstantiatedObject.of(lambda), appInfo.dexItemFactory().objectType, lambda.interfaces);
   }
 
   private void transitionMethodsForInstantiatedClass(DexProgramClass clazz) {
     assert !clazz.isAnnotation();
     assert !clazz.isInterface();
     transitionMethodsForInstantiatedObject(
-        InstantiatedObject.of(clazz), clazz, Collections.emptyList());
+        InstantiatedObject.of(clazz), clazz.type, Collections.emptyList());
   }
 
   /**
@@ -2362,102 +2360,66 @@
    * methods are considered reachable.
    */
   private void transitionMethodsForInstantiatedObject(
-      InstantiatedObject instantiation, DexClass clazz, List<DexType> interfaces) {
-    Set<Wrapper<DexMethod>> seen = new HashSet<>();
-    WorkList<DexType> worklist = WorkList.newIdentityWorkList();
+      InstantiatedObject instantiation, DexType type, List<DexType> interfaces) {
+    WorkList<DexType> worklist = WorkList.newIdentityWorkList(type);
     worklist.addIfNotSeen(interfaces);
-    // First we lookup and mark all targets on the instantiated class for each reachable method in
-    // the super chain (inclusive).
-    DexClass initialClass = clazz;
-    while (clazz != null) {
+    while (worklist.hasNext()) {
+      DexClass clazz = appInfo().definitionFor(worklist.next());
+      if (clazz == null) {
+        continue;
+      }
       if (clazz.isProgramClass()) {
-        markProgramMethodOverridesAsLive(instantiation, initialClass, clazz.asProgramClass(), seen);
+        markProgramMethodOverridesAsLive(instantiation, clazz.asProgramClass());
       } else {
         markLibraryAndClasspathMethodOverridesAsLive(instantiation, clazz);
       }
+      if (clazz.superType != null) {
+        worklist.addIfNotSeen(clazz.superType);
+      }
       worklist.addIfNotSeen(clazz.interfaces);
-      clazz = clazz.superType != null ? appInfo().definitionFor(clazz.superType) : null;
-    }
-    // The targets for methods on the type and its supertype that are reachable are now marked.
-    // In a second step, we look at interfaces. We order the search this way such that a
-    // method reachable on a class takes precedence when reporting edges. That order mirrors JVM
-    // resolution/dispatch.
-    while (worklist.hasNext()) {
-      DexType type = worklist.next();
-      DexClass iface = appInfo().definitionFor(type);
-      if (iface == null) {
-        continue;
-      }
-      assert iface.superType == appInfo.dexItemFactory().objectType;
-      if (iface.isNotProgramClass()) {
-        markLibraryAndClasspathMethodOverridesAsLive(instantiation, iface);
-      } else {
-        markProgramMethodOverridesAsLive(instantiation, initialClass, iface.asProgramClass(), seen);
-      }
-      worklist.addIfNotSeen(Arrays.asList(iface.interfaces.values));
     }
   }
 
-  private Set<DexMethod> getReachableVirtualTargets(DexProgramClass clazz) {
-    return reachableVirtualTargets.getOrDefault(clazz, Collections.emptySet());
+  private Map<ResolutionSearchKey, Set<DexProgramClass>> getReachableVirtualTargets(
+      DexProgramClass clazz) {
+    return reachableVirtualTargets.getOrDefault(clazz, Collections.emptyMap());
   }
 
   private void markProgramMethodOverridesAsLive(
-      InstantiatedObject instantiation,
-      DexClass initialClass,
-      DexProgramClass superClass,
-      Set<Wrapper<DexMethod>> seenMethods) {
-    for (DexMethod method : getReachableVirtualTargets(superClass)) {
-      assert method.holder == superClass.type;
-      Wrapper<DexMethod> signature = MethodSignatureEquivalence.get().wrap(method);
-      if (!seenMethods.contains(signature)) {
-        SingleResolutionResult resolution =
-            appInfo.resolveMethodOn(superClass, method).asSingleResolution();
-        assert resolution != null;
-        assert resolution.getResolvedHolder().isProgramClass();
-        if (resolution != null) {
-          if (!initialClass.isProgramClass()
-              || resolution
-                  .isAccessibleForVirtualDispatchFrom(initialClass.asProgramClass(), appInfo)
-                  .isTrue()) {
-            seenMethods.add(signature);
-          }
-          if (resolution.getResolvedHolder().isProgramClass()) {
-            markLiveOverrides(
-                instantiation, superClass, resolution.getResolutionPair().asProgramMethod());
-          }
-        }
-      }
-    }
-  }
-
-  private void markLiveOverrides(
-      InstantiatedObject instantiation,
-      DexProgramClass initialHolder,
-      ProgramMethod resolutionMethod) {
-    // The validity of the reachable method is checked at the point it becomes "reachable" and is
-    // resolved. If the method is private, then the dispatch is not "virtual" and the method is
-    // simply marked live on its holder.
-    if (resolutionMethod.getDefinition().isPrivateMethod()) {
-      markVirtualMethodAsLive(
-          resolutionMethod,
-          graphReporter.reportReachableMethodAsLive(
-              resolutionMethod.getDefinition().getReference(), resolutionMethod));
-      return;
-    }
-    // Otherwise, we set the initial holder type to be the holder of the reachable method, which
-    // ensures that access will be generally valid.
-    SingleResolutionResult resolution =
-        new SingleResolutionResult(
-            initialHolder, resolutionMethod.getHolder(), resolutionMethod.getDefinition());
-    LookupTarget lookup = resolution.lookupVirtualDispatchTarget(instantiation, appInfo);
-    if (lookup != null) {
-      markVirtualDispatchTargetAsLive(
-          lookup,
-          programMethod ->
-              graphReporter.reportReachableMethodAsLive(
-                  resolutionMethod.getDefinition().getReference(), programMethod));
-    }
+      InstantiatedObject instantiation, DexProgramClass currentClass) {
+    assert instantiation.isLambda()
+        || appInfo.isSubtype(instantiation.asClass().getType(), currentClass.type);
+    getReachableVirtualTargets(currentClass)
+        .forEach(
+            (resolutionSearchKey, contexts) -> {
+              SingleResolutionResult singleResolution =
+                  appInfo
+                      .resolveMethod(resolutionSearchKey.method, resolutionSearchKey.isInterface)
+                      .asSingleResolution();
+              if (singleResolution == null) {
+                assert false : "Should not be null";
+                return;
+              }
+              contexts.forEach(
+                  context ->
+                      singleResolution
+                          .lookupVirtualDispatchTargets(
+                              context,
+                              appInfo,
+                              (type, subTypeConsumer, lambdaConsumer) -> {
+                                assert appInfo.isSubtype(currentClass.type, type);
+                                instantiation.apply(subTypeConsumer, lambdaConsumer);
+                              },
+                              definition -> keepInfo.isPinned(definition.getReference(), appInfo))
+                          .forEach(
+                              target ->
+                                  markVirtualDispatchTargetAsLive(
+                                      target,
+                                      programMethod ->
+                                          graphReporter.reportReachableMethodAsLive(
+                                              singleResolution.getResolvedMethod().getReference(),
+                                              programMethod))));
+            });
   }
 
   private void markLibraryAndClasspathMethodOverridesAsLive(
@@ -2798,8 +2760,13 @@
       return;
     }
 
-    // If the method has already been marked, just report the new reason for the resolved target.
-    if (getReachableVirtualTargets(holder).contains(method)) {
+    DexProgramClass contextHolder = context.getContextClass();
+    // If the method has already been marked, just report the new reason for the resolved target and
+    // save the context to ensure correct lookup of virtual dispatch targets.
+    ResolutionSearchKey resolutionSearchKey = new ResolutionSearchKey(method, interfaceInvoke);
+    Set<DexProgramClass> seenContexts = getReachableVirtualTargets(holder).get(resolutionSearchKey);
+    if (seenContexts != null) {
+      seenContexts.add(contextHolder);
       graphReporter.registerMethod(resolution.getResolvedMethod(), reason);
       return;
     }
@@ -2813,15 +2780,16 @@
     DexProgramClass resolvedHolder = resolution.getResolvedHolder().asProgramClass();
     DexEncodedMethod resolvedMethod = resolution.getResolvedMethod();
     markMethodAsTargeted(new ProgramMethod(resolvedHolder, resolvedMethod), reason);
-
-    DexProgramClass contextHolder = context.getContextClass();
     if (resolution.isAccessibleForVirtualDispatchFrom(contextHolder, appInfo).isFalse()) {
       // Not accessible from this context, so this call will cause a runtime exception.
       return;
     }
 
     // The method resolved and is accessible, so currently live overrides become live.
-    reachableVirtualTargets.computeIfAbsent(holder, k -> Sets.newIdentityHashSet()).add(method);
+    reachableVirtualTargets
+        .computeIfAbsent(holder, ignoreArgument(HashMap::new))
+        .computeIfAbsent(resolutionSearchKey, ignoreArgument(Sets::newIdentityHashSet))
+        .add(contextHolder);
 
     resolution
         .lookupVirtualDispatchTargets(
@@ -3347,7 +3315,7 @@
             rootSet.noHorizontalClassMerging,
             rootSet.neverPropagateValue,
             joinIdentifierNameStrings(rootSet.identifierNameStrings, identifierNameStrings),
-            Collections.emptySet(),
+            emptySet(),
             Collections.emptyMap(),
             lockCandidates,
             initClassReferences);
@@ -3776,7 +3744,7 @@
     Set<DexClass> subtypes =
         objectAllocationInfoCollection.getImmediateSubtypesInInstantiatedHierarchy(clazz.type);
     if (subtypes == null) {
-      return Collections.emptySet();
+      return emptySet();
     }
     Set<DexProgramClass> programClasses = SetUtils.newIdentityHashSet(subtypes.size());
     for (DexClass subtype : subtypes) {
@@ -4548,4 +4516,29 @@
       return enqueuer.definitionFor(type, context, enqueuer::ignoreMissingClass);
     }
   }
+
+  public static class ResolutionSearchKey {
+
+    private final DexMethod method;
+    private final boolean isInterface;
+
+    private ResolutionSearchKey(DexMethod method, boolean isInterface) {
+      this.method = method;
+      this.isInterface = isInterface;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      if (o == null || getClass() != o.getClass()) {
+        return false;
+      }
+      ResolutionSearchKey that = (ResolutionSearchKey) o;
+      return method == that.method && isInterface == that.isInterface;
+    }
+
+    @Override
+    public int hashCode() {
+      return Objects.hash(method, isInterface);
+    }
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/shaking/InstantiatedObject.java b/src/main/java/com/android/tools/r8/shaking/InstantiatedObject.java
index d4fe555..9c92725 100644
--- a/src/main/java/com/android/tools/r8/shaking/InstantiatedObject.java
+++ b/src/main/java/com/android/tools/r8/shaking/InstantiatedObject.java
@@ -5,6 +5,7 @@
 
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.ir.desugar.LambdaDescriptor;
+import java.util.function.Consumer;
 
 public abstract class InstantiatedObject {
 
@@ -16,6 +17,16 @@
     return new InstantiatedLambda(lambda);
   }
 
+  public void apply(
+      Consumer<DexProgramClass> classConsumer, Consumer<LambdaDescriptor> lambdaConsumer) {
+    if (isClass()) {
+      classConsumer.accept(asClass());
+    } else {
+      assert isLambda();
+      lambdaConsumer.accept(asLambda());
+    }
+  }
+
   public boolean isClass() {
     return false;
   }
diff --git a/src/main/java/com/android/tools/r8/utils/FunctionUtils.java b/src/main/java/com/android/tools/r8/utils/FunctionUtils.java
index 3338dde..acd5cb3 100644
--- a/src/main/java/com/android/tools/r8/utils/FunctionUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/FunctionUtils.java
@@ -7,6 +7,7 @@
 import java.util.function.BiFunction;
 import java.util.function.Consumer;
 import java.util.function.Function;
+import java.util.function.Supplier;
 
 public class FunctionUtils {
 
@@ -28,4 +29,8 @@
       func.apply(t).accept(argument);
     }
   }
+
+  public static <T, R> Function<T, R> ignoreArgument(Supplier<R> supplier) {
+    return ignore -> supplier.get();
+  }
 }
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 7a99160..83a2245 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -571,7 +571,7 @@
   @Override
   public boolean isRepackagingEnabled() {
     return proguardConfiguration.getPackageObfuscationMode().isSome()
-        && (isShrinking() || isMinifying());
+        && (isMinifying() || testing.repackageWithNoMinification);
   }
 
   @Override
@@ -1154,7 +1154,10 @@
 
   public static class HorizontalClassMergerOptions {
 
-    public boolean enable = true;
+    // TODO(b/138781768): Set enable to true when this bug is resolved.
+    public boolean enable =
+        !Version.isDevelopmentVersion()
+            || System.getProperty("com.android.tools.r8.disableHorizontalClassMerging") == null;
     public boolean enableConstructorMerging = true;
     public boolean enableJavaLambdaMerging = true;
 
@@ -1320,6 +1323,7 @@
     // TODO(b/177333791): Set to true
     public boolean checkForNotExpandingMainDexTracingResult = false;
     public Set<String> allowedUnusedDontWarnPatterns = new HashSet<>();
+    public boolean repackageWithNoMinification = false;
 
     public boolean allowConflictingSyntheticTypes = false;
 
diff --git a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
index 47ccd91..f8ad5bb 100644
--- a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
+++ b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
@@ -47,6 +47,7 @@
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.naming.Range;
+import com.android.tools.r8.naming.mappinginformation.CompilerSynthesizedMappingInformation;
 import com.android.tools.r8.naming.mappinginformation.FileNameInformation;
 import com.android.tools.r8.retrace.internal.RetraceUtils;
 import com.android.tools.r8.shaking.KeepInfoCollection;
@@ -274,6 +275,8 @@
     ClassNameMapper.Builder classNameMapperBuilder = ClassNameMapper.builder();
     // Collect which files contain which classes that need to have their line numbers optimized.
     for (DexProgramClass clazz : application.classes()) {
+      boolean isSyntheticClass = appView.getSyntheticItems().isSyntheticClass(clazz);
+
       IdentityHashMap<DexString, List<DexEncodedMethod>> methodsByRenamedName =
           groupMethodsByRenamedName(appView.graphLens(), namingLens, clazz);
 
@@ -299,6 +302,12 @@
         }
       }
 
+      if (isSyntheticClass) {
+        onDemandClassNamingBuilder
+            .get()
+            .addMappingInformation(new CompilerSynthesizedMappingInformation());
+      }
+
       // If the class is renamed add it to the classNamingBuilder.
       addClassToClassNaming(originalType, renamedClassName, onDemandClassNamingBuilder);
 
diff --git a/src/test/examplesJava9/stream/ProgramRewritingTestClass.java b/src/test/examplesJava9/stream/ProgramRewritingTestClass.java
index 7eedeb9..6bf4f12 100644
--- a/src/test/examplesJava9/stream/ProgramRewritingTestClass.java
+++ b/src/test/examplesJava9/stream/ProgramRewritingTestClass.java
@@ -27,11 +27,9 @@
     ArrayList<Object> aList = new ArrayList<>();
     Queue<Object> queue = new LinkedList<>();
     LinkedHashSet<Object> lhs = new LinkedHashSet<>();
-    // They both should be rewritten to invokeStatic to the dispatch class.
+    // Following should be rewritten to invokeStatic to the dispatch class.
     System.out.println(set.spliterator().getClass().getName());
     System.out.println("j$.util.Spliterators$IteratorSpliterator");
-    System.out.println(list.spliterator().getClass().getName());
-    System.out.println("j$.util.Spliterators$IteratorSpliterator");
     // Following should be rewritten to invokeStatic to Collection dispatch class.
     System.out.println(set.stream().getClass().getName());
     System.out.println("j$.util.stream.ReferencePipeline$Head");
diff --git a/src/test/java/com/android/tools/r8/BackportedMethodListTest.java b/src/test/java/com/android/tools/r8/BackportedMethodListTest.java
index bb344d7..4ffaaa7 100644
--- a/src/test/java/com/android/tools/r8/BackportedMethodListTest.java
+++ b/src/test/java/com/android/tools/r8/BackportedMethodListTest.java
@@ -88,7 +88,7 @@
   private void addLibraryDesugaring(BackportedMethodListCommand.Builder builder) {
     builder
         .addDesugaredLibraryConfiguration(
-            StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING))
+            StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
         .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P.getLevel()));
   }
 
@@ -143,7 +143,7 @@
       BackportedMethodList.run(
           BackportedMethodListCommand.builder()
               .addDesugaredLibraryConfiguration(
-                  StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING))
+                  StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
               .setConsumer(new ListStringConsumer())
               .build());
       fail("Expected failure");
diff --git a/src/test/java/com/android/tools/r8/ExtractMarkerTest.java b/src/test/java/com/android/tools/r8/ExtractMarkerTest.java
index 7cbcf63..6ed73d8 100644
--- a/src/test/java/com/android/tools/r8/ExtractMarkerTest.java
+++ b/src/test/java/com/android/tools/r8/ExtractMarkerTest.java
@@ -129,7 +129,7 @@
     DexString markerString =
         factory.createString(
             "~~D8{\"compilation-mode\":\"debug\",\"has-checksums\":false,"
-                + "\"min-api\":21,\"sha-1\":\"engineering\",\"version\":\"master\" }");
+                + "\"min-api\":21,\"sha-1\":\"engineering\",\"version\":\"main\" }");
     assertEquals("dex", Marker.parse(markerString).getBackend());
   }
 
@@ -139,7 +139,7 @@
     DexString markerString =
         factory.createString(
             "~~R8{\"compilation-mode\":\"release\",\"has-checksums\":true,"
-                + "\"sha-1\":\"engineering\",\"version\":\"master\" }");
+                + "\"sha-1\":\"engineering\",\"version\":\"main\" }");
     assertEquals("cf", Marker.parse(markerString).getBackend());
   }
 }
diff --git a/src/test/java/com/android/tools/r8/L8CommandTest.java b/src/test/java/com/android/tools/r8/L8CommandTest.java
index bb32740..8bb9f30 100644
--- a/src/test/java/com/android/tools/r8/L8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/L8CommandTest.java
@@ -15,19 +15,19 @@
 
 import com.android.tools.r8.AssertionsConfiguration.AssertionTransformation;
 import com.android.tools.r8.AssertionsConfiguration.AssertionTransformationScope;
-import com.android.tools.r8.dex.Marker;
+import com.android.tools.r8.StringConsumer.FileConsumer;
 import com.android.tools.r8.dex.Marker.Tool;
 import com.android.tools.r8.origin.EmbeddedOrigin;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.FileUtils;
+import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.ThreadUtils;
 import com.google.common.collect.ImmutableList;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import org.junit.Test;
@@ -58,7 +58,7 @@
         L8Command.builder()
             .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
             .addDesugaredLibraryConfiguration(
-                StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING))
+                StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
             .build());
   }
 
@@ -79,7 +79,7 @@
             .addProgramFiles(ToolHelper.getDesugarJDKLibs())
             .setMinApiLevel(20)
             .addDesugaredLibraryConfiguration(
-                StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING))
+                StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
             .setOutput(output, OutputMode.DexIndexed)
             .build());
     assertMarkersMatch(
@@ -96,7 +96,7 @@
             .addProgramFiles(ToolHelper.getDesugarJDKLibs())
             .setMinApiLevel(20)
             .addDesugaredLibraryConfiguration(
-                StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING))
+                StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
             .setOutput(output, OutputMode.ClassFile)
             .build());
     assertMarkersMatch(ExtractMarker.extractMarkerFromDexFile(output), markerTool(Tool.L8));
@@ -113,11 +113,10 @@
             "--min-api",
             "20",
             "--desugared-lib",
-            ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString(),
+            ToolHelper.getDesugarLibJsonForTesting().toString(),
             "--output",
             output.toString());
     L8.run(l8Command);
-    Collection<Marker> markers = ExtractMarker.extractMarkerFromDexFile(output);
     assertMarkersMatch(
         ExtractMarker.extractMarkerFromDexFile(output),
         ImmutableList.of(markerTool(Tool.L8), markerTool(Tool.D8)));
@@ -134,7 +133,7 @@
             "--min-api",
             "20",
             "--desugared-lib",
-            ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString(),
+            ToolHelper.getDesugarLibJsonForTesting().toString(),
             "--output",
             output.toString(),
             "--classfile");
@@ -150,12 +149,35 @@
     parse(
         diagnostics,
         "--desugared-lib",
-        ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString(),
+        ToolHelper.getDesugarLibJsonForTesting().toString(),
         "--pg-conf",
         pgconf.toString());
   }
 
   @Test
+  public void testFlagPgConfWithConsumer() throws Exception {
+    TestDiagnosticMessagesImpl diagnostics = new TestDiagnosticMessagesImpl();
+    Path pgconf = temp.newFolder().toPath().resolve("pg.conf");
+    Path pgMap = temp.newFolder().toPath().resolve("pg-map.txt");
+    FileUtils.writeTextFile(pgconf, "");
+    L8Command parsedCommand =
+        parse(
+            diagnostics,
+            "--desugared-lib",
+            ToolHelper.getDesugarLibJsonForTesting().toString(),
+            "--pg-conf",
+            pgconf.toString(),
+            "--pg-map-output",
+            pgMap.toString());
+    assertNotNull(parsedCommand.getR8Command());
+    InternalOptions internalOptions = parsedCommand.getR8Command().getInternalOptions();
+    assertNotNull(internalOptions);
+    assertTrue(internalOptions.proguardMapConsumer instanceof StringConsumer.FileConsumer);
+    FileConsumer proguardMapConsumer = (FileConsumer) internalOptions.proguardMapConsumer;
+    assertEquals(pgMap, proguardMapConsumer.getOutputPath());
+  }
+
+  @Test
   public void testFlagPgConfWithClassFile() throws Exception {
     TestDiagnosticMessagesImpl diagnostics = new TestDiagnosticMessagesImpl();
     try {
@@ -164,7 +186,7 @@
       parse(
           diagnostics,
           "--desugared-lib",
-          ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString(),
+          ToolHelper.getDesugarLibJsonForTesting().toString(),
           "--pg-conf",
           pgconf.toString(),
           "--classfile");
@@ -182,7 +204,7 @@
       parse(
           diagnostics,
           "--desugared-lib",
-          ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString(),
+          ToolHelper.getDesugarLibJsonForTesting().toString(),
           "--pg-conf");
       fail("Expected parse error");
     } catch (CompilationFailedException e) {
@@ -227,6 +249,29 @@
             prepareBuilder(handler).setProgramConsumer(ClassFileConsumer.emptyConsumer()).build());
   }
 
+  @Test(expected = CompilationFailedException.class)
+  public void proguardMapConsumerNotShrinking() throws Throwable {
+    DiagnosticsChecker.checkErrorsContains(
+        "L8 does not support defining a map consumer when not shrinking",
+        (handler) ->
+            prepareBuilder(handler)
+                .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
+                .setProguardMapConsumer(StringConsumer.emptyConsumer())
+                .build());
+  }
+
+  @Test(expected = CompilationFailedException.class)
+  public void proguardMapOutputNotShrinking() throws Throwable {
+    Path pgMapOut = temp.newFile("pg-out.txt").toPath();
+    DiagnosticsChecker.checkErrorsContains(
+        "L8 does not support defining a map consumer when not shrinking",
+        (handler) ->
+            prepareBuilder(handler)
+                .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
+                .setProguardMapOutputPath(pgMapOut)
+                .build());
+  }
+
   private void addProguardConfigurationString(
       DiagnosticsHandler diagnostics, ProgramConsumer programConsumer) throws Throwable {
     String keepRule = "-keep class java.time.*";
@@ -236,7 +281,7 @@
         prepareBuilder(diagnostics)
             .setProgramConsumer(programConsumer)
             .addDesugaredLibraryConfiguration(
-                StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING))
+                StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
             .addProguardConfiguration(keepRules, Origin.unknown());
     assertTrue(builder.isShrinking());
     assertNotNull(builder.build().getR8Command());
@@ -270,7 +315,7 @@
         prepareBuilder(diagnostics)
             .setProgramConsumer(programConsumer)
             .addDesugaredLibraryConfiguration(
-                StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING))
+                StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
             .addProguardConfigurationFiles(keepRuleFile);
     assertTrue(builder1.isShrinking());
     assertNotNull(builder1.build().getR8Command());
@@ -281,7 +326,7 @@
         prepareBuilder(new TestDiagnosticMessagesImpl())
             .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
             .addDesugaredLibraryConfiguration(
-                StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING))
+                StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
             .addProguardConfigurationFiles(keepRuleFiles);
     assertTrue(builder2.isShrinking());
     assertNotNull(builder2.build().getR8Command());
@@ -308,7 +353,7 @@
   @Test
   public void desugaredLibrary() throws CompilationFailedException {
     L8Command l8Command =
-        parse("--desugared-lib", ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString());
+        parse("--desugared-lib", ToolHelper.getDesugarLibJsonForTesting().toString());
     assertFalse(
         l8Command.getInternalOptions().desugaredLibraryConfiguration.getRewritePrefix().isEmpty());
   }
@@ -337,21 +382,21 @@
         parse(
                 "--force-enable-assertions",
                 "--desugared-lib",
-                ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString())
+                ToolHelper.getDesugarLibJsonForTesting().toString())
             .getAssertionsConfiguration(),
         AssertionTransformation.ENABLE);
     checkSingleForceAllAssertion(
         parse(
                 "--force-disable-assertions",
                 "--desugared-lib",
-                ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString())
+                ToolHelper.getDesugarLibJsonForTesting().toString())
             .getAssertionsConfiguration(),
         AssertionTransformation.DISABLE);
     checkSingleForceAllAssertion(
         parse(
                 "--force-passthrough-assertions",
                 "--desugared-lib",
-                ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString())
+                ToolHelper.getDesugarLibJsonForTesting().toString())
             .getAssertionsConfiguration(),
         AssertionTransformation.PASSTHROUGH);
     checkSingleForceClassAndPackageAssertion(
@@ -359,7 +404,7 @@
                 "--force-enable-assertions:ClassName",
                 "--force-enable-assertions:PackageName...",
                 "--desugared-lib",
-                ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString())
+                ToolHelper.getDesugarLibJsonForTesting().toString())
             .getAssertionsConfiguration(),
         AssertionTransformation.ENABLE);
     checkSingleForceClassAndPackageAssertion(
@@ -367,7 +412,7 @@
                 "--force-disable-assertions:ClassName",
                 "--force-disable-assertions:PackageName...",
                 "--desugared-lib",
-                ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString())
+                ToolHelper.getDesugarLibJsonForTesting().toString())
             .getAssertionsConfiguration(),
         AssertionTransformation.DISABLE);
     checkSingleForceClassAndPackageAssertion(
@@ -375,7 +420,7 @@
                 "--force-passthrough-assertions:ClassName",
                 "--force-passthrough-assertions:PackageName...",
                 "--desugared-lib",
-                ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString())
+                ToolHelper.getDesugarLibJsonForTesting().toString())
             .getAssertionsConfiguration(),
         AssertionTransformation.PASSTHROUGH);
   }
@@ -384,7 +429,7 @@
   public void numThreadsOption() throws Exception {
     assertEquals(
         ThreadUtils.NOT_SPECIFIED,
-        parse("--desugared-lib", ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString())
+        parse("--desugared-lib", ToolHelper.getDesugarLibJsonForTesting().toString())
             .getThreadCount());
     assertEquals(
         1,
@@ -392,7 +437,7 @@
                 "--thread-count",
                 "1",
                 "--desugared-lib",
-                ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString())
+                ToolHelper.getDesugarLibJsonForTesting().toString())
             .getThreadCount());
     assertEquals(
         2,
@@ -400,7 +445,7 @@
                 "--thread-count",
                 "2",
                 "--desugared-lib",
-                ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString())
+                ToolHelper.getDesugarLibJsonForTesting().toString())
             .getThreadCount());
     assertEquals(
         10,
@@ -408,7 +453,7 @@
                 "--thread-count",
                 "10",
                 "--desugared-lib",
-                ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString())
+                ToolHelper.getDesugarLibJsonForTesting().toString())
             .getThreadCount());
   }
 
@@ -423,7 +468,7 @@
                   "--thread-count",
                   value,
                   "--desugared-lib",
-                  ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString()));
+                  ToolHelper.getDesugarLibJsonForTesting().toString()));
       fail("Expected failure");
     } catch (CompilationFailedException e) {
       // Expected.
@@ -439,7 +484,7 @@
 
   @Override
   String[] requiredArgsForTest() {
-    return new String[] {"--desugared-lib", ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString()};
+    return new String[] {"--desugared-lib", ToolHelper.getDesugarLibJsonForTesting().toString()};
   }
 
   @Override
diff --git a/src/test/java/com/android/tools/r8/MarkersTest.java b/src/test/java/com/android/tools/r8/MarkersTest.java
index 1a7c92a..2ab8a16 100644
--- a/src/test/java/com/android/tools/r8/MarkersTest.java
+++ b/src/test/java/com/android/tools/r8/MarkersTest.java
@@ -66,7 +66,7 @@
             .setMinApiLevel(apiLevel.getLevel())
             .setMode(compilationMode)
             .addDesugaredLibraryConfiguration(
-                StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING))
+                StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
             .setOutput(output, OutputMode.DexIndexed);
     if (shrinkDesugaredLibrary) {
       builder.addProguardConfiguration(ImmutableList.of("-keep class * { *; }"), Origin.unknown());
@@ -75,7 +75,7 @@
     Collection<Marker> markers = ExtractMarker.extractMarkerFromDexFile(output);
     String version =
         new JsonParser()
-            .parse(FileUtils.readTextFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING, Charsets.UTF_8))
+            .parse(FileUtils.readTextFile(ToolHelper.getDesugarLibJsonForTesting(), Charsets.UTF_8))
             .getAsJsonObject()
             .get("version")
             .getAsString();
diff --git a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
index e9cd5ff..a6c4924 100644
--- a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
@@ -429,7 +429,7 @@
       AndroidApiLevel minApiLevel, KeepRuleConsumer keepRuleConsumer) {
     assert minApiLevel.getLevel() < AndroidApiLevel.O.getLevel();
     builder.addDesugaredLibraryConfiguration(
-        StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING));
+        StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()));
     // TODO(b/158543446): This should not be setting an implicit library file. Doing so causes
     //  inconsistent library setup depending on the api level and makes tests hard to read and
     //  reason about.
diff --git a/src/test/java/com/android/tools/r8/TestRuntime.java b/src/test/java/com/android/tools/r8/TestRuntime.java
index 04b61c0..20bf4b8 100644
--- a/src/test/java/com/android/tools/r8/TestRuntime.java
+++ b/src/test/java/com/android/tools/r8/TestRuntime.java
@@ -83,11 +83,13 @@
     return new CfRuntime(CfVm.JDK8, home);
   }
 
-  private static Path getCheckedInJdkHome(Path path) {
+  private static Path getCheckedInJdkHome(Path path, CfVm vm) {
     if (ToolHelper.isLinux()) {
       return path.resolve("linux");
     } else if (ToolHelper.isMac()) {
-      return path.resolve("osx");
+      return vm.lessThanOrEqual(CfVm.JDK9)
+          ? path.resolve("osx")
+          : path.resolve("osx/Contents/Home");
     } else {
       assert ToolHelper.isWindows();
       return path.resolve("windows");
@@ -95,16 +97,16 @@
   }
 
   public static CfRuntime getCheckedInJdk9() {
-    return new CfRuntime(CfVm.JDK9, getCheckedInJdkHome(JDK9_PATH));
+    return new CfRuntime(CfVm.JDK9, getCheckedInJdkHome(JDK9_PATH, CfVm.JDK9));
   }
 
   public static CfRuntime getCheckedInJdk11() {
-    return new CfRuntime(CfVm.JDK11, getCheckedInJdkHome(JDK11_PATH));
+    return new CfRuntime(CfVm.JDK11, getCheckedInJdkHome(JDK11_PATH, CfVm.JDK11));
   }
 
   // TODO(b/169692487): Add this to 'getCheckedInCfRuntimes' when we start having support for JDK15.
   public static CfRuntime getCheckedInJdk15() {
-    return new CfRuntime(CfVm.JDK15, getCheckedInJdkHome(JDK15_PATH));
+    return new CfRuntime(CfVm.JDK15, getCheckedInJdkHome(JDK15_PATH, CfVm.JDK15));
   }
 
   public static List<CfRuntime> getCheckedInCfRuntimes() {
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 9d0e9b5..18037be 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -133,9 +133,6 @@
   public static final String DEFAULT_PROGUARD_MAP_FILE = "proguard.map";
 
   public static final String JAVA_8_RUNTIME = "third_party/openjdk/openjdk-rt-1.8/rt.jar";
-  public static final String DESUGAR_JDK_LIBS =
-      System.getProperty(
-          "desugar_jdk_libs", "third_party/openjdk/desugar_jdk_libs/desugar_jdk_libs.jar");
   public static final String CORE_LAMBDA_STUBS =
       "third_party/core-lambda-stubs/core-lambda-stubs.jar";
   public static final String JSR223_RI_JAR = "third_party/jsr223-api-1.0/jsr223-api-1.0.jar";
@@ -180,12 +177,24 @@
 
   public static final Path DESUGAR_LIB_CONVERSIONS =
       Paths.get(LIBS_DIR, "library_desugar_conversions.zip");
-  public static final String DESUGAR_LIB_JSON_DIR =
-      System.getProperty("desugar_jdk_json_dir", "src/library_desugar");
-  public static final Path DESUGAR_LIB_JSON_FOR_TESTING =
-      Paths.get(DESUGAR_LIB_JSON_DIR, "desugar_jdk_libs.json");
-  public static final Path DESUGAR_LIB_JSON_FOR_TESTING_ALTERNATIVE_3 =
-      Paths.get(DESUGAR_LIB_JSON_DIR, "desugar_jdk_libs_alternative_3.json");
+
+  public static Path getDesugarJDKLibs() {
+    return Paths.get(
+        System.getProperty(
+            "desugar_jdk_libs", "third_party/openjdk/desugar_jdk_libs/desugar_jdk_libs.jar"));
+  }
+
+  private static String getDesugarLibraryJsonDir() {
+    return System.getProperty("desugar_jdk_json_dir", "src/library_desugar");
+  }
+
+  public static Path getDesugarLibJsonForTesting() {
+    return Paths.get(getDesugarLibraryJsonDir(), "desugar_jdk_libs.json");
+  }
+
+  public static Path getDesugarLibJsonForTestingAlternative3() {
+    return Paths.get(getDesugarLibraryJsonDir(), "desugar_jdk_libs_alternative_3.json");
+  }
 
   public static boolean isLocalDevelopment() {
     return System.getProperty("local_development", "0").equals("1");
@@ -758,10 +767,6 @@
     return Paths.get(JAVA_8_RUNTIME);
   }
 
-  public static Path getDesugarJDKLibs() {
-    return Paths.get(DESUGAR_JDK_LIBS);
-  }
-
   public static Path getCoreLambdaStubs() {
     return Paths.get(CORE_LAMBDA_STUBS);
   }
diff --git a/src/test/java/com/android/tools/r8/VersionTests.java b/src/test/java/com/android/tools/r8/VersionTests.java
index dad43b9..343ea89 100644
--- a/src/test/java/com/android/tools/r8/VersionTests.java
+++ b/src/test/java/com/android/tools/r8/VersionTests.java
@@ -33,12 +33,12 @@
     int minorVersion = Version.getMinorVersion();
     int patchVersion = Version.getPatchVersion();
     String preReleaseString = Version.getPreReleaseString();
-    if (LABEL.equals("master")) {
+    if (LABEL.equals("main")) {
       assertEquals(-1, majorVersion);
       assertEquals(-1, minorVersion);
       assertEquals(-1, patchVersion);
       assertNull(preReleaseString);
-      assertTrue(Version.getVersionString().startsWith("master"));
+      assertTrue(Version.getVersionString().startsWith("main"));
     } else {
       assertTrue(majorVersion > 0);
       assertTrue(minorVersion >= 0);
@@ -59,7 +59,7 @@
 
   @Test
   public void testDevelopmentPredicate() {
-   if (LABEL.equals("master") || LABEL.contains("-dev")) {
+    if (LABEL.equals("main") || LABEL.contains("-dev")) {
       assertTrue(Version.isDevelopmentVersion());
     } else {
       // This is a release branch, but Version.isDevelopmentVersion will still return true
@@ -70,13 +70,13 @@
 
   @Test
   public void testLabelParsing() {
-    assertEquals(-1, Version.getMajorVersion("master"));
-    assertEquals(-1, Version.getMinorVersion("master"));
-    assertEquals(-1, Version.getPatchVersion("master"));
-    assertNull(Version.getPreReleaseString("master"));
-    // 'master' is checked before 'isEngineering'.
-    assertTrue(Version.isDevelopmentVersion("master", false));
-    assertTrue(Version.isDevelopmentVersion("master", true));
+    assertEquals(-1, Version.getMajorVersion("main"));
+    assertEquals(-1, Version.getMinorVersion("main"));
+    assertEquals(-1, Version.getPatchVersion("main"));
+    assertNull(Version.getPreReleaseString("main"));
+    // 'main' is checked before 'isEngineering'.
+    assertTrue(Version.isDevelopmentVersion("main", false));
+    assertTrue(Version.isDevelopmentVersion("main", true));
 
     assertEquals(1, Version.getMajorVersion("1.2.3-dev"));
     assertEquals(2, Version.getMinorVersion("1.2.3-dev"));
diff --git a/src/test/java/com/android/tools/r8/accessrelaxation/PackagePrivateOverridePublicizerBottomTest.java b/src/test/java/com/android/tools/r8/accessrelaxation/PackagePrivateOverridePublicizerBottomTest.java
index 6dc8328..45ddf3e 100644
--- a/src/test/java/com/android/tools/r8/accessrelaxation/PackagePrivateOverridePublicizerBottomTest.java
+++ b/src/test/java/com/android/tools/r8/accessrelaxation/PackagePrivateOverridePublicizerBottomTest.java
@@ -64,8 +64,7 @@
         .enableNeverClassInliningAnnotations()
         .allowAccessModification()
         .run(parameters.getRuntime(), Main.class)
-        // TODO(b/182185057): This is an error in the devirtualizer
-        .assertSuccessWithOutputLines(EXPECTED_ART_4)
+        .apply(this::assertSuccessOutput)
         .inspect(
             inspector -> {
               ClassSubject subViewModelSubject =
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergeWithRepackageNameCollissionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergeWithRepackageNameCollissionTest.java
new file mode 100644
index 0000000..f3772a7
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergeWithRepackageNameCollissionTest.java
@@ -0,0 +1,104 @@
+// 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.classmerging.horizontal;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoHorizontalClassMerging;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.google.common.collect.ImmutableList;
+import java.util.Collection;
+import org.junit.Test;
+import org.junit.runners.Parameterized;
+
+public class MergeWithRepackageNameCollissionTest extends HorizontalClassMergingTestBase {
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withDexRuntimes().withAllApiLevels().build();
+  }
+
+  public MergeWithRepackageNameCollissionTest(TestParameters parameters) {
+    super(parameters);
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramClassFileData(getProgramFileData())
+        .addProgramClasses(I.class, Runner.class)
+        .addKeepMainRule(Main.class)
+        .addKeepClassAndMembersRules(I.class, Runner.class)
+        .setMinApi(parameters.getApiLevel())
+        .enableNoHorizontalClassMergingAnnotations()
+        .enableInliningAnnotations()
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines("C::baz", "Hello World");
+  }
+
+  private Collection<byte[]> getProgramFileData() throws Exception {
+    return ImmutableList.of(
+        transformer(A.class).setClassDescriptor("La/a;").transform(),
+        transformer(B.class).setClassDescriptor("Lb/a;").setSuper("La/a;").transform(),
+        transformer(D.class).setClassDescriptor("Lc/a;").transform(),
+        transformer(Main.class)
+            .replaceClassDescriptorInMethodInstructions(descriptor(A.class), "La/a;")
+            .replaceClassDescriptorInMethodInstructions(descriptor(B.class), "Lb/a;")
+            .replaceClassDescriptorInMethodInstructions(descriptor(D.class), "Lc/a;")
+            .transform());
+  }
+
+  public static /* will be: a.a */ class A {
+
+    @NeverInline
+    public static void foo() {
+      System.out.println("A::foo");
+    }
+  }
+
+  // a.a will be merged into b.a and thereby produce a mapping from a.a -> b.a in our lens.
+  public static /* will be: b.a */ class B extends A {}
+
+  // c.a will be repackaged to a.a
+  @NoHorizontalClassMerging
+  public static /* will be: c.a */ class D {
+
+    @NeverInline
+    public static void baz() {
+      System.out.println("C::baz");
+    }
+  }
+
+  public interface I {
+
+    void run();
+  }
+
+  public static class Runner {
+
+    @NeverInline
+    static void callI(I i) {
+      i.run();
+    }
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) {
+      D.baz();
+      callFoo(null);
+      Runner.callI(
+          () -> {
+            System.out.println("Hello World");
+          });
+    }
+
+    public static void callFoo(Object obj) {
+      if (obj != null) {
+        B.foo();
+      }
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/InvokeSuperToRewrittenDefaultMethodTest.java b/src/test/java/com/android/tools/r8/desugar/InvokeSuperToRewrittenDefaultMethodTest.java
index 93e46d0..5aa2894 100644
--- a/src/test/java/com/android/tools/r8/desugar/InvokeSuperToRewrittenDefaultMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/InvokeSuperToRewrittenDefaultMethodTest.java
@@ -76,7 +76,7 @@
                   // TODO(b/158543446): Remove this once enableCoreLibraryDesugaring is fixed.
                   b.getBuilder()
                       .addDesugaredLibraryConfiguration(
-                          StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING));
+                          StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()));
                 } else {
                   // TODO(b/158543446): Move this out to the shared builder once
                   //  enableCoreLibraryDesugaring is fixed.
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BackwardsCompatibleSpecificationTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BackwardsCompatibleSpecificationTest.java
index 6b46ee4..a922636 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BackwardsCompatibleSpecificationTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BackwardsCompatibleSpecificationTest.java
@@ -28,7 +28,7 @@
   }
 
   private final Path desugaredLib = ToolHelper.getDesugarJDKLibs();
-  private final Path desugaredSpec = ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING;
+  private final Path desugaredSpec = ToolHelper.getDesugarLibJsonForTesting();
   private final String release;
 
   public BackwardsCompatibleSpecificationTest(TestParameters parameters, String release) {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java
index f71c916..5cc22b7 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java
@@ -69,7 +69,7 @@
             options.reporter,
             libraryCompilation,
             parameters.getApiLevel().getLevel())
-        .parse(StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING_ALTERNATIVE_3));
+        .parse(StringResource.fromFile(ToolHelper.getDesugarLibJsonForTestingAlternative3()));
   }
 
   private void configurationForProgramCompilation(InternalOptions options) {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionTest.java
index 19cd88f..514742c 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionTest.java
@@ -223,8 +223,9 @@
 
       System.out.println(ccollection.spliterator().getClass().getName());
       System.out.println("j$.util.Spliterators$IteratorSpliterator");
+      // See SpliteratorTest for the concrete class name.
       System.out.println(cArrayList.spliterator().getClass().getName());
-      System.out.println("j$.util.Spliterators$IteratorSpliterator");
+      System.out.println(new ArrayList<>().spliterator().getClass().getName());
       System.out.println(cSortedSet.spliterator().getClass().getName());
       System.out.println("j$.util.SortedSet$1");
       System.out.println(customSortedSetWithReverseChain.spliterator().getClass().getName());
@@ -264,7 +265,8 @@
       System.out.println(ccollection.spliterator().getClass().getName());
       System.out.println("j$.util.Spliterators$IteratorSpliterator");
       System.out.println(cArrayList.spliterator().getClass().getName());
-      System.out.println("j$.util.Spliterators$IteratorSpliterator");
+      // See SpliteratorTest for the concrete class name.
+      System.out.println(new ArrayList<>().spliterator().getClass().getName());
       System.out.println(cSortedSet.spliterator().getClass().getName());
       System.out.println("j$.util.SortedSet$1");
       System.out.println(customSortedSetWithReverseChain.spliterator().getClass().getName());
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryChecksumsTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryChecksumsTest.java
index 6aff20f..bcefe74 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryChecksumsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryChecksumsTest.java
@@ -43,7 +43,7 @@
             .addProgramFiles(ToolHelper.DESUGAR_LIB_CONVERSIONS)
             .setMode(CompilationMode.DEBUG)
             .addDesugaredLibraryConfiguration(
-                StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING))
+                StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
             .setMinApiLevel(AndroidApiLevel.B.getLevel())
             .setOutput(out, OutputMode.DexIndexed)
             .build());
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryConfigurationParsingTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryConfigurationParsingTest.java
index 12ed820..348351b 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryConfigurationParsingTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryConfigurationParsingTest.java
@@ -115,7 +115,7 @@
   public void testReference() throws Exception {
     // Just test that the reference file parses without issues.
     DesugaredLibraryConfiguration config =
-        runPassing(StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING));
+        runPassing(StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()));
     assertEquals(libraryCompilation, config.isLibraryCompilation());
   }
 
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java
index d99b31f..02d036c 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java
@@ -70,7 +70,7 @@
             .addProgramFiles(ToolHelper.DESUGAR_LIB_CONVERSIONS)
             .addLibraryFiles(ToolHelper.getCoreLambdaStubs())
             .addDesugaredLibraryConfiguration(
-                StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING))
+                StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
             .setMinApiLevel(parameters.getApiLevel().getLevel())
             .setOutput(desugaredLib, OutputMode.DexIndexed);
     ToolHelper.runL8(l8Builder.build(), options -> {});
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java
index 4de3828..8f1d451 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java
@@ -41,12 +41,31 @@
 import java.util.List;
 import java.util.Map;
 import java.util.function.Consumer;
+import org.junit.BeforeClass;
 import org.objectweb.asm.ClassReader;
 import org.objectweb.asm.ClassVisitor;
 import org.objectweb.asm.MethodVisitor;
 
 public class DesugaredLibraryTestBase extends TestBase {
 
+  private static final boolean FORCE_JDK11_DESUGARED_LIB = false;
+
+  @BeforeClass
+  public static void setUpDesugaredLibrary() {
+    if (!FORCE_JDK11_DESUGARED_LIB) {
+      return;
+    }
+    System.setProperty("desugar_jdk_json_dir", "src/library_desugar/jdk11");
+    System.setProperty(
+        "desugar_jdk_libs", "third_party/openjdk/desugar_jdk_libs_11/desugar_jdk_libs.jar");
+    System.out.println("Forcing the usage of JDK11 desugared library.");
+  }
+
+  public static boolean isJDK11DesugaredLibrary() {
+    String property = System.getProperty("desugar_jdk_json_dir", "");
+    return property.contains("jdk11");
+  }
+
   // For conversions tests, we need DexRuntimes where classes to convert are present (DexRuntimes
   // above N and O depending if Stream or Time APIs are used), but we need to compile the program
   // with a minAPI below to force the use of conversions.
@@ -124,7 +143,7 @@
               .setMode(shrink ? CompilationMode.RELEASE : CompilationMode.DEBUG)
               .addProgramFiles(extraPaths)
               .addDesugaredLibraryConfiguration(
-                  StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING))
+                  StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
               .setMinApiLevel(apiLevel.getLevel())
               .setOutput(desugaredLib, OutputMode.DexIndexed);
       Path mapping = null;
@@ -201,7 +220,7 @@
             .addProgramFiles(ToolHelper.DESUGAR_LIB_CONVERSIONS)
             .setMode(CompilationMode.DEBUG)
             .addDesugaredLibraryConfiguration(
-                StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING))
+                StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
             .setMinApiLevel(parameters.getApiLevel().getLevel())
             .setOutput(desugaredLib, OutputMode.ClassFile);
 
@@ -220,7 +239,7 @@
             libraryCompilation,
             parameters.getApiLevel().getLevel())
         .parse(
-            StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING),
+            StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()),
             builder -> builder.setSupportAllCallbacksFromLibrary(supportAllCallbacksFromLibrary));
   }
 
@@ -240,7 +259,7 @@
             .addProgramFiles(ToolHelper.DESUGAR_LIB_CONVERSIONS)
             .setMode(CompilationMode.DEBUG)
             .addDesugaredLibraryConfiguration(
-                StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING))
+                StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
             .setMinApiLevel(apiLevel.getLevel())
             .setOutput(desugaredLib, OutputMode.ClassFile);
     ToolHelper.runL8(l8Builder.build());
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryWarningTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryWarningTest.java
index 8dd0d27..04411fb 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryWarningTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryWarningTest.java
@@ -58,7 +58,7 @@
             .addProgramFiles(ToolHelper.DESUGAR_LIB_CONVERSIONS)
             .setMode(shrinkDesugaredLibrary ? CompilationMode.RELEASE : CompilationMode.DEBUG)
             .addDesugaredLibraryConfiguration(
-                StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING))
+                StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
             .setMinApiLevel(parameters.getApiLevel().getLevel())
             .setOutput(desugaredLib, OutputMode.DexIndexed);
     if (shrinkDesugaredLibrary) {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmptyDesugaredLibrary.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmptyDesugaredLibrary.java
index 5b706e8..fc35e73 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmptyDesugaredLibrary.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmptyDesugaredLibrary.java
@@ -44,7 +44,7 @@
         .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addProgramFiles(ToolHelper.getDesugarJDKLibs())
         .addDesugaredLibraryConfiguration(
-            StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING))
+            StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
         .setMinApiLevel(minApiLevel.getLevel());
   }
 
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 cae7a4a..9cb9cea 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
@@ -195,7 +195,7 @@
     DesugaredLibraryConfigurationParser parser =
         new DesugaredLibraryConfigurationParser(
             new DexItemFactory(), null, true, minApi.getLevel());
-    return parser.parse(StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING));
+    return parser.parse(StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()));
   }
 
   private Map<ClassReference, Set<MethodReference>> getDirectlyReferencedWrapperTypes(
@@ -275,8 +275,8 @@
     Path out = temp.newFolder().toPath();
     GenerateLintFiles desugaredApi =
         new GenerateLintFiles(
-            ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString(),
-            ToolHelper.DESUGAR_JDK_LIBS,
+            ToolHelper.getDesugarLibJsonForTesting().toString(),
+            ToolHelper.getDesugarJDKLibs().toString(),
             out.toString());
     desugaredApi.run(targetApi.getLevel());
     return new CodeInspector(
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
new file mode 100644
index 0000000..41935e4
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IterateTest.java
@@ -0,0 +1,102 @@
+// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.desugar.desugaredlibrary;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.StringUtils;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.stream.IntStream;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class IterateTest extends DesugaredLibraryTestBase {
+
+  private final TestParameters parameters;
+  private final boolean shrinkDesugaredLibrary;
+  private static final String EXPECTED_OUTPUT = StringUtils.lines("1");
+
+  @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        BooleanUtils.values(),
+        getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build());
+  }
+
+  public IterateTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
+    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testIterateD8Cf() throws Exception {
+    // Only test without shrinking desugared library.
+    Assume.assumeFalse(shrinkDesugaredLibrary);
+    // Use D8 to desugar with Java classfile output.
+    Path jar =
+        testForD8(Backend.CF)
+            .addInnerClasses(IterateTest.class)
+            .setMinApi(parameters.getApiLevel())
+            .enableCoreLibraryDesugaring(parameters.getApiLevel())
+            .compile()
+            .writeToZip();
+
+    if (parameters.getRuntime().isDex()) {
+      // Convert to DEX without desugaring and run.
+      testForD8()
+          .addProgramFiles(jar)
+          .setMinApi(parameters.getApiLevel())
+          .disableDesugaring()
+          .compile()
+          .addRunClasspathFiles(buildDesugaredLibrary(parameters.getApiLevel()))
+          .run(parameters.getRuntime(), Main.class)
+          .assertSuccessWithOutput(EXPECTED_OUTPUT);
+    } else {
+      // Run on the JVM with desugared library on classpath.
+      testForJvm()
+          .addProgramFiles(jar)
+          .addRunClasspathFiles(buildDesugaredLibraryClassFile(parameters.getApiLevel()))
+          .run(parameters.getRuntime(), Main.class)
+          .assertSuccessWithOutput(EXPECTED_OUTPUT);
+    }
+  }
+
+  @Test
+  public void testIterate() throws Exception {
+    if (parameters.isCfRuntime()) {
+      testForJvm()
+          .addInnerClasses(IterateTest.class)
+          .run(parameters.getRuntime(), Main.class)
+          .assertSuccessWithOutput(EXPECTED_OUTPUT);
+      return;
+    }
+    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
+    testForD8()
+        .addInnerClasses(IterateTest.class)
+        .setMinApi(parameters.getApiLevel())
+        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+        .compile()
+        .addDesugaredCoreLibraryRunClassPath(
+            this::buildDesugaredLibrary,
+            parameters.getApiLevel(),
+            keepRuleConsumer.get(),
+            shrinkDesugaredLibrary)
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
+  }
+
+  static class Main {
+
+    public static void main(String[] args) {
+      IntStream iterate = IntStream.iterate(1, x -> x + 3);
+      System.out.println(iterate.findFirst().getAsInt());
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java
index 624e8a0..f5f2275 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java
@@ -120,15 +120,15 @@
     Path directory = temp.newFolder().toPath();
     GenerateLintFiles.main(
         new String[] {
-          ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING.toString(),
-          ToolHelper.DESUGAR_JDK_LIBS,
+          ToolHelper.getDesugarLibJsonForTesting().toString(),
+          ToolHelper.getDesugarJDKLibs().toString(),
           directory.toString()
         });
     InternalOptions options = new InternalOptions(new DexItemFactory(), new Reporter());
     DesugaredLibraryConfiguration desugaredLibraryConfiguration =
         new DesugaredLibraryConfigurationParser(
                 options.itemFactory, options.reporter, false, AndroidApiLevel.B.getLevel())
-            .parse(StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING));
+            .parse(StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()));
 
     for (AndroidApiLevel apiLevel : AndroidApiLevel.values()) {
       Path compileApiLevelDirectory = directory.resolve("compile_api_level_" + apiLevel.getLevel());
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingJ$Test.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingJ$Test.java
index 0245f6e..a8462e1 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingJ$Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingJ$Test.java
@@ -106,7 +106,7 @@
             .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .addProgramFiles(ToolHelper.getDesugarJDKLibs())
             .addDesugaredLibraryConfiguration(
-                StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING))
+                StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
             .setMinApiLevel(AndroidApiLevel.B.getLevel())
             .setOutput(outputDex, OutputMode.DexIndexed)
             .build());
@@ -121,7 +121,7 @@
             .addProgramFiles(JDK_11_JAVA_BASE_EXTENSION_COMPILED_FILES)
             .addClasspathFiles(ToolHelper.getDesugarJDKLibs())
             .addDesugaredLibraryConfiguration(
-                StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING))
+                StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
             .setMinApiLevel(AndroidApiLevel.B.getLevel())
             .setOutput(outputDex, OutputMode.DexIndexed)
             .build());
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ObjectsTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ObjectsTest.java
index f62067c..efddc67 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ObjectsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ObjectsTest.java
@@ -75,8 +75,8 @@
         .parse(
             StringResource.fromFile(
                 libraryDesugarJavaUtilObjects
-                    ? ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING_ALTERNATIVE_3
-                    : ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING));
+                    ? ToolHelper.getDesugarLibJsonForTestingAlternative3()
+                    : ToolHelper.getDesugarLibJsonForTesting()));
   }
 
   private void configurationForProgramCompilation(InternalOptions options) {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramRewritingTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramRewritingTest.java
index 082253b..aa05c9d 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramRewritingTest.java
@@ -14,7 +14,6 @@
 import com.android.tools.r8.D8TestRunResult;
 import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestShrinkerBuilder;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.DexVm;
 import com.android.tools.r8.utils.AndroidApiLevel;
@@ -154,28 +153,24 @@
             .streamInstructions()
             .filter(instr -> instr.isInvokeInterface() || instr.isInvokeStatic())
             .collect(Collectors.toList());
-    assertEquals(23, invokes.size());
+    assertEquals(22, invokes.size());
     assertInvokeStaticMatching(invokes, 0, "Set$-EL;->spliterator");
-    assertInvokeStaticMatching(invokes, 1, "List$-EL;->spliterator");
-    assertInvokeStaticMatching(invokes, 2, "Collection$-EL;->stream");
-    assertInvokeInterfaceMatching(invokes, 3, "Set;->iterator");
-    assertInvokeStaticMatching(invokes, 4, "Collection$-EL;->stream");
-    assertInvokeStaticMatching(invokes, 5, "Set$-EL;->spliterator");
-    assertInvokeInterfaceMatching(invokes, 9, "Iterator;->remove");
+    assertInvokeStaticMatching(invokes, 1, "Collection$-EL;->stream");
+    assertInvokeInterfaceMatching(invokes, 2, "Set;->iterator");
+    assertInvokeStaticMatching(invokes, 3, "Collection$-EL;->stream");
+    assertInvokeStaticMatching(invokes, 4, "Set$-EL;->spliterator");
+    assertInvokeInterfaceMatching(invokes, 8, "Iterator;->remove");
+    assertInvokeStaticMatching(invokes, 9, "DesugarArrays;->spliterator");
     assertInvokeStaticMatching(invokes, 10, "DesugarArrays;->spliterator");
-    assertInvokeStaticMatching(invokes, 11, "DesugarArrays;->spliterator");
+    assertInvokeStaticMatching(invokes, 11, "DesugarArrays;->stream");
     assertInvokeStaticMatching(invokes, 12, "DesugarArrays;->stream");
-    assertInvokeStaticMatching(invokes, 13, "DesugarArrays;->stream");
-    assertInvokeStaticMatching(invokes, 14, "Collection$-EL;->stream");
-    assertInvokeStaticMatching(invokes, 15, "IntStream$-CC;->range");
-    assertInvokeStaticMatching(invokes, 17, "Comparator$-CC;->comparingInt");
-    assertInvokeStaticMatching(invokes, 18, "List$-EL;->sort");
-    assertInvokeStaticMatching(invokes, 20, "Comparator$-CC;->comparingInt");
-    assertInvokeStaticMatching(invokes, 21, "List$-EL;->sort");
-    assertInvokeStaticMatching(invokes, 22, "Collection$-EL;->stream");
-    // TODO (b/134732760): Support Java 9 Stream APIs
-    // assertTrue(invokes.get(17).isInvokeStatic());
-    // assertTrue(invokes.get(17).toString().contains("Stream$-CC;->iterate"));
+    assertInvokeStaticMatching(invokes, 13, "Collection$-EL;->stream");
+    assertInvokeStaticMatching(invokes, 14, "IntStream$-CC;->range");
+    assertInvokeStaticMatching(invokes, 16, "Comparator$-CC;->comparingInt");
+    assertInvokeStaticMatching(invokes, 17, "List$-EL;->sort");
+    assertInvokeStaticMatching(invokes, 19, "Comparator$-CC;->comparingInt");
+    assertInvokeStaticMatching(invokes, 20, "List$-EL;->sort");
+    assertInvokeStaticMatching(invokes, 21, "Collection$-EL;->stream");
   }
 
   private void assertInvokeInterfaceMatching(List<InstructionSubject> invokes, int i, String s) {
@@ -193,7 +188,6 @@
         StringUtils.lines(
             "-keep class j$.util.List$-EL {",
             "    void sort(java.util.List, java.util.Comparator);",
-            "    j$.util.Spliterator spliterator(java.util.List);",
             "}",
             "-keep class j$.util.Collection$-EL {",
             "    j$.util.stream.Stream stream(java.util.Collection);",
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/SpliteratorTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/SpliteratorTest.java
new file mode 100644
index 0000000..5af29c3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/SpliteratorTest.java
@@ -0,0 +1,103 @@
+// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.desugar.desugaredlibrary;
+
+import static junit.framework.TestCase.assertTrue;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class SpliteratorTest extends DesugaredLibraryTestBase {
+
+  private final TestParameters parameters;
+  private static final String EXPECTED_OUTPUT_JDK11 =
+      StringUtils.lines(
+          "j$.util.AbstractList$RandomAccessSpliterator",
+          "j$.util.AbstractList$RandomAccessSpliterator",
+          "j$.util.Spliterators$IteratorSpliterator",
+          "j$.util.Spliterators$IteratorSpliterator");
+  private static final String EXPECTED_OUTPUT_JDK8 =
+      StringUtils.lines(
+          "j$.util.Spliterators$IteratorSpliterator",
+          "j$.util.Spliterators$IteratorSpliterator",
+          "j$.util.Spliterators$IteratorSpliterator",
+          "j$.util.Spliterators$IteratorSpliterator");
+
+  @Parameters(name = "{0}")
+  public static List<Object[]> data() {
+    return buildParameters(getTestParameters().withDexRuntimes().withAllApiLevels().build());
+  }
+
+  public SpliteratorTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testSpliterator() throws Exception {
+    Assume.assumeTrue(requiresEmulatedInterfaceCoreLibDesugaring(parameters));
+    testForD8()
+        .addInnerClasses(SpliteratorTest.class)
+        .setMinApi(parameters.getApiLevel())
+        .enableCoreLibraryDesugaring(parameters.getApiLevel())
+        .compile()
+        .inspect(this::validateInterfaces)
+        .addDesugaredCoreLibraryRunClassPath(this::buildDesugaredLibrary, parameters.getApiLevel())
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutput(
+            isJDK11DesugaredLibrary() ? EXPECTED_OUTPUT_JDK11 : EXPECTED_OUTPUT_JDK8);
+  }
+
+  private void validateInterfaces(CodeInspector inspector) {
+    assertTrue(
+        inspector
+            .clazz("com.android.tools.r8.desugar.desugaredlibrary.SpliteratorTest$MyArrayList")
+            .getDexProgramClass()
+            .interfaces
+            .toString()
+            .contains("j$.util.List"));
+    assertTrue(
+        inspector
+            .clazz("com.android.tools.r8.desugar.desugaredlibrary.SpliteratorTest$MyLinkedList")
+            .getDexProgramClass()
+            .interfaces
+            .toString()
+            .contains("j$.util.List"));
+  }
+
+  static class Main {
+
+    public static void main(String[] args) {
+      System.out.println(new ArrayList<>().spliterator().getClass().getName());
+      System.out.println(new MyArrayList<>().spliterator().getClass().getName());
+      System.out.println(new LinkedList<>().spliterator().getClass().getName());
+      System.out.println(new MyLinkedList<>().spliterator().getClass().getName());
+    }
+  }
+
+  static class MyArrayList<E> extends ArrayList<E> {
+    @Override
+    public void sort(Comparator<? super E> c) {
+      // Override to force j$ interface.
+    }
+  }
+
+  static class MyLinkedList<E> extends LinkedList<E> {
+    @Override
+    public void sort(Comparator<? super E> c) {
+      // Override to force j$ interface.
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionsPresentTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionsPresentTest.java
index 43d5b9a..3fe90f3 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionsPresentTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionsPresentTest.java
@@ -48,7 +48,7 @@
             .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .addProgramFiles(ToolHelper.DESUGAR_LIB_CONVERSIONS)
             .addDesugaredLibraryConfiguration(
-                StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING))
+                StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
             .setMinApiLevel(parameters.getApiLevel().getLevel())
             .setOutput(desugaredLib, OutputMode.DexIndexed);
     ToolHelper.runL8(l8Builder.build(), x -> {});
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIDesugaredLibTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIDesugaredLibTest.java
index 812cd34..9a251a9 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIDesugaredLibTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIDesugaredLibTest.java
@@ -82,8 +82,12 @@
 
   private void assertDupMethod(CodeInspector inspector, boolean supportAllCallbacksFromLibrary) {
     ClassSubject clazz = inspector.clazz("j$.util.concurrent.ConcurrentHashMap");
+    int numForEachMethods =
+        isJDK11DesugaredLibrary()
+            ? supportAllCallbacksFromLibrary ? 4 : 3
+            : supportAllCallbacksFromLibrary ? 2 : 1;
     assertEquals(
-        supportAllCallbacksFromLibrary ? 2 : 1,
+        numForEachMethods,
         clazz.virtualMethods().stream().filter(m -> m.getOriginalName().equals("forEach")).count());
   }
 
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11StreamTests.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11StreamTests.java
index 0901c28..355343d 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11StreamTests.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11StreamTests.java
@@ -73,23 +73,31 @@
     return files;
   }
 
-  private static String[] FAILING_RUNNABLE_TESTS =
-      new String[] {
-        // J9 failure.
-        "org/openjdk/tests/java/util/stream/SpliteratorTest.java",
-        "org/openjdk/tests/java/util/stream/WhileOpStatefulTest.java",
-        "org/openjdk/tests/java/util/stream/IterateTest.java",
-        "org/openjdk/tests/java/util/stream/WhileOpTest.java",
-        // Assertion error
-        "org/openjdk/tests/java/util/stream/StreamCloseTest.java",
-        "org/openjdk/tests/java/util/stream/CollectAndSummaryStatisticsTest.java",
-        "org/openjdk/tests/java/util/stream/CountTest.java",
-        // J9 Random problem
-        "org/openjdk/tests/java/util/stream/LongPrimitiveOpsTests.java",
-        "org/openjdk/tests/java/util/stream/IntPrimitiveOpsTests.java",
-        "org/openjdk/tests/java/util/stream/DoublePrimitiveOpsTests.java"
+  private static final String[] FAILING_RUNNABLE_TESTS = new String[] {
+        // Disabled, D8 generated code raises AbstractMethodError instead of NPE because of API
+        // unsupported in the desugared library.
+        // "org/openjdk/tests/java/util/stream/SpliteratorTest.java",
+        // Disabled because both the stream close issue and the Random issue (See below).
+        // "org/openjdk/tests/java/util/stream/LongPrimitiveOpsTests.java",
         // Disabled because explicit cast done on a wrapped value.
         // "org/openjdk/tests/java/util/SplittableRandomTest.java",
+        // Disabled due to a desugaring failure due to the extended library used for the test.
+        // "org/openjdk/tests/java/util/stream/IterateTest.java",
+      };
+
+  // Cannot succeed with JDK 8 desugared library because use J9 features.
+  // Stream close issue with try with resource desugaring mixed with partial library desugaring.
+  public static final String[] STREAM_CLOSE_TESTS =
+      new String[] {"org/openjdk/tests/java/util/stream/StreamCloseTest.java"};
+
+  // Cannot succeed with JDK 8 desugared library because use J9 features.
+  public static final String[] SUCCESSFUL_RUNNABLE_TESTS_ON_JDK11_AND_V7 =
+      new String[] {
+        // Require the virtual method isDefault() in class java/lang/reflect/Method.
+        "org/openjdk/tests/java/util/stream/WhileOpTest.java",
+        "org/openjdk/tests/java/util/stream/WhileOpStatefulTest.java",
+        // Require a Random method not present before Android 7 and not desugared.
+        "org/openjdk/tests/java/util/stream/IntPrimitiveOpsTests.java"
       };
 
   // Disabled because time to run > 1 min for each test.
@@ -108,6 +116,15 @@
         "org/openjdk/tests/java/util/stream/ToArrayOpTest.java"
       };
 
+  private static final String[] SUCCESSFUL_RUNNABLE_TESTS_ON_JDK11_ONLY =
+      new String[] {
+        // Assertion error
+        "org/openjdk/tests/java/util/stream/CollectAndSummaryStatisticsTest.java",
+        "org/openjdk/tests/java/util/stream/CountTest.java",
+        // J9 Random problem
+        "org/openjdk/tests/java/util/stream/DoublePrimitiveOpsTests.java",
+      };
+
   private static String[] SUCCESSFUL_RUNNABLE_TESTS =
       new String[] {
         "org/openjdk/tests/java/util/stream/FindFirstOpTest.java",
@@ -136,6 +153,37 @@
         "org/openjdk/tests/java/util/stream/FindAnyOpTest.java"
       };
 
+  private Map<String, String> getSuccessfulTests() {
+    Map<String, String> runnableTests = getRunnableTests(SUCCESSFUL_RUNNABLE_TESTS);
+    if (isJDK11DesugaredLibrary()) {
+      runnableTests.putAll(getRunnableTests(SUCCESSFUL_RUNNABLE_TESTS_ON_JDK11_ONLY));
+      if (parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V7_0_0)) {
+        runnableTests.putAll(getRunnableTests(SUCCESSFUL_RUNNABLE_TESTS_ON_JDK11_AND_V7));
+      }
+      if (!parameters.getApiLevel().isLessThanOrEqualTo(AndroidApiLevel.K)) {
+        runnableTests.putAll(getRunnableTests(STREAM_CLOSE_TESTS));
+      }
+    }
+    return runnableTests;
+  }
+
+  private Map<String, String> getFailingTests() {
+    Map<String, String> runnableTests = getRunnableTests(FAILING_RUNNABLE_TESTS);
+    if (!isJDK11DesugaredLibrary()) {
+      runnableTests.putAll(getRunnableTests(SUCCESSFUL_RUNNABLE_TESTS_ON_JDK11_ONLY));
+      runnableTests.putAll(getRunnableTests(SUCCESSFUL_RUNNABLE_TESTS_ON_JDK11_AND_V7));
+      runnableTests.putAll(getRunnableTests(STREAM_CLOSE_TESTS));
+    } else {
+      if (parameters.getApiLevel().isLessThanOrEqualTo(AndroidApiLevel.K)) {
+        runnableTests.putAll(getRunnableTests(STREAM_CLOSE_TESTS));
+      }
+      if (!parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V7_0_0)) {
+        runnableTests.putAll(getRunnableTests(SUCCESSFUL_RUNNABLE_TESTS_ON_JDK11_AND_V7));
+      }
+    }
+    return runnableTests;
+  }
+
   private static Map<String, String> getRunnableTests(String[] tests) {
     IdentityHashMap<String, String> pathToName = new IdentityHashMap<>();
     int javaExtSize = JAVA_EXTENSION.length();
@@ -150,16 +198,18 @@
 
   private static String[] missingDesugaredMethods() {
     // These methods are from Java 9 and not supported in the current desugared libraries.
-    return new String[]{
-        // Stream
-        "takeWhile(",
-        "dropWhile(",
-        "iterate(",
-        "range(",
-        "doubles(",
-        // Collectors
-        "filtering(",
-        "flatMapping(",
+    return new String[] {
+      // Stream
+      "takeWhile(",
+      "dropWhile(",
+      "iterate(",
+      "range(",
+      "doubles(",
+      // Collectors
+      "filtering(",
+      "flatMapping(",
+      // isDefault()Z in class Ljava/lang/reflect/Method
+      "isDefault("
     };
   }
 
@@ -262,7 +312,7 @@
 
   private void runSuccessfulTests(D8TestCompileResult compileResult) throws Exception {
     String verbosity = "2"; // Increase verbosity for debugging.
-    Map<String, String> runnableTests = getRunnableTests(SUCCESSFUL_RUNNABLE_TESTS);
+    Map<String, String> runnableTests = getSuccessfulTests();
     for (String path : runnableTests.keySet()) {
       assert runnableTests.get(path) != null;
       D8TestRunResult result =
@@ -281,7 +331,7 @@
     // For failing runnable tests, we just ensure that they do not fail due to desugaring, but
     // due to an expected failure (missing API, etc.).
     String verbosity = "2"; // Increase verbosity for debugging.
-    Map<String, String> runnableTests = getRunnableTests(FAILING_RUNNABLE_TESTS);
+    Map<String, String> runnableTests = getFailingTests();
     for (String path : runnableTests.keySet()) {
       assert runnableTests.get(path) != null;
       D8TestRunResult result =
@@ -291,9 +341,6 @@
       if (stdout.contains("java.lang.NoSuchMethodError")
           && Arrays.stream(missingDesugaredMethods()).anyMatch(stdout::contains)) {
         // TODO(b/134732760): support Java 9 APIs.
-      } else if (stdout.contains("java.lang.NoSuchMethodError")
-          && stdout.contains("org.openjdk.tests.java.util.stream.IterateTest.testIterate")) {
-        // TODO(b/134732760): support Java 9 APIs.
       } else if (stdout.contains("in class Ljava/util/Random")
           && stdout.contains("java.lang.NoSuchMethodError")) {
         // TODO(b/134732760): Random Java 9 Apis, support or do not use them.
diff --git a/src/test/java/com/android/tools/r8/desugar/lambdas/ExplicitCallToJavacGeneratedInstanceLambdaMethodTest.java b/src/test/java/com/android/tools/r8/desugar/lambdas/ExplicitCallToJavacGeneratedInstanceLambdaMethodTest.java
index 721e41d..ac20adf 100644
--- a/src/test/java/com/android/tools/r8/desugar/lambdas/ExplicitCallToJavacGeneratedInstanceLambdaMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/lambdas/ExplicitCallToJavacGeneratedInstanceLambdaMethodTest.java
@@ -43,10 +43,7 @@
         .addProgramClasses(Main.class, A.class, FunctionalInterface.class)
         .addProgramClassFileData(getProgramClassFileData())
         .run(parameters.getRuntime(), Main.class)
-        .applyIf(
-            parameters.isCfRuntime(),
-            result -> result.assertSuccessWithOutputLines("Hello world!", "Hello world!"),
-            result -> result.assertFailureWithErrorThatThrows(NoSuchMethodError.class));
+        .assertSuccessWithOutputLines("Hello world!", "Hello world!");
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/PackagePrivateOverrideDeVirtualizerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/PackagePrivateOverrideDeVirtualizerTest.java
index b3ca988..33da30f 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/PackagePrivateOverrideDeVirtualizerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/PackagePrivateOverrideDeVirtualizerTest.java
@@ -56,8 +56,7 @@
         .enableNoVerticalClassMergingAnnotations()
         .enableNeverClassInliningAnnotations()
         .run(parameters.getRuntime(), Main.class)
-        // TODO(b/182185057): This should be EXPECTED.
-        .assertSuccessWithOutputLines(EXPECTED_DALVIK);
+        .apply(this::assertSuccessOutput);
   }
 
   private byte[] getSubViewModelInAnotherPackage() throws Exception {
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageDontObfuscateTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageDontObfuscateTest.java
new file mode 100644
index 0000000..5ece41d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageDontObfuscateTest.java
@@ -0,0 +1,109 @@
+// 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.repackage;
+
+import static com.android.tools.r8.shaking.ProguardConfigurationParser.FLATTEN_PACKAGE_HIERARCHY;
+import static com.android.tools.r8.shaking.ProguardConfigurationParser.REPACKAGE_CLASSES;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.ProguardVersion;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * A simple test that checks that R8 behaves the same as PG for repackaging. We do require that
+ * classes that are looked up reflectively are kept in some way, however, for easier debugging with
+ * -dontobfuscate we should follow PG behavior. *
+ */
+@RunWith(Parameterized.class)
+public class RepackageDontObfuscateTest extends RepackageTestBase {
+
+  private final String[] EXPECTED = new String[] {"A::foo", "A::foo", "A::foo"};
+
+  @Parameters(name = "{1}, kind: {0}, PG-version: {2}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        ImmutableList.of(FLATTEN_PACKAGE_HIERARCHY, REPACKAGE_CLASSES),
+        getTestParameters().withAllRuntimesAndApiLevels().build(),
+        ProguardVersion.values());
+  }
+
+  private final ProguardVersion proguardVersion;
+
+  public RepackageDontObfuscateTest(
+      String flattenPackageHierarchyOrRepackageClasses,
+      TestParameters parameters,
+      ProguardVersion proguardVersion) {
+    super(flattenPackageHierarchyOrRepackageClasses, parameters);
+    this.proguardVersion = proguardVersion;
+  }
+
+  @Test
+  public void testPG() throws Exception {
+    assumeTrue(parameters.isCfRuntime());
+    testForProguard(proguardVersion)
+        .addInnerClasses(getClass())
+        .addKeepMainRule(Main.class)
+        .apply(this::configureRepackaging)
+        .addInliningAnnotations()
+        .addDontWarn(RepackageDontObfuscateTest.class)
+        .noMinification()
+        .compile()
+        .inspect(
+            inspector -> {
+              ClassSubject aClass = inspector.clazz(A.class);
+              assertThat(aClass, isPresentAndNotRenamed());
+            })
+        .run(parameters.getRuntime(), Main.class, A.class.getTypeName())
+        .assertSuccessWithOutputLines(EXPECTED);
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(getClass())
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(Main.class)
+        .enableInliningAnnotations()
+        .apply(this::configureRepackaging)
+        .noMinification()
+        .compile()
+        .inspect(
+            inspector -> {
+              ClassSubject aClass = inspector.clazz(A.class);
+              assertThat(aClass, isPresentAndNotRenamed());
+            })
+        .run(parameters.getRuntime(), Main.class, A.class.getTypeName())
+        .assertSuccessWithOutputLines(EXPECTED);
+  }
+
+  public static class A {
+
+    @NeverInline
+    public static void foo() {
+      System.out.println("A::foo");
+    }
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) throws Exception {
+      A.foo();
+      Class.forName("com.android.tools.r8.repackage.RepackageDontObfuscateTest$A")
+          .getDeclaredMethod("foo")
+          .invoke(null);
+      Class.forName(args[0]).getDeclaredMethod("foo").invoke(null);
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageFeatureWithSyntheticsTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageFeatureWithSyntheticsTest.java
index 4eb6d15..5e62057 100644
--- a/src/test/java/com/android/tools/r8/repackage/RepackageFeatureWithSyntheticsTest.java
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageFeatureWithSyntheticsTest.java
@@ -92,7 +92,6 @@
             .addKeepMethodRules(
                 Reference.methodFromMethod(TestClass.class.getDeclaredMethod("run", I.class)))
             .addKeepAttributeInnerClassesAndEnclosingMethod()
-            .noMinification()
             .apply(this::configureRepackaging)
             .enableNeverClassInliningAnnotations()
             .setMinApi(parameters.getApiLevel())
@@ -107,14 +106,14 @@
     // If it is, the access will fail resulting in a runtime exception.
     compileResult.inspect(
         baseInspector -> {
-          assertThat(FIRST_FOO, isRepackagedAsExpected(baseInspector, "first"));
+          assertThat(FIRST_FOO, isRepackagedAsExpected(baseInspector, "a"));
           assertThat(FIRST_PKG_PRIVATE, isNotRepackaged(baseInspector));
           assertEquals(
               getTestClasses().size() + expectedSyntheticsInBase,
               baseInspector.allClasses().size());
         },
         featureInspector -> {
-          assertThat(FIRST_FIRST_FOO, isRepackagedAsExpected(featureInspector, "first$1"));
+          assertThat(FIRST_FIRST_FOO, isRepackagedAsExpected(featureInspector, "b"));
           assertThat(FIRST_FIRST_PKG_PRIVATE, isNotRepackaged(featureInspector));
           assertEquals(
               getFeatureClasses().size() + expectedSyntheticsInFeature,
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageTestBase.java b/src/test/java/com/android/tools/r8/repackage/RepackageTestBase.java
index 788bb0a..616295a 100644
--- a/src/test/java/com/android/tools/r8/repackage/RepackageTestBase.java
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageTestBase.java
@@ -7,9 +7,9 @@
 import static com.android.tools.r8.shaking.ProguardConfigurationParser.FLATTEN_PACKAGE_HIERARCHY;
 import static com.android.tools.r8.shaking.ProguardConfigurationParser.REPACKAGE_CLASSES;
 
-import com.android.tools.r8.R8TestBuilder;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestShrinkerBuilder;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -130,7 +130,7 @@
     };
   }
 
-  protected void configureRepackaging(R8TestBuilder<?> testBuilder) {
+  protected void configureRepackaging(TestShrinkerBuilder<?, ?, ?, ?, ?> testBuilder) {
     testBuilder.addKeepRules(
         "-" + flattenPackageHierarchyOrRepackageClasses + " \"" + getRepackagePackage() + "\"");
   }
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageWithSuffixRenamingConfigurationTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageWithSuffixRenamingConfigurationTest.java
index b22042f..dcfd6c3 100644
--- a/src/test/java/com/android/tools/r8/repackage/RepackageWithSuffixRenamingConfigurationTest.java
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageWithSuffixRenamingConfigurationTest.java
@@ -30,10 +30,12 @@
         .addKeepMainRule(TestClass.class)
         .addKeepClassRules(GreeterFoo.class)
         .addOptionsModification(
-            options ->
-                options.testing.repackagingConfigurationFactory =
-                    appView ->
-                        new SuffixRenamingRepackagingConfiguration("Foo", appView.dexItemFactory()))
+            options -> {
+              options.testing.repackageWithNoMinification = true;
+              options.testing.repackagingConfigurationFactory =
+                  appView ->
+                      new SuffixRenamingRepackagingConfiguration("Foo", appView.dexItemFactory());
+            })
         .apply(this::configureRepackaging)
         .enableInliningAnnotations()
         .noMinification()
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageWithSyntheticItemTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageWithSyntheticItemTest.java
index 4df6622..1a3bfca 100644
--- a/src/test/java/com/android/tools/r8/repackage/RepackageWithSyntheticItemTest.java
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageWithSyntheticItemTest.java
@@ -67,7 +67,7 @@
               // TODO(b/172014416): We should not be able to look this up through the repackage name
               String expectedOriginalNamePrefix =
                   isFlattenPackageHierarchy()
-                      ? "foo.repackage.RepackageWithSyntheticItemTest$A"
+                      ? "foo.a.RepackageWithSyntheticItemTest$A"
                       : "foo.RepackageWithSyntheticItemTest$A";
               assertThat(
                   classesStartingWithfoo.get(0).getOriginalName(),
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java b/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java
index aa543c8..41d1c3f 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceLambdaTest.java
@@ -5,15 +5,23 @@
 package com.android.tools.r8.retrace;
 
 import static com.android.tools.r8.naming.retrace.StackTrace.isSameExceptForFileNameAndLineNumber;
+import static com.android.tools.r8.references.Reference.classFromClass;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isCompilerSynthesized;
 import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.naming.retrace.StackTrace;
+import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
+import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
+import com.google.common.collect.ImmutableList;
+import java.util.Collection;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -48,22 +56,48 @@
         .run(parameters.getRuntime(), Main.class)
         .assertFailureWithErrorThatMatches(containsString("Hello World!"))
         .inspectStackTrace(
-            stackTrace -> {
-              assertThat(
-                  stackTrace,
-                  isSameExceptForFileNameAndLineNumber(
-                      StackTrace.builder()
-                          .addWithoutFileNameAndLineNumber(Main.class, JAVAC_LAMBDA_METHOD)
-                          // TODO(b/172014416): Support a D8 mapping and prune the synthetic.
-                          .applyIf(
-                              parameters.isDexRuntime(),
-                              b ->
-                                  b.addWithoutFileNameAndLineNumber(
-                                      SyntheticItemsTestUtils.syntheticLambdaClass(Main.class, 0),
-                                      "run"))
-                          .addWithoutFileNameAndLineNumber(Main.class, "runIt")
-                          .addWithoutFileNameAndLineNumber(Main.class, "main")
-                          .build()));
+            stackTrace ->
+                assertThat(
+                    stackTrace,
+                    isSameExceptForFileNameAndLineNumber(
+                        StackTrace.builder()
+                            .addWithoutFileNameAndLineNumber(Main.class, JAVAC_LAMBDA_METHOD)
+                            // TODO(b/172014416): Support a D8 mapping and prune the synthetic.
+                            .applyIf(
+                                parameters.isDexRuntime(),
+                                b ->
+                                    b.addWithoutFileNameAndLineNumber(
+                                        SyntheticItemsTestUtils.syntheticLambdaClass(Main.class, 0),
+                                        "run"))
+                            .addWithoutFileNameAndLineNumber(Main.class, "runIt")
+                            .addWithoutFileNameAndLineNumber(Main.class, "main")
+                            .build())));
+  }
+
+  @Test
+  public void testMappingInformation() throws Exception {
+    assumeTrue("R8/CF does not desugar", parameters.isDexRuntime());
+    testForR8(parameters.getBackend())
+        .addInnerClasses(getClass())
+        .addKeepAttributeSourceFile()
+        .addKeepAttributeLineNumberTable()
+        .noTreeShaking()
+        .noMinification()
+        .setMinApi(parameters.getApiLevel())
+        .run(parameters.getRuntime(), Main.class)
+        .assertFailureWithErrorThatMatches(containsString("Hello World!"))
+        .inspectFailure(
+            inspector -> {
+              Collection<ClassReference> inputs =
+                  ImmutableList.of(classFromClass(MyRunner.class), classFromClass(Main.class));
+              for (FoundClassSubject clazz : inspector.allClasses()) {
+                if (inputs.contains(clazz.getFinalReference())) {
+                  assertThat(clazz, not(isCompilerSynthesized()));
+                } else {
+                  assertThat(clazz, isCompilerSynthesized());
+                }
+              }
+              assertEquals(inputs.size() + 1, inspector.allClasses().size());
             });
   }
 
diff --git a/src/test/java/com/android/tools/r8/shaking/AbstractSuperClassLiveMethodTest.java b/src/test/java/com/android/tools/r8/shaking/AbstractSuperClassLiveMethodTest.java
deleted file mode 100644
index 8cdd48e..0000000
--- a/src/test/java/com/android/tools/r8/shaking/AbstractSuperClassLiveMethodTest.java
+++ /dev/null
@@ -1,103 +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.shaking;
-
-import com.android.tools.r8.NeverClassInline;
-import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NoVerticalClassMerging;
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
-import com.google.common.collect.ImmutableList;
-import java.util.List;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-@RunWith(Parameterized.class)
-public class AbstractSuperClassLiveMethodTest extends TestBase {
-
-  private final TestParameters parameters;
-  private final String NEW_DESCRIPTOR = "Lfoo/A;";
-  private final String[] EXPECTED = new String[] {"A::foo", "Base::foo"};
-  private final String[] EXPECTED_DALVIK = new String[] {"A::foo", "A::foo"};
-
-  @Parameters(name = "{0}")
-  public static TestParametersCollection data() {
-    return getTestParameters().withAllRuntimesAndApiLevels().build();
-  }
-
-  public AbstractSuperClassLiveMethodTest(TestParameters parameters) {
-    this.parameters = parameters;
-  }
-
-  public List<byte[]> getProgramClassFileData() throws Exception {
-    return ImmutableList.of(
-        transformer(A.class).setClassDescriptor(NEW_DESCRIPTOR).transform(),
-        transformer(Main.class)
-            .replaceClassDescriptorInMethodInstructions(descriptor(A.class), NEW_DESCRIPTOR)
-            .transform());
-  }
-
-  @Test
-  public void testRuntime() throws Exception {
-    testForRuntime(parameters)
-        .addProgramClasses(Base.class)
-        .addProgramClassFileData(getProgramClassFileData())
-        .run(parameters.getRuntime(), Main.class)
-        .applyIf(
-            parameters.isDexRuntime() && parameters.getDexRuntimeVersion().isDalvik(),
-            r -> r.assertSuccessWithOutputLines(EXPECTED_DALVIK),
-            r -> r.assertSuccessWithOutputLines(EXPECTED));
-  }
-
-  @Test
-  public void testForR8() throws Exception {
-    testForR8(parameters.getBackend())
-        .addProgramClasses(Base.class)
-        .addProgramClassFileData(getProgramClassFileData())
-        .setMinApi(parameters.getApiLevel())
-        .addKeepMainRule(Main.class)
-        .enableInliningAnnotations()
-        .enableNoVerticalClassMergingAnnotations()
-        .enableNeverClassInliningAnnotations()
-        .addOptionsModification(options -> options.enableDevirtualization = false)
-        .run(parameters.getRuntime(), Main.class)
-        .applyIf(
-            parameters.isDexRuntime() && parameters.getDexRuntimeVersion().isDalvik(),
-            r -> r.assertSuccessWithOutputLines(EXPECTED_DALVIK),
-            // TODO(b/182444403): Should succeed with EXPECTED.
-            r -> r.assertFailureWithErrorThatThrows(AbstractMethodError.class));
-  }
-
-  @NoVerticalClassMerging
-  public abstract static class Base {
-
-    @NeverInline
-    void foo() {
-      System.out.println("Base::foo");
-    }
-  }
-
-  @NeverClassInline
-  public static class /* will be foo.A */ A extends Base {
-
-    @Override
-    @NeverInline
-    public void foo() {
-      System.out.println("A::foo");
-    }
-  }
-
-  public static class Main {
-
-    public static void main(String[] args) {
-      Base a = new A();
-      ((A) a).foo();
-      a.foo();
-    }
-  }
-}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
index be358de..1763108 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
@@ -26,7 +26,9 @@
 import com.android.tools.r8.naming.MemberNaming;
 import com.android.tools.r8.naming.MemberNaming.FieldSignature;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
+import com.android.tools.r8.naming.MemberNaming.NoSignature;
 import com.android.tools.r8.naming.MemberNaming.Signature;
+import com.android.tools.r8.naming.mappinginformation.MappingInformation;
 import com.android.tools.r8.naming.signature.GenericSignatureParser;
 import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.references.FieldReference;
@@ -44,6 +46,7 @@
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
@@ -412,6 +415,27 @@
   }
 
   @Override
+  public boolean isCompilerSynthesized() {
+    if (naming == null) {
+      return false;
+    }
+    Map<Signature, List<MappingInformation>> additionalMappings = naming.getAdditionalMappings();
+    if (additionalMappings == null) {
+      return false;
+    }
+    List<MappingInformation> infos = additionalMappings.get(NoSignature.NO_SIGNATURE);
+    if (infos == null) {
+      return false;
+    }
+    for (MappingInformation info : infos) {
+      if (info.isCompilerSynthesizedMappingInformation()) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  @Override
   public boolean isLocalClass() {
     return dexClass.isLocalClass();
   }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/HorizontallyMergedClassesInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/HorizontallyMergedClassesInspector.java
index 91fb002..e6fa548 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/HorizontallyMergedClassesInspector.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/HorizontallyMergedClassesInspector.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.utils.codeinspector;
 
-import static com.android.tools.r8.TestBase.toDexType;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -72,11 +71,20 @@
     return this;
   }
 
+  public HorizontallyMergedClassesInspector assertClassesMerged(Class<?>... classes) {
+    return assertClassesMerged(Arrays.asList(classes));
+  }
+
   public HorizontallyMergedClassesInspector assertClassesMerged(Collection<Class<?>> classes) {
     return assertTypesMerged(classes.stream().map(this::toDexType).collect(Collectors.toList()));
   }
 
   public HorizontallyMergedClassesInspector assertClassReferencesMerged(
+      ClassReference... classReferences) {
+    return assertClassReferencesMerged(Arrays.asList(classReferences));
+  }
+
+  public HorizontallyMergedClassesInspector assertClassReferencesMerged(
       Collection<ClassReference> classReferences) {
     return assertTypesMerged(
         classReferences.stream().map(this::toDexType).collect(Collectors.toList()));
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/Matchers.java b/src/test/java/com/android/tools/r8/utils/codeinspector/Matchers.java
index 28f0b9c..e7db18c 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/Matchers.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/Matchers.java
@@ -218,6 +218,28 @@
     };
   }
 
+  public static Matcher<Subject> isCompilerSynthesized() {
+    return new TypeSafeMatcher<Subject>() {
+      @Override
+      protected boolean matchesSafely(Subject subject) {
+        return subject.isPresent() && subject.isCompilerSynthesized();
+      }
+
+      @Override
+      public void describeTo(Description description) {
+        description.appendText(" compiler synthesized");
+      }
+
+      @Override
+      public void describeMismatchSafely(final Subject subject, Description description) {
+        description
+            .appendText(type(subject) + " ")
+            .appendValue(name(subject))
+            .appendText(" was not");
+      }
+    };
+  }
+
   public static Matcher<ClassSubject> hasDefaultConstructor() {
     return new TypeSafeMatcher<ClassSubject>() {
       @Override
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/Subject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/Subject.java
index 05d83b7..29bc90b 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/Subject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/Subject.java
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.utils.codeinspector;
 
+import com.android.tools.r8.errors.Unimplemented;
+
 public abstract class Subject {
 
   public abstract boolean isPresent();
@@ -11,4 +13,9 @@
   public abstract boolean isRenamed();
 
   public abstract boolean isSynthetic();
+
+  public boolean isCompilerSynthesized() {
+    throw new Unimplemented(
+        "Predicate not yet supported on Subject: " + getClass().getSimpleName());
+  }
 }
diff --git a/third_party/openjdk/desugar_jdk_libs_11.tar.gz.sha1 b/third_party/openjdk/desugar_jdk_libs_11.tar.gz.sha1
new file mode 100644
index 0000000..cb35cd0
--- /dev/null
+++ b/third_party/openjdk/desugar_jdk_libs_11.tar.gz.sha1
@@ -0,0 +1 @@
+5696c90f0675746b4e996c80de461dd2cfd80076
\ No newline at end of file
diff --git a/tools/archive.py b/tools/archive.py
index e92e87d..24e8e0a 100755
--- a/tools/archive.py
+++ b/tools/archive.py
@@ -56,51 +56,51 @@
 def GetGitHash():
   return subprocess.check_output(['git', 'rev-parse', 'HEAD']).strip()
 
-def IsMaster(version):
+def IsMain(version):
   branches = subprocess.check_output(['git', 'branch', '-r', '--contains',
                                       'HEAD'])
-  # CL runs from gerrit does not have a branch, we always treat them as master
+  # CL runs from gerrit does not have a branch, we always treat them as main
   # commits to archive these to the hash based location
   if len(branches) == 0:
     return True
-  if not version == 'master':
+  if not version == 'main':
     # Sanity check, we don't want to archive on top of release builds EVER
     # Note that even though we branch, we never push the bots to build the same
-    # commit as master on a branch since we always change the version to
-    # not be just 'master' (or we crash here :-)).
-    if 'origin/master' in branches:
-      raise Exception('We are seeing origin/master in a commit that '
-                      'don\'t have \'master\' as version')
+    # commit as main on a branch since we always change the version to
+    # not be just 'main' (or we crash here :-)).
+    if 'origin/main' in branches:
+      raise Exception('We are seeing origin/main in a commit that '
+                      'don\'t have \'main\' as version')
     return False
-  if not 'origin/master' in branches:
-      raise Exception('We are not seeing origin/master '
-                      'in a commit that have \'master\' as version')
+  if not 'origin/main' in branches:
+      raise Exception('We are not seeing origin/main '
+                      'in a commit that have \'main\' as version')
   return True
 
 def GetStorageDestination(storage_prefix,
                           version_or_path,
                           file_name,
-                          is_master):
-  # We archive master commits under raw/master instead of directly under raw
+                          is_main):
+  # We archive main commits under raw/main instead of directly under raw
   version_dir = GetVersionDestination(storage_prefix,
                                       version_or_path,
-                                      is_master)
+                                      is_main)
   return '%s/%s' % (version_dir, file_name)
 
-def GetVersionDestination(storage_prefix, version_or_path, is_master):
-  archive_dir = 'raw/master' if is_master else 'raw'
+def GetVersionDestination(storage_prefix, version_or_path, is_main):
+  archive_dir = 'raw/main' if is_main else 'raw'
   return '%s%s/%s/%s' % (storage_prefix, ARCHIVE_BUCKET,
                          archive_dir, version_or_path)
 
-def GetUploadDestination(version_or_path, file_name, is_master):
-  return GetStorageDestination('gs://', version_or_path, file_name, is_master)
+def GetUploadDestination(version_or_path, file_name, is_main):
+  return GetStorageDestination('gs://', version_or_path, file_name, is_main)
 
-def GetUrl(version_or_path, file_name, is_master):
+def GetUrl(version_or_path, file_name, is_main):
   return GetStorageDestination('https://storage.googleapis.com/',
-                               version_or_path, file_name, is_master)
+                               version_or_path, file_name, is_main)
 
-def GetMavenUrl(is_master):
-  return GetVersionDestination('https://storage.googleapis.com/', '', is_master)
+def GetMavenUrl(is_main):
+  return GetVersionDestination('https://storage.googleapis.com/', '', is_main)
 
 def SetRLimitToMax():
   (soft, hard) = resource.getrlimit(resource.RLIMIT_NOFILE)
@@ -157,13 +157,13 @@
       utils.DESUGAR_CONFIGURATION_MAVEN_ZIP)
 
   version = GetVersion()
-  is_master = IsMaster(version)
-  if is_master:
-    # On master we use the git hash to archive with
-    print('On master, using git hash for archiving')
+  is_main = IsMain(version)
+  if is_main:
+    # On main we use the git hash to archive with
+    print('On main, using git hash for archiving')
     version = GetGitHash()
 
-  destination = GetVersionDestination('gs://', version, is_master)
+  destination = GetVersionDestination('gs://', version, is_main)
   if utils.cloud_storage_exists(destination) and not options.dry_run:
     raise Exception('Target archive directory %s already exists' % destination)
   with utils.TempDir() as temp:
@@ -207,7 +207,7 @@
       if file_name.endswith('.jar') and not file_name.endswith('-src.jar'):
         with zipfile.ZipFile(tagged_jar, 'a') as zip:
           zip.write(version_file, os.path.basename(version_file))
-      destination = GetUploadDestination(version, file_name, is_master)
+      destination = GetUploadDestination(version, file_name, is_main)
       print('Uploading %s to %s' % (tagged_jar, destination))
       if options.dry_run:
         if options.dry_run_output:
@@ -219,21 +219,21 @@
           print('Dry run, not actually uploading')
       else:
         utils.upload_file_to_cloud_storage(tagged_jar, destination)
-        print('File available at: %s' % GetUrl(version, file_name, is_master))
+        print('File available at: %s' % GetUrl(version, file_name, is_main))
 
       # Upload R8 to a maven compatible location.
       if file == utils.R8_JAR:
         maven_dst = GetUploadDestination(utils.get_maven_path('r8', version),
-                                         'r8-%s.jar' % version, is_master)
+                                         'r8-%s.jar' % version, is_main)
         maven_pom_dst = GetUploadDestination(
             utils.get_maven_path('r8', version),
-            'r8-%s.pom' % version, is_master)
+            'r8-%s.pom' % version, is_main)
         if options.dry_run:
           print('Dry run, not actually creating maven repo for R8')
         else:
           utils.upload_file_to_cloud_storage(tagged_jar, maven_dst)
           utils.upload_file_to_cloud_storage(default_pom_file, maven_pom_dst)
-          print('Maven repo root available at: %s' % GetMavenUrl(is_master))
+          print('Maven repo root available at: %s' % GetMavenUrl(is_main))
 
       # Upload desugar_jdk_libs configuration to a maven compatible location.
       if file == utils.DESUGAR_CONFIGURATION:
@@ -241,7 +241,7 @@
         jar_version_name = 'desugar_jdk_libs_configuration-%s.jar' % version
         maven_dst = GetUploadDestination(
             utils.get_maven_path('desugar_jdk_libs_configuration', version),
-                                 jar_version_name, is_master)
+                                 jar_version_name, is_main)
 
         with utils.TempDir() as tmp_dir:
           desugar_jdk_libs_configuration_jar = os.path.join(tmp_dir,
@@ -262,10 +262,10 @@
           else:
             utils.upload_file_to_cloud_storage(
                 desugar_jdk_libs_configuration_jar, maven_dst)
-            print('Maven repo root available at: %s' % GetMavenUrl(is_master))
+            print('Maven repo root available at: %s' % GetMavenUrl(is_main))
             # Also archive the jar as non maven destination for Google3
             jar_destination = GetUploadDestination(
-                version, jar_basename, is_master)
+                version, jar_basename, is_main)
             utils.upload_file_to_cloud_storage(
                 desugar_jdk_libs_configuration_jar, jar_destination)
 
diff --git a/tools/archive_desugar_jdk_libs.py b/tools/archive_desugar_jdk_libs.py
index 825cb91..2bc8386 100755
--- a/tools/archive_desugar_jdk_libs.py
+++ b/tools/archive_desugar_jdk_libs.py
@@ -64,7 +64,7 @@
     return version
 
 
-def Upload(options, file_name, storage_path, destination, is_master):
+def Upload(options, file_name, storage_path, destination, is_main):
   print('Uploading %s to %s' % (file_name, destination))
   if options.dry_run:
     if options.dry_run_output:
@@ -148,14 +148,14 @@
       return
 
   # Only handling versioned desugar_jdk_libs.
-  is_master = False
+  is_main = False
 
   with utils.TempDir() as checkout_dir:
     CloneDesugaredLibrary(options.github_account, checkout_dir)
     version = GetVersion(os.path.join(checkout_dir, VERSION_FILE))
 
     destination = archive.GetVersionDestination(
-        'gs://', LIBRARY_NAME + '/' + version, is_master)
+        'gs://', LIBRARY_NAME + '/' + version, is_main)
     if utils.cloud_storage_exists(destination) and not options.dry_run:
       raise Exception(
           'Target archive directory %s already exists' % destination)
@@ -165,24 +165,24 @@
     storage_path = LIBRARY_NAME + '/' + version
     # Upload the jar file with the library.
     destination = archive.GetUploadDestination(
-        storage_path, LIBRARY_NAME + '.jar', is_master)
-    Upload(options, library_jar, storage_path, destination, is_master)
+        storage_path, LIBRARY_NAME + '.jar', is_main)
+    Upload(options, library_jar, storage_path, destination, is_main)
 
     # Upload the maven zip file with the library.
     destination = archive.GetUploadDestination(
-        storage_path, LIBRARY_NAME + '.zip', is_master)
-    Upload(options, maven_zip, storage_path, destination, is_master)
+        storage_path, LIBRARY_NAME + '.zip', is_main)
+    Upload(options, maven_zip, storage_path, destination, is_main)
 
     # Upload the jar file for accessing GCS as a maven repro.
     maven_destination = archive.GetUploadDestination(
         utils.get_maven_path('desugar_jdk_libs', version),
         'desugar_jdk_libs-%s.jar' % version,
-        is_master)
+        is_main)
     if options.dry_run:
       print('Dry run, not actually creating maven repo')
     else:
       utils.upload_file_to_cloud_storage(library_jar, maven_destination)
-      print('Maven repo root available at: %s' % archive.GetMavenUrl(is_master))
+      print('Maven repo root available at: %s' % archive.GetMavenUrl(is_main))
 
 
 if __name__ == '__main__':
diff --git a/tools/compiledump.py b/tools/compiledump.py
index 3828739..bce5d75 100755
--- a/tools/compiledump.py
+++ b/tools/compiledump.py
@@ -37,10 +37,10 @@
     '--version',
     help='Compiler version to use (default read from dump version file).'
       'Valid arguments are:'
-      '  "master" to run from your own tree,'
+      '  "main" to run from your own tree,'
       '  "source" to run from build classes directly,'
       '  "X.Y.Z" to run a specific version, or'
-      '  <hash> to run that hash from master.',
+      '  <hash> to run that hash from main.',
     default=None)
   parser.add_argument(
     '--r8-jar',
@@ -236,7 +236,7 @@
   return None
 
 def download_distribution(args, version, temp):
-  if version == 'master':
+  if version == 'main':
     return utils.R8_JAR if args.nolib else utils.R8LIB_JAR
   if version == 'source':
     return '%s:%s' % (utils.BUILD_JAVA_MAIN_DIR, utils.ALL_DEPS_JAR)
@@ -340,8 +340,8 @@
       if not args.nolib and version != 'source':
         stacktrace = os.path.join(temp, 'stacktrace')
         open(stacktrace, 'w+').write(e.output.decode('UTF-8'))
-        local_map = utils.R8LIB_MAP if version == 'master' else None
-        hash_or_version = None if version == 'master' else version
+        local_map = utils.R8LIB_MAP if version == 'main' else None
+        hash_or_version = None if version == 'main' else version
         print("=" * 80)
         print(" RETRACED OUTPUT")
         print("=" * 80)
diff --git a/tools/git_sync_cl_chain.py b/tools/git_sync_cl_chain.py
index 857aab8..ea67f63 100755
--- a/tools/git_sync_cl_chain.py
+++ b/tools/git_sync_cl_chain.py
@@ -12,8 +12,8 @@
 #   * feature_final    xxxxxxxxx [feature_prereq_c: ...] ...
 #     feature_prereq_c xxxxxxxxx [feature_prereq_b: ...] ...
 #     feature_prereq_b xxxxxxxxx [feature_prereq_a: ...] ...
-#     feature_prereq_a xxxxxxxxx [master: ...] ...
-#     master           xxxxxxxxx [origin/master] ...
+#     feature_prereq_a xxxxxxxxx [main: ...] ...
+#     main             xxxxxxxxx [origin/main] ...
 #
 # Executing `git_sync_cl_chain.py -m <message>` causes the following chain of
 # commands to be executed:
@@ -54,8 +54,8 @@
                     action='store_true')
   result.add_option('--no_upload', '--no-upload',
                     help='Disable uploading to Gerrit', action='store_true')
-  result.add_option('--skip_master', '--skip-master',
-                    help='Disable syncing for master',
+  result.add_option('--skip_main', '--skip-main',
+                    help='Disable syncing for main',
                     action='store_true')
   (options, args) = result.parse_args(argv)
   options.upload = not options.no_upload
@@ -105,7 +105,7 @@
 
       pull_for_current_branch(branch, options)
 
-      if branch.name == 'master':
+      if branch.name == 'main':
         continue
 
       if status == 'closed':
@@ -119,9 +119,9 @@
       if not options.leave_upstream:
         if not has_seen_open_branch and len(closed_branches) > 0:
           print(
-              'Setting upstream for first open branch %s to master'
+              'Setting upstream for first open branch %s to main'
                   % branch.name)
-          set_upstream_for_current_branch_to_master()
+          set_upstream_for_current_branch_to_main()
 
       has_seen_open_branch = True
       has_seen_local_branch = has_seen_local_branch or (status == 'None')
@@ -170,14 +170,14 @@
   return utils.RunCmd(['git', 'cl', 'status', '--field', 'status'], quiet=True)[0].strip()
 
 def pull_for_current_branch(branch, options):
-  if branch.name == 'master' and options.skip_master:
+  if branch.name == 'main' and options.skip_main:
     return
   rebase_args = ['--rebase'] if options.rebase else []
   utils.RunCmd(['git', 'pull'] + rebase_args, quiet=True)
 
 
-def set_upstream_for_current_branch_to_master():
-  utils.RunCmd(['git', 'cl', 'upstream', 'master'], quiet=True)
+def set_upstream_for_current_branch_to_main():
+  utils.RunCmd(['git', 'cl', 'upstream', 'main'], quiet=True)
 
 # Parses a line from the output of `git branch -vv`.
 #
@@ -187,8 +187,8 @@
 #   * feature_final    xxxxxxxxx [feature_prereq_c: ...] ...
 #     feature_prereq_c xxxxxxxxx [feature_prereq_b: ...] ...
 #     feature_prereq_b xxxxxxxxx [feature_prereq_a: ...] ...
-#     feature_prereq_a xxxxxxxxx [master: ...] ...
-#     master           xxxxxxxxx [origin/master] ...
+#     feature_prereq_a xxxxxxxxx [main: ...] ...
+#     main             xxxxxxxxx [origin/main] ...
 def parse(line):
   is_current = False
   if line.startswith('*'):
diff --git a/tools/git_utils.py b/tools/git_utils.py
index 72485e1..9d9c6bd 100644
--- a/tools/git_utils.py
+++ b/tools/git_utils.py
@@ -11,8 +11,8 @@
   utils.PrintCmd(cmd)
   return subprocess.check_call(cmd)
 
-def GetHeadRevision(checkout_dir, use_master=False):
-  revision_from = 'origin/master' if use_master else 'HEAD'
+def GetHeadRevision(checkout_dir, use_main=False):
+  revision_from = 'origin/main' if use_main else 'HEAD'
   cmd = ['git', 'rev-parse', revision_from]
   utils.PrintCmd(cmd)
   with utils.ChangedWorkingDirectory(checkout_dir):
diff --git a/tools/internal_test.py b/tools/internal_test.py
index 9309237..48409c0 100755
--- a/tools/internal_test.py
+++ b/tools/internal_test.py
@@ -180,7 +180,7 @@
 def restart_if_new_version(original_content):
   new_content = get_own_file_content()
   log('Lengths %s %s' % (len(original_content), len(new_content)))
-  log('is master %s ' % utils.is_master())
+  log('is main %s ' % utils.is_main())
   # Restart if the script got updated.
   if new_content != original_content:
     log('Restarting tools/internal_test.py, content changed')
@@ -195,7 +195,7 @@
 
 def git_pull():
   ensure_git_clean()
-  subprocess.check_call(['git', 'checkout', 'master'])
+  subprocess.check_call(['git', 'checkout', 'main'])
   subprocess.check_call(['git', 'pull'])
   return utils.get_HEAD_sha1()
 
diff --git a/tools/r8_release.py b/tools/r8_release.py
index 72a5e02..397c97d 100755
--- a/tools/r8_release.py
+++ b/tools/r8_release.py
@@ -68,13 +68,13 @@
         old_version = '%s.%s-dev' % (R8_DEV_BRANCH, patch_version)
         version = '%s.%s-dev' % (R8_DEV_BRANCH, patch_version + 1)
 
-        # Verify that the merge point from master is not empty.
+        # Verify that the merge point from main is not empty.
         merge_diff_output = subprocess.check_output([
           'git', 'diff', 'HEAD..%s' % commithash]).decode('utf-8')
         other_diff = version_change_diff(
-            merge_diff_output, old_version, "master")
+            merge_diff_output, old_version, "main")
         if not other_diff:
-          print('Merge point from master (%s)' % commithash, \
+          print('Merge point from main (%s)' % commithash, \
             'is the same as exiting release (%s).' % old_version)
           sys.exit(1)
 
@@ -83,7 +83,7 @@
             subprocess.check_call([
                 'git', 'cherry-pick', '--no-edit', pre_commit])
 
-        # Merge the desired commit from master on to the branch.
+        # Merge the desired commit from main on to the branch.
         subprocess.check_call([
           'git', 'merge', '--no-ff', '--no-edit', commithash])
 
@@ -96,7 +96,7 @@
         version_diff_output = subprocess.check_output([
           'git', 'diff', '%s..HEAD' % commithash]).decode('utf-8')
 
-        validate_version_change_diff(version_diff_output, "master", version)
+        validate_version_change_diff(version_diff_output, "main", version)
 
         # Double check that we want to push the release.
         if not args.dry_run:
@@ -488,7 +488,7 @@
       with utils.ChangedWorkingDirectory(temp):
         library_gfile = ('/bigstore/r8-releases/raw/%s/%s/%s'
               % (DESUGAR_JDK_LIBS, library_version, library_archive))
-        configuration_gfile = ('/bigstore/r8-releases/raw/master/%s/%s'
+        configuration_gfile = ('/bigstore/r8-releases/raw/main/%s/%s'
               % (configuration_version, configuration_archive))
 
         download_gfile(library_gfile, library_archive)
@@ -685,7 +685,7 @@
         subprocess.check_call(['git', 'checkout', branch_version])
 
         # Rewrite the version, commit and validate.
-        old_version = 'master'
+        old_version = 'main'
         full_version = branch_version + '.0-dev'
         version_prefix = 'LABEL = "'
         sed(version_prefix + old_version,
@@ -754,7 +754,7 @@
   result = argparse.ArgumentParser(description='Release r8')
   group = result.add_mutually_exclusive_group()
   group.add_argument('--dev-release',
-                      metavar=('<master hash>'),
+                      metavar=('<main hash>'),
                       help='The hash to use for the new dev version of R8')
   group.add_argument('--version',
                       metavar=('<version>'),
@@ -769,10 +769,10 @@
                       help='Update studio mirror of com.android.tools:desugar_jdk_libs')
   group.add_argument('--new-dev-branch',
                       nargs=2,
-                      metavar=('<version>', '<master hash>'),
+                      metavar=('<version>', '<main hash>'),
                       help='Create a new branch starting a version line (e.g. 2.0)')
   result.add_argument('--dev-pre-cherry-pick',
-                      metavar=('<master hash(s)>'),
+                      metavar=('<main hash(s)>'),
                       default=[],
                       action='append',
                       help='List of commits to cherry pick before doing full '
diff --git a/tools/run_on_app_dump.py b/tools/run_on_app_dump.py
index 1644895..779af1d 100755
--- a/tools/run_on_app_dump.py
+++ b/tools/run_on_app_dump.py
@@ -9,6 +9,7 @@
 import compiledump
 import gradle
 import hashlib
+import jdk
 import optparse
 import os
 import shutil
@@ -449,7 +450,7 @@
         f.write(line)
 
 
-def download_app(app_sha, internal, quiet=False):
+def download_sha(app_sha, internal, quiet=False):
   if internal:
     utils.DownloadFromX20(app_sha)
   else:
@@ -473,7 +474,7 @@
 
 
 def version_is_built_jar(version):
-  return version != 'master' and version != 'source'
+  return version != 'main' and version != 'source'
 
 
 def compute_size_of_dex_files_in_package(path):
@@ -502,12 +503,13 @@
 
 def get_results_for_app(app, options, temp_dir):
   app_folder = app.folder if app.folder else app.name + "_" + app.revision
+  opensource_basedir = (os.path.join('benchmarks', app.name) if options.golem
+                        else utils.OPENSOURCE_DUMPS_DIR)
   app_dir = (os.path.join(utils.INTERNAL_DUMPS_DIR, app_folder) if app.internal
-              else os.path.join(utils.OPENSOURCE_DUMPS_DIR, app_folder))
-
+              else os.path.join(opensource_basedir, app_folder))
   if not os.path.exists(app_dir) and not options.golem:
     # Download the app from google storage.
-    download_app(app_dir + ".tar.gz.sha1", app.internal)
+    download_sha(app_dir + ".tar.gz.sha1", app.internal)
 
   # Ensure that the dumps are in place
   assert os.path.isfile(dump_for_app(app_dir, app)), "Could not find dump " \
@@ -929,7 +931,7 @@
                     help='The shrinkers to use (by default, all are run)',
                     action='append')
   result.add_option('--version',
-                    default='master',
+                    default='main',
                     help='The version of R8 to use (e.g., 1.4.51)')
   (options, args) = result.parse_args(argv)
 
@@ -996,6 +998,10 @@
   print('')
   print('createOpenSourceAppBenchmarks() {')
   print_indented('final cpus = ["Lenovo M90"];', 2)
+  # Avoid calculating this for every app
+  jdk_gz = jdk.GetJdkHome() + '.tar.gz'
+  download_sha(jdk_gz + '.sha1', False, quiet=True)
+  jdk_sha256 = get_sha256(jdk_gz)
   for app in options.apps:
     if app.folder and not app.internal:
       indentation = 2;
@@ -1014,24 +1020,31 @@
       print_indented('options.fromRevision = 9700;', indentation);
       print_indented('options.mainFile = "tools/run_on_app_dump.py "', indentation)
       print_indented('"--golem --shrinker r8 --app %s";' % app.name, indentation + 4)
+
       app_gz = os.path.join(utils.OPENSOURCE_DUMPS_DIR, app.folder + '.tar.gz')
-      app_sha = app_gz + '.sha1'
-      # Golem uses a sha256 of the file in the cache, and you need to specify that.
-      download_app(app_sha, app.internal, quiet=True)
-      sha256 = get_sha256(app_gz)
-      sha = get_sha_from_file(app_sha)
-      print_indented('final resource = BenchmarkResource("",', indentation)
-      print_indented('type: BenchmarkResourceType.Storage,', indentation + 4)
-      print_indented('uri: "gs://r8-deps/%s",' % sha, indentation + 4)
-      print_indented('hash:', indentation + 4)
-      print_indented('"%s",' % sha256, indentation + 8)
-      print_indented('extract: "gz");', indentation + 4);
-      print_indented('options.resources.add(resource);', indentation)
+      add_golem_resource(indentation, app_gz, 'app_resource')
+      add_golem_resource(indentation, jdk_gz, 'openjdk', sha256=jdk_sha256)
+
       print_indented('dumpsSuite.addBenchmark(name);', indentation)
       indentation = 2
       print_indented('}', indentation)
   print('}')
 
+def add_golem_resource(indentation, gz, name, sha256=None):
+  sha = gz + '.sha1'
+  if not sha256:
+    # Golem uses a sha256 of the file in the cache, and you need to specify that.
+    download_sha(sha, False, quiet=True)
+    sha256 = get_sha256(gz)
+  sha = get_sha_from_file(sha)
+  print_indented('final %s = BenchmarkResource("",' % name, indentation)
+  print_indented('type: BenchmarkResourceType.Storage,', indentation + 4)
+  print_indented('uri: "gs://r8-deps/%s",' % sha, indentation + 4)
+  print_indented('hash:', indentation + 4)
+  print_indented('"%s",' % sha256, indentation + 8)
+  print_indented('extract: "gz");', indentation + 4);
+  print_indented('options.resources.add(%s);' % name, indentation)
+
 def main(argv):
   (options, args) = parse_options(argv)
 
@@ -1070,7 +1083,7 @@
         as_utils.MoveFile(
           os.path.join(temp_dir, target), os.path.join(temp_dir, 'r8lib.jar'),
           quiet=options.quiet)
-    elif options.version == 'master':
+    elif options.version == 'main':
       if not (options.no_build or options.golem):
         gradle.RunGradle(['r8', '-Pno_internal'])
         build_r8lib = False
diff --git a/tools/test.py b/tools/test.py
index f7b204f..ea6a880 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -162,7 +162,8 @@
       help='Enable Java debug agent and suspend compilation (default disabled)',
       default=False,
       action='store_true')
-  result.add_option('--desugared-library-configuration', '--desugared_library-configuration',
+  result.add_option('--desugared-library-configuration',
+      '--desugared_library-configuration',
       help='Use alternative desugared library configuration.')
   result.add_option('--desugared-library', '--desugared_library',
       help='Build and use desugared library from GitHub.')
diff --git a/tools/trigger.py b/tools/trigger.py
index 482608a..984cc08 100755
--- a/tools/trigger.py
+++ b/tools/trigger.py
@@ -42,7 +42,7 @@
 def get_builders():
 
   is_release = False
-  master_builders = []
+  main_builders = []
   release_builders = []
   with open(LUCI_SCHEDULE, 'r') as fp:
     lines = fp.readlines()
@@ -57,13 +57,13 @@
           release_builders.append(builder)
         else:
           assert 'release' not in builder
-          master_builders.append(builder)
-  assert DESUGAR_BOT in master_builders
+          main_builders.append(builder)
+  assert DESUGAR_BOT in main_builders
   print 'Desugar builder:\n  ' + DESUGAR_BOT
-  master_builders.remove(DESUGAR_BOT)
-  print 'Master builders:\n  ' + '\n  '.join(master_builders)
+  main_builders.remove(DESUGAR_BOT)
+  print 'Main builders:\n  ' + '\n  '.join(main_builders)
   print 'Release builders:\n  ' + '\n  '.join(release_builders)
-  return (master_builders, release_builders)
+  return (main_builders, release_builders)
 
 def sanity_check_url(url):
   a = urllib.urlopen(url)
@@ -97,15 +97,15 @@
     return 1
 
   commit = None if (options.cl or options.desugar)  else args[0]
-  (master_builders, release_builders) = get_builders()
-  builders = release_builders if options.release else master_builders
+  (main_builders, release_builders) = get_builders()
+  builders = release_builders if options.release else main_builders
   if options.builder:
     builder = options.builder
-    assert builder in master_builders or builder in release_builders
+    assert builder in main_builders or builder in release_builders
     builders = [options.builder]
   if options.desugar:
     builders = [DESUGAR_BOT]
-    commit = git_utils.GetHeadRevision(utils.REPO_ROOT, use_master=True)
+    commit = git_utils.GetHeadRevision(utils.REPO_ROOT, use_main=True)
   if options.cl:
     trigger_cl(builders, options.cl)
   else:
diff --git a/tools/utils.py b/tools/utils.py
index da4a0e4..5c1b32b 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -263,10 +263,10 @@
       sha1.update(chunk)
   return sha1.hexdigest()
 
-def is_master():
+def is_main():
   remotes = subprocess.check_output(['git', 'branch', '-r', '--contains',
                                      'HEAD'])
-  return 'origin/master' in remotes
+  return 'origin/main' in remotes
 
 def get_HEAD_sha1():
   return get_HEAD_sha1_for_checkout(REPO_ROOT)