L8 Cf to Cf

- Made L8 working Cf to Cf followed
  by a R8/D8 compilation to compile desugared library.
- Added a cache in the test for desugared library
  since tests were taking many minutes with new design.
- Change 2 test classes to generate desugared
  library with and without shrinking based on
  program compilation generated keep rules.
- Fix other tests to make them work with new L8.

Change-Id: Id2d23e852f3fc85b0a8a68edbc2cc012b9f25e97
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index 1088e60..23e4e09 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -153,7 +153,7 @@
       final CfgPrinter printer = options.printCfg ? new CfgPrinter() : null;
 
       IRConverter converter = new IRConverter(appInfo, options, timing, printer);
-      app = converter.convertToDex(app, executor);
+      app = converter.convert(app, executor);
 
       if (options.printCfg) {
         if (options.printCfgFile == null || options.printCfgFile.isEmpty()) {
@@ -225,7 +225,7 @@
     final CfgPrinter printer = options.printCfg ? new CfgPrinter() : null;
 
     IRConverter converter = new IRConverter(appInfo, options, timing, printer);
-    application = converter.convertToDex(application, executor);
+    application = converter.convert(application, executor);
 
     if (options.printCfg) {
       if (options.printCfgFile == null || options.printCfgFile.isEmpty()) {
diff --git a/src/main/java/com/android/tools/r8/L8.java b/src/main/java/com/android/tools/r8/L8.java
index 4bf785c..2ea9573 100644
--- a/src/main/java/com/android/tools/r8/L8.java
+++ b/src/main/java/com/android/tools/r8/L8.java
@@ -6,20 +6,19 @@
 import static com.android.tools.r8.utils.ExceptionUtils.unwrapExecutionException;
 
 import com.android.tools.r8.dex.ApplicationReader;
-import com.android.tools.r8.dex.ApplicationWriter;
 import com.android.tools.r8.dex.Marker.Tool;
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.ir.conversion.IRConverter;
+import com.android.tools.r8.jar.CfApplicationWriter;
 import com.android.tools.r8.naming.PrefixRewritingNamingLens;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.ExceptionUtils;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.ThreadUtils;
 import com.android.tools.r8.utils.Timing;
-import com.google.common.collect.ImmutableList;
 import java.io.IOException;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
@@ -60,24 +59,24 @@
 
       AppView<?> appView = AppView.createForL8(appInfo, options);
       IRConverter converter = new IRConverter(appView, timing);
-      app = converter.convertToDex(app, executor);
+
+      app = converter.convert(app, executor);
       assert appView.appInfo() == appInfo;
 
       // Close any internal archive providers now the application is fully processed.
       inputApp.closeInternalArchiveProviders();
 
-      new ApplicationWriter(
+      new CfApplicationWriter(
               app,
-              null,
+              appView,
               options,
-              ImmutableList.of(options.getMarker(Tool.L8)),
-              null,
+              options.getMarker(Tool.L8),
               null,
               GraphLense.getIdentityLense(),
               PrefixRewritingNamingLens.createPrefixRewritingNamingLens(
                   options, converter.getAdditionalRewritePrefix()),
               null)
-          .write(executor);
+          .write(options.getClassFileConsumer(), executor);
       options.printWarnings();
     } catch (ExecutionException e) {
       throw unwrapExecutionException(e);
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index 3b23ef5..944c2bd 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -72,8 +72,8 @@
       } else if (!getSpecialLibraryConfiguration().equals("default")) {
         reporter.error("L8 currently requires the special library configuration to be \"default\"");
       }
-      if (getProgramConsumer() instanceof ClassFileConsumer) {
-        reporter.error("L8 does not support compiling to Java class files");
+      if (getProgramConsumer() instanceof DexIndexedConsumer) {
+        reporter.error("L8 does not support compiling to dex");
       }
       if (getProgramConsumer() instanceof DexFilePerClassFileConsumer) {
         reporter.error("L8 does not support compiling to dex per class");
diff --git a/src/main/java/com/android/tools/r8/graph/CfCode.java b/src/main/java/com/android/tools/r8/graph/CfCode.java
index 5912651..4b3ace9 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -40,6 +40,7 @@
 public class CfCode extends Code implements CfOrJarCode {
 
   public static class LocalVariableInfo {
+
     private final int index;
     private final DebugLocalInfo local;
     private final CfLabel start;
@@ -207,8 +208,7 @@
     for (CfInstruction instruction : instructions) {
       if (instruction instanceof CfFrame
           && (classFileVersion <= 49
-              || (classFileVersion == 50
-                  && !options.getProguardConfiguration().getKeepAttributes().stackMapTable))) {
+              || (classFileVersion == 50 && !options.shouldKeepStackMapTable()))) {
         continue;
       }
       instruction.write(visitor, namingLens);
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 90c15c6..fc5874f 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -78,6 +78,7 @@
 import org.objectweb.asm.Opcodes;
 
 public class DexEncodedMethod extends KeyedDexItem<DexMethod> implements ResolutionResult {
+
   public static final String CONFIGURATION_DEBUGGING_PREFIX = "Shaking error: Missing method in ";
 
   /**
@@ -679,6 +680,18 @@
     }
   }
 
+  public static void setDebugInfoWithFakeThisParameter(Code code, int arity, AppView<?> appView) {
+    if (code.isDexCode()) {
+      DexCode dexCode = code.asDexCode();
+      dexCode.setDebugInfo(dexCode.debugInfoWithFakeThisParameter(appView.dexItemFactory()));
+      assert (dexCode.getDebugInfo() == null)
+          || (arity == dexCode.getDebugInfo().parameters.length);
+    } else {
+      // TODO(b/134732760): Patch Cf debug info.
+      assert appView.options().coreLibraryCompilation;
+    }
+  }
+
   private DexEncodedMethod toMethodThatLogsErrorDexCode(DexItemFactory itemFactory) {
     checkIfObsolete();
     Signature signature = MethodSignature.fromDexMethod(method);
@@ -1066,6 +1079,7 @@
   }
 
   public static class ClassInlinerEligibility {
+
     public final boolean returnsReceiver;
 
     public ClassInlinerEligibility(boolean returnsReceiver) {
@@ -1074,12 +1088,14 @@
   }
 
   public static class TrivialInitializer {
+
     private TrivialInitializer() {
     }
 
     // Defines instance trivial initialized, see details in comments
     // to CodeRewriter::computeInstanceInitializerInfo(...)
     public static final class TrivialInstanceInitializer extends TrivialInitializer {
+
       public static final TrivialInstanceInitializer INSTANCE =
           new TrivialInstanceInitializer();
     }
@@ -1087,6 +1103,7 @@
     // Defines class trivial initialized, see details in comments
     // to CodeRewriter::computeClassInitializerInfo(...)
     public static final class TrivialClassInitializer extends TrivialInitializer {
+
       public final DexField field;
 
       public TrivialClassInitializer(DexField field) {
@@ -1096,6 +1113,7 @@
   }
 
   public static class DefaultMethodOptimizationInfoImpl implements MethodOptimizationInfo {
+
     public static final MethodOptimizationInfo DEFAULT_INSTANCE =
         new DefaultMethodOptimizationInfoImpl();
 
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 484a529..87c976d 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -132,6 +132,10 @@
   private final GeneratedMessageLiteShrinker generatedMessageLiteShrinker;
   private final LibraryMethodOverrideAnalysis libraryMethodOverrideAnalysis;
   private final StringConcatRewriter stringConcatRewriter;
+  private final StringOptimizer stringOptimizer;
+  private final StringBuilderOptimizer stringBuilderOptimizer;
+  private final IdempotentFunctionCallCanonicalizer idempotentFunctionCallCanonicalizer;
+  private final List<DexString> neverMergePrefixes;
   private final LambdaRewriter lambdaRewriter;
   private final D8NestBasedAccessDesugaring d8NestBasedAccessDesugaring;
   private final InterfaceMethodRewriter interfaceMethodRewriter;
@@ -151,13 +155,9 @@
   private final IdentifierNameStringMarker identifierNameStringMarker;
   private final Devirtualizer devirtualizer;
   private final CovariantReturnTypeAnnotationTransformer covariantReturnTypeAnnotationTransformer;
-  private final StringOptimizer stringOptimizer;
-  private final StringBuilderOptimizer stringBuilderOptimizer;
   private final StringSwitchRemover stringSwitchRemover;
   private final UninstantiatedTypeOptimization uninstantiatedTypeOptimization;
   private final TypeChecker typeChecker;
-  private final IdempotentFunctionCallCanonicalizer idempotentFunctionCallCanonicalizer;
-  private final List<DexString> neverMergePrefixes;
 
   final DeadCodeRemover deadCodeRemover;
 
@@ -187,6 +187,46 @@
     this.classInitializerDefaultsOptimization =
         options.debug ? null : new ClassInitializerDefaultsOptimization(appView, this);
     this.stringConcatRewriter = new StringConcatRewriter(appView);
+    this.stringOptimizer = new StringOptimizer(appView);
+    this.stringBuilderOptimizer = new StringBuilderOptimizer(appView);
+    this.deadCodeRemover = new DeadCodeRemover(appView, codeRewriter);
+    this.idempotentFunctionCallCanonicalizer = new IdempotentFunctionCallCanonicalizer(appView);
+    this.neverMergePrefixes =
+        options.neverMergePrefixes.stream()
+            .map(prefix -> "L" + DescriptorUtils.getPackageBinaryNameFromJavaType(prefix))
+            .map(options.itemFactory::createString)
+            .collect(Collectors.toList());
+    if (options.coreLibraryCompilation) {
+      // Specific L8 Settings.
+      // BackportedMethodRewriter is needed for retarget core library members and backports.
+      // InterfaceMethodRewriter is needed for emulated interfaces.
+      // LambdaRewriter is needed because if it is missing there are invoke custom on
+      // default/static interface methods, and this is not supported by the compiler.
+      // The rest is nulled out.
+      this.backportedMethodRewriter = new BackportedMethodRewriter(appView, this);
+      this.interfaceMethodRewriter = new InterfaceMethodRewriter(appView, this);
+      this.lambdaRewriter = new LambdaRewriter(appView, this);
+      this.twrCloseResourceRewriter = null;
+      this.lambdaMerger = null;
+      this.covariantReturnTypeAnnotationTransformer = null;
+      this.nonNullTracker = null;
+      this.classInliner = null;
+      this.classStaticizer = null;
+      this.dynamicTypeOptimization = null;
+      this.generatedMessageLiteShrinker = null;
+      this.libraryMethodOverrideAnalysis = null;
+      this.inliner = null;
+      this.outliner = null;
+      this.memberValuePropagation = null;
+      this.lensCodeRewriter = null;
+      this.identifierNameStringMarker = null;
+      this.devirtualizer = null;
+      this.uninstantiatedTypeOptimization = null;
+      this.typeChecker = null;
+      this.d8NestBasedAccessDesugaring = null;
+      this.stringSwitchRemover = null;
+      return;
+    }
     this.lambdaRewriter = options.enableDesugaring ? new LambdaRewriter(appView, this) : null;
     this.interfaceMethodRewriter =
         options.isInterfaceMethodDesugaringEnabled()
@@ -205,8 +245,6 @@
         options.processCovariantReturnTypeAnnotations
             ? new CovariantReturnTypeAnnotationTransformer(this, appView.dexItemFactory())
             : null;
-    this.stringOptimizer = new StringOptimizer(appView);
-    this.stringBuilderOptimizer = new StringBuilderOptimizer(appView);
     this.nonNullTracker = options.enableNonNullTracking ? new NonNullTracker(appView) : null;
     if (appView.enableWholeProgramOptimizations()) {
       assert appView.appInfo().hasLiveness();
@@ -265,17 +303,10 @@
       this.d8NestBasedAccessDesugaring =
           options.shouldDesugarNests() ? new D8NestBasedAccessDesugaring(appView) : null;
     }
-    this.deadCodeRemover = new DeadCodeRemover(appView, codeRewriter);
-    this.idempotentFunctionCallCanonicalizer = new IdempotentFunctionCallCanonicalizer(appView);
     this.stringSwitchRemover =
         options.isStringSwitchConversionEnabled()
             ? new StringSwitchRemover(appView, identifierNameStringMarker)
             : null;
-    this.neverMergePrefixes =
-        options.neverMergePrefixes.stream()
-            .map(prefix -> "L" + DescriptorUtils.getPackageBinaryNameFromJavaType(prefix))
-            .map(options.itemFactory::createString)
-            .collect(Collectors.toList());
   }
 
   public Set<DexCallSite> getDesugaredCallSites() {
@@ -390,12 +421,12 @@
     }
   }
 
-  public DexApplication convertToDex(DexApplication application, ExecutorService executor)
+  public DexApplication convert(DexApplication application, ExecutorService executor)
       throws ExecutionException {
     removeLambdaDeserializationMethods();
 
     timing.begin("IR conversion");
-    convertClassesToDex(application.classes(), executor);
+    convertClasses(application.classes(), executor);
 
     // Build a new application with jumbo string info,
     Builder<?> builder = application.builder();
@@ -482,22 +513,22 @@
     }
   }
 
-  private void convertClassesToDex(Iterable<DexProgramClass> classes,
-      ExecutorService executor) throws ExecutionException {
+  private void convertClasses(Iterable<DexProgramClass> classes, ExecutorService executor)
+      throws ExecutionException {
     List<Future<?>> futures = new ArrayList<>();
     for (DexProgramClass clazz : classes) {
-      futures.add(executor.submit(() -> convertMethodsToDex(clazz)));
+      futures.add(executor.submit(() -> convertMethods(clazz)));
     }
     ThreadUtils.awaitFutures(futures);
   }
 
-  private void convertMethodsToDex(DexProgramClass clazz) {
+  private void convertMethods(DexProgramClass clazz) {
     boolean isReachabilitySensitive = clazz.hasReachabilitySensitiveAnnotation(options.itemFactory);
     // When converting all methods on a class always convert <clinit> first.
     for (DexEncodedMethod method : clazz.directMethods()) {
       if (method.isClassInitializer()) {
         method.getMutableOptimizationInfo().setReachabilitySensitive(isReachabilitySensitive);
-        convertMethodToDex(method);
+        convertMethod(method);
         break;
       }
     }
@@ -505,17 +536,17 @@
         method -> {
           if (!method.isClassInitializer()) {
             method.getMutableOptimizationInfo().setReachabilitySensitive(isReachabilitySensitive);
-            convertMethodToDex(method);
+            convertMethod(method);
           }
         });
   }
 
-  private void convertMethodToDex(DexEncodedMethod method) {
-    assert options.isGeneratingDex();
+  private void convertMethod(DexEncodedMethod method) {
     if (method.getCode() != null) {
       boolean matchesMethodFilter = options.methodMatchesFilter(method);
       if (matchesMethodFilter) {
-        if (!(options.passthroughDexCode && method.getCode().isDexCode())) {
+        if (options.isGeneratingClassFiles()
+            || !(options.passthroughDexCode && method.getCode().isDexCode())) {
           // We do not process in call graph order, so anything could be a leaf.
           rewriteCode(method, simpleOptimizationFeedback, x -> true, CallSiteInformation.empty(),
               Outliner::noProcessing);
@@ -530,7 +561,9 @@
             }
           }
         }
-        updateHighestSortingStrings(method);
+        if (!options.isGeneratingClassFiles()) {
+          updateHighestSortingStrings(method);
+        }
       }
     }
   }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
index d534cf6..ff771b7 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
@@ -239,8 +239,7 @@
       initializeJava9MethodProviders(factory);
       initializeJava11MethodProviders(factory);
 
-      // interface method desugaring also toggles library emulation.
-      if (options.isInterfaceMethodDesugaringEnabled()) {
+      if (!options.retargetCoreLibMember.isEmpty()) {
         initializeRetargetCoreLibraryMembers(appView);
       }
     }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
index 752db0e..044b50b 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
@@ -126,7 +126,7 @@
         .setReceiver(clazz.type)
         .setTarget(rewriter.defaultAsMethodOfCompanionClass(method))
         .setInvokeType(Invoke.Type.STATIC)
-        .setIsInterface(target.isInterface());
+        .setIsInterface(false); // Holder is companion class, not an interface.
     return new DexEncodedMethod(
         newMethod,
         newFlags,
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
index e044477..c5f5e24 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
@@ -16,7 +16,6 @@
 import com.android.tools.r8.graph.Code;
 import com.android.tools.r8.graph.DexAnnotationSet;
 import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexLibraryClass;
@@ -87,11 +86,7 @@
         MethodAccessFlags newFlags = virtual.accessFlags.copy();
         newFlags.unsetBridge();
         newFlags.promoteToStatic();
-        DexCode dexCode = code.asDexCode();
-        dexCode.setDebugInfo(dexCode.debugInfoWithFakeThisParameter(rewriter.factory));
-        assert (dexCode.getDebugInfo() == null)
-            || (companionMethod.getArity() == dexCode.getDebugInfo().parameters.length);
-
+        DexEncodedMethod.setDebugInfoWithFakeThisParameter(code, companionMethod.getArity(), appView);
         DexEncodedMethod implMethod = new DexEncodedMethod(
             companionMethod, newFlags, virtual.annotations, virtual.parameterAnnotationsList, code);
         virtual.setDefaultInterfaceMethodImplementation(implMethod);
@@ -143,11 +138,7 @@
             throw new CompilationError("Code is missing for private instance "
                 + "interface method: " + oldMethod.toSourceString(), iface.origin);
           }
-          DexCode dexCode = code.asDexCode();
-          dexCode.setDebugInfo(dexCode.debugInfoWithFakeThisParameter(rewriter.factory));
-          assert (dexCode.getDebugInfo() == null)
-              || (companionMethod.getArity() == dexCode.getDebugInfo().parameters.length);
-
+          DexEncodedMethod.setDebugInfoWithFakeThisParameter(code, companionMethod.getArity(), appView);
           companionMethods.add(new DexEncodedMethod(companionMethod,
               newFlags, direct.annotations, direct.parameterAnnotationsList, code));
           graphLensBuilder.move(oldMethod, companionMethod);
@@ -232,7 +223,7 @@
       forwardSourceCodeBuilder
           .setTarget(origMethod)
           .setInvokeType(Type.STATIC)
-          .setIsInterface(true);
+          .setIsInterface(false); // We forward to the Companion class, not an interface.
       DexEncodedMethod newEncodedMethod =
           new DexEncodedMethod(
               newMethod,
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 5be5a81..1c7132a 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
@@ -10,7 +10,6 @@
 import com.android.tools.r8.graph.ClassAccessFlags;
 import com.android.tools.r8.graph.DexAnnotationSet;
 import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexField;
@@ -39,22 +38,19 @@
 import java.util.function.Supplier;
 
 /**
- * Represents lambda class generated for a lambda descriptor in context
- * of lambda instantiation point.
+ * Represents lambda class generated for a lambda descriptor in context of lambda instantiation
+ * point.
  *
- * Even though call sites, and thus lambda descriptors, are canonicalized
- * across the application, the context may require several lambda classes
- * to be generated for the same lambda descriptor.
+ * <p>Even though call sites, and thus lambda descriptors, are canonicalized across the application,
+ * the context may require several lambda classes to be generated for the same lambda descriptor.
  *
- * One reason is that we always generate a lambda class in the same package
- * lambda instantiation point is located in, so if same call site is used in
- * two classes from different packages (which can happen if same public method
- * is being references via method reference expression) we generate separate
- * lambda classes in those packages.
+ * <p>One reason is that we always generate a lambda class in the same package lambda instantiation
+ * point is located in, so if same call site is used in two classes from different packages (which
+ * can happen if same public method is being references via method reference expression) we generate
+ * separate lambda classes in those packages.
  *
- * Another reason is that if we generate an accessor, we generate it in the
- * class referencing the call site, and thus two such classes will require two
- * separate lambda classes.
+ * <p>Another reason is that if we generate an accessor, we generate it in the class referencing the
+ * call site, and thus two such classes will require two separate lambda classes.
  */
 final class LambdaClass {
 
@@ -397,9 +393,11 @@
       // To avoid potential conflicts on the name of the lambda method once dispatch becomes virtual
       // we add the method-holder name as suffix to the lambda-method name.
       return new InstanceLambdaImplTarget(
-            rewriter.factory.createMethod(implMethod.holder, implMethod.proto,
-                rewriter.factory.createString(
-                    implMethod.name.toString() + "$" + implMethod.holder.getName())));
+          rewriter.factory.createMethod(
+              implMethod.holder,
+              implMethod.proto,
+              rewriter.factory.createString(
+                  implMethod.name.toString() + "$" + implMethod.holder.getName())));
     }
   }
 
@@ -510,6 +508,13 @@
     DexProgramClass programDefinitionFor(DexType type) {
       return rewriter.converter.appView.appInfo().app().programDefinitionFor(type);
     }
+
+    boolean holderIsInterface() {
+      DexMethod implMethod = descriptor.implHandle.asMethod();
+      DexClass implMethodHolder = definitionFor(implMethod.holder);
+      assert implMethodHolder != null;
+      return implMethodHolder.isInterface();
+    }
   }
 
   // Used for targeting methods referenced directly without creating accessors.
@@ -581,10 +586,9 @@
                   encodedMethod.getCode());
           newMethod.copyMetadata(encodedMethod);
           rewriter.methodMapping.put(encodedMethod.method, callTarget);
-          DexCode dexCode = newMethod.getCode().asDexCode();
-          dexCode.setDebugInfo(dexCode.debugInfoWithFakeThisParameter(rewriter.factory));
-          assert (dexCode.getDebugInfo() == null)
-              || (callTarget.getArity() == dexCode.getDebugInfo().parameters.length);
+
+          DexEncodedMethod.setDebugInfoWithFakeThisParameter(
+              newMethod.getCode(), callTarget.getArity(), rewriter.converter.appView);
           implMethodHolder.setDirectMethod(i, newMethod);
           return true;
         }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java
index 99112d7..a5cf917 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java
@@ -232,7 +232,7 @@
                 methodToCall.proto,
                 argValueTypes,
                 argRegisters,
-                false /* isInterface */));
+                target.holderIsInterface()));
 
     // Does the method have return value?
     if (enforcedReturnType.isVoidType()) {
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 5699977..ed86c65 100644
--- a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
@@ -117,7 +117,7 @@
     }
     String markerString = marker.toString();
     for (DexProgramClass clazz : application.classes()) {
-      if (clazz.getSynthesizedFrom().isEmpty()) {
+      if (clazz.getSynthesizedFrom().isEmpty() || options.coreLibraryCompilation) {
         writeClass(clazz, consumer, markerString);
       } else {
         throw new Unimplemented("No support for synthetics in the Java bytecode backend.");
@@ -205,7 +205,8 @@
     if (!method.hasClassFileVersion()) {
       // In this case bridges have been introduced for the Cf back-end,
       // which do not have class file version.
-      assert options.testing.enableForceNestBasedAccessDesugaringForTest;
+      assert options.testing.enableForceNestBasedAccessDesugaringForTest
+          || options.coreLibraryCompilation;
       return 0;
     }
     return method.getClassFileVersion();
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 b914026..7e788e1 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -286,6 +286,10 @@
     throw new UnsupportedOperationException("Cannot find internal output mode.");
   }
 
+  public boolean shouldKeepStackMapTable() {
+    return coreLibraryCompilation || getProguardConfiguration().getKeepAttributes().stackMapTable;
+  }
+
   public boolean isGeneratingDex() {
     return isGeneratingDexIndexed() || isGeneratingDexFilePerClassFile();
   }
diff --git a/src/test/examplesJava9/stream/TestClass.java b/src/test/examplesJava9/stream/ProgramRewritingTestClass.java
similarity index 98%
rename from src/test/examplesJava9/stream/TestClass.java
rename to src/test/examplesJava9/stream/ProgramRewritingTestClass.java
index f29a4c8..7eedeb9 100644
--- a/src/test/examplesJava9/stream/TestClass.java
+++ b/src/test/examplesJava9/stream/ProgramRewritingTestClass.java
@@ -17,7 +17,7 @@
 import java.util.Set;
 import java.util.stream.IntStream;
 
-public class TestClass {
+public class ProgramRewritingTestClass {
 
   // Each print to the console is immediately followed by the expected result so the tests
   // can assert the results by checking the lines 2 by 2.
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/CoreLibDesugarTestBase.java b/src/test/java/com/android/tools/r8/desugar/corelib/CoreLibDesugarTestBase.java
index fc2e5df..ab28e74 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/CoreLibDesugarTestBase.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/CoreLibDesugarTestBase.java
@@ -10,15 +10,22 @@
 import com.android.tools.r8.L8Command;
 import com.android.tools.r8.OutputMode;
 import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestCompileResult;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.google.common.collect.ImmutableList;
 import java.nio.file.Path;
 import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
 
 public class CoreLibDesugarTestBase extends TestBase {
 
+  private static Map<CacheEntry, TestCompileResult> computedLibraryCache =
+      new ConcurrentHashMap<>();
+
   protected boolean requiresCoreLibDesugaring(TestParameters parameters) {
     // TODO(b/134732760): Use the two other APIS instead.
     return requiresEmulatedInterfaceCoreLibDesugaring(parameters)
@@ -33,10 +40,45 @@
     return parameters.getApiLevel().getLevel() < AndroidApiLevel.P.getLevel();
   }
 
+  protected Path buildDesugaredLibrary(AndroidApiLevel apiLevel) throws RuntimeException {
+    return buildDesugaredLibrary(apiLevel, "", false);
+  }
+
+  protected Path buildDesugaredLibrary(AndroidApiLevel apiLevel, String keepRules)
+      throws RuntimeException {
+    return buildDesugaredLibrary(apiLevel, keepRules, true);
+  }
+
+  protected Path buildDesugaredLibrary(AndroidApiLevel apiLevel, String keepRules, boolean shrink)
+      throws RuntimeException {
+    return buildDesugaredLibrary(apiLevel, keepRules, shrink, ImmutableList.of());
+  }
+
   protected Path buildDesugaredLibrary(
-      AndroidApiLevel apiLevel, List<Path> additionalProgramFiles) {
+      AndroidApiLevel apiLevel, String keepRules, boolean shrink, List<Path> additionalProgramFiles)
+      throws RuntimeException {
+    // We wrap exceptions in a RuntimeException to call this from a lambda.
     try {
-      Path output = temp.newFolder().toPath().resolve("desugar_jdk_libs.zip");
+      Path output = temp.newFolder().toPath().resolve("desugar_jdk_libs_dex.zip");
+      CacheEntry cacheEntry = new CacheEntry(apiLevel, keepRules, shrink, additionalProgramFiles);
+      TestCompileResult testCompileResult =
+          computedLibraryCache.computeIfAbsent(
+              cacheEntry,
+              key -> compileDesugaredLibrary(apiLevel, keepRules, shrink, additionalProgramFiles));
+      testCompileResult.writeToZip(output);
+      return output;
+    } catch (Exception e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  private TestCompileResult compileDesugaredLibrary(
+      AndroidApiLevel apiLevel, String keepRules, boolean shrink, List<Path> additionalProgramFiles)
+      throws RuntimeException {
+    // We wrap exceptions in a RuntimeException to call this from a lambda.
+    try {
+      // TODO(b/138922694): Known performance issue here.
+      Path cfDesugaredLib = temp.newFolder().toPath().resolve("desugar_jdk_libs_cf.zip");
       L8.run(
           L8Command.builder()
               .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
@@ -44,16 +86,64 @@
               .addProgramFiles(additionalProgramFiles)
               .addSpecialLibraryConfiguration("default")
               .setMinApiLevel(apiLevel.getLevel())
-              .setOutput(output, OutputMode.DexIndexed)
+              .setOutput(cfDesugaredLib, OutputMode.ClassFile)
               .build());
-      return output;
+      if (shrink) {
+        return testForR8(Backend.DEX)
+            .addProgramFiles(cfDesugaredLib)
+            .noMinification()
+            .addKeepRules(keepRules)
+            // We still need P+ library files to resolve classes.
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+            .setMinApi(apiLevel)
+            .compile();
+      }
+      return testForD8()
+          .addProgramFiles(cfDesugaredLib)
+          .setMinApi(apiLevel)
+          // We still need P+ library files to resolve classes.
+          .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+          .compile();
     } catch (Exception e) {
       throw new RuntimeException(e);
     }
   }
 
-  protected Path buildDesugaredLibrary(AndroidApiLevel apiLevel) {
-    return buildDesugaredLibrary(apiLevel, ImmutableList.of());
+  private static class CacheEntry {
+
+    private int apiLevel;
+    private String keepRules;
+    private boolean shrink;
+    private List<Path> additionalProgramFiles;
+
+    private CacheEntry(
+        AndroidApiLevel apiLevel,
+        String keepRules,
+        boolean shrink,
+        List<Path> additionalProgramFiles) {
+      this.apiLevel = apiLevel.getLevel();
+      this.keepRules = keepRules;
+      this.shrink = shrink;
+      this.additionalProgramFiles = additionalProgramFiles;
+    }
+
+    @Override
+    public int hashCode() {
+      // In practice there are only 2 sets of additionalProgramFiles with different sizes.
+      return Objects.hash(apiLevel, keepRules, shrink, additionalProgramFiles.size());
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      if (!(o instanceof CacheEntry)) {
+        return false;
+      }
+      CacheEntry other = (CacheEntry) o;
+      return apiLevel == other.apiLevel
+          && keepRules.equals(other.keepRules)
+          && shrink == other.shrink
+          && additionalProgramFiles.equals(other.additionalProgramFiles);
+    }
   }
 
   protected void assertLines2By2Correct(String stdOut) {
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/DesugaredLibraryContentTest.java b/src/test/java/com/android/tools/r8/desugar/corelib/DesugaredLibraryContentTest.java
index 5d803bd..20d4868 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/DesugaredLibraryContentTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/DesugaredLibraryContentTest.java
@@ -19,6 +19,7 @@
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.google.common.collect.ImmutableSet;
 import java.util.stream.Collectors;
+import org.junit.Assume;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -39,6 +40,7 @@
 
   @Test
   public void test() throws Exception {
+    Assume.assumeTrue(requiresCoreLibDesugaring(parameters));
     CodeInspector inspector = new CodeInspector(buildDesugaredLibrary(parameters.getApiLevel()));
     assertThat(inspector.clazz("j$.util.Optional"), isPresent());
     assertThat(inspector.clazz("j$.util.OptionalInt"), isPresent());
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/EmulatedInterfacesTest.java b/src/test/java/com/android/tools/r8/desugar/corelib/EmulatedInterfacesTest.java
new file mode 100644
index 0000000..cc3a1b0
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/EmulatedInterfacesTest.java
@@ -0,0 +1,94 @@
+// 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.corelib;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertTrue;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.code.Instruction;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+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 EmulatedInterfacesTest extends CoreLibDesugarTestBase {
+
+  private final TestParameters parameters;
+  private final boolean shrinkCoreLibrary;
+
+  @Parameters(name = "{1}, shrinkCoreLibrary: {0}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
+  }
+
+  public EmulatedInterfacesTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
+    this.shrinkCoreLibrary = shrinkDesugaredLibrary;
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testEmulatedInterface() throws Exception {
+    Assume.assumeTrue((requiresCoreLibDesugaring(parameters)));
+    CodeInspector inspector =
+        new CodeInspector(
+            buildDesugaredLibrary(
+                parameters.getApiLevel(), "-keep class **$-EL", shrinkCoreLibrary));
+    assertEmulateInterfaceClassesPresentWithDispatchMethods(inspector);
+    assertCollectionMethodsPresentWithCorrectDispatch(inspector);
+  }
+
+  private void assertEmulateInterfaceClassesPresentWithDispatchMethods(CodeInspector inspector) {
+    List<FoundClassSubject> dispatchClasses =
+        inspector.allClasses().stream()
+            .filter(
+                clazz ->
+                    clazz
+                        .getOriginalName()
+                        .contains(InterfaceMethodRewriter.EMULATE_LIBRARY_CLASS_NAME_SUFFIX))
+            .collect(Collectors.toList());
+    int numDispatchClasses = 9;
+    assertEquals(numDispatchClasses, dispatchClasses.size());
+    for (FoundClassSubject clazz : dispatchClasses) {
+      assertTrue(
+          clazz.allMethods().stream()
+              .allMatch(
+                  method ->
+                      method.isStatic()
+                          && method
+                              .streamInstructions()
+                              .anyMatch(InstructionSubject::isInstanceOf)));
+    }
+  }
+
+  private void assertCollectionMethodsPresentWithCorrectDispatch(CodeInspector inspector) {
+    DexClass collectionDispatch = inspector.clazz("j$.util.Collection$-EL").getDexClass();
+    for (DexEncodedMethod method : collectionDispatch.methods()) {
+      int numCheckCast =
+          (int)
+              Stream.of(method.getCode().asDexCode().instructions)
+                  .filter(Instruction::isCheckCast)
+                  .count();
+      if (method.qualifiedName().contains("spliterator")) {
+        assertEquals(5, numCheckCast);
+      } else {
+        assertEquals(1, numCheckCast);
+      }
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/MergingJ$Test.java b/src/test/java/com/android/tools/r8/desugar/corelib/MergingJ$Test.java
index 36561cb..f4f5807 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/MergingJ$Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/MergingJ$Test.java
@@ -47,20 +47,27 @@
   }
 
   private Path buildSplitDesugaredLibraryPart1() throws Exception {
-    Path output = temp.newFolder().toPath().resolve("merger-input.zip");
+    Path outputCf = temp.newFolder().toPath().resolve("merger-input-cf.zip");
+    Path outputDex = temp.newFolder().toPath().resolve("merger-input-dex.zip");
     L8.run(
         L8Command.builder()
             .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .addProgramFiles(ToolHelper.getDesugarJDKLibs())
             .addSpecialLibraryConfiguration("default")
             .setMinApiLevel(AndroidApiLevel.B.getLevel())
-            .setOutput(output, OutputMode.DexIndexed)
+            .setOutput(outputCf, OutputMode.ClassFile)
             .build());
-    return output;
+    testForD8()
+        .addProgramFiles(outputCf)
+        .setMinApi(AndroidApiLevel.B)
+        .compile()
+        .writeToZip(outputDex);
+    return outputDex;
   }
 
   private Path buildSplitDesugaredLibraryPart2() throws Exception {
-    Path output = temp.newFolder().toPath().resolve("merger-input-split.zip");
+    Path outputCf = temp.newFolder().toPath().resolve("merger-input-split-cf.zip");
+    Path outputDex = temp.newFolder().toPath().resolve("merger-input-split-dex.zip");
     L8.run(
         L8Command.builder()
             .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
@@ -68,8 +75,13 @@
             .addClasspathFiles(ToolHelper.getDesugarJDKLibs())
             .addSpecialLibraryConfiguration("default")
             .setMinApiLevel(AndroidApiLevel.B.getLevel())
-            .setOutput(output, OutputMode.DexIndexed)
+            .setOutput(outputCf, OutputMode.ClassFile)
             .build());
-    return output;
+    testForD8()
+        .addProgramFiles(outputCf)
+        .setMinApi(AndroidApiLevel.B)
+        .compile()
+        .writeToZip(outputDex);
+    return outputDex;
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/EmulateLibraryInterfaceTest.java b/src/test/java/com/android/tools/r8/desugar/corelib/ProgramRewritingTest.java
similarity index 76%
rename from src/test/java/com/android/tools/r8/desugar/corelib/EmulateLibraryInterfaceTest.java
rename to src/test/java/com/android/tools/r8/desugar/corelib/ProgramRewritingTest.java
index 19763ad..8aeddab 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/EmulateLibraryInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/ProgramRewritingTest.java
@@ -16,80 +16,111 @@
 import com.android.tools.r8.D8TestRunResult;
 import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.DexVm;
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.Box;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import java.nio.file.Paths;
 import java.util.List;
 import java.util.stream.Collectors;
-import java.util.stream.Stream;
 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 EmulateLibraryInterfaceTest extends CoreLibDesugarTestBase {
+public class ProgramRewritingTest extends CoreLibDesugarTestBase {
+
+  private static final String TEST_CLASS = "stream.ProgramRewritingTestClass";
 
   private final TestParameters parameters;
+  private final boolean shrinkCoreLibrary;
 
-  @Parameterized.Parameters(name = "{0}")
-  public static TestParametersCollection data() {
-    return getTestParameters().withDexRuntimes().withAllApiLevels().build();
+  @Parameters(name = "{1}, shrinkCoreLibrary: {0}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
   }
 
-  public EmulateLibraryInterfaceTest(TestParameters parameters) {
+  public ProgramRewritingTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
+    this.shrinkCoreLibrary = shrinkDesugaredLibrary;
     this.parameters = parameters;
   }
 
   @Test
-  public void testDispatchClasses() throws Exception {
-    CodeInspector inspector = new CodeInspector(buildDesugaredLibrary(parameters.getApiLevel()));
-    List<FoundClassSubject> dispatchClasses =
-        inspector.allClasses().stream()
-            .filter(
-                clazz ->
-                    clazz
-                        .getOriginalName()
-                        .contains(InterfaceMethodRewriter.EMULATE_LIBRARY_CLASS_NAME_SUFFIX))
-            .collect(Collectors.toList());
-    int numDispatchClasses = requiresCoreLibDesugaring(parameters) ? 9 : 0;
-    assertEquals(numDispatchClasses, dispatchClasses.size());
-    for (FoundClassSubject clazz : dispatchClasses) {
+  public void testProgramD8() throws Exception {
+    Assume.assumeTrue("No desugaring for high API levels", requiresCoreLibDesugaring(parameters));
+    Box<String> keepRulesHolder = new Box<>("");
+    D8TestRunResult d8TestRunResult =
+        testForD8()
+            .addProgramFiles(Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR + "stream.jar"))
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+            .setMinApi(parameters.getApiLevel())
+            .addOptionsModification(
+                options ->
+                    options.testing.desugaredLibraryKeepRuleConsumer =
+                        (string, handler) -> keepRulesHolder.set(keepRulesHolder.get() + string))
+            .enableCoreLibraryDesugaring()
+            .compile()
+            .inspect(this::checkRewrittenInvokes)
+            .addRunClasspathFiles(
+                buildDesugaredLibrary(
+                    parameters.getApiLevel(), keepRulesHolder.get(), shrinkCoreLibrary))
+            .run(parameters.getRuntime(), TEST_CLASS)
+            .assertSuccess();
+    assertLines2By2Correct(d8TestRunResult.getStdOut());
+    assertGeneratedKeepRulesAreCorrect(keepRulesHolder.get());
+    String stdErr = d8TestRunResult.getStdErr();
+    if (parameters.getRuntime().asDex().getVm().isOlderThanOrEqual(DexVm.ART_4_4_4_HOST)) {
+      // Flaky: There might be a missing method on lambda deserialization.
       assertTrue(
-          clazz.allMethods().stream()
-              .allMatch(
-                  method ->
-                      method.isStatic()
-                          && method
-                              .streamInstructions()
-                              .anyMatch(InstructionSubject::isInstanceOf)));
+          !stdErr.contains("Could not find method")
+              || stdErr.contains("Could not find method java.lang.invoke.SerializedLambda"));
+    } else {
+      assertFalse(stdErr.contains("Could not find method"));
     }
-    if (requiresCoreLibDesugaring(parameters)) {
-      DexClass collectionDispatch = inspector.clazz("j$.util.Collection$-EL").getDexClass();
-      for (DexEncodedMethod method : collectionDispatch.methods()) {
-        int numCheckCast =
-            (int)
-                Stream.of(method.getCode().asDexCode().instructions)
-                    .filter(Instruction::isCheckCast)
-                    .count();
-        if (method.qualifiedName().contains("spliterator")) {
-          assertEquals(5, numCheckCast);
-        } else {
-          assertEquals(1, numCheckCast);
-        }
+  }
+
+  @Test
+  public void testProgramR8() throws Exception {
+    Assume.assumeTrue("No desugaring for high API levels", requiresCoreLibDesugaring(parameters));
+    for (Boolean minifying : BooleanUtils.values()) {
+      Box<String> keepRulesHolder = new Box<>("");
+      R8TestRunResult r8TestRunResult =
+          testForR8(parameters.getBackend())
+              .minification(minifying)
+              .addKeepMainRule(TEST_CLASS)
+              .addProgramFiles(Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR + "stream.jar"))
+              .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+              .setMinApi(parameters.getApiLevel())
+              .addOptionsModification(
+                  options ->
+                      options.testing.desugaredLibraryKeepRuleConsumer =
+                          (string, handler) -> keepRulesHolder.set(keepRulesHolder.get() + string))
+              .enableCoreLibraryDesugaring()
+              .compile()
+              .inspect(this::checkRewrittenInvokes)
+              .addRunClasspathFiles(
+                  buildDesugaredLibrary(
+                      parameters.getApiLevel(), keepRulesHolder.get(), shrinkCoreLibrary))
+              .run(parameters.getRuntime(), TEST_CLASS)
+              .assertSuccess();
+      assertLines2By2Correct(r8TestRunResult.getStdOut());
+      assertGeneratedKeepRulesAreCorrect(keepRulesHolder.get());
+      if (parameters.getRuntime().asDex().getVm().isOlderThanOrEqual(DexVm.ART_4_4_4_HOST)) {
+        // Flaky: There might be a missing method on lambda deserialization.
+        r8TestRunResult.assertStderrMatches(
+            anyOf(
+                not(containsString("Could not find method")),
+                containsString("Could not find method java.lang.invoke.SerializedLambda")));
+      } else {
+        r8TestRunResult.assertStderrMatches(not(containsString("Could not find method")));
       }
     }
   }
@@ -98,7 +129,7 @@
     if (!requiresCoreLibDesugaring(parameters)) {
       return;
     }
-    ClassSubject classSubject = inspector.clazz("stream.TestClass");
+    ClassSubject classSubject = inspector.clazz(TEST_CLASS);
     assertThat(classSubject, isPresent());
     List<InstructionSubject> invokes =
         classSubject
@@ -140,74 +171,6 @@
     assertTrue(invokes.get(i).toString().contains(s));
   }
 
-  @Test
-  public void testProgramD8() throws Exception {
-    Assume.assumeTrue("No desugaring for high API levels", requiresCoreLibDesugaring(parameters));
-    Box<String> keepRulesHolder = new Box<>("");
-    D8TestRunResult d8TestRunResult =
-        testForD8()
-            .addProgramFiles(Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR + "stream.jar"))
-            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
-            .setMinApi(parameters.getApiLevel())
-            .addOptionsModification(
-                options ->
-                    options.testing.desugaredLibraryKeepRuleConsumer =
-                        (string, handler) -> keepRulesHolder.set(keepRulesHolder.get() + string))
-            .enableCoreLibraryDesugaring()
-            .compile()
-            .inspect(this::checkRewrittenInvokes)
-            .addRunClasspathFiles(buildDesugaredLibrary(parameters.getApiLevel()))
-            .run(parameters.getRuntime(), "stream.TestClass")
-            .assertSuccess();
-    assertLines2By2Correct(d8TestRunResult.getStdOut());
-    assertGeneratedKeepRulesAreCorrect(keepRulesHolder.get());
-    String stdErr = d8TestRunResult.getStdErr();
-    if (parameters.getRuntime().asDex().getVm().isOlderThanOrEqual(DexVm.ART_4_4_4_HOST)) {
-      // Flaky: There might be a missing method on lambda deserialization.
-      assertTrue(
-          !stdErr.contains("Could not find method")
-              || stdErr.contains("Could not find method java.lang.invoke.SerializedLambda"));
-    } else {
-      assertFalse(stdErr.contains("Could not find method"));
-    }
-  }
-
-  @Test
-  public void testProgramR8() throws Exception {
-    Assume.assumeTrue("No desugaring for high API levels", requiresCoreLibDesugaring(parameters));
-    for (Boolean minifying : BooleanUtils.values()) {
-      Box<String> keepRulesHolder = new Box<>("");
-      R8TestRunResult r8TestRunResult =
-          testForR8(parameters.getBackend())
-              .minification(minifying)
-              .addKeepMainRule("stream.TestClass")
-              .addProgramFiles(Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR + "stream.jar"))
-              .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
-              .setMinApi(parameters.getApiLevel())
-              .addOptionsModification(
-                  options ->
-                      options.testing.desugaredLibraryKeepRuleConsumer =
-                          (string, handler) -> keepRulesHolder.set(keepRulesHolder.get() + string))
-              .enableCoreLibraryDesugaring()
-              .compile()
-              .inspect(this::checkRewrittenInvokes)
-              .addRunClasspathFiles(buildDesugaredLibrary(parameters.getApiLevel()))
-              .run(parameters.getRuntime(), "stream.TestClass")
-              .assertSuccess();
-      assertLines2By2Correct(r8TestRunResult.getStdOut());
-      assertGeneratedKeepRulesAreCorrect(keepRulesHolder.get());
-      if (parameters.getRuntime().asDex().getVm().isOlderThanOrEqual(DexVm.ART_4_4_4_HOST)) {
-        // Flaky: There might be a missing method on lambda deserialization.
-        r8TestRunResult.assertStderrMatches(
-            anyOf(
-                not(containsString("Could not find method")),
-                containsString("Could not find method java.lang.invoke.SerializedLambda")));
-      } else {
-        r8TestRunResult.assertStderrMatches(not(containsString("Could not find method")));
-      }
-    }
-  }
-
   private void assertGeneratedKeepRulesAreCorrect(String keepRules) {
     String expectedResult =
         StringUtils.lines(
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/corelibjdktests/Jdk11CoreLibTestBase.java b/src/test/java/com/android/tools/r8/desugar/corelib/corelibjdktests/Jdk11CoreLibTestBase.java
index f77099a..169c7f9 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/corelibjdktests/Jdk11CoreLibTestBase.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/corelibjdktests/Jdk11CoreLibTestBase.java
@@ -103,6 +103,6 @@
   protected Path buildDesugaredLibraryWithJavaBaseExtension(AndroidApiLevel apiLevel)
       throws Exception {
     return buildDesugaredLibrary(
-        apiLevel, ImmutableList.copyOf(JDK_11_JAVA_BASE_EXTENSION_COMPILED_FILES));
+        apiLevel, "", false, ImmutableList.copyOf(JDK_11_JAVA_BASE_EXTENSION_COMPILED_FILES));
   }
 }