Merge commit '54a1c60229a9124084ddcfba5bc4521b10825ce3' into dev-release
diff --git a/.gitignore b/.gitignore
index 24eead1..d78f4a4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -121,6 +121,16 @@
 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/desugar_jdk_libs_releases/1.0.9
+third_party/openjdk/desugar_jdk_libs_releases/1.0.9.tar.gz
+third_party/openjdk/desugar_jdk_libs_releases/1.0.10
+third_party/openjdk/desugar_jdk_libs_releases/1.0.10.tar.gz
+third_party/openjdk/desugar_jdk_libs_releases/1.1.0
+third_party/openjdk/desugar_jdk_libs_releases/1.1.0.tar.gz
+third_party/openjdk/desugar_jdk_libs_releases/1.1.1
+third_party/openjdk/desugar_jdk_libs_releases/1.1.1.tar.gz
+third_party/openjdk/desugar_jdk_libs_releases/1.1.5
+third_party/openjdk/desugar_jdk_libs_releases/1.1.5.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/PRESUBMIT.py b/PRESUBMIT.py
index faa8808..c3902b8 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -82,7 +82,10 @@
   return results
 
 def CopyRightInContents(f, contents):
-  expected = ('#' if f.LocalPath().endswith('.py') else '//') + ' Copyright'
+  expected = '//'
+  if f.LocalPath().endswith('.py') or f.LocalPath().endswith('.sh'):
+    expected = '#'
+  expected = expected + ' Copyright'
   for content_line in contents:
     if expected in content_line:
       return True
diff --git a/build.gradle b/build.gradle
index f69b505..7f0d08f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -336,6 +336,11 @@
                 "openjdk/openjdk-rt-1.8",
                 "openjdk/desugar_jdk_libs",
                 "openjdk/desugar_jdk_libs_11",
+                "openjdk/desugar_jdk_libs_releases/1.0.9",
+                "openjdk/desugar_jdk_libs_releases/1.0.10",
+                "openjdk/desugar_jdk_libs_releases/1.1.0",
+                "openjdk/desugar_jdk_libs_releases/1.1.1",
+                "openjdk/desugar_jdk_libs_releases/1.1.5",
                 "openjdk/jdk-11-test",
                 "proguard/proguard5.2.1",
                 "proguard/proguard6.0.1",
diff --git a/scripts/import_released_desugar_jdk_libs.sh b/scripts/import_released_desugar_jdk_libs.sh
new file mode 100755
index 0000000..6f02117
--- /dev/null
+++ b/scripts/import_released_desugar_jdk_libs.sh
@@ -0,0 +1,56 @@
+#!/bin/bash
+#
+# 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.
+
+set -e
+set -x
+
+if [[ -z "$1" ]]; then
+  echo "No version argument supplied"
+  exit -1
+fi
+
+VERSION=$1
+
+RELEASES_ROOT=third_party/openjdk/desugar_jdk_libs_releases
+mkdir -p $RELEASES_ROOT
+RELEASED_VERSION_DIR=$RELEASES_ROOT/$VERSION
+if [[ -d $RELEASED_VERSION_DIR ]]; then
+    echo "$RELEASED_VERSION_DIR already exists"
+    exit -1
+fi
+
+MAVEN_REPO_DIR=/tmp/maven_repo_local
+rm -rf $MAVEN_REPO_DIR
+
+DOWNLOAD_DIR=/tmp/desugar_jdk_libs_download
+rm -rf $DOWNLOAD_DIR
+mkdir -p $DOWNLOAD_DIR
+
+mvn \
+  org.apache.maven.plugins:maven-dependency-plugin:2.4:get \
+  -Dmaven.repo.local=$MAVEN_REPO_DIR \
+  -DremoteRepositories=http://maven.google.com \
+  -Dartifact=com.android.tools:desugar_jdk_libs:$VERSION \
+  -Ddest=$DOWNLOAD_DIR/desugar_jdk_libs.jar
+
+mvn \
+  org.apache.maven.plugins:maven-dependency-plugin:2.4:get \
+  -Dmaven.repo.local=$MAVEN_REPO_DIR \
+  -DremoteRepositories=http://maven.google.com \
+  -Dartifact=com.android.tools:desugar_jdk_libs_configuration:$VERSION \
+  -Ddest=$DOWNLOAD_DIR/desugar_jdk_libs_configuration.jar
+
+  unzip $DOWNLOAD_DIR/desugar_jdk_libs_configuration.jar META-INF/desugar/d8/desugar.json -d $DOWNLOAD_DIR
+
+  mkdir $RELEASED_VERSION_DIR
+  cp $DOWNLOAD_DIR/desugar_jdk_libs.jar $RELEASED_VERSION_DIR
+  cp $DOWNLOAD_DIR/desugar_jdk_libs_configuration.jar $RELEASED_VERSION_DIR
+  cp $DOWNLOAD_DIR/META-INF/desugar/d8/desugar.json $RELEASED_VERSION_DIR/desugar.json
+  cp third_party/openjdk/desugar_jdk_libs/README.google $RELEASED_VERSION_DIR
+
+  (cd $RELEASES_ROOT && \
+    upload_to_google_storage.py -a --bucket r8-deps $VERSION && \
+    git add $VERSION.tar.gz.sha1)
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index e02ccfb..6edb405 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -344,6 +344,18 @@
                         options.getProguardConfiguration().getRules(), synthesizedProguardRules))
                 .build(executorService));
 
+        // Compute the main dex rootset that will be the base of first and final main dex tracing
+        // before building a new appview with only live classes (and invalidating subtypingInfo).
+        if (!options.mainDexKeepRules.isEmpty()) {
+          assert appView.graphLens().isIdentityLens();
+          // Find classes which may have code executed before secondary dex files installation.
+          MainDexRootSet mainDexRootSet =
+              MainDexRootSet.builder(appView, subtypingInfo, options.mainDexKeepRules)
+                  .build(executorService);
+          appView.setMainDexRootSet(mainDexRootSet);
+          appView.appInfo().unsetObsolete();
+        }
+
         AnnotationRemover.Builder annotationRemoverBuilder =
             options.isShrinking() ? AnnotationRemover.builder() : null;
         AppView<AppInfoWithLiveness> appViewWithLiveness =
@@ -423,6 +435,7 @@
       // Build conservative main dex content after first round of tree shaking. This is used
       // by certain optimizations to avoid introducing additional class references into main dex
       // classes, as that can cause the final number of main dex methods to grow.
+      // TODO(b/190941270): See if we can move this up before treepruning.
       performInitialMainDexTracing(appView, executorService);
 
       // The class type lattice elements include information about the interfaces that a class
@@ -853,16 +866,12 @@
       return;
     }
     assert appView.graphLens().isIdentityLens();
-    // Find classes which may have code executed before secondary dex files installation.
-    SubtypingInfo subtypingInfo = new SubtypingInfo(appView);
-    MainDexRootSet mainDexRootSet =
-        MainDexRootSet.builder(appView, subtypingInfo, options.mainDexKeepRules)
-            .build(executorService);
-    appView.setMainDexRootSet(mainDexRootSet);
-    appView.appInfo().unsetObsolete();
-    // Live types is the tracing result.
+
+    // Find classes which may have code executed before secondary dex files installation by
+    // computing from the initially computed main dex root set.
     MainDexInfo mainDexInfo =
-        EnqueuerFactory.createForInitialMainDexTracing(appView, executorService, subtypingInfo)
+        EnqueuerFactory.createForInitialMainDexTracing(
+                appView, executorService, new SubtypingInfo(appView))
             .traceMainDex(executorService, timing);
     appView.setAppInfo(appView.appInfo().rebuildWithMainDexInfo(mainDexInfo));
   }
diff --git a/src/main/java/com/android/tools/r8/ResourceShrinker.java b/src/main/java/com/android/tools/r8/ResourceShrinker.java
index bf4f471..bf40d89 100644
--- a/src/main/java/com/android/tools/r8/ResourceShrinker.java
+++ b/src/main/java/com/android/tools/r8/ResourceShrinker.java
@@ -259,7 +259,7 @@
               .flatMap(f -> f.annotations().stream());
       Stream<DexAnnotation> methodAnnotations =
           Streams.stream(classDef.methods())
-              .filter(DexEncodedMethod::hasAnnotation)
+              .filter(DexEncodedMethod::hasAnyAnnotations)
               .flatMap(m -> m.annotations().stream());
 
       Streams.concat(classAnnotations, fieldAnnotations, methodAnnotations)
diff --git a/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java b/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java
index bc57c25..02aebd3 100644
--- a/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java
+++ b/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java
@@ -352,7 +352,7 @@
 
   @Override
   public void print(CfConstNull constNull) {
-    throw new Unimplemented(constNull.getClass().getSimpleName());
+    printNewInstruction("CfConstNull");
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
index eee2f72..3b2c1df 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -557,7 +557,7 @@
               clazz.annotations().annotations,
               annotations.toArray(DexAnnotation.EMPTY_ARRAY),
               DexAnnotation.class);
-      clazz.setAnnotations(new DexAnnotationSet(copy));
+      clazz.setAnnotations(DexAnnotationSet.create(copy));
     }
 
     // Clear the attribute structures now that they are represented in annotations.
@@ -572,7 +572,7 @@
     }
     // Append the annotations to annotations array of the field.
     field.setAnnotations(
-        new DexAnnotationSet(
+        DexAnnotationSet.create(
             ArrayUtils.appendSingleElement(
                 field.annotations().annotations,
                 DexAnnotation.createSignatureAnnotation(
@@ -587,7 +587,7 @@
     }
     // Append the annotations to annotations array of the method.
     method.setAnnotations(
-        new DexAnnotationSet(
+        DexAnnotationSet.create(
             ArrayUtils.appendSingleElement(
                 method.annotations().annotations,
                 DexAnnotation.createSignatureAnnotation(
diff --git a/src/main/java/com/android/tools/r8/dex/DexParser.java b/src/main/java/com/android/tools/r8/dex/DexParser.java
index e2b7f93..b279333 100644
--- a/src/main/java/com/android/tools/r8/dex/DexParser.java
+++ b/src/main/java/com/android/tools/r8/dex/DexParser.java
@@ -396,7 +396,7 @@
     for (int i = 0; i < size; i++) {
       values[i] = annotationSetAt(annotationOffsets[i]);
     }
-    return new ParameterAnnotationsList(values);
+    return ParameterAnnotationsList.create(values);
   }
 
   private DexParameterAnnotation[] parseParameterAnnotations(int size) {
@@ -485,7 +485,7 @@
       throw new CompilationError(
           "Multiple annotations of type `" + dupType.toSourceString() + "`");
     }
-    return new DexAnnotationSet(result);
+    return DexAnnotationSet.create(result);
   }
 
   private boolean retainAnnotation(DexAnnotation annotation) {
@@ -1375,7 +1375,7 @@
         int size = lazyAnnotations.size();
         return size == 0
             ? DexAnnotationSet.empty()
-            : new DexAnnotationSet(lazyAnnotations.toArray(DexAnnotation.EMPTY_ARRAY));
+            : DexAnnotationSet.create(lazyAnnotations.toArray(DexAnnotation.EMPTY_ARRAY));
       }
       return originalAnnotations;
     }
diff --git a/src/main/java/com/android/tools/r8/graph/ClasspathClass.java b/src/main/java/com/android/tools/r8/graph/ClasspathClass.java
index 9ae72e4..3801ef8 100644
--- a/src/main/java/com/android/tools/r8/graph/ClasspathClass.java
+++ b/src/main/java/com/android/tools/r8/graph/ClasspathClass.java
@@ -4,4 +4,10 @@
 
 package com.android.tools.r8.graph;
 
-public interface ClasspathClass extends ClasspathDefinition, ClasspathOrLibraryClass {}
+public interface ClasspathClass extends ClasspathDefinition, ClasspathOrLibraryClass {
+
+  @Override
+  default DexClass asDexClass() {
+    return asClasspathClass();
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/ClasspathOrLibraryClass.java b/src/main/java/com/android/tools/r8/graph/ClasspathOrLibraryClass.java
index cf385e0..da19912 100644
--- a/src/main/java/com/android/tools/r8/graph/ClasspathOrLibraryClass.java
+++ b/src/main/java/com/android/tools/r8/graph/ClasspathOrLibraryClass.java
@@ -4,4 +4,6 @@
 
 package com.android.tools.r8.graph;
 
-public interface ClasspathOrLibraryClass extends ClassDefinition, ClasspathOrLibraryDefinition {}
+public interface ClasspathOrLibraryClass extends ClassDefinition, ClasspathOrLibraryDefinition {
+  DexClass asDexClass();
+}
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java b/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java
index 454be57..40ff50e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java
@@ -30,8 +30,7 @@
   public static final DexAnnotationSet[] EMPTY_ARRAY = {};
 
   private static final int UNSORTED = 0;
-  private static final DexAnnotationSet THE_EMPTY_ANNOTATIONS_SET =
-      new DexAnnotationSet(DexAnnotation.EMPTY_ARRAY);
+  private static final DexAnnotationSet THE_EMPTY_ANNOTATIONS_SET = new DexAnnotationSet();
 
   public final DexAnnotation[] annotations;
   private int sorted = UNSORTED;
@@ -40,11 +39,16 @@
     spec.withItemArray(a -> a.annotations);
   }
 
-  public DexAnnotationSet(DexAnnotation[] annotations) {
+  private DexAnnotationSet() {
+    this.annotations = DexAnnotation.EMPTY_ARRAY;
+  }
+
+  private DexAnnotationSet(DexAnnotation[] annotations) {
+    assert !ArrayUtils.isEmpty(annotations);
     this.annotations = annotations;
   }
 
-  public DexAnnotationSet create(DexAnnotation[] annotations) {
+  public static DexAnnotationSet create(DexAnnotation[] annotations) {
     return ArrayUtils.isEmpty(annotations) ? empty() : new DexAnnotationSet(annotations);
   }
 
@@ -160,7 +164,7 @@
         if (index < reducedArray.length) {
           System.arraycopy(annotations, index + 1, reducedArray, index, reducedArray.length - index);
         }
-        return new DexAnnotationSet(reducedArray);
+        return DexAnnotationSet.create(reducedArray);
       }
       ++index;
     }
@@ -180,7 +184,7 @@
       if (annotation.annotation.type == newAnnotation.annotation.type) {
         DexAnnotation[] modifiedArray = annotations.clone();
         modifiedArray[index] = newAnnotation;
-        return new DexAnnotationSet(modifiedArray);
+        return DexAnnotationSet.create(modifiedArray);
       }
       ++index;
     }
@@ -189,7 +193,7 @@
     DexAnnotation[] extendedArray = new DexAnnotation[annotations.length + 1];
     System.arraycopy(annotations, 0, extendedArray, 0, annotations.length);
     extendedArray[annotations.length] = newAnnotation;
-    return new DexAnnotationSet(extendedArray);
+    return DexAnnotationSet.create(extendedArray);
   }
 
   public DexAnnotationSet keepIf(Predicate<DexAnnotation> filter) {
@@ -242,7 +246,7 @@
         }
       }
     }
-    return newAnnotations == null ? this : new DexAnnotationSet(newAnnotations);
+    return newAnnotations == null ? this : DexAnnotationSet.create(newAnnotations);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexClassAndField.java b/src/main/java/com/android/tools/r8/graph/DexClassAndField.java
index e2deec9..2c78b93 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClassAndField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClassAndField.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.graph;
 
+import com.android.tools.r8.ir.optimize.info.FieldOptimizationInfo;
 import com.android.tools.r8.references.FieldReference;
 
 public abstract class DexClassAndField extends DexClassAndMember<DexEncodedField, DexField> {
@@ -35,6 +36,11 @@
     return getReference().asFieldReference();
   }
 
+  @Override
+  public FieldOptimizationInfo getOptimizationInfo() {
+    return getDefinition().getOptimizationInfo();
+  }
+
   public DexType getType() {
     return getReference().getType();
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexClassAndMember.java b/src/main/java/com/android/tools/r8/graph/DexClassAndMember.java
index 2ac7ced..4aebe97 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClassAndMember.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClassAndMember.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.graph;
 
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.ir.optimize.info.MemberOptimizationInfo;
 import com.android.tools.r8.origin.Origin;
 
 public abstract class DexClassAndMember<D extends DexEncodedMember<D, R>, R extends DexMember<D, R>>
@@ -49,6 +50,10 @@
     return definition.getReference();
   }
 
+  public MemberOptimizationInfo<?> getOptimizationInfo() {
+    return getDefinition().getOptimizationInfo();
+  }
+
   @Override
   public Origin getOrigin() {
     return holder.origin;
diff --git a/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java b/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
index ccc7dbc..53cbfe8 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.graph;
 
+import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo;
 import com.android.tools.r8.references.MethodReference;
 
 public abstract class DexClassAndMethod extends DexClassAndMember<DexEncodedMethod, DexMethod>
@@ -52,6 +53,11 @@
     return getReference().getSignature();
   }
 
+  @Override
+  public MethodOptimizationInfo getOptimizationInfo() {
+    return getDefinition().getOptimizationInfo();
+  }
+
   public DexType getParameter(int index) {
     return getReference().getParameter(index);
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexDefinition.java b/src/main/java/com/android/tools/r8/graph/DexDefinition.java
index 2695b1f..c2e8fae 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDefinition.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDefinition.java
@@ -25,6 +25,11 @@
     return !annotations().isEmpty();
   }
 
+  // Also returns true if a method has parameter annotations.
+  public boolean hasAnyAnnotations() {
+    return hasAnnotations();
+  }
+
   public DexAnnotationSet annotations() {
     return annotations;
   }
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 f8a2537..36cb33c 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -48,7 +48,6 @@
 import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
 import com.android.tools.r8.ir.analysis.inlining.SimpleInliningConstraint;
 import com.android.tools.r8.ir.code.IRCode;
-import com.android.tools.r8.ir.code.Invoke;
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.DexBuilder;
@@ -63,16 +62,14 @@
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
 import com.android.tools.r8.ir.optimize.inliner.WhyAreYouNotInliningReporter;
 import com.android.tools.r8.ir.regalloc.RegisterAllocator;
-import com.android.tools.r8.ir.synthetic.FieldAccessorBuilder;
 import com.android.tools.r8.ir.synthetic.ForwardMethodBuilder;
-import com.android.tools.r8.ir.synthetic.ForwardMethodSourceCode;
-import com.android.tools.r8.ir.synthetic.SynthesizedCode;
 import com.android.tools.r8.kotlin.KotlinMethodLevelInfo;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
 import com.android.tools.r8.naming.MemberNaming.Signature;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.position.MethodPosition;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.ConsumerUtils;
 import com.android.tools.r8.utils.InternalOptions;
@@ -890,6 +887,11 @@
   }
 
   @Override
+  public boolean hasAnyAnnotations() {
+    return hasAnnotations() || hasParameterAnnotations();
+  }
+
+  @Override
   public void clearAllAnnotations() {
     clearAnnotations();
     clearParameterAnnotations();
@@ -917,6 +919,10 @@
     return parameterAnnotationsList;
   }
 
+  public boolean hasParameterAnnotations() {
+    return !getParameterAnnotations().isEmpty();
+  }
+
   public void setParameterAnnotations(ParameterAnnotationsList parameterAnnotations) {
     this.parameterAnnotationsList = parameterAnnotations;
   }
@@ -1220,89 +1226,12 @@
     return builder.build();
   }
 
-  public ProgramMethod toInitializerForwardingBridge(
-      DexProgramClass holder, DexMethod newMethod, DexItemFactory dexItemFactory) {
-    assert isPrivate()
-        : "Expected to create bridge for private constructor as part of nest-based access"
-            + " desugaring";
-    assert !holder.isInterface();
-    return new ProgramMethod(
-        holder,
-        syntheticBuilder(this)
-            .setMethod(newMethod)
-            .setCode(
-                ForwardMethodBuilder.builder(dexItemFactory)
-                    .setNonStaticSourceWithExtraUnusedParameter(newMethod)
-                    .setConstructorTarget(getReference())
-                    .build())
-            .modifyAccessFlags(
-                accessFlags -> {
-                  assert !accessFlags.isStatic();
-                  accessFlags.unsetPrivate();
-                  accessFlags.setSynthetic();
-                  accessFlags.setConstructor();
-                })
-            .build());
-  }
-
-  public static ProgramMethod createFieldAccessorBridge(
-      ProgramField field, boolean isGet, DexMethod newMethod) {
-    MethodAccessFlags accessFlags =
-        MethodAccessFlags.fromSharedAccessFlags(
-            Constants.ACC_SYNTHETIC
-                | Constants.ACC_STATIC
-                | (field.getHolder().isInterface() ? Constants.ACC_PUBLIC : 0),
-            false);
-    CfCode code =
-        FieldAccessorBuilder.builder()
-            .apply(isGet ? FieldAccessorBuilder::setGetter : FieldAccessorBuilder::setSetter)
-            .setField(field)
-            .setSourceMethod(newMethod)
-            .build();
-    return new ProgramMethod(
-        field.getHolder(),
-        new DexEncodedMethod(
-            newMethod,
-            accessFlags,
-            MethodTypeSignature.noSignature(),
-            DexAnnotationSet.empty(),
-            ParameterAnnotationsList.empty(),
-            code,
-            true));
-  }
-
   public DexEncodedMethod toRenamedHolderMethod(DexType newHolderType, DexItemFactory factory) {
     DexEncodedMethod.Builder builder = DexEncodedMethod.builder(this);
     builder.setMethod(getReference().withHolder(newHolderType, factory));
     return builder.build();
   }
 
-  public ProgramMethod toStaticForwardingBridge(
-      DexProgramClass holder, DexMethod newMethod, DexItemFactory dexItemFactory) {
-    assert isPrivate()
-        : "Expected to create bridge for private method as part of nest-based access desugaring";
-    return new ProgramMethod(
-        holder,
-        syntheticBuilder(this)
-            .setMethod(newMethod)
-            .setCode(
-                ForwardMethodBuilder.builder(dexItemFactory)
-                    .setStaticSource(newMethod)
-                    .applyIf(
-                        isStatic(),
-                        builder -> builder.setStaticTarget(getReference(), holder.isInterface()),
-                        builder -> builder.setDirectTarget(getReference(), holder.isInterface()))
-                    .build())
-            .setAccessFlags(
-                MethodAccessFlags.builder()
-                    .setBridge()
-                    .setPublic(holder.isInterface())
-                    .setStatic()
-                    .setSynthetic()
-                    .build())
-            .build());
-  }
-
   public ProgramMethod toPrivateSyntheticMethod(DexProgramClass holder, DexMethod method) {
     assert !isStatic();
     assert !isPrivate();
@@ -1381,31 +1310,28 @@
     // Some debuggers (like IntelliJ) automatically skip synthetic methods on single step.
     newFlags.setSynthetic();
     newFlags.unsetAbstract();
-    ForwardMethodSourceCode.Builder forwardSourceCodeBuilder =
-        ForwardMethodSourceCode.builder(newMethod);
-    forwardSourceCodeBuilder
-        .setReceiver(clazz.type)
-        .setTarget(forwardMethod)
-        .setInvokeType(Invoke.Type.STATIC)
-        .setIsInterface(false); // Holder is companion class, or retarget method, not an interface.
     return new DexEncodedMethod(
         newMethod,
         newFlags,
         MethodTypeSignature.noSignature(),
         DexAnnotationSet.empty(),
         ParameterAnnotationsList.empty(),
-        new SynthesizedCode(forwardSourceCodeBuilder::build),
+        ForwardMethodBuilder.builder(factory)
+            .setNonStaticSource(newMethod)
+            // Holder is companion class, or retarget method, not an interface.
+            .setStaticTarget(forwardMethod, false)
+            .build(),
         true);
   }
 
-  public DexEncodedMethod toStaticMethodWithoutThis() {
+  public DexEncodedMethod toStaticMethodWithoutThis(AppView<AppInfoWithLiveness> appView) {
     checkIfObsolete();
     assert !accessFlags.isStatic();
     Builder builder =
         builder(this)
             .promoteToStatic()
             .withoutThisParameter()
-            .adjustOptimizationInfoAfterRemovingThisParameter()
+            .adjustOptimizationInfoAfterRemovingThisParameter(appView)
             .setGenericSignature(MethodTypeSignature.noSignature());
     DexEncodedMethod method = builder.build();
     method.copyMetadata(this);
@@ -1462,11 +1388,6 @@
     return this;
   }
 
-  public boolean hasAnnotation() {
-    checkIfObsolete();
-    return !annotations().isEmpty() || !parameterAnnotationsList.isEmpty();
-  }
-
   public static int slowCompare(DexEncodedMethod m1, DexEncodedMethod m2) {
     return m1.getReference().compareTo(m2.getReference());
   }
@@ -1535,26 +1456,34 @@
     return new Builder(from, true);
   }
 
+  public static Builder builder() {
+    return new Builder();
+  }
+
   private static Builder builder(DexEncodedMethod from) {
     return new Builder(from);
   }
 
   public static class Builder {
 
-    private DexMethod method;
     private MethodAccessFlags accessFlags;
-    private MethodTypeSignature genericSignature;
-    private final DexAnnotationSet annotations;
-    private OptionalBool isLibraryMethodOverride = OptionalBool.UNKNOWN;
-    private ParameterAnnotationsList parameterAnnotations;
     private Code code;
-    private CompilationState compilationState;
-    private MethodOptimizationInfo optimizationInfo;
-    private KotlinMethodLevelInfo kotlinMemberInfo;
-    private final CfVersion classFileVersion;
-    private boolean d8R8Synthesized;
+    private DexMethod method;
+
+    private MethodTypeSignature genericSignature = MethodTypeSignature.noSignature();
+    private DexAnnotationSet annotations = DexAnnotationSet.empty();
+    private OptionalBool isLibraryMethodOverride = OptionalBool.UNKNOWN;
+    private ParameterAnnotationsList parameterAnnotations = ParameterAnnotationsList.empty();
+    private CompilationState compilationState = CompilationState.NOT_PROCESSED;
+    private MethodOptimizationInfo optimizationInfo = DefaultMethodOptimizationInfo.getInstance();
+    private KotlinMethodLevelInfo kotlinInfo = getNoKotlinInfo();
+    private CfVersion classFileVersion = null;
+    private boolean d8R8Synthesized = false;
+
     private Consumer<DexEncodedMethod> buildConsumer = ConsumerUtils.emptyConsumer();
 
+    private Builder() {}
+
     private Builder(DexEncodedMethod from) {
       this(from, from.isD8R8Synthesized());
     }
@@ -1562,26 +1491,25 @@
     private Builder(DexEncodedMethod from, boolean d8R8Synthesized) {
       // Copy all the mutable state of a DexEncodedMethod here.
       method = from.getReference();
-      accessFlags = from.accessFlags.copy();
+      accessFlags = from.getAccessFlags().copy();
       genericSignature = from.getGenericSignature();
       annotations = from.annotations();
-      code = from.code;
-      compilationState = CompilationState.NOT_PROCESSED;
+      code = from.getCode();
       optimizationInfo =
-          from.optimizationInfo.isMutableOptimizationInfo()
-              ? from.optimizationInfo.asMutableMethodOptimizationInfo().mutableCopy()
-              : from.optimizationInfo;
-      kotlinMemberInfo = from.kotlinMemberInfo;
+          from.getOptimizationInfo().isMutableOptimizationInfo()
+              ? from.getOptimizationInfo().asMutableMethodOptimizationInfo().mutableCopy()
+              : from.getOptimizationInfo();
+      kotlinInfo = from.getKotlinInfo();
       classFileVersion = from.classFileVersion;
       this.d8R8Synthesized = d8R8Synthesized;
 
-      if (from.parameterAnnotationsList.isEmpty()
-          || from.parameterAnnotationsList.size() == method.proto.parameters.size()) {
-        parameterAnnotations = from.parameterAnnotationsList;
+      if (from.getParameterAnnotations().isEmpty()
+          || from.getParameterAnnotations().size() == from.getParameters().size()) {
+        parameterAnnotations = from.getParameterAnnotations();
       } else {
         // If the there are missing parameter annotations populate these when creating the builder.
         parameterAnnotations =
-            from.parameterAnnotationsList.withParameterCount(method.proto.parameters.size());
+            from.getParameterAnnotations().withParameterCount(from.getParameters().size());
       }
     }
 
@@ -1625,6 +1553,11 @@
       return this;
     }
 
+    public Builder setD8R8Synthesized() {
+      this.d8R8Synthesized = true;
+      return this;
+    }
+
     public Builder setMethod(DexMethod method) {
       this.method = method;
       return this;
@@ -1684,7 +1617,7 @@
       }
 
       return setParameterAnnotations(
-          new ParameterAnnotationsList(
+          ParameterAnnotationsList.create(
               newParameterAnnotations.toArray(DexAnnotationSet.EMPTY_ARRAY),
               newNumberOfMissingParameterAnnotations));
     }
@@ -1704,11 +1637,12 @@
       return this;
     }
 
-    public Builder adjustOptimizationInfoAfterRemovingThisParameter() {
+    public Builder adjustOptimizationInfoAfterRemovingThisParameter(
+        AppView<AppInfoWithLiveness> appView) {
       if (optimizationInfo.isMutableOptimizationInfo()) {
         optimizationInfo
             .asMutableMethodOptimizationInfo()
-            .adjustOptimizationInfoAfterRemovingThisParameter();
+            .adjustOptimizationInfoAfterRemovingThisParameter(appView);
       }
       return this;
     }
@@ -1735,7 +1669,7 @@
               code,
               d8R8Synthesized,
               classFileVersion);
-      result.setKotlinMemberInfo(kotlinMemberInfo);
+      result.setKotlinMemberInfo(kotlinInfo);
       result.compilationState = compilationState;
       result.optimizationInfo = optimizationInfo;
       if (!isLibraryMethodOverride.isUnknown()) {
diff --git a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
index 3c01abb..0b179ac 100644
--- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -610,7 +610,7 @@
             "Multiple annotations of type `" + dupType.toSourceString() + "`");
       }
     }
-    return new DexAnnotationSet(annotations.toArray(DexAnnotation.EMPTY_ARRAY));
+    return DexAnnotationSet.create(annotations.toArray(DexAnnotation.EMPTY_ARRAY));
   }
 
   private static class CreateFieldVisitor extends FieldVisitor {
@@ -885,7 +885,7 @@
         for (int i = 0; i < parameterAnnotationsLists.size(); i++) {
           sets[i] = createAnnotationSet(parameterAnnotationsLists.get(i), options);
         }
-        parameterAnnotationsList = new ParameterAnnotationsList(sets);
+        parameterAnnotationsList = ParameterAnnotationsList.create(sets);
       }
       if (parameterNames != null) {
         assert parameterFlags != null;
diff --git a/src/main/java/com/android/tools/r8/graph/LibraryClass.java b/src/main/java/com/android/tools/r8/graph/LibraryClass.java
index f4a7081..a45c77f 100644
--- a/src/main/java/com/android/tools/r8/graph/LibraryClass.java
+++ b/src/main/java/com/android/tools/r8/graph/LibraryClass.java
@@ -4,4 +4,10 @@
 
 package com.android.tools.r8.graph;
 
-public interface LibraryClass extends LibraryDefinition, ClasspathOrLibraryClass {}
+public interface LibraryClass extends LibraryDefinition, ClasspathOrLibraryClass {
+
+  @Override
+  default DexClass asDexClass() {
+    return asLibraryClass();
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/MethodCollection.java b/src/main/java/com/android/tools/r8/graph/MethodCollection.java
index 635132f..2412ea7 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodCollection.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodCollection.java
@@ -322,7 +322,7 @@
   public boolean hasAnnotations() {
     return traverse(
             method ->
-                method.hasAnnotation()
+                method.hasAnyAnnotations()
                     ? TraversalContinuation.BREAK
                     : TraversalContinuation.CONTINUE)
         .shouldBreak();
diff --git a/src/main/java/com/android/tools/r8/graph/ParameterAnnotationsList.java b/src/main/java/com/android/tools/r8/graph/ParameterAnnotationsList.java
index ba98190..fdda61b 100644
--- a/src/main/java/com/android/tools/r8/graph/ParameterAnnotationsList.java
+++ b/src/main/java/com/android/tools/r8/graph/ParameterAnnotationsList.java
@@ -60,23 +60,34 @@
     this.missingParameterAnnotations = 0;
   }
 
-  public ParameterAnnotationsList(DexAnnotationSet[] values) {
-    this(values, 0);
-  }
-
-  public ParameterAnnotationsList(DexAnnotationSet[] values, int missingParameterAnnotations) {
-    assert values != null && values.length > 0;
+  private ParameterAnnotationsList(DexAnnotationSet[] values, int missingParameterAnnotations) {
+    assert values != null;
+    assert values.length > 0;
+    assert !isAllEmpty(values);
     this.values = values;
     this.missingParameterAnnotations = missingParameterAnnotations;
   }
 
+  public static ParameterAnnotationsList create(DexAnnotationSet[] values) {
+    return create(values, 0);
+  }
+
   public static ParameterAnnotationsList create(
       DexAnnotationSet[] values, int missingParameterAnnotations) {
-    return ArrayUtils.isEmpty(values)
+    return ArrayUtils.isEmpty(values) || isAllEmpty(values)
         ? empty()
         : new ParameterAnnotationsList(values, missingParameterAnnotations);
   }
 
+  private static boolean isAllEmpty(DexAnnotationSet[] values) {
+    for (int i = 0; i < values.length; i++) {
+      if (!values[i].isEmpty()) {
+        return false;
+      }
+    }
+    return true;
+  }
+
   @Override
   public ParameterAnnotationsList self() {
     return this;
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/DesugaredLibraryConversionWrapperAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/DesugaredLibraryConversionWrapperAnalysis.java
index 4291896..ee41edb 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/DesugaredLibraryConversionWrapperAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/DesugaredLibraryConversionWrapperAnalysis.java
@@ -6,14 +6,11 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClasspathClass;
 import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.desugar.DesugaredLibraryAPIConverter;
 import com.android.tools.r8.ir.desugar.DesugaredLibraryAPIConverter.Mode;
 import com.android.tools.r8.utils.collections.ProgramMethodSet;
-import java.util.IdentityHashMap;
-import java.util.Map;
 import java.util.function.Consumer;
 
 public class DesugaredLibraryConversionWrapperAnalysis extends EnqueuerAnalysis
@@ -21,7 +18,6 @@
 
   private final AppView<?> appView;
   private final DesugaredLibraryAPIConverter converter;
-  private Map<DexType, DexClasspathClass> synthesizedWrappers = new IdentityHashMap<>();
 
   public DesugaredLibraryConversionWrapperAnalysis(AppView<?> appView) {
     this.appView = appView;
@@ -68,6 +64,6 @@
   }
 
   public void generateWrappers(Consumer<DexClasspathClass> synthesizedCallback) {
-    converter.synthesizeWrappers(synthesizedWrappers, synthesizedCallback);
+    converter.synthesizeWrappers(synthesizedCallback);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/RespectPackageBoundaries.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/RespectPackageBoundaries.java
index 8f59c36..6e9e19f 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/RespectPackageBoundaries.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/RespectPackageBoundaries.java
@@ -6,12 +6,16 @@
 
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexDefinition;
 import com.android.tools.r8.graph.DexEncodedMember;
 import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.horizontalclassmerging.MergeGroup;
 import com.android.tools.r8.horizontalclassmerging.MultiClassPolicy;
 import com.android.tools.r8.shaking.VerticalClassMerger.IllegalAccessDetector;
 import com.android.tools.r8.utils.TraversalContinuation;
+import com.google.common.collect.Iterables;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.LinkedHashMap;
@@ -31,6 +35,26 @@
       return true;
     }
 
+    // Annotations may access non-public items (or themselves be non-public), so for now we
+    // conservatively restrict class merging when annotations are present.
+    //
+    // Note that in non-compat mode we should never see any annotations here, since we only merge
+    // non-kept classes with non-kept members.
+    if (clazz.hasAnnotations()
+        || Iterables.any(clazz.members(), DexDefinition::hasAnyAnnotations)) {
+      return true;
+    }
+
+    // Check that each implemented interface is public.
+    for (DexType interfaceType : clazz.getInterfaces()) {
+      if (clazz.getType().isSamePackage(interfaceType)) {
+        DexClass interfaceClass = appView.definitionFor(interfaceType);
+        if (interfaceClass == null || !interfaceClass.isPublic()) {
+          return true;
+        }
+      }
+    }
+
     // If any members are package private or protected, then their access depends on the package.
     for (DexEncodedMember<?, ?> member : clazz.members()) {
       if (member.getAccessFlags().isPackagePrivateOrProtected()) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/AlwaysSimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/AlwaysSimpleInliningConstraint.java
index 32e01d8..a164607 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/AlwaysSimpleInliningConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/AlwaysSimpleInliningConstraint.java
@@ -30,6 +30,12 @@
   }
 
   @Override
+  public SimpleInliningConstraint fixupAfterRemovingThisParameter(
+      SimpleInliningConstraintFactory factory) {
+    return this;
+  }
+
+  @Override
   public SimpleInliningConstraint rewrittenWithUnboxedArguments(IntList unboxedArgumentIndices) {
     return this;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/BooleanFalseSimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/BooleanFalseSimpleInliningConstraint.java
index a4a6a73..351d51d 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/BooleanFalseSimpleInliningConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/BooleanFalseSimpleInliningConstraint.java
@@ -34,6 +34,13 @@
   }
 
   @Override
+  public SimpleInliningConstraint fixupAfterRemovingThisParameter(
+      SimpleInliningConstraintFactory factory) {
+    assert getArgumentIndex() > 0;
+    return factory.createBooleanFalseConstraint(getArgumentIndex() - 1);
+  }
+
+  @Override
   public SimpleInliningConstraint rewrittenWithUnboxedArguments(IntList unboxedArgumentIndices) {
     return this;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/BooleanTrueSimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/BooleanTrueSimpleInliningConstraint.java
index f69381f..bf3fde3 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/BooleanTrueSimpleInliningConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/BooleanTrueSimpleInliningConstraint.java
@@ -34,6 +34,13 @@
   }
 
   @Override
+  public SimpleInliningConstraint fixupAfterRemovingThisParameter(
+      SimpleInliningConstraintFactory factory) {
+    assert getArgumentIndex() > 0;
+    return factory.createBooleanTrueConstraint(getArgumentIndex() - 1);
+  }
+
+  @Override
   public SimpleInliningConstraint rewrittenWithUnboxedArguments(IntList unboxedArgumentIndices) {
     return this;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/NeverSimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NeverSimpleInliningConstraint.java
index 9407b7b..4568e5f 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/NeverSimpleInliningConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NeverSimpleInliningConstraint.java
@@ -29,6 +29,12 @@
   }
 
   @Override
+  public SimpleInliningConstraint fixupAfterRemovingThisParameter(
+      SimpleInliningConstraintFactory factory) {
+    return this;
+  }
+
+  @Override
   public SimpleInliningConstraint rewrittenWithUnboxedArguments(IntList unboxedArgumentIndices) {
     return this;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/NotNullSimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NotNullSimpleInliningConstraint.java
index ea41ccb..0834cba 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/NotNullSimpleInliningConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NotNullSimpleInliningConstraint.java
@@ -34,6 +34,13 @@
   }
 
   @Override
+  public SimpleInliningConstraint fixupAfterRemovingThisParameter(
+      SimpleInliningConstraintFactory factory) {
+    assert getArgumentIndex() > 0;
+    return factory.createNotNullConstraint(getArgumentIndex() - 1);
+  }
+
+  @Override
   public SimpleInliningConstraint rewrittenWithUnboxedArguments(IntList unboxedArgumentIndices) {
     if (unboxedArgumentIndices.contains(getArgumentIndex())) {
       // TODO(b/176067541): Could be refined to an argument-equals-int constraint.
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/NullSimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NullSimpleInliningConstraint.java
index 76d075d..2dce46e 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/NullSimpleInliningConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NullSimpleInliningConstraint.java
@@ -34,6 +34,13 @@
   }
 
   @Override
+  public SimpleInliningConstraint fixupAfterRemovingThisParameter(
+      SimpleInliningConstraintFactory factory) {
+    assert getArgumentIndex() > 0;
+    return factory.createNullConstraint(getArgumentIndex() - 1);
+  }
+
+  @Override
   public SimpleInliningConstraint rewrittenWithUnboxedArguments(IntList unboxedArgumentIndices) {
     if (unboxedArgumentIndices.contains(getArgumentIndex())) {
       // TODO(b/176067541): Could be refined to an argument-equals-int constraint.
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraint.java
index b411c8b..df108ac 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraint.java
@@ -106,6 +106,9 @@
     return new SimpleInliningConstraintDisjunction(ImmutableList.of(this, other));
   }
 
+  public abstract SimpleInliningConstraint fixupAfterRemovingThisParameter(
+      SimpleInliningConstraintFactory factory);
+
   public abstract SimpleInliningConstraint rewrittenWithUnboxedArguments(
       IntList unboxedArgumentIndices);
 }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintConjunction.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintConjunction.java
index 02a8536..c993b12 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintConjunction.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintConjunction.java
@@ -66,15 +66,25 @@
   }
 
   @Override
+  public SimpleInliningConstraint fixupAfterRemovingThisParameter(
+      SimpleInliningConstraintFactory factory) {
+    List<SimpleInliningConstraint> rewrittenConstraints =
+        ListUtils.mapOrElse(
+            constraints, constraint -> constraint.fixupAfterRemovingThisParameter(factory), null);
+    return rewrittenConstraints != null
+        ? new SimpleInliningConstraintConjunction(rewrittenConstraints)
+        : this;
+  }
+
+  @Override
   public SimpleInliningConstraint rewrittenWithUnboxedArguments(IntList unboxedArgumentIndices) {
     List<SimpleInliningConstraint> rewrittenConstraints =
         ListUtils.mapOrElse(
             constraints,
             constraint -> constraint.rewrittenWithUnboxedArguments(unboxedArgumentIndices),
             null);
-    if (rewrittenConstraints != null) {
-      return new SimpleInliningConstraintConjunction(rewrittenConstraints);
-    }
-    return this;
+    return rewrittenConstraints != null
+        ? new SimpleInliningConstraintConjunction(rewrittenConstraints)
+        : this;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintDisjunction.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintDisjunction.java
index c069f37..a6b418d 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintDisjunction.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintDisjunction.java
@@ -66,15 +66,25 @@
   }
 
   @Override
+  public SimpleInliningConstraint fixupAfterRemovingThisParameter(
+      SimpleInliningConstraintFactory factory) {
+    List<SimpleInliningConstraint> rewrittenConstraints =
+        ListUtils.mapOrElse(
+            constraints, constraint -> constraint.fixupAfterRemovingThisParameter(factory), null);
+    return rewrittenConstraints != null
+        ? new SimpleInliningConstraintDisjunction(rewrittenConstraints)
+        : this;
+  }
+
+  @Override
   public SimpleInliningConstraint rewrittenWithUnboxedArguments(IntList unboxedArgumentIndices) {
     List<SimpleInliningConstraint> rewrittenConstraints =
         ListUtils.mapOrElse(
             constraints,
             constraint -> constraint.rewrittenWithUnboxedArguments(unboxedArgumentIndices),
             null);
-    if (rewrittenConstraints != null) {
-      return new SimpleInliningConstraintDisjunction(rewrittenConstraints);
-    }
-    return this;
+    return rewrittenConstraints != null
+        ? new SimpleInliningConstraintDisjunction(rewrittenConstraints)
+        : this;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Invoke.java b/src/main/java/com/android/tools/r8/ir/code/Invoke.java
index 02c1ad0..27f9d4b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Invoke.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Invoke.java
@@ -178,6 +178,7 @@
   }
 
   public Value getArgument(int index) {
+    assert index < arguments().size();
     return arguments().get(index);
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java b/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java
index 39f52cb..6a83961 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java
@@ -269,6 +269,6 @@
       }
     }
 
-    return optimizationInfo.mayHaveSideEffects();
+    return optimizationInfo.mayHaveSideEffects(this, appView.options());
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java b/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
index 1b3aef3..9313b59 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
@@ -216,11 +216,11 @@
     }
 
     // Verify that the target method does not have side-effects.
-    if (appViewWithLiveness.appInfo().noSideEffects.containsKey(singleTarget.getReference())) {
+    if (appViewWithLiveness.appInfo().isAssumeNoSideEffectsMethod(singleTarget)) {
       return false;
     }
 
-    if (singleTarget.getDefinition().getOptimizationInfo().mayHaveSideEffects()) {
+    if (singleTarget.getOptimizationInfo().mayHaveSideEffects(this, appView.options())) {
       return true;
     }
 
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 f68c904..3f52f3d 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
@@ -894,6 +894,9 @@
     if (appView.options().protoShrinking().enableRemoveProtoEnumSwitchMap()) {
       appView.protoShrinker().protoEnumSwitchMapRemover.updateVisibleStaticFieldValues();
     }
+    if (enumUnboxer != null) {
+      enumUnboxer.updateEnumUnboxingCandidatesInfo();
+    }
     assert delayedOptimizationFeedback.noUpdatesLeft();
     onWaveDoneActions.forEach(com.android.tools.r8.utils.Action::execute);
     onWaveDoneActions = null;
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 021ffa2..b287221 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
@@ -199,6 +199,12 @@
         initializeStreamMethodProviders(factory);
       }
 
+      if (appView.rewritePrefix.hasRewrittenType(factory.supplierType, appView)) {
+        // TODO(b/191188594): Consider adding the Objects method from R here, or instead
+        //  rely on desugared library to support them.
+        initializeObjectsMethodProviders(factory);
+      }
+
       // These are currently not implemented at any API level in Android.
       initializeJava9MethodProviders(factory);
       initializeJava10MethodProviders(factory);
@@ -1347,6 +1353,19 @@
           new MethodGenerator(method, BackportedMethods::StreamMethods_ofNullable, "ofNullable"));
     }
 
+    private void initializeObjectsMethodProviders(DexItemFactory factory) {
+      // Objects
+      DexType type = factory.objectsType;
+
+      // Objects.requireNonNull(Object, Supplier)
+      DexString name = factory.createString("requireNonNull");
+      DexProto proto =
+          factory.createProto(factory.objectType, factory.objectType, factory.supplierType);
+      DexMethod method = factory.createMethod(type, proto, name);
+      addProvider(
+          new MethodGenerator(method, BackportedMethods::ObjectsMethods_requireNonNullSupplier));
+    }
+
     private void addProvider(MethodProvider generator) {
       if (appView.options().desugaredLibraryConfiguration.isSupported(generator.method, appView)) {
         // TODO(b/174453232): Remove this after the configuration file format has bee updated
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryAPIConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryAPIConverter.java
index 6394d39..5fc1537 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryAPIConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryAPIConverter.java
@@ -107,7 +107,7 @@
 
   public void desugar(IRCode code) {
 
-    if (wrapperSynthesizor.hasSynthesized(code.method().getHolderType())) {
+    if (wrapperSynthesizor.isSyntheticWrapper(code.method().getHolderType())) {
       return;
     }
 
@@ -310,7 +310,7 @@
     SortedProgramMethodSet callbacks = generateCallbackMethods();
     irConverter.processMethodsConcurrently(callbacks, executorService);
     if (appView.options().isDesugaredLibraryCompilation()) {
-      wrapperSynthesizor.finalizeWrappersForL8(builder, irConverter, executorService);
+      wrapperSynthesizor.finalizeWrappersForL8();
     }
   }
 
@@ -337,10 +337,8 @@
     return allCallbackMethods;
   }
 
-  public void synthesizeWrappers(
-      Map<DexType, DexClasspathClass> synthesizedWrappers,
-      Consumer<DexClasspathClass> synthesizedCallback) {
-    wrapperSynthesizor.synthesizeWrappersForClasspath(synthesizedWrappers, synthesizedCallback);
+  public void synthesizeWrappers(Consumer<DexClasspathClass> synthesizedCallback) {
+    wrapperSynthesizor.synthesizeWrappersForClasspath(synthesizedCallback);
   }
 
   private ProgramMethod generateCallbackMethod(
@@ -409,11 +407,11 @@
     }
     DexType returnType = invokedMethod.proto.returnType;
     if (appView.rewritePrefix.hasRewrittenType(returnType, appView) && canConvert(returnType)) {
-      registerConversionWrappers(returnType, vivifiedTypeFor(returnType, appView));
+      registerConversionWrappers(returnType);
     }
     for (DexType argType : invokedMethod.proto.parameters.values) {
       if (appView.rewritePrefix.hasRewrittenType(argType, appView) && canConvert(argType)) {
-        registerConversionWrappers(argType, argType);
+        registerConversionWrappers(argType);
       }
     }
   }
@@ -549,7 +547,7 @@
 
   private Instruction createParameterConversion(
       IRCode code, DexType argType, DexType argVivifiedType, Value inValue) {
-    DexMethod conversionMethod = createConversionMethod(argType, argType, argVivifiedType);
+    DexMethod conversionMethod = ensureConversionMethod(argType, argType, argVivifiedType);
     // The value is null only if the input is null.
     Value convertedValue =
         createConversionValue(code, inValue.getType().nullability(), argVivifiedType, null);
@@ -558,7 +556,7 @@
 
   private Instruction createReturnConversionAndReplaceUses(
       IRCode code, InvokeMethod invokeMethod, DexType returnType, DexType returnVivifiedType) {
-    DexMethod conversionMethod = createConversionMethod(returnType, returnVivifiedType, returnType);
+    DexMethod conversionMethod = ensureConversionMethod(returnType, returnVivifiedType, returnType);
     Value outValue = invokeMethod.outValue();
     Value convertedValue =
         createConversionValue(code, Nullability.maybeNull(), returnType, outValue.getLocalInfo());
@@ -569,17 +567,13 @@
     return new InvokeStatic(conversionMethod, convertedValue, Collections.singletonList(outValue));
   }
 
-  private void registerConversionWrappers(DexType type, DexType srcType) {
+  private void registerConversionWrappers(DexType type) {
     if (appView.options().desugaredLibraryConfiguration.getCustomConversions().get(type) == null) {
-      if (type == srcType) {
-        wrapperSynthesizor.getTypeWrapper(type);
-      } else {
-        wrapperSynthesizor.getVivifiedTypeWrapper(type);
-      }
+      wrapperSynthesizor.registerWrapper(type);
     }
   }
 
-  public DexMethod createConversionMethod(DexType type, DexType srcType, DexType destType) {
+  public DexMethod ensureConversionMethod(DexType type, DexType srcType, DexType destType) {
     // ConversionType holds the methods "rewrittenType convert(type)" and the other way around.
     // But everything is going to be rewritten, so we need to use vivifiedType and type".
     DexType conversionHolder =
@@ -587,8 +581,8 @@
     if (conversionHolder == null) {
       conversionHolder =
           type == srcType
-              ? wrapperSynthesizor.getTypeWrapper(type)
-              : wrapperSynthesizor.getVivifiedTypeWrapper(type);
+              ? wrapperSynthesizor.ensureTypeWrapper(type)
+              : wrapperSynthesizor.ensureVivifiedTypeWrapper(type);
     }
     assert conversionHolder != null;
     return factory.createMethod(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java
index a0153a0..eb354b0 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java
@@ -367,14 +367,6 @@
   }
 
   private InvokeRetargetingResult computeRetargetLibraryMember(DexMethod method) {
-    Map<DexType, DexType> backportCoreLibraryMembers =
-        appView.options().desugaredLibraryConfiguration.getBackportCoreLibraryMember();
-    if (backportCoreLibraryMembers.containsKey(method.holder)) {
-      DexType newHolder = backportCoreLibraryMembers.get(method.holder);
-      DexMethod newMethod =
-          appView.dexItemFactory().createMethod(newHolder, method.proto, method.name);
-      return InvokeRetargetingResult.createInvokeRetargetingResult(newMethod);
-    }
     DexClassAndMethod emulatedMethod = emulatedDispatchMethods.get(method);
     if (emulatedMethod != null) {
       assert !emulatedMethod.getAccessFlags().isStatic();
@@ -517,7 +509,12 @@
       List<DexClassAndMethod> found = new ArrayList<>();
       clazz.forEachClassMethodMatching(
           definition -> definition.getName() == methodName, found::add);
-      assert !found.isEmpty() : "Should have found a method (library specifications).";
+      assert !found.isEmpty()
+          : "Should have found a method (library specifications) for "
+              + clazz.toSourceString()
+              + "."
+              + methodName
+              + ". Maybe the library used for the compilation should be newer.";
       return found;
     }
   }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java
index e0c6d41..00c8bff 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java
@@ -4,16 +4,14 @@
 
 package com.android.tools.r8.ir.desugar;
 
-import com.android.tools.r8.ProgramResource.Kind;
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
-import com.android.tools.r8.graph.ClassAccessFlags;
-import com.android.tools.r8.graph.ClassKind;
+import com.android.tools.r8.graph.ClasspathOrLibraryClass;
 import com.android.tools.r8.graph.Code;
 import com.android.tools.r8.graph.DexAnnotationSet;
-import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexClasspathClass;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
@@ -21,38 +19,33 @@
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.DexTypeList;
 import com.android.tools.r8.graph.FieldAccessFlags;
-import com.android.tools.r8.graph.GenericSignature.ClassSignature;
 import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
 import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.ParameterAnnotationsList;
-import com.android.tools.r8.ir.conversion.IRConverter;
+import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APIConverterConstructorCfCodeProvider;
 import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APIConverterThrowRuntimeExceptionCfCodeProvider;
 import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APIConverterVivifiedWrapperCfCodeProvider;
 import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APIConverterWrapperCfCodeProvider;
 import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APIConverterWrapperConversionCfCodeProvider;
-import com.android.tools.r8.origin.SynthesizedOrigin;
+import com.android.tools.r8.synthesis.SyntheticClassBuilder;
+import com.android.tools.r8.synthesis.SyntheticMethodBuilder;
+import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
+import com.android.tools.r8.utils.BooleanBox;
 import com.android.tools.r8.utils.StringDiagnostic;
 import com.google.common.collect.Sets;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.Collections;
-import java.util.IdentityHashMap;
+import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.function.BiConsumer;
 import java.util.function.Consumer;
+import java.util.function.Function;
 
 // I am responsible for the generation of wrappers used to call library APIs when desugaring
 // libraries. Wrappers can be both ways, wrapping the desugarType as a type, or the type as
@@ -99,16 +92,8 @@
 //   }
 public class DesugaredLibraryWrapperSynthesizer {
 
-  public static final String WRAPPER_PACKAGE = "wrappers/";
-  public static final String WRAPPER_PREFIX = "$r8$wrapper$";
-  public static final String TYPE_WRAPPER_SUFFIX = "$-WRP";
-  public static final String VIVIFIED_TYPE_WRAPPER_SUFFIX = "$-V-WRP";
-
   private final AppView<?> appView;
-  private final String dexWrapperPrefixString;
-  private final DexString dexWrapperPrefixDexString;
-  private final Map<DexType, DexType> typeWrappers = new ConcurrentHashMap<>();
-  private final Map<DexType, DexType> vivifiedTypeWrappers = new ConcurrentHashMap<>();
+  private final Set<DexType> wrappersToGenerate = Sets.newConcurrentHashSet();
   // The invalidWrappers are wrappers with incorrect behavior because of final methods that could
   // not be overridden. Such wrappers are awful because the runtime behavior is undefined and does
   // not raise explicit errors. So we register them here and conversion methods for such wrappers
@@ -120,55 +105,29 @@
   DesugaredLibraryWrapperSynthesizer(AppView<?> appView, DesugaredLibraryAPIConverter converter) {
     this.appView = appView;
     this.factory = appView.dexItemFactory();
-    dexWrapperPrefixString =
-        "L"
-            + appView
-                .options()
-                .desugaredLibraryConfiguration
-                .getSynthesizedLibraryClassesPackagePrefix()
-            + WRAPPER_PACKAGE
-            + WRAPPER_PREFIX;
-    dexWrapperPrefixDexString = factory.createString(dexWrapperPrefixString);
     this.converter = converter;
   }
 
-  boolean hasSynthesized(DexType type) {
-    return type.descriptor.startsWith(dexWrapperPrefixDexString);
+  public boolean isSyntheticWrapper(DexType type) {
+    return appView.getSyntheticItems().isSyntheticOfKind(type, SyntheticKind.WRAPPER)
+        || appView.getSyntheticItems().isSyntheticOfKind(type, SyntheticKind.VIVIFIED_WRAPPER);
   }
 
   boolean canGenerateWrapper(DexType type) {
     return appView.options().desugaredLibraryConfiguration.getWrapperConversions().contains(type);
   }
 
-  DexType getTypeWrapper(DexType type) {
-    // Force create the reverse wrapper.
-    getWrapper(type, VIVIFIED_TYPE_WRAPPER_SUFFIX, vivifiedTypeWrappers);
-    return getWrapper(type, TYPE_WRAPPER_SUFFIX, typeWrappers);
+  DexType ensureTypeWrapper(DexType type) {
+    return ensureWrappers(type).getWrapper().type;
   }
 
-  DexType getVivifiedTypeWrapper(DexType type) {
-    // Force create the reverse wrapper.
-    getWrapper(type, TYPE_WRAPPER_SUFFIX, typeWrappers);
-    return getWrapper(type, VIVIFIED_TYPE_WRAPPER_SUFFIX, vivifiedTypeWrappers);
+  DexType ensureVivifiedTypeWrapper(DexType type) {
+    return ensureWrappers(type).getVivifiedWrapper().type;
   }
 
-  private DexType createWrapperType(DexType type, String suffix) {
-    return factory.createType(
-        dexWrapperPrefixString + type.toString().replace('.', '$') + suffix + ";");
-  }
-
-  private DexType getWrapper(DexType type, String suffix, Map<DexType, DexType> wrappers) {
-    assert !type.toString().startsWith(DesugaredLibraryAPIConverter.VIVIFIED_PREFIX);
-    return wrappers.computeIfAbsent(
-        type,
-        t -> {
-          assert canGenerateWrapper(type) : type;
-          DexType wrapperType = createWrapperType(type, suffix);
-          assert converter.canGenerateWrappersAndCallbacks()
-                  || appView.definitionFor(wrapperType).isClasspathClass()
-              : "Wrapper " + wrapperType + " should have been generated in the enqueuer.";
-          return wrapperType;
-        });
+  public void registerWrapper(DexType type) {
+    wrappersToGenerate.add(type);
+    assert getValidClassToWrap(type) != null;
   }
 
   private DexClass getValidClassToWrap(DexType type) {
@@ -184,68 +143,242 @@
     return DesugaredLibraryAPIConverter.vivifiedTypeFor(type, appView);
   }
 
-  private DexClass generateTypeWrapper(
-      ClassKind<?> classKind, DexClass dexClass, DexType typeWrapperType) {
-    DexType type = dexClass.type;
-    DexEncodedField wrapperField = synthesizeWrappedValueEncodedField(typeWrapperType, type);
-    return synthesizeWrapper(
-        classKind,
-        vivifiedTypeFor(type),
-        dexClass,
-        synthesizeVirtualMethodsForTypeWrapper(dexClass, wrapperField),
-        generateTypeConversion(type, typeWrapperType),
-        wrapperField);
+  static class Wrappers {
+    private final DexClass wrapper;
+    private final DexClass vivifiedWrapper;
+
+    Wrappers(DexClass wrapper, DexClass vivifiedWrapper) {
+      this.wrapper = wrapper;
+      this.vivifiedWrapper = vivifiedWrapper;
+    }
+
+    public DexClass getWrapper() {
+      return wrapper;
+    }
+
+    public DexClass getVivifiedWrapper() {
+      return vivifiedWrapper;
+    }
   }
 
-  private DexClass generateVivifiedTypeWrapper(
-      ClassKind<?> classKind, DexClass dexClass, DexType vivifiedTypeWrapperType) {
-    DexType type = dexClass.type;
-    DexEncodedField wrapperField =
-        synthesizeWrappedValueEncodedField(vivifiedTypeWrapperType, vivifiedTypeFor(type));
-    return synthesizeWrapper(
-        classKind,
-        type,
-        dexClass,
-        synthesizeVirtualMethodsForVivifiedTypeWrapper(dexClass, wrapperField),
-        generateVivifiedTypeConversion(type, vivifiedTypeWrapperType),
-        wrapperField);
+  private Wrappers ensureWrappers(DexType type) {
+    assert canGenerateWrapper(type) : type;
+    DexClass dexClass = getValidClassToWrap(type);
+    return ensureWrappers(dexClass, ignored -> {});
   }
 
-  private DexClass synthesizeWrapper(
-      ClassKind<?> classKind,
+  private Wrappers ensureWrappers(DexClass context, Consumer<DexClasspathClass> creationCallback) {
+    DexType type = context.type;
+    DexClass wrapper;
+    DexClass vivifiedWrapper;
+    if (context.isProgramClass()) {
+      assert appView.options().isDesugaredLibraryCompilation();
+      DexProgramClass programContext = context.asProgramClass();
+      wrapper =
+          ensureProgramWrapper(
+              SyntheticKind.WRAPPER,
+              vivifiedTypeFor(type),
+              type,
+              programContext,
+              wrapperField -> synthesizeVirtualMethodsForTypeWrapper(programContext, wrapperField));
+      vivifiedWrapper =
+          ensureProgramWrapper(
+              SyntheticKind.VIVIFIED_WRAPPER,
+              type,
+              vivifiedTypeFor(type),
+              programContext,
+              wrapperField ->
+                  synthesizeVirtualMethodsForVivifiedTypeWrapper(programContext, wrapperField));
+      DexField wrapperField = getWrapperUniqueField(wrapper);
+      DexField vivifiedWrapperField = getWrapperUniqueField(vivifiedWrapper);
+      ensureProgramConversionMethod(
+          SyntheticKind.WRAPPER, programContext, wrapperField, vivifiedWrapperField);
+      ensureProgramConversionMethod(
+          SyntheticKind.VIVIFIED_WRAPPER, programContext, vivifiedWrapperField, wrapperField);
+    } else {
+      assert context.isNotProgramClass();
+      ClasspathOrLibraryClass classpathOrLibraryContext = context.asClasspathOrLibraryClass();
+      wrapper =
+          ensureClasspathWrapper(
+              SyntheticKind.WRAPPER,
+              vivifiedTypeFor(type),
+              type,
+              classpathOrLibraryContext,
+              creationCallback,
+              wrapperField -> synthesizeVirtualMethodsForTypeWrapper(context, wrapperField));
+      vivifiedWrapper =
+          ensureClasspathWrapper(
+              SyntheticKind.VIVIFIED_WRAPPER,
+              type,
+              vivifiedTypeFor(type),
+              classpathOrLibraryContext,
+              creationCallback,
+              wrapperField ->
+                  synthesizeVirtualMethodsForVivifiedTypeWrapper(context, wrapperField));
+      DexField wrapperField = getWrapperUniqueField(wrapper);
+      DexField vivifiedWrapperField = getWrapperUniqueField(vivifiedWrapper);
+      ensureClasspathConversionMethod(
+          SyntheticKind.WRAPPER, classpathOrLibraryContext, wrapperField, vivifiedWrapperField);
+      ensureClasspathConversionMethod(
+          SyntheticKind.VIVIFIED_WRAPPER,
+          classpathOrLibraryContext,
+          vivifiedWrapperField,
+          wrapperField);
+    }
+    return new Wrappers(wrapper, vivifiedWrapper);
+  }
+
+  private DexEncodedField getWrapperUniqueEncodedField(DexClass wrapper) {
+    assert wrapper.instanceFields().size() == 1;
+    return wrapper.instanceFields().get(0);
+  }
+
+  private DexField getWrapperUniqueField(DexClass wrapper) {
+    return getWrapperUniqueEncodedField(wrapper).getReference();
+  }
+
+  private DexProgramClass ensureProgramWrapper(
+      SyntheticKind kind,
       DexType wrappingType,
+      DexType wrappedType,
+      DexProgramClass programContext,
+      Function<DexEncodedField, DexEncodedMethod[]> virtualMethodProvider) {
+    return appView
+        .getSyntheticItems()
+        .ensureFixedClass(
+            kind,
+            programContext,
+            appView,
+            builder -> buildWrapper(wrappingType, wrappedType, programContext, builder),
+            // The creation of virtual methods may require new wrappers, this needs to happen
+            // once the wrapper is created to avoid infinite recursion.
+            wrapper ->
+                wrapper.setVirtualMethods(
+                    virtualMethodProvider.apply(getWrapperUniqueEncodedField(wrapper))));
+  }
+
+  private DexClasspathClass ensureClasspathWrapper(
+      SyntheticKind kind,
+      DexType wrappingType,
+      DexType wrappedType,
+      ClasspathOrLibraryClass classpathOrLibraryContext,
+      Consumer<DexClasspathClass> creationCallback,
+      Function<DexEncodedField, DexEncodedMethod[]> virtualMethodProvider) {
+    return appView
+        .getSyntheticItems()
+        .ensureFixedClasspathClass(
+            kind,
+            classpathOrLibraryContext,
+            appView,
+            builder ->
+                buildWrapper(
+                    wrappingType, wrappedType, classpathOrLibraryContext.asDexClass(), builder),
+            // The creation of virtual methods may require new wrappers, this needs to happen
+            // once the wrapper is created to avoid infinite recursion.
+            wrapper -> {
+              wrapper.setVirtualMethods(
+                  virtualMethodProvider.apply(getWrapperUniqueEncodedField(wrapper)));
+              creationCallback.accept(wrapper);
+            });
+  }
+
+  private ProgramMethod ensureProgramConversionMethod(
+      SyntheticKind kind,
+      DexProgramClass context,
+      DexField wrapperField,
+      DexField reverseWrapperField) {
+    return appView
+        .getSyntheticItems()
+        .ensureFixedClassMethod(
+            factory.convertMethodName,
+            factory.createProto(reverseWrapperField.type, wrapperField.type),
+            kind,
+            context,
+            appView,
+            ignored -> {},
+            methodBuilder ->
+                buildConversionMethod(
+                    methodBuilder, wrapperField, reverseWrapperField, context.type));
+  }
+
+  private DexClassAndMethod ensureClasspathConversionMethod(
+      SyntheticKind kind,
+      ClasspathOrLibraryClass context,
+      DexField wrapperField,
+      DexField reverseWrapperField) {
+    return appView
+        .getSyntheticItems()
+        .ensureFixedClasspathClassMethod(
+            factory.convertMethodName,
+            factory.createProto(reverseWrapperField.type, wrapperField.type),
+            kind,
+            context,
+            appView,
+            ignored -> {},
+            methodBuilder ->
+                buildConversionMethod(
+                    methodBuilder, wrapperField, reverseWrapperField, context.getType()));
+  }
+
+  private void buildConversionMethod(
+      SyntheticMethodBuilder methodBuilder,
+      DexField wrapperField,
+      DexField reverseWrapperField,
+      DexType reportingType) {
+    CfCode cfCode;
+    if (invalidWrappers.contains(wrapperField.holder)) {
+      cfCode =
+          new APIConverterThrowRuntimeExceptionCfCodeProvider(
+                  appView,
+                  factory.createString(
+                      "Unsupported conversion for "
+                          + reportingType
+                          + ". See compilation time warnings for more details."),
+                  wrapperField.holder)
+              .generateCfCode();
+    } else {
+      cfCode =
+          new APIConverterWrapperConversionCfCodeProvider(
+                  appView, reverseWrapperField, wrapperField)
+              .generateCfCode();
+    }
+    methodBuilder
+        .setAccessFlags(
+            MethodAccessFlags.fromCfAccessFlags(
+                Constants.ACC_SYNTHETIC | Constants.ACC_STATIC | Constants.ACC_PUBLIC, false))
+        .setCode(methodSignature -> cfCode);
+  }
+
+  private void buildWrapper(
+      DexType wrappingType,
+      DexType wrappedType,
       DexClass clazz,
-      DexEncodedMethod[] virtualMethods,
-      DexEncodedMethod conversionMethod,
-      DexEncodedField wrapperField) {
+      SyntheticClassBuilder<?, ?> builder) {
     boolean isItf = clazz.isInterface();
     DexType superType = isItf ? factory.objectType : wrappingType;
-    DexTypeList interfaces =
-        isItf ? new DexTypeList(new DexType[] {wrappingType}) : DexTypeList.empty();
-    return classKind.create(
-        wrapperField.getHolderType(),
-        Kind.CF,
-        new SynthesizedOrigin("Desugared library API Converter", getClass()),
-        ClassAccessFlags.fromSharedAccessFlags(
-            Constants.ACC_FINAL | Constants.ACC_SYNTHETIC | Constants.ACC_PUBLIC),
-        superType,
-        interfaces,
-        clazz.sourceFile,
-        null,
-        Collections.emptyList(),
-        null,
-        Collections.emptyList(),
-        ClassSignature.noSignature(),
-        DexAnnotationSet.empty(),
-        DexEncodedField.EMPTY_ARRAY, // No static fields.
-        new DexEncodedField[] {wrapperField},
-        new DexEncodedMethod[] {
-          synthesizeConstructor(wrapperField.getReference()), conversionMethod
-        },
-        virtualMethods,
-        factory.getSkipNameValidationForTesting(),
-        DexProgramClass::checksumFromType,
-        null);
+    List<DexType> interfaces =
+        isItf ? Collections.singletonList(wrappingType) : Collections.emptyList();
+    DexEncodedField wrapperField =
+        synthesizeWrappedValueEncodedField(builder.getType(), wrappedType);
+    builder
+        .setInterfaces(interfaces)
+        .setSuperType(superType)
+        .setInstanceFields(Collections.singletonList(wrapperField))
+        .addMethod(methodBuilder -> buildWrapperConstructor(wrapperField, methodBuilder));
+  }
+
+  private void buildWrapperConstructor(
+      DexEncodedField wrappedValueField, SyntheticMethodBuilder methodBuilder) {
+    methodBuilder
+        .setName(factory.constructorMethodName)
+        .setProto(factory.createProto(factory.voidType, wrappedValueField.getType()))
+        .setAccessFlags(
+            MethodAccessFlags.fromCfAccessFlags(
+                Constants.ACC_PRIVATE | Constants.ACC_SYNTHETIC, true))
+        .setCode(
+            codeSynthesizor ->
+                new APIConverterConstructorCfCodeProvider(appView, wrappedValueField.getReference())
+                    .generateCfCode());
   }
 
   private DexEncodedMethod[] synthesizeVirtualMethodsForVivifiedTypeWrapper(
@@ -441,166 +574,33 @@
         field, fieldAccessFlags, FieldTypeSignature.noSignature(), DexAnnotationSet.empty(), null);
   }
 
-  private DexEncodedMethod synthesizeConstructor(DexField field) {
-    DexMethod method =
-        factory.createMethod(
-            field.holder,
-            factory.createProto(factory.voidType, field.type),
-            factory.constructorMethodName);
-    return newSynthesizedMethod(
-        method,
-        Constants.ACC_PRIVATE | Constants.ACC_SYNTHETIC,
-        true,
-        new APIConverterConstructorCfCodeProvider(appView, field).generateCfCode());
-  }
-
-  private DexEncodedMethod newSynthesizedMethod(
-      DexMethod methodToInstall, int flags, boolean constructor, Code code) {
-    MethodAccessFlags accessFlags = MethodAccessFlags.fromSharedAccessFlags(flags, constructor);
-    return new DexEncodedMethod(
-        methodToInstall,
-        accessFlags,
-        MethodTypeSignature.noSignature(),
-        DexAnnotationSet.empty(),
-        ParameterAnnotationsList.empty(),
-        code,
-        true);
-  }
-
-  void finalizeWrappersForL8(
-      DexApplication.Builder<?> builder, IRConverter irConverter, ExecutorService executorService)
-      throws ExecutionException {
-    List<DexProgramClass> synthesizedWrappers = synthesizeWrappers();
-    registerAndProcessWrappers(builder, irConverter, executorService, synthesizedWrappers);
-  }
-
-  private List<DexProgramClass> synthesizeWrappers() {
+  void finalizeWrappersForL8() {
     DesugaredLibraryConfiguration conf = appView.options().desugaredLibraryConfiguration;
     for (DexType type : conf.getWrapperConversions()) {
       assert !conf.getCustomConversions().containsKey(type);
-      getTypeWrapper(type);
-    }
-    Map<DexType, DexClass> synthesizedWrappers = new IdentityHashMap<>();
-    List<DexProgramClass> additions = new ArrayList<>();
-    int total = typeWrappers.size() + vivifiedTypeWrappers.size();
-    generateWrappers(
-        ClassKind.PROGRAM,
-        synthesizedWrappers.keySet(),
-        (type, wrapper) -> {
-          synthesizedWrappers.put(type, wrapper);
-          additions.add(wrapper.asProgramClass());
-        });
-    assert total == typeWrappers.size() + vivifiedTypeWrappers.size() : "unexpected additions";
-    return additions;
-  }
-
-  void synthesizeWrappersForClasspath(
-      Map<DexType, DexClasspathClass> synthesizedWrappers,
-      Consumer<DexClasspathClass> synthesizedCallback) {
-    generateWrappers(
-        ClassKind.CLASSPATH,
-        synthesizedWrappers.keySet(),
-        (type, wrapper) -> {
-          DexClasspathClass classpathWrapper = wrapper.asClasspathClass();
-          synthesizedWrappers.put(type, classpathWrapper);
-          synthesizedCallback.accept(classpathWrapper);
-        });
-  }
-
-  private void generateWrappers(
-      ClassKind<?> classKind,
-      Set<DexType> synthesized,
-      BiConsumer<DexType, DexClass> generatedCallback) {
-    while (synthesized.size() != typeWrappers.size() + vivifiedTypeWrappers.size()) {
-      for (DexType type : typeWrappers.keySet()) {
-        DexType typeWrapperType = typeWrappers.get(type);
-        if (!synthesized.contains(typeWrapperType)) {
-          DexClass wrapper =
-              generateTypeWrapper(classKind, getValidClassToWrap(type), typeWrapperType);
-          generatedCallback.accept(typeWrapperType, wrapper);
-        }
-      }
-      for (DexType type : vivifiedTypeWrappers.keySet()) {
-        DexType vivifiedTypeWrapperType = vivifiedTypeWrappers.get(type);
-        if (!synthesized.contains(vivifiedTypeWrapperType)) {
-          DexClass wrapper =
-              generateVivifiedTypeWrapper(
-                  classKind, getValidClassToWrap(type), vivifiedTypeWrapperType);
-          generatedCallback.accept(vivifiedTypeWrapperType, wrapper);
-        }
+      DexClass validClassToWrap = getValidClassToWrap(type);
+      // In broken set-ups we can end up having a json files containing wrappers of non desugared
+      // classes. Such wrappers are not required since the class won't be rewritten.
+      if (validClassToWrap.isProgramClass()) {
+        ensureWrappers(validClassToWrap, ignored -> {});
       }
     }
   }
 
-  private void registerAndProcessWrappers(
-      DexApplication.Builder<?> builder,
-      IRConverter irConverter,
-      ExecutorService executorService,
-      Collection<DexProgramClass> wrappers)
-      throws ExecutionException {
-    for (DexProgramClass wrapper : wrappers) {
-      builder.addSynthesizedClass(wrapper);
-      appView.appInfo().addSynthesizedClassForLibraryDesugaring(wrapper);
+  void synthesizeWrappersForClasspath(Consumer<DexClasspathClass> synthesizedCallback) {
+    BooleanBox changed = new BooleanBox(true);
+    while (changed.get()) {
+      changed.set(false);
+      Set<DexType> copy = new HashSet<>(wrappersToGenerate);
+      for (DexType type : copy) {
+        DexClass validClassToWrap = getValidClassToWrap(type);
+        ensureWrappers(
+            validClassToWrap,
+            classpathWrapper -> {
+              changed.set(true);
+              synthesizedCallback.accept(classpathWrapper);
+            });
+      }
     }
-    irConverter.optimizeSynthesizedClasses(wrappers, executorService);
-  }
-
-  private DexEncodedMethod generateTypeConversion(DexType type, DexType typeWrapperType) {
-    DexType reverse = vivifiedTypeWrappers.get(type);
-    assert reverse != null;
-    return synthesizeConversionMethod(
-        typeWrapperType,
-        type,
-        type,
-        vivifiedTypeFor(type),
-        wrappedValueField(reverse, vivifiedTypeFor(type)));
-  }
-
-  private DexEncodedMethod generateVivifiedTypeConversion(
-      DexType type, DexType vivifiedTypeWrapperType) {
-    DexType reverse = typeWrappers.get(type);
-    assert reverse != null;
-    return synthesizeConversionMethod(
-        vivifiedTypeWrapperType,
-        type,
-        vivifiedTypeFor(type),
-        type,
-        wrappedValueField(reverse, type));
-  }
-
-  private DexEncodedMethod synthesizeConversionMethod(
-      DexType holder,
-      DexType type,
-      DexType argType,
-      DexType returnType,
-      DexField reverseField) {
-    DexMethod method =
-        factory.createMethod(
-            holder, factory.createProto(returnType, argType), factory.convertMethodName);
-    CfCode cfCode;
-    if (invalidWrappers.contains(holder)) {
-      cfCode =
-          new APIConverterThrowRuntimeExceptionCfCodeProvider(
-                  appView,
-                  factory.createString(
-                      "Unsupported conversion for "
-                          + type
-                          + ". See compilation time warnings for more details."),
-                  holder)
-              .generateCfCode();
-    } else {
-      cfCode =
-          new APIConverterWrapperConversionCfCodeProvider(
-                  appView,
-                  argType,
-                  reverseField,
-                  factory.createField(holder, returnType, factory.wrapperFieldName))
-              .generateCfCode();
-    }
-    return newSynthesizedMethod(
-        method,
-        Constants.ACC_SYNTHETIC | Constants.ACC_STATIC | Constants.ACC_PUBLIC,
-        false,
-        cfCode);
   }
 }
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 bb345a4..ba7cbc0b 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
@@ -276,6 +276,8 @@
                       && desugaring instanceof InterfaceMethodRewriter)
               : "Desugaring of "
                   + instruction
+                  + " in method "
+                  + context.toSourceString()
                   + " has multiple matches: "
                   + appliedDesugaring.getClass().getName()
                   + " and "
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
index 3f7a705..9413849 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
@@ -1,4 +1,4 @@
-// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// 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.
 
@@ -14,6 +14,7 @@
 import com.android.tools.r8.cf.code.CfArrayStore;
 import com.android.tools.r8.cf.code.CfCheckCast;
 import com.android.tools.r8.cf.code.CfCmp;
+import com.android.tools.r8.cf.code.CfConstNull;
 import com.android.tools.r8.cf.code.CfConstNumber;
 import com.android.tools.r8.cf.code.CfConstString;
 import com.android.tools.r8.cf.code.CfFrame;
@@ -6803,6 +6804,89 @@
         ImmutableList.of());
   }
 
+  public static CfCode ObjectsMethods_requireNonNullSupplier(
+      InternalOptions options, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    CfLabel label5 = new CfLabel();
+    CfLabel label6 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        3,
+        3,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfIf(If.Type.NE, ValueType.OBJECT, label5),
+            label1,
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfIf(If.Type.EQ, ValueType.OBJECT, label2),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfInvoke(
+                185,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/function/Supplier;"),
+                    options.itemFactory.createProto(options.itemFactory.objectType),
+                    options.itemFactory.createString("get")),
+                true),
+            new CfCheckCast(options.itemFactory.stringType),
+            new CfGoto(label3),
+            label2,
+            new CfFrame(
+                new Int2ReferenceAVLTreeMap<>(
+                    new int[] {0, 1},
+                    new FrameType[] {
+                      FrameType.initialized(options.itemFactory.objectType),
+                      FrameType.initialized(
+                          options.itemFactory.createType("Ljava/util/function/Supplier;"))
+                    }),
+                new ArrayDeque<>(Arrays.asList())),
+            new CfConstNull(),
+            label3,
+            new CfFrame(
+                new Int2ReferenceAVLTreeMap<>(
+                    new int[] {0, 1},
+                    new FrameType[] {
+                      FrameType.initialized(options.itemFactory.objectType),
+                      FrameType.initialized(
+                          options.itemFactory.createType("Ljava/util/function/Supplier;"))
+                    }),
+                new ArrayDeque<>(
+                    Arrays.asList(FrameType.initialized(options.itemFactory.stringType)))),
+            new CfStore(ValueType.OBJECT, 2),
+            label4,
+            new CfNew(options.itemFactory.createType("Ljava/lang/NullPointerException;")),
+            new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+            new CfLoad(ValueType.OBJECT, 2),
+            new CfInvoke(
+                183,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/lang/NullPointerException;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.voidType, options.itemFactory.stringType),
+                    options.itemFactory.createString("<init>")),
+                false),
+            new CfThrow(),
+            label5,
+            new CfFrame(
+                new Int2ReferenceAVLTreeMap<>(
+                    new int[] {0, 1},
+                    new FrameType[] {
+                      FrameType.initialized(options.itemFactory.objectType),
+                      FrameType.initialized(
+                          options.itemFactory.createType("Ljava/util/function/Supplier;"))
+                    }),
+                new ArrayDeque<>(Arrays.asList())),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfReturn(ValueType.OBJECT),
+            label6),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
   public static CfCode ObjectsMethods_toString(InternalOptions options, DexMethod method) {
     CfLabel label0 = new CfLabel();
     CfLabel label1 = new CfLabel();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
index 4c784f0..3381ece 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
@@ -4,9 +4,15 @@
 
 package com.android.tools.r8.ir.desugar.itf;
 
+import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.cf.code.CfNew;
+import com.android.tools.r8.cf.code.CfStackInstruction;
+import com.android.tools.r8.cf.code.CfStackInstruction.Opcode;
+import com.android.tools.r8.cf.code.CfThrow;
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.DexAnnotationSet;
 import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexClass;
@@ -24,10 +30,9 @@
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.ParameterAnnotationsList;
 import com.android.tools.r8.graph.ResolutionResult;
-import com.android.tools.r8.ir.synthetic.ExceptionThrowingSourceCode;
-import com.android.tools.r8.ir.synthetic.SynthesizedCode;
 import com.android.tools.r8.position.MethodPosition;
 import com.android.tools.r8.utils.BooleanBox;
+import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.IterableUtils;
 import com.android.tools.r8.utils.MethodSignatureEquivalence;
 import com.android.tools.r8.utils.WorkList;
@@ -756,21 +761,43 @@
     if (!clazz.isProgramClass()) {
       return;
     }
-    DexMethod newMethod = dexItemFactory.createMethod(clazz.type, method.proto, method.name);
+    MethodAccessFlags accessFlags = MethodAccessFlags.builder().setPublic().build();
+    DexMethod newMethod = method.withHolder(clazz.getType(), dexItemFactory);
     DexEncodedMethod newEncodedMethod =
         new DexEncodedMethod(
             newMethod,
-            MethodAccessFlags.fromCfAccessFlags(Opcodes.ACC_PUBLIC, false),
+            accessFlags,
             MethodTypeSignature.noSignature(),
             DexAnnotationSet.empty(),
             ParameterAnnotationsList.empty(),
-            new SynthesizedCode(
-                (ignored, callerPosition) ->
-                    new ExceptionThrowingSourceCode(clazz.type, method, callerPosition, errorType)),
+            createExceptionThrowingCfCode(newMethod, accessFlags, errorType, dexItemFactory),
             true);
     addSyntheticMethod(clazz.asProgramClass(), newEncodedMethod);
   }
 
+  private static CfCode createExceptionThrowingCfCode(
+      DexMethod method,
+      MethodAccessFlags accessFlags,
+      DexType exceptionType,
+      DexItemFactory dexItemFactory) {
+    DexMethod instanceInitializer =
+        dexItemFactory.createMethod(
+            exceptionType,
+            dexItemFactory.createProto(dexItemFactory.voidType),
+            dexItemFactory.constructorMethodName);
+    int maxStack = 2;
+    int maxLocals = method.getParameters().size() + BooleanUtils.intValue(!accessFlags.isStatic());
+    return new CfCode(
+        method.getHolderType(),
+        maxStack,
+        maxLocals,
+        ImmutableList.of(
+            new CfNew(exceptionType),
+            new CfStackInstruction(Opcode.Dup),
+            new CfInvoke(Opcodes.INVOKESPECIAL, instanceInitializer, false),
+            new CfThrow()));
+  }
+
   // Note: The parameter 'target' may be a public method on a class in case of desugared
   // library retargeting (See below target.isInterface check).
   private void addForwardingMethod(DexClassAndMethod target, DexClass clazz) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
index ae334dc..97af733 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
@@ -9,8 +9,6 @@
 import static com.android.tools.r8.ir.code.Invoke.Type.STATIC;
 import static com.android.tools.r8.ir.code.Invoke.Type.SUPER;
 import static com.android.tools.r8.ir.code.Invoke.Type.VIRTUAL;
-import static com.android.tools.r8.ir.desugar.DesugaredLibraryWrapperSynthesizer.TYPE_WRAPPER_SUFFIX;
-import static com.android.tools.r8.ir.desugar.DesugaredLibraryWrapperSynthesizer.VIVIFIED_TYPE_WRAPPER_SUFFIX;
 
 import com.android.tools.r8.DesugarGraphConsumer;
 import com.android.tools.r8.cf.CfVersion;
@@ -1401,18 +1399,12 @@
   private Predicate<DexType> getShouldIgnoreFromReportsPredicate(AppView<?> appView) {
     DexItemFactory dexItemFactory = appView.dexItemFactory();
     InternalOptions options = appView.options();
-    DexString typeWrapperClassNameDescriptorSuffix =
-        dexItemFactory.createString(TYPE_WRAPPER_SUFFIX + ';');
-    DexString vivifiedTypeWrapperClassNameDescriptorSuffix =
-        dexItemFactory.createString(VIVIFIED_TYPE_WRAPPER_SUFFIX + ';');
     DexString companionClassNameDescriptorSuffix =
         dexItemFactory.createString(COMPANION_CLASS_NAME_SUFFIX + ";");
 
     return type -> {
       DexString descriptor = type.getDescriptor();
       return appView.rewritePrefix.hasRewrittenType(type, appView)
-          || descriptor.endsWith(typeWrapperClassNameDescriptorSuffix)
-          || descriptor.endsWith(vivifiedTypeWrapperClassNameDescriptorSuffix)
           || descriptor.endsWith(companionClassNameDescriptorSuffix)
           || emulatedInterfaces.containsValue(type)
           || options.desugaredLibraryConfiguration.getCustomConversions().containsValue(type)
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/nest/AccessBridgeFactory.java b/src/main/java/com/android/tools/r8/ir/desugar/nest/AccessBridgeFactory.java
new file mode 100644
index 0000000..9266ad9
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/nest/AccessBridgeFactory.java
@@ -0,0 +1,93 @@
+// 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.ir.desugar.nest;
+
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.MethodAccessFlags;
+import com.android.tools.r8.graph.ProgramField;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.synthetic.FieldAccessorBuilder;
+import com.android.tools.r8.ir.synthetic.ForwardMethodBuilder;
+
+public class AccessBridgeFactory {
+
+  static ProgramMethod createFieldAccessorBridge(
+      DexMethod bridgeMethodReference, ProgramField field, boolean isGet) {
+    assert bridgeMethodReference.getHolderType() == field.getHolderType();
+    assert field.getAccessFlags().isPrivate();
+    return new ProgramMethod(
+        field.getHolder(),
+        DexEncodedMethod.builder()
+            .setAccessFlags(
+                MethodAccessFlags.builder()
+                    .setBridge()
+                    .setPublic(field.getHolder().isInterface())
+                    .setStatic()
+                    .setSynthetic()
+                    .build())
+            .setCode(
+                FieldAccessorBuilder.builder()
+                    .applyIf(
+                        isGet, FieldAccessorBuilder::setGetter, FieldAccessorBuilder::setSetter)
+                    .setField(field)
+                    .setSourceMethod(bridgeMethodReference)
+                    .build())
+            .setMethod(bridgeMethodReference)
+            .setD8R8Synthesized()
+            .build());
+  }
+
+  static ProgramMethod createInitializerAccessorBridge(
+      DexMethod bridgeMethodReference, ProgramMethod method, DexItemFactory dexItemFactory) {
+    assert bridgeMethodReference.getHolderType() == method.getHolderType();
+    assert method.getAccessFlags().isConstructor();
+    assert method.getAccessFlags().isPrivate();
+    assert !method.getHolder().isInterface();
+    return new ProgramMethod(
+        method.getHolder(),
+        DexEncodedMethod.builder()
+            // Not setting the 'bridge' flag as this fails verification.
+            .setAccessFlags(MethodAccessFlags.builder().setConstructor().setSynthetic().build())
+            .setCode(
+                ForwardMethodBuilder.builder(dexItemFactory)
+                    .setNonStaticSourceWithExtraUnusedParameter(bridgeMethodReference)
+                    .setConstructorTarget(method.getReference())
+                    .build())
+            .setMethod(bridgeMethodReference)
+            .setD8R8Synthesized()
+            .build());
+  }
+
+  static ProgramMethod createMethodAccessorBridge(
+      DexMethod bridgeMethodReference, ProgramMethod method, DexItemFactory dexItemFactory) {
+    assert bridgeMethodReference.getHolderType() == method.getHolderType();
+    assert !method.getAccessFlags().isConstructor();
+    assert method.getAccessFlags().isPrivate();
+    boolean isInterface = method.getHolder().isInterface();
+    return new ProgramMethod(
+        method.getHolder(),
+        DexEncodedMethod.builder()
+            .setAccessFlags(
+                MethodAccessFlags.builder()
+                    .setBridge()
+                    .setPublic(isInterface)
+                    .setStatic()
+                    .setSynthetic()
+                    .build())
+            .setCode(
+                ForwardMethodBuilder.builder(dexItemFactory)
+                    .setStaticSource(bridgeMethodReference)
+                    .applyIf(
+                        method.getAccessFlags().isStatic(),
+                        builder -> builder.setStaticTarget(method.getReference(), isInterface),
+                        builder -> builder.setDirectTarget(method.getReference(), isInterface))
+                    .build())
+            .setMethod(bridgeMethodReference)
+            .setD8R8Synthesized()
+            .build());
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/nest/NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/nest/NestBasedAccessDesugaring.java
index a7f094e..b052672 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/nest/NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/nest/NestBasedAccessDesugaring.java
@@ -235,7 +235,7 @@
     synchronized (field.getHolder().getMethodCollection()) {
       ProgramMethod bridge = field.getHolder().lookupProgramMethod(bridgeReference);
       if (bridge == null) {
-        bridge = DexEncodedMethod.createFieldAccessorBridge(field, isGet, bridgeReference);
+        bridge = AccessBridgeFactory.createFieldAccessorBridge(bridgeReference, field, isGet);
         bridge.getHolder().addDirectMethod(bridge.getDefinition());
         if (eventConsumer != null) {
           if (isGet) {
@@ -300,10 +300,10 @@
         DexEncodedMethod definition = method.getDefinition();
         bridge =
             definition.isInstanceInitializer()
-                ? definition.toInitializerForwardingBridge(
-                    method.getHolder(), bridgeReference, dexItemFactory)
-                : definition.toStaticForwardingBridge(
-                    method.getHolder(), bridgeReference, dexItemFactory);
+                ? AccessBridgeFactory.createInitializerAccessorBridge(
+                    bridgeReference, method, dexItemFactory)
+                : AccessBridgeFactory.createMethodAccessorBridge(
+                    bridgeReference, method, dexItemFactory);
         bridge.getHolder().addDirectMethod(bridge.getDefinition());
         if (eventConsumer != null) {
           eventConsumer.acceptNestMethodBridge(method, bridge);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/IdempotentFunctionCallCanonicalizer.java b/src/main/java/com/android/tools/r8/ir/optimize/IdempotentFunctionCallCanonicalizer.java
index 50443c6..b3dd6b6 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/IdempotentFunctionCallCanonicalizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/IdempotentFunctionCallCanonicalizer.java
@@ -160,7 +160,7 @@
           }
 
           MethodOptimizationInfo optimizationInfo = target.getDefinition().getOptimizationInfo();
-          if (optimizationInfo.mayHaveSideEffects()
+          if (optimizationInfo.mayHaveSideEffects(invoke, appViewWithLiveness.options())
               || !optimizationInfo.returnValueOnlyDependsOnArguments()) {
             continue;
           }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
index edd774e..e9b1e25 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
@@ -127,6 +127,7 @@
   // Map the enum candidates with their dependencies, i.e., the methods to reprocess for the given
   // enum if the optimization eventually decides to unbox it.
   private final EnumUnboxingCandidateInfoCollection enumUnboxingCandidatesInfo;
+  private final Set<DexProgramClass> candidatesToRemoveInWave = Sets.newConcurrentHashSet();
   private final Map<DexType, EnumStaticFieldValues> staticFieldValuesMap =
       new ConcurrentHashMap<>();
   private final ProgramMethodSet methodsDependingOnLibraryModelisation =
@@ -165,6 +166,13 @@
     return ordinal + 1;
   }
 
+  public void updateEnumUnboxingCandidatesInfo() {
+    for (DexProgramClass candidate : candidatesToRemoveInWave) {
+      enumUnboxingCandidatesInfo.removeCandidate(candidate);
+    }
+    candidatesToRemoveInWave.clear();
+  }
+
   /**
    * Returns true if {@param enumClass} was marked as being unboxable.
    *
@@ -175,7 +183,7 @@
     assert enumClass.isEnum();
     if (!reportFailure(enumClass, reason)) {
       // The failure was not reported, meaning debug logging is disabled.
-      enumUnboxingCandidatesInfo.removeCandidate(enumClass);
+      candidatesToRemoveInWave.add(enumClass);
       return true;
     }
     return false;
@@ -461,7 +469,9 @@
       ExecutorService executorService,
       OptimizationFeedbackDelayed feedback)
       throws ExecutionException {
+    assert candidatesToRemoveInWave.isEmpty();
     EnumDataMap enumDataMap = finishAnalysis();
+    assert candidatesToRemoveInWave.isEmpty();
     // At this point the enum unboxing candidates are no longer candidates, they will all be
     // unboxed. We extract the now immutable enums to unbox information and clear the candidate
     // info.
@@ -540,6 +550,7 @@
 
   public EnumDataMap finishAnalysis() {
     analyzeInitializers();
+    updateEnumUnboxingCandidatesInfo();
     EnumDataMap enumDataMap = analyzeEnumInstances();
     if (debugLogEnabled) {
       // Remove all enums that have been reported as being unboxable.
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
index 0aed133..a98bc38 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
@@ -12,11 +12,13 @@
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
 import com.android.tools.r8.ir.analysis.value.UnknownValue;
 import com.android.tools.r8.ir.code.InvokeDirect;
+import com.android.tools.r8.ir.code.InvokeMethod;
 import com.android.tools.r8.ir.optimize.classinliner.constraint.ClassInlinerMethodConstraint;
 import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
 import com.android.tools.r8.ir.optimize.info.initializer.DefaultInstanceInitializerInfo;
 import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo;
 import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.InternalOptions;
 import com.google.common.collect.ImmutableSet;
 import java.util.BitSet;
 import java.util.Set;
@@ -134,6 +136,11 @@
   }
 
   @Override
+  public SimpleInliningConstraint getNopInliningConstraint(InternalOptions options) {
+    return NeverSimpleInliningConstraint.getInstance();
+  }
+
+  @Override
   public SimpleInliningConstraint getSimpleInliningConstraint() {
     return NeverSimpleInliningConstraint.getInstance();
   }
@@ -169,6 +176,11 @@
   }
 
   @Override
+  public boolean mayHaveSideEffects(InvokeMethod invoke, InternalOptions options) {
+    return UNKNOWN_MAY_HAVE_SIDE_EFFECTS;
+  }
+
+  @Override
   public boolean returnValueOnlyDependsOnArguments() {
     return UNKNOWN_RETURN_VALUE_ONLY_DEPENDS_ON_ARGUMENTS;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
index 748d82d..a25eabb 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
@@ -12,6 +12,7 @@
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
 import com.android.tools.r8.ir.code.InvokeDirect;
+import com.android.tools.r8.ir.code.InvokeMethod;
 import com.android.tools.r8.ir.optimize.classinliner.constraint.ClassInlinerMethodConstraint;
 import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
 import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo;
@@ -78,6 +79,8 @@
 
   public abstract AbstractValue getAbstractReturnValue();
 
+  public abstract SimpleInliningConstraint getNopInliningConstraint(InternalOptions options);
+
   public abstract SimpleInliningConstraint getSimpleInliningConstraint();
 
   public abstract boolean forceInline();
@@ -90,6 +93,9 @@
 
   public abstract boolean mayHaveSideEffects();
 
+  /** Context sensitive version of {@link #mayHaveSideEffects()}. */
+  public abstract boolean mayHaveSideEffects(InvokeMethod invoke, InternalOptions options);
+
   public abstract boolean returnValueOnlyDependsOnArguments();
 
   public abstract boolean returnValueHasBeenPropagated();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
index 1b47801..5b99126 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
@@ -17,6 +17,7 @@
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
 import com.android.tools.r8.ir.analysis.value.UnknownValue;
 import com.android.tools.r8.ir.code.InvokeDirect;
+import com.android.tools.r8.ir.code.InvokeMethod;
 import com.android.tools.r8.ir.optimize.classinliner.constraint.ClassInlinerMethodConstraint;
 import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
 import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo;
@@ -24,6 +25,7 @@
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.InternalOptions;
 import java.util.BitSet;
 import java.util.Optional;
 import java.util.Set;
@@ -322,6 +324,15 @@
   }
 
   @Override
+  public SimpleInliningConstraint getNopInliningConstraint(InternalOptions options) {
+    // We currently require that having a simple inlining constraint implies that the method becomes
+    // empty after inlining. Therefore, an invoke is a nop if the simple inlining constraint is
+    // satisfied (if the invoke does not trigger other side effects, such as class initialization).
+    assert options.simpleInliningConstraintThreshold == 0;
+    return getSimpleInliningConstraint();
+  }
+
+  @Override
   public SimpleInliningConstraint getSimpleInliningConstraint() {
     return simpleInliningConstraint;
   }
@@ -357,6 +368,17 @@
   }
 
   @Override
+  public boolean mayHaveSideEffects(InvokeMethod invoke, InternalOptions options) {
+    if (!mayHaveSideEffects()) {
+      return false;
+    }
+    if (getNopInliningConstraint(options).isSatisfied(invoke)) {
+      return false;
+    }
+    return true;
+  }
+
+  @Override
   public boolean returnValueOnlyDependsOnArguments() {
     return isFlagSet(RETURN_VALUE_ONLY_DEPENDS_ON_ARGUMENTS_FLAG);
   }
@@ -529,8 +551,12 @@
     return new MutableMethodOptimizationInfo(this);
   }
 
-  public void adjustOptimizationInfoAfterRemovingThisParameter() {
+  public void adjustOptimizationInfoAfterRemovingThisParameter(
+      AppView<AppInfoWithLiveness> appView) {
     classInlinerConstraint = classInlinerConstraint.fixupAfterRemovingThisParameter();
+    simpleInliningConstraint =
+        simpleInliningConstraint.fixupAfterRemovingThisParameter(
+            appView.simpleInliningConstraintFactory());
     // cannotBeKept: doesn't depend on `this`
     // classInitializerMayBePostponed: `this` could trigger <clinit> of the previous holder.
     clearFlag(CLASS_INITIALIZER_MAY_BE_POSTPONED_FLAG);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
index 91b334c..3e59aa8 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
@@ -759,7 +759,7 @@
         if (method.isStatic()) {
           newDirectMethods.add(method);
         } else if (!factory().isConstructor(method.getReference())) {
-          DexEncodedMethod staticizedMethod = method.toStaticMethodWithoutThis();
+          DexEncodedMethod staticizedMethod = method.toStaticMethodWithoutThis(appView);
           newDirectMethods.add(staticizedMethod);
           staticizedMethods.createAndAdd(candidateClass, staticizedMethod);
           methodMapping.put(method.getReference(), staticizedMethod.getReference());
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
index 6986b3d..254511e 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
@@ -98,7 +98,7 @@
           instructions.add(
               new CfInvoke(
                   Opcodes.INVOKESTATIC,
-                  converter.createConversionMethod(param, param, vivifiedTypeFor(param)),
+                  converter.ensureConversionMethod(param, param, vivifiedTypeFor(param)),
                   false));
           newParameters[index - 1] = vivifiedTypeFor(param);
         }
@@ -129,7 +129,7 @@
         instructions.add(
             new CfInvoke(
                 Opcodes.INVOKESTATIC,
-                converter.createConversionMethod(
+                converter.ensureConversionMethod(
                     returnType, vivifiedTypeFor(returnType), returnType),
                 false));
       }
@@ -185,7 +185,7 @@
           instructions.add(
               new CfInvoke(
                   Opcodes.INVOKESTATIC,
-                  converter.createConversionMethod(param, vivifiedTypeFor(param), param),
+                  converter.ensureConversionMethod(param, vivifiedTypeFor(param), param),
                   false));
         }
         if (param == factory.longType || param == factory.doubleType) {
@@ -205,7 +205,7 @@
         instructions.add(
             new CfInvoke(
                 Opcodes.INVOKESTATIC,
-                converter.createConversionMethod(
+                converter.ensureConversionMethod(
                     returnType, returnType, vivifiedTypeFor(returnType)),
                 false));
         returnType = vivifiedTypeFor(returnType);
@@ -221,14 +221,12 @@
 
   public static class APIConverterWrapperConversionCfCodeProvider extends SyntheticCfCodeProvider {
 
-    DexType argType;
     DexField reverseWrapperField;
     DexField wrapperField;
 
     public APIConverterWrapperConversionCfCodeProvider(
-        AppView<?> appView, DexType argType, DexField reverseWrapperField, DexField wrapperField) {
+        AppView<?> appView, DexField reverseWrapperField, DexField wrapperField) {
       super(appView, wrapperField.holder);
-      this.argType = argType;
       this.reverseWrapperField = reverseWrapperField;
       this.wrapperField = wrapperField;
     }
@@ -238,6 +236,7 @@
       DexItemFactory factory = appView.dexItemFactory();
       List<CfInstruction> instructions = new ArrayList<>();
 
+      DexType argType = wrapperField.type;
       ImmutableInt2ReferenceSortedMap<FrameType> locals =
           ImmutableInt2ReferenceSortedMap.<FrameType>builder()
               .put(0, FrameType.initialized(argType))
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/FieldAccessorBuilder.java b/src/main/java/com/android/tools/r8/ir/synthetic/FieldAccessorBuilder.java
index 1f3c6d0..d6794c6 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/FieldAccessorBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/FieldAccessorBuilder.java
@@ -40,6 +40,13 @@
     return this;
   }
 
+  public FieldAccessorBuilder applyIf(
+      boolean condition,
+      Consumer<FieldAccessorBuilder> thenConsumer,
+      Consumer<FieldAccessorBuilder> elseConsumer) {
+    return apply(condition ? thenConsumer : elseConsumer);
+  }
+
   public FieldAccessorBuilder setField(DexClassAndField field) {
     return field.getAccessFlags().isStatic()
         ? setStaticField(field.getReference())
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java
index c89cb3e..eb56742 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java
@@ -17,7 +17,7 @@
     this(sourceCodeProvider, SynthesizedCode::registerReachableDefinitionsDefault);
   }
 
-  public SynthesizedCode(SourceCodeProvider sourceCodeProvider, Consumer<UseRegistry> callback) {
+  private SynthesizedCode(SourceCodeProvider sourceCodeProvider, Consumer<UseRegistry> callback) {
     this.sourceCodeProvider = sourceCodeProvider;
     this.registryCallback = callback;
   }
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 75bb5f5..abb6523 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -3155,7 +3155,7 @@
       return empty;
     }
 
-    void addClasspathClass(DexClasspathClass clazz) {
+    void addLiveClasspathClass(DexClasspathClass clazz) {
       DexClasspathClass old = syntheticClasspathClasses.put(clazz.type, clazz);
       assert old == null;
     }
@@ -3172,11 +3172,6 @@
       liveMethodsWithKeepActions.add(new Pair<>(method, keepAction));
     }
 
-    void amendApplication(Builder appBuilder) {
-      assert !isEmpty();
-      appBuilder.addClasspathClasses(syntheticClasspathClasses.values());
-    }
-
     void enqueueWorkItems(Enqueuer enqueuer) {
       assert !isEmpty();
       assert enqueuer.mode.isInitialTreeShaking();
@@ -3214,14 +3209,8 @@
       return;
     }
 
-    // Now all additions are computed, the application is atomically extended with those additions.
-    appInfo =
-        appInfo.rebuildWithClassHierarchy(
-            app -> {
-              Builder appBuilder = app.asDirect().builder();
-              additions.amendApplication(appBuilder);
-              return appBuilder.build();
-            });
+    // Commit the pending synthetics and recompute subtypes.
+    appInfo = appInfo.rebuildWithClassHierarchy(app -> app);
     appView.setAppInfo(appInfo);
     subtypingInfo = new SubtypingInfo(appView);
 
@@ -3528,7 +3517,7 @@
     callbacks.forEach(additions::addLiveMethod);
 
     // Generate wrappers on classpath so types are defined.
-    desugaredLibraryWrapperAnalysis.generateWrappers(additions::addClasspathClass);
+    desugaredLibraryWrapperAnalysis.generateWrappers(additions::addLiveClasspathClass);
   }
 
 
diff --git a/src/main/java/com/android/tools/r8/shaking/GraphReporter.java b/src/main/java/com/android/tools/r8/shaking/GraphReporter.java
index 6146c2c..fabdd04 100644
--- a/src/main/java/com/android/tools/r8/shaking/GraphReporter.java
+++ b/src/main/java/com/android/tools/r8/shaking/GraphReporter.java
@@ -333,13 +333,17 @@
     }
   }
 
+  private boolean hasKeptGraphConsumer() {
+    return keptGraphConsumer != null;
+  }
+
   private boolean skipReporting(KeepReason reason) {
     assert reason != null;
     if (reason == KeepReasonWitness.INSTANCE) {
       return true;
     }
     assert getSourceNode(reason) != null;
-    return keptGraphConsumer == null;
+    return !hasKeptGraphConsumer();
   }
 
   public KeepReasonWitness registerInterface(DexProgramClass iface, KeepReason reason) {
@@ -359,11 +363,15 @@
 
   public KeepReasonWitness registerAnnotation(
       DexAnnotation annotation, ProgramDefinition annotatedItem) {
-    KeepReason reason = KeepReason.annotatedOn(annotatedItem.getDefinition());
-    if (skipReporting(reason)) {
-      return KeepReasonWitness.INSTANCE;
+    if (hasKeptGraphConsumer()) {
+      registerEdge(
+          getAnnotationGraphNode(annotation, annotatedItem),
+          KeepReason.annotatedOn(annotatedItem.getDefinition()));
+      registerEdge(
+          getClassGraphNode(annotation.getAnnotationType()),
+          KeepReason.referencedInAnnotation(annotation, annotatedItem));
     }
-    return registerEdge(getAnnotationGraphNode(annotation, annotatedItem), reason);
+    return KeepReasonWitness.INSTANCE;
   }
 
   public KeepReasonWitness registerMethod(DexEncodedMethod method, KeepReason reason) {
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
index 72a0a0b..e4890a0 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
@@ -149,6 +149,10 @@
       this(appView, subtypingInfo, null);
     }
 
+    boolean isMainDexRootSetBuilder() {
+      return false;
+    }
+
     void handleMatchedAnnotation(AnnotationMatchResult annotation) {
       // Intentionally empty.
     }
@@ -517,7 +521,8 @@
       //  fullmode.
       if (clazz.isProgramClass()
           && rule.isProguardKeepRule()
-          && !rule.asProguardKeepRule().getModifiers().allowsShrinking) {
+          && !rule.asProguardKeepRule().getModifiers().allowsShrinking
+          && !isMainDexRootSetBuilder()) {
         new SynthesizeMissingInterfaceMethodsForMemberRules(
                 clazz.asProgramClass(), memberKeepRules, rule, preconditionSupplier, ifRule)
             .run();
@@ -2241,6 +2246,11 @@
     }
 
     @Override
+    boolean isMainDexRootSetBuilder() {
+      return true;
+    }
+
+    @Override
     public MainDexRootSet build(ExecutorService executorService) throws ExecutionException {
       // Call the super builder to have if-tests calculated automatically.
       RootSet rootSet = super.build(executorService);
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index e0837dd..d43f32a 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -1206,7 +1206,7 @@
           }
           holder =
               holder.superType != null
-                  ? appInfo.definitionFor(holder.superType).asProgramClass()
+                  ? asProgramClassOrNull(appInfo.definitionFor(holder.superType))
                   : null;
         }
       }
diff --git a/src/main/java/com/android/tools/r8/synthesis/CommittedSyntheticsCollection.java b/src/main/java/com/android/tools/r8/synthesis/CommittedSyntheticsCollection.java
index cd80b53..fd7437e 100644
--- a/src/main/java/com/android/tools/r8/synthesis/CommittedSyntheticsCollection.java
+++ b/src/main/java/com/android/tools/r8/synthesis/CommittedSyntheticsCollection.java
@@ -9,6 +9,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
 import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
 import com.android.tools.r8.utils.IterableUtils;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
@@ -215,6 +216,19 @@
     return containsLegacyType(type) || containsNonLegacyType(type);
   }
 
+  boolean containsTypeOfKind(DexType type, SyntheticKind kind) {
+    List<SyntheticProgramClassReference> synthetics = nonLegacyClasses.get(type);
+    if (synthetics == null) {
+      return false;
+    }
+    for (SyntheticProgramClassReference synthetic : synthetics) {
+      if (synthetic.getKind() == kind) {
+        return true;
+      }
+    }
+    return false;
+  }
+
   public boolean containsLegacyType(DexType type) {
     return legacyTypes.containsKey(type);
   }
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java
index 737ffa6..6a6aef4 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java
@@ -98,6 +98,11 @@
     return self();
   }
 
+  public B setSuperType(DexType superType) {
+    this.superType = superType;
+    return self();
+  }
+
   public B setOriginKind(Kind originKind) {
     this.originKind = originKind;
     return self();
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
index 3bd99a2..f7e235f 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
@@ -76,6 +76,11 @@
       return legacyClasses.containsKey(type) || nonLegacyDefinitions.containsKey(type);
     }
 
+    boolean containsTypeOfKind(DexType type, SyntheticKind kind) {
+      SyntheticDefinition<?, ?, ?> definition = nonLegacyDefinitions.get(type);
+      return definition != null && definition.getKind() == kind;
+    }
+
     boolean verifyNotRewritten(NonIdentityGraphLens lens) {
       assert legacyClasses.keySet().equals(lens.rewriteTypes(legacyClasses.keySet()));
       assert nonLegacyDefinitions.keySet().equals(lens.rewriteTypes(nonLegacyDefinitions.keySet()));
@@ -291,6 +296,10 @@
     return isSyntheticClass(clazz.type);
   }
 
+  public boolean isSyntheticOfKind(DexType type, SyntheticKind kind) {
+    return pending.containsTypeOfKind(type, kind) || committed.containsTypeOfKind(type, kind);
+  }
+
   boolean isSyntheticInput(DexProgramClass clazz) {
     return committed.containsSyntheticInput(clazz.getType());
   }
@@ -609,8 +618,8 @@
           new SyntheticClasspathClassBuilder(type, kind, outerContext, appView.dexItemFactory());
       classConsumer.accept(classBuilder);
       DexClasspathClass clazz = classBuilder.build();
-      onCreationConsumer.accept(clazz);
       addPendingDefinition(new SyntheticClasspathClassDefinition(kind, outerContext, clazz));
+      onCreationConsumer.accept(clazz);
       return clazz;
     }
   }
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
index 33530e6..c142281 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
@@ -28,6 +28,8 @@
     EMULATED_INTERFACE_CLASS("$-EL", 3, false, true),
     RETARGET_CLASS("RetargetClass", 20, false, true),
     RETARGET_INTERFACE("RetargetInterface", 21, false, true),
+    WRAPPER("$Wrapper", 22, false, true),
+    VIVIFIED_WRAPPER("$VivifiedWrapper", 23, false, true),
     LAMBDA("Lambda", 4, false),
     INIT_TYPE_ARGUMENT("-IA", 5, false, true),
     HORIZONTAL_INIT_TYPE_ARGUMENT_1(SYNTHETIC_CLASS_SEPARATOR + "IA$1", 6, false, true),
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 b75ac5a..0a1fcc7 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -263,7 +263,7 @@
   public boolean enableInliningOfInvokesWithNullableReceivers = true;
   public boolean disableInliningOfLibraryMethodOverrides = true;
   public boolean enableSimpleInliningConstraints = true;
-  public int simpleInliningConstraintThreshold = 0;
+  public final int simpleInliningConstraintThreshold = 0;
   public boolean enableClassInlining = true;
   public boolean enableClassStaticizer = true;
   public boolean enableInitializedClassesAnalysis = true;
diff --git a/src/test/java/com/android/tools/r8/D8TestBuilder.java b/src/test/java/com/android/tools/r8/D8TestBuilder.java
index 1cae06b..2ada4dd 100644
--- a/src/test/java/com/android/tools/r8/D8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/D8TestBuilder.java
@@ -65,9 +65,15 @@
   D8TestCompileResult internalCompile(
       Builder builder, Consumer<InternalOptions> optionsConsumer, Supplier<AndroidApp> app)
       throws CompilationFailedException {
+    libraryDesugaringTestConfiguration.configure(builder);
     ToolHelper.runD8(builder, optionsConsumer);
     return new D8TestCompileResult(
-        getState(), app.get(), minApiLevel, getOutputMode(), getMapContent());
+        getState(),
+        app.get(),
+        minApiLevel,
+        getOutputMode(),
+        libraryDesugaringTestConfiguration,
+        getMapContent());
   }
 
   private String getMapContent() {
@@ -87,7 +93,6 @@
     if (minApiLevel.getLevel() < AndroidApiLevel.O.getLevel()) {
       super.enableCoreLibraryDesugaring(
           minApiLevel, keepRuleConsumer, desugaredLibraryConfiguration);
-      builder.setDesugaredLibraryKeepRuleConsumer(keepRuleConsumer);
     }
     return self();
   }
diff --git a/src/test/java/com/android/tools/r8/D8TestCompileResult.java b/src/test/java/com/android/tools/r8/D8TestCompileResult.java
index 7e8e572..6d7634c 100644
--- a/src/test/java/com/android/tools/r8/D8TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/D8TestCompileResult.java
@@ -11,8 +11,13 @@
   private final String proguardMap;
 
   D8TestCompileResult(
-      TestState state, AndroidApp app, int minApiLevel, OutputMode outputMode, String proguardMap) {
-    super(state, app, minApiLevel, outputMode);
+      TestState state,
+      AndroidApp app,
+      int minApiLevel,
+      OutputMode outputMode,
+      LibraryDesugaringTestConfiguration libraryDesugaringTestConfiguration,
+      String proguardMap) {
+    super(state, app, minApiLevel, outputMode, libraryDesugaringTestConfiguration);
     this.proguardMap = proguardMap;
   }
 
diff --git a/src/test/java/com/android/tools/r8/DXTestBuilder.java b/src/test/java/com/android/tools/r8/DXTestBuilder.java
index 30917a7..2459f1d 100644
--- a/src/test/java/com/android/tools/r8/DXTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/DXTestBuilder.java
@@ -46,6 +46,7 @@
   DXTestCompileResult internalCompile(
       Builder builder, Consumer<InternalOptions> optionsConsumer, Supplier<AndroidApp> app)
       throws CompilationFailedException {
+    assert !libraryDesugaringTestConfiguration.isEnabled();
     try {
       Path dxOutputFolder = getState().getNewTempFolder();
       Path outJar = dxOutputFolder.resolve("output.jar");
diff --git a/src/test/java/com/android/tools/r8/ExternalR8TestBuilder.java b/src/test/java/com/android/tools/r8/ExternalR8TestBuilder.java
index ca3e2f0..73c4623 100644
--- a/src/test/java/com/android/tools/r8/ExternalR8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/ExternalR8TestBuilder.java
@@ -112,6 +112,7 @@
   ExternalR8TestCompileResult internalCompile(
       Builder builder, Consumer<InternalOptions> optionsConsumer, Supplier<AndroidApp> app)
       throws CompilationFailedException {
+    assert !libraryDesugaringTestConfiguration.isEnabled();
     try {
       Path outputFolder = getState().getNewTempFolder();
       Path outputJar = outputFolder.resolve("output.jar");
diff --git a/src/test/java/com/android/tools/r8/L8TestBuilder.java b/src/test/java/com/android/tools/r8/L8TestBuilder.java
new file mode 100644
index 0000000..567d471
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/L8TestBuilder.java
@@ -0,0 +1,201 @@
+// 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;
+
+import static junit.framework.Assert.assertNull;
+import static junit.framework.TestCase.assertTrue;
+
+import com.android.tools.r8.TestBase.Backend;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.AndroidAppConsumers;
+import com.android.tools.r8.utils.ConsumerUtils;
+import com.android.tools.r8.utils.FileUtils;
+import com.android.tools.r8.utils.InternalOptions;
+import com.google.common.collect.ImmutableList;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.function.Consumer;
+
+public class L8TestBuilder {
+
+  private final AndroidApiLevel apiLevel;
+  private final Backend backend;
+  private final TestState state;
+
+  private CompilationMode mode = CompilationMode.RELEASE;
+  private String generatedKeepRules = null;
+  private List<String> keepRules = new ArrayList<>();
+  private List<Path> additionalProgramFiles = new ArrayList<>();
+  private List<byte[]> additionalProgramClassFileData = new ArrayList<>();
+  private Consumer<InternalOptions> optionsModifier = ConsumerUtils.emptyConsumer();
+  private Path desugarJDKLibs = ToolHelper.getDesugarJDKLibs();
+  private Path desugarJDKLibsConfiguration = null;
+  private StringResource desugaredLibraryConfiguration =
+      StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting());
+  private List<Path> libraryFiles = new ArrayList<>();
+
+  private L8TestBuilder(AndroidApiLevel apiLevel, Backend backend, TestState state) {
+    this.apiLevel = apiLevel;
+    this.backend = backend;
+    this.state = state;
+  }
+
+  public static L8TestBuilder create(AndroidApiLevel apiLevel, Backend backend, TestState state) {
+    return new L8TestBuilder(apiLevel, backend, state);
+  }
+
+  public L8TestBuilder addProgramFiles(Collection<Path> programFiles) {
+    this.additionalProgramFiles.addAll(programFiles);
+    return this;
+  }
+
+  public L8TestBuilder addProgramClassFileData(byte[]... classes) {
+    this.additionalProgramClassFileData.addAll(Arrays.asList(classes));
+    return this;
+  }
+
+  public L8TestBuilder addLibraryFiles(Path... libraryFiles) {
+    Collections.addAll(this.libraryFiles, libraryFiles);
+    return this;
+  }
+
+  public L8TestBuilder addGeneratedKeepRules(String generatedKeepRules) {
+    assertNull(this.generatedKeepRules);
+    this.generatedKeepRules = generatedKeepRules;
+    return this;
+  }
+
+  public L8TestBuilder addKeepRuleFile(Path keepRuleFile) throws IOException {
+    this.keepRules.add(FileUtils.readTextFile(keepRuleFile, StandardCharsets.UTF_8));
+    return this;
+  }
+
+  public L8TestBuilder addKeepRuleFiles(Collection<Path> keepRuleFiles) throws IOException {
+    for (Path keepRuleFile : keepRuleFiles) {
+      addKeepRuleFile(keepRuleFile);
+    }
+    return this;
+  }
+
+  public L8TestBuilder addOptionsModifier(Consumer<InternalOptions> optionsModifier) {
+    this.optionsModifier = this.optionsModifier.andThen(optionsModifier);
+    return this;
+  }
+
+  public L8TestBuilder applyIf(boolean condition, ThrowableConsumer<L8TestBuilder> thenConsumer) {
+    return applyIf(condition, thenConsumer, ThrowableConsumer.empty());
+  }
+
+  public L8TestBuilder applyIf(
+      boolean condition,
+      ThrowableConsumer<L8TestBuilder> thenConsumer,
+      ThrowableConsumer<L8TestBuilder> elseConsumer) {
+    if (condition) {
+      thenConsumer.acceptWithRuntimeException(this);
+    } else {
+      elseConsumer.acceptWithRuntimeException(this);
+    }
+    return this;
+  }
+
+  public L8TestBuilder setDebug() {
+    this.mode = CompilationMode.DEBUG;
+    return this;
+  }
+
+  public L8TestBuilder setDesugarJDKLibs(Path desugarJDKLibs) {
+    assert desugarJDKLibs != null : "Use noDefaultDesugarJDKLibs to clear the default.";
+    this.desugarJDKLibs = desugarJDKLibs;
+    return this;
+  }
+
+  public L8TestBuilder noDefaultDesugarJDKLibs() {
+    this.desugarJDKLibs = null;
+    return this;
+  }
+
+  public L8TestBuilder setDesugarJDKLibsConfiguration(Path desugarJDKLibsConfiguration) {
+    this.desugarJDKLibsConfiguration = desugarJDKLibsConfiguration;
+    return this;
+  }
+
+  public L8TestBuilder setDesugaredLibraryConfiguration(Path path) {
+    this.desugaredLibraryConfiguration = StringResource.fromFile(path);
+    return this;
+  }
+
+  public L8TestBuilder setDisableL8AnnotationRemoval(boolean disableL8AnnotationRemoval) {
+    return addOptionsModifier(
+        options -> options.testing.disableL8AnnotationRemoval = disableL8AnnotationRemoval);
+  }
+
+  public L8TestCompileResult compile()
+      throws IOException, CompilationFailedException, ExecutionException {
+    // We wrap exceptions in a RuntimeException to call this from a lambda.
+    AndroidAppConsumers sink = new AndroidAppConsumers();
+    L8Command.Builder l8Builder =
+        L8Command.builder(state.getDiagnosticsHandler())
+            .addProgramFiles(getProgramFiles())
+            .addLibraryFiles(getLibraryFiles())
+            .setMode(mode)
+            .addDesugaredLibraryConfiguration(desugaredLibraryConfiguration)
+            .setMinApiLevel(apiLevel.getLevel())
+            .setProgramConsumer(
+                backend.isCf()
+                    ? sink.wrapProgramConsumer(ClassFileConsumer.emptyConsumer())
+                    : sink.wrapProgramConsumer(DexIndexedConsumer.emptyConsumer()));
+    addProgramClassFileData(l8Builder);
+    Path mapping = null;
+    if (!keepRules.isEmpty() || generatedKeepRules != null) {
+      mapping = state.getNewTempFile("mapping.txt");
+      l8Builder
+          .addProguardConfiguration(
+              ImmutableList.<String>builder()
+                  .addAll(keepRules)
+                  .addAll(
+                      generatedKeepRules != null
+                          ? ImmutableList.of(generatedKeepRules)
+                          : Collections.emptyList())
+                  .build(),
+              Origin.unknown())
+          .setProguardMapOutputPath(mapping);
+    }
+    ToolHelper.runL8(l8Builder.build(), optionsModifier);
+    return new L8TestCompileResult(sink.build(), apiLevel, generatedKeepRules, mapping, state)
+        .inspect(
+            inspector ->
+                inspector.forAllClasses(
+                    clazz -> assertTrue(clazz.getFinalName().startsWith("j$."))));
+  }
+
+  private Collection<Path> getProgramFiles() {
+    ImmutableList.Builder<Path> builder = ImmutableList.builder();
+    if (desugarJDKLibs != null) {
+      builder.add(desugarJDKLibs);
+    }
+    if (desugarJDKLibsConfiguration != null) {
+      builder.add(desugarJDKLibsConfiguration);
+    }
+    return builder.addAll(additionalProgramFiles).build();
+  }
+
+  private L8Command.Builder addProgramClassFileData(L8Command.Builder builder) {
+    additionalProgramClassFileData.forEach(
+        data -> builder.addClassProgramData(data, Origin.unknown()));
+    return builder;
+  }
+
+  private Collection<Path> getLibraryFiles() {
+    return libraryFiles;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/LibraryDesugaringTestConfiguration.java b/src/test/java/com/android/tools/r8/LibraryDesugaringTestConfiguration.java
new file mode 100644
index 0000000..79dc2c9
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/LibraryDesugaringTestConfiguration.java
@@ -0,0 +1,316 @@
+// 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;
+
+import static com.android.tools.r8.LibraryDesugaringTestConfiguration.Configuration.DEFAULT;
+import static junit.framework.TestCase.assertNotNull;
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.TestBase.Backend;
+import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase.KeepRuleConsumer;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.google.common.collect.ImmutableList;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+
+public class LibraryDesugaringTestConfiguration {
+
+  private static final String RELEASES_DIR = "third_party/openjdk/desugar_jdk_libs_releases/";
+
+  public enum Configuration {
+    DEFAULT(
+        ToolHelper.getDesugarJDKLibs(),
+        ToolHelper.DESUGAR_LIB_CONVERSIONS,
+        ToolHelper.getDesugarLibJsonForTesting()),
+    DEFAULT_JDK11(
+        Paths.get("third_party/openjdk/desugar_jdk_libs_11/desugar_jdk_libs.jar"),
+        ToolHelper.DESUGAR_LIB_CONVERSIONS,
+        Paths.get("src/library_desugar/jdk11/desugar_jdk_libs.json")),
+    RELEASED_1_0_9("1.0.9"),
+    RELEASED_1_0_10("1.0.10"),
+    RELEASED_1_1_0("1.1.0"),
+    RELEASED_1_1_1("1.1.1"),
+    RELEASED_1_1_5("1.1.5");
+
+    private final Path desugarJdkLibs;
+    private final Path customConversions;
+    private final Path configuration;
+
+    Configuration(Path desugarJdkLibs, Path customConversions, Path configuration) {
+      this.desugarJdkLibs = desugarJdkLibs;
+      this.customConversions = customConversions;
+      this.configuration = configuration;
+    }
+
+    Configuration(String version) {
+      this(
+          Paths.get(RELEASES_DIR, version, "desugar_jdk_libs.jar"),
+          Paths.get(RELEASES_DIR, version, "desugar_jdk_libs_configuration.jar"),
+          Paths.get(RELEASES_DIR, version, "desugar.json"));
+    }
+
+    public static List<Configuration> getReleased() {
+      return ImmutableList.of(
+          RELEASED_1_0_9, RELEASED_1_0_10, RELEASED_1_1_0, RELEASED_1_1_1, RELEASED_1_1_5);
+    }
+  }
+
+  private final AndroidApiLevel minApiLevel;
+  private final Path desugarJdkLibs;
+  private final Path customConversions;
+  private final List<StringResource> desugaredLibraryConfigurationResources;
+  private final boolean withKeepRuleConsumer;
+  private final KeepRuleConsumer keepRuleConsumer;
+  private final CompilationMode mode;
+  private final boolean addRunClassPath;
+
+  public static final LibraryDesugaringTestConfiguration DISABLED =
+      new LibraryDesugaringTestConfiguration();
+
+  private LibraryDesugaringTestConfiguration() {
+    this.minApiLevel = null;
+    this.desugarJdkLibs = null;
+    this.customConversions = null;
+    this.keepRuleConsumer = null;
+    this.withKeepRuleConsumer = false;
+    this.desugaredLibraryConfigurationResources = null;
+    this.mode = null;
+    this.addRunClassPath = false;
+  }
+
+  private LibraryDesugaringTestConfiguration(
+      AndroidApiLevel minApiLevel,
+      Path desugarJdkLibs,
+      Path customConversions,
+      List<StringResource> desugaredLibraryConfigurationResources,
+      boolean withKeepRuleConsumer,
+      KeepRuleConsumer keepRuleConsumer,
+      CompilationMode mode,
+      boolean addRunClassPath) {
+    this.minApiLevel = minApiLevel;
+    this.desugarJdkLibs = desugarJdkLibs;
+    this.customConversions = customConversions;
+    this.desugaredLibraryConfigurationResources = desugaredLibraryConfigurationResources;
+    this.withKeepRuleConsumer = withKeepRuleConsumer;
+    this.keepRuleConsumer = keepRuleConsumer;
+    this.mode = mode;
+    this.addRunClassPath = addRunClassPath;
+  }
+
+  public static class Builder {
+
+    AndroidApiLevel minApiLevel;
+    private Path desugarJdkLibs;
+    private Path customConversions;
+    private final List<StringResource> desugaredLibraryConfigurationResources = new ArrayList<>();
+    boolean withKeepRuleConsumer = false;
+    KeepRuleConsumer keepRuleConsumer;
+    private CompilationMode mode = CompilationMode.DEBUG;
+    boolean addRunClassPath = true;
+
+    private Builder() {}
+
+    public Builder setMinApi(AndroidApiLevel minApiLevel) {
+      this.minApiLevel = minApiLevel;
+      return this;
+    }
+
+    public Builder setConfiguration(Configuration configuration) {
+      desugarJdkLibs = configuration.desugarJdkLibs;
+      customConversions = configuration.customConversions;
+      desugaredLibraryConfigurationResources.clear();
+      desugaredLibraryConfigurationResources.add(
+          StringResource.fromFile(configuration.configuration));
+      return this;
+    }
+
+    public Builder withKeepRuleConsumer() {
+      withKeepRuleConsumer = true;
+      return this;
+    }
+
+    public Builder setKeepRuleConsumer(StringConsumer keepRuleConsumer) {
+      withKeepRuleConsumer = false;
+      if (keepRuleConsumer == null) {
+        this.keepRuleConsumer = null;
+      } else {
+        assert keepRuleConsumer instanceof KeepRuleConsumer;
+        this.keepRuleConsumer = (KeepRuleConsumer) keepRuleConsumer;
+      }
+      return this;
+    }
+
+    public Builder addDesugaredLibraryConfiguration(StringResource desugaredLibraryConfiguration) {
+      desugaredLibraryConfigurationResources.add(desugaredLibraryConfiguration);
+      return this;
+    }
+
+    public Builder setMode(CompilationMode mode) {
+      this.mode = mode;
+      return this;
+    }
+
+    public Builder dontAddRunClasspath() {
+      addRunClassPath = false;
+      return this;
+    }
+
+    public LibraryDesugaringTestConfiguration build() {
+      if (desugaredLibraryConfigurationResources.isEmpty()) {
+        desugaredLibraryConfigurationResources.add(
+            StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()));
+      }
+      if (withKeepRuleConsumer) {
+        this.keepRuleConsumer = createKeepRuleConsumer(minApiLevel);
+      }
+      return new LibraryDesugaringTestConfiguration(
+          minApiLevel,
+          desugarJdkLibs != null ? desugarJdkLibs : DEFAULT.desugarJdkLibs,
+          customConversions != null ? customConversions : DEFAULT.customConversions,
+          desugaredLibraryConfigurationResources,
+          withKeepRuleConsumer,
+          keepRuleConsumer,
+          mode,
+          addRunClassPath);
+    }
+  }
+
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  public boolean isEnabled() {
+    return this != DISABLED;
+  }
+
+  public boolean isAddRunClassPath() {
+    return addRunClassPath;
+  }
+
+  public void configure(D8Command.Builder builder) {
+    if (!isEnabled()) {
+      return;
+    }
+    if (keepRuleConsumer != null) {
+      builder.setDesugaredLibraryKeepRuleConsumer(keepRuleConsumer);
+    }
+    desugaredLibraryConfigurationResources.forEach(builder::addDesugaredLibraryConfiguration);
+  }
+
+  public void configure(R8Command.Builder builder) {
+    if (!isEnabled()) {
+      return;
+    }
+    if (keepRuleConsumer != null) {
+      builder.setDesugaredLibraryKeepRuleConsumer(keepRuleConsumer);
+    }
+    desugaredLibraryConfigurationResources.forEach(builder::addDesugaredLibraryConfiguration);
+  }
+
+  public Path buildDesugaredLibrary(TestState state) {
+    String generatedKeepRules = null;
+    if (withKeepRuleConsumer) {
+      if (keepRuleConsumer instanceof PresentKeepRuleConsumer) {
+        generatedKeepRules = keepRuleConsumer.get();
+        assertNotNull(generatedKeepRules);
+      } else {
+        assertThat(keepRuleConsumer, instanceOf(AbsentKeepRuleConsumer.class));
+      }
+    }
+    String finalGeneratedKeepRules = generatedKeepRules;
+    try {
+      return L8TestBuilder.create(minApiLevel, Backend.DEX, state)
+          .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+          .setDesugarJDKLibs(desugarJdkLibs)
+          .setDesugarJDKLibsConfiguration(customConversions)
+          .applyIf(
+              mode == CompilationMode.RELEASE,
+              builder -> {
+                if (finalGeneratedKeepRules != null && !finalGeneratedKeepRules.trim().isEmpty()) {
+                  builder.addGeneratedKeepRules(finalGeneratedKeepRules);
+                }
+              },
+              L8TestBuilder::setDebug)
+          .compile()
+          .writeToZip();
+    } catch (CompilationFailedException | ExecutionException | IOException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  public KeepRuleConsumer getKeepRuleConsumer() {
+    return keepRuleConsumer;
+  }
+
+  public static KeepRuleConsumer createKeepRuleConsumer(TestParameters parameters) {
+    return createKeepRuleConsumer(parameters.getApiLevel());
+  }
+
+  private static KeepRuleConsumer createKeepRuleConsumer(AndroidApiLevel apiLevel) {
+    if (requiresAnyCoreLibDesugaring(apiLevel)) {
+      return new PresentKeepRuleConsumer();
+    }
+    return new AbsentKeepRuleConsumer();
+  }
+
+  private static boolean requiresAnyCoreLibDesugaring(AndroidApiLevel apiLevel) {
+    return apiLevel.isLessThan(AndroidApiLevel.O);
+  }
+
+  public static class PresentKeepRuleConsumer implements KeepRuleConsumer {
+
+    StringBuilder stringBuilder = new StringBuilder();
+    String result = null;
+
+    @Override
+    public void accept(String string, DiagnosticsHandler handler) {
+      assert stringBuilder != null;
+      assert result == null;
+      stringBuilder.append(string);
+    }
+
+    @Override
+    public void finished(DiagnosticsHandler handler) {
+      assert stringBuilder != null;
+      assert result == null;
+      result = stringBuilder.toString();
+      stringBuilder = null;
+    }
+
+    public String get() {
+      // TODO(clement): remove that branch once StringConsumer has finished again.
+      if (stringBuilder != null) {
+        finished(null);
+      }
+
+      assert stringBuilder == null;
+      assert result != null;
+      return result;
+    }
+  }
+
+  public static class AbsentKeepRuleConsumer implements KeepRuleConsumer {
+
+    public String get() {
+      return null;
+    }
+
+    @Override
+    public void accept(String string, DiagnosticsHandler handler) {
+      throw new Unreachable("No desugaring on high API levels");
+    }
+
+    @Override
+    public void finished(DiagnosticsHandler handler) {
+      throw new Unreachable("No desugaring on high API levels");
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/ProguardTestBuilder.java b/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
index 460246c..830047f 100644
--- a/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
@@ -66,6 +66,7 @@
   ProguardTestCompileResult internalCompile(
       Builder builder, Consumer<InternalOptions> optionsConsumer, Supplier<AndroidApp> app)
       throws CompilationFailedException {
+    assert !libraryDesugaringTestConfiguration.isEnabled();
     try {
       Path proguardOutputFolder = getState().getNewTempFolder();
       Path outJar = proguardOutputFolder.resolve("output.jar");
diff --git a/src/test/java/com/android/tools/r8/R8TestBuilder.java b/src/test/java/com/android/tools/r8/R8TestBuilder.java
index 0e11c5b..d245c58 100644
--- a/src/test/java/com/android/tools/r8/R8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/R8TestBuilder.java
@@ -111,6 +111,7 @@
     Box box = new Box();
     ToolHelper.addSyntheticProguardRulesConsumerForTesting(
         builder, rules -> box.syntheticProguardRules = rules);
+    libraryDesugaringTestConfiguration.configure(builder);
     ToolHelper.runR8WithoutResult(
         builder.build(),
         optionsConsumer.andThen(
@@ -119,6 +120,7 @@
         new R8TestCompileResult(
             getState(),
             getOutputMode(),
+            libraryDesugaringTestConfiguration,
             app.get(),
             box.proguardConfiguration,
             box.syntheticProguardRules,
@@ -654,7 +656,6 @@
     if (minApiLevel.getLevel() < AndroidApiLevel.O.getLevel()) {
       super.enableCoreLibraryDesugaring(
           minApiLevel, keepRuleConsumer, desugaredLibraryConfiguration);
-      builder.setDesugaredLibraryKeepRuleConsumer(keepRuleConsumer);
     }
     return self();
   }
diff --git a/src/test/java/com/android/tools/r8/R8TestCompileResult.java b/src/test/java/com/android/tools/r8/R8TestCompileResult.java
index a1a5f88..0480694 100644
--- a/src/test/java/com/android/tools/r8/R8TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/R8TestCompileResult.java
@@ -35,6 +35,7 @@
   R8TestCompileResult(
       TestState state,
       OutputMode outputMode,
+      LibraryDesugaringTestConfiguration libraryDesugaringTestConfiguration,
       AndroidApp app,
       ProguardConfiguration proguardConfiguration,
       List<ProguardConfigurationRule> syntheticProguardRules,
@@ -42,7 +43,7 @@
       CollectingGraphConsumer graphConsumer,
       int minApiLevel,
       List<Path> features) {
-    super(state, app, minApiLevel, outputMode);
+    super(state, app, minApiLevel, outputMode, libraryDesugaringTestConfiguration);
     this.proguardConfiguration = proguardConfiguration;
     this.syntheticProguardRules = syntheticProguardRules;
     this.proguardMap = proguardMap;
@@ -110,6 +111,12 @@
     return self();
   }
 
+  public final <E extends Throwable> R8TestCompileResult inspectGraph(
+      ThrowingConsumer<GraphInspector, E> consumer) throws IOException, E {
+    consumer.accept(graphInspector());
+    return self();
+  }
+
   public GraphInspector graphInspector() throws IOException {
     assert graphConsumer != null;
     return new GraphInspector(graphConsumer, inspector());
diff --git a/src/test/java/com/android/tools/r8/TestCompileResult.java b/src/test/java/com/android/tools/r8/TestCompileResult.java
index 827684d..b80c482 100644
--- a/src/test/java/com/android/tools/r8/TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/TestCompileResult.java
@@ -42,6 +42,7 @@
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
+import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.stream.Collectors;
@@ -58,12 +59,27 @@
   final List<String> vmArguments = new ArrayList<>();
   private boolean withArt6Plus64BitsLib = false;
   private boolean withArtFrameworks = true;
+  private LibraryDesugaringTestConfiguration libraryDesugaringTestConfiguration;
 
   TestCompileResult(TestState state, AndroidApp app, int minApiLevel, OutputMode outputMode) {
     super(state);
     this.app = app;
     this.minApiLevel = minApiLevel;
     this.outputMode = outputMode;
+    this.libraryDesugaringTestConfiguration = LibraryDesugaringTestConfiguration.DISABLED;
+  }
+
+  TestCompileResult(
+      TestState state,
+      AndroidApp app,
+      int minApiLevel,
+      OutputMode outputMode,
+      LibraryDesugaringTestConfiguration libraryDesugaringTestConfiguration) {
+    super(state);
+    this.app = app;
+    this.minApiLevel = minApiLevel;
+    this.outputMode = outputMode;
+    this.libraryDesugaringTestConfiguration = libraryDesugaringTestConfiguration;
   }
 
   public CR applyIf(boolean condition, ThrowableConsumer<CR> thenConsumer) {
@@ -118,6 +134,12 @@
     return self();
   }
 
+  public final CR inspectMainDexClasses(BiConsumer<CodeInspector, Set<String>> consumer)
+      throws IOException {
+    consumer.accept(inspector(), getMainDexClasses());
+    return self();
+  }
+
   public abstract String getStdout();
 
   public abstract String getStderr();
@@ -135,6 +157,7 @@
 
   @Deprecated
   public RR run(String mainClass) throws ExecutionException, IOException {
+    assert !libraryDesugaringTestConfiguration.isEnabled();
     ClassSubject mainClassSubject = inspector().clazz(mainClass);
     assertThat(mainClassSubject, isPresent());
     switch (getBackend()) {
@@ -169,6 +192,10 @@
   public RR run(TestRuntime runtime, String mainClass, String... args)
       throws ExecutionException, IOException {
     assert getBackend() == runtime.getBackend();
+    if (libraryDesugaringTestConfiguration.isEnabled()
+        && libraryDesugaringTestConfiguration.isAddRunClassPath()) {
+      additionalRunClassPath.add(libraryDesugaringTestConfiguration.buildDesugaredLibrary(state));
+    }
     ClassSubject mainClassSubject = inspector().clazz(mainClass);
     if (!mainClassSubject.isPresent()) {
       for (Path classpathFile : additionalRunClassPath) {
diff --git a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
index 3c5b479..211df9c 100644
--- a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
@@ -75,6 +75,9 @@
 
   private boolean isAndroidBuildVersionAdded = false;
 
+  LibraryDesugaringTestConfiguration libraryDesugaringTestConfiguration =
+      LibraryDesugaringTestConfiguration.DISABLED;
+
   public boolean isTestShrinkerBuilder() {
     return false;
   }
@@ -445,17 +448,33 @@
         StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()));
   }
 
+  public T enableCoreLibraryDesugaring(LibraryDesugaringTestConfiguration configuration) {
+    this.libraryDesugaringTestConfiguration = configuration;
+    return self();
+  }
+
   public T enableCoreLibraryDesugaring(
       AndroidApiLevel minApiLevel,
       StringConsumer keepRuleConsumer,
       StringResource desugaredLibraryConfiguration) {
     assert minApiLevel.getLevel() < AndroidApiLevel.O.getLevel();
-    builder.addDesugaredLibraryConfiguration(desugaredLibraryConfiguration);
-    // 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.
-    // Use P to mimic current Android Studio.
-    builder.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P));
+    return enableLibraryDesugaring(
+        LibraryDesugaringTestConfiguration.builder()
+            .setMinApi(minApiLevel)
+            .setKeepRuleConsumer(keepRuleConsumer)
+            .addDesugaredLibraryConfiguration(desugaredLibraryConfiguration)
+            .dontAddRunClasspath()
+            .build());
+  }
+
+  public T enableLibraryDesugaring(AndroidApiLevel minApiLevel) {
+    this.libraryDesugaringTestConfiguration =
+        LibraryDesugaringTestConfiguration.builder().setMinApi(minApiLevel).build();
+    return self();
+  }
+
+  public T enableLibraryDesugaring(LibraryDesugaringTestConfiguration configuration) {
+    this.libraryDesugaringTestConfiguration = configuration;
     return self();
   }
 
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfDefaultInterfaceMethodsTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfDefaultInterfaceMethodsTest.java
new file mode 100644
index 0000000..a19ecec
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfDefaultInterfaceMethodsTest.java
@@ -0,0 +1,103 @@
+// 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.apimodel;
+
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
+import static com.android.tools.r8.utils.AndroidApiLevel.L_MR1;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeMatchers;
+import java.lang.reflect.Method;
+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 ApiModelNoInliningOfDefaultInterfaceMethodsTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public ApiModelNoInliningOfDefaultInterfaceMethodsTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test()
+  public void testR8() throws Exception {
+    Method apiMethod = Api.class.getDeclaredMethod("apiLevel22");
+    testForR8(parameters.getBackend())
+        .addProgramClasses(Main.class, A.class, ApiCaller.class)
+        .addLibraryClasses(Api.class)
+        .addDefaultRuntimeLibrary(parameters)
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(Main.class)
+        .apply(setMockApiLevelForMethod(apiMethod, L_MR1))
+        .apply(ApiModelingTestHelper::enableApiCallerIdentification)
+        .compile()
+        .inspect(
+            inspector -> {
+              ClassSubject aSubject = inspector.clazz(A.class);
+              assertThat(aSubject, isPresent());
+              aSubject.forAllMethods(
+                  method -> {
+                    // TODO(b/191013385): callApiLevel is merged into A, but not with method
+                    // implementation.
+                    // TODO(b/191013233): Check that the bridge is supposed to stay in R8.
+                    if (method
+                            .getOriginalName()
+                            .equals(ApiCaller.class.getTypeName() + ".callApiLevel")
+                        && !method.getAccessFlags().isBridge()) {
+                      // TODO(b/191008231): Should not invoke api here.
+                      assertThat(method, CodeMatchers.invokesMethodWithName("apiLevel22"));
+                      return;
+                    }
+                    assertThat(method, not(CodeMatchers.invokesMethodWithName("apiLevel")));
+                  });
+            })
+        .addRunClasspathClasses(Api.class)
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines("A::noApiCall", "ApiCaller::callApiLevel", "Api::apiLevel22");
+  }
+
+  public static class Api {
+
+    public static void apiLevel22() {
+      System.out.println("Api::apiLevel22");
+    }
+  }
+
+  public interface ApiCaller {
+    default void callApiLevel() {
+      System.out.println("ApiCaller::callApiLevel");
+      Api.apiLevel22();
+    }
+  }
+
+  public static class A implements ApiCaller {
+
+    public void noApiCall() {
+      System.out.println("A::noApiCall");
+      callApiLevel();
+    }
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) {
+      new A().noApiCall();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfLambdaTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfLambdaTest.java
new file mode 100644
index 0000000..c8f7caa
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfLambdaTest.java
@@ -0,0 +1,140 @@
+// 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.apimodel;
+
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
+import static com.android.tools.r8.utils.AndroidApiLevel.L_MR1;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeMatchers;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import java.lang.reflect.Method;
+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 ApiModelNoInliningOfLambdaTest extends TestBase {
+
+  private final TestParameters parameters;
+  private final String EXPECTED =
+      StringUtils.lines(
+          "ApiCaller::getAction",
+          "Api::apiLevel22",
+          "ApiCaller::callApi",
+          "Api::apiLevel22",
+          "Action::getAction",
+          "Api::apiLevel22");
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public ApiModelNoInliningOfLambdaTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    Method apiMethod = Api.class.getDeclaredMethod("apiLevel22");
+    testForR8(parameters.getBackend())
+        .addProgramClasses(ApiCaller.class, Action.class, Main.class)
+        .addLibraryClasses(Api.class)
+        .addDefaultRuntimeLibrary(parameters)
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(Main.class)
+        .apply(setMockApiLevelForMethod(apiMethod, L_MR1))
+        .apply(ApiModelingTestHelper::enableApiCallerIdentification)
+        .allowAccessModification()
+        .noMinification()
+        .compile()
+        .inspect(
+            inspector -> {
+              ClassSubject action;
+              if (parameters.canUseDefaultAndStaticInterfaceMethods()) {
+                action = inspector.clazz(Action.class);
+              } else {
+                action = inspector.companionClassFor(Action.class);
+              }
+              assertThat(action, isPresent());
+              MethodSubject action$lambda$getAction$0 =
+                  action.uniqueMethodWithName("lambda$getAction$0");
+              assertThat(action$lambda$getAction$0, isPresent());
+              assertThat(
+                  action$lambda$getAction$0, CodeMatchers.invokesMethodWithName("apiLevel22"));
+              ClassSubject apiCaller = inspector.clazz(ApiCaller.class);
+              if (parameters.isDexRuntime()
+                  && parameters.getApiLevel().isGreaterThanOrEqualTo(L_MR1)) {
+                assertThat(apiCaller, not(isPresent()));
+              } else {
+                assertThat(apiCaller, isPresent());
+                MethodSubject apiCaller$lambdagetAction$0 =
+                    apiCaller.uniqueMethodWithName("lambda$getAction$0");
+                assertThat(apiCaller$lambdagetAction$0, isPresent());
+                assertThat(
+                    apiCaller$lambdagetAction$0, CodeMatchers.invokesMethodWithName("apiLevel22"));
+              }
+            })
+        .addRunClasspathClasses(Api.class)
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  public static class Api {
+
+    public static void apiLevel22() {
+      System.out.println("Api::apiLevel22");
+    }
+  }
+
+  public interface Action {
+
+    void doSomething();
+
+    static Action getAction() {
+      return () -> {
+        System.out.println("Action::getAction");
+        Api.apiLevel22();
+      };
+    }
+  }
+
+  public static class ApiCaller {
+
+    public static Action getAction() {
+      return () -> {
+        System.out.println("ApiCaller::getAction");
+        Api.apiLevel22();
+      };
+    }
+
+    public static Action getActionMethodReference() {
+      return ApiCaller::callApi;
+    }
+
+    public static void callApi() {
+      System.out.println("ApiCaller::callApi");
+      Api.apiLevel22();
+    }
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) {
+      ApiCaller.getAction().doSomething();
+      ApiCaller.getActionMethodReference().doSomething();
+      Action.getAction().doSomething();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfStaticInterfaceMethodsTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfStaticInterfaceMethodsTest.java
new file mode 100644
index 0000000..5ed1708
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfStaticInterfaceMethodsTest.java
@@ -0,0 +1,103 @@
+// 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.apimodel;
+
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
+import static com.android.tools.r8.utils.AndroidApiLevel.L_MR1;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeMatchers;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import java.lang.reflect.Method;
+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 ApiModelNoInliningOfStaticInterfaceMethodsTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public ApiModelNoInliningOfStaticInterfaceMethodsTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    Method apiMethod = Api.class.getDeclaredMethod("apiLevel22");
+    // Method apiCaller = ApiCaller.class.getDeclaredMethod("callApiLevel");
+    testForR8(parameters.getBackend())
+        .addProgramClasses(Main.class, A.class, ApiCaller.class)
+        .addLibraryClasses(Api.class)
+        .addDefaultRuntimeLibrary(parameters)
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(Main.class)
+        .apply(setMockApiLevelForMethod(apiMethod, L_MR1))
+        .apply(ApiModelingTestHelper::enableApiCallerIdentification)
+        .noMinification()
+        .compile()
+        .inspect(
+            inspector -> {
+              // The call to the api is moved to $-CC (or stays) and is then merged if allowed.
+              if (parameters.isDexRuntime()
+                  && parameters.getApiLevel().isGreaterThanOrEqualTo(L_MR1)) {
+                assertEquals(1, inspector.allClasses().size());
+              } else {
+                assertEquals(2, inspector.allClasses().size());
+                ClassSubject aSubject = inspector.clazz(A.class);
+                assertThat(aSubject, isPresent());
+                // TODO(b/191008231): Should not invoke api here but stay on the CC class.
+                assertEquals(1, aSubject.allMethods().size());
+                MethodSubject callApiLevel = aSubject.uniqueMethodWithName("callApiLevel");
+                assertThat(callApiLevel, isPresent());
+                assertThat(callApiLevel, CodeMatchers.invokesMethodWithName("apiLevel22"));
+              }
+            })
+        .addRunClasspathClasses(Api.class)
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines("A::noApiCall", "ApiCaller::callApiLevel", "Api::apiLevel22");
+  }
+
+  public static class Api {
+
+    public static void apiLevel22() {
+      System.out.println("Api::apiLevel22");
+    }
+  }
+
+  public interface ApiCaller {
+    static void callApiLevel() {
+      System.out.println("ApiCaller::callApiLevel");
+      Api.apiLevel22();
+    }
+  }
+
+  public static class A implements ApiCaller {
+
+    public static void noApiCall() {
+      System.out.println("A::noApiCall");
+      ApiCaller.callApiLevel();
+    }
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) {
+      A.noApiCall();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingTest.java
new file mode 100644
index 0000000..e7c41d8
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingTest.java
@@ -0,0 +1,106 @@
+// 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.apimodel;
+
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
+import static com.android.tools.r8.utils.AndroidApiLevel.L_MR1;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static junit.framework.TestCase.assertEquals;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
+import java.lang.reflect.Method;
+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 ApiModelNoVerticalMergingTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public ApiModelNoVerticalMergingTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test()
+  public void testR8() throws Exception {
+    Method apiMethod = Api.class.getDeclaredMethod("apiLevel22");
+    testForR8(parameters.getBackend())
+        .addProgramClasses(Main.class, Base.class, Sub.class)
+        .addLibraryClasses(Api.class)
+        .addDefaultRuntimeLibrary(parameters)
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(Main.class)
+        .apply(setMockApiLevelForMethod(apiMethod, L_MR1))
+        .apply(ApiModelingTestHelper::enableApiCallerIdentification)
+        .enableInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
+        .noMinification()
+        .compile()
+        .inspect(
+            inspector -> {
+              // TODO(b/191013385): Prevent Base merging with Sub.
+              ClassSubject base = inspector.clazz(Base.class);
+              assertThat(base, not(isPresent()));
+              ClassSubject sub = inspector.clazz(Sub.class);
+              List<FoundMethodSubject> callApis =
+                  sub.allMethods(
+                      method ->
+                          method.getOriginalName().equals(Base.class.getTypeName() + ".callApi"));
+              // TODO(b/191013233): Remove synthetic bridge.
+              assertEquals(2, callApis.size());
+            })
+        .addRunClasspathClasses(Api.class)
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines("Sub::callCallApi", "Base::callApi", "Api::apiLevel22");
+  }
+
+  public static class Api {
+
+    public static void apiLevel22() {
+      System.out.println("Api::apiLevel22");
+    }
+  }
+
+  public static class Base {
+
+    public void callApi() {
+      System.out.println("Base::callApi");
+      Api.apiLevel22();
+    }
+  }
+
+  @NeverClassInline
+  public static class Sub extends Base {
+
+    @NeverInline
+    public void callCallApi() {
+      System.out.println("Sub::callCallApi");
+      callApi();
+    }
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) {
+      new Sub().callCallApi();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/InterfacesVisibilityTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/InterfacesVisibilityTest.java
new file mode 100644
index 0000000..b03e236
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/InterfacesVisibilityTest.java
@@ -0,0 +1,80 @@
+// 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 static com.android.tools.r8.utils.codeinspector.Matchers.isImplementing;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.classmerging.horizontal.testclasses.InterfacesVisibilityTestClasses;
+import com.android.tools.r8.classmerging.horizontal.testclasses.InterfacesVisibilityTestClasses.ImplementingPackagePrivateInterface;
+import com.android.tools.r8.classmerging.horizontal.testclasses.InterfacesVisibilityTestClasses.Invoker;
+import com.android.tools.r8.utils.codeinspector.HorizontallyMergedClassesInspector;
+import org.junit.Test;
+
+public class InterfacesVisibilityTest extends HorizontalClassMergingTestBase {
+  public InterfacesVisibilityTest(TestParameters parameters) {
+    super(parameters);
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    String packagePrivateInterfaceName =
+        InterfacesVisibilityTestClasses.class.getTypeName() + "$PackagePrivateInterface";
+    testForR8(parameters.getBackend())
+        .addInnerClasses(getClass(), InterfacesVisibilityTestClasses.class)
+        .addKeepMainRule(Main.class)
+        .enableInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
+        .enableNoVerticalClassMergingAnnotations()
+        .enableNoHorizontalClassMergingAnnotations()
+        .setMinApi(parameters.getApiLevel())
+        .addHorizontallyMergedClassesInspector(
+            HorizontallyMergedClassesInspector::assertNoClassesMerged)
+        .compile()
+        .inspect(
+            codeInspector -> {
+              // A is present and has no interfaces.
+              assertThat(codeInspector.clazz(A.class), isPresent());
+              assertTrue(
+                  codeInspector.clazz(A.class).getDexProgramClass().getInterfaces().isEmpty());
+
+              // ImplementingPackagePrivateInterface is present and implements
+              // PackagePrivateInterface.
+              assertThat(
+                  codeInspector.clazz(ImplementingPackagePrivateInterface.class),
+                  isImplementing(codeInspector.clazz(packagePrivateInterfaceName)));
+            })
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines("foo", "bar");
+  }
+
+  @NeverClassInline
+  public static class A {
+    @NeverInline
+    public void bar() {
+      System.out.println("bar");
+    }
+  }
+
+  public static class Main {
+    @NeverInline
+    public static void foo(ImplementingPackagePrivateInterface o) {
+      Invoker.invokeFoo(o);
+    }
+
+    public static void main(String[] args) {
+      ImplementingPackagePrivateInterface implementingPackagePrivateInterface =
+          new ImplementingPackagePrivateInterface();
+      A a = new A();
+      Invoker.invokeFoo(implementingPackagePrivateInterface);
+      a.bar();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/testclasses/InterfacesVisibilityTestClasses.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/testclasses/InterfacesVisibilityTestClasses.java
new file mode 100644
index 0000000..d5a5c14
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/testclasses/InterfacesVisibilityTestClasses.java
@@ -0,0 +1,34 @@
+// 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.testclasses;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoHorizontalClassMerging;
+import com.android.tools.r8.NoVerticalClassMerging;
+
+public class InterfacesVisibilityTestClasses {
+  public static class Invoker {
+    @NeverInline
+    public static void invokeFoo(PackagePrivateInterface i) {
+      i.foo();
+    }
+  }
+
+  @NoVerticalClassMerging
+  @NeverClassInline
+  public static class ImplementingPackagePrivateInterface implements PackagePrivateInterface {
+    @Override
+    public void foo() {
+      System.out.println("foo");
+    }
+  }
+
+  @NoHorizontalClassMerging
+  @NoVerticalClassMerging
+  interface PackagePrivateInterface {
+    void foo();
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/ForceInlineConstructorWithRetargetedLibMemberTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/ForceInlineConstructorWithRetargetedLibMemberTest.java
index 4a81ae5..b2010d7 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/ForceInlineConstructorWithRetargetedLibMemberTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/ForceInlineConstructorWithRetargetedLibMemberTest.java
@@ -12,6 +12,8 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import java.util.Arrays;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -36,6 +38,7 @@
   public void test() throws Exception {
     // Regression test for b/170677722.
     testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(getClass())
         .addKeepMainRule(TestClass.class)
         .addVerticallyMergedClassesInspector(
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergingWithMissingSuperClassTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergingWithMissingSuperClassTest.java
new file mode 100644
index 0000000..53fbaa5
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergingWithMissingSuperClassTest.java
@@ -0,0 +1,72 @@
+// 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.vertical;
+
+
+import com.android.tools.r8.NoVerticalClassMerging;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class VerticalClassMergingWithMissingSuperClassTest extends TestBase {
+
+  @Parameter public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramClasses(Main.class, A.class, B.class, C.class)
+        .addKeepMainRule(Main.class)
+        .addDontWarn(MissingClass.class)
+        .addVerticallyMergedClassesInspector(
+            inspector -> inspector.assertMergedIntoSubtype(B.class))
+        .enableNoVerticalClassMergingAnnotations()
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .addRunClasspathFiles(buildOnDexRuntime(parameters, MissingClass.class))
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines("C", "A", "B");
+  }
+
+  static class Main {
+    public static void main(String[] args) {
+      new C().m();
+    }
+  }
+
+  static class MissingClass {}
+
+  @NoVerticalClassMerging
+  static class A extends MissingClass {
+    void m() {
+      System.out.println("A");
+    }
+  }
+
+  static class B extends A {
+    @Override
+    void m() {
+      super.m();
+      System.out.println("B");
+    }
+  }
+
+  static class C extends B {
+    C() {
+      System.out.println("C");
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/InvokeSuperToEmulatedDefaultMethodTest.java b/src/test/java/com/android/tools/r8/desugar/InvokeSuperToEmulatedDefaultMethodTest.java
index 9d3d498..8d914a8 100644
--- a/src/test/java/com/android/tools/r8/desugar/InvokeSuperToEmulatedDefaultMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/InvokeSuperToEmulatedDefaultMethodTest.java
@@ -8,7 +8,9 @@
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.StringUtils;
 import java.util.Collection;
 import java.util.HashMap;
@@ -51,12 +53,13 @@
   @Test
   public void testDesugaring() throws Exception {
     assumeTrue(needsDefaultInterfaceMethodDesugaring());
+
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(InvokeSuperToEmulatedDefaultMethodTest.class)
         .setMinApi(parameters.getApiLevel())
-        .enableCoreLibraryDesugaring(parameters.getApiLevel())
+        .enableLibraryDesugaring(parameters.getApiLevel())
         .compile()
-        .addDesugaredCoreLibraryRunClassPath(this::buildDesugaredLibrary, parameters.getApiLevel())
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutput(EXPECTED);
   }
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 5aa2894..6e82466 100644
--- a/src/test/java/com/android/tools/r8/desugar/InvokeSuperToRewrittenDefaultMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/InvokeSuperToRewrittenDefaultMethodTest.java
@@ -13,7 +13,6 @@
 import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.StringResource;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
@@ -69,20 +68,11 @@
       testForD8()
           .addInnerClasses(InvokeSuperToRewrittenDefaultMethodTest.class)
           .setMinApi(parameters.getApiLevel())
-          .apply(
-              b -> {
-                if (rtWithoutConsumer) {
-                  b.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.B));
-                  // TODO(b/158543446): Remove this once enableCoreLibraryDesugaring is fixed.
-                  b.getBuilder()
-                      .addDesugaredLibraryConfiguration(
-                          StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()));
-                } else {
-                  // TODO(b/158543446): Move this out to the shared builder once
-                  //  enableCoreLibraryDesugaring is fixed.
-                  b.enableCoreLibraryDesugaring(parameters.getApiLevel());
-                }
-              })
+          .addLibraryFiles(
+              rtWithoutConsumer
+                  ? ToolHelper.getAndroidJar(AndroidApiLevel.B)
+                  : ToolHelper.getAndroidJar(AndroidApiLevel.P))
+          .enableCoreLibraryDesugaring(parameters.getApiLevel())
           .compileWithExpectedDiagnostics(
               diagnostics -> {
                 if (rtWithoutConsumer) {
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 5cc22b7..e0f9136 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
@@ -140,6 +140,7 @@
     Assume.assumeTrue(parameters.getRuntime().isDex());
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addOptionsModification(
             options ->
                 options.desugaredLibraryConfiguration =
@@ -168,6 +169,7 @@
     Assume.assumeTrue(parameters.getRuntime().isDex());
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addOptionsModification(
             options ->
                 options.desugaredLibraryConfiguration =
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ConcurrentHashMapSubclassTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ConcurrentHashMapSubclassTest.java
index 9b48952..696de2e 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ConcurrentHashMapSubclassTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ConcurrentHashMapSubclassTest.java
@@ -7,6 +7,8 @@
 import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
 import java.nio.file.Path;
@@ -46,6 +48,7 @@
     Assume.assumeTrue(parameters.getRuntime().isDex());
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(ConcurrentHashMapSubclassTest.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -102,6 +105,7 @@
     Assume.assumeTrue(parameters.getRuntime().isDex());
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(Backend.DEX)
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(ConcurrentHashMapSubclassTest.class)
         .setMinApi(parameters.getApiLevel())
         .addKeepClassAndMembersRules(Executor.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionForwardingTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionForwardingTest.java
index 3c822f2..10a127d 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionForwardingTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionForwardingTest.java
@@ -5,7 +5,7 @@
 package com.android.tools.r8.desugar.desugaredlibrary;
 
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestShrinkerBuilder;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
@@ -42,6 +42,7 @@
   public void testCustomCollectionD8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(CustomCollectionForwardingTest.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -60,6 +61,7 @@
   public void testCustomCollectionR8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(CustomCollectionForwardingTest.class)
         .addKeepMainRule(Executor.class)
         .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionInterfaceSuperTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionInterfaceSuperTest.java
index 684998e..10d91fa 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionInterfaceSuperTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionInterfaceSuperTest.java
@@ -7,6 +7,7 @@
 import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
@@ -58,6 +59,7 @@
     }
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(CustomCollectionInterfaceSuperTest.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -79,6 +81,7 @@
     assumeTrue(parameters.isDexRuntime());
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(CustomCollectionInterfaceSuperTest.class)
         .addKeepMainRule(Main.class)
         .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionSuperCallsTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionSuperCallsTest.java
index 2269987..e917cd3 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionSuperCallsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionSuperCallsTest.java
@@ -9,7 +9,7 @@
 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.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import java.nio.file.Path;
@@ -44,6 +44,7 @@
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     D8TestRunResult d8TestRunResult =
         testForD8()
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .addInnerClasses(CustomCollectionSuperCallsTest.class)
             .setMinApi(parameters.getApiLevel())
             .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -106,6 +107,7 @@
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     R8TestRunResult r8TestRunResult =
         testForR8(parameters.getBackend())
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .addInnerClasses(CustomCollectionSuperCallsTest.class)
             .addKeepMainRule(Executor.class)
             .setMinApi(parameters.getApiLevel())
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 514742c..d24f4dd 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
@@ -10,6 +10,8 @@
 import com.android.tools.r8.D8TestRunResult;
 import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
@@ -54,6 +56,7 @@
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     D8TestRunResult d8TestRunResult =
         testForD8()
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .addInnerClasses(CustomCollectionTest.class)
             .setMinApi(parameters.getApiLevel())
             .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -130,6 +133,7 @@
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     R8TestRunResult r8TestRunResult =
         testForR8(Backend.DEX)
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .addInnerClasses(CustomCollectionTest.class)
             .setMinApi(parameters.getApiLevel())
             .addKeepClassAndMembersRules(Executor.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomMapHierarchyTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomMapHierarchyTest.java
index 57d8867..a1c19eb 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomMapHierarchyTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomMapHierarchyTest.java
@@ -8,7 +8,9 @@
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
 import java.nio.file.Path;
@@ -60,6 +62,7 @@
     Assume.assumeTrue(parameters.getRuntime().isDex());
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(CustomMapHierarchyTest.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -121,6 +124,7 @@
     Assume.assumeTrue(parameters.getRuntime().isDex());
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(CustomMapHierarchyTest.class)
         .addKeepMainRule(Main.class)
         .addKeepAllClassesRuleWithAllowObfuscation()
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideConflictWithLibrary2Test.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideConflictWithLibrary2Test.java
index b7181de..4a4ee82 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideConflictWithLibrary2Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideConflictWithLibrary2Test.java
@@ -12,6 +12,8 @@
 import com.android.tools.r8.TestRunResult;
 import com.android.tools.r8.TestRuntime;
 import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.google.common.collect.ImmutableList;
 import java.io.IOException;
 import java.lang.reflect.Method;
@@ -76,6 +78,7 @@
           .apply(this::checkResult);
     } else {
       testForD8()
+          .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
           .addProgramClasses(getClasses())
           .addProgramClassFileData(getTransforms())
           .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideConflictWithLibraryTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideConflictWithLibraryTest.java
index d244909..e597f8e 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideConflictWithLibraryTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideConflictWithLibraryTest.java
@@ -12,6 +12,8 @@
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.TestRuntime;
 import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.google.common.collect.ImmutableList;
 import java.io.IOException;
 import java.lang.reflect.Method;
@@ -77,6 +79,7 @@
           .assertFailureWithErrorThatMatches(getExpectedError());
     } else {
       testForD8()
+          .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
           .setMinApi(parameters.getApiLevel())
           .addProgramClasses(CLASSES)
           .addProgramClassFileData(getTransforms())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideInLibraryTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideInLibraryTest.java
index ec4ba98..085cd28 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideInLibraryTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DefaultMethodOverrideInLibraryTest.java
@@ -11,6 +11,7 @@
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.TestRuntime;
 import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.DexVm.Version;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.StringUtils;
@@ -65,6 +66,7 @@
           .assertSuccessWithOutput(EXPECTED);
     } else {
       testForD8()
+          .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
           .setMinApi(parameters.getApiLevel())
           .addInnerClasses(DefaultMethodOverrideInLibraryTest.class)
           .enableCoreLibraryDesugaring(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredGenericSignatureTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredGenericSignatureTest.java
index af6ca9e..3e23d64 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredGenericSignatureTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredGenericSignatureTest.java
@@ -11,6 +11,7 @@
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
@@ -55,6 +56,7 @@
     Assume.assumeTrue(parameters.getRuntime().isDex());
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(DesugaredGenericSignatureTest.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -118,6 +120,7 @@
     Assume.assumeTrue(parameters.getRuntime().isDex());
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(DesugaredGenericSignatureTest.class)
         .addKeepMainRule(Main.class)
         .addKeepAllClassesRuleWithAllowObfuscation()
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCloneTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCloneTest.java
index 73e5d67..c4c0c13 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCloneTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCloneTest.java
@@ -5,6 +5,8 @@
 package com.android.tools.r8.desugar.desugaredlibrary;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import java.time.DayOfWeek;
 import java.util.List;
@@ -35,6 +37,7 @@
   public void testD8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(getClass())
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -52,6 +55,7 @@
   public void testR8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(getClass())
         .addKeepMainRule(Main.class)
         .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryMismatchTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryMismatchTest.java
index e705ca6..888436d 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryMismatchTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryMismatchTest.java
@@ -11,6 +11,7 @@
 
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.errors.DesugaredLibraryMismatchDiagnostic;
 import com.android.tools.r8.ir.desugar.DesugaredLibraryConfiguration;
 import com.android.tools.r8.origin.Origin;
@@ -55,6 +56,7 @@
     // Combine DEX input without library desugaring with dexing with library desugaring.
     try {
       testForD8()
+          .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
           .addProgramFiles(libraryDex)
           .addProgramClasses(TestRunner.class)
           .setMinApi(apiLevel)
@@ -91,6 +93,7 @@
 
     // Combine CF desugared input without library desugaring with dexing with library desugaring.
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addProgramFiles(desugaredLibrary)
         .addProgramClasses(TestRunner.class)
         .setMinApi(apiLevel)
@@ -118,6 +121,7 @@
             .writeToZip();
 
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addProgramFiles(desugaredLibraryDex)
         .addProgramClasses(TestRunner.class)
         .setMinApi(apiLevel)
@@ -161,6 +165,7 @@
     // DEX code with library desugaring.
     Path libraryDex =
         testForD8(Backend.DEX)
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .addProgramClasses(Library.class)
             .setMinApi(apiLevel)
             .enableCoreLibraryDesugaring(apiLevel)
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 a4c52ad..2414cf7 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
@@ -5,16 +5,14 @@
 package com.android.tools.r8.desugar.desugaredlibrary;
 
 import static com.android.tools.r8.utils.InternalOptions.ASM_VERSION;
-import static junit.framework.Assert.assertNull;
 import static junit.framework.TestCase.assertEquals;
 import static junit.framework.TestCase.assertTrue;
 
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.CompilationMode;
-import com.android.tools.r8.DexIndexedConsumer;
-import com.android.tools.r8.DiagnosticsHandler;
 import com.android.tools.r8.L8Command;
-import com.android.tools.r8.L8TestCompileResult;
+import com.android.tools.r8.L8TestBuilder;
+import com.android.tools.r8.LibraryDesugaringTestConfiguration;
 import com.android.tools.r8.OutputMode;
 import com.android.tools.r8.StringConsumer;
 import com.android.tools.r8.StringResource;
@@ -22,36 +20,27 @@
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.TestState;
-import com.android.tools.r8.ThrowableConsumer;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.DexVm.Version;
-import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.ir.desugar.DesugaredLibraryConfiguration;
 import com.android.tools.r8.ir.desugar.DesugaredLibraryConfigurationParser;
-import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.tracereferences.TraceReferences;
 import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.AndroidAppConsumers;
-import com.android.tools.r8.utils.ConsumerUtils;
 import com.android.tools.r8.utils.FileUtils;
 import com.android.tools.r8.utils.InternalOptions;
 import com.google.common.base.Charsets;
 import com.google.common.collect.ImmutableList;
 import java.io.IOException;
-import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ExecutionException;
 import java.util.function.Consumer;
 import org.junit.BeforeClass;
-import org.junit.rules.TemporaryFolder;
 import org.objectweb.asm.ClassReader;
 import org.objectweb.asm.ClassVisitor;
 import org.objectweb.asm.MethodVisitor;
@@ -104,151 +93,12 @@
     return parameters.getApiLevel().getLevel() < AndroidApiLevel.O.getLevel();
   }
 
-  public static class L8TestBuilder {
-
-    private final AndroidApiLevel apiLevel;
-    private final TestState state;
-
-    private CompilationMode mode = CompilationMode.RELEASE;
-    private String generatedKeepRules = null;
-    private List<String> keepRules = new ArrayList<>();
-    private List<Path> additionalProgramFiles = new ArrayList<>();
-    private Consumer<InternalOptions> optionsModifier = ConsumerUtils.emptyConsumer();
-    private Path desugarJDKLibs = ToolHelper.getDesugarJDKLibs();
-    private Path desugarJDKLibsConfiguration = null;
-    private StringResource desugaredLibraryConfiguration =
-        StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting());
-    private List<Path> libraryFiles = new ArrayList<>();
-
-    private L8TestBuilder(AndroidApiLevel apiLevel, TemporaryFolder temp) {
-      this.apiLevel = apiLevel;
-      this.state = new TestState(temp);
-    }
-
-    public L8TestBuilder addProgramFiles(Collection<Path> programFiles) {
-      this.additionalProgramFiles.addAll(programFiles);
-      return this;
-    }
-
-    public L8TestBuilder addLibraryFiles(Path... libraryFiles) {
-      Collections.addAll(this.libraryFiles, libraryFiles);
-      return this;
-    }
-
-    public L8TestBuilder addGeneratedKeepRules(String generatedKeepRules) {
-      assertNull(this.generatedKeepRules);
-      this.generatedKeepRules = generatedKeepRules;
-      return this;
-    }
-
-    public L8TestBuilder addKeepRuleFile(Path keepRuleFile) throws IOException {
-      this.keepRules.add(FileUtils.readTextFile(keepRuleFile, StandardCharsets.UTF_8));
-      return this;
-    }
-
-    public L8TestBuilder addKeepRuleFiles(Collection<Path> keepRuleFiles) throws IOException {
-      for (Path keepRuleFile : keepRuleFiles) {
-        addKeepRuleFile(keepRuleFile);
-      }
-      return this;
-    }
-
-    public L8TestBuilder addOptionsModifier(Consumer<InternalOptions> optionsModifier) {
-      this.optionsModifier = this.optionsModifier.andThen(optionsModifier);
-      return this;
-    }
-
-    public L8TestBuilder applyIf(boolean condition, ThrowableConsumer<L8TestBuilder> thenConsumer) {
-      return applyIf(condition, thenConsumer, ThrowableConsumer.empty());
-    }
-
-    public L8TestBuilder applyIf(
-        boolean condition,
-        ThrowableConsumer<L8TestBuilder> thenConsumer,
-        ThrowableConsumer<L8TestBuilder> elseConsumer) {
-      if (condition) {
-        thenConsumer.acceptWithRuntimeException(this);
-      } else {
-        elseConsumer.acceptWithRuntimeException(this);
-      }
-      return this;
-    }
-
-    public L8TestBuilder setDebug() {
-      this.mode = CompilationMode.DEBUG;
-      return this;
-    }
-
-    public L8TestBuilder setDesugarJDKLibs(Path desugarJDKLibs) {
-      this.desugarJDKLibs = desugarJDKLibs;
-      return this;
-    }
-
-    public L8TestBuilder setDesugarJDKLibsConfiguration(Path desugarJDKLibsConfiguration) {
-      this.desugarJDKLibsConfiguration = desugarJDKLibsConfiguration;
-      return this;
-    }
-
-    public L8TestBuilder setDesugaredLibraryConfiguration(Path path) {
-      this.desugaredLibraryConfiguration = StringResource.fromFile(path);
-      return this;
-    }
-
-    private L8TestBuilder setDisableL8AnnotationRemoval(boolean disableL8AnnotationRemoval) {
-      return addOptionsModifier(
-          options -> options.testing.disableL8AnnotationRemoval = disableL8AnnotationRemoval);
-    }
-
-    public L8TestCompileResult compile()
-        throws IOException, CompilationFailedException, ExecutionException {
-      // We wrap exceptions in a RuntimeException to call this from a lambda.
-      AndroidAppConsumers sink = new AndroidAppConsumers();
-      L8Command.Builder l8Builder =
-          L8Command.builder(state.getDiagnosticsHandler())
-              .addProgramFiles(getProgramFiles())
-              .addLibraryFiles(getLibraryFiles())
-              .setMode(mode)
-              .addDesugaredLibraryConfiguration(desugaredLibraryConfiguration)
-              .setMinApiLevel(apiLevel.getLevel())
-              .setProgramConsumer(sink.wrapProgramConsumer(DexIndexedConsumer.emptyConsumer()));
-      Path mapping = null;
-      if (!keepRules.isEmpty() || generatedKeepRules != null) {
-        mapping = state.getNewTempFile("mapping.txt");
-        l8Builder
-            .addProguardConfiguration(
-                ImmutableList.<String>builder()
-                    .addAll(keepRules)
-                    .addAll(
-                        generatedKeepRules != null
-                            ? ImmutableList.of(generatedKeepRules)
-                            : Collections.emptyList())
-                    .build(),
-                Origin.unknown())
-            .setProguardMapOutputPath(mapping);
-        }
-      ToolHelper.runL8(l8Builder.build(), optionsModifier);
-      return new L8TestCompileResult(sink.build(), apiLevel, generatedKeepRules, mapping, state)
-          .inspect(
-              inspector ->
-                  inspector.forAllClasses(
-                      clazz -> assertTrue(clazz.getFinalName().startsWith("j$."))));
-    }
-
-    private Collection<Path> getProgramFiles() {
-      ImmutableList.Builder<Path> builder = ImmutableList.<Path>builder().add(desugarJDKLibs);
-      if (desugarJDKLibsConfiguration != null) {
-        builder.add(desugarJDKLibsConfiguration);
-      }
-      return builder.addAll(additionalProgramFiles).build();
-    }
-
-    private Collection<Path> getLibraryFiles() {
-      return libraryFiles;
-    }
+  protected L8TestBuilder testForL8(AndroidApiLevel apiLevel) {
+    return L8TestBuilder.create(apiLevel, Backend.DEX, new TestState(temp));
   }
 
-  protected L8TestBuilder testForL8(AndroidApiLevel apiLevel) {
-    return new L8TestBuilder(apiLevel, temp);
+  protected L8TestBuilder testForL8(AndroidApiLevel apiLevel, Backend backend) {
+    return L8TestBuilder.create(apiLevel, backend, new TestState(temp));
   }
 
   protected Path buildDesugaredLibrary(AndroidApiLevel apiLevel) {
@@ -341,10 +191,7 @@
   }
 
   protected KeepRuleConsumer createKeepRuleConsumer(TestParameters parameters) {
-    if (requiresAnyCoreLibDesugaring(parameters)) {
-      return new PresentKeepRuleConsumer();
-    }
-    return new AbsentKeepRuleConsumer();
+    return LibraryDesugaringTestConfiguration.createKeepRuleConsumer(parameters);
   }
 
   public Path getDesugaredLibraryInCF(
@@ -471,55 +318,6 @@
     String get();
   }
 
-  public static class AbsentKeepRuleConsumer implements KeepRuleConsumer {
-
-    public String get() {
-      return null;
-    }
-
-    @Override
-    public void accept(String string, DiagnosticsHandler handler) {
-      throw new Unreachable("No desugaring on high API levels");
-    }
-
-    @Override
-    public void finished(DiagnosticsHandler handler) {
-      throw new Unreachable("No desugaring on high API levels");
-    }
-  }
-
-  public static class PresentKeepRuleConsumer implements KeepRuleConsumer {
-
-    StringBuilder stringBuilder = new StringBuilder();
-    String result = null;
-
-    @Override
-    public void accept(String string, DiagnosticsHandler handler) {
-      assert stringBuilder != null;
-      assert result == null;
-      stringBuilder.append(string);
-    }
-
-    @Override
-    public void finished(DiagnosticsHandler handler) {
-      assert stringBuilder != null;
-      assert result == null;
-      result = stringBuilder.toString();
-      stringBuilder = null;
-    }
-
-    public String get() {
-      // TODO(clement): remove that branch once StringConsumer has finished again.
-      if (stringBuilder != null) {
-        finished(null);
-      }
-
-      assert stringBuilder == null;
-      assert result != null;
-      return result;
-    }
-  }
-
   protected static class ClassFileInfo {
     private final String classBinaryName;
     private List<String> interfaces;
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLocalDateReflectedTypePassedToStaticType.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLocalDateReflectedTypePassedToStaticType.java
index 593c003..7a7ae9f 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLocalDateReflectedTypePassedToStaticType.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLocalDateReflectedTypePassedToStaticType.java
@@ -9,6 +9,7 @@
 import com.android.tools.r8.D8TestRunResult;
 import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
@@ -43,6 +44,7 @@
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     D8TestRunResult runResult =
         testForD8()
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .addInnerClasses(DesugaredLocalDateReflectedTypePassedToStaticType.class)
             .setMinApi(parameters.getApiLevel())
             .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -67,6 +69,7 @@
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     R8TestRunResult runResult =
         testForR8(parameters.getBackend())
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .addInnerClasses(DesugaredLocalDateReflectedTypePassedToStaticType.class)
             .addKeepMainRule(Main.class)
             .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLocalDateReflectionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLocalDateReflectionTest.java
index f5205f1..15d312d 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLocalDateReflectionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLocalDateReflectionTest.java
@@ -9,7 +9,9 @@
 import com.android.tools.r8.D8TestRunResult;
 import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.DexVm;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
 import java.util.List;
@@ -42,6 +44,7 @@
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     D8TestRunResult runResult =
         testForD8()
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .addInnerClasses(DesugaredLocalDateReflectionTest.class)
             .setMinApi(parameters.getApiLevel())
             .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -66,6 +69,7 @@
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     R8TestRunResult runResult =
         testForR8(parameters.getBackend())
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .addInnerClasses(DesugaredLocalDateReflectionTest.class)
             .addKeepMainRule(Main.class)
             .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredReflectedDesugaredTypePassedToStaticTypeTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredReflectedDesugaredTypePassedToStaticTypeTest.java
index bedf904..bb2da3c 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredReflectedDesugaredTypePassedToStaticTypeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredReflectedDesugaredTypePassedToStaticTypeTest.java
@@ -9,6 +9,7 @@
 import com.android.tools.r8.D8TestRunResult;
 import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
@@ -44,6 +45,7 @@
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     D8TestRunResult runResult =
         testForD8()
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .addInnerClasses(DesugaredReflectedDesugaredTypePassedToStaticTypeTest.class)
             .setMinApi(parameters.getApiLevel())
             .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -68,6 +70,7 @@
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     R8TestRunResult runResult =
         testForR8(parameters.getBackend())
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .addInnerClasses(DesugaredReflectedDesugaredTypePassedToStaticTypeTest.class)
             .addKeepMainRule(Main.class)
             .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DontKeepBootstrapClassesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DontKeepBootstrapClassesTest.java
index 5f323bc..057d37f 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DontKeepBootstrapClassesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DontKeepBootstrapClassesTest.java
@@ -6,8 +6,10 @@
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.MatcherAssert.assertThat;
 
+import com.android.tools.r8.LibraryDesugaringTestConfiguration.PresentKeepRuleConsumer;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import java.util.Arrays;
 import java.util.function.Consumer;
@@ -33,6 +35,7 @@
   public void test() throws Exception {
     KeepRuleConsumer keepRuleConsumer = new PresentKeepRuleConsumer();
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addProgramClasses(TestClass.class)
         .setMinApi(minApiLevel)
         .addLibraryClasses(CustomLibClass.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DoubleUtilityClassTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DoubleUtilityClassTest.java
index 3b12474..8ab1e6b 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DoubleUtilityClassTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DoubleUtilityClassTest.java
@@ -9,6 +9,8 @@
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
 import java.time.zone.ZoneOffsetTransition;
@@ -36,6 +38,7 @@
   public void testDoubleUtility() throws Exception {
     for (Class<?> executor : new Class<?>[] {ExecutorV1.class, ExecutorV2.class}) {
       testForD8()
+          .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
           .addProgramClasses(executor)
           .enableCoreLibraryDesugaring(parameters.getApiLevel())
           .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/FeatureSplitTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/FeatureSplitTest.java
index bca207f..f7eecc8 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/FeatureSplitTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/FeatureSplitTest.java
@@ -11,7 +11,6 @@
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestRuntime;
-import com.android.tools.r8.TestShrinkerBuilder;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.ArtCommandBuilder;
 import com.android.tools.r8.ToolHelper.ProcessResult;
@@ -237,6 +236,7 @@
 
       KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
       testForR8(parameters.getBackend())
+          .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
           .addProgramClasses(BaseClass.class, RunInterface.class, SplitRunner.class)
           .setMinApi(parameters.getApiLevel())
           .addFeatureSplit(
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ImplementedInterfacesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ImplementedInterfacesTest.java
index b5ab3b5..75692a2 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ImplementedInterfacesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ImplementedInterfacesTest.java
@@ -10,6 +10,8 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import java.io.Serializable;
@@ -67,6 +69,7 @@
   public void testInterfaces() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(ImplementedInterfacesTest.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InstantTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InstantTest.java
index 7e38a30..a99d29c 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InstantTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InstantTest.java
@@ -5,6 +5,8 @@
 package com.android.tools.r8.desugar.desugaredlibrary;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import java.time.Instant;
 import java.time.ZoneOffset;
@@ -35,6 +37,7 @@
   public void testInstantD8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(InstantTest.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -52,6 +55,7 @@
   public void testInstantR8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(InstantTest.class)
         .setMinApi(parameters.getApiLevel())
         .addKeepClassAndMembersRules(Executor.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InvalidLibraryTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InvalidLibraryTest.java
index 0490d71..8ef34bb 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InvalidLibraryTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InvalidLibraryTest.java
@@ -8,7 +8,7 @@
 
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.errors.InvalidLibrarySuperclassDiagnostic;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
@@ -67,6 +67,7 @@
   public void testProgramSupertype() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .setMinApi(parameters.getApiLevel())
         .addProgramClasses(
             Executor.class, SuperLibraryClass.class, LocalClass.class, LocalClassOverride.class)
@@ -88,6 +89,7 @@
     Assume.assumeTrue(requiresAnyCoreLibDesugaring(parameters));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .setMinApi(parameters.getApiLevel())
         .addProgramClasses(Executor.class, LocalClass.class, LocalClassOverride.class)
         .addClasspathClasses(SuperLibraryClass.class)
@@ -114,6 +116,7 @@
     Assume.assumeTrue(requiresAnyCoreLibDesugaring(parameters));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .setMinApi(parameters.getApiLevel())
         .addProgramClasses(Executor.class, LocalClass.class, LocalClassOverride.class)
         .addLibraryClasses(CustomLibraryClass.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IterableTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IterableTest.java
index 0c16701..e5f51dd 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IterableTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IterableTest.java
@@ -7,6 +7,8 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -104,6 +106,7 @@
     }
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(IterableTest.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IterateTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IterateTest.java
index 41935e4..0726e49 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IterateTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IterateTest.java
@@ -5,6 +5,8 @@
 package com.android.tools.r8.desugar.desugaredlibrary;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
 import java.nio.file.Path;
@@ -79,6 +81,7 @@
     }
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(IterateTest.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IteratorTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IteratorTest.java
index 46cb2bd..976f00e 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IteratorTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IteratorTest.java
@@ -10,7 +10,9 @@
 import static org.hamcrest.CoreMatchers.containsString;
 
 import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.LibraryDesugaringTestConfiguration.AbsentKeepRuleConsumer;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.DescriptorUtils;
@@ -61,6 +63,7 @@
     }
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(IteratorTest.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/J$ExtensionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/J$ExtensionTest.java
index 3c78730..5d0cea7 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/J$ExtensionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/J$ExtensionTest.java
@@ -143,6 +143,7 @@
 
     try {
       testForD8()
+          .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
           .addProgramFiles(compiledClasses)
           .setMinApi(parameters.getApiLevel())
           .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
index 7190c34..e1889a8 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
@@ -9,12 +9,13 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 
+import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.LibraryDesugaringTestConfiguration;
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.NoVerticalClassMerging;
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.TestCompileResult;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestShrinkerBuilder;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
@@ -237,20 +238,18 @@
     Assume.assumeTrue(parameters.getRuntime().isDex());
     Assume.assumeTrue(shrinkDesugaredLibrary || !traceReferencesKeepRules);
 
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    TestCompileResult<?, ?> result =
-        testForD8()
-            .addInnerClasses(JavaTimeTest.class)
-            .setMinApi(parameters.getApiLevel())
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-            .compile()
-            .inspect(this::checkRewrittenInvokesForD8);
-    result
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            desugaredLibraryKeepRules(keepRuleConsumer, result::writeToZip),
-            shrinkDesugaredLibrary)
+    testForD8()
+        .addInnerClasses(JavaTimeTest.class)
+        .setMinApi(parameters.getApiLevel())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+        .enableLibraryDesugaring(
+            LibraryDesugaringTestConfiguration.builder()
+                .setMinApi(parameters.getApiLevel())
+                .withKeepRuleConsumer()
+                .setMode(shrinkDesugaredLibrary ? CompilationMode.RELEASE : CompilationMode.DEBUG)
+                .build())
+        .compile()
+        .inspect(this::checkRewrittenInvokesForD8)
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutput(expectedOutput);
   }
@@ -260,23 +259,21 @@
     Assume.assumeTrue(parameters.getRuntime().isDex());
     Assume.assumeTrue(shrinkDesugaredLibrary || !traceReferencesKeepRules);
 
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
-    TestCompileResult<?, ?> result =
-        testForR8(parameters.getBackend())
-            .addInnerClasses(JavaTimeTest.class)
-            .addKeepMainRule(TestClass.class)
-            .enableNoVerticalClassMergingAnnotations()
-            .setMinApi(parameters.getApiLevel())
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
-            .enableInliningAnnotations()
-            .compile()
-            .inspect(this::checkRewrittenInvokesForR8);
-    result
-        .addDesugaredCoreLibraryRunClassPath(
-            this::buildDesugaredLibrary,
-            parameters.getApiLevel(),
-            desugaredLibraryKeepRules(keepRuleConsumer, result::writeToZip),
-            shrinkDesugaredLibrary)
+    testForR8(parameters.getBackend())
+        .addInnerClasses(JavaTimeTest.class)
+        .addKeepMainRule(TestClass.class)
+        .enableNoVerticalClassMergingAnnotations()
+        .setMinApi(parameters.getApiLevel())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+        .enableLibraryDesugaring(
+            LibraryDesugaringTestConfiguration.builder()
+                .setMinApi(parameters.getApiLevel())
+                .withKeepRuleConsumer()
+                .setMode(shrinkDesugaredLibrary ? CompilationMode.RELEASE : CompilationMode.DEBUG)
+                .build())
+        .enableInliningAnnotations()
+        .compile()
+        .inspect(this::checkRewrittenInvokesForR8)
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutput(expectedOutput);
   }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaUtilFunctionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaUtilFunctionTest.java
index 32d9d95..0ac3687 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaUtilFunctionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaUtilFunctionTest.java
@@ -10,6 +10,8 @@
 
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -61,6 +63,7 @@
   public void testJavaUtilFunctionD8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(JavaUtilFunctionTest.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -80,6 +83,7 @@
   public void testJavaUtilFunctionR8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .enableInliningAnnotations()
         .noMinification()
         .addKeepMainRule(TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaUtilOptionalTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaUtilOptionalTest.java
index c2f83eb..1e145c4 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaUtilOptionalTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaUtilOptionalTest.java
@@ -93,6 +93,7 @@
   @Test
   public void testJavaOptionalJava9() throws Exception {
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addProgramFiles(
             Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR).resolve("backport" + JAR_EXTENSION))
         .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LibraryEmptySubclassInterfaceTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LibraryEmptySubclassInterfaceTest.java
index ced1c31..172d7f9 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LibraryEmptySubclassInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LibraryEmptySubclassInterfaceTest.java
@@ -8,6 +8,8 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import java.util.List;
 import java.util.concurrent.ConcurrentHashMap;
@@ -38,6 +40,7 @@
   public void testD8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(LibraryEmptySubclassInterfaceTest.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -64,6 +67,7 @@
   public void testR8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(Backend.DEX)
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(LibraryEmptySubclassInterfaceTest.class)
         .addKeepMainRule(Executor.class)
         .noMinification()
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LinkedHashSetTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LinkedHashSetTest.java
index bbadc1d..ed4b6bc 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LinkedHashSetTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LinkedHashSetTest.java
@@ -6,6 +6,8 @@
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import java.util.LinkedHashSet;
 import java.util.Set;
 import java.util.Spliterator;
@@ -32,6 +34,7 @@
   public void testLinkedHashSetOverrides() throws Exception {
     String stdOut =
         testForD8()
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .addInnerClasses(LinkedHashSetTest.class)
             .setMinApi(parameters.getApiLevel())
             .enableCoreLibraryDesugaring(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingWithDesugaredLibraryTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingWithDesugaredLibraryTest.java
index be9ae1a..1f1b593 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingWithDesugaredLibraryTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingWithDesugaredLibraryTest.java
@@ -62,6 +62,7 @@
     try {
       compileResult =
           testForD8()
+              .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
               .addProgramFiles(buildPart1DesugaredLibrary(), buildPart2NoDesugaredLibrary())
               .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
               .setMinApi(parameters.getApiLevel())
@@ -250,6 +251,7 @@
 
   private Path buildPart1DesugaredLibrary() throws Exception {
     return testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addProgramClasses(Part1.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MinimalInterfaceSuperTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MinimalInterfaceSuperTest.java
index ff1039f..8de40b0 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MinimalInterfaceSuperTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MinimalInterfaceSuperTest.java
@@ -6,6 +6,7 @@
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.StringUtils;
 import java.util.AbstractCollection;
@@ -44,6 +45,7 @@
       return;
     }
     testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(MinimalInterfaceSuperTest.class)
         .addKeepMainRule(Main.class)
         .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MonthTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MonthTest.java
index 6b2692b..2b71ee8 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MonthTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MonthTest.java
@@ -7,6 +7,8 @@
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.TestRuntime;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.StringUtils;
 import java.time.Month;
 import java.time.format.TextStyle;
@@ -57,6 +59,7 @@
       return;
     }
     testForD8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(MonthTest.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel())
@@ -70,6 +73,7 @@
   public void testMonthR8() throws Exception {
     Assume.assumeTrue(parameters.isDexRuntime());
     testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(MonthTest.class)
         .addKeepMainRule(MonthTest.Main.class)
         .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NoDefaultMethodOverrideInLibraryTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NoDefaultMethodOverrideInLibraryTest.java
index d9f93b9..37f834a 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NoDefaultMethodOverrideInLibraryTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NoDefaultMethodOverrideInLibraryTest.java
@@ -11,6 +11,8 @@
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.TestRuntime;
 import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.StringUtils;
 import java.lang.reflect.Method;
 import java.util.Collection;
@@ -69,6 +71,7 @@
           .assertSuccessWithOutput(EXPECTED);
     } else {
       testForD8()
+          .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
           .setMinApi(parameters.getApiLevel())
           .addInnerClasses(NoDefaultMethodOverrideInLibraryTest.class)
           .enableCoreLibraryDesugaring(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NoDesugaredLibraryDexFileTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NoDesugaredLibraryDexFileTest.java
index f0e55c0..4d99161 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NoDesugaredLibraryDexFileTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NoDesugaredLibraryDexFileTest.java
@@ -7,6 +7,8 @@
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import java.util.ArrayList;
@@ -44,6 +46,7 @@
     Assume.assumeTrue(requiresEmulatedInterfaceCoreLibDesugaring(parameters));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(NoDesugaredLibraryDexFileTest.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -59,6 +62,7 @@
     Assume.assumeTrue(requiresEmulatedInterfaceCoreLibDesugaring(parameters));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(NoDesugaredLibraryDexFileTest.class)
         .setMinApi(parameters.getApiLevel())
         .addKeepClassAndMembersRules(Executor.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NoForwardingMethodsTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NoForwardingMethodsTest.java
index 625395f..81457f6 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NoForwardingMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NoForwardingMethodsTest.java
@@ -7,6 +7,7 @@
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -44,6 +45,7 @@
   public void testCustomCollectionD8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(NoForwardingMethodsTest.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -62,6 +64,7 @@
   public void testCustomCollectionR8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(NoForwardingMethodsTest.class)
         .setMinApi(parameters.getApiLevel())
         .addKeepClassAndMembersRules(Executor.class)
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 3e89a4f..213324c 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
@@ -45,6 +45,25 @@
 @RunWith(Parameterized.class)
 public class ObjectsTest extends DesugaredLibraryTestBase implements Opcodes {
 
+  private static final String EXPECTED_OUTPUT =
+      StringUtils.lines(
+          "1",
+          "false",
+          "false",
+          Objects.toString(Objects.hash(1, 2)),
+          "4",
+          "NPE",
+          "Was null",
+          "Supplier said was null",
+          "5",
+          "6",
+          "true",
+          "false",
+          "1",
+          "2",
+          "3",
+          "4");
+
   private final TestParameters parameters;
   private final boolean libraryDesugarJavaUtilObjects;
   private final boolean shrinkDesugaredLibrary = false;
@@ -178,7 +197,7 @@
     boolean invokeJDollarUtilObjects =
         libraryDesugarJavaUtilObjects && parameters.getApiLevel().isLessThan(AndroidApiLevel.N);
     boolean invokeJavaUtilObjectsWithSupplier =
-        !libraryDesugarJavaUtilObjects || !parameters.getApiLevel().isLessThan(AndroidApiLevel.N);
+        parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N);
     boolean invokeJDollarUtilObjectsWithSupplier =
         libraryDesugarJavaUtilObjects && parameters.getApiLevel().isLessThan(AndroidApiLevel.N);
 
@@ -329,25 +348,19 @@
               parameters.getApiLevel(),
               desugaredLibraryKeepRules,
               shrinkDesugaredLibrary)
-          .run(
-              parameters.getRuntime(),
-              TestClass.class,
-              Boolean.toString(libraryDesugarJavaUtilObjects))
-          .assertSuccessWithOutput(expectedOutput(libraryDesugarJavaUtilObjects));
+          .run(parameters.getRuntime(), TestClass.class)
+          .assertSuccessWithOutput(EXPECTED_OUTPUT);
     } else {
       // Build the desugared library in class file format.
       Path desugaredLib =
           getDesugaredLibraryInCF(parameters, this::configurationForLibraryCompilation);
 
-      // Run on the JVM with desuagred library on classpath.
+      // Run on the JVM with desugared library on classpath.
       testForJvm()
           .addProgramFiles(jar)
           .addRunClasspathFiles(desugaredLib)
-          .run(
-              parameters.getRuntime(),
-              TestClass.class,
-              Boolean.toString(libraryDesugarJavaUtilObjects))
-          .assertSuccessWithOutput(expectedOutput(libraryDesugarJavaUtilObjects));
+          .run(parameters.getRuntime(), TestClass.class)
+          .assertSuccessWithOutput(EXPECTED_OUTPUT);
     }
   }
 
@@ -375,11 +388,8 @@
             keepRuleConsumer.get(),
             shrinkDesugaredLibrary)
         .inspect(this::inspect)
-        .run(
-            parameters.getRuntime(),
-            TestClass.class,
-            Boolean.toString(libraryDesugarJavaUtilObjects))
-        .assertSuccessWithOutput(expectedOutput(libraryDesugarJavaUtilObjects));
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
   }
 
   @Test
@@ -411,33 +421,8 @@
             keepRuleConsumer.get(),
             shrinkDesugaredLibrary)
         .inspect(this::inspect)
-        .run(
-            parameters.getRuntime(),
-            TestClass.class,
-            Boolean.toString(libraryDesugarJavaUtilObjects))
-        .assertSuccessWithOutput(expectedOutput(libraryDesugarJavaUtilObjects));
-  }
-
-  private String expectedOutput(boolean objectsRequireNonNullWithSupplierSupported) {
-    return StringUtils.lines(
-        "1",
-        "false",
-        "false",
-        Objects.toString(Objects.hash(1, 2)),
-        "4",
-        "NPE",
-        "Was null",
-        objectsRequireNonNullWithSupplierSupported
-            ? "Supplier said was null"
-            : "Not supported (b/174840626)",
-        "5",
-        "6",
-        "true",
-        "false",
-        "1",
-        "2",
-        "3",
-        "4");
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
   }
 
   static class TestClass {
@@ -522,7 +507,6 @@
     }
 
     public static void main(String[] args) throws Exception {
-      boolean objectsRequireNonNullWithSupplierSupported = Boolean.parseBoolean(args[0]);
       // Android K methods.
       objectsCompare("b", "a");
       objectsDeepEquals(args, new Object());
@@ -531,11 +515,7 @@
       objectsHashCode(4);
       objectsRequireNonNull(getNonNullableNull());
       objectsRequireNonNullWithMessage(null, "Was null");
-      if (objectsRequireNonNullWithSupplierSupported) {
-        objectsRequireNonNullWithSupplier(null, () -> "Supplier said was null");
-      } else {
-        System.out.println("Not supported (b/174840626)");
-      }
+      objectsRequireNonNullWithSupplier(null, () -> "Supplier said was null");
       objectsToString(makeNullable("5"));
       objectsToStringWithNullDefault(getNonNullableNull(), "6");
 
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/PriorityQueueSubclassTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/PriorityQueueSubclassTest.java
index 2c29f58..8cd0cca 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/PriorityQueueSubclassTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/PriorityQueueSubclassTest.java
@@ -5,6 +5,8 @@
 package com.android.tools.r8.desugar.desugaredlibrary;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import java.util.List;
 import java.util.PriorityQueue;
@@ -35,6 +37,7 @@
   public void testPriorityQueueD8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(PriorityQueueSubclassTest.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -52,6 +55,7 @@
   public void testPriorityQueueR8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(Backend.DEX)
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(PriorityQueueSubclassTest.class)
         .setMinApi(parameters.getApiLevel())
         .addKeepClassAndMembersRules(Executor.class)
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 aa05c9d..9fe36a6 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
@@ -60,6 +60,7 @@
       KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
       D8TestCompileResult compileResult =
           testForD8()
+              .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
               .addProgramFiles(Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR + "stream.jar"))
               .setMinApi(parameters.getApiLevel())
               .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -118,6 +119,7 @@
       KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
       R8TestRunResult runResult =
           testForR8(parameters.getBackend())
+              .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
               .minification(minifying)
               .addKeepMainRule(TEST_CLASS)
               .addProgramFiles(Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR + "stream.jar"))
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ReleasedVersionsSmokeTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ReleasedVersionsSmokeTest.java
new file mode 100644
index 0000000..a81de0a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ReleasedVersionsSmokeTest.java
@@ -0,0 +1,112 @@
+// 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.CompilationMode;
+import com.android.tools.r8.LibraryDesugaringTestConfiguration;
+import com.android.tools.r8.LibraryDesugaringTestConfiguration.Configuration;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.StringUtils;
+import java.time.Clock;
+import java.time.Duration;
+import java.time.ZoneId;
+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 ReleasedVersionsSmokeTest extends DesugaredLibraryTestBase {
+
+  private final TestParameters parameters;
+  private final Configuration configuration;
+  private static final String expectedOutput =
+      StringUtils.lines(
+          "true",
+          "Caught java.time.format.DateTimeParseException",
+          "true",
+          "1970-01-02T10:17:36.789Z",
+          "GMT",
+          "GMT",
+          "1000",
+          "Hello, world");
+
+  @Parameters(name = "{0}, {1}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        Configuration.getReleased(),
+        getTestParameters().withDexRuntimes().withApiLevel(AndroidApiLevel.B).build());
+  }
+
+  public ReleasedVersionsSmokeTest(Configuration configuration, TestParameters parameters) {
+    this.configuration = configuration;
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testD8() throws Exception {
+    testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+        .addInnerClasses(ReleasedVersionsSmokeTest.class)
+        .setMinApi(parameters.getApiLevel())
+        .enableCoreLibraryDesugaring(
+            LibraryDesugaringTestConfiguration.builder()
+                .setMinApi(parameters.getApiLevel())
+                .setConfiguration(configuration)
+                .withKeepRuleConsumer()
+                .setMode(CompilationMode.DEBUG)
+                .build())
+        .compile()
+        .run(parameters.getRuntime(), TestClass.class)
+        .applyIf(
+            configuration.equals(Configuration.RELEASED_1_1_5),
+            r -> r.assertSuccessWithOutput(expectedOutput),
+            r -> r.assertFailureWithErrorThatThrows(NoClassDefFoundError.class));
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+        .addInnerClasses(ReleasedVersionsSmokeTest.class)
+        .addKeepMainRule(TestClass.class)
+        .setMinApi(parameters.getApiLevel())
+        .enableCoreLibraryDesugaring(
+            LibraryDesugaringTestConfiguration.builder()
+                .setMinApi(parameters.getApiLevel())
+                .withKeepRuleConsumer()
+                .setMode(CompilationMode.RELEASE)
+                .build())
+        .compile()
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(expectedOutput);
+  }
+
+  static class TestClass {
+
+    public static void main(String[] args) {
+      System.out.println(Clock.systemDefaultZone().getZone().equals(ZoneId.systemDefault()));
+      try {
+        java.time.LocalDate.parse("");
+      } catch (java.time.format.DateTimeParseException e) {
+        System.out.println("Caught java.time.format.DateTimeParseException");
+      }
+      System.out.println(java.time.ZoneOffset.getAvailableZoneIds().size() > 0);
+      System.out.println(
+          java.util.Date.from(new java.util.Date(123456789).toInstant()).toInstant());
+
+      java.util.TimeZone timeZone = java.util.TimeZone.getTimeZone(ZoneId.of("GMT"));
+      System.out.println(timeZone.getID());
+      System.out.println(timeZone.toZoneId().getId());
+
+      System.out.println(Duration.ofMillis(1000).toMillis());
+
+      System.out.println("Hello, world");
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RequiredNonNullWithSupplierTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RequiredNonNullWithSupplierTest.java
new file mode 100644
index 0000000..e1b302d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RequiredNonNullWithSupplierTest.java
@@ -0,0 +1,86 @@
+// 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.desugar.desugaredlibrary;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.StringUtils;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Supplier;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class RequiredNonNullWithSupplierTest extends DesugaredLibraryTestBase {
+
+  private static final String EXPECTED_OUTPUT = StringUtils.lines("SuppliedString2", "OK");
+
+  private final TestParameters parameters;
+  private final boolean shrinkDesugaredLibrary;
+
+  @Parameterized.Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+  }
+
+  public RequiredNonNullWithSupplierTest(
+      boolean shrinkDesugaredLibrary, TestParameters parameters) {
+    this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testRequiredNonNullWithSupplierTest() throws Exception {
+    if (parameters.isCfRuntime()) {
+      testForJvm()
+          .addInnerClasses(RequiredNonNullWithSupplierTest.class)
+          .run(parameters.getRuntime(), Executor.class)
+          .assertSuccessWithOutput(EXPECTED_OUTPUT);
+      return;
+    }
+    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
+    testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+        .addInnerClasses(RequiredNonNullWithSupplierTest.class)
+        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .addDesugaredCoreLibraryRunClassPath(
+            this::buildDesugaredLibrary,
+            parameters.getApiLevel(),
+            keepRuleConsumer.get(),
+            shrinkDesugaredLibrary)
+        .run(parameters.getRuntime(), Executor.class)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
+  }
+
+  static class Executor {
+
+    public static void main(String[] args) {
+      Object o = System.currentTimeMillis() > 10 ? new Object() : new Object();
+      Objects.requireNonNull(o, () -> "SuppliedString");
+      try {
+        Objects.requireNonNull(null, () -> "SuppliedString2");
+        throw new AssertionError("Unexpected");
+      } catch (NullPointerException e) {
+        System.out.println(e.getMessage());
+      }
+      try {
+        Objects.requireNonNull(null, (Supplier<String>) null);
+        throw new AssertionError("Unexpected");
+      } catch (NullPointerException e) {
+        // Normally we would want to print the exception message, but some ART versions have a bug
+        // where they erroneously calls supplier.get() on a null reference which produces the NPE
+        // but with an ART-defined message. See b/147419222.
+        System.out.println("OK");
+      }
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetAndBackportTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetAndBackportTest.java
new file mode 100644
index 0000000..40d658d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetAndBackportTest.java
@@ -0,0 +1,175 @@
+// 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.desugar.desugaredlibrary;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ir.desugar.DesugaredLibraryConfiguration;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+@RunWith(Parameterized.class)
+public class RetargetAndBackportTest extends DesugaredLibraryTestBase implements Opcodes {
+
+  Backend backend;
+
+  @Parameters(name = "{0} {1}")
+  public static List<Object[]> data() {
+    return buildParameters(getTestParameters().withNoneRuntime().build(), Backend.values());
+  }
+
+  public RetargetAndBackportTest(TestParameters parameters, Backend backend) {
+    this.backend = backend;
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForL8(AndroidApiLevel.B, backend)
+        .noDefaultDesugarJDKLibs()
+        .addProgramClassFileData(dump())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+        /*
+         Add this library desugaring configuration:
+         "library_flags": [
+           {
+             "rewrite_prefix": {"java.time.": "j$.time."},
+             "backport": {"java.lang.DesugarMath": "java.lang.Math"},
+             "retarget_lib_member": {"java.util.Date#toInstant": "java.util.DesugarDate"}
+           }
+         ],
+        */
+        .addOptionsModifier(
+            options ->
+                options.desugaredLibraryConfiguration =
+                    DesugaredLibraryConfiguration.builder(
+                            options.dexItemFactory(), options.reporter, Origin.unknown())
+                        .setDesugaredLibraryIdentifier("my-identifier")
+                        .putRewritePrefix("java.time.", "j$.time.")
+                        .putBackportCoreLibraryMember("java.lang.DesugarMath", "java.lang.Math")
+                        .putRetargetCoreLibMember(
+                            "java.util.Date#toInstant", "java.util.DesugarDate")
+                        .setLibraryCompilation()
+                        .build())
+        .compile()
+        .inspect(
+            inspector -> {
+              assertTrue(
+                  inspector
+                      .clazz("j$.time.Duration")
+                      .uniqueMethodWithName("toMillis")
+                      .streamInstructions()
+                      .filter(InstructionSubject::isInvokeStatic)
+                      .map(InstructionSubject::toString)
+                      .allMatch(s -> s.contains("Backport")));
+            });
+  }
+
+  // Dump of java.time.Duration from JDK 11 based desugared library input built from
+  // https://github.com/google/desugar_jdk_libs/commit/a2a0a26c06cbee9144eceaefd8c65e1bae2b611c.
+  public static byte[] dump() {
+
+    ClassWriter classWriter = new ClassWriter(0);
+    MethodVisitor methodVisitor;
+
+    classWriter.visit(
+        V11,
+        ACC_PUBLIC | ACC_FINAL | ACC_SUPER,
+        "java/time/Duration",
+        "Ljava/lang/Object;Ljava/time/temporal/TemporalAmount;Ljava/lang/Comparable<Ljava/time/Duration;>;Ljava/io/Serializable;",
+        "java/lang/Object",
+        new String[] {
+          "java/time/temporal/TemporalAmount", "java/lang/Comparable", "java/io/Serializable"
+        });
+
+    classWriter.visitSource("Duration.java", null);
+
+    {
+      methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "toMillis", "()J", null, null);
+      methodVisitor.visitCode();
+      Label label0 = new Label();
+      methodVisitor.visitLabel(label0);
+      methodVisitor.visitLineNumber(1217, label0);
+      methodVisitor.visitVarInsn(ALOAD, 0);
+      methodVisitor.visitFieldInsn(GETFIELD, "java/time/Duration", "seconds", "J");
+      methodVisitor.visitVarInsn(LSTORE, 1);
+      Label label1 = new Label();
+      methodVisitor.visitLabel(label1);
+      methodVisitor.visitLineNumber(1218, label1);
+      methodVisitor.visitVarInsn(ALOAD, 0);
+      methodVisitor.visitFieldInsn(GETFIELD, "java/time/Duration", "nanos", "I");
+      methodVisitor.visitInsn(I2L);
+      methodVisitor.visitVarInsn(LSTORE, 3);
+      Label label2 = new Label();
+      methodVisitor.visitLabel(label2);
+      methodVisitor.visitLineNumber(1219, label2);
+      methodVisitor.visitVarInsn(LLOAD, 1);
+      methodVisitor.visitInsn(LCONST_0);
+      methodVisitor.visitInsn(LCMP);
+      Label label3 = new Label();
+      methodVisitor.visitJumpInsn(IFGE, label3);
+      Label label4 = new Label();
+      methodVisitor.visitLabel(label4);
+      methodVisitor.visitLineNumber(1222, label4);
+      methodVisitor.visitVarInsn(LLOAD, 1);
+      methodVisitor.visitInsn(LCONST_1);
+      methodVisitor.visitInsn(LADD);
+      methodVisitor.visitVarInsn(LSTORE, 1);
+      Label label5 = new Label();
+      methodVisitor.visitLabel(label5);
+      methodVisitor.visitLineNumber(1223, label5);
+      methodVisitor.visitVarInsn(LLOAD, 3);
+      methodVisitor.visitLdcInsn(new Long(1000000000L));
+      methodVisitor.visitInsn(LSUB);
+      methodVisitor.visitVarInsn(LSTORE, 3);
+      methodVisitor.visitLabel(label3);
+      methodVisitor.visitLineNumber(1225, label3);
+      methodVisitor.visitFrame(
+          Opcodes.F_APPEND, 2, new Object[] {Opcodes.LONG, Opcodes.LONG}, 0, null);
+      methodVisitor.visitVarInsn(LLOAD, 1);
+      methodVisitor.visitIntInsn(SIPUSH, 1000);
+      methodVisitor.visitMethodInsn(
+          INVOKESTATIC, "java/lang/DesugarMath", "multiplyExact", "(JI)J", false);
+      methodVisitor.visitVarInsn(LSTORE, 5);
+      Label label6 = new Label();
+      methodVisitor.visitLabel(label6);
+      methodVisitor.visitLineNumber(1226, label6);
+      methodVisitor.visitVarInsn(LLOAD, 5);
+      methodVisitor.visitVarInsn(LLOAD, 3);
+      methodVisitor.visitLdcInsn(new Long(1000000L));
+      methodVisitor.visitInsn(LDIV);
+      methodVisitor.visitMethodInsn(
+          INVOKESTATIC, "java/lang/DesugarMath", "addExact", "(JJ)J", false);
+      methodVisitor.visitVarInsn(LSTORE, 5);
+      Label label7 = new Label();
+      methodVisitor.visitLabel(label7);
+      methodVisitor.visitLineNumber(1227, label7);
+      methodVisitor.visitVarInsn(LLOAD, 5);
+      methodVisitor.visitInsn(LRETURN);
+      Label label8 = new Label();
+      methodVisitor.visitLabel(label8);
+      methodVisitor.visitLocalVariable("this", "Ljava/time/Duration;", null, label0, label8, 0);
+      methodVisitor.visitLocalVariable("tempSeconds", "J", null, label1, label8, 1);
+      methodVisitor.visitLocalVariable("tempNanos", "J", null, label2, label8, 3);
+      methodVisitor.visitLocalVariable("millis", "J", null, label6, label8, 5);
+      methodVisitor.visitMaxs(6, 7);
+      methodVisitor.visitEnd();
+    }
+    classWriter.visitEnd();
+
+    return classWriter.toByteArray();
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetOverrideTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetOverrideTest.java
index 8df7620..3409cfd 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetOverrideTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetOverrideTest.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.desugar.desugaredlibrary;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import java.time.Instant;
@@ -41,6 +42,7 @@
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     String stdout =
         testForD8()
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .addInnerClasses(RetargetOverrideTest.class)
             .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
             .setMinApi(parameters.getApiLevel())
@@ -61,6 +63,7 @@
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     String stdout =
         testForR8(Backend.DEX)
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .addKeepMainRule(Executor.class)
             .addInnerClasses(RetargetOverrideTest.class)
             .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/SimpleStreamTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/SimpleStreamTest.java
index aec1045..60fb964 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/SimpleStreamTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/SimpleStreamTest.java
@@ -5,6 +5,8 @@
 package com.android.tools.r8.desugar.desugaredlibrary;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
 import java.util.ArrayList;
@@ -38,6 +40,7 @@
   public void testStreamD8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(SimpleStreamTest.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -55,6 +58,7 @@
   public void testStreamR8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(Backend.DEX)
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(SimpleStreamTest.class)
         .setMinApi(parameters.getApiLevel())
         .addKeepClassAndMembersRules(Executor.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/SpliteratorTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/SpliteratorTest.java
index 5af29c3..738d9d4 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/SpliteratorTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/SpliteratorTest.java
@@ -7,6 +7,8 @@
 import static junit.framework.TestCase.assertTrue;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import java.util.ArrayList;
@@ -49,6 +51,7 @@
   public void testSpliterator() throws Exception {
     Assume.assumeTrue(requiresEmulatedInterfaceCoreLibDesugaring(parameters));
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(SpliteratorTest.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/StaticInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/StaticInterfaceMethodTest.java
index c9b2a93..9c06716 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/StaticInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/StaticInterfaceMethodTest.java
@@ -7,6 +7,8 @@
 import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
 import java.nio.file.Path;
@@ -50,6 +52,7 @@
     }
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(StaticInterfaceMethodTest.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -109,6 +112,7 @@
     Assume.assumeFalse(parameters.isCfRuntime());
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addKeepMainRule(Executor.class)
         .addInnerClasses(StaticInterfaceMethodTest.class)
         .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/SynchronizedCollectionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/SynchronizedCollectionTest.java
index 27a8590..feaa98a 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/SynchronizedCollectionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/SynchronizedCollectionTest.java
@@ -6,7 +6,6 @@
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestRuntime.CfVm;
-import com.android.tools.r8.TestShrinkerBuilder;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
@@ -59,6 +58,7 @@
     }
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addProgramFiles(INPUT_JAR)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -79,6 +79,7 @@
     Assume.assumeFalse(parameters.isCfRuntime());
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addProgramFiles(INPUT_JAR)
         .addKeepMainRule(MAIN_CLASS)
         .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/APIConversionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/APIConversionTest.java
index dc13cb2..3a864c2 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/APIConversionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/APIConversionTest.java
@@ -7,6 +7,7 @@
 import static org.hamcrest.core.StringContains.containsString;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
@@ -30,7 +31,7 @@
 
   private static final AndroidApiLevel MIN_SUPPORTED = AndroidApiLevel.N;
   private static final String EXPECTED_RESULT =
-      StringUtils.lines("[5, 6, 7]", "j$.wrappers.$r8$wrapper$java$util$stream$IntStream$-V-WRP");
+      StringUtils.lines("[5, 6, 7]", "j$.util.stream.IntStream$VivifiedWrapper");
 
   @Parameters(name = "{0}, shrinkDesugaredLibrary: {1}")
   public static List<Object[]> data() {
@@ -63,6 +64,7 @@
   public void testAPIConversionDesugaringD8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(APIConversionTest.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/AllOptionalConversionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/AllOptionalConversionTest.java
index 75d46fe..e301fd1 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/AllOptionalConversionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/AllOptionalConversionTest.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.desugar.desugaredlibrary.conversiontests;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
@@ -64,6 +65,7 @@
   public void testRewrittenAPICallsD8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .setMinApi(parameters.getApiLevel())
         .addProgramClasses(Executor.class)
         .addLibraryClasses(CustomLibClass.class)
@@ -83,6 +85,7 @@
   public void testRewrittenAPICallsR8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .setMinApi(parameters.getApiLevel())
         .addKeepMainRule(Executor.class)
         .addProgramClasses(Executor.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/AllTimeConversionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/AllTimeConversionTest.java
index 5a03f73..1d79e26 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/AllTimeConversionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/AllTimeConversionTest.java
@@ -9,6 +9,7 @@
 
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
@@ -71,6 +72,7 @@
   public void testRewrittenAPICallsD8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .setMinApi(parameters.getApiLevel())
         .addProgramClasses(Executor.class)
         .addLibraryClasses(CustomLibClass.class)
@@ -92,6 +94,7 @@
   public void testRewrittenAPICallsR8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .setMinApi(parameters.getApiLevel())
         .addKeepMainRule(Executor.class)
         .addProgramClasses(Executor.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/BasicLongDoubleConversionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/BasicLongDoubleConversionTest.java
index 4ac3ccc..3c0ad88 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/BasicLongDoubleConversionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/BasicLongDoubleConversionTest.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.desugar.desugaredlibrary.conversiontests;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
@@ -57,6 +58,7 @@
   public void testRewrittenAPICallsD8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .setMinApi(parameters.getApiLevel())
         .addProgramClasses(Executor.class)
         .addLibraryClasses(CustomLibClass.class)
@@ -76,6 +78,7 @@
   public void testRewrittenAPICallsR8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .setMinApi(parameters.getApiLevel())
         .addProgramClasses(Executor.class)
         .addKeepMainRule(Executor.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/CallBackConversionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/CallBackConversionTest.java
index e23e86d..bf148dc 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/CallBackConversionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/CallBackConversionTest.java
@@ -7,7 +7,9 @@
 import static junit.framework.TestCase.assertEquals;
 import static junit.framework.TestCase.assertTrue;
 
+import com.android.tools.r8.LibraryDesugaringTestConfiguration.AbsentKeepRuleConsumer;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
@@ -87,6 +89,7 @@
   public void testCallBack() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .setMinApi(parameters.getApiLevel())
         .addProgramClasses(Impl.class)
         .addLibraryClasses(CustomLibClass.class)
@@ -108,6 +111,7 @@
     // Use D8 to desugar with Java classfile output.
     Path firstJar =
         testForD8(Backend.CF)
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .setMinApi(parameters.getApiLevel())
             .addProgramClasses(Impl.class)
             .addLibraryClasses(CustomLibClass.class)
@@ -127,6 +131,7 @@
     // Use D8 to desugar with Java classfile output.
     Path secondJar =
         testForD8(Backend.CF)
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .addOptionsModification(
                 options -> options.desugarSpecificOptions().allowAllDesugaredInput = true)
             .setMinApi(parameters.getApiLevel())
@@ -147,6 +152,7 @@
 
     // Convert to DEX without desugaring and run.
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addProgramFiles(firstJar)
         .setMinApi(parameters.getApiLevel())
         .disableDesugaring()
@@ -167,6 +173,7 @@
   public void testCallBackR8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(Backend.DEX)
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addKeepMainRule(Impl.class)
         .noMinification()
         .setMinApi(parameters.getApiLevel())
@@ -185,6 +192,7 @@
   public void testCallBackR8Minifying() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(Backend.DEX)
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addKeepMainRule(Impl.class)
         .setMinApi(parameters.getApiLevel())
         .addProgramClasses(Impl.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ClockAPIConversionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ClockAPIConversionTest.java
index 382f55d..37ed786 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ClockAPIConversionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ClockAPIConversionTest.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.desugar.desugaredlibrary.conversiontests;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
@@ -52,6 +53,7 @@
   public void testClockD8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .setMinApi(parameters.getApiLevel())
         .addProgramClasses(Executor.class)
         .addLibraryClasses(CustomLibClass.class)
@@ -72,6 +74,7 @@
   public void testClockR8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addKeepMainRule(Executor.class)
         .setMinApi(parameters.getApiLevel())
         .addProgramClasses(Executor.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionAndMergeTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionAndMergeTest.java
index ef584d2..e2b5c8b 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionAndMergeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionAndMergeTest.java
@@ -6,6 +6,7 @@
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.StringUtils;
@@ -37,6 +38,7 @@
     Path extra = buildClass(ExtraClass.class);
     Path convClass = buildClass(APIConversionClass.class);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .setMinApi(parameters.getApiLevel())
         .addProgramFiles(extra, convClass)
         .enableCoreLibraryDesugaring(parameters.getApiLevel())
@@ -48,6 +50,7 @@
 
   private Path buildClass(Class<?> cls) throws Exception {
     return testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .setMinApi(parameters.getApiLevel())
         .addProgramClasses(cls)
         .enableCoreLibraryDesugaring(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionErrorMessageTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionErrorMessageTest.java
index bdd9f5d..3976a4f 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionErrorMessageTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionErrorMessageTest.java
@@ -6,6 +6,7 @@
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.StringUtils;
@@ -75,6 +76,7 @@
     //  NoSuchMethodError instead of NoClassDefFoundError on the wrapper.
     Assume.assumeTrue(hasRequiredAPI());
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addProgramClasses(Executor.class, MyIntUnaryOperator.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java
index 5cd8c8d..9264433 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java
@@ -9,6 +9,7 @@
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
@@ -79,6 +80,7 @@
   public void testNoInterfaceMethodsD8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .setMinApi(parameters.getApiLevel())
         .addProgramClasses(MyCollectionInterface.class, MyCollection.class, Executor.class)
         .addLibraryClasses(CustomLibClass.class)
@@ -142,6 +144,7 @@
   public void testNoInterfaceMethodsR8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .setMinApi(parameters.getApiLevel())
         .addProgramClasses(MyCollectionInterface.class, MyCollection.class, Executor.class)
         .addKeepMainRule(Executor.class)
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 9a251a9..160726b 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
@@ -8,6 +8,7 @@
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestRuntime.DexRuntime;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.DexVm;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
 import com.android.tools.r8.utils.AndroidApiLevel;
@@ -54,6 +55,7 @@
               .writeToZip();
       String stdOut =
           testForD8()
+              .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
               .setMinApi(AndroidApiLevel.B)
               .addProgramClasses(Executor.class)
               .addLibraryClasses(CustomLibClass.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIProgramTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIProgramTest.java
index a96a874..38b7c3f 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIProgramTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIProgramTest.java
@@ -7,6 +7,7 @@
 import static junit.framework.TestCase.assertEquals;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
@@ -56,6 +57,7 @@
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     String stdOut =
         testForD8()
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .setMinApi(parameters.getApiLevel())
             .addProgramClasses(Executor.class, MyMap.class)
             .addLibraryClasses(CustomLibClass.class)
@@ -79,6 +81,7 @@
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     String stdOut =
         testForR8(parameters.getBackend())
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .setMinApi(parameters.getApiLevel())
             .addKeepMainRule(Executor.class)
             .addProgramClasses(Executor.class, MyMap.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/FunctionConversionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/FunctionConversionTest.java
index 24588c6..5800cf5 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/FunctionConversionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/FunctionConversionTest.java
@@ -7,6 +7,7 @@
 import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
@@ -64,6 +65,7 @@
   public void testFunctionCompositionD8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .setMinApi(parameters.getApiLevel())
         .addProgramClasses(
             Executor.class, Executor.Object1.class, Executor.Object2.class, Executor.Object3.class)
@@ -86,6 +88,7 @@
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     Path jar =
         testForD8(Backend.CF)
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .setMinApi(parameters.getApiLevel())
             .addProgramClasses(
                 Executor.class,
@@ -131,12 +134,14 @@
   public void testFunctionCompositionR8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .setMinApi(parameters.getApiLevel())
         .addKeepMainRule(Executor.class)
         .addProgramClasses(
             Executor.class, Executor.Object1.class, Executor.Object2.class, Executor.Object3.class)
         .addLibraryClasses(CustomLibClass.class)
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+        .allowStdoutMessages()
         .compile()
         .addDesugaredCoreLibraryRunClassPath(
             this::buildDesugaredLibrary,
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/MoreFunctionConversionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/MoreFunctionConversionTest.java
index 10823c3..ba7f28d 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/MoreFunctionConversionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/MoreFunctionConversionTest.java
@@ -8,6 +8,7 @@
 
 import com.android.tools.r8.D8TestCompileResult;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
@@ -60,6 +61,7 @@
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     D8TestCompileResult compileResult =
         testForD8()
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .setMinApi(parameters.getApiLevel())
             .addProgramClasses(Executor.class)
             .addLibraryClasses(CustomLibClass.class)
@@ -82,6 +84,7 @@
   public void testFunctionR8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .setMinApi(parameters.getApiLevel())
         .addProgramClasses(Executor.class)
         .addKeepMainRule(Executor.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/SummaryStatisticsConversionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/SummaryStatisticsConversionTest.java
index 7fe00d5..4d5f8d1 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/SummaryStatisticsConversionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/SummaryStatisticsConversionTest.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.desugar.desugaredlibrary.conversiontests;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
@@ -68,6 +69,7 @@
   public void testStatsD8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .setMinApi(parameters.getApiLevel())
         .addProgramClasses(Executor.class)
         .addLibraryClasses(CustomLibClass.class)
@@ -87,6 +89,7 @@
   public void testStatsR8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .setMinApi(parameters.getApiLevel())
         .addProgramClasses(Executor.class)
         .addKeepMainRule(Executor.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/SuperAPIConversionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/SuperAPIConversionTest.java
index d4e1c8f..958e8b4 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/SuperAPIConversionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/SuperAPIConversionTest.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.desugar.desugaredlibrary.conversiontests;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
@@ -50,6 +51,7 @@
     Assume.assumeFalse("TODO(b/189435770): fix", shrinkDesugaredLibrary);
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(SuperAPIConversionTest.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -60,7 +62,7 @@
             keepRuleConsumer.get(),
             shrinkDesugaredLibrary)
         .run(parameters.getRuntime(), Executor.class)
-        .assertSuccessWithOutputLines("$r8$wrapper$java$util$stream$IntStream$-V-WRP");
+        .assertSuccessWithOutputLines("IntStream$VivifiedWrapper");
   }
 
   @Test
@@ -68,6 +70,7 @@
     Assume.assumeFalse("TODO(b/189435770): fix", shrinkDesugaredLibrary);
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(SuperAPIConversionTest.class)
         .setMinApi(parameters.getApiLevel())
         .addKeepMainRule(Executor.class)
@@ -79,7 +82,7 @@
             keepRuleConsumer.get(),
             shrinkDesugaredLibrary)
         .run(parameters.getRuntime(), Executor.class)
-        .assertSuccessWithOutputLines("$r8$wrapper$java$util$stream$IntStream$-V-WRP");
+        .assertSuccessWithOutputLines("IntStream$VivifiedWrapper");
   }
 
   static class ParallelRandom extends Random {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/TryCatchTimeConversionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/TryCatchTimeConversionTest.java
index 4dbcccb..b7c33c4 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/TryCatchTimeConversionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/TryCatchTimeConversionTest.java
@@ -5,8 +5,8 @@
 package com.android.tools.r8.desugar.desugaredlibrary.conversiontests;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
-import com.android.tools.r8.desugar.desugaredlibrary.conversiontests.SummaryStatisticsConversionTest.CustomLibClass;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
@@ -75,6 +75,7 @@
   public void testBaselineR8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .setMinApi(parameters.getApiLevel())
         .addProgramClasses(BaselineExecutor.class)
         .addKeepMainRule(BaselineExecutor.class)
@@ -114,6 +115,7 @@
   public void testTryCatchR8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .setMinApi(parameters.getApiLevel())
         .addProgramClasses(TryCatchExecutor.class)
         .addKeepMainRule(TryCatchExecutor.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/UnwrapConversionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/UnwrapConversionTest.java
index 2f10f3a..ed2db6a 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/UnwrapConversionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/UnwrapConversionTest.java
@@ -5,8 +5,8 @@
 package com.android.tools.r8.desugar.desugaredlibrary.conversiontests;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
-import com.android.tools.r8.desugar.desugaredlibrary.conversiontests.SummaryStatisticsConversionTest.CustomLibClass;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
@@ -54,6 +54,7 @@
   public void testUnwrapD8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .setMinApi(parameters.getApiLevel())
         .addProgramClasses(Executor.class)
         .addLibraryClasses(CustomLibClass.class)
@@ -73,6 +74,7 @@
   public void testUnwrapR8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .setMinApi(parameters.getApiLevel())
         .addProgramClasses(Executor.class)
         .addKeepMainRule(Executor.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/WrapperPlacementTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/WrapperPlacementTest.java
index cbab10c..c4d1f98 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/WrapperPlacementTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/WrapperPlacementTest.java
@@ -10,8 +10,9 @@
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
-import com.android.tools.r8.ir.desugar.DesugaredLibraryWrapperSynthesizer;
+import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
 import com.android.tools.r8.testing.AndroidBuildVersion;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.StringUtils;
@@ -61,6 +62,7 @@
     Path path1 = compileWithCoreLibraryDesugaring(MyArrays1.class);
     Path path2 = compileWithCoreLibraryDesugaring(MyArrays2.class);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addProgramClasses(TestClass.class)
         .addAndroidBuildVersion()
         .enableCoreLibraryDesugaring(parameters.getApiLevel())
@@ -83,6 +85,7 @@
 
   private Path compileWithCoreLibraryDesugaring(Class<?> clazz) throws Exception {
     return testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addProgramClassesAndInnerClasses(clazz)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel())
@@ -108,8 +111,7 @@
 
   private Stream<FoundClassSubject> getWrappers(CodeInspector inspector) {
     return inspector.allClasses().stream()
-        .filter(
-            c -> c.getOriginalName().contains(DesugaredLibraryWrapperSynthesizer.WRAPPER_PREFIX));
+        .filter(c -> SyntheticItemsTestUtils.isWrapper(c.getOriginalReference()));
   }
 
   static class MyArrays1 {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/ConcurrentHashMapFileSerializationTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/ConcurrentHashMapFileSerializationTest.java
index db361d4..5c1e73d 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/ConcurrentHashMapFileSerializationTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/ConcurrentHashMapFileSerializationTest.java
@@ -5,8 +5,10 @@
 package com.android.tools.r8.desugar.desugaredlibrary.gson;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.DexVm.Version;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
 import java.io.File;
@@ -52,6 +54,7 @@
   public void testMapSerializationD8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(ConcurrentHashMapFileSerializationTest.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -71,6 +74,7 @@
   public void testMapSerializationR8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(Backend.DEX)
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(ConcurrentHashMapFileSerializationTest.class)
         .addKeepMainRule(Executor.class)
         .noMinification()
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GetGenericInterfaceTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GetGenericInterfaceTest.java
index 70dab5d..fd1b30b 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GetGenericInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GetGenericInterfaceTest.java
@@ -8,6 +8,7 @@
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
@@ -52,6 +53,7 @@
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     String stdOut =
         testForD8()
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .addInnerClasses(GetGenericInterfaceTest.class)
             .setMinApi(parameters.getApiLevel())
             .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -72,6 +74,7 @@
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     String stdOut =
         testForR8(Backend.DEX)
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .addInnerClasses(GetGenericInterfaceTest.class)
             .addKeepMainRule(Executor.class)
             .noMinification()
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GsonAllMapsTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GsonAllMapsTest.java
index d5a6637..a6a460d 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GsonAllMapsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GsonAllMapsTest.java
@@ -4,6 +4,8 @@
 package com.android.tools.r8.desugar.desugaredlibrary.gson;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import java.util.List;
 import org.junit.Assume;
@@ -38,6 +40,7 @@
     Assume.assumeTrue(requiresEmulatedInterfaceCoreLibDesugaring(parameters));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addProgramClassesAndInnerClasses(AllMapsTestClass.class)
         .addProgramFiles(GSON_2_8_1_JAR)
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -57,6 +60,7 @@
     Assume.assumeTrue(requiresEmulatedInterfaceCoreLibDesugaring(parameters));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addProgramClassesAndInnerClasses(AllMapsTestClass.class)
         .addProgramFiles(GSON_2_8_1_JAR)
         .addKeepMainRule(AllMapsTestClass.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GsonEnumTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GsonEnumTest.java
index d71b536..584c3f3 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GsonEnumTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GsonEnumTest.java
@@ -5,7 +5,9 @@
 package com.android.tools.r8.desugar.desugaredlibrary.gson;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import java.lang.reflect.Field;
 import java.time.chrono.IsoEra;
@@ -36,6 +38,7 @@
   public void testCustomCollectionD8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(GsonEnumTest.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -53,6 +56,7 @@
   public void testCustomCollectionR8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(Backend.DEX)
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(GsonEnumTest.class)
         .addKeepMainRule(Executor.class)
         .noMinification()
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GsonOptionalTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GsonOptionalTest.java
index 62cf8d2..39c6644 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GsonOptionalTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GsonOptionalTest.java
@@ -4,6 +4,8 @@
 package com.android.tools.r8.desugar.desugaredlibrary.gson;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import java.util.List;
 import org.junit.Assume;
@@ -32,6 +34,7 @@
     Assume.assumeTrue(requiresEmulatedInterfaceCoreLibDesugaring(parameters));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addProgramClassesAndInnerClasses(OptionalTestClass.class)
         .addProgramFiles(GSON_2_8_1_JAR)
         .addOptionsModification(opt -> opt.ignoreMissingClasses = true)
@@ -52,6 +55,7 @@
     Assume.assumeTrue(requiresEmulatedInterfaceCoreLibDesugaring(parameters));
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addProgramClassesAndInnerClasses(OptionalTestClass.class)
         .addProgramFiles(GSON_2_8_1_JAR)
         .addKeepMainRule(OptionalTestClass.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/MyMapFileSerializationTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/MyMapFileSerializationTest.java
index 42844c1..01c1b44 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/MyMapFileSerializationTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/MyMapFileSerializationTest.java
@@ -5,8 +5,10 @@
 package com.android.tools.r8.desugar.desugaredlibrary.gson;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.DexVm.Version;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
 import java.io.File;
@@ -50,6 +52,7 @@
   public void testMapSerializationD8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(MyMapFileSerializationTest.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -69,6 +72,7 @@
   public void testMapSerializationR8() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForR8(Backend.DEX)
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addInnerClasses(MyMapFileSerializationTest.class)
         .addKeepMainRule(Executor.class)
         .noMinification()
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11AtomicTests.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11AtomicTests.java
index 03995ac..e1849dc 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11AtomicTests.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11AtomicTests.java
@@ -76,6 +76,7 @@
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     String verbosity = "2";
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addProgramFiles(
             ATOMIC_COMPILED_TESTS_FOLDER.resolve(ATOMIC_REFERENCE_TEST + CLASS_EXTENSION))
         .addProgramFiles(testNGSupportProgramFiles())
@@ -99,6 +100,7 @@
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     String verbosity = "2";
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addProgramFiles(
             getAllFilesWithSuffixInDirectory(ATOMIC_COMPILED_TESTS_FOLDER, CLASS_EXTENSION))
         .addProgramFiles(testNGSupportProgramFiles())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11ConcurrentMapTests.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11ConcurrentMapTests.java
index 7d0fc6b..9123915 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11ConcurrentMapTests.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11ConcurrentMapTests.java
@@ -163,6 +163,7 @@
     String verbosity = "2";
     D8TestCompileResult d8TestCompileResult =
         testForD8()
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .addProgramFiles(concurrentHashTestToCompile())
             .addProgramFiles(testNGSupportProgramFiles())
             .addProgramFiles(getPathsFiles())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeTests.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeTests.java
index 6288598..c8ddd5d 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeTests.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeTests.java
@@ -10,6 +10,7 @@
 import com.android.tools.r8.D8TestCompileResult;
 import com.android.tools.r8.D8TestRunResult;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.DexVm.Version;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
@@ -137,6 +138,7 @@
     String verbosity = "2";
     D8TestCompileResult compileResult =
         testForD8()
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .addProgramFiles(getPathsFiles())
             .addProgramFiles(Paths.get(JDK_TESTS_BUILD_DIR + "jdk11TimeTests.jar"))
             .addProgramFiles(Paths.get(JDK_TESTS_BUILD_DIR + "testng-6.10.jar"))
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java
index 55e2905..c7fc371 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java
@@ -27,6 +27,7 @@
 import com.android.tools.r8.kotlin.KotlinMetadataWriter;
 import com.android.tools.r8.kotlin.metadata.KotlinMetadataTestBase;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.FileUtils;
@@ -94,6 +95,7 @@
     final File output = temp.newFile("output.zip");
     final D8TestRunResult d8TestRunResult =
         testForD8()
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .addProgramFiles(compiledJars.getForConfiguration(kotlinParameters))
             .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinParameters.getCompiler()))
             .addProgramFiles(ToolHelper.getKotlinReflectJar(kotlinParameters.getCompiler()))
@@ -123,6 +125,7 @@
     boolean desugarLibrary = parameters.isDexRuntime() && requiresAnyCoreLibDesugaring(parameters);
     final R8FullTestBuilder testBuilder =
         testForR8(parameters.getBackend())
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .addProgramFiles(compiledJars.getForConfiguration(kotlinParameters))
             .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinParameters.getCompiler()))
             .addProgramFiles(ToolHelper.getKotlinReflectJar(kotlinParameters.getCompiler()))
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/r8ondex/HelloWorldCompiledOnArtTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/r8ondex/HelloWorldCompiledOnArtTest.java
index cd8ec64..537b873 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/r8ondex/HelloWorldCompiledOnArtTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/r8ondex/HelloWorldCompiledOnArtTest.java
@@ -128,6 +128,7 @@
     }
     D8TestCompileResult compile =
         d8TestBuilder
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .setMinApi(parameters.getApiLevel())
             .enableCoreLibraryDesugaring(parameters.getApiLevel())
             .addOptionsModification(opt -> opt.testing.trackDesugaredAPIConversions = true)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/EnumSetTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/EnumSetTest.java
index 454adc7..bdc2b91 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/EnumSetTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/EnumSetTest.java
@@ -5,7 +5,9 @@
 package com.android.tools.r8.desugar.desugaredlibrary.shrinkingtests;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
 import java.time.DayOfWeek;
@@ -39,6 +41,7 @@
   public void testEnum() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addProgramClasses(EnumSetUser.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/FieldAccessTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/FieldAccessTest.java
index aabd492..2b57223 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/FieldAccessTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/FieldAccessTest.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.desugar.desugaredlibrary.shrinkingtests;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
@@ -37,6 +38,7 @@
   public void testField() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addProgramClasses(Executor.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/InheritanceTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/InheritanceTest.java
index 5d9e5e7..f314581 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/InheritanceTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/InheritanceTest.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.desugar.desugaredlibrary.shrinkingtests;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
@@ -39,6 +40,7 @@
   public void testInheritance() throws Exception {
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     testForD8()
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addProgramClasses(Impl.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/KeepRuleShrinkTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/KeepRuleShrinkTest.java
index 391cd8d..fa6a0c6 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/KeepRuleShrinkTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/shrinkingtests/KeepRuleShrinkTest.java
@@ -6,6 +6,7 @@
 
 import com.android.tools.r8.D8TestRunResult;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
@@ -41,6 +42,7 @@
     KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
     D8TestRunResult d8TestRunResult =
         testForD8()
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
             .addInnerClasses(KeepRuleShrinkTest.class)
             .setMinApi(parameters.getApiLevel())
             .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/MethodParametersTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/MethodParametersTest.java
index 8bec281..30dc93f 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/MethodParametersTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/MethodParametersTest.java
@@ -4,8 +4,9 @@
 package com.android.tools.r8.desugar.nestaccesscontrol;
 
 import static com.android.tools.r8.TestRuntime.getCheckedInJdk11;
-import static org.hamcrest.CoreMatchers.anyOf;
-import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -13,7 +14,11 @@
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.DexVm.Version;
 import com.android.tools.r8.desugar.nestaccesscontrol.methodparameters.Outer;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
 import java.nio.file.Path;
+import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -51,6 +56,8 @@
             .addProgramFiles(nestCompiledWithParameters)
             .setMinApi(parameters.getApiLevel())
             .compile()
+            .assertNoMessages()
+            .inspect(this::verifyNoAnnotationsOnSyntheticConstructors)
             .writeToZip();
 
     Path nestDesugaredTwice =
@@ -58,12 +65,8 @@
             .addProgramFiles(nestDesugared)
             .setMinApi(parameters.getApiLevel())
             .compile()
-            // TODO(b/189743726): These warnings should not be there.
-            .assertAtLeastOneInfoMessage()
-            .assertAllInfoMessagesMatch(
-                anyOf(
-                    containsString("Invalid parameter counts in MethodParameter attributes"),
-                    containsString("Methods with invalid MethodParameter attributes")))
+            .assertNoMessages()
+            .inspect(this::verifyNoAnnotationsOnSyntheticConstructors)
             .writeToZip();
 
     Path programDesugared =
@@ -72,6 +75,7 @@
             .addInnerClasses(getClass())
             .setMinApi(parameters.getApiLevel())
             .compile()
+            .assertNoMessages()
             .writeToZip();
 
     testForD8(parameters.getBackend())
@@ -79,16 +83,47 @@
         .addProgramFiles(programDesugared)
         .setMinApi(parameters.getApiLevel())
         .compile()
-        // TODO(b/189743726): These warnings should not be there.
-        .assertAtLeastOneInfoMessage()
-        .assertAllInfoMessagesMatch(
-            anyOf(
-                containsString("Invalid parameter counts in MethodParameter attributes"),
-                containsString("Methods with invalid MethodParameter attributes")))
+        .assertNoMessages()
+        .inspect(this::verifyNoAnnotationsOnSyntheticConstructors)
         .run(parameters.getRuntime(), TestRunner.class)
-        // TODO(b/189743726): Should not fail at runtime.
-        .assertFailureWithErrorThatMatches(
-            containsString("Wrong number of parameters in MethodParameters attribute"));
+        // Order of constructors is different on dex due to sorting.
+        .applyIf(
+            parameters.isCfRuntime(),
+            result ->
+                result.assertSuccessWithOutputLines(
+                    "int, int, Outer$Inner-IA, 3",
+                    "int, Outer$Inner-IA, 2",
+                    "Outer$Inner-IA, 1",
+                    "int, int, 2",
+                    "int, 1",
+                    "0"),
+            result ->
+                result.assertSuccessWithOutputLines(
+                    "0",
+                    "int, 1",
+                    "int, int, 2",
+                    "int, int, Outer$Inner-IA, 3",
+                    "int, Outer$Inner-IA, 2",
+                    "Outer$Inner-IA, 1"));
+  }
+
+  @Test
+  public void testJavacBridges() throws Exception {
+    assumeTrue(parameters.useRuntimeAsNoneRuntime());
+    verifyNoAnnotationsOnSyntheticConstructors(
+        new CodeInspector(ToolHelper.getClassFileForTestClass(Outer.Inner.class)));
+  }
+
+  private void verifyNoAnnotationsOnSyntheticConstructors(CodeInspector inspector) {
+    ClassSubject innerClassSubject = inspector.clazz(Outer.Inner.class);
+    List<FoundMethodSubject> syntheticInitializers =
+        innerClassSubject.allMethods(
+            method -> method.isInstanceInitializer() && method.isSynthetic());
+    assertEquals(3, syntheticInitializers.size());
+    syntheticInitializers.forEach(
+        syntheticInitializer ->
+            assertTrue(
+                syntheticInitializer.getProgramMethod().getDefinition().annotations().isEmpty()));
   }
 
   static class TestRunner {
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestPrivateInterfaceMethodsTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestPrivateInterfaceMethodsTest.java
new file mode 100644
index 0000000..ae2b6ae
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestPrivateInterfaceMethodsTest.java
@@ -0,0 +1,78 @@
+// 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.desugar.nestaccesscontrol;
+
+import com.android.tools.r8.DesugarTestConfiguration;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class NestPrivateInterfaceMethodsTest extends TestBase {
+
+  static final String EXPECTED = StringUtils.lines("Hello world!");
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build();
+  }
+
+  public NestPrivateInterfaceMethodsTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  private byte[] getClassWithNest(Class<?> clazz) throws Exception {
+    return transformer(clazz)
+        .setNest(I.class, J.class)
+        .setAccessFlags(
+            I.class.getMethod("foo"),
+            flags -> {
+              flags.unsetPublic();
+              flags.setPrivate();
+            })
+        .transform();
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForDesugaring(parameters)
+        .addProgramClasses(TestClass.class)
+        .addProgramClassFileData(getClassWithNest(I.class), getClassWithNest(J.class))
+        .run(parameters.getRuntime(), TestClass.class)
+        // TODO(191115349): Nest desugar does not downgrade the classfile version.
+        .applyIf(
+            c ->
+                DesugarTestConfiguration.isNotJavac(c)
+                    || parameters.getRuntime().asCf().isNewerThanOrEqual(CfVm.JDK11),
+            r -> r.assertSuccessWithOutput(EXPECTED),
+            r -> r.assertFailureWithErrorThatThrows(UnsupportedClassVersionError.class));
+  }
+
+  interface I {
+    default /* will be private */ void foo() {
+      System.out.println("Hello world!");
+    }
+  }
+
+  interface J {
+    default void bar(I o) {
+      o.foo();
+    }
+  }
+
+  static class TestClass implements I, J {
+
+    public static void main(String[] args) {
+      TestClass o = new TestClass();
+      o.bar(o);
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/methodparameters/Outer.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/methodparameters/Outer.java
index 9c92994..369aff3 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/methodparameters/Outer.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/methodparameters/Outer.java
@@ -3,21 +3,37 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.desugar.nestaccesscontrol.methodparameters;
 
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 import java.lang.reflect.Constructor;
+import java.lang.reflect.Parameter;
 
 public class Outer {
   public static class Inner {
+    @MyAnnotation
     private Inner() {
       for (Constructor<?> constructor : getClass().getDeclaredConstructors()) {
+        for (Parameter parameter : constructor.getParameters()) {
+          System.out.print(parameter.getType().getSimpleName());
+          System.out.print(", ");
+        }
         System.out.println(constructor.getParameters().length);
       }
     }
 
+    @MyAnnotation
     private Inner(int a) {}
 
+    @MyAnnotation
     private Inner(int a, int b) {}
   }
 
+  @Retention(RetentionPolicy.RUNTIME)
+  @Target(ElementType.CONSTRUCTOR)
+  @interface MyAnnotation {}
+
   public static Inner callPrivateInnerConstructorZeroArgs() {
     return new Inner();
   }
diff --git a/src/test/java/com/android/tools/r8/internal/YouTubeV1612Test.java b/src/test/java/com/android/tools/r8/internal/YouTubeV1612Test.java
index f2fe2b8..830d6fc 100644
--- a/src/test/java/com/android/tools/r8/internal/YouTubeV1612Test.java
+++ b/src/test/java/com/android/tools/r8/internal/YouTubeV1612Test.java
@@ -16,6 +16,7 @@
 
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.L8TestCompileResult;
+import com.android.tools.r8.LibraryDesugaringTestConfiguration.PresentKeepRuleConsumer;
 import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.R8TestCompileResult;
 import com.android.tools.r8.ResourceException;
diff --git a/src/test/java/com/android/tools/r8/internal/YouTubeV1620Test.java b/src/test/java/com/android/tools/r8/internal/YouTubeV1620Test.java
index c1182bd..0b76040 100644
--- a/src/test/java/com/android/tools/r8/internal/YouTubeV1620Test.java
+++ b/src/test/java/com/android/tools/r8/internal/YouTubeV1620Test.java
@@ -16,6 +16,7 @@
 
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.L8TestCompileResult;
+import com.android.tools.r8.LibraryDesugaringTestConfiguration.PresentKeepRuleConsumer;
 import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.R8TestCompileResult;
 import com.android.tools.r8.ResourceException;
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/backports/GenerateBackportMethods.java b/src/test/java/com/android/tools/r8/ir/desugar/backports/GenerateBackportMethods.java
index 455c5c2..5e79870 100644
--- a/src/test/java/com/android/tools/r8/ir/desugar/backports/GenerateBackportMethods.java
+++ b/src/test/java/com/android/tools/r8/ir/desugar/backports/GenerateBackportMethods.java
@@ -75,7 +75,7 @@
 
   @Override
   protected int getYear() {
-    return 2020;
+    return 2021;
   }
 
   private static CfInstruction rewriteToJava9API(
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/backports/ObjectsMethods.java b/src/test/java/com/android/tools/r8/ir/desugar/backports/ObjectsMethods.java
index 97e896e..566d8f2 100644
--- a/src/test/java/com/android/tools/r8/ir/desugar/backports/ObjectsMethods.java
+++ b/src/test/java/com/android/tools/r8/ir/desugar/backports/ObjectsMethods.java
@@ -71,6 +71,18 @@
     return obj;
   }
 
+  public static <T> T requireNonNullSupplier(T obj, Supplier<String> messageSupplier) {
+    if (obj == null) {
+      // While calling `messageSupplier.get()` unconditionally would produce the correct behavior,
+      // some ART versions add an exception message to seemingly-unintended null dereferences along
+      // the lines of "Attempted to invoke interface method Supplier.get() on a null reference"
+      // which we don't want to expose as the reference implementation has a null message.
+      String message = messageSupplier != null ? messageSupplier.get() : null;
+      throw new NullPointerException(message);
+    }
+    return obj;
+  }
+
   public static <T> T requireNonNullElse(T obj, T defaultObj) {
     if (obj != null) return obj;
     return Objects.requireNonNull(defaultObj, "defaultObj");
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineMethodWithRetargetedLibMemberTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineMethodWithRetargetedLibMemberTest.java
index 415a868..70c10da 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineMethodWithRetargetedLibMemberTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineMethodWithRetargetedLibMemberTest.java
@@ -11,6 +11,8 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import java.util.Arrays;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,6 +36,7 @@
   @Test
   public void test() throws Exception {
     testForR8(parameters.getBackend())
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
         .addProgramClasses(TestClass.class)
         .addKeepMainRule(TestClass.class)
         .enableCoreLibraryDesugaring(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/conditionalsimpleinlining/NopInliningConstraintTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/conditionalsimpleinlining/NopInliningConstraintTest.java
new file mode 100644
index 0000000..3295203
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/conditionalsimpleinlining/NopInliningConstraintTest.java
@@ -0,0 +1,108 @@
+// 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.ir.optimize.inliner.conditionalsimpleinlining;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.AlwaysInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeMatchers;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class NopInliningConstraintTest extends TestBase {
+
+  @Parameter public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(getClass())
+        .addKeepMainRule(Main.class)
+        .enableAlwaysInliningAnnotations()
+        .enableInliningAnnotations()
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .inspect(
+            inspector -> {
+              ClassSubject mainClassSubject = inspector.clazz(Main.class);
+              assertThat(mainClassSubject, isPresent());
+
+              // Method doStuff() is inlined into main().
+              assertThat(mainClassSubject.uniqueMethodWithName("doStuff"), isAbsent());
+
+              // Method checkNotNull() is not inlined.
+              MethodSubject checkNotNullMethodSubject =
+                  mainClassSubject.uniqueMethodWithName("checkNotNull");
+              assertThat(checkNotNullMethodSubject, isPresent());
+
+              // There is a single call to checkNotNull() in main(), as checkNotNull(newObject())
+              // is dead code eliminated.
+              assertEquals(
+                  1,
+                  mainClassSubject
+                      .mainMethod()
+                      .streamInstructions()
+                      .filter(CodeMatchers.isInvokeWithTarget(checkNotNullMethodSubject))
+                      .count());
+            })
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines(
+            "Caught NPE: Parameter specified as non-null is null: method "
+                + Main.class.getTypeName()
+                + ".main, parameter o");
+  }
+
+  static class Main {
+    public static void main(String[] args) {
+      doStuff(new Object());
+      try {
+        doStuff(null);
+      } catch (NullPointerException e) {
+        System.out.println("Caught NPE: " + e.getMessage());
+      }
+    }
+
+    @AlwaysInline
+    static void doStuff(Object o) {
+      checkNotNull(o, "o");
+    }
+
+    @NeverInline
+    static void checkNotNull(Object o, String parameterName) {
+      if (o != null) {
+        return;
+      }
+      StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
+      int callerStackTraceElementIndex =
+          stackTrace[0].getMethodName().equals("getThreadStackTrace") ? 3 : 2;
+      StackTraceElement callerStackTraceElement = stackTrace[callerStackTraceElementIndex];
+      throw new NullPointerException(
+          "Parameter specified as non-null is null: method "
+              + callerStackTraceElement.getClassName()
+              + "."
+              + callerStackTraceElement.getMethodName()
+              + ", parameter "
+              + parameterName);
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinIntrinsicsInlineTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinIntrinsicsInlineTest.java
index 872b5f0..f6cc385 100644
--- a/src/test/java/com/android/tools/r8/kotlin/KotlinIntrinsicsInlineTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinIntrinsicsInlineTest.java
@@ -130,10 +130,10 @@
               MethodSubject method = main.uniqueMethodWithName(methodName);
               assertThat(method, isPresent());
               int arity = method.getMethod().getReference().getArity();
-              // One from the method's own argument, if any, and
-              // Two from Array utils, `contains` and `indexOf`, if inlined with access relaxation.
+              // One for each of the method's own arguments, unless building with
+              // -allowaccessmodification.
               assertEquals(
-                  allowAccessModification ? 0 : arity + 2,
+                  allowAccessModification ? 0 : arity,
                   countCall(method, "checkParameterIsNotNull"));
             });
   }
diff --git a/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java b/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java
index 4769427..e83626b 100644
--- a/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java
@@ -91,7 +91,7 @@
               // ?: in aOrDefault
               // TODO(b/179951729): Not the same amount of ifz on CF and DEX.
               assertEquals(testParameters.isCfRuntime() ? 0 : 1, ifzCount);
-              assertEquals(allowAccessModification ? 0 : 1, paramNullCheckCount);
+              assertEquals(0, paramNullCheckCount);
             });
   }
 
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexRemovedAnnotationTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexRemovedAnnotationTest.java
index 67b113c..589a1e2 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexRemovedAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexRemovedAnnotationTest.java
@@ -13,6 +13,7 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -43,7 +44,7 @@
   @Test
   public void testMainDexTracing() throws Exception {
     testForR8(parameters.getBackend())
-        .addProgramClasses(MainDex.class, Inside.class, Main.class)
+        .addProgramClasses(MainDex.class, Inside.class, Dead.class, Main.class)
         .addKeepClassAndMembersRules(Main.class)
         .setMinApi(parameters.getApiLevel())
         .enableInliningAnnotations()
@@ -51,13 +52,11 @@
         .collectMainDexClasses()
         .compile()
         .inspectMainDexClasses(
-            mainDexClasses -> {
-              // TODO(b/190623364): Should not be empty.
-              assertTrue(mainDexClasses.isEmpty());
-            })
-        .inspect(
-            codeInspector -> {
-              assertThat(codeInspector.clazz(MainDex.class), not(isPresent()));
+            (inspector, mainDexClasses) -> {
+              ClassSubject inside = inspector.clazz(Inside.class);
+              assertThat(inside, isPresent());
+              assertTrue(mainDexClasses.contains(inside.getFinalName()));
+              assertThat(inspector.clazz(MainDex.class), not(isPresent()));
             })
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines("Hello World!");
@@ -76,6 +75,11 @@
     }
   }
 
+  @MainDex
+  public static class Dead {
+    // Will be removed during first round of tree-pruning.
+  }
+
   public static class Main {
 
     public static void main(String[] args) {
diff --git a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByReferenceInAnnotationTest.java b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByReferenceInAnnotationTest.java
new file mode 100644
index 0000000..137706a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByReferenceInAnnotationTest.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.shaking.keptgraph;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.MethodReferenceUtils;
+import com.android.tools.r8.utils.graphinspector.GraphInspector.QueryNode;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class KeptByReferenceInAnnotationTest extends TestBase {
+
+  @Parameter public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(getClass())
+        .addKeepMainRule(Main.class)
+        .addKeepRuntimeVisibleAnnotations()
+        .enableGraphInspector()
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .inspectGraph(
+            inspector -> {
+              QueryNode keepMainMethodRule = inspector.rule(Origin.unknown(), 1, 1).assertRoot();
+
+              QueryNode mainClassNode =
+                  inspector
+                      .clazz(Main.class)
+                      .assertPresent()
+                      .assertNotRenamed()
+                      .assertKeptBy(keepMainMethodRule);
+
+              // The main() method is kept by the -keep rule.
+              QueryNode mainMethodNode =
+                  inspector
+                      .method(MethodReferenceUtils.mainMethod(Main.class))
+                      .assertPresent()
+                      .assertNotRenamed()
+                      .assertKeptBy(keepMainMethodRule);
+
+              // MyAnnotation is referenced from main() and is also used to annotate class Main.
+              QueryNode annotationNode =
+                  inspector
+                      .clazz(MyAnnotation.class)
+                      .assertPresent()
+                      .assertRenamed()
+                      .assertKeptBy(mainMethodNode);
+              annotationNode.assertKeptByReferenceInAnnotationOn(annotationNode, mainClassNode);
+
+              // ReferencedInAnnotation is referenced from inside the annotation on class Main.
+              inspector
+                  .clazz(ReferencedInAnnotation.class)
+                  .assertPresent()
+                  .assertRenamed()
+                  .assertKeptByReferenceInAnnotationOn(annotationNode, mainClassNode);
+
+              // Check the presence of an edge from main() to the annotation node.
+              inspector
+                  .annotation(MyAnnotation.class, mainClassNode)
+                  .assertPresent()
+                  .assertKeptByAnnotationOn(mainClassNode);
+            })
+        .run(parameters.getRuntime(), Main.class)
+        .apply(
+            result ->
+                result.assertSuccessWithOutputLines(
+                    result.inspector().clazz(ReferencedInAnnotation.class).getFinalName()));
+  }
+
+  @MyAnnotation(ReferencedInAnnotation.class)
+  static class Main {
+
+    public static void main(String[] args) {
+      MyAnnotation annotation = Main.class.getAnnotation(MyAnnotation.class);
+      System.out.println(annotation.value().getName());
+    }
+  }
+
+  static class ReferencedInAnnotation {}
+
+  @Retention(RetentionPolicy.RUNTIME)
+  @interface MyAnnotation {
+
+    Class<?> value();
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java b/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
index 9e49bc9..dfcf7e8 100644
--- a/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
+++ b/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
@@ -117,6 +117,11 @@
             reference, null, SyntheticKind.HORIZONTAL_INIT_TYPE_ARGUMENT_3);
   }
 
+  public static boolean isWrapper(ClassReference reference) {
+    return SyntheticNaming.isSynthetic(reference, null, SyntheticKind.WRAPPER)
+        || SyntheticNaming.isSynthetic(reference, null, SyntheticKind.VIVIFIED_WRAPPER);
+  }
+
   public static Matcher<String> containsInternalSyntheticReference() {
     return containsString(SyntheticNaming.getPhaseSeparator(Phase.INTERNAL));
   }
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 4ac4f95..1114bce 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
@@ -538,6 +538,7 @@
         codeInspector.getFactory().kotlin, annotationSubject.getAnnotation());
   }
 
+  @Override
   public RetraceClassResult retrace() {
     assertTrue(mapping.getNaming() != null);
     return codeInspector
@@ -545,6 +546,7 @@
         .retraceClass(Reference.classFromTypeName(mapping.getNaming().renamedName));
   }
 
+  @Override
   public RetraceClassElement retraceUnique() {
     RetraceClassResult result = retrace();
     if (result.isAmbiguous()) {
diff --git a/src/test/java/com/android/tools/r8/utils/graphinspector/GraphInspector.java b/src/test/java/com/android/tools/r8/utils/graphinspector/GraphInspector.java
index e51c162..45ffbf2 100644
--- a/src/test/java/com/android/tools/r8/utils/graphinspector/GraphInspector.java
+++ b/src/test/java/com/android/tools/r8/utils/graphinspector/GraphInspector.java
@@ -26,10 +26,12 @@
 import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.references.FieldReference;
 import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.shaking.CollectingGraphConsumer;
 import com.android.tools.r8.utils.Box;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.google.common.collect.ImmutableSet;
+import java.lang.annotation.Annotation;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
@@ -53,6 +55,10 @@
         new EdgeKindPredicate(EdgeKind.ReflectiveUseFrom);
     public static final EdgeKindPredicate isLibraryMethod =
         new EdgeKindPredicate(EdgeKind.IsLibraryMethod);
+    public static final EdgeKindPredicate isAnnotatedOn =
+        new EdgeKindPredicate(EdgeKind.AnnotatedOn);
+    public static final EdgeKindPredicate isReferencedInAnnotation =
+        new EdgeKindPredicate(EdgeKind.ReferencedInAnnotation);
     public static final EdgeKindPredicate overriding =
         new EdgeKindPredicate(EdgeKind.OverridingMethod);
     public static final EdgeKindPredicate compatibilityRule =
@@ -148,6 +154,11 @@
 
     public abstract boolean isPureCompatKeptBy(QueryNode node);
 
+    public abstract boolean isKeptByAnnotationOn(QueryNode annotatedNode);
+
+    public abstract boolean isKeptByReferenceInAnnotationOn(
+        QueryNode annotationNode, QueryNode annotatedNode);
+
     public abstract boolean isKeptByLibraryMethod(QueryNode node);
 
     public abstract boolean isSatisfiedBy(QueryNode... nodes);
@@ -274,14 +285,46 @@
       if (isSatisfiedBy(nodes)) {
         return this;
       }
-      QueryNodeImpl impl = (QueryNodeImpl) this;
+      QueryNodeImpl<?> impl = (QueryNodeImpl<?>) this;
       impl.runSatisfiedBy(Assert::fail, nodes);
       throw new Unreachable();
     }
 
+    public QueryNode assertKeptByAnnotationOn(QueryNode annotatedNode) {
+      assertTrue(
+          "Invalid call to assertKeptByAnnotation with: " + annotatedNode.getNodeDescription(),
+          annotatedNode.isPresent());
+      assertTrue(
+          errorMessage(
+              "kept by annotation on " + annotatedNode.getNodeDescription(),
+              "was not kept by an annotation"),
+          isKeptByAnnotationOn(annotatedNode));
+      return this;
+    }
+
+    public QueryNode assertKeptByReferenceInAnnotationOn(
+        QueryNode annotationNode, QueryNode annotatedNode) {
+      assertTrue(
+          "Invalid call to assertKeptByAnnotation with: " + annotationNode.getNodeDescription(),
+          annotationNode.isPresent());
+      assertTrue(
+          "Invalid call to assertKeptByAnnotation with: " + annotatedNode.getNodeDescription(),
+          annotatedNode.isPresent());
+      assertTrue(
+          errorMessage(
+              "kept by annotation "
+                  + annotationNode.getNodeDescription()
+                  + " on "
+                  + annotatedNode.getNodeDescription(),
+              "was not kept by an annotation"),
+          isKeptByReferenceInAnnotationOn(annotationNode, annotatedNode));
+      return this;
+    }
+
     public QueryNode assertKeptByLibraryMethod(QueryNode node) {
       assertTrue(
-          "Invalid call to assertKeptBy with: " + node.getNodeDescription(), node.isPresent());
+          "Invalid call to assertKeptByLibraryMethod with: " + node.getNodeDescription(),
+          node.isPresent());
       assertTrue(
           errorMessage(
               "kept by library method on " + node.getNodeDescription(),
@@ -376,14 +419,27 @@
     }
 
     @Override
+    public boolean isKeptByAnnotationOn(QueryNode annotatedNode) {
+      fail("Invalid call to isKeptByAnnotationOn on " + getNodeDescription());
+      throw new Unreachable();
+    }
+
+    @Override
+    public boolean isKeptByReferenceInAnnotationOn(
+        QueryNode annotationNode, QueryNode annotatedNode) {
+      fail("Invalid call to isKeptByReferenceInAnnotationOn on " + getNodeDescription());
+      throw new Unreachable();
+    }
+
+    @Override
     public boolean isKeptByLibraryMethod(QueryNode node) {
-      fail("Invalid call to isKeptByLibrary on " + getNodeDescription());
+      fail("Invalid call to isKeptByLibraryMethod on " + getNodeDescription());
       throw new Unreachable();
     }
 
     @Override
     public boolean isSatisfiedBy(QueryNode... nodes) {
-      fail("Invalid call to isTriggeredBy on " + getNodeDescription());
+      fail("Invalid call to isSatisfiedBy on " + getNodeDescription());
       throw new Unreachable();
     }
   }
@@ -391,19 +447,19 @@
   // Class representing a point in the kept-graph structure.
   // The purpose of this class is to tersely specify what relationships are expected between nodes,
   // thus most methods will throw assertion errors if the predicate is false.
-  private static class QueryNodeImpl extends QueryNode {
+  private static class QueryNodeImpl<T extends GraphNode> extends QueryNode {
 
     private final GraphInspector inspector;
-    private final GraphNode graphNode;
+    private final T graphNode;
 
-    public QueryNodeImpl(GraphInspector inspector, GraphNode graphNode) {
+    public QueryNodeImpl(GraphInspector inspector, T graphNode) {
       this.inspector = inspector;
       this.graphNode = graphNode;
     }
 
     @Override
     public boolean equals(Object obj) {
-      return obj instanceof QueryNodeImpl && graphNode.equals(((QueryNodeImpl) obj).graphNode);
+      return obj instanceof QueryNodeImpl && graphNode.equals(((QueryNodeImpl<?>) obj).graphNode);
     }
 
     @Override
@@ -484,7 +540,7 @@
       if (!(node instanceof QueryNodeImpl)) {
         return false;
       }
-      QueryNodeImpl impl = (QueryNodeImpl) node;
+      QueryNodeImpl<?> impl = (QueryNodeImpl<?>) node;
       return filterSources((source, infos) -> impl.graphNode == source).findFirst().isPresent();
     }
 
@@ -493,7 +549,7 @@
       if (!(node instanceof QueryNodeImpl)) {
         return false;
       }
-      QueryNodeImpl impl = (QueryNodeImpl) node;
+      QueryNodeImpl<?> impl = (QueryNodeImpl<?>) node;
       return filterSources(
               (source, infos) ->
                   impl.graphNode == source && EdgeKindPredicate.compatibilityRule.test(infos))
@@ -506,22 +562,63 @@
       if (!isCompatKeptBy(node)) {
         return false;
       }
-      QueryNodeImpl impl = (QueryNodeImpl) node;
+      QueryNodeImpl<?> impl = (QueryNodeImpl<?>) node;
       return filterSources((source, infos) -> impl.graphNode != source).count() == 0;
     }
 
     @Override
+    public boolean isKeptByAnnotationOn(QueryNode annotatedNode) {
+      // This should be an annotation node or a class node which it an annotation.
+      assert graphNode instanceof AnnotationGraphNode || graphNode instanceof ClassGraphNode;
+
+      // The annotated node (class, field or method) should be present.
+      assert annotatedNode.isPresent();
+      QueryNodeImpl<?> annotatedNodeImpl = (QueryNodeImpl<?>) annotatedNode;
+      assert annotatedNodeImpl.graphNode instanceof ClassGraphNode
+          || annotatedNodeImpl.graphNode instanceof FieldGraphNode
+          || annotatedNodeImpl.graphNode instanceof MethodGraphNode;
+
+      return hasSource(
+          (source, infos) ->
+              source.equals(annotatedNodeImpl.graphNode)
+                  && EdgeKindPredicate.isAnnotatedOn.test(infos));
+    }
+
+    @Override
+    public boolean isKeptByReferenceInAnnotationOn(
+        QueryNode annotationNode, QueryNode annotatedNode) {
+      // The annotation node should be present.
+      assert annotationNode.isPresent();
+      QueryNodeImpl<ClassGraphNode> annotationNodeImpl =
+          (QueryNodeImpl<ClassGraphNode>) annotationNode;
+
+      // The annotated node (class, field or method) should be present.
+      assert annotatedNode.isPresent();
+      QueryNodeImpl<?> annotatedNodeImpl = (QueryNodeImpl<?>) annotatedNode;
+      assert annotatedNodeImpl.graphNode instanceof ClassGraphNode
+          || annotatedNodeImpl.graphNode instanceof FieldGraphNode
+          || annotatedNodeImpl.graphNode instanceof MethodGraphNode;
+
+      AnnotationGraphNode expectedSource =
+          new AnnotationGraphNode(annotatedNodeImpl.graphNode, annotationNodeImpl.graphNode);
+
+      return hasSource(
+          (source, infos) ->
+              source.equals(expectedSource)
+                  && EdgeKindPredicate.isReferencedInAnnotation.test(infos));
+    }
+
+    @Override
     public boolean isKeptByLibraryMethod(QueryNode node) {
       assert graphNode instanceof MethodGraphNode;
-      if (!(node instanceof QueryNodeImpl)) {
+      if (!node.isPresent()) {
         return false;
       }
-      QueryNodeImpl impl = (QueryNodeImpl) node;
-      return filterSources(
-              (source, infos) ->
-                  impl.graphNode == source && EdgeKindPredicate.isLibraryMethod.test(infos))
-          .findFirst()
-          .isPresent();
+      assert node instanceof QueryNodeImpl;
+      QueryNodeImpl<?> impl = (QueryNodeImpl<?>) node;
+      return hasSource(
+          (source, infos) ->
+              impl.graphNode == source && EdgeKindPredicate.isLibraryMethod.test(infos));
     }
 
     @Override
@@ -544,7 +641,7 @@
                   + node.getNodeDescription());
           return;
         }
-        QueryNodeImpl impl = (QueryNodeImpl) node;
+        QueryNodeImpl<?> impl = (QueryNodeImpl<?>) node;
         if (!filterSources((source, infos) -> impl.graphNode == source).findFirst().isPresent()) {
           onError.accept(
               "Expected to find dependency from precondtion to dependent rule, but could not. "
@@ -564,7 +661,7 @@
       if (nodes.length != preconditions.size()) {
         for (GraphNode precondition : preconditions) {
           if (Arrays.stream(nodes)
-              .noneMatch(node -> ((QueryNodeImpl) node).graphNode == precondition)) {
+              .noneMatch(node -> ((QueryNodeImpl<?>) node).graphNode == precondition)) {
             onError.accept("Unexpected item in precondtions: " + precondition.toString());
             return;
           }
@@ -614,6 +711,10 @@
           .filter(e -> test.test(e.getKey(), e.getValue()))
           .map(Entry::getKey);
     }
+
+    private boolean hasSource(BiPredicate<GraphNode, Set<GraphEdgeInfo>> test) {
+      return filterSources(test).findAny().isPresent();
+    }
   }
 
   private final CollectingGraphConsumer consumer;
@@ -753,6 +854,52 @@
     return "rule@" + origin + ":" + new TextPosition(0, line, column);
   }
 
+  public QueryNode annotation(Class<? extends Annotation> clazz, QueryNode annotatedNode) {
+    return annotation(Reference.classFromClass(clazz), annotatedNode);
+  }
+
+  public QueryNode annotation(ClassReference annotationClassReference, QueryNode annotatedNode) {
+    // The annotation node (class, field or method) should be present.
+    assert annotatedNode.isPresent();
+    QueryNodeImpl<?> annotatedNodeImpl = (QueryNodeImpl<?>) annotatedNode;
+    assert annotatedNodeImpl.graphNode instanceof ClassGraphNode
+        || annotatedNodeImpl.graphNode instanceof FieldGraphNode
+        || annotatedNodeImpl.graphNode instanceof MethodGraphNode;
+
+    Map<ClassReference, AnnotationGraphNode> annotationsOnAnnotatedItem;
+    if (annotatedNodeImpl.graphNode instanceof ClassGraphNode) {
+      annotationsOnAnnotatedItem =
+          classAnnotations.get(((ClassGraphNode) annotatedNodeImpl.graphNode).getReference());
+    } else if (annotatedNodeImpl.graphNode instanceof FieldGraphNode) {
+      annotationsOnAnnotatedItem =
+          fieldAnnotations.get(((FieldGraphNode) annotatedNodeImpl.graphNode).getReference());
+    } else {
+      assert annotatedNodeImpl.graphNode instanceof MethodGraphNode;
+      annotationsOnAnnotatedItem =
+          methodAnnotations.get(((MethodGraphNode) annotatedNodeImpl.graphNode).getReference());
+    }
+
+    if (annotationsOnAnnotatedItem == null) {
+      return new AbsentQueryNode(
+          "Node " + annotatedNode.getNodeDescription() + " has no annotations");
+    }
+
+    AnnotationGraphNode annotationGraphNode =
+        annotationsOnAnnotatedItem.get(annotationClassReference);
+    if (annotationGraphNode == null) {
+      return new AbsentQueryNode(
+          "Node "
+              + annotatedNode.getNodeDescription()
+              + " has no annotation of type "
+              + annotationClassReference.getTypeName());
+    }
+    return new QueryNodeImpl<>(this, annotationGraphNode);
+  }
+
+  public QueryNode clazz(Class<?> clazz) {
+    return clazz(Reference.classFromClass(clazz));
+  }
+
   public QueryNode clazz(ClassReference clazz) {
     return getQueryNode(classes.get(clazz), clazz.toString());
   }
diff --git a/third_party/openjdk/desugar_jdk_libs_releases/1.0.10.tar.gz.sha1 b/third_party/openjdk/desugar_jdk_libs_releases/1.0.10.tar.gz.sha1
new file mode 100644
index 0000000..ec8b41b
--- /dev/null
+++ b/third_party/openjdk/desugar_jdk_libs_releases/1.0.10.tar.gz.sha1
@@ -0,0 +1 @@
+ee0cf6f06d1f8f725a72f28826533bbcc407678e
\ No newline at end of file
diff --git a/third_party/openjdk/desugar_jdk_libs_releases/1.0.9.tar.gz.sha1 b/third_party/openjdk/desugar_jdk_libs_releases/1.0.9.tar.gz.sha1
new file mode 100644
index 0000000..10b5a1f
--- /dev/null
+++ b/third_party/openjdk/desugar_jdk_libs_releases/1.0.9.tar.gz.sha1
@@ -0,0 +1 @@
+e5b342cfdd5c0799c9c729e55d4258a4bd2b13c7
\ No newline at end of file
diff --git a/third_party/openjdk/desugar_jdk_libs_releases/1.1.0.tar.gz.sha1 b/third_party/openjdk/desugar_jdk_libs_releases/1.1.0.tar.gz.sha1
new file mode 100644
index 0000000..f42f4c4
--- /dev/null
+++ b/third_party/openjdk/desugar_jdk_libs_releases/1.1.0.tar.gz.sha1
@@ -0,0 +1 @@
+d49b2f1b946cfb868a843605a8c75f5d958fb2a6
\ No newline at end of file
diff --git a/third_party/openjdk/desugar_jdk_libs_releases/1.1.1.tar.gz.sha1 b/third_party/openjdk/desugar_jdk_libs_releases/1.1.1.tar.gz.sha1
new file mode 100644
index 0000000..1133b23
--- /dev/null
+++ b/third_party/openjdk/desugar_jdk_libs_releases/1.1.1.tar.gz.sha1
@@ -0,0 +1 @@
+57bafe4d948330c30123732981e40827a6e02479
\ No newline at end of file
diff --git a/third_party/openjdk/desugar_jdk_libs_releases/1.1.5.tar.gz.sha1 b/third_party/openjdk/desugar_jdk_libs_releases/1.1.5.tar.gz.sha1
new file mode 100644
index 0000000..522687f
--- /dev/null
+++ b/third_party/openjdk/desugar_jdk_libs_releases/1.1.5.tar.gz.sha1
@@ -0,0 +1 @@
+074f2bea4a557e48a92ffc6c572a791db655574c
\ No newline at end of file
diff --git a/tools/compiledump.py b/tools/compiledump.py
index cc71d22..192145b 100755
--- a/tools/compiledump.py
+++ b/tools/compiledump.py
@@ -3,21 +3,26 @@
 # for details. All rights reserved. Use of this source code is governed by a
 # BSD-style license that can be found in the LICENSE file.
 
-import archive
 import argparse
-import jdk
 import os
-import retrace
 import subprocess
 import sys
 import zipfile
 
+import archive
+import jdk
+import retrace
 import utils
 
 
 def make_parser():
   parser = argparse.ArgumentParser(description = 'Compile a dump artifact.')
   parser.add_argument(
+      '--summary',
+      help='List a summary of the contents of the dumps.',
+      default=False,
+      action='store_true')
+  parser.add_argument(
     '-d',
     '--dump',
     help='Dump file or directory to compile',
@@ -169,15 +174,17 @@
       return open(f).read().split(' ')[0]
     return None
 
-def read_dump(args, temp):
+def read_dump_from_args(args, temp):
   if args.dump is None:
     error("A dump file or directory must be specified")
-  if os.path.isdir(args.dump):
-    return Dump(args.dump)
-  dump_file = zipfile.ZipFile(os.path.abspath(args.dump), 'r')
-  with utils.ChangedWorkingDirectory(temp):
-    if args.override or not os.path.isfile('r8-version'):
-      print("Extracting into: %s" % temp)
+  return read_dump(args.dump, temp, args.override)
+
+def read_dump(dump, temp, override=False):
+  if os.path.isdir(dump):
+    return Dump(dump)
+  dump_file = zipfile.ZipFile(os.path.abspath(dump), 'r')
+  with utils.ChangedWorkingDirectory(temp, quiet=True):
+    if override or not os.path.isfile('r8-version'):
       dump_file.extractall()
       if not os.path.isfile('r8-version'):
         error("Did not extract into %s. Either the zip file is invalid or the "
@@ -268,7 +275,7 @@
       temp = out
       if not os.path.exists(temp):
         os.makedirs(temp)
-    dump = read_dump(args, temp)
+    dump = read_dump_from_args(args, temp)
     if not dump.program_jar():
       error("Cannot compile dump with no program classes")
     if not dump.library_jar():
@@ -376,8 +383,56 @@
     print('Could not find map file from argument: %s.' % version)
     return None
 
+def summarize_dump_files(dumpfiles):
+  if len(dumpfiles) == 0:
+    error('Summary command expects a list of dumps to summarize')
+  for f in dumpfiles:
+    print(f + ':')
+    try:
+      with utils.TempDir() as temp:
+        dump = read_dump(f, temp)
+        summarize_dump(dump)
+    except IOError as e:
+      print("Error: " + str(e))
+    except zipfile.BadZipfile as e:
+      print("Error: " + str(e))
+
+def summarize_dump(dump):
+  version = dump.version()
+  if not version:
+    print('No dump version info')
+    return
+  print('version=' + version)
+  props = dump.build_properties_file()
+  if props:
+    with open(props) as props_file:
+      print(props_file.read())
+  if dump.library_jar():
+    print('library.jar present')
+  if dump.classpath_jar():
+    print('classpath.jar present')
+  prog = dump.program_jar()
+  if prog:
+    print('program.jar content:')
+    summarize_jar(prog)
+
+def summarize_jar(jar):
+  with zipfile.ZipFile(jar) as zip:
+    pkgs = {}
+    for info in zip.infolist():
+      if info.filename.endswith('.class'):
+        pkg, clazz = os.path.split(info.filename)
+        count = pkgs.get(pkg, 0)
+        pkgs[pkg] = count + 1
+  sorted = list(pkgs.keys())
+  sorted.sort()
+  for p in sorted:
+    print('  ' + p + ': ' + str(pkgs[p]))
+
 def run(args, otherargs):
-  if (args.loop):
+  if args.summary:
+    summarize_dump_files(otherargs)
+  elif args.loop:
     count = 1
     while True:
       print('Iteration {:03d}'.format(count))