Merge commit 'c152f9cd43434984e548705d2457d89ac2d34dc1' into dev-release
diff --git a/build.gradle b/build.gradle
index 9800595..1fd0955 100644
--- a/build.gradle
+++ b/build.gradle
@@ -125,6 +125,11 @@
             srcDirs = ['src/test/examplesJava9']
         }
     }
+    examplesJava10 {
+        java {
+            srcDirs = ['src/test/examplesJava10']
+        }
+    }
     examplesJava11 {
         java {
             srcDirs = ['src/test/examplesJava11']
@@ -504,7 +509,7 @@
 } else {
     def javaHomeOut = new StringBuilder()
     def javaHomeErr = new StringBuilder()
-    def javaHomeProc = './tools/jdk.py'.execute()
+    def javaHomeProc = './tools/jdk.py'.execute([], projectDir)
     javaHomeProc.waitForProcessOutput(javaHomeOut, javaHomeErr)
     def jdkHome = new File(javaHomeOut.toString().trim())
     if (!jdkHome.exists()) {
@@ -550,7 +555,7 @@
     targetCompatibility = JavaVersion.VERSION_1_9
 }
 
-def setJava11Compilation(sourceSet) {
+def setJdk11CompilationWithCompatibility(String sourceSet, JavaVersion compatibility) {
     tasks.named(sourceSet).get().configure {
         def jdkDir = 'third_party/openjdk/jdk-11/'
         options.fork = true
@@ -562,14 +567,15 @@
         } else {
             options.forkOptions.javaHome = file(jdkDir + 'Windows')
         }
-        sourceCompatibility = JavaVersion.VERSION_11
-        targetCompatibility = JavaVersion.VERSION_11
+        sourceCompatibility = compatibility
+        targetCompatibility = compatibility
     }
 }
 
-setJava11Compilation(sourceSets.examplesJava11.compileJavaTaskName)
-setJava11Compilation(sourceSets.examplesTestNGRunner.compileJavaTaskName)
-setJava11Compilation(sourceSets.jdk11TimeTests.compileJavaTaskName)
+setJdk11CompilationWithCompatibility(sourceSets.examplesJava10.compileJavaTaskName, JavaVersion.VERSION_1_10)
+setJdk11CompilationWithCompatibility(sourceSets.examplesJava11.compileJavaTaskName, JavaVersion.VERSION_11)
+setJdk11CompilationWithCompatibility(sourceSets.examplesTestNGRunner.compileJavaTaskName, JavaVersion.VERSION_11)
+setJdk11CompilationWithCompatibility(sourceSets.jdk11TimeTests.compileJavaTaskName, JavaVersion.VERSION_11)
 
 task compileMainWithJava11 (type: JavaCompile) {
     dependsOn downloadDeps
@@ -1434,6 +1440,22 @@
     }
 }
 
+task buildExampleJava10Jars {
+    def examplesDir = file("src/test/examplesJava10")
+    examplesDir.eachDir { dir ->
+        def name = dir.getName();
+        def exampleOutputDir = file("build/test/examplesJava10");
+        def jarName = "${name}.jar"
+        dependsOn "jar_examplesJava10_${name}"
+        task "jar_examplesJava10_${name}"(type: Jar) {
+            archiveName = jarName
+            destinationDir = exampleOutputDir
+            from sourceSets.examplesJava10.output
+            include "**/" + name + "/**/*.class"
+        }
+    }
+}
+
 task buildExampleJava11Jars {
     def examplesDir = file("src/test/examplesJava11")
     examplesDir.eachDir { dir ->
@@ -1566,6 +1588,7 @@
     dependsOn buildExampleAndroidOJars
     dependsOn buildExampleAndroidPJars
     dependsOn buildExampleJava9Jars
+    dependsOn buildExampleJava10Jars
     dependsOn buildExampleJava11Jars
     dependsOn buildExampleAndroidApi
     def examplesDir = file("src/test/examples")
diff --git a/src/main/java/com/android/tools/r8/graph/AccessFlags.java b/src/main/java/com/android/tools/r8/graph/AccessFlags.java
index 64135fd..98760b6 100644
--- a/src/main/java/com/android/tools/r8/graph/AccessFlags.java
+++ b/src/main/java/com/android/tools/r8/graph/AccessFlags.java
@@ -101,7 +101,7 @@
     return visibilityOrdinal() >= other.visibilityOrdinal();
   }
 
-  public boolean isSameVisiblity(AccessFlags other) {
+  public boolean isSameVisibility(AccessFlags other) {
     return visibilityOrdinal() == other.visibilityOrdinal();
   }
 
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfo.java b/src/main/java/com/android/tools/r8/graph/AppInfo.java
index 2390bc6..cc8af52 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfo.java
@@ -215,13 +215,20 @@
    */
   public DexEncodedMethod lookupSuperTarget(DexMethod method, DexType invocationContext) {
     assert checkIfObsolete();
+    assert invocationContext.isClassType();
+    DexClass context = definitionFor(invocationContext);
+    return context == null ? null : lookupSuperTarget(method, context);
+  }
+
+  public DexEncodedMethod lookupSuperTarget(DexMethod method, DexClass invocationContext) {
+    assert checkIfObsolete();
     return resolveMethod(method.holder, method).lookupInvokeSuperTarget(invocationContext, this);
   }
 
   /**
    * Lookup direct method following the super chain from the holder of {@code method}.
-   * <p>
-   * This method will lookup private and constructor methods.
+   *
+   * <p>This method will lookup private and constructor methods.
    *
    * @param method the method to lookup
    * @return The actual target for {@code method} or {@code null} if none found.
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java b/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
index 0998136..a24212f 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
@@ -354,7 +354,7 @@
     assert potentialHolder.isInterface();
     for (DexEncodedMethod virtualMethod : potentialHolder.virtualMethods) {
       if (virtualMethod.method.hasSameProtoAndName(method.method)
-          && virtualMethod.accessFlags.isSameVisiblity(method.accessFlags)) {
+          && virtualMethod.accessFlags.isSameVisibility(method.accessFlags)) {
         return true;
       }
     }
@@ -468,6 +468,12 @@
     return !getTypeInfo(type).directSubtypes.isEmpty();
   }
 
+  public boolean isRelatedBySubtyping(DexType type, DexType other) {
+    assert type.isClassType();
+    assert other.isClassType();
+    return isSubtype(type, other) || isSubtype(other, type);
+  }
+
   @Override
   public boolean isSubtype(DexType subtype, DexType supertype) {
     if (subtype == supertype || isStrictSubtypeOf(subtype, supertype)) {
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index 91994d1..ac4e4eb 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -247,6 +247,13 @@
     }
   }
 
+  public void withGeneratedMessageLiteBuilderShrinker(
+      Consumer<GeneratedMessageLiteBuilderShrinker> consumer) {
+    if (protoShrinker != null && protoShrinker.generatedMessageLiteBuilderShrinker != null) {
+      consumer.accept(protoShrinker.generatedMessageLiteBuilderShrinker);
+    }
+  }
+
   public <U> U withGeneratedMessageLiteShrinker(
       Function<GeneratedMessageLiteShrinker, U> fn, U defaultValue) {
     if (protoShrinker != null && protoShrinker.generatedMessageLiteShrinker != null) {
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 97da896..7fe4555 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -1007,6 +1007,31 @@
     return builder.build();
   }
 
+  public static DexEncodedMethod createDesugaringForwardingMethod(
+      DexEncodedMethod target, DexClass clazz, DexMethod forwardMethod, DexItemFactory factory) {
+    DexMethod method = target.method;
+    assert forwardMethod != null;
+    // New method will have the same name, proto, and also all the flags of the
+    // default method, including bridge flag.
+    DexMethod newMethod = factory.createMethod(clazz.type, method.proto, method.name);
+    MethodAccessFlags newFlags = target.accessFlags.copy();
+    // Some debuggers (like IntelliJ) automatically skip synthetic methods on single step.
+    newFlags.setSynthetic();
+    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,
+        target.annotations,
+        target.parameterAnnotationsList,
+        new SynthesizedCode(forwardSourceCodeBuilder::build));
+  }
+
   public DexEncodedMethod toStaticMethodWithoutThis() {
     checkIfObsolete();
     assert !accessFlags.isStatic();
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index faad0e6..5d85611 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -230,6 +230,9 @@
   public final DexString consumerDescriptor = createString("Ljava/util/function/Consumer;");
   public final DexString runnableDescriptor = createString("Ljava/lang/Runnable;");
   public final DexString optionalDescriptor = createString("Ljava/util/Optional;");
+  public final DexString optionalDoubleDescriptor = createString("Ljava/util/OptionalDouble;");
+  public final DexString optionalIntDescriptor = createString("Ljava/util/OptionalInt;");
+  public final DexString optionalLongDescriptor = createString("Ljava/util/OptionalLong;");
   public final DexString streamDescriptor = createString("Ljava/util/stream/Stream;");
   public final DexString arraysDescriptor = createString("Ljava/util/Arrays;");
 
@@ -328,6 +331,9 @@
   public final DexType consumerType = createType(consumerDescriptor);
   public final DexType runnableType = createType(runnableDescriptor);
   public final DexType optionalType = createType(optionalDescriptor);
+  public final DexType optionalDoubleType = createType(optionalDoubleDescriptor);
+  public final DexType optionalIntType = createType(optionalIntDescriptor);
+  public final DexType optionalLongType = createType(optionalLongDescriptor);
   public final DexType streamType = createType(streamDescriptor);
 
   public final DexType runtimeExceptionType = createType(runtimeExceptionDescriptor);
diff --git a/src/main/java/com/android/tools/r8/graph/GraphLense.java b/src/main/java/com/android/tools/r8/graph/GraphLense.java
index 8c5dd71..1fc834d 100644
--- a/src/main/java/com/android/tools/r8/graph/GraphLense.java
+++ b/src/main/java/com/android/tools/r8/graph/GraphLense.java
@@ -345,8 +345,8 @@
     protected final Map<DexMethod, DexMethod> methodMap = new IdentityHashMap<>();
     protected final Map<DexField, DexField> fieldMap = new IdentityHashMap<>();
 
-    private final BiMap<DexField, DexField> originalFieldSignatures = HashBiMap.create();
-    private final BiMap<DexMethod, DexMethod> originalMethodSignatures = HashBiMap.create();
+    protected final BiMap<DexField, DexField> originalFieldSignatures = HashBiMap.create();
+    protected final BiMap<DexMethod, DexMethod> originalMethodSignatures = HashBiMap.create();
 
     public void map(DexType from, DexType to) {
       if (from == to) {
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
new file mode 100644
index 0000000..1e33e66
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
@@ -0,0 +1,28 @@
+// 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.graph;
+
+import com.android.tools.r8.errors.Unreachable;
+
+/** Type representing a method definition in the programs compilation unit and its holder. */
+public class ProgramMethod {
+  public final DexProgramClass holder;
+  public final DexEncodedMethod method;
+
+  public ProgramMethod(DexProgramClass holder,  DexEncodedMethod method) {
+    assert holder.type == method.method.holder;
+    this.holder = holder;
+    this.method = method;
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    throw new Unreachable("Unsupported attempt at comparing ProgramMethod");
+  }
+
+  @Override
+  public int hashCode() {
+    throw new Unreachable("Unsupported attempt at computing the hashcode of ProgramMethod");
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/ResolutionResult.java b/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
index bdea265..65a2c7c 100644
--- a/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
+++ b/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
@@ -6,7 +6,6 @@
 import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
 
 import com.android.tools.r8.errors.CompilationError;
-import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.SetUtils;
 import com.google.common.collect.Sets;
@@ -61,8 +60,16 @@
 
   public abstract boolean isValidVirtualTargetForDynamicDispatch();
 
+  /** Lookup the single target of an invoke-special on this resolution result if possible. */
+  public abstract DexEncodedMethod lookupInvokeSpecialTarget(
+      DexProgramClass context, AppInfoWithSubtyping appInfo);
+
   /** Lookup the single target of an invoke-super on this resolution result if possible. */
-  public abstract DexEncodedMethod lookupInvokeSuperTarget(DexType context, AppInfo appInfo);
+  public abstract DexEncodedMethod lookupInvokeSuperTarget(
+      DexProgramClass context, AppInfoWithSubtyping appInfo);
+
+  @Deprecated
+  public abstract DexEncodedMethod lookupInvokeSuperTarget(DexClass context, AppInfo appInfo);
 
   public final Set<DexEncodedMethod> lookupVirtualDispatchTargets(
       boolean isInterface, AppInfoWithSubtyping appInfo) {
@@ -143,6 +150,96 @@
     }
 
     /**
+     * This is intended to model the actual behavior of invoke-special on a JVM.
+     *
+     * <p>See https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-6.html#jvms-6.5.invokespecial
+     * and comments below for deviations due to diverging behavior on actual JVMs.
+     */
+    @Override
+    public DexEncodedMethod lookupInvokeSpecialTarget(
+        DexProgramClass context, AppInfoWithSubtyping appInfo) {
+      // If the resolution is non-accessible then no target exists.
+      if (!isAccessibleFrom(context, appInfo)) {
+        return null;
+      }
+
+      // Statics cannot be targeted by invoke-special.
+      if (getResolvedMethod().isStatic()) {
+        return null;
+      }
+
+      // The symbolic reference is the holder type that resolution was initiated at.
+      DexClass symbolicReference = initialResolutionHolder;
+
+      // First part of the spec is to determine the starting point for lookup for invoke special.
+      // Notice that the specification indicates that the immediate super type should
+      // be used when three items hold, the second being:
+      //   is-class(sym-ref) => is-super(sym-ref, context)
+      // in the case of an interface that is trivially satisfied, which would lead the initial type
+      // to be java.lang.Object. However in practice the lookup appears to start at the symbolic
+      // reference in the case of interfaces, so the second condition should likely be interpreted:
+      //   is-class(sym-ref) *and* is-super(sym-ref, context).
+      final DexClass initialType;
+      if (!resolvedMethod.isInstanceInitializer()
+          && !symbolicReference.isInterface()
+          && isSuperclass(symbolicReference, context, appInfo)) {
+        // If reference is a super type of the context then search starts at the immediate super.
+        initialType = appInfo.definitionFor(context.superType);
+      } else {
+        // Otherwise it starts at the reference itself.
+        initialType = symbolicReference;
+      }
+      // Abort if for some reason the starting point could not be found.
+      if (initialType == null) {
+        return null;
+      }
+      // 1-3. Search the initial class and its supers in order for a matching instance method.
+      DexMethod method = getResolvedMethod().method;
+      DexEncodedMethod target = null;
+      DexClass current = initialType;
+      while (current != null) {
+        target = current.lookupMethod(method);
+        if (target != null) {
+          break;
+        }
+        current = current.superType == null ? null : appInfo.definitionFor(current.superType);
+      }
+      // 4. Otherwise, it is the single maximally specific method:
+      if (target == null) {
+        target = appInfo.resolveMaximallySpecificMethods(initialType, method).getSingleTarget();
+      }
+      if (target == null) {
+        return null;
+      }
+      // Linking exceptions:
+      // A non-instance method throws IncompatibleClassChangeError.
+      if (target.isStatic()) {
+        return null;
+      }
+      // An instance initializer that is not to the symbolic reference throws NoSuchMethodError.
+      // It appears as if this check is also in place for non-initializer methods too.
+      // See NestInvokeSpecialMethodAccessWithIntermediateTest.
+      if ((target.isInstanceInitializer() || target.isPrivateMethod())
+          && target.method.holder != symbolicReference.type) {
+        return null;
+      }
+      // Runtime exceptions:
+      // An abstract method throws AbstractMethodError.
+      if (target.isAbstract()) {
+        return null;
+      }
+      // Should we check access control again?
+      if (!AccessControl.isMethodAccessible(target, initialType, context, appInfo)) {
+        return null;
+      }
+      return target;
+    }
+
+    private static boolean isSuperclass(DexClass sup, DexClass sub, AppInfoWithSubtyping appInfo) {
+      return sup != sub && appInfo.isSubtype(sub.type, sup.type);
+    }
+
+    /**
      * Lookup super method following the super chain from the holder of {@code method}.
      *
      * <p>This method will resolve the method on the holder of {@code method} and only return a
@@ -164,17 +261,26 @@
      * @return The actual target for the invoke-super or {@code null} if none found.
      */
     @Override
-    public DexEncodedMethod lookupInvokeSuperTarget(DexType context, AppInfo appInfo) {
+    public DexEncodedMethod lookupInvokeSuperTarget(
+        DexProgramClass context, AppInfoWithSubtyping appInfo) {
+      if (!isAccessibleFrom(context, appInfo)) {
+        return null;
+      }
+      return lookupInvokeSuperTarget(context.asDexClass(), appInfo);
+    }
+
+    @Override
+    public DexEncodedMethod lookupInvokeSuperTarget(DexClass context, AppInfo appInfo) {
+      assert context != null;
       DexMethod method = resolvedMethod.method;
       // TODO(b/145775365): Check the requirements for an invoke-special to a protected method.
       // See https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.invokespecial
 
       if (appInfo.hasSubtyping()
-          && !appInfo.withSubtyping().isSubtype(context, initialResolutionHolder.type)) {
-        DexClass contextClass = appInfo.definitionFor(context);
+          && !appInfo.withSubtyping().isSubtype(context.type, initialResolutionHolder.type)) {
         throw new CompilationError(
             "Illegal invoke-super to " + method.toSourceString() + " from class " + context,
-            contextClass != null ? contextClass.getOrigin() : Origin.unknown());
+            context.getOrigin());
       }
 
       // According to
@@ -189,12 +295,11 @@
         return appInfo.resolveMethodOnInterface(initialResolutionHolder, method).getSingleTarget();
       }
       // Then, resume on the search, but this time, starting from the holder of the caller.
-      DexClass contextClass = appInfo.definitionFor(context);
-      if (contextClass == null || contextClass.superType == null) {
+      if (context.superType == null) {
         return null;
       }
       SingleResolutionResult resolution =
-          appInfo.resolveMethodOnClass(contextClass.superType, method).asSingleResolution();
+          appInfo.resolveMethodOnClass(context.superType, method).asSingleResolution();
       return resolution != null && !resolution.resolvedMethod.isStatic()
           ? resolution.resolvedMethod
           : null;
@@ -305,7 +410,19 @@
   abstract static class EmptyResult extends ResolutionResult {
 
     @Override
-    public final DexEncodedMethod lookupInvokeSuperTarget(DexType context, AppInfo appInfo) {
+    public final DexEncodedMethod lookupInvokeSpecialTarget(
+        DexProgramClass context, AppInfoWithSubtyping appInfo) {
+      return null;
+    }
+
+    @Override
+    public DexEncodedMethod lookupInvokeSuperTarget(
+        DexProgramClass context, AppInfoWithSubtyping appInfo) {
+      return null;
+    }
+
+    @Override
+    public final DexEncodedMethod lookupInvokeSuperTarget(DexClass context, AppInfo appInfo) {
       return null;
     }
 
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
index 0e8da38..d1cf2e5 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
@@ -11,6 +11,10 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.conversion.CallGraph.Node;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.function.BooleanSupplier;
 
@@ -41,6 +45,21 @@
     new RootSetExtension(appView, alwaysInline, neverInline, bypassClinitforInlining).extend();
   }
 
+  public void preprocessCallGraphBeforeCycleElimination(Map<DexMethod, Node> nodes) {
+    Node node = nodes.get(references.generatedMessageLiteBuilderMethods.constructorMethod);
+    if (node != null) {
+      List<Node> calleesToBeRemoved = new ArrayList<>();
+      for (Node callee : node.getCalleesWithDeterministicOrder()) {
+        if (references.isDynamicMethodBridge(callee.method)) {
+          calleesToBeRemoved.add(callee);
+        }
+      }
+      for (Node callee : calleesToBeRemoved) {
+        callee.removeCaller(node);
+      }
+    }
+  }
+
   private static class RootSetExtension {
 
     private final AppView<? extends AppInfoWithSubtyping> appView;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoReferences.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoReferences.java
index cedb6ed..c90eaf2 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoReferences.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoReferences.java
@@ -99,6 +99,14 @@
     return isDynamicMethod(encodedMethod.method);
   }
 
+  public boolean isDynamicMethodBridge(DexMethod method) {
+    return method == generatedMessageLiteMethods.dynamicMethodBridgeMethod;
+  }
+
+  public boolean isDynamicMethodBridge(DexEncodedMethod method) {
+    return isDynamicMethodBridge(method.method);
+  }
+
   public boolean isFindLiteExtensionByNumberMethod(DexMethod method) {
     return method.proto == findLiteExtensionByNumberProto
         && method.name.startsWith(findLiteExtensionByNumberName);
@@ -115,6 +123,7 @@
   class GeneratedMessageLiteMethods {
 
     public final DexMethod createBuilderMethod;
+    public final DexMethod dynamicMethodBridgeMethod;
     public final DexMethod isInitializedMethod;
 
     private GeneratedMessageLiteMethods(DexItemFactory dexItemFactory) {
@@ -123,6 +132,11 @@
               generatedMessageLiteType,
               dexItemFactory.createProto(generatedMessageLiteBuilderType),
               "createBuilder");
+      dynamicMethodBridgeMethod =
+          dexItemFactory.createMethod(
+              generatedMessageLiteType,
+              dexItemFactory.createProto(dexItemFactory.objectType, methodToInvokeType),
+              "dynamicMethod");
       isInitializedMethod =
           dexItemFactory.createMethod(
               generatedMessageLiteType,
@@ -134,6 +148,7 @@
   class GeneratedMessageLiteBuilderMethods {
 
     public final DexMethod buildPartialMethod;
+    public final DexMethod constructorMethod;
 
     private GeneratedMessageLiteBuilderMethods(DexItemFactory dexItemFactory) {
       buildPartialMethod =
@@ -141,6 +156,11 @@
               generatedMessageLiteBuilderType,
               dexItemFactory.createProto(generatedMessageLiteType),
               "buildPartial");
+      constructorMethod =
+          dexItemFactory.createMethod(
+              generatedMessageLiteBuilderType,
+              dexItemFactory.createProto(dexItemFactory.voidType, generatedMessageLiteType),
+              dexItemFactory.constructorMethodName);
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java b/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java
index 189bb92..c7939b5 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java
@@ -56,6 +56,9 @@
     process(executorService);
     assert verifyAllMethodsWithCodeExists();
 
+    appView.withGeneratedMessageLiteBuilderShrinker(
+        shrinker -> shrinker.preprocessCallGraphBeforeCycleElimination(nodes));
+
     timing.begin("Cycle elimination");
     // Sort the nodes for deterministic cycle elimination.
     Set<Node> nodesWithDeterministicOrder = Sets.newTreeSet(nodes.values());
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index 7ef6cd5..6233a57 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -470,6 +470,10 @@
     return true;
   }
 
+  public DexEncodedMethod getMethod() {
+    return method;
+  }
+
   public boolean isDebugMode() {
     return appView.options().debug || method.getOptimizationInfo().isReachabilitySensitive();
   }
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 939d33a..bdc98f0 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
@@ -29,7 +29,6 @@
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionListIterator;
-import com.android.tools.r8.ir.code.Invoke;
 import com.android.tools.r8.ir.code.InvokeMethod;
 import com.android.tools.r8.ir.code.InvokeStatic;
 import com.android.tools.r8.ir.conversion.IRConverter;
@@ -41,8 +40,7 @@
 import com.android.tools.r8.ir.desugar.backports.LongMethodRewrites;
 import com.android.tools.r8.ir.desugar.backports.NumericMethodRewrites;
 import com.android.tools.r8.ir.desugar.backports.ObjectsMethodRewrites;
-import com.android.tools.r8.ir.synthetic.ForwardMethodSourceCode;
-import com.android.tools.r8.ir.synthetic.SynthesizedCode;
+import com.android.tools.r8.ir.desugar.backports.OptionalMethodRewrites;
 import com.android.tools.r8.origin.SynthesizedOrigin;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.InternalOptions;
@@ -134,16 +132,12 @@
                 .appInfo()
                 .lookupSuperTarget(invoke.getInvokedMethod(), code.method.method.holder);
         if (!dexEncodedMethod.isFinal()) { // Final methods can be rewritten as a normal invoke.
-          Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
-              appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember();
-          Map<DexType, DexType> typeMap = retargetCoreLibMember.get(dexEncodedMethod.method.name);
-          if (typeMap != null && typeMap.containsKey(dexEncodedMethod.method.holder)) {
-            DexMethod retargetMethod =
-                factory.createMethod(
-                    typeMap.get(dexEncodedMethod.method.holder),
-                    factory.prependTypeToProto(
-                        dexEncodedMethod.method.holder, dexEncodedMethod.method.proto),
-                    dexEncodedMethod.method.name);
+          DexMethod retargetMethod =
+              appView
+                  .options()
+                  .desugaredLibraryConfiguration
+                  .retargetMethod(dexEncodedMethod.method, appView);
+          if (retargetMethod != null) {
             iterator.replaceCurrentInstruction(
                 new InvokeStatic(retargetMethod, invoke.outValue(), invoke.arguments()));
           }
@@ -217,32 +211,17 @@
       DexEncodedMethod dexEncodedMethod =
           new DexEncodedMethod(
               method, flags, DexAnnotationSet.empty(), ParameterAnnotationsList.empty(), code);
-      DexProgramClass utilityClass =
-          new DexProgramClass(
-              method.holder,
-              null,
-              new SynthesizedOrigin("java8 methods utility class", getClass()),
-              classAccessFlags,
-              factory.objectType,
-              DexTypeList.empty(),
-              null,
-              null,
-              Collections.emptyList(),
-              null,
-              Collections.emptyList(),
-              DexAnnotationSet.empty(),
-              DexEncodedField.EMPTY_ARRAY,
-              DexEncodedField.EMPTY_ARRAY,
-              new DexEncodedMethod[] {dexEncodedMethod},
-              DexEncodedMethod.EMPTY_ARRAY,
-              factory.getSkipNameValidationForTesting(),
-              getChecksumSupplier(dexEncodedMethod),
-              referencingClasses);
       boolean addToMainDexList =
           referencingClasses.stream()
               .anyMatch(clazz -> appView.appInfo().isInMainDexList(clazz.type));
-      appView.appInfo().addSynthesizedClass(utilityClass);
-      builder.addSynthesizedClass(utilityClass, addToMainDexList);
+      DexProgramClass utilityClass =
+          synthesizeClassWithUniqueMethod(
+              builder,
+              classAccessFlags,
+              method.holder,
+              dexEncodedMethod,
+              "java8 methods utility class",
+              addToMainDexList);
       // The following may add elements to methodsProviders.
       converter.optimizeSynthesizedClass(utilityClass, executorService);
     }
@@ -318,27 +297,11 @@
     // NOTE: Never add a forwarding method to methods of classes unknown or coming from android.jar
     // even if this results in invalid code, these classes are never desugared.
     // In desugared library, emulated interface methods can be overridden by retarget lib members.
-    DexMethod forwardMethod = ClassProcessor.retargetMethod(appView, target);
-    // New method will have the same name, proto, and also all the flags of the
-    // default method, including bridge flag.
-    DexMethod newMethod =
-        appView.dexItemFactory().createMethod(clazz.type, target.proto, target.name);
-    DexEncodedMethod dexEncodedMethod = appView.definitionFor(target);
-    MethodAccessFlags newFlags = dexEncodedMethod.accessFlags.copy();
-    newFlags.setSynthetic();
-    ForwardMethodSourceCode.Builder forwardSourceCodeBuilder =
-        ForwardMethodSourceCode.builder(newMethod);
-    forwardSourceCodeBuilder
-        .setReceiver(clazz.type)
-        .setTarget(forwardMethod)
-        .setInvokeType(Invoke.Type.STATIC)
-        .setIsInterface(false);
-    return new DexEncodedMethod(
-        newMethod,
-        newFlags,
-        dexEncodedMethod.annotations,
-        dexEncodedMethod.parameterAnnotationsList,
-        new SynthesizedCode(forwardSourceCodeBuilder::build));
+    DexMethod forwardMethod =
+        appView.options().desugaredLibraryConfiguration.retargetMethod(target, appView);
+    assert forwardMethod != null && forwardMethod != target;
+    return DexEncodedMethod.createDesugaringForwardingMethod(
+        appView.definitionFor(target), clazz, forwardMethod, appView.dexItemFactory());
   }
 
   private void synthesizeEmulatedDispatchMethods(Builder<?> builder) {
@@ -359,57 +322,63 @@
       DexType interfaceType = dispatchInterfaceTypeFor(appView, emulatedDispatchMethod);
       DexEncodedMethod itfMethod =
           generateInterfaceDispatchMethod(emulatedDispatchMethod, interfaceType);
-      DexProgramClass dispatchInterface =
-          new DexProgramClass(
-              interfaceType,
-              null,
-              new SynthesizedOrigin("desugared library interface dispatch", getClass()),
-              itfAccessFlags,
-              factory.objectType,
-              DexTypeList.empty(),
-              null,
-              null,
-              Collections.emptyList(),
-              null,
-              Collections.emptyList(),
-              DexAnnotationSet.empty(),
-              DexEncodedField.EMPTY_ARRAY,
-              DexEncodedField.EMPTY_ARRAY,
-              DexEncodedMethod.EMPTY_ARRAY,
-              new DexEncodedMethod[] {itfMethod},
-              factory.getSkipNameValidationForTesting(),
-              getChecksumSupplier(itfMethod));
-      appView.appInfo().addSynthesizedClass(dispatchInterface);
-      builder.addSynthesizedClass(dispatchInterface, false);
+      synthesizeClassWithUniqueMethod(
+          builder,
+          itfAccessFlags,
+          interfaceType,
+          itfMethod,
+          "desugared library dispatch interface",
+          false);
       // Dispatch holder.
       DexType holderType = dispatchHolderTypeFor(appView, emulatedDispatchMethod);
       DexEncodedMethod dispatchMethod =
           generateHolderDispatchMethod(emulatedDispatchMethod, holderType, itfMethod.method);
-      DexProgramClass dispatchHolder =
-          new DexProgramClass(
-              holderType,
-              null,
-              new SynthesizedOrigin("desugared library dispatch holder class", getClass()),
-              holderAccessFlags,
-              factory.objectType,
-              DexTypeList.empty(),
-              null,
-              null,
-              Collections.emptyList(),
-              null,
-              Collections.emptyList(),
-              DexAnnotationSet.empty(),
-              DexEncodedField.EMPTY_ARRAY,
-              DexEncodedField.EMPTY_ARRAY,
-              new DexEncodedMethod[] {dispatchMethod},
-              DexEncodedMethod.EMPTY_ARRAY,
-              factory.getSkipNameValidationForTesting(),
-              getChecksumSupplier(dispatchMethod));
-      appView.appInfo().addSynthesizedClass(dispatchHolder);
-      builder.addSynthesizedClass(dispatchHolder, false);
+      synthesizeClassWithUniqueMethod(
+          builder,
+          holderAccessFlags,
+          holderType,
+          dispatchMethod,
+          "desugared library dispatch class",
+          false);
     }
   }
 
+  private DexProgramClass synthesizeClassWithUniqueMethod(
+      Builder<?> builder,
+      ClassAccessFlags accessFlags,
+      DexType type,
+      DexEncodedMethod uniqueMethod,
+      String origin,
+      boolean addToMainDexList) {
+    DexProgramClass newClass =
+        new DexProgramClass(
+            type,
+            null,
+            new SynthesizedOrigin(origin, getClass()),
+            accessFlags,
+            factory.objectType,
+            DexTypeList.empty(),
+            null,
+            null,
+            Collections.emptyList(),
+            null,
+            Collections.emptyList(),
+            DexAnnotationSet.empty(),
+            DexEncodedField.EMPTY_ARRAY,
+            DexEncodedField.EMPTY_ARRAY,
+            uniqueMethod.isStatic()
+                ? new DexEncodedMethod[] {uniqueMethod}
+                : DexEncodedMethod.EMPTY_ARRAY,
+            uniqueMethod.isStatic()
+                ? DexEncodedMethod.EMPTY_ARRAY
+                : new DexEncodedMethod[] {uniqueMethod},
+            factory.getSkipNameValidationForTesting(),
+            getChecksumSupplier(uniqueMethod));
+    appView.appInfo().addSynthesizedClass(newClass);
+    builder.addSynthesizedClass(newClass, addToMainDexList);
+    return newClass;
+  }
+
   private DexEncodedMethod generateInterfaceDispatchMethod(
       DexMethod emulatedDispatchMethod, DexType interfaceType) {
     MethodAccessFlags flags =
@@ -433,20 +402,16 @@
     //    }
     // We do not deal with complex cases (multiple retargeting of the same signature in the
     // same inheritance tree, etc., since they do not happen in the most common desugared library.
-    DexItemFactory factory = appView.dexItemFactory();
-    DexProto newProto =
-        factory.prependTypeToProto(emulatedDispatchMethod.holder, emulatedDispatchMethod.proto);
-    DexMethod newMethod =
-        factory.createMethod(dispatchHolder, newProto, emulatedDispatchMethod.name);
-    DexType desugarType =
+    DexMethod desugarMethod =
         appView
             .options()
             .desugaredLibraryConfiguration
-            .getRetargetCoreLibMember()
-            .get(emulatedDispatchMethod.name)
-            .get(emulatedDispatchMethod.holder);
-    DexMethod desugarMethod =
-        factory.createMethod(desugarType, newProto, emulatedDispatchMethod.name);
+            .retargetMethod(emulatedDispatchMethod, appView);
+    assert desugarMethod != null; // This method is reached only for retarget core lib members.
+    DexMethod newMethod =
+        appView
+            .dexItemFactory()
+            .createMethod(dispatchHolder, desugarMethod.proto, emulatedDispatchMethod.name);
     return DexEncodedMethod.toEmulateDispatchLibraryMethod(
         emulatedDispatchMethod.holder,
         newMethod,
@@ -540,7 +505,9 @@
       // we do not desugar to avoid confusion in error messages.
       if (appView.rewritePrefix.hasRewrittenType(factory.optionalType)
           || options.minApiLevel >= AndroidApiLevel.N.getLevel()) {
-        initializeOptionalMethodProviders(factory);
+        initializeJava9OptionalMethodProviders(factory);
+        initializeJava10OptionalMethodProviders(factory);
+        initializeJava11OptionalMethodProviders(factory);
       }
       if (appView.rewritePrefix.hasRewrittenType(factory.streamType)
           || options.minApiLevel >= AndroidApiLevel.N.getLevel()) {
@@ -549,6 +516,7 @@
 
       // These are currently not implemented at any API level in Android.
       initializeJava9MethodProviders(factory);
+      initializeJava10MethodProviders(factory);
       initializeJava11MethodProviders(factory);
 
       if (!options.desugaredLibraryConfiguration.getRetargetCoreLibMember().isEmpty()) {
@@ -1241,6 +1209,24 @@
                 BackportedMethods::MathMethods_multiplyExactLongInt,
                 "multiplyExactLongInt"));
 
+        // long {Math,StrictMath}.multiplyFull(int, int)
+        name = factory.createString("multiplyFull");
+        proto = factory.createProto(factory.longType, factory.intType, factory.intType);
+        method = factory.createMethod(type, proto, name);
+        addProvider(
+            new MethodGenerator(
+                method,
+                BackportedMethods::MathMethods_multiplyFull));
+
+        // long {Math,StrictMath}.multiplyHigh(long, long)
+        name = factory.createString("multiplyHigh");
+        proto = factory.createProto(factory.longType, factory.longType, factory.longType);
+        method = factory.createMethod(type, proto, name);
+        addProvider(
+            new MethodGenerator(
+                method,
+                BackportedMethods::MathMethods_multiplyHigh));
+
         // long {Math,StrictMath}.floorDiv(long, int)
         name = factory.createString("floorDiv");
         proto = factory.createProto(factory.longType, factory.longType, factory.intType);
@@ -1385,6 +1371,41 @@
       addProvider(new MethodGenerator(method, BackportedMethods::CollectionMethods_mapEntry));
     }
 
+    private void initializeJava10MethodProviders(DexItemFactory factory) {
+      // List
+      DexType type = factory.listType;
+
+      // List List.copyOf(Collection)
+      DexString name = factory.createString("copyOf");
+      DexProto proto = factory.createProto(factory.listType, factory.collectionType);
+      DexMethod method = factory.createMethod(type, proto, name);
+      addProvider(
+          new MethodGenerator(
+              method, BackportedMethods::CollectionsMethods_copyOfList, "copyOfList"));
+
+      // Set
+      type = factory.setType;
+
+      // Set Set.copyOf(Collection)
+      name = factory.createString("copyOf");
+      proto = factory.createProto(factory.setType, factory.collectionType);
+      method = factory.createMethod(type, proto, name);
+      addProvider(
+          new MethodGenerator(
+              method, BackportedMethods::CollectionsMethods_copyOfSet, "copyOfSet"));
+
+      // Set
+      type = factory.mapType;
+
+      // Map Map.copyOf(Map)
+      name = factory.createString("copyOf");
+      proto = factory.createProto(factory.mapType, factory.mapType);
+      method = factory.createMethod(type, proto, name);
+      addProvider(
+          new MethodGenerator(
+              method, BackportedMethods::CollectionsMethods_copyOfMap, "copyOfMap"));
+    }
+
     private void initializeJava11MethodProviders(DexItemFactory factory) {
       // Character
       DexType type = factory.boxedCharType;
@@ -1398,7 +1419,7 @@
               method, BackportedMethods::CharacterMethods_toStringCodepoint, "toStringCodepoint"));
     }
 
-    private void initializeOptionalMethodProviders(DexItemFactory factory) {
+    private void initializeJava9OptionalMethodProviders(DexItemFactory factory) {
       // Optional
       DexType optionalType = factory.optionalType;
 
@@ -1410,22 +1431,40 @@
           new StatifyingMethodGenerator(
               method, BackportedMethods::OptionalMethods_or, "or", optionalType));
 
-      // Optional.stream()
+      // Optional{void,Int,Long,Double}.stream()
+      DexType[] optionalTypes =
+          new DexType[] {
+              optionalType,
+              factory.optionalDoubleType,
+              factory.optionalLongType,
+              factory.optionalIntType,
+          };
+      DexType[] streamReturnTypes =
+          new DexType[] {
+              factory.streamType,
+              factory.createType(factory.createString("Ljava/util/stream/DoubleStream;")),
+              factory.createType(factory.createString("Ljava/util/stream/LongStream;")),
+              factory.createType(factory.createString("Ljava/util/stream/IntStream;")),
+          };
+      TemplateMethodFactory[] streamMethodFactories =
+          new TemplateMethodFactory[] {
+              BackportedMethods::OptionalMethods_stream,
+              BackportedMethods::OptionalMethods_streamDouble,
+              BackportedMethods::OptionalMethods_streamLong,
+              BackportedMethods::OptionalMethods_streamInt,
+          };
       name = factory.createString("stream");
-      proto = factory.createProto(factory.streamType);
-      method = factory.createMethod(optionalType, proto, name);
-      addProvider(
-          new StatifyingMethodGenerator(
-              method, BackportedMethods::OptionalMethods_stream, "stream", optionalType));
+      for (int i = 0; i < optionalTypes.length; i++) {
+        DexType optional = optionalTypes[i];
+        DexType streamReturnType = streamReturnTypes[i];
+        proto = factory.createProto(streamReturnType);
+        method = factory.createMethod(optional, proto, name);
+        addProvider(
+            new StatifyingMethodGenerator(
+                method, streamMethodFactories[i], "stream", optional));
+      }
 
       // Optional{void,Int,Long,Double}.ifPresentOrElse(consumer,runnable)
-      DexType[] optionalTypes =
-          new DexType[]{
-              optionalType,
-              factory.createType(factory.createString("Ljava/util/OptionalDouble;")),
-              factory.createType(factory.createString("Ljava/util/OptionalLong;")),
-              factory.createType(factory.createString("Ljava/util/OptionalInt;"))
-          };
       DexType[] consumerTypes =
           new DexType[]{
               factory.consumerType,
@@ -1451,6 +1490,63 @@
       }
     }
 
+    private void initializeJava10OptionalMethodProviders(DexItemFactory factory) {
+      // Optional{void,Int,Long,Double}.orElseThrow()
+      DexType[] optionalTypes =
+          new DexType[] {
+              factory.optionalType,
+              factory.optionalDoubleType,
+              factory.optionalLongType,
+              factory.optionalIntType,
+          };
+      DexType[] returnTypes =
+          new DexType[] {
+              factory.objectType,
+              factory.doubleType,
+              factory.longType,
+              factory.intType,
+          };
+      MethodInvokeRewriter[] rewriters =
+          new MethodInvokeRewriter[] {
+              OptionalMethodRewrites::rewriteOrElseGet,
+              OptionalMethodRewrites::rewriteDoubleOrElseGet,
+              OptionalMethodRewrites::rewriteLongOrElseGet,
+              OptionalMethodRewrites::rewriteIntOrElseGet,
+          };
+      DexString name = factory.createString("orElseThrow");
+      for (int i = 0; i < optionalTypes.length; i++) {
+        DexProto proto = factory.createProto(returnTypes[i]);
+        DexMethod method = factory.createMethod(optionalTypes[i], proto, name);
+        addProvider(new InvokeRewriter(method, rewriters[i]));
+      }
+    }
+
+    private void initializeJava11OptionalMethodProviders(DexItemFactory factory) {
+      // Optional{void,Int,Long,Double}.isEmpty()
+      DexType[] optionalTypes =
+          new DexType[] {
+              factory.optionalType,
+              factory.optionalDoubleType,
+              factory.optionalLongType,
+              factory.optionalIntType,
+          };
+      TemplateMethodFactory[] methodFactories =
+          new TemplateMethodFactory[]{
+              BackportedMethods::OptionalMethods_isEmpty,
+              BackportedMethods::OptionalMethods_isEmptyDouble,
+              BackportedMethods::OptionalMethods_isEmptyLong,
+              BackportedMethods::OptionalMethods_isEmptyInt
+          };
+      DexString name = factory.createString("isEmpty");
+      for (int i = 0; i < optionalTypes.length; i++) {
+        DexType optionalType = optionalTypes[i];
+        DexProto proto = factory.createProto(factory.booleanType);
+        DexMethod method = factory.createMethod(optionalType, proto, name);
+        addProvider(
+            new StatifyingMethodGenerator(method, methodFactories[i], "isEmpty", optionalType));
+      }
+    }
+
     private void initializeStreamMethodProviders(DexItemFactory factory) {
       // Stream
       DexType streamType = factory.streamType;
@@ -1461,7 +1557,7 @@
       DexMethod method = factory.createMethod(streamType, proto, name);
       addProvider(
           new MethodGenerator(
-              method, BackportedMethods::StreamMethods_ofNullable, "ofNullable") {});
+              method, BackportedMethods::StreamMethods_ofNullable, "ofNullable"));
     }
 
     private void warnMissingRetargetCoreLibraryMember(DexType type, AppView<?> appView) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
index c2f5ae9..f4fbdde 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
@@ -12,15 +12,12 @@
 import com.android.tools.r8.graph.DexLibraryClass;
 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.MethodAccessFlags;
 import com.android.tools.r8.graph.ParameterAnnotationsList;
 import com.android.tools.r8.graph.ResolutionResult;
 import com.android.tools.r8.graph.ResolutionResult.IncompatibleClassResult;
-import com.android.tools.r8.ir.code.Invoke;
 import com.android.tools.r8.ir.synthetic.ExceptionThrowingSourceCode;
-import com.android.tools.r8.ir.synthetic.ForwardMethodSourceCode;
 import com.android.tools.r8.ir.synthetic.SynthesizedCode;
 import com.android.tools.r8.utils.MethodSignatureEquivalence;
 import com.google.common.base.Equivalence.Wrapper;
@@ -50,6 +47,7 @@
 
   // Collection for method signatures that may cause forwarding methods to be created.
   private static class MethodSignatures {
+
     static final MethodSignatures EMPTY = new MethodSignatures(Collections.emptySet());
 
     static MethodSignatures create(Set<Wrapper<DexMethod>> signatures) {
@@ -125,6 +123,7 @@
 
   // Helper to keep track of the direct active subclass and nearest program subclass for reporting.
   private static class ReportingContext {
+
     final DexClass directSubClass;
     final DexProgramClass closestProgramSubClass;
 
@@ -156,6 +155,7 @@
 
   // Specialized context to disable reporting when traversing the library strucure.
   private static class LibraryReportingContext extends ReportingContext {
+
     static final LibraryReportingContext LIBRARY_CONTEXT = new LibraryReportingContext();
 
     LibraryReportingContext() {
@@ -340,13 +340,8 @@
     if (method.isFinal()) {
       return false;
     }
-    Map<DexType, DexType> typeMap =
-        appView
-            .options()
-            .desugaredLibraryConfiguration
-            .getRetargetCoreLibMember()
-            .get(method.method.name);
-    return typeMap != null && typeMap.containsKey(holder.type);
+    return appView.options().desugaredLibraryConfiguration.retargetMethod(method.method, appView)
+        != null;
   }
 
   private boolean dontRewrite(DexClass clazz, DexEncodedMethod method) {
@@ -391,42 +386,11 @@
     DexMethod forwardMethod =
         targetHolder.isInterface()
             ? rewriter.defaultAsMethodOfCompanionClass(method)
-            : retargetMethod(appView, method);
-    // New method will have the same name, proto, and also all the flags of the
-    // default method, including bridge flag.
-    DexMethod newMethod = dexItemFactory.createMethod(clazz.type, method.proto, method.name);
-    MethodAccessFlags newFlags = target.accessFlags.copy();
-    // Some debuggers (like IntelliJ) automatically skip synthetic methods on single step.
-    newFlags.setSynthetic();
-    ForwardMethodSourceCode.Builder forwardSourceCodeBuilder =
-        ForwardMethodSourceCode.builder(newMethod);
-    forwardSourceCodeBuilder
-        .setReceiver(clazz.type)
-        .setTarget(forwardMethod)
-        .setInvokeType(Invoke.Type.STATIC)
-        .setIsInterface(false); // Holder is companion class, not an interface.
-    DexEncodedMethod newEncodedMethod =
-        new DexEncodedMethod(
-            newMethod,
-            newFlags,
-            target.annotations,
-            target.parameterAnnotationsList,
-            new SynthesizedCode(forwardSourceCodeBuilder::build));
-    addSyntheticMethod(clazz.asProgramClass(), newEncodedMethod);
-  }
-
-  static DexMethod retargetMethod(AppView<?> appView, DexMethod method) {
-    Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
-        appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember();
-    Map<DexType, DexType> typeMap = retargetCoreLibMember.get(method.name);
-    assert typeMap != null;
-    assert typeMap.get(method.holder) != null;
-    return appView
-        .dexItemFactory()
-        .createMethod(
-            typeMap.get(method.holder),
-            appView.dexItemFactory().prependTypeToProto(method.holder, method.proto),
-            method.name);
+            : appView.options().desugaredLibraryConfiguration.retargetMethod(method, appView);
+    DexEncodedMethod desugaringForwardingMethod =
+        DexEncodedMethod.createDesugaringForwardingMethod(
+            target, clazz, forwardMethod, dexItemFactory);
+    addSyntheticMethod(clazz.asProgramClass(), desugaringForwardingMethod);
   }
 
   // Topological order traversal and its helpers.
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java
index 68a8bd4..e4af36c 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java
@@ -62,7 +62,7 @@
       InstructionListIterator instructions = block.listIterator(code);
       while (instructions.hasNext()) {
         Instruction instruction = instructions.next();
-        if (instruction.isInvokeMethod() && !instruction.isInvokeSuper()) {
+        if (instruction.isInvokeMethod()) {
           InvokeMethod invokeMethod = instruction.asInvokeMethod();
           DexMethod methodCalled = invokeMethod.getInvokedMethod();
           DexEncodedMethod encodedMethodCalled =
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfiguration.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfiguration.java
index fd954e5..3d0a59c 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfiguration.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfiguration.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.desugar.PrefixRewritingMapper.DesugarPrefixRewritingMapper;
@@ -126,6 +127,20 @@
     return emulateLibraryInterface;
   }
 
+  // If the method is retargeted, answers the retargeted method, else null.
+  public DexMethod retargetMethod(DexMethod method, AppView<?> appView) {
+    Map<DexType, DexType> typeMap = retargetCoreLibMember.get(method.name);
+    if (typeMap != null && typeMap.containsKey(method.holder)) {
+      return appView
+          .dexItemFactory()
+          .createMethod(
+              typeMap.get(method.holder),
+              appView.dexItemFactory().prependTypeToProto(method.holder, method.proto),
+              method.name);
+    }
+    return null;
+  }
+
   public Map<DexString, Map<DexType, DexType>> getRetargetCoreLibMember() {
     return retargetCoreLibMember;
   }
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 c9bd364..e3e7ab0 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
@@ -395,6 +395,8 @@
     MethodAccessFlags newFlags = template.accessFlags.copy();
     assert newFlags.isPublic();
     newFlags.unsetAbstract();
+    // TODO(b/146114533): Fix inlining in synthetic methods and remove unsetBridge.
+    newFlags.unsetBridge();
     newFlags.setSynthetic();
     return new DexEncodedMethod(
         methodToInstall,
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
index 679f927..a43d321 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
@@ -25,7 +25,6 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.DexTypeList;
 import com.android.tools.r8.graph.DexValue;
-import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.graph.GraphLense.NestedGraphLense;
 import com.android.tools.r8.graph.ResolutionResult;
 import com.android.tools.r8.ir.code.BasicBlock;
@@ -38,6 +37,7 @@
 import com.android.tools.r8.ir.code.InvokeSuper;
 import com.android.tools.r8.ir.conversion.IRConverter;
 import com.android.tools.r8.ir.desugar.DefaultMethodsHelper.Collection;
+import com.android.tools.r8.ir.desugar.InterfaceProcessor.InterfaceProcessorNestedGraphLense;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.origin.SynthesizedOrigin;
 import com.android.tools.r8.position.MethodPosition;
@@ -288,11 +288,10 @@
                   // Rewriting is required because the super invoke resolves into a missing
                   // method (method is on desugared library). Find out if it needs to be
                   // retarget or if it just calls a companion class method and rewrite.
-                  Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
-                      options.desugaredLibraryConfiguration.getRetargetCoreLibMember();
-                  Map<DexType, DexType> typeMap =
-                      retargetCoreLibMember.get(dexEncodedMethod.method.name);
-                  if (typeMap == null || !typeMap.containsKey(dexEncodedMethod.method.holder)) {
+                  DexMethod retargetMethod =
+                      options.desugaredLibraryConfiguration.retargetMethod(
+                          dexEncodedMethod.method, appView);
+                  if (retargetMethod == null) {
                     DexMethod originalCompanionMethod =
                         instanceAsMethodOfCompanionClass(
                             dexEncodedMethod.method, DEFAULT_METHOD_PREFIX, factory);
@@ -306,12 +305,6 @@
                         new InvokeStatic(
                             companionMethod, invokeSuper.outValue(), invokeSuper.arguments()));
                   } else {
-                    DexMethod retargetMethod =
-                        factory.createMethod(
-                            typeMap.get(dexEncodedMethod.method.holder),
-                            factory.prependTypeToProto(
-                                dexEncodedMethod.method.holder, dexEncodedMethod.method.proto),
-                            dexEncodedMethod.method.name);
                     instructions.replaceCurrentInstruction(
                         new InvokeStatic(
                             retargetMethod, invokeSuper.outValue(), invokeSuper.arguments()));
@@ -964,7 +957,7 @@
   }
 
   private Map<DexType, DexProgramClass> processInterfaces(Builder<?> builder, Flavor flavour) {
-    NestedGraphLense.Builder graphLensBuilder = GraphLense.builder();
+    NestedGraphLense.Builder graphLensBuilder = InterfaceProcessorNestedGraphLense.builder();
     InterfaceProcessor processor = new InterfaceProcessor(appView, this);
     for (DexProgramClass clazz : builder.getProgramClasses()) {
       if (shouldProcess(clazz, flavour, true)) {
@@ -1058,6 +1051,7 @@
     // they are in the desugared library.
     if (appView.rewritePrefix.hasRewrittenType(missing)
         || DesugaredLibraryWrapperSynthesizer.isSynthesizedWrapper(missing)
+        || isCompanionClassType(missing)
         || appView
             .options()
             .desugaredLibraryConfiguration
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
index 1c20983..787fbe1 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
@@ -18,12 +18,15 @@
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexLibraryClass;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexProgramClass.ChecksumSupplier;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.DexTypeList;
+import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.graph.GraphLense.NestedGraphLense;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.ParameterAnnotationsList;
@@ -31,6 +34,7 @@
 import com.android.tools.r8.ir.synthetic.ForwardMethodSourceCode;
 import com.android.tools.r8.ir.synthetic.SynthesizedCode;
 import com.android.tools.r8.origin.SynthesizedOrigin;
+import com.google.common.collect.BiMap;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -341,4 +345,53 @@
     }
     return method.accessFlags.isStatic() && !rewriter.factory.isClassConstructor(method.method);
   }
+
+  // Specific lens which remaps invocation types to static since all rewrites performed here
+  // are to static companion methods.
+  public static class InterfaceProcessorNestedGraphLense extends NestedGraphLense {
+
+    public InterfaceProcessorNestedGraphLense(
+        Map<DexType, DexType> typeMap,
+        Map<DexMethod, DexMethod> methodMap,
+        Map<DexField, DexField> fieldMap,
+        BiMap<DexField, DexField> originalFieldSignatures,
+        BiMap<DexMethod, DexMethod> originalMethodSignatures,
+        GraphLense previousLense,
+        DexItemFactory dexItemFactory) {
+      super(
+          typeMap,
+          methodMap,
+          fieldMap,
+          originalFieldSignatures,
+          originalMethodSignatures,
+          previousLense,
+          dexItemFactory);
+    }
+
+    @Override
+    protected Type mapInvocationType(DexMethod newMethod, DexMethod originalMethod, Type type) {
+      return Type.STATIC;
+    }
+
+    public static GraphLense.Builder builder() {
+      return new Builder();
+    }
+
+    public static class Builder extends NestedGraphLense.Builder {
+      @Override
+      public GraphLense build(DexItemFactory dexItemFactory, GraphLense previousLense) {
+        if (originalFieldSignatures.isEmpty() && originalMethodSignatures.isEmpty()) {
+          return previousLense;
+        }
+        return new InterfaceProcessorNestedGraphLense(
+            typeMap,
+            methodMap,
+            fieldMap,
+            originalFieldSignatures,
+            originalMethodSignatures,
+            previousLense,
+            dexItemFactory);
+      }
+    }
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
index ff95053..30edf6a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
@@ -385,8 +385,7 @@
 
     @Override
     public boolean registerInvokeSuper(DexMethod method) {
-      // Cannot target private method.
-      return false;
+      return registerInvoke(method, Invoke.Type.SUPER);
     }
 
     @Override
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 ddfb1c5..8440fc2 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
@@ -958,6 +958,363 @@
         ImmutableList.of());
   }
 
+  public static CfCode CollectionsMethods_copyOfList(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,
+        4,
+        ImmutableList.of(
+            label0,
+            new CfNew(options.itemFactory.createType("Ljava/util/ArrayList;")),
+            new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInvoke(
+                185,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/Collection;"),
+                    options.itemFactory.createProto(options.itemFactory.createType("I")),
+                    options.itemFactory.createString("size")),
+                true),
+            new CfInvoke(
+                183,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/ArrayList;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("V"), options.itemFactory.createType("I")),
+                    options.itemFactory.createString("<init>")),
+                false),
+            new CfStore(ValueType.OBJECT, 1),
+            label1,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInvoke(
+                185,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/Collection;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/util/Iterator;")),
+                    options.itemFactory.createString("iterator")),
+                true),
+            new CfStore(ValueType.OBJECT, 2),
+            label2,
+            new CfLoad(ValueType.OBJECT, 2),
+            new CfInvoke(
+                185,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/Iterator;"),
+                    options.itemFactory.createProto(options.itemFactory.createType("Z")),
+                    options.itemFactory.createString("hasNext")),
+                true),
+            new CfIf(If.Type.EQ, ValueType.INT, label5),
+            new CfLoad(ValueType.OBJECT, 2),
+            new CfInvoke(
+                185,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/Iterator;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/lang/Object;")),
+                    options.itemFactory.createString("next")),
+                true),
+            new CfStore(ValueType.OBJECT, 3),
+            label3,
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 3),
+            new CfInvoke(
+                184,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/Objects;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/lang/Object;"),
+                        options.itemFactory.createType("Ljava/lang/Object;")),
+                    options.itemFactory.createString("requireNonNull")),
+                false),
+            new CfInvoke(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/ArrayList;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Z"),
+                        options.itemFactory.createType("Ljava/lang/Object;")),
+                    options.itemFactory.createString("add")),
+                false),
+            new CfStackInstruction(CfStackInstruction.Opcode.Pop),
+            label4,
+            new CfGoto(label2),
+            label5,
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfInvoke(
+                184,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/Collections;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/util/List;"),
+                        options.itemFactory.createType("Ljava/util/List;")),
+                    options.itemFactory.createString("unmodifiableList")),
+                false),
+            new CfReturn(ValueType.OBJECT),
+            label6),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode CollectionsMethods_copyOfMap(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();
+    CfLabel label7 = new CfLabel();
+    CfLabel label8 = new CfLabel();
+    CfLabel label9 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        3,
+        4,
+        ImmutableList.of(
+            label0,
+            new CfNew(options.itemFactory.createType("Ljava/util/HashMap;")),
+            new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInvoke(
+                185,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/Map;"),
+                    options.itemFactory.createProto(options.itemFactory.createType("I")),
+                    options.itemFactory.createString("size")),
+                true),
+            new CfInvoke(
+                183,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/HashMap;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("V"), options.itemFactory.createType("I")),
+                    options.itemFactory.createString("<init>")),
+                false),
+            new CfStore(ValueType.OBJECT, 1),
+            label1,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInvoke(
+                185,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/Map;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/util/Set;")),
+                    options.itemFactory.createString("entrySet")),
+                true),
+            new CfInvoke(
+                185,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/Set;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/util/Iterator;")),
+                    options.itemFactory.createString("iterator")),
+                true),
+            new CfStore(ValueType.OBJECT, 2),
+            label2,
+            new CfLoad(ValueType.OBJECT, 2),
+            new CfInvoke(
+                185,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/Iterator;"),
+                    options.itemFactory.createProto(options.itemFactory.createType("Z")),
+                    options.itemFactory.createString("hasNext")),
+                true),
+            new CfIf(If.Type.EQ, ValueType.INT, label8),
+            new CfLoad(ValueType.OBJECT, 2),
+            new CfInvoke(
+                185,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/Iterator;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/lang/Object;")),
+                    options.itemFactory.createString("next")),
+                true),
+            new CfCheckCast(options.itemFactory.createType("Ljava/util/Map$Entry;")),
+            new CfStore(ValueType.OBJECT, 3),
+            label3,
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 3),
+            label4,
+            new CfInvoke(
+                185,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/Map$Entry;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/lang/Object;")),
+                    options.itemFactory.createString("getKey")),
+                true),
+            new CfInvoke(
+                184,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/Objects;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/lang/Object;"),
+                        options.itemFactory.createType("Ljava/lang/Object;")),
+                    options.itemFactory.createString("requireNonNull")),
+                false),
+            new CfLoad(ValueType.OBJECT, 3),
+            label5,
+            new CfInvoke(
+                185,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/Map$Entry;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/lang/Object;")),
+                    options.itemFactory.createString("getValue")),
+                true),
+            new CfInvoke(
+                184,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/Objects;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/lang/Object;"),
+                        options.itemFactory.createType("Ljava/lang/Object;")),
+                    options.itemFactory.createString("requireNonNull")),
+                false),
+            label6,
+            new CfInvoke(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/HashMap;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/lang/Object;"),
+                        options.itemFactory.createType("Ljava/lang/Object;"),
+                        options.itemFactory.createType("Ljava/lang/Object;")),
+                    options.itemFactory.createString("put")),
+                false),
+            new CfStackInstruction(CfStackInstruction.Opcode.Pop),
+            label7,
+            new CfGoto(label2),
+            label8,
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfInvoke(
+                184,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/Collections;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/util/Map;"),
+                        options.itemFactory.createType("Ljava/util/Map;")),
+                    options.itemFactory.createString("unmodifiableMap")),
+                false),
+            new CfReturn(ValueType.OBJECT),
+            label9),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode CollectionsMethods_copyOfSet(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,
+        4,
+        ImmutableList.of(
+            label0,
+            new CfNew(options.itemFactory.createType("Ljava/util/HashSet;")),
+            new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInvoke(
+                185,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/Collection;"),
+                    options.itemFactory.createProto(options.itemFactory.createType("I")),
+                    options.itemFactory.createString("size")),
+                true),
+            new CfInvoke(
+                183,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/HashSet;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("V"), options.itemFactory.createType("I")),
+                    options.itemFactory.createString("<init>")),
+                false),
+            new CfStore(ValueType.OBJECT, 1),
+            label1,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInvoke(
+                185,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/Collection;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/util/Iterator;")),
+                    options.itemFactory.createString("iterator")),
+                true),
+            new CfStore(ValueType.OBJECT, 2),
+            label2,
+            new CfLoad(ValueType.OBJECT, 2),
+            new CfInvoke(
+                185,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/Iterator;"),
+                    options.itemFactory.createProto(options.itemFactory.createType("Z")),
+                    options.itemFactory.createString("hasNext")),
+                true),
+            new CfIf(If.Type.EQ, ValueType.INT, label5),
+            new CfLoad(ValueType.OBJECT, 2),
+            new CfInvoke(
+                185,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/Iterator;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/lang/Object;")),
+                    options.itemFactory.createString("next")),
+                true),
+            new CfStore(ValueType.OBJECT, 3),
+            label3,
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 3),
+            new CfInvoke(
+                184,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/Objects;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/lang/Object;"),
+                        options.itemFactory.createType("Ljava/lang/Object;")),
+                    options.itemFactory.createString("requireNonNull")),
+                false),
+            new CfInvoke(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/HashSet;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Z"),
+                        options.itemFactory.createType("Ljava/lang/Object;")),
+                    options.itemFactory.createString("add")),
+                false),
+            new CfStackInstruction(CfStackInstruction.Opcode.Pop),
+            label4,
+            new CfGoto(label2),
+            label5,
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfInvoke(
+                184,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/Collections;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/util/Set;"),
+                        options.itemFactory.createType("Ljava/util/Set;")),
+                    options.itemFactory.createString("unmodifiableSet")),
+                false),
+            new CfReturn(ValueType.OBJECT),
+            label6),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
   public static CfCode CollectionsMethods_emptyEnumeration(
       InternalOptions options, DexMethod method) {
     CfLabel label0 = new CfLabel();
@@ -3155,6 +3512,130 @@
         ImmutableList.of());
   }
 
+  public static CfCode MathMethods_multiplyFull(InternalOptions options, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        4,
+        2,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.INT, 0),
+            new CfNumberConversion(NumericType.INT, NumericType.LONG),
+            new CfLoad(ValueType.INT, 1),
+            new CfNumberConversion(NumericType.INT, NumericType.LONG),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.LONG),
+            new CfReturn(ValueType.LONG),
+            label1),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode MathMethods_multiplyHigh(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();
+    CfLabel label7 = new CfLabel();
+    CfLabel label8 = new CfLabel();
+    CfLabel label9 = new CfLabel();
+    CfLabel label10 = new CfLabel();
+    CfLabel label11 = new CfLabel();
+    CfLabel label12 = new CfLabel();
+    CfLabel label13 = new CfLabel();
+    CfLabel label14 = new CfLabel();
+    CfLabel label15 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        4,
+        32,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.LONG, 0),
+            new CfConstNumber(4294967295L, ValueType.LONG),
+            new CfLogicalBinop(CfLogicalBinop.Opcode.And, NumericType.LONG),
+            new CfStore(ValueType.LONG, 4),
+            label1,
+            new CfLoad(ValueType.LONG, 0),
+            new CfConstNumber(32, ValueType.INT),
+            new CfLogicalBinop(CfLogicalBinop.Opcode.Shr, NumericType.LONG),
+            new CfStore(ValueType.LONG, 6),
+            label2,
+            new CfLoad(ValueType.LONG, 2),
+            new CfConstNumber(4294967295L, ValueType.LONG),
+            new CfLogicalBinop(CfLogicalBinop.Opcode.And, NumericType.LONG),
+            new CfStore(ValueType.LONG, 8),
+            label3,
+            new CfLoad(ValueType.LONG, 2),
+            new CfConstNumber(32, ValueType.INT),
+            new CfLogicalBinop(CfLogicalBinop.Opcode.Shr, NumericType.LONG),
+            new CfStore(ValueType.LONG, 10),
+            label4,
+            new CfLoad(ValueType.LONG, 4),
+            new CfLoad(ValueType.LONG, 8),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.LONG),
+            new CfStore(ValueType.LONG, 12),
+            label5,
+            new CfLoad(ValueType.LONG, 12),
+            new CfConstNumber(32, ValueType.INT),
+            new CfLogicalBinop(CfLogicalBinop.Opcode.Ushr, NumericType.LONG),
+            new CfStore(ValueType.LONG, 14),
+            label6,
+            new CfLoad(ValueType.LONG, 6),
+            new CfLoad(ValueType.LONG, 8),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.LONG),
+            new CfStore(ValueType.LONG, 16),
+            label7,
+            new CfLoad(ValueType.LONG, 16),
+            new CfLoad(ValueType.LONG, 14),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.LONG),
+            new CfStore(ValueType.LONG, 18),
+            label8,
+            new CfLoad(ValueType.LONG, 18),
+            new CfConstNumber(4294967295L, ValueType.LONG),
+            new CfLogicalBinop(CfLogicalBinop.Opcode.And, NumericType.LONG),
+            new CfStore(ValueType.LONG, 20),
+            label9,
+            new CfLoad(ValueType.LONG, 18),
+            new CfConstNumber(32, ValueType.INT),
+            new CfLogicalBinop(CfLogicalBinop.Opcode.Shr, NumericType.LONG),
+            new CfStore(ValueType.LONG, 22),
+            label10,
+            new CfLoad(ValueType.LONG, 4),
+            new CfLoad(ValueType.LONG, 10),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.LONG),
+            new CfStore(ValueType.LONG, 24),
+            label11,
+            new CfLoad(ValueType.LONG, 24),
+            new CfLoad(ValueType.LONG, 20),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.LONG),
+            new CfStore(ValueType.LONG, 26),
+            label12,
+            new CfLoad(ValueType.LONG, 26),
+            new CfConstNumber(32, ValueType.INT),
+            new CfLogicalBinop(CfLogicalBinop.Opcode.Shr, NumericType.LONG),
+            new CfStore(ValueType.LONG, 28),
+            label13,
+            new CfLoad(ValueType.LONG, 6),
+            new CfLoad(ValueType.LONG, 10),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.LONG),
+            new CfStore(ValueType.LONG, 30),
+            label14,
+            new CfLoad(ValueType.LONG, 30),
+            new CfLoad(ValueType.LONG, 22),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.LONG),
+            new CfLoad(ValueType.LONG, 28),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.LONG),
+            new CfReturn(ValueType.LONG),
+            label15),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
   public static CfCode MathMethods_negateExactInt(InternalOptions options, DexMethod method) {
     CfLabel label0 = new CfLabel();
     CfLabel label1 = new CfLabel();
@@ -4689,6 +5170,130 @@
         ImmutableList.of());
   }
 
+  public static CfCode OptionalMethods_isEmpty(InternalOptions options, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        1,
+        1,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInvoke(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/Optional;"),
+                    options.itemFactory.createProto(options.itemFactory.createType("Z")),
+                    options.itemFactory.createString("isPresent")),
+                false),
+            new CfIf(If.Type.NE, ValueType.INT, label1),
+            new CfConstNumber(1, ValueType.INT),
+            new CfGoto(label2),
+            label1,
+            new CfConstNumber(0, ValueType.INT),
+            label2,
+            new CfReturn(ValueType.INT),
+            label3),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode OptionalMethods_isEmptyDouble(InternalOptions options, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        1,
+        1,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInvoke(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/OptionalDouble;"),
+                    options.itemFactory.createProto(options.itemFactory.createType("Z")),
+                    options.itemFactory.createString("isPresent")),
+                false),
+            new CfIf(If.Type.NE, ValueType.INT, label1),
+            new CfConstNumber(1, ValueType.INT),
+            new CfGoto(label2),
+            label1,
+            new CfConstNumber(0, ValueType.INT),
+            label2,
+            new CfReturn(ValueType.INT),
+            label3),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode OptionalMethods_isEmptyInt(InternalOptions options, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        1,
+        1,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInvoke(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/OptionalInt;"),
+                    options.itemFactory.createProto(options.itemFactory.createType("Z")),
+                    options.itemFactory.createString("isPresent")),
+                false),
+            new CfIf(If.Type.NE, ValueType.INT, label1),
+            new CfConstNumber(1, ValueType.INT),
+            new CfGoto(label2),
+            label1,
+            new CfConstNumber(0, ValueType.INT),
+            label2,
+            new CfReturn(ValueType.INT),
+            label3),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode OptionalMethods_isEmptyLong(InternalOptions options, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        1,
+        1,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInvoke(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/OptionalLong;"),
+                    options.itemFactory.createProto(options.itemFactory.createType("Z")),
+                    options.itemFactory.createString("isPresent")),
+                false),
+            new CfIf(If.Type.NE, ValueType.INT, label1),
+            new CfConstNumber(1, ValueType.INT),
+            new CfGoto(label2),
+            label1,
+            new CfConstNumber(0, ValueType.INT),
+            label2,
+            new CfReturn(ValueType.INT),
+            label3),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
   public static CfCode OptionalMethods_or(InternalOptions options, DexMethod method) {
     CfLabel label0 = new CfLabel();
     CfLabel label1 = new CfLabel();
@@ -4811,6 +5416,168 @@
         ImmutableList.of());
   }
 
+  public static CfCode OptionalMethods_streamDouble(InternalOptions options, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        2,
+        1,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInvoke(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/OptionalDouble;"),
+                    options.itemFactory.createProto(options.itemFactory.createType("Z")),
+                    options.itemFactory.createString("isPresent")),
+                false),
+            new CfIf(If.Type.EQ, ValueType.INT, label2),
+            label1,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInvoke(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/OptionalDouble;"),
+                    options.itemFactory.createProto(options.itemFactory.createType("D")),
+                    options.itemFactory.createString("getAsDouble")),
+                false),
+            new CfInvoke(
+                184,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/stream/DoubleStream;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/util/stream/DoubleStream;"),
+                        options.itemFactory.createType("D")),
+                    options.itemFactory.createString("of")),
+                true),
+            new CfReturn(ValueType.OBJECT),
+            label2,
+            new CfInvoke(
+                184,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/stream/DoubleStream;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/util/stream/DoubleStream;")),
+                    options.itemFactory.createString("empty")),
+                true),
+            new CfReturn(ValueType.OBJECT),
+            label3),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode OptionalMethods_streamInt(InternalOptions options, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        1,
+        1,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInvoke(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/OptionalInt;"),
+                    options.itemFactory.createProto(options.itemFactory.createType("Z")),
+                    options.itemFactory.createString("isPresent")),
+                false),
+            new CfIf(If.Type.EQ, ValueType.INT, label2),
+            label1,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInvoke(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/OptionalInt;"),
+                    options.itemFactory.createProto(options.itemFactory.createType("I")),
+                    options.itemFactory.createString("getAsInt")),
+                false),
+            new CfInvoke(
+                184,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/stream/IntStream;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/util/stream/IntStream;"),
+                        options.itemFactory.createType("I")),
+                    options.itemFactory.createString("of")),
+                true),
+            new CfReturn(ValueType.OBJECT),
+            label2,
+            new CfInvoke(
+                184,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/stream/IntStream;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/util/stream/IntStream;")),
+                    options.itemFactory.createString("empty")),
+                true),
+            new CfReturn(ValueType.OBJECT),
+            label3),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode OptionalMethods_streamLong(InternalOptions options, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        2,
+        1,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInvoke(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/OptionalLong;"),
+                    options.itemFactory.createProto(options.itemFactory.createType("Z")),
+                    options.itemFactory.createString("isPresent")),
+                false),
+            new CfIf(If.Type.EQ, ValueType.INT, label2),
+            label1,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInvoke(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/OptionalLong;"),
+                    options.itemFactory.createProto(options.itemFactory.createType("J")),
+                    options.itemFactory.createString("getAsLong")),
+                false),
+            new CfInvoke(
+                184,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/stream/LongStream;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/util/stream/LongStream;"),
+                        options.itemFactory.createType("J")),
+                    options.itemFactory.createString("of")),
+                true),
+            new CfReturn(ValueType.OBJECT),
+            label2,
+            new CfInvoke(
+                184,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/stream/LongStream;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/util/stream/LongStream;")),
+                    options.itemFactory.createString("empty")),
+                true),
+            new CfReturn(ValueType.OBJECT),
+            label3),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
   public static CfCode ShortMethods_compare(InternalOptions options, DexMethod method) {
     CfLabel label0 = new CfLabel();
     CfLabel label1 = new CfLabel();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/OptionalMethodRewrites.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/OptionalMethodRewrites.java
new file mode 100644
index 0000000..7965b0b
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/OptionalMethodRewrites.java
@@ -0,0 +1,47 @@
+// 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.ir.desugar.backports;
+
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.ir.code.InstructionListIterator;
+import com.android.tools.r8.ir.code.InvokeMethod;
+import com.android.tools.r8.ir.code.InvokeVirtual;
+
+public final class OptionalMethodRewrites {
+
+  private OptionalMethodRewrites() {}
+
+  public static void rewriteOrElseGet(
+      InvokeMethod invoke, InstructionListIterator iterator, DexItemFactory factory) {
+    InvokeVirtual getInvoke = new InvokeVirtual(
+        factory.createMethod(factory.optionalType, invoke.getInvokedMethod().proto,
+            "get"), invoke.outValue(), invoke.inValues());
+    iterator.replaceCurrentInstruction(getInvoke);
+  }
+
+  public static void rewriteDoubleOrElseGet(
+      InvokeMethod invoke, InstructionListIterator iterator, DexItemFactory factory) {
+    InvokeVirtual getInvoke = new InvokeVirtual(
+        factory.createMethod(factory.optionalDoubleType, invoke.getInvokedMethod().proto,
+            "getAsDouble"), invoke.outValue(), invoke.inValues());
+    iterator.replaceCurrentInstruction(getInvoke);
+  }
+
+  public static void rewriteIntOrElseGet(
+      InvokeMethod invoke, InstructionListIterator iterator, DexItemFactory factory) {
+    InvokeVirtual getInvoke = new InvokeVirtual(
+        factory.createMethod(factory.optionalIntType, invoke.getInvokedMethod().proto,
+            "getAsInt"), invoke.outValue(), invoke.inValues());
+    iterator.replaceCurrentInstruction(getInvoke);
+  }
+
+  public static void rewriteLongOrElseGet(
+      InvokeMethod invoke, InstructionListIterator iterator, DexItemFactory factory) {
+    InvokeVirtual getInvoke = new InvokeVirtual(
+        factory.createMethod(factory.optionalLongType, invoke.getInvokedMethod().proto,
+            "getAsLong"), invoke.outValue(), invoke.inValues());
+    iterator.replaceCurrentInstruction(getInvoke);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index d26e953..6de35d0 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -971,6 +971,7 @@
           classInitializationAnalysis.notifyCodeHasChanged();
           strategy.updateTypeInformationIfNeeded(inlinee.code, blockIterator, block);
 
+          // TODO(b/146114533): Fix inlining in synthetic methods.
           // If we inlined the invoke from a bridge method, it is no longer a bridge method.
           if (context.accessFlags.isBridge()) {
             context.accessFlags.unsetSynthetic();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
index 18c56e6..36fd914 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
@@ -231,7 +231,10 @@
             new ClassInlinerCostAnalysis(
                 appView, inliningIRProvider, processor.getReceivers().getDefiniteReceiverAliases());
         if (costAnalysis.willExceedInstructionBudget(
-            code, processor.getDirectInlinees(), processor.getIndirectInlinees())) {
+            code,
+            processor.getEligibleClass(),
+            processor.getDirectInlinees(),
+            processor.getIndirectInlinees())) {
           // This root is unlikely to be inlined in the future.
           rootsIterator.remove();
           continue;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerCostAnalysis.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerCostAnalysis.java
index 9b9670e..da76b7b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerCostAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerCostAnalysis.java
@@ -11,11 +11,13 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InvokeMethod;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.ir.optimize.inliner.InliningIRProvider;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.google.common.collect.Sets;
 import java.util.List;
 import java.util.Map;
@@ -24,14 +26,14 @@
 /** Analysis that estimates the cost of class inlining an object allocation. */
 class ClassInlinerCostAnalysis {
 
-  private final AppView<?> appView;
+  private final AppView<AppInfoWithLiveness> appView;
   private final InliningIRProvider inliningIRProvider;
   private final Set<Value> definiteReceiverAliases;
 
   private int estimatedCost = 0;
 
   ClassInlinerCostAnalysis(
-      AppView<?> appView,
+      AppView<AppInfoWithLiveness> appView,
       InliningIRProvider inliningIRProvider,
       Set<Value> definiteReceiverAliases) {
     this.appView = appView;
@@ -41,8 +43,13 @@
 
   boolean willExceedInstructionBudget(
       IRCode code,
+      DexProgramClass eligibleClass,
       Map<InvokeMethod, DexEncodedMethod> directInlinees,
       List<DexEncodedMethod> indirectInlinees) {
+    if (appView.appInfo().alwaysClassInline.contains(eligibleClass.type)) {
+      return false;
+    }
+
     for (DexEncodedMethod inlinee : indirectInlinees) {
       // We do not have the corresponding invoke instruction for the inlinees that are not called
       // directly from `code` (these are called indirectly from one of the methods in
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerEligibilityInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerEligibilityInfo.java
index a80a9ec..bf06bc1 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerEligibilityInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerEligibilityInfo.java
@@ -4,10 +4,16 @@
 
 package com.android.tools.r8.ir.optimize.classinliner;
 
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.ir.code.Invoke;
 import com.android.tools.r8.utils.OptionalBool;
+import com.android.tools.r8.utils.Pair;
+import java.util.List;
 
 public class ClassInlinerEligibilityInfo {
 
+  final List<Pair<Invoke.Type, DexMethod>> callsReceiver;
+
   /**
    * Set to {@link OptionalBool#TRUE} if the method is guaranteed to return the receiver, {@link
    * OptionalBool#FALSE} if the method is guaranteed not to return the receiver, and {@link
@@ -15,7 +21,9 @@
    */
   final OptionalBool returnsReceiver;
 
-  public ClassInlinerEligibilityInfo(OptionalBool returnsReceiver) {
+  public ClassInlinerEligibilityInfo(
+      List<Pair<Invoke.Type, DexMethod>> callsReceiver, OptionalBool returnsReceiver) {
+    this.callsReceiver = callsReceiver;
     this.returnsReceiver = returnsReceiver;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
index 9afba98..c522ff3 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.ir.optimize.classinliner;
 
+import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
 
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
@@ -13,6 +14,7 @@
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.ResolutionResult;
 import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
@@ -85,7 +87,7 @@
 
   private Value eligibleInstance;
   private DexType eligibleClass;
-  private DexClass eligibleClassDefinition;
+  private DexProgramClass eligibleClassDefinition;
   private boolean isDesugaredLambda;
 
   private final Map<InvokeMethodWithReceiver, InliningInfo> methodCallsOnInstance =
@@ -120,6 +122,10 @@
     this.receivers = new ClassInlinerReceiverSet(root.outValue());
   }
 
+  DexProgramClass getEligibleClass() {
+    return eligibleClassDefinition;
+  }
+
   Map<InvokeMethod, DexEncodedMethod> getDirectInlinees() {
     return directInlinees;
   }
@@ -165,7 +171,7 @@
       isDesugaredLambda = eligibleClassDefinition != null;
     }
     if (eligibleClassDefinition == null) {
-      eligibleClassDefinition = appView.definitionFor(eligibleClass);
+      eligibleClassDefinition = asProgramClassOrNull(appView.definitionFor(eligibleClass));
     }
     if (eligibleClassDefinition != null) {
       return EligibilityStatus.ELIGIBLE;
@@ -328,8 +334,7 @@
                       && !invoke.inValues().isEmpty()
                       && root.outValue() == invoke.getReceiver();
               if (isCorrespondingConstructorCall) {
-                InliningInfo inliningInfo =
-                    isEligibleConstructorCall(invoke, singleTarget, defaultOracle);
+                InliningInfo inliningInfo = isEligibleConstructorCall(invoke, singleTarget);
                 if (inliningInfo != null) {
                   methodCallsOnInstance.put(invoke, inliningInfo);
                   continue;
@@ -670,7 +675,7 @@
   }
 
   private InliningInfo isEligibleConstructorCall(
-      InvokeDirect invoke, DexEncodedMethod singleTarget, Supplier<InliningOracle> defaultOracle) {
+      InvokeDirect invoke, DexEncodedMethod singleTarget) {
     assert appView.dexItemFactory().isConstructor(invoke.getInvokedMethod());
     assert isEligibleSingleTarget(singleTarget);
 
@@ -696,8 +701,9 @@
     }
 
     // Check that the `eligibleInstance` does not escape via the constructor.
-    ParameterUsage parameterUsage = singleTarget.getOptimizationInfo().getParameterUsages(0);
-    if (!isEligibleParameterUsage(parameterUsage, invoke, defaultOracle)) {
+    InstanceInitializerInfo instanceInitializerInfo =
+        singleTarget.getOptimizationInfo().getInstanceInitializerInfo();
+    if (instanceInitializerInfo.receiverMayEscapeOutsideConstructorChain()) {
       return null;
     }
 
@@ -709,7 +715,7 @@
 
     // Check that the entire constructor chain can be inlined into the current context.
     DexItemFactory dexItemFactory = appView.dexItemFactory();
-    DexMethod parent = singleTarget.getOptimizationInfo().getInstanceInitializerInfo().getParent();
+    DexMethod parent = instanceInitializerInfo.getParent();
     while (parent != dexItemFactory.objectMethods.constructor) {
       if (parent == null) {
         return null;
@@ -728,9 +734,7 @@
       parent = encodedParent.getOptimizationInfo().getInstanceInitializerInfo().getParent();
     }
 
-    return singleTarget.getOptimizationInfo().getClassInlinerEligibility() != null
-        ? new InliningInfo(singleTarget, eligibleClass)
-        : null;
+    return new InliningInfo(singleTarget, eligibleClass);
   }
 
   // An invoke is eligible for inlining in the following cases:
@@ -870,7 +874,7 @@
 
     MethodOptimizationInfo optimizationInfo = singleTarget.getOptimizationInfo();
     ClassInlinerEligibilityInfo eligibility = optimizationInfo.getClassInlinerEligibility();
-    if (eligibility == null) {
+    if (eligibility == null || !eligibility.callsReceiver.isEmpty()) {
       return null;
     }
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
index 614258b..1fb2e0c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
@@ -5,13 +5,18 @@
 
 import static com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.Query.DIRECTLY;
 import static com.android.tools.r8.ir.code.DominatorTree.Assumption.MAY_HAVE_UNREACHABLE_BLOCKS;
+import static com.android.tools.r8.ir.code.Opcodes.ADD;
+import static com.android.tools.r8.ir.code.Opcodes.AND;
 import static com.android.tools.r8.ir.code.Opcodes.ARGUMENT;
+import static com.android.tools.r8.ir.code.Opcodes.ARRAY_LENGTH;
 import static com.android.tools.r8.ir.code.Opcodes.ASSUME;
 import static com.android.tools.r8.ir.code.Opcodes.CHECK_CAST;
+import static com.android.tools.r8.ir.code.Opcodes.CMP;
 import static com.android.tools.r8.ir.code.Opcodes.CONST_CLASS;
 import static com.android.tools.r8.ir.code.Opcodes.CONST_NUMBER;
 import static com.android.tools.r8.ir.code.Opcodes.CONST_STRING;
 import static com.android.tools.r8.ir.code.Opcodes.DEX_ITEM_BASED_CONST_STRING;
+import static com.android.tools.r8.ir.code.Opcodes.DIV;
 import static com.android.tools.r8.ir.code.Opcodes.GOTO;
 import static com.android.tools.r8.ir.code.Opcodes.IF;
 import static com.android.tools.r8.ir.code.Opcodes.INSTANCE_GET;
@@ -19,12 +24,22 @@
 import static com.android.tools.r8.ir.code.Opcodes.INSTANCE_PUT;
 import static com.android.tools.r8.ir.code.Opcodes.INVOKE_DIRECT;
 import static com.android.tools.r8.ir.code.Opcodes.INVOKE_INTERFACE;
+import static com.android.tools.r8.ir.code.Opcodes.INVOKE_NEW_ARRAY;
 import static com.android.tools.r8.ir.code.Opcodes.INVOKE_STATIC;
 import static com.android.tools.r8.ir.code.Opcodes.INVOKE_VIRTUAL;
+import static com.android.tools.r8.ir.code.Opcodes.MUL;
+import static com.android.tools.r8.ir.code.Opcodes.NEW_ARRAY_EMPTY;
 import static com.android.tools.r8.ir.code.Opcodes.NEW_INSTANCE;
+import static com.android.tools.r8.ir.code.Opcodes.OR;
+import static com.android.tools.r8.ir.code.Opcodes.REM;
 import static com.android.tools.r8.ir.code.Opcodes.RETURN;
+import static com.android.tools.r8.ir.code.Opcodes.SHL;
+import static com.android.tools.r8.ir.code.Opcodes.SHR;
 import static com.android.tools.r8.ir.code.Opcodes.STATIC_GET;
+import static com.android.tools.r8.ir.code.Opcodes.SUB;
 import static com.android.tools.r8.ir.code.Opcodes.THROW;
+import static com.android.tools.r8.ir.code.Opcodes.USHR;
+import static com.android.tools.r8.ir.code.Opcodes.XOR;
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
@@ -52,8 +67,11 @@
 import com.android.tools.r8.ir.code.InstancePut;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionIterator;
+import com.android.tools.r8.ir.code.Invoke;
 import com.android.tools.r8.ir.code.InvokeDirect;
 import com.android.tools.r8.ir.code.InvokeMethod;
+import com.android.tools.r8.ir.code.InvokeNewArray;
+import com.android.tools.r8.ir.code.InvokeVirtual;
 import com.android.tools.r8.ir.code.NewInstance;
 import com.android.tools.r8.ir.code.Return;
 import com.android.tools.r8.ir.code.Value;
@@ -70,6 +88,7 @@
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.MethodSignatureEquivalence;
+import com.android.tools.r8.utils.Pair;
 import com.google.common.base.Equivalence.Wrapper;
 import com.google.common.collect.Sets;
 import com.google.common.collect.Streams;
@@ -145,6 +164,7 @@
       return;
     }
 
+    List<Pair<Invoke.Type, DexMethod>> callsReceiver = new ArrayList<>();
     boolean seenSuperInitCall = false;
     for (Instruction insn : receiver.aliasedUsers()) {
       if (insn.isAssume()) {
@@ -192,6 +212,27 @@
         return;
       }
 
+      if (insn.isInvokeVirtual()) {
+        InvokeVirtual invoke = insn.asInvokeVirtual();
+        if (invoke.getReceiver().getAliasedValue() != receiver) {
+          return; // Not allowed.
+        }
+        for (int i = 1; i < invoke.arguments().size(); i++) {
+          Value argument = invoke.arguments().get(i);
+          if (argument.getAliasedValue() == receiver) {
+            return; // Not allowed.
+          }
+        }
+        DexMethod invokedMethod = invoke.getInvokedMethod();
+        DexType returnType = invokedMethod.proto.returnType;
+        if (returnType.isClassType()
+            && appView.appInfo().isRelatedBySubtyping(returnType, method.method.holder)) {
+          return; // Not allowed, could introduce an alias of the receiver.
+        }
+        callsReceiver.add(new Pair<>(Invoke.Type.VIRTUAL, invokedMethod));
+        continue;
+      }
+
       if (insn.isReturn()) {
         continue;
       }
@@ -208,6 +249,7 @@
     feedback.setClassInlinerEligibility(
         method,
         new ClassInlinerEligibilityInfo(
+            callsReceiver,
             new ClassInlinerReceiverAnalysis(appView, method, code).computeReturnsReceiver()));
   }
 
@@ -357,12 +399,26 @@
             builder.setInstanceFieldInitializationMayDependOnEnvironment();
             break;
 
+          case ADD:
+          case AND:
+          case ARRAY_LENGTH:
           case CHECK_CAST:
+          case CMP:
           case CONST_CLASS:
           case CONST_STRING:
           case DEX_ITEM_BASED_CONST_STRING:
+          case DIV:
           case INSTANCE_OF:
+          case MUL:
+          case NEW_ARRAY_EMPTY:
+          case OR:
+          case REM:
+          case SHL:
+          case SHR:
+          case SUB:
           case THROW:
+          case USHR:
+          case XOR:
             // These instructions types may raise an exception, which is a side effect. None of the
             // instructions can trigger class initialization side effects, hence it is not necessary
             // to mark all fields as potentially being read. Also, none of the instruction types
@@ -463,15 +519,34 @@
             }
             break;
 
+          case INVOKE_NEW_ARRAY:
+            {
+              InvokeNewArray invoke = instruction.asInvokeNewArray();
+              if (invoke.instructionMayHaveSideEffects(appView, clazz.type)) {
+                builder.setMayHaveOtherSideEffectsThanInstanceFieldAssignments();
+              }
+              for (Value argument : invoke.arguments()) {
+                if (argument.getAliasedValue() == receiver) {
+                  builder.setReceiverMayEscapeOutsideConstructorChain();
+                  break;
+                }
+              }
+            }
+            break;
+
           case INVOKE_INTERFACE:
           case INVOKE_STATIC:
           case INVOKE_VIRTUAL:
-            InvokeMethod invoke = instruction.asInvokeMethod();
-            builder.markAllFieldsAsRead().setMayHaveOtherSideEffectsThanInstanceFieldAssignments();
-            for (Value inValue : invoke.inValues()) {
-              if (inValue.getAliasedValue() == receiver) {
-                builder.setReceiverMayEscapeOutsideConstructorChain();
-                break;
+            {
+              InvokeMethod invoke = instruction.asInvokeMethod();
+              builder
+                  .markAllFieldsAsRead()
+                  .setMayHaveOtherSideEffectsThanInstanceFieldAssignments();
+              for (Value argument : invoke.arguments()) {
+                if (argument.getAliasedValue() == receiver) {
+                  builder.setReceiverMayEscapeOutsideConstructorChain();
+                  break;
+                }
               }
             }
             break;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java
index d599a38..def162e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java
@@ -14,24 +14,16 @@
 import com.android.tools.r8.ir.optimize.info.ParameterUsagesInfo.ParameterUsage;
 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.BooleanUtils;
 import java.util.BitSet;
 import java.util.Set;
 import java.util.function.Function;
 
 public class UpdatableMethodOptimizationInfo implements MethodOptimizationInfo {
 
-  private boolean cannotBeKept = false;
-  private boolean classInitializerMayBePostponed = false;
-  private boolean hasBeenInlinedIntoSingleCallSite = false;
   private Set<DexType> initializedClassesOnNormalExit =
       DefaultMethodOptimizationInfo.UNKNOWN_INITIALIZED_CLASSES_ON_NORMAL_EXIT;
   private int returnedArgument = DefaultMethodOptimizationInfo.UNKNOWN_RETURNED_ARGUMENT;
-  private boolean mayHaveSideEffects = DefaultMethodOptimizationInfo.UNKNOWN_MAY_HAVE_SIDE_EFFECTS;
-  private boolean returnValueOnlyDependsOnArguments =
-      DefaultMethodOptimizationInfo.UNKNOWN_RETURN_VALUE_ONLY_DEPENDS_ON_ARGUMENTS;
-  private boolean neverReturnsNull = DefaultMethodOptimizationInfo.UNKNOWN_NEVER_RETURNS_NULL;
-  private boolean neverReturnsNormally =
-      DefaultMethodOptimizationInfo.UNKNOWN_NEVER_RETURNS_NORMALLY;
   private AbstractValue abstractReturnValue =
       DefaultMethodOptimizationInfo.UNKNOWN_ABSTRACT_RETURN_VALUE;
   private TypeLatticeElement returnsObjectWithUpperBoundType =
@@ -39,20 +31,12 @@
   private ClassTypeLatticeElement returnsObjectWithLowerBoundType =
       DefaultMethodOptimizationInfo.UNKNOWN_CLASS_TYPE;
   private InlinePreference inlining = InlinePreference.Default;
-  private boolean useIdentifierNameString =
-      DefaultMethodOptimizationInfo.DOES_NOT_USE_IDENTIFIER_NAME_STRING;
-  private boolean checksNullReceiverBeforeAnySideEffect =
-      DefaultMethodOptimizationInfo.UNKNOWN_CHECKS_NULL_RECEIVER_BEFORE_ANY_SIDE_EFFECT;
-  private boolean triggersClassInitBeforeAnySideEffect =
-      DefaultMethodOptimizationInfo.UNKNOWN_TRIGGERS_CLASS_INIT_BEFORE_ANY_SIDE_EFFECT;
   // Stores information about instance methods and constructors for
   // class inliner, null value indicates that the method is not eligible.
   private ClassInlinerEligibilityInfo classInlinerEligibility =
       DefaultMethodOptimizationInfo.UNKNOWN_CLASS_INLINER_ELIGIBILITY;
   private InstanceInitializerInfo instanceInitializerInfo =
       DefaultInstanceInitializerInfo.getInstance();
-  private boolean initializerEnablingJavaAssertions =
-      DefaultMethodOptimizationInfo.UNKNOWN_INITIALIZER_ENABLING_JAVA_ASSERTIONS;
   private ParameterUsagesInfo parametersUsages =
       DefaultMethodOptimizationInfo.UNKNOWN_PARAMETER_USAGE_INFO;
   // Stores information about nullability hint per parameter. If set, that means, the method
@@ -73,8 +57,69 @@
   // Note that this bit set takes into account the receiver for instance methods.
   private BitSet nonNullParamOnNormalExits =
       DefaultMethodOptimizationInfo.NO_NULL_PARAMETER_ON_NORMAL_EXITS_FACTS;
-  private boolean reachabilitySensitive = false;
-  private boolean returnValueHasBeenPropagated = false;
+
+  // To reduce the memory footprint of UpdatableMethodOptimizationInfo, all the boolean fields are
+  // merged into a flag int field. The various static final FLAG fields indicate which bit is
+  // used by each boolean. DEFAULT_FLAGS encodes the default value for efficient instantiation and
+  // is computed during class initialization from the default method optimization info. The
+  // methods setFlag, clearFlag and isFlagSet are used to access the booleans.
+  private static final int CANNOT_BE_KEPT_FLAG = 0x1;
+  private static final int CLASS_INITIALIZER_MAY_BE_POSTPONED_FLAG = 0x2;
+  private static final int HAS_BEEN_INLINED_INTO_SINGLE_CALL_SITE_FLAG = 0x4;
+  private static final int MAY_HAVE_SIDE_EFFECT_FLAG = 0x8;
+  private static final int RETURN_VALUE_ONLY_DEPENDS_ON_ARGUMENTS_FLAG = 0x10;
+  private static final int NEVER_RETURNS_NULL_FLAG = 0x20;
+  private static final int NEVER_RETURNS_NORMALLY_FLAG = 0x40;
+  private static final int USE_IDENTIFIER_NAME_STRING_FLAG = 0x80;
+  private static final int CHECKS_NULL_RECEIVER_BEFORE_ANY_SIDE_EFFECT_FLAG = 0x100;
+  private static final int TRIGGERS_CLASS_INIT_BEFORE_ANY_SIDE_EFFECT_FLAG = 0x200;
+  private static final int INITIALIZER_ENABLING_JAVA_ASSERTIONS_FLAG = 0x400;
+  private static final int REACHABILITY_SENSITIVE_FLAG = 0x800;
+  private static final int RETURN_VALUE_HAS_BEEN_PROPAGATED_FLAG = 0x1000;
+
+  private static final int DEFAULT_FLAGS;
+
+  static {
+    int defaultFlags = 0;
+    MethodOptimizationInfo defaultOptInfo = DefaultMethodOptimizationInfo.DEFAULT_INSTANCE;
+    defaultFlags |= BooleanUtils.intValue(defaultOptInfo.cannotBeKept()) * CANNOT_BE_KEPT_FLAG;
+    defaultFlags |=
+        BooleanUtils.intValue(defaultOptInfo.classInitializerMayBePostponed())
+            * CLASS_INITIALIZER_MAY_BE_POSTPONED_FLAG;
+    defaultFlags |=
+        BooleanUtils.intValue(defaultOptInfo.hasBeenInlinedIntoSingleCallSite())
+            * HAS_BEEN_INLINED_INTO_SINGLE_CALL_SITE_FLAG;
+    defaultFlags |=
+        BooleanUtils.intValue(defaultOptInfo.mayHaveSideEffects()) * MAY_HAVE_SIDE_EFFECT_FLAG;
+    defaultFlags |=
+        BooleanUtils.intValue(defaultOptInfo.returnValueOnlyDependsOnArguments())
+            * RETURN_VALUE_ONLY_DEPENDS_ON_ARGUMENTS_FLAG;
+    defaultFlags |=
+        BooleanUtils.intValue(defaultOptInfo.neverReturnsNull()) * NEVER_RETURNS_NULL_FLAG;
+    defaultFlags |=
+        BooleanUtils.intValue(defaultOptInfo.neverReturnsNormally()) * NEVER_RETURNS_NORMALLY_FLAG;
+    defaultFlags |=
+        BooleanUtils.intValue(defaultOptInfo.useIdentifierNameString())
+            * USE_IDENTIFIER_NAME_STRING_FLAG;
+    defaultFlags |=
+        BooleanUtils.intValue(defaultOptInfo.checksNullReceiverBeforeAnySideEffect())
+            * CHECKS_NULL_RECEIVER_BEFORE_ANY_SIDE_EFFECT_FLAG;
+    defaultFlags |=
+        BooleanUtils.intValue(defaultOptInfo.triggersClassInitBeforeAnySideEffect())
+            * TRIGGERS_CLASS_INIT_BEFORE_ANY_SIDE_EFFECT_FLAG;
+    defaultFlags |=
+        BooleanUtils.intValue(defaultOptInfo.isInitializerEnablingJavaAssertions())
+            * INITIALIZER_ENABLING_JAVA_ASSERTIONS_FLAG;
+    defaultFlags |=
+        BooleanUtils.intValue(defaultOptInfo.isReachabilitySensitive())
+            * REACHABILITY_SENSITIVE_FLAG;
+    defaultFlags |=
+        BooleanUtils.intValue(defaultOptInfo.returnValueHasBeenPropagated())
+            * RETURN_VALUE_HAS_BEEN_PROPAGATED_FLAG;
+    DEFAULT_FLAGS = defaultFlags;
+  }
+
+  private int flags = DEFAULT_FLAGS;
 
   UpdatableMethodOptimizationInfo() {
     // Intentionally left empty, just use the default values.
@@ -83,30 +128,18 @@
   // Copy constructor used to create a mutable copy. Do not forget to copy from template when a new
   // field is added.
   private UpdatableMethodOptimizationInfo(UpdatableMethodOptimizationInfo template) {
-    cannotBeKept = template.cannotBeKept;
-    classInitializerMayBePostponed = template.classInitializerMayBePostponed;
-    hasBeenInlinedIntoSingleCallSite = template.hasBeenInlinedIntoSingleCallSite;
+    flags = template.flags;
     initializedClassesOnNormalExit = template.initializedClassesOnNormalExit;
     returnedArgument = template.returnedArgument;
-    mayHaveSideEffects = template.mayHaveSideEffects;
-    returnValueOnlyDependsOnArguments = template.returnValueOnlyDependsOnArguments;
-    neverReturnsNull = template.neverReturnsNull;
-    neverReturnsNormally = template.neverReturnsNormally;
     abstractReturnValue = template.abstractReturnValue;
     returnsObjectWithUpperBoundType = template.returnsObjectWithUpperBoundType;
     returnsObjectWithLowerBoundType = template.returnsObjectWithLowerBoundType;
     inlining = template.inlining;
-    useIdentifierNameString = template.useIdentifierNameString;
-    checksNullReceiverBeforeAnySideEffect = template.checksNullReceiverBeforeAnySideEffect;
-    triggersClassInitBeforeAnySideEffect = template.triggersClassInitBeforeAnySideEffect;
     classInlinerEligibility = template.classInlinerEligibility;
     instanceInitializerInfo = template.instanceInitializerInfo;
-    initializerEnablingJavaAssertions = template.initializerEnablingJavaAssertions;
     parametersUsages = template.parametersUsages;
     nonNullParamOrThrow = template.nonNullParamOrThrow;
     nonNullParamOnNormalExits = template.nonNullParamOnNormalExits;
-    reachabilitySensitive = template.reachabilitySensitive;
-    returnValueHasBeenPropagated = template.returnValueHasBeenPropagated;
   }
 
   public void fixupClassTypeReferences(
@@ -121,6 +154,26 @@
     }
   }
 
+  private void setFlag(int flag, boolean value) {
+    if (value) {
+      setFlag(flag);
+    } else {
+      clearFlag(flag);
+    }
+  }
+
+  private void setFlag(int flag) {
+    flags |= flag;
+  }
+
+  private void clearFlag(int flag) {
+    flags &= ~flag;
+  }
+
+  private boolean isFlagSet(int flag) {
+    return (flags & flag) != 0;
+  }
+
   @Override
   public boolean isDefaultMethodOptimizationInfo() {
     return false;
@@ -138,21 +191,21 @@
 
   @Override
   public boolean cannotBeKept() {
-    return cannotBeKept;
+    return isFlagSet(CANNOT_BE_KEPT_FLAG);
   }
 
   // TODO(b/140214568): Should be package-private.
   public void markCannotBeKept() {
-    cannotBeKept = true;
+    setFlag(CANNOT_BE_KEPT_FLAG);
   }
 
   @Override
   public boolean classInitializerMayBePostponed() {
-    return classInitializerMayBePostponed;
+    return isFlagSet(CLASS_INITIALIZER_MAY_BE_POSTPONED_FLAG);
   }
 
   void markClassInitializerMayBePostponed() {
-    classInitializerMayBePostponed = true;
+    setFlag(CLASS_INITIALIZER_MAY_BE_POSTPONED_FLAG);
   }
 
   @Override
@@ -192,16 +245,16 @@
 
   @Override
   public boolean hasBeenInlinedIntoSingleCallSite() {
-    return hasBeenInlinedIntoSingleCallSite;
+    return isFlagSet(HAS_BEEN_INLINED_INTO_SINGLE_CALL_SITE_FLAG);
   }
 
   void markInlinedIntoSingleCallSite() {
-    hasBeenInlinedIntoSingleCallSite = true;
+    setFlag(HAS_BEEN_INLINED_INTO_SINGLE_CALL_SITE_FLAG);
   }
 
   @Override
   public boolean isReachabilitySensitive() {
-    return reachabilitySensitive;
+    return isFlagSet(REACHABILITY_SENSITIVE_FLAG);
   }
 
   @Override
@@ -217,12 +270,12 @@
 
   @Override
   public boolean neverReturnsNull() {
-    return neverReturnsNull;
+    return isFlagSet(NEVER_RETURNS_NULL_FLAG);
   }
 
   @Override
   public boolean neverReturnsNormally() {
-    return neverReturnsNormally;
+    return isFlagSet(NEVER_RETURNS_NORMALLY_FLAG);
   }
 
   @Override
@@ -237,12 +290,12 @@
 
   @Override
   public boolean isInitializerEnablingJavaAssertions() {
-    return initializerEnablingJavaAssertions;
+    return isFlagSet(INITIALIZER_ENABLING_JAVA_ASSERTIONS_FLAG);
   }
 
   @Override
   public boolean useIdentifierNameString() {
-    return useIdentifierNameString;
+    return isFlagSet(USE_IDENTIFIER_NAME_STRING_FLAG);
   }
 
   @Override
@@ -257,22 +310,22 @@
 
   @Override
   public boolean checksNullReceiverBeforeAnySideEffect() {
-    return checksNullReceiverBeforeAnySideEffect;
+    return isFlagSet(CHECKS_NULL_RECEIVER_BEFORE_ANY_SIDE_EFFECT_FLAG);
   }
 
   @Override
   public boolean triggersClassInitBeforeAnySideEffect() {
-    return triggersClassInitBeforeAnySideEffect;
+    return isFlagSet(TRIGGERS_CLASS_INIT_BEFORE_ANY_SIDE_EFFECT_FLAG);
   }
 
   @Override
   public boolean mayHaveSideEffects() {
-    return mayHaveSideEffects;
+    return isFlagSet(MAY_HAVE_SIDE_EFFECT_FLAG);
   }
 
   @Override
   public boolean returnValueOnlyDependsOnArguments() {
-    return returnValueOnlyDependsOnArguments;
+    return isFlagSet(RETURN_VALUE_ONLY_DEPENDS_ON_ARGUMENTS_FLAG);
   }
 
   void setParameterUsages(ParameterUsagesInfo parametersUsages) {
@@ -288,7 +341,7 @@
   }
 
   public void setReachabilitySensitive(boolean reachabilitySensitive) {
-    this.reachabilitySensitive = reachabilitySensitive;
+    setFlag(REACHABILITY_SENSITIVE_FLAG, reachabilitySensitive);
   }
 
   void setClassInlinerEligibility(ClassInlinerEligibilityInfo eligibility) {
@@ -300,7 +353,7 @@
   }
 
   void setInitializerEnablingJavaAssertions() {
-    this.initializerEnablingJavaAssertions = true;
+    setFlag(INITIALIZER_ENABLING_JAVA_ASSERTIONS_FLAG);
   }
 
   void markInitializesClassesOnNormalExit(Set<DexType> initializedClassesOnNormalExit) {
@@ -314,19 +367,19 @@
   }
 
   void markMayNotHaveSideEffects() {
-    mayHaveSideEffects = false;
+    clearFlag(MAY_HAVE_SIDE_EFFECT_FLAG);
   }
 
   void markReturnValueOnlyDependsOnArguments() {
-    returnValueOnlyDependsOnArguments = true;
+    setFlag(RETURN_VALUE_ONLY_DEPENDS_ON_ARGUMENTS_FLAG);
   }
 
   void markNeverReturnsNull() {
-    neverReturnsNull = true;
+    setFlag(NEVER_RETURNS_NULL_FLAG);
   }
 
   void markNeverReturnsNormally() {
-    neverReturnsNormally = true;
+    setFlag(NEVER_RETURNS_NORMALLY_FLAG);
   }
 
   void markReturnsAbstractValue(AbstractValue value) {
@@ -385,25 +438,25 @@
 
   // TODO(b/140214568): Should be package-private.
   public void markUseIdentifierNameString() {
-    useIdentifierNameString = true;
+    setFlag(USE_IDENTIFIER_NAME_STRING_FLAG);
   }
 
   void markCheckNullReceiverBeforeAnySideEffect(boolean mark) {
-    checksNullReceiverBeforeAnySideEffect = mark;
+    setFlag(CHECKS_NULL_RECEIVER_BEFORE_ANY_SIDE_EFFECT_FLAG, mark);
   }
 
   void markTriggerClassInitBeforeAnySideEffect(boolean mark) {
-    triggersClassInitBeforeAnySideEffect = mark;
+    setFlag(TRIGGERS_CLASS_INIT_BEFORE_ANY_SIDE_EFFECT_FLAG, mark);
   }
 
   // TODO(b/140214568): Should be package-private.
   public void markAsPropagated() {
-    returnValueHasBeenPropagated = true;
+    setFlag(RETURN_VALUE_HAS_BEEN_PROPAGATED_FLAG);
   }
 
   @Override
   public boolean returnValueHasBeenPropagated() {
-    return returnValueHasBeenPropagated;
+    return isFlagSet(RETURN_VALUE_HAS_BEEN_PROPAGATED_FLAG);
   }
 
   @Override
@@ -415,9 +468,9 @@
   public void adjustOptimizationInfoAfterRemovingThisParameter() {
     // cannotBeKept: doesn't depend on `this`
     // classInitializerMayBePostponed: `this` could trigger <clinit> of the previous holder.
-    classInitializerMayBePostponed = false;
+    clearFlag(CLASS_INITIALIZER_MAY_BE_POSTPONED_FLAG);
     // hasBeenInlinedIntoSingleCallSite: then it should not be staticized.
-    hasBeenInlinedIntoSingleCallSite = false;
+    clearFlag(HAS_BEEN_INLINED_INTO_SINGLE_CALL_SITE_FLAG);
     // initializedClassesOnNormalExit: `this` could trigger <clinit> of the previous holder.
     initializedClassesOnNormalExit =
         DefaultMethodOptimizationInfo.UNKNOWN_INITIALIZED_CLASSES_ON_NORMAL_EXIT;
@@ -441,18 +494,19 @@
     inlining = InlinePreference.Default;
     // useIdentifierNameString: code is not changed.
     // checksNullReceiverBeforeAnySideEffect: no more receiver.
-    checksNullReceiverBeforeAnySideEffect =
-        DefaultMethodOptimizationInfo.UNKNOWN_CHECKS_NULL_RECEIVER_BEFORE_ANY_SIDE_EFFECT;
+    markCheckNullReceiverBeforeAnySideEffect(
+        DefaultMethodOptimizationInfo.UNKNOWN_CHECKS_NULL_RECEIVER_BEFORE_ANY_SIDE_EFFECT);
     // triggersClassInitBeforeAnySideEffect: code is not changed.
-    triggersClassInitBeforeAnySideEffect =
-        DefaultMethodOptimizationInfo.UNKNOWN_TRIGGERS_CLASS_INIT_BEFORE_ANY_SIDE_EFFECT;
+    markTriggerClassInitBeforeAnySideEffect(
+        DefaultMethodOptimizationInfo.UNKNOWN_TRIGGERS_CLASS_INIT_BEFORE_ANY_SIDE_EFFECT);
     // classInlinerEligibility: chances are the method is not an instance method anymore.
     classInlinerEligibility = DefaultMethodOptimizationInfo.UNKNOWN_CLASS_INLINER_ELIGIBILITY;
     // initializerInfo: the computed initializer info may become invalid.
     instanceInitializerInfo = null;
     // initializerEnablingJavaAssertions: `this` could trigger <clinit> of the previous holder.
-    initializerEnablingJavaAssertions =
-        DefaultMethodOptimizationInfo.UNKNOWN_INITIALIZER_ENABLING_JAVA_ASSERTIONS;
+    setFlag(
+        INITIALIZER_ENABLING_JAVA_ASSERTIONS_FLAG,
+        DefaultMethodOptimizationInfo.UNKNOWN_INITIALIZER_ENABLING_JAVA_ASSERTIONS);
     parametersUsages =
         parametersUsages == DefaultMethodOptimizationInfo.UNKNOWN_PARAMETER_USAGE_INFO
             ? DefaultMethodOptimizationInfo.UNKNOWN_PARAMETER_USAGE_INFO
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
index 9981290..a11f309 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
@@ -434,9 +434,7 @@
             .map(method -> appView.graphLense().mapDexEncodedMethod(method, appView))
             .collect(Collectors.toSet());
     converter.processMethodsConcurrently(methods, executorService);
-    methods.forEach(method -> {
-      assert method.isProcessed();
-    });
+    assert methods.stream().allMatch(DexEncodedMethod::isProcessed);
   }
 
   private void analyzeClass(DexProgramClass clazz) {
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/SyntheticSourceCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/SyntheticSourceCode.java
index 1784753..98e83c4 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/SyntheticSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/SyntheticSourceCode.java
@@ -9,11 +9,10 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.analysis.type.Nullability;
-import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.code.CatchHandlers;
 import com.android.tools.r8.ir.code.Position;
 import com.android.tools.r8.ir.code.ValueType;
+import com.android.tools.r8.ir.conversion.DexSourceCode;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.conversion.SourceCode;
 import java.util.ArrayList;
@@ -25,6 +24,7 @@
   protected final static Predicate<IRBuilder> doesNotEndBlock = x -> false;
   protected final static Predicate<IRBuilder> endsBlock = x -> true;
 
+  // TODO(b/146124603): Remove these fields as optimzations (e.g., merging) could invalidate them.
   protected final DexType receiver;
   protected final DexMethod method;
   protected final DexProto proto;
@@ -156,19 +156,11 @@
 
   @Override
   public final void buildPrelude(IRBuilder builder) {
-    if (receiver != null) {
-      builder.addThisArgument(
-          receiverRegister,
-          TypeLatticeElement.fromDexType(
-              receiver, Nullability.definitelyNotNull(), builder.appView));
-    }
-    // Fill in the Argument instructions in the argument block.
-    DexType[] parameters = proto.parameters.values;
-    for (int i = 0; i < parameters.length; i++) {
-      TypeLatticeElement typeLattice =
-          TypeLatticeElement.fromDexType(parameters[i], Nullability.maybeNull(), builder.appView);
-      builder.addNonThisArgument(paramRegisters[i], typeLattice);
-    }
+    DexSourceCode.buildArgumentsWithUnusedArgumentStubs(
+        builder,
+        0,
+        builder.getMethod(),
+        DexSourceCode::doNothingWriteConsumer);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassFacade.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassFacade.java
index a24055e..f8c1c12 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassFacade.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassFacade.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.kotlin;
 
-import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.naming.NamingLens;
@@ -35,12 +34,15 @@
 
   @Override
   void rewrite(AppView<AppInfoWithLiveness> appView, NamingLens lens) {
-    throw new Unreachable(toString());
+    // TODO(b/70169921): no idea yet!
+    assert lens.lookupType(clazz.type, appView.dexItemFactory()) == clazz.type
+        : toString();
   }
 
   @Override
   KotlinClassHeader createHeader() {
-    throw new Unreachable(toString());
+    // TODO(b/70169921): may need to update if `rewrite` is implemented.
+    return metadata.getHeader();
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
index c05b48f..a195f97 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
@@ -83,10 +83,13 @@
     if (kMetadata instanceof KotlinClassMetadata.Class) {
       return KotlinClass.fromKotlinClassMetadata(kMetadata, clazz);
     } else if (kMetadata instanceof KotlinClassMetadata.FileFacade) {
+      // e.g., B.kt becomes class `BKt`
       return KotlinFile.fromKotlinClassMetadata(kMetadata, clazz);
     } else if (kMetadata instanceof KotlinClassMetadata.MultiFileClassFacade) {
+      // multi-file class with the same @JvmName.
       return KotlinClassFacade.fromKotlinClassMetadata(kMetadata, clazz);
     } else if (kMetadata instanceof KotlinClassMetadata.MultiFileClassPart) {
+      // A single file, which is part of multi-file class.
       return KotlinClassPart.fromKotlinClassMetadata(kMetadata, clazz);
     } else if (kMetadata instanceof KotlinClassMetadata.SyntheticClass) {
       return KotlinSyntheticClass.fromKotlinClassMetadata(kMetadata, kotlin, clazz);
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
index 054c5e2..5658b0d 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
@@ -66,9 +66,6 @@
         clazz -> {
           KotlinInfo<?> kotlinInfo = clazz.getKotlinInfo();
           if (kotlinInfo != null) {
-            assert kotlinInfo.isClass()
-                || kotlinInfo.isSyntheticClass()
-                || kotlinInfo.isFile(); // e.g., B.kt becomes class `BKt`
             // If @Metadata is still associated, this class should not be renamed
             // (by {@link ClassNameMinifier} of course).
             assert lens.lookupType(clazz.type, appView.dexItemFactory()) == clazz.type
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizer.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizer.java
index 0b061f3..4400273 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizer.java
@@ -19,18 +19,16 @@
       return null;
     }
     // For library or classpath class, synthesize @Metadata always.
-    if (clazz.isNotProgramClass()) {
-      KmType kmType = new KmType(clazz.accessFlags.getAsCfAccessFlags());
-      assert type == lens.lookupType(type, appView.dexItemFactory());
-      kmType.visitClass(DescriptorUtils.descriptorToInternalName(type.toDescriptorString()));
-      return kmType;
-    }
-    // From now on, it is a program class. First, make sure it is live.
-    if (!appView.appInfo().isLiveProgramType(type)) {
+    // For a program class, make sure it is live.
+    if (!appView.appInfo().isNonProgramTypeOrLiveProgramType(type)) {
       return null;
     }
-    KmType kmType = new KmType(clazz.accessFlags.getAsCfAccessFlags());
     DexType renamedType = lens.lookupType(type, appView.dexItemFactory());
+    // For library or classpath class, we should not have renamed it.
+    assert clazz.isProgramClass() || renamedType == type
+        : type.toSourceString() + " -> " + renamedType.toSourceString();
+    // TODO(b/70169921): Consult kotlinx.metadata.Flag for kotlin-specific flags (e.g., sealed).
+    KmType kmType = new KmType(clazz.accessFlags.getAsCfAccessFlags());
     kmType.visitClass(DescriptorUtils.descriptorToInternalName(renamedType.toDescriptorString()));
     return kmType;
   }
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index 347ae0f..0aea415 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -142,6 +142,8 @@
   public final Set<DexMethod> keepConstantArguments;
   /** All methods that may not have any unused arguments removed. */
   public final Set<DexMethod> keepUnusedArguments;
+  /** All types that should be inlined if possible due to a configuration directive. */
+  public final Set<DexType> alwaysClassInline;
   /** All types that *must* never be inlined due to a configuration directive (testing only). */
   public final Set<DexType> neverClassInline;
   /** All types that *must* never be merged due to a configuration directive (testing only). */
@@ -210,6 +212,7 @@
       Set<DexMethod> whyAreYouNotInlining,
       Set<DexMethod> keepConstantArguments,
       Set<DexMethod> keepUnusedArguments,
+      Set<DexType> alwaysClassInline,
       Set<DexType> neverClassInline,
       Set<DexType> neverMerge,
       Set<DexReference> neverPropagateValue,
@@ -248,6 +251,7 @@
     this.whyAreYouNotInlining = whyAreYouNotInlining;
     this.keepConstantArguments = keepConstantArguments;
     this.keepUnusedArguments = keepUnusedArguments;
+    this.alwaysClassInline = alwaysClassInline;
     this.neverClassInline = neverClassInline;
     this.neverMerge = neverMerge;
     this.neverPropagateValue = neverPropagateValue;
@@ -289,6 +293,7 @@
       Set<DexMethod> whyAreYouNotInlining,
       Set<DexMethod> keepConstantArguments,
       Set<DexMethod> keepUnusedArguments,
+      Set<DexType> alwaysClassInline,
       Set<DexType> neverClassInline,
       Set<DexType> neverMerge,
       Set<DexReference> neverPropagateValue,
@@ -327,6 +332,7 @@
     this.whyAreYouNotInlining = whyAreYouNotInlining;
     this.keepConstantArguments = keepConstantArguments;
     this.keepUnusedArguments = keepUnusedArguments;
+    this.alwaysClassInline = alwaysClassInline;
     this.neverClassInline = neverClassInline;
     this.neverMerge = neverMerge;
     this.neverPropagateValue = neverPropagateValue;
@@ -369,6 +375,7 @@
         previous.whyAreYouNotInlining,
         previous.keepConstantArguments,
         previous.keepUnusedArguments,
+        previous.alwaysClassInline,
         previous.neverClassInline,
         previous.neverMerge,
         previous.neverPropagateValue,
@@ -418,6 +425,7 @@
         previous.whyAreYouNotInlining,
         previous.keepConstantArguments,
         previous.keepUnusedArguments,
+        previous.alwaysClassInline,
         previous.neverClassInline,
         previous.neverMerge,
         previous.neverPropagateValue,
@@ -499,6 +507,7 @@
             .map(this::definitionFor)
             .filter(Objects::nonNull)
             .collect(Collectors.toList()));
+    this.alwaysClassInline = rewriteItems(previous.alwaysClassInline, lense::lookupType);
     this.neverClassInline = rewriteItems(previous.neverClassInline, lense::lookupType);
     this.neverMerge = rewriteItems(previous.neverMerge, lense::lookupType);
     this.neverPropagateValue = lense.rewriteReferencesConservatively(previous.neverPropagateValue);
@@ -550,6 +559,7 @@
     this.whyAreYouNotInlining = previous.whyAreYouNotInlining;
     this.keepConstantArguments = previous.keepConstantArguments;
     this.keepUnusedArguments = previous.keepUnusedArguments;
+    this.alwaysClassInline = previous.alwaysClassInline;
     this.neverClassInline = previous.neverClassInline;
     this.neverMerge = previous.neverMerge;
     this.neverPropagateValue = previous.neverPropagateValue;
diff --git a/src/main/java/com/android/tools/r8/shaking/ClassInlineRule.java b/src/main/java/com/android/tools/r8/shaking/ClassInlineRule.java
index e7dc76c..4e69cd2 100644
--- a/src/main/java/com/android/tools/r8/shaking/ClassInlineRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ClassInlineRule.java
@@ -11,6 +11,7 @@
 public class ClassInlineRule extends ProguardConfigurationRule {
 
   public enum Type {
+    ALWAYS,
     NEVER
   }
 
@@ -95,8 +96,20 @@
   }
 
   @Override
+  public boolean isClassInlineRule() {
+    return true;
+  }
+
+  @Override
+  public ClassInlineRule asClassInlineRule() {
+    return this;
+  }
+
+  @Override
   String typeString() {
     switch (type) {
+      case ALWAYS:
+        return "alwaysclassinline";
       case NEVER:
         return "neverclassinline";
     }
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 3548caf..8329fcf 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -2168,11 +2168,7 @@
 
   // Package protected due to entry point from worklist.
   void markSuperMethodAsReachable(DexMethod method, DexEncodedMethod from) {
-    // We have to mark the immediate target of the descriptor as targeted, as otherwise
-    // the invoke super will fail in the resolution step with a NSM error.
-    // See <a
-    // href="https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.invokespecial">
-    // the JVM spec for invoke-special.
+    // If the method does not resolve, mark it broken to avoid hiding errors in other optimizations.
     SingleResolutionResult resolution =
         appInfo.resolveMethod(method.holder, method).asSingleResolution();
     if (resolution == null) {
@@ -2180,31 +2176,26 @@
       reportMissingMethod(method);
       return;
     }
-
-    DexEncodedMethod resolutionTarget = resolution.getResolvedMethod();
-    if (resolutionTarget.accessFlags.isPrivate() || resolutionTarget.accessFlags.isStatic()) {
-      brokenSuperInvokes.add(resolutionTarget.method);
-    }
-    DexProgramClass resolutionTargetClass = resolution.getResolvedHolder().asProgramClass();
-    if (resolutionTargetClass != null) {
+    // If the resolution is in the program, mark it targeted.
+    if (resolution.getResolvedHolder().isProgramClass()) {
       markMethodAsTargeted(
-          resolutionTargetClass, resolutionTarget, KeepReason.targetedBySuperFrom(from));
+          resolution.getResolvedHolder().asProgramClass(),
+          resolution.getResolvedMethod(),
+          KeepReason.targetedBySuperFrom(from));
     }
-
-    // Now we need to compute the actual target in the context.
-    DexEncodedMethod target = resolution.lookupInvokeSuperTarget(from.method.holder, appInfo);
+    // If invoke target is invalid (inaccessible or not an instance-method) record it and stop.
+    // TODO(b/146016987): We should be passing the full program context and not looking it up again.
+    DexProgramClass fromHolder = appInfo.definitionFor(from.method.holder).asProgramClass();
+    DexEncodedMethod target = resolution.lookupInvokeSuperTarget(fromHolder, appInfo);
     if (target == null) {
-      // The actual implementation in the super class is missing.
-      reportMissingMethod(method);
+      brokenSuperInvokes.add(resolution.getResolvedMethod().method);
       return;
     }
+
     DexProgramClass clazz = getProgramClassOrNull(target.method.holder);
     if (clazz == null) {
       return;
     }
-    if (target.accessFlags.isPrivate()) {
-      brokenSuperInvokes.add(resolutionTarget.method);
-    }
     if (Log.ENABLED) {
       Log.verbose(getClass(), "Adding super constraint from `%s` to `%s`", from.method,
           target.method);
@@ -2317,6 +2308,7 @@
             rootSet.whyAreYouNotInlining,
             rootSet.keepConstantArguments,
             rootSet.keepUnusedArguments,
+            rootSet.alwaysClassInline,
             rootSet.neverClassInline,
             rootSet.neverMerge,
             rootSet.neverPropagateValue,
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
index cee2d66..4778c35 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -432,6 +432,11 @@
           configurationBuilder.addRule(rule);
           return true;
         }
+        if (acceptString("alwaysclassinline")) {
+          ClassInlineRule rule = parseClassInlineRule(ClassInlineRule.Type.ALWAYS, optionStart);
+          configurationBuilder.addRule(rule);
+          return true;
+        }
         if (acceptString("neverclassinline")) {
           ClassInlineRule rule = parseClassInlineRule(ClassInlineRule.Type.NEVER, optionStart);
           configurationBuilder.addRule(rule);
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java
index ed49a01..f899a6b 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java
@@ -57,6 +57,14 @@
     return null;
   }
 
+  public boolean isClassInlineRule() {
+    return false;
+  }
+
+  public ClassInlineRule asClassInlineRule() {
+    return null;
+  }
+
   Iterable<DexProgramClass> relevantCandidatesForRule(
       AppView<? extends AppInfoWithSubtyping> appView, Iterable<DexProgramClass> defaultValue) {
     if (hasInheritanceClassName() && getInheritanceClassName().hasSpecificType()) {
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
index 24b5004..b86857a 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.shaking;
 
-
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfo;
@@ -82,6 +81,7 @@
   private final Set<DexMethod> whyAreYouNotInlining = Sets.newIdentityHashSet();
   private final Set<DexMethod> keepParametersWithConstantValue = Sets.newIdentityHashSet();
   private final Set<DexMethod> keepUnusedArguments = Sets.newIdentityHashSet();
+  private final Set<DexType> alwaysClassInline = Sets.newIdentityHashSet();
   private final Set<DexType> neverClassInline = Sets.newIdentityHashSet();
   private final Set<DexType> neverMerge = Sets.newIdentityHashSet();
   private final Set<DexReference> neverPropagateValue = Sets.newIdentityHashSet();
@@ -312,6 +312,7 @@
         whyAreYouNotInlining,
         keepParametersWithConstantValue,
         keepUnusedArguments,
+        alwaysClassInline,
         neverClassInline,
         neverMerge,
         neverPropagateValue,
@@ -1108,12 +1109,23 @@
       }
       whyAreYouNotInlining.add(item.asDexEncodedMethod().method);
       context.markAsUsed();
-    } else if (context instanceof ClassInlineRule) {
-      switch (((ClassInlineRule) context).getType()) {
+    } else if (context.isClassInlineRule()) {
+      ClassInlineRule classInlineRule = context.asClassInlineRule();
+      DexClass clazz = item.asDexClass();
+      if (clazz == null) {
+        throw new IllegalStateException(
+            "Unexpected -"
+                + classInlineRule.typeString()
+                + " rule for a non-class type: `"
+                + item.toReference().toSourceString()
+                + "`");
+      }
+      switch (classInlineRule.getType()) {
+        case ALWAYS:
+          alwaysClassInline.add(item.asDexClass().type);
+          break;
         case NEVER:
-          if (item.isDexClass()) {
-            neverClassInline.add(item.asDexClass().type);
-          }
+          neverClassInline.add(item.asDexClass().type);
           break;
         default:
           throw new Unreachable();
@@ -1189,6 +1201,7 @@
     public final Set<DexMethod> whyAreYouNotInlining;
     public final Set<DexMethod> keepConstantArguments;
     public final Set<DexMethod> keepUnusedArguments;
+    public final Set<DexType> alwaysClassInline;
     public final Set<DexType> neverClassInline;
     public final Set<DexType> neverMerge;
     public final Set<DexReference> neverPropagateValue;
@@ -1215,6 +1228,7 @@
         Set<DexMethod> whyAreYouNotInlining,
         Set<DexMethod> keepConstantArguments,
         Set<DexMethod> keepUnusedArguments,
+        Set<DexType> alwaysClassInline,
         Set<DexType> neverClassInline,
         Set<DexType> neverMerge,
         Set<DexReference> neverPropagateValue,
@@ -1238,6 +1252,7 @@
       this.whyAreYouNotInlining = whyAreYouNotInlining;
       this.keepConstantArguments = keepConstantArguments;
       this.keepUnusedArguments = keepUnusedArguments;
+      this.alwaysClassInline = alwaysClassInline;
       this.neverClassInline = neverClassInline;
       this.neverMerge = Collections.unmodifiableSet(neverMerge);
       this.neverPropagateValue = neverPropagateValue;
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 77de8e2..9a477cc 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -1147,7 +1147,7 @@
           // Only rewrite the invoke-super call if it does not lead to a NoSuchMethodError.
           boolean resolutionSucceeds =
               holder.lookupVirtualMethod(signatureInHolder) != null
-                  || appInfo.lookupSuperTarget(signatureInHolder, holder.type) != null;
+                  || appInfo.lookupSuperTarget(signatureInHolder, holder) != null;
           if (resolutionSucceeds) {
             deferredRenamings.mapVirtualMethodToDirectInType(
                 signatureInHolder, new GraphLenseLookupResult(newTarget, DIRECT), target.type);
@@ -1169,7 +1169,7 @@
               // its super classes declared the method.
               boolean resolutionSucceededBeforeMerge =
                   renamedMembersLense.hasMappingForSignatureInContext(holder.type, signatureInType)
-                      || appInfo.lookupSuperTarget(signatureInHolder, holder.type) != null;
+                      || appInfo.lookupSuperTarget(signatureInHolder, holder) != null;
               if (resolutionSucceededBeforeMerge) {
                 deferredRenamings.mapVirtualMethodToDirectInType(
                     signatureInType, new GraphLenseLookupResult(newTarget, DIRECT), target.type);
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 40633b6..a5f672e 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -205,7 +205,8 @@
       !Version.isDevelopmentVersion()
           || System.getProperty("com.android.tools.r8.disableinlining") == null;
   // TODO(b/141451716): Evaluate the effect of allowing inlining in the inlinee.
-  public boolean applyInliningToInlinee = false;
+  public boolean applyInliningToInlinee =
+      System.getProperty("com.android.tools.r8.applyInliningToInlinee") != null;
   public int applyInliningToInlineeMaxDepth = 0;
   public boolean enableInliningOfInvokesWithNullableReceivers = true;
   public boolean disableInliningOfLibraryMethodOverrides = true;
diff --git a/src/test/examples/classmerging/NeverClassInline.java b/src/test/examples/classmerging/NeverClassInline.java
new file mode 100644
index 0000000..2dca10e
--- /dev/null
+++ b/src/test/examples/classmerging/NeverClassInline.java
@@ -0,0 +1,10 @@
+// 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 classmerging;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+@Target({ElementType.TYPE})
+public @interface NeverClassInline {}
diff --git a/src/test/examples/classmerging/ProguardFieldMapTest.java b/src/test/examples/classmerging/ProguardFieldMapTest.java
index 0cbf8a1..e512173 100644
--- a/src/test/examples/classmerging/ProguardFieldMapTest.java
+++ b/src/test/examples/classmerging/ProguardFieldMapTest.java
@@ -16,6 +16,7 @@
     public String f = "A.f";
   }
 
+  @NeverClassInline
   public static class B extends A {
 
     public void test() {
diff --git a/src/test/examples/classmerging/ProguardMethodMapTest.java b/src/test/examples/classmerging/ProguardMethodMapTest.java
index 9ce0ad7..dd3ccff 100644
--- a/src/test/examples/classmerging/ProguardMethodMapTest.java
+++ b/src/test/examples/classmerging/ProguardMethodMapTest.java
@@ -18,6 +18,7 @@
     }
   }
 
+  @NeverClassInline
   public static class B extends A {
 
     @Override
diff --git a/src/test/examples/classmerging/keep-rules.txt b/src/test/examples/classmerging/keep-rules.txt
index 11a66c6..5297ee9 100644
--- a/src/test/examples/classmerging/keep-rules.txt
+++ b/src/test/examples/classmerging/keep-rules.txt
@@ -68,6 +68,7 @@
   public static void main(...);
 }
 
+-neverclassinline @classmerging.NeverClassInline class *
 -neverinline class * {
   @classmerging.NeverInline <methods>;
 }
diff --git a/src/test/examplesJava10/backport/ListBackportJava10Main.java b/src/test/examplesJava10/backport/ListBackportJava10Main.java
new file mode 100644
index 0000000..376f67a
--- /dev/null
+++ b/src/test/examplesJava10/backport/ListBackportJava10Main.java
@@ -0,0 +1,67 @@
+// 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 backport;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class ListBackportJava10Main {
+
+  public static void main(String[] args) {
+    testCopyOf();
+  }
+
+  private static void testCopyOf() {
+    Object anObject0 = new Object();
+    Object anObject1 = new Object();
+    List<Object> original = Arrays.asList(anObject0, anObject1);
+    List<Object> copy = List.copyOf(original);
+    assertEquals(2, copy.size());
+    assertEquals(original, copy);
+    assertSame(anObject0, copy.get(0));
+    assertSame(anObject1, copy.get(1));
+    assertMutationNotAllowed(copy);
+
+    // Mutate the original backing collection and ensure it's not reflected in copy.
+    original.set(0, new Object());
+    assertSame(anObject0, copy.get(0));
+
+    try {
+      List.copyOf(null);
+      throw new AssertionError();
+    } catch (NullPointerException expected) {
+    }
+    try {
+      List.copyOf(Arrays.asList(1, null, 2));
+      throw new AssertionError();
+    } catch (NullPointerException expected) {
+    }
+  }
+
+  private static void assertMutationNotAllowed(List<Object> ofObject) {
+    try {
+      ofObject.add(new Object());
+      throw new AssertionError();
+    } catch (UnsupportedOperationException expected) {
+    }
+    try {
+      ofObject.set(0, new Object());
+      throw new AssertionError();
+    } catch (UnsupportedOperationException expected) {
+    }
+  }
+
+  private static void assertSame(Object expected, Object actual) {
+    if (expected != actual) {
+      throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
+    }
+  }
+
+  private static void assertEquals(Object expected, Object actual) {
+    if (expected != actual && !expected.equals(actual)) {
+      throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
+    }
+  }
+}
diff --git a/src/test/examplesJava10/backport/MapBackportJava10Main.java b/src/test/examplesJava10/backport/MapBackportJava10Main.java
new file mode 100644
index 0000000..95413e9
--- /dev/null
+++ b/src/test/examplesJava10/backport/MapBackportJava10Main.java
@@ -0,0 +1,82 @@
+// 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 backport;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class MapBackportJava10Main {
+
+  public static void main(String[] args) {
+    testCopyOf();
+  }
+
+  private static void testCopyOf() {
+    Object key0 = new Object();
+    Object value0 = new Object();
+    Object key1 = new Object();
+    Object value1 = new Object();
+    Map<Object, Object> original = new HashMap<>();
+    original.put(key0, value0);
+    original.put(key1, value1);
+    Map<Object, Object> copy = Map.copyOf(original);
+    assertEquals(2, copy.size());
+    assertEquals(original, copy);
+    assertSame(value0, copy.get(key0));
+    assertSame(value1, copy.get(key1));
+    assertMutationNotAllowed(copy);
+
+    // Mutate the original backing collection and ensure it's not reflected in copy.
+    original.put(key0, new Object());
+    assertSame(value0, copy.get(key0));
+
+    try {
+      Map.copyOf(null);
+      throw new AssertionError();
+    } catch (NullPointerException expected) {
+    }
+    try {
+      Map<Object, Object> map = new HashMap<>();
+      map.put(null, new Object());
+      Map.copyOf(map);
+      throw new AssertionError();
+    } catch (NullPointerException expected) {
+    }
+    try {
+      Map<Object, Object> map = new HashMap<>();
+      map.put(new Object(), null);
+      Map.copyOf(map);
+      throw new AssertionError();
+    } catch (NullPointerException expected) {
+    }
+  }
+
+  private static void assertMutationNotAllowed(Map<Object, Object> ofObject) {
+    try {
+      ofObject.put(new Object(), new Object());
+      throw new AssertionError();
+    } catch (UnsupportedOperationException expected) {
+    }
+    for (Map.Entry<Object, Object> entry : ofObject.entrySet()) {
+      try {
+        entry.setValue(new Object());
+        throw new AssertionError();
+      } catch (UnsupportedOperationException expected) {
+      }
+    }
+  }
+
+  private static void assertSame(Object expected, Object actual) {
+    if (expected != actual) {
+      throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
+    }
+  }
+
+  private static void assertEquals(Object expected, Object actual) {
+    if (expected != actual && !expected.equals(actual)) {
+      throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
+    }
+  }
+}
diff --git a/src/test/examplesJava10/backport/OptionalBackportJava10Main.java b/src/test/examplesJava10/backport/OptionalBackportJava10Main.java
new file mode 100644
index 0000000..3d2c919
--- /dev/null
+++ b/src/test/examplesJava10/backport/OptionalBackportJava10Main.java
@@ -0,0 +1,32 @@
+// 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 backport;
+
+import java.util.NoSuchElementException;
+import java.util.Optional;
+
+public final class OptionalBackportJava10Main {
+
+  public static void main(String[] args) {
+    testOrElseThrow();
+  }
+
+  private static void testOrElseThrow() {
+    Optional<String> present = Optional.of("hey");
+    assertEquals("hey", present.orElseThrow());
+
+    Optional<String> absent = Optional.empty();
+    try {
+      throw new AssertionError(absent.orElseThrow());
+    } catch (NoSuchElementException expected) {
+    }
+  }
+
+  private static void assertEquals(Object expected, Object actual) {
+    if (expected != actual && !expected.equals(actual)) {
+      throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
+    }
+  }
+}
diff --git a/src/test/examplesJava10/backport/OptionalDoubleBackportJava10Main.java b/src/test/examplesJava10/backport/OptionalDoubleBackportJava10Main.java
new file mode 100644
index 0000000..1c27538
--- /dev/null
+++ b/src/test/examplesJava10/backport/OptionalDoubleBackportJava10Main.java
@@ -0,0 +1,32 @@
+// 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 backport;
+
+import java.util.NoSuchElementException;
+import java.util.OptionalDouble;
+
+public final class OptionalDoubleBackportJava10Main {
+
+  public static void main(String[] args) {
+    testOrElseThrow();
+  }
+
+  private static void testOrElseThrow() {
+    OptionalDouble present = OptionalDouble.of(2d);
+    assertEquals(2d, present.orElseThrow());
+
+    OptionalDouble absent = OptionalDouble.empty();
+    try {
+      throw new AssertionError(absent.orElseThrow());
+    } catch (NoSuchElementException expected) {
+    }
+  }
+
+  private static void assertEquals(Object expected, Object actual) {
+    if (expected != actual && !expected.equals(actual)) {
+      throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
+    }
+  }
+}
diff --git a/src/test/examplesJava10/backport/OptionalIntBackportJava10Main.java b/src/test/examplesJava10/backport/OptionalIntBackportJava10Main.java
new file mode 100644
index 0000000..06c85f5
--- /dev/null
+++ b/src/test/examplesJava10/backport/OptionalIntBackportJava10Main.java
@@ -0,0 +1,32 @@
+// 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 backport;
+
+import java.util.NoSuchElementException;
+import java.util.OptionalInt;
+
+public final class OptionalIntBackportJava10Main {
+
+  public static void main(String[] args) {
+    testOrElseThrow();
+  }
+
+  private static void testOrElseThrow() {
+    OptionalInt present = OptionalInt.of(2);
+    assertEquals(2, present.orElseThrow());
+
+    OptionalInt absent = OptionalInt.empty();
+    try {
+      throw new AssertionError(absent.orElseThrow());
+    } catch (NoSuchElementException expected) {
+    }
+  }
+
+  private static void assertEquals(Object expected, Object actual) {
+    if (expected != actual && !expected.equals(actual)) {
+      throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
+    }
+  }
+}
diff --git a/src/test/examplesJava10/backport/OptionalLongBackportJava10Main.java b/src/test/examplesJava10/backport/OptionalLongBackportJava10Main.java
new file mode 100644
index 0000000..e92b9a5
--- /dev/null
+++ b/src/test/examplesJava10/backport/OptionalLongBackportJava10Main.java
@@ -0,0 +1,32 @@
+// 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 backport;
+
+import java.util.NoSuchElementException;
+import java.util.OptionalLong;
+
+public final class OptionalLongBackportJava10Main {
+
+  public static void main(String[] args) {
+    testOrElseThrow();
+  }
+
+  private static void testOrElseThrow() {
+    OptionalLong present = OptionalLong.of(2L);
+    assertEquals(2L, present.orElseThrow());
+
+    OptionalLong absent = OptionalLong.empty();
+    try {
+      throw new AssertionError(absent.orElseThrow());
+    } catch (NoSuchElementException expected) {
+    }
+  }
+
+  private static void assertEquals(Object expected, Object actual) {
+    if (expected != actual && !expected.equals(actual)) {
+      throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
+    }
+  }
+}
diff --git a/src/test/examplesJava10/backport/SetBackportJava10Main.java b/src/test/examplesJava10/backport/SetBackportJava10Main.java
new file mode 100644
index 0000000..b8fb356
--- /dev/null
+++ b/src/test/examplesJava10/backport/SetBackportJava10Main.java
@@ -0,0 +1,74 @@
+// 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 backport;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class SetBackportJava10Main {
+
+  public static void main(String[] args) {
+    testCopyOf();
+  }
+
+  private static void testCopyOf() {
+    Object anObject0 = new Object();
+    Object anObject1 = new Object();
+    List<Object> original = Arrays.asList(anObject0, anObject1);
+    Set<Object> copy = Set.copyOf(original);
+    assertEquals(2, copy.size());
+    assertEquals(new HashSet<>(original), copy);
+    assertTrue(copy.contains(anObject0));
+    assertTrue(copy.contains(anObject1));
+    assertMutationNotAllowed(copy);
+
+    // Mutate the original backing collection and ensure it's not reflected in copy.
+    Object newObject = new Object();
+    original.set(0, newObject);
+    assertFalse(copy.contains(newObject));
+
+    // Ensure duplicates are allowed and are de-duped.
+    assertEquals(Set.of(1, 2), Set.copyOf(List.of(1, 2, 1, 2)));
+
+    try {
+      Set.copyOf(null);
+      throw new AssertionError();
+    } catch (NullPointerException expected) {
+    }
+    try {
+      Set.copyOf(Arrays.asList(1, null, 2));
+      throw new AssertionError();
+    } catch (NullPointerException expected) {
+    }
+  }
+
+  private static void assertMutationNotAllowed(Set<Object> ofObject) {
+    try {
+      ofObject.add(new Object());
+      throw new AssertionError();
+    } catch (UnsupportedOperationException expected) {
+    }
+  }
+
+  private static void assertTrue(boolean value) {
+    if (!value) {
+      throw new AssertionError("Expected <true> but was <false>");
+    }
+  }
+
+  private static void assertFalse(boolean value) {
+    if (value) {
+      throw new AssertionError("Expected <false> but was <true>");
+    }
+  }
+
+  private static void assertEquals(Object expected, Object actual) {
+    if (expected != actual && !expected.equals(actual)) {
+      throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
+    }
+  }
+}
diff --git a/src/test/examplesJava11/backport/OptionalBackportJava11Main.java b/src/test/examplesJava11/backport/OptionalBackportJava11Main.java
new file mode 100644
index 0000000..d1f6fa1
--- /dev/null
+++ b/src/test/examplesJava11/backport/OptionalBackportJava11Main.java
@@ -0,0 +1,34 @@
+// 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 backport;
+
+import java.util.Optional;
+
+public final class OptionalBackportJava11Main {
+
+  public static void main(String[] args) {
+    testIsEmpty();
+  }
+
+  private static void testIsEmpty() {
+    Optional<String> present = Optional.of("hey");
+    assertFalse(present.isEmpty());
+
+    Optional<String> absent = Optional.empty();
+    assertTrue(absent.isEmpty());
+  }
+
+  private static void assertTrue(boolean value) {
+    if (!value) {
+      throw new AssertionError("Expected <true> but was <false>");
+    }
+  }
+
+  private static void assertFalse(boolean value) {
+    if (value) {
+      throw new AssertionError("Expected <false> but was <true>");
+    }
+  }
+}
diff --git a/src/test/examplesJava11/backport/OptionalDoubleBackportJava11Main.java b/src/test/examplesJava11/backport/OptionalDoubleBackportJava11Main.java
new file mode 100644
index 0000000..1fa5617
--- /dev/null
+++ b/src/test/examplesJava11/backport/OptionalDoubleBackportJava11Main.java
@@ -0,0 +1,34 @@
+// 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 backport;
+
+import java.util.OptionalDouble;
+
+public final class OptionalDoubleBackportJava11Main {
+
+  public static void main(String[] args) {
+    testIsEmpty();
+  }
+
+  private static void testIsEmpty() {
+    OptionalDouble present = OptionalDouble.of(2d);
+    assertFalse(present.isEmpty());
+
+    OptionalDouble absent = OptionalDouble.empty();
+    assertTrue(absent.isEmpty());
+  }
+
+  private static void assertTrue(boolean value) {
+    if (!value) {
+      throw new AssertionError("Expected <true> but was <false>");
+    }
+  }
+
+  private static void assertFalse(boolean value) {
+    if (value) {
+      throw new AssertionError("Expected <false> but was <true>");
+    }
+  }
+}
diff --git a/src/test/examplesJava11/backport/OptionalIntBackportJava11Main.java b/src/test/examplesJava11/backport/OptionalIntBackportJava11Main.java
new file mode 100644
index 0000000..9d1a09a
--- /dev/null
+++ b/src/test/examplesJava11/backport/OptionalIntBackportJava11Main.java
@@ -0,0 +1,34 @@
+// 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 backport;
+
+import java.util.OptionalInt;
+
+public final class OptionalIntBackportJava11Main {
+
+  public static void main(String[] args) {
+    testIsEmpty();
+  }
+
+  private static void testIsEmpty() {
+    OptionalInt present = OptionalInt.of(2);
+    assertFalse(present.isEmpty());
+
+    OptionalInt absent = OptionalInt.empty();
+    assertTrue(absent.isEmpty());
+  }
+
+  private static void assertTrue(boolean value) {
+    if (!value) {
+      throw new AssertionError("Expected <true> but was <false>");
+    }
+  }
+
+  private static void assertFalse(boolean value) {
+    if (value) {
+      throw new AssertionError("Expected <false> but was <true>");
+    }
+  }
+}
diff --git a/src/test/examplesJava11/backport/OptionalLongBackportJava11Main.java b/src/test/examplesJava11/backport/OptionalLongBackportJava11Main.java
new file mode 100644
index 0000000..573bbba
--- /dev/null
+++ b/src/test/examplesJava11/backport/OptionalLongBackportJava11Main.java
@@ -0,0 +1,34 @@
+// 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 backport;
+
+import java.util.OptionalLong;
+
+public final class OptionalLongBackportJava11Main {
+
+  public static void main(String[] args) {
+    testIsEmpty();
+  }
+
+  private static void testIsEmpty() {
+    OptionalLong present = OptionalLong.of(2L);
+    assertFalse(present.isEmpty());
+
+    OptionalLong absent = OptionalLong.empty();
+    assertTrue(absent.isEmpty());
+  }
+
+  private static void assertTrue(boolean value) {
+    if (!value) {
+      throw new AssertionError("Expected <true> but was <false>");
+    }
+  }
+
+  private static void assertFalse(boolean value) {
+    if (value) {
+      throw new AssertionError("Expected <false> but was <true>");
+    }
+  }
+}
diff --git a/src/test/examplesJava9/backport/MathBackportJava9Main.java b/src/test/examplesJava9/backport/MathBackportJava9Main.java
index 5eefb65..9030283 100644
--- a/src/test/examplesJava9/backport/MathBackportJava9Main.java
+++ b/src/test/examplesJava9/backport/MathBackportJava9Main.java
@@ -4,10 +4,14 @@
 
 package backport;
 
+import java.math.BigInteger;
+
 public class MathBackportJava9Main {
 
   public static void main(String[] args) {
     testMultiplyExactLongInt();
+    testMultiplyFull();
+    testMultiplyHigh();
     testFloorDivLongInt();
     testFloorModLongInt();
   }
@@ -26,6 +30,37 @@
     }
   }
 
+  public static void testMultiplyFull() {
+    assertEquals(8L, Math.multiplyFull(2, 4));
+    assertEquals(4611686014132420609L,
+        Math.multiplyFull(Integer.MAX_VALUE, Integer.MAX_VALUE));
+    assertEquals(-4611686016279904256L,
+        Math.multiplyFull(Integer.MAX_VALUE, Integer.MIN_VALUE));
+    assertEquals(4611686018427387904L,
+        Math.multiplyFull(Integer.MIN_VALUE, Integer.MIN_VALUE));
+  }
+
+  public static void testMultiplyHigh() {
+    long[] interestingValues = {
+        Long.MIN_VALUE, Long.MAX_VALUE,
+        Integer.MIN_VALUE, Integer.MAX_VALUE,
+        Short.MIN_VALUE, Short.MAX_VALUE,
+        Byte.MIN_VALUE, Byte.MAX_VALUE,
+        0L,
+        -1L, 1L,
+        -42L, 42L
+    };
+    for (long x : interestingValues) {
+      for (long y : interestingValues) {
+        long expected = BigInteger.valueOf(x)
+            .multiply(BigInteger.valueOf(y))
+            .shiftRight(64)
+            .longValue();
+        assertEquals(expected, Math.multiplyHigh(x, y));
+      }
+    }
+  }
+
   public static void testFloorDivLongInt() {
     assertEquals(1L, Math.floorDiv(4L, 4));
     assertEquals(1L, Math.floorDiv(-4L, -4));
diff --git a/src/test/examplesJava9/backport/OptionalBackportJava9Main.java b/src/test/examplesJava9/backport/OptionalBackportJava9Main.java
index b337875..c25226f 100644
--- a/src/test/examplesJava9/backport/OptionalBackportJava9Main.java
+++ b/src/test/examplesJava9/backport/OptionalBackportJava9Main.java
@@ -5,9 +5,6 @@
 package backport;
 
 import java.util.Optional;
-import java.util.OptionalDouble;
-import java.util.OptionalInt;
-import java.util.OptionalLong;
 
 public final class OptionalBackportJava9Main {
 
@@ -15,9 +12,6 @@
     testOr();
     testOrNull();
     testIfPresentOrElse();
-    testIfPresentOrElseInt();
-    testIfPresentOrElseLong();
-    testIfPresentOrElseDouble();
     testStream();
   }
 
@@ -69,27 +63,6 @@
     emptyValue.ifPresentOrElse(val -> assertTrue(false), () -> {});
   }
 
-  private static void testIfPresentOrElseInt() {
-    OptionalInt value = OptionalInt.of(1);
-    OptionalInt emptyValue = OptionalInt.empty();
-    value.ifPresentOrElse(val -> {}, () -> assertTrue(false));
-    emptyValue.ifPresentOrElse(val -> assertTrue(false), () -> {});
-  }
-
-  private static void testIfPresentOrElseLong() {
-    OptionalLong value = OptionalLong.of(1L);
-    OptionalLong emptyValue = OptionalLong.empty();
-    value.ifPresentOrElse(val -> {}, () -> assertTrue(false));
-    emptyValue.ifPresentOrElse(val -> assertTrue(false), () -> {});
-  }
-
-  private static void testIfPresentOrElseDouble() {
-    OptionalDouble value = OptionalDouble.of(1.0d);
-    OptionalDouble emptyValue = OptionalDouble.empty();
-    value.ifPresentOrElse(val -> {}, () -> assertTrue(false));
-    emptyValue.ifPresentOrElse(val -> assertTrue(false), () -> {});
-  }
-
   private static void testStream() {
     Optional<String> value = Optional.of("value");
     Optional<String> emptyValue = Optional.empty();
diff --git a/src/test/examplesJava9/backport/OptionalDoubleBackportJava9Main.java b/src/test/examplesJava9/backport/OptionalDoubleBackportJava9Main.java
new file mode 100644
index 0000000..9b08718
--- /dev/null
+++ b/src/test/examplesJava9/backport/OptionalDoubleBackportJava9Main.java
@@ -0,0 +1,35 @@
+// 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 backport;
+
+import java.util.OptionalDouble;
+
+public final class OptionalDoubleBackportJava9Main {
+
+  public static void main(String[] args) {
+    testIfPresentOrElseDouble();
+    testStreamDouble();
+  }
+
+  private static void testIfPresentOrElseDouble() {
+    OptionalDouble value = OptionalDouble.of(1.0d);
+    OptionalDouble emptyValue = OptionalDouble.empty();
+    value.ifPresentOrElse(val -> {}, () -> assertTrue(false));
+    emptyValue.ifPresentOrElse(val -> assertTrue(false), () -> {});
+  }
+
+  private static void testStreamDouble() {
+    OptionalDouble value = OptionalDouble.of(2d);
+    OptionalDouble emptyValue = OptionalDouble.empty();
+    assertTrue(value.stream().count() == 1);
+    assertTrue(emptyValue.stream().count() == 0);
+  }
+
+  private static void assertTrue(boolean value) {
+    if (!value) {
+      throw new AssertionError("Expected <true> but was <false>");
+    }
+  }
+}
diff --git a/src/test/examplesJava9/backport/OptionalIntBackportJava9Main.java b/src/test/examplesJava9/backport/OptionalIntBackportJava9Main.java
new file mode 100644
index 0000000..fedc472
--- /dev/null
+++ b/src/test/examplesJava9/backport/OptionalIntBackportJava9Main.java
@@ -0,0 +1,35 @@
+// 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 backport;
+
+import java.util.OptionalInt;
+
+public final class OptionalIntBackportJava9Main {
+
+  public static void main(String[] args) {
+    testIfPresentOrElseInt();
+    testStreamInt();
+  }
+
+  private static void testIfPresentOrElseInt() {
+    OptionalInt value = OptionalInt.of(1);
+    OptionalInt emptyValue = OptionalInt.empty();
+    value.ifPresentOrElse(val -> {}, () -> assertTrue(false));
+    emptyValue.ifPresentOrElse(val -> assertTrue(false), () -> {});
+  }
+
+  private static void testStreamInt() {
+    OptionalInt value = OptionalInt.of(2);
+    OptionalInt emptyValue = OptionalInt.empty();
+    assertTrue(value.stream().count() == 1);
+    assertTrue(emptyValue.stream().count() == 0);
+  }
+
+  private static void assertTrue(boolean value) {
+    if (!value) {
+      throw new AssertionError("Expected <true> but was <false>");
+    }
+  }
+}
diff --git a/src/test/examplesJava9/backport/OptionalLongBackportJava9Main.java b/src/test/examplesJava9/backport/OptionalLongBackportJava9Main.java
new file mode 100644
index 0000000..07438e1
--- /dev/null
+++ b/src/test/examplesJava9/backport/OptionalLongBackportJava9Main.java
@@ -0,0 +1,35 @@
+// 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 backport;
+
+import java.util.OptionalLong;
+
+public final class OptionalLongBackportJava9Main {
+
+  public static void main(String[] args) {
+    testIfPresentOrElseLong();
+    testStreamLong();
+  }
+
+  private static void testIfPresentOrElseLong() {
+    OptionalLong value = OptionalLong.of(1L);
+    OptionalLong emptyValue = OptionalLong.empty();
+    value.ifPresentOrElse(val -> {}, () -> assertTrue(false));
+    emptyValue.ifPresentOrElse(val -> assertTrue(false), () -> {});
+  }
+
+  private static void testStreamLong() {
+    OptionalLong value = OptionalLong.of(2L);
+    OptionalLong emptyValue = OptionalLong.empty();
+    assertTrue(value.stream().count() == 1);
+    assertTrue(emptyValue.stream().count() == 0);
+  }
+
+  private static void assertTrue(boolean value) {
+    if (!value) {
+      throw new AssertionError("Expected <true> but was <false>");
+    }
+  }
+}
diff --git a/src/test/examplesJava9/backport/StrictMathBackportJava9Main.java b/src/test/examplesJava9/backport/StrictMathBackportJava9Main.java
index b711539..e9c33ca 100644
--- a/src/test/examplesJava9/backport/StrictMathBackportJava9Main.java
+++ b/src/test/examplesJava9/backport/StrictMathBackportJava9Main.java
@@ -4,10 +4,13 @@
 
 package backport;
 
+import java.math.BigInteger;
+
 public class StrictMathBackportJava9Main {
 
   public static void main(String[] args) {
     testMultiplyExactLongInt();
+    testMultiplyFull();
     testFloorDivLongInt();
     testFloorModLongInt();
   }
@@ -26,6 +29,37 @@
     }
   }
 
+  public static void testMultiplyFull() {
+    assertEquals(8L, StrictMath.multiplyFull(2, 4));
+    assertEquals(4611686014132420609L,
+        StrictMath.multiplyFull(Integer.MAX_VALUE, Integer.MAX_VALUE));
+    assertEquals(-4611686016279904256L,
+        StrictMath.multiplyFull(Integer.MAX_VALUE, Integer.MIN_VALUE));
+    assertEquals(4611686018427387904L,
+        StrictMath.multiplyFull(Integer.MIN_VALUE, Integer.MIN_VALUE));
+  }
+
+  public static void testMultiplyHigh() {
+    long[] interestingValues = {
+        Long.MIN_VALUE, Long.MAX_VALUE,
+        Integer.MIN_VALUE, Integer.MAX_VALUE,
+        Short.MIN_VALUE, Short.MAX_VALUE,
+        Byte.MIN_VALUE, Byte.MAX_VALUE,
+        0L,
+        -1L, 1L,
+        -42L, 42L
+    };
+    for (long x : interestingValues) {
+      for (long y : interestingValues) {
+        long expected = BigInteger.valueOf(x)
+            .multiply(BigInteger.valueOf(y))
+            .shiftRight(64)
+            .longValue();
+        assertEquals(expected, StrictMath.multiplyHigh(x, y));
+      }
+    }
+  }
+
   public static void testFloorDivLongInt() {
     assertEquals(1L, StrictMath.floorDiv(4L, 4));
     assertEquals(1L, StrictMath.floorDiv(-4L, -4));
diff --git a/src/test/java/com/android/tools/r8/GenerateMainDexListTestBuilder.java b/src/test/java/com/android/tools/r8/GenerateMainDexListTestBuilder.java
index 3ceeb97..e0f3cea 100644
--- a/src/test/java/com/android/tools/r8/GenerateMainDexListTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/GenerateMainDexListTestBuilder.java
@@ -46,6 +46,7 @@
     throw new Unimplemented("No support for running with a main class");
   }
 
+  @Override
   public DebugTestConfig debugConfig() {
     throw new Unimplemented("No support for debug configuration");
   }
diff --git a/src/test/java/com/android/tools/r8/JvmTestBuilder.java b/src/test/java/com/android/tools/r8/JvmTestBuilder.java
index e44287f..bef8a14 100644
--- a/src/test/java/com/android/tools/r8/JvmTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/JvmTestBuilder.java
@@ -44,6 +44,7 @@
     return run(TestRuntime.getDefaultJavaRuntime(), mainClass);
   }
 
+  @Override
   public JvmTestRunResult run(TestRuntime runtime, String mainClass, String... args)
       throws IOException {
     assert runtime.isCf();
diff --git a/src/test/java/com/android/tools/r8/R8TestBuilder.java b/src/test/java/com/android/tools/r8/R8TestBuilder.java
index 8e3e149..59ae602 100644
--- a/src/test/java/com/android/tools/r8/R8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/R8TestBuilder.java
@@ -35,7 +35,7 @@
   }
 
   private boolean enableInliningAnnotations = false;
-  private boolean enableClassInliningAnnotations = false;
+  private boolean enableNeverClassInliningAnnotations = false;
   private boolean enableMergeAnnotations = false;
   private boolean enableMemberValuePropagationAnnotations = false;
   private boolean enableConstantArgumentAnnotations = false;
@@ -51,7 +51,7 @@
       Builder builder, Consumer<InternalOptions> optionsConsumer, Supplier<AndroidApp> app)
       throws CompilationFailedException {
     if (enableInliningAnnotations
-        || enableClassInliningAnnotations
+        || enableNeverClassInliningAnnotations
         || enableMergeAnnotations
         || enableMemberValuePropagationAnnotations
         || enableConstantArgumentAnnotations
@@ -239,9 +239,9 @@
     return self();
   }
 
-  public T enableClassInliningAnnotations() {
-    if (!enableClassInliningAnnotations) {
-      enableClassInliningAnnotations = true;
+  public T enableNeverClassInliningAnnotations() {
+    if (!enableNeverClassInliningAnnotations) {
+      enableNeverClassInliningAnnotations = true;
       addInternalKeepRules("-neverclassinline @com.android.tools.r8.NeverClassInline class *");
     }
     return self();
diff --git a/src/test/java/com/android/tools/r8/TestBuilder.java b/src/test/java/com/android/tools/r8/TestBuilder.java
index 94b0afc..27af1aa 100644
--- a/src/test/java/com/android/tools/r8/TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestBuilder.java
@@ -5,10 +5,12 @@
 
 import com.android.tools.r8.debug.DebugTestConfig;
 import com.android.tools.r8.utils.ListUtils;
+import com.google.common.collect.ImmutableList;
 import java.io.IOException;
 import java.nio.file.Path;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.List;
 import java.util.concurrent.ExecutionException;
 
 public abstract class TestBuilder<RR extends TestRunResult, T extends TestBuilder<RR, T>> {
@@ -110,6 +112,26 @@
     return addLibraryFiles(Arrays.asList(files));
   }
 
+  public final T addTestingAnnotationsAsProgramClasses() {
+    return addProgramClasses(getTestingAnnotations());
+  }
+
+  public final T addTestingAnnotationsAsLibraryClasses() {
+    return addLibraryClasses(getTestingAnnotations());
+  }
+
+  private List<Class<?>> getTestingAnnotations() {
+    return ImmutableList.of(
+        AssumeMayHaveSideEffects.class,
+        ForceInline.class,
+        KeepConstantArguments.class,
+        KeepUnusedArguments.class,
+        NeverClassInline.class,
+        NeverInline.class,
+        NeverMerge.class,
+        NeverPropagateValue.class);
+  }
+
   static Collection<Path> getFilesForClasses(Collection<Class<?>> classes) {
     return ListUtils.map(classes, ToolHelper::getClassFileForTestClass);
   }
diff --git a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
index af1b81e..3b368b6 100644
--- a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
@@ -61,8 +61,6 @@
     }
   }
 
-  abstract T self();
-
   abstract CR internalCompile(
       B builder, Consumer<InternalOptions> optionsConsumer, Supplier<AndroidApp> app)
       throws CompilationFailedException;
diff --git a/src/test/java/com/android/tools/r8/TestRunResult.java b/src/test/java/com/android/tools/r8/TestRunResult.java
index f286bac..e1ebfa2 100644
--- a/src/test/java/com/android/tools/r8/TestRunResult.java
+++ b/src/test/java/com/android/tools/r8/TestRunResult.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8;
 
+import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
@@ -90,6 +91,15 @@
     return self();
   }
 
+  public RR assertFailureWithErrorThatThrows(Class<? extends Throwable> expectedError) {
+    assertFailure();
+    assertThat(
+        errorMessage("Run stderr incorrect.", expectedError.getName()),
+        result.stderr,
+        containsString(expectedError.getName()));
+    return self();
+  }
+
   public RR assertStderrMatches(Matcher<String> matcher) {
     assertThat(errorMessage("Run stderr incorrect.", matcher.toString()), result.stderr, matcher);
     return self();
diff --git a/src/test/java/com/android/tools/r8/TestRuntime.java b/src/test/java/com/android/tools/r8/TestRuntime.java
index 6347853..99f9a71 100644
--- a/src/test/java/com/android/tools/r8/TestRuntime.java
+++ b/src/test/java/com/android/tools/r8/TestRuntime.java
@@ -25,7 +25,9 @@
   public enum CfVm {
     JDK8("jdk8", 52),
     JDK9("jdk9", 53),
-    JDK11("jdk11", 55);
+    JDK10("jdk10", 54),
+    JDK11("jdk11", 55),
+    ;
 
     private final String name;
     private final int classfileVersion;
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index c0a5ee0..87b2806 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -107,6 +107,7 @@
   public static final String EXAMPLES_ANDROID_O_BUILD_DIR = TESTS_BUILD_DIR + "examplesAndroidO/";
   public static final String EXAMPLES_ANDROID_P_BUILD_DIR = TESTS_BUILD_DIR + "examplesAndroidP/";
   public static final String EXAMPLES_JAVA9_BUILD_DIR = TESTS_BUILD_DIR + "examplesJava9/";
+  public static final String EXAMPLES_JAVA10_BUILD_DIR = TESTS_BUILD_DIR + "examplesJava10/";
   public static final String EXAMPLES_JAVA11_JAR_DIR = TESTS_BUILD_DIR + "examplesJava11/";
   public static final String EXAMPLES_JAVA11_BUILD_DIR = BUILD_DIR + "classes/java/examplesJava11/";
   public static final String EXAMPLES_PROTO_BUILD_DIR = TESTS_BUILD_DIR + "examplesProto/";
diff --git a/src/test/java/com/android/tools/r8/accessrelaxation/NoRelaxationForSerializableTest.java b/src/test/java/com/android/tools/r8/accessrelaxation/NoRelaxationForSerializableTest.java
index 294ee96..b9883ef 100644
--- a/src/test/java/com/android/tools/r8/accessrelaxation/NoRelaxationForSerializableTest.java
+++ b/src/test/java/com/android/tools/r8/accessrelaxation/NoRelaxationForSerializableTest.java
@@ -82,8 +82,7 @@
 @RunWith(Parameterized.class)
 public class NoRelaxationForSerializableTest extends AccessRelaxationTestBase {
   private static final Class<?> MAIN = NoRelaxationForSerializableTestRunner.class;
-  private static final List<Class<?>> CLASSES = ImmutableList.of(
-      NeverMerge.class, NeverInline.class, MySerializable.class, MAIN);
+  private static final List<Class<?>> CLASSES = ImmutableList.of(MySerializable.class, MAIN);
   private static final String KEEPMEMBER_RULES = StringUtils.lines(
       "-keepclassmembers class * implements java.io.Serializable {",
       "  private void writeObject(java.io.ObjectOutputStream);",
@@ -101,7 +100,8 @@
 
   @Parameterized.Parameters(name = "{0}, access-modification: {1}")
   public static List<Object[]> data() {
-    return buildParameters(getTestParameters().withAllRuntimes().build(), BooleanUtils.values());
+    return buildParameters(
+        getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values());
   }
 
   public NoRelaxationForSerializableTest(TestParameters parameters, boolean accessModification) {
@@ -123,6 +123,7 @@
     assumeTrue(parameters.isCfRuntime());
     testForProguard()
         .addProgramClasses(CLASSES)
+        .addTestingAnnotationsAsProgramClasses()
         .addKeepRuleFiles(configuration)
         .addKeepRules(KEEPMEMBER_RULES)
         .compile()
@@ -133,14 +134,15 @@
 
   @Test
   public void testR8_withKeepRules() throws Exception {
-    R8TestCompileResult result = testForR8(parameters.getBackend())
-        .addProgramClasses(CLASSES)
-        .enableInliningAnnotations()
-        .addKeepRuleFiles(configuration)
-        .addKeepRules(KEEPMEMBER_RULES)
-        .setMinApi(parameters.getRuntime())
-        .compile()
-        .inspect(this::inspect);
+    R8TestCompileResult result =
+        testForR8(parameters.getBackend())
+            .addProgramClasses(CLASSES)
+            .enableInliningAnnotations()
+            .addKeepRuleFiles(configuration)
+            .addKeepRules(KEEPMEMBER_RULES)
+            .setMinApi(parameters.getApiLevel())
+            .compile()
+            .inspect(this::inspect);
     // TODO(b/117302947): Need to update ART binary.
     if (parameters.isCfRuntime()) {
       result
@@ -154,20 +156,22 @@
     assumeTrue(parameters.isCfRuntime());
     testForProguard()
         .addProgramClasses(CLASSES)
+        .addTestingAnnotationsAsProgramClasses()
         .addKeepRuleFiles(configuration)
         .compile()
-        .run(MAIN)
+        .run(parameters.getRuntime(), MAIN)
         .assertFailureWithErrorThatMatches(containsString("Could not deserialize"));
   }
 
   @Test
   public void testR8_withoutKeepRules() throws Exception {
-    R8TestCompileResult result = testForR8(parameters.getBackend())
-        .addProgramClasses(CLASSES)
-        .enableInliningAnnotations()
-        .addKeepRuleFiles(configuration)
-        .setMinApi(parameters.getRuntime())
-        .compile();
+    R8TestCompileResult result =
+        testForR8(parameters.getBackend())
+            .addProgramClasses(CLASSES)
+            .enableInliningAnnotations()
+            .addKeepRuleFiles(configuration)
+            .setMinApi(parameters.getApiLevel())
+            .compile();
     // TODO(b/117302947): Need to update ART binary.
     if (parameters.isCfRuntime()) {
       result
@@ -182,5 +186,4 @@
     assertNotPublic(inspector, MySerializable.class,
         new MethodSignature("readObject", "void", ImmutableList.of("java.io.ObjectInputStream")));
   }
-
 }
diff --git a/src/test/java/com/android/tools/r8/accessrelaxation/NonConstructorRelaxationTest.java b/src/test/java/com/android/tools/r8/accessrelaxation/NonConstructorRelaxationTest.java
index f203ade..7756299 100644
--- a/src/test/java/com/android/tools/r8/accessrelaxation/NonConstructorRelaxationTest.java
+++ b/src/test/java/com/android/tools/r8/accessrelaxation/NonConstructorRelaxationTest.java
@@ -36,7 +36,8 @@
 
   @Parameterized.Parameters(name = "{0}, argument removal: {1}")
   public static List<Object[]> data() {
-    return buildParameters(getTestParameters().withAllRuntimes().build(), BooleanUtils.values());
+    return buildParameters(
+        getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values());
   }
 
   public NonConstructorRelaxationTest(TestParameters parameters, boolean enableArgumentRemoval) {
@@ -99,7 +100,7 @@
                 "  *** pBlah1();",
                 "}")
             .allowAccessModification()
-            .setMinApi(parameters.getRuntime())
+            .setMinApi(parameters.getApiLevel())
             .run(parameters.getRuntime(), mainClass);
 
     assertEquals(
@@ -157,6 +158,7 @@
             .addProgramFiles(ToolHelper.getClassFilesForTestPackage(mainClass.getPackage()))
             .addKeepMainRule(mainClass)
             .addOptionsModification(o -> o.enableVerticalClassMerging = enableVerticalClassMerging)
+            .enableNeverClassInliningAnnotations()
             .enableInliningAnnotations()
             .enableMemberValuePropagationAnnotations()
             .noMinification()
@@ -171,7 +173,7 @@
                 "  *** p*();",
                 "}")
             .allowAccessModification()
-            .setMinApi(parameters.getRuntime())
+            .setMinApi(parameters.getApiLevel())
             .run(parameters.getRuntime(), mainClass);
 
     assertEquals(
diff --git a/src/test/java/com/android/tools/r8/accessrelaxation/privateinstance/Sub1.java b/src/test/java/com/android/tools/r8/accessrelaxation/privateinstance/Sub1.java
index 0793001..b45a708 100644
--- a/src/test/java/com/android/tools/r8/accessrelaxation/privateinstance/Sub1.java
+++ b/src/test/java/com/android/tools/r8/accessrelaxation/privateinstance/Sub1.java
@@ -3,8 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.accessrelaxation.privateinstance;
 
+import com.android.tools.r8.NeverClassInline;
 import com.android.tools.r8.NeverInline;
 
+@NeverClassInline
 public class Sub1 extends Base implements Itf1 {
 
   @Override
diff --git a/src/test/java/com/android/tools/r8/accessrelaxation/privateinstance/Sub2.java b/src/test/java/com/android/tools/r8/accessrelaxation/privateinstance/Sub2.java
index 018bc90..fbc2ebc 100644
--- a/src/test/java/com/android/tools/r8/accessrelaxation/privateinstance/Sub2.java
+++ b/src/test/java/com/android/tools/r8/accessrelaxation/privateinstance/Sub2.java
@@ -3,8 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.accessrelaxation.privateinstance;
 
+import com.android.tools.r8.NeverClassInline;
 import com.android.tools.r8.NeverInline;
 
+@NeverClassInline
 public class Sub2 extends Base implements Itf2 {
 
   @Override
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/bridgestokeep/KeepNonVisibilityBridgeMethodsTest.java b/src/test/java/com/android/tools/r8/bridgeremoval/bridgestokeep/KeepNonVisibilityBridgeMethodsTest.java
index c188c87..3b7481b 100644
--- a/src/test/java/com/android/tools/r8/bridgeremoval/bridgestokeep/KeepNonVisibilityBridgeMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/bridgeremoval/bridgestokeep/KeepNonVisibilityBridgeMethodsTest.java
@@ -51,7 +51,7 @@
             "  synthetic void registerObserver(...);",
             "}")
         .allowAccessModification()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         // TODO(b/120764902): MemberSubject.getOriginalName() is not working without the @NeverMerge
         //  annotation on DataAdapter.Observer.
         .enableMergeAnnotations()
diff --git a/src/test/java/com/android/tools/r8/checkdiscarded/CheckDiscardedOverriddenMethodTest.java b/src/test/java/com/android/tools/r8/checkdiscarded/CheckDiscardedOverriddenMethodTest.java
index 851fff9..3f5b778 100644
--- a/src/test/java/com/android/tools/r8/checkdiscarded/CheckDiscardedOverriddenMethodTest.java
+++ b/src/test/java/com/android/tools/r8/checkdiscarded/CheckDiscardedOverriddenMethodTest.java
@@ -46,7 +46,7 @@
           .addKeepMainRule(main)
           .addKeepRules(
               "-checkdiscard class **.*$" + targetClass.getSimpleName() + " { void gone(); }")
-          .enableClassInliningAnnotations()
+          .enableNeverClassInliningAnnotations()
           .enableInliningAnnotations()
           .enableMergeAnnotations()
           .minification(minification)
diff --git a/src/test/java/com/android/tools/r8/classmerging/B141942381.java b/src/test/java/com/android/tools/r8/classmerging/B141942381.java
index 438ab13..2c47534 100644
--- a/src/test/java/com/android/tools/r8/classmerging/B141942381.java
+++ b/src/test/java/com/android/tools/r8/classmerging/B141942381.java
@@ -51,7 +51,7 @@
         .addKeepMainRule(TestClass.class)
         .setMinApi(parameters.getRuntime())
         .addKeepAttributes("Signatures")
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .noMinification()
         .compile()
         .inspect(this::inspect)
diff --git a/src/test/java/com/android/tools/r8/classmerging/InterfaceWithProxyTest.java b/src/test/java/com/android/tools/r8/classmerging/InterfaceWithProxyTest.java
index 8284d3f..03f5803 100644
--- a/src/test/java/com/android/tools/r8/classmerging/InterfaceWithProxyTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/InterfaceWithProxyTest.java
@@ -35,7 +35,7 @@
     testForR8(parameters.getBackend())
         .addInnerClasses(InterfaceWithProxyTest.class)
         .addKeepMainRule(TestClass.class)
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/classmerging/StaticClassMergerInterfaceTest.java b/src/test/java/com/android/tools/r8/classmerging/StaticClassMergerInterfaceTest.java
index f37eab0..b0557d3 100644
--- a/src/test/java/com/android/tools/r8/classmerging/StaticClassMergerInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/StaticClassMergerInterfaceTest.java
@@ -44,7 +44,7 @@
             .addKeepMainRule(TestClass.class)
             .addKeepRules("-dontobfuscate")
             .enableInliningAnnotations()
-            .enableClassInliningAnnotations()
+            .enableNeverClassInliningAnnotations()
             .run(TestClass.class)
             .assertSuccessWithOutput(expectedOutput)
             .inspector();
diff --git a/src/test/java/com/android/tools/r8/classmerging/VerticalClassMergerInitTest.java b/src/test/java/com/android/tools/r8/classmerging/VerticalClassMergerInitTest.java
index 1c4f406..b95a89a 100644
--- a/src/test/java/com/android/tools/r8/classmerging/VerticalClassMergerInitTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/VerticalClassMergerInitTest.java
@@ -8,6 +8,7 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 
 import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.NeverClassInline;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -45,6 +46,7 @@
         .addInnerClasses(VerticalClassMergerInitTest.class)
         .addKeepMainRule(Main.class)
         .addMainDexRules("-keep class " + Main.class.getTypeName())
+        .enableNeverClassInliningAnnotations()
         .setMinApi(AndroidApiLevel.K_WATCH)
         .addOptionsModification(
             options -> {
@@ -76,6 +78,7 @@
     }
   }
 
+  @NeverClassInline
   public static class Child extends Base {
 
     // We need a static member to force the main-dex tracing to include Child and Base.
diff --git a/src/test/java/com/android/tools/r8/classmerging/VerticalClassMergerTest.java b/src/test/java/com/android/tools/r8/classmerging/VerticalClassMergerTest.java
index fc3f22f..7fab7a1 100644
--- a/src/test/java/com/android/tools/r8/classmerging/VerticalClassMergerTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/VerticalClassMergerTest.java
@@ -509,8 +509,8 @@
                 "    1:1:void <init>():14:14 -> <init>",
                 "    2:2:void <init>():16:16 -> <init>",
                 "classmerging.ProguardFieldMapTest$B -> classmerging.ProguardFieldMapTest$B:",
-                "    1:1:void <init>():19:19 -> <init>",
-                "    1:1:void test():22:22 -> test");
+                "    1:1:void <init>():20:20 -> <init>",
+                "    1:1:void test():23:23 -> test");
     runTestOnInput(
         main,
         readProgramFiles(programFiles),
@@ -536,10 +536,10 @@
                 "classmerging.ProguardFieldMapTest$B -> classmerging.ProguardFieldMapTest$B:",
                 "    java.lang.String classmerging.ProguardFieldMapTest$A.f -> f",
                 "    1:1:void classmerging.ProguardFieldMapTest$A.<init>():14:14 -> <init>",
-                "    1:1:void <init>():19 -> <init>",
+                "    1:1:void <init>():20 -> <init>",
                 "    2:2:void classmerging.ProguardFieldMapTest$A.<init>():16:16 -> <init>",
-                "    2:2:void <init>():19 -> <init>",
-                "    1:1:void test():22:22 -> test");
+                "    2:2:void <init>():20 -> <init>",
+                "    1:1:void test():23:23 -> test");
     Set<String> preservedClassNames =
         ImmutableSet.of("classmerging.ProguardFieldMapTest", "classmerging.ProguardFieldMapTest$B");
     runTestOnInput(
@@ -577,8 +577,8 @@
                 "    1:1:void <init>():14:14 -> <init>",
                 "    1:1:void method():17:17 -> method",
                 "classmerging.ProguardMethodMapTest$B -> classmerging.ProguardMethodMapTest$B:",
-                "    1:1:void <init>():21:21 -> <init>",
-                "    1:2:void method():25:26 -> method");
+                "    1:1:void <init>():22:22 -> <init>",
+                "    1:2:void method():26:27 -> method");
     runTestOnInput(
         main,
         readProgramFiles(programFiles),
@@ -606,8 +606,8 @@
                 // A.<init> has been inlined into B.<init>?
                 "    1:1:void classmerging.ProguardMethodMapTest$A.<init>():14:14 -> <init>",
                 // TODO(christofferqa): Should this be " ...<init>():21:21 -> <init>"?
-                "    1:1:void <init>():21 -> <init>",
-                "    1:2:void method():25:26 -> method",
+                "    1:1:void <init>():22 -> <init>",
+                "    1:2:void method():26:27 -> method",
                 "    1:1:void classmerging.ProguardMethodMapTest$A.method():17:17 -> "
                     + "method$classmerging$ProguardMethodMapTest$A");
     Set<String> preservedClassNames =
@@ -647,10 +647,10 @@
                 "classmerging.ProguardMethodMapTest$A -> classmerging.ProguardMethodMapTest$A:",
                 "    1:1:void <init>():14:14 -> <init>",
                 "classmerging.ProguardMethodMapTest$B -> classmerging.ProguardMethodMapTest$B:",
-                "    1:1:void <init>():21:21 -> <init>",
-                "    1:1:void method():25:25 -> method",
+                "    1:1:void <init>():22:22 -> <init>",
+                "    1:1:void method():26:26 -> method",
                 "    2:2:void classmerging.ProguardMethodMapTest$A.method():17:17 -> method",
-                "    2:2:void method():26 -> method");
+                "    2:2:void method():27 -> method");
     runTestOnInput(
         main,
         readProgramFiles(programFiles),
@@ -677,10 +677,10 @@
                 "    1:2:void main(java.lang.String[]):10:11 -> main",
                 "classmerging.ProguardMethodMapTest$B -> classmerging.ProguardMethodMapTest$B:",
                 "    1:1:void classmerging.ProguardMethodMapTest$A.<init>():14:14 -> <init>",
-                "    1:1:void <init>():21 -> <init>",
-                "    1:1:void method():25:25 -> method",
+                "    1:1:void <init>():22 -> <init>",
+                "    1:1:void method():26:26 -> method",
                 "    2:2:void classmerging.ProguardMethodMapTest$A.method():17:17 -> method",
-                "    2:2:void method():26 -> method");
+                "    2:2:void method():27 -> method");
     Set<String> preservedClassNames =
         ImmutableSet.of(
             "classmerging.ProguardMethodMapTest", "classmerging.ProguardMethodMapTest$B");
diff --git a/src/test/java/com/android/tools/r8/debug/R8DebugNonMinifiedProgramTestRunner.java b/src/test/java/com/android/tools/r8/debug/R8DebugNonMinifiedProgramTestRunner.java
index ecfc8c1..3f61638 100644
--- a/src/test/java/com/android/tools/r8/debug/R8DebugNonMinifiedProgramTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debug/R8DebugNonMinifiedProgramTestRunner.java
@@ -54,17 +54,19 @@
 
   private static R8TestCompileResult compile(R8FullTestBuilder builder, AndroidApiLevel apiLevel)
       throws Exception {
-    return builder.enableInliningAnnotations()
-        .enableClassInliningAnnotations()
+    return builder
+        .enableInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .addProgramClassesAndInnerClasses(CLASS)
         .addKeepMainRule(CLASS)
         .setMinApi(apiLevel)
         .compile()
-        .inspect(inspector -> {
-          // Check that tree shaking is running (e.g., B is removed).
-          assertTrue(inspector.clazz(R8DebugNonMinifiedProgramTest.A.class).isPresent());
-          assertFalse(inspector.clazz(R8DebugNonMinifiedProgramTest.B.class).isPresent());
-        });
+        .inspect(
+            inspector -> {
+              // Check that tree shaking is running (e.g., B is removed).
+              assertTrue(inspector.clazz(R8DebugNonMinifiedProgramTest.A.class).isPresent());
+              assertFalse(inspector.clazz(R8DebugNonMinifiedProgramTest.B.class).isPresent());
+            });
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTestRunner.java b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTestRunner.java
index b89f09a..c04e3eb 100644
--- a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTestRunner.java
+++ b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTestRunner.java
@@ -8,7 +8,6 @@
 
 import com.android.tools.r8.D8TestCompileResult;
 import com.android.tools.r8.R8TestCompileResult;
-import com.android.tools.r8.TestBase;
 import com.android.tools.r8.debug.DebugTestBase;
 import com.android.tools.r8.debug.DebugTestBase.JUnit3Wrapper.Command;
 import com.android.tools.r8.debug.DebugTestConfig;
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ByteBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/ByteBackportJava9Test.java
index 28eefe3..37aa606 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/ByteBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ByteBackportJava9Test.java
@@ -31,6 +31,7 @@
 
   public ByteBackportJava9Test(TestParameters parameters) {
     super(parameters, Byte.class, TEST_JAR, "backport.ByteBackportJava9Main");
-    // TODO Once shipped in an actual API level, migrate to ByteBackportTest
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to ByteBackportTest.
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/CharacterBackportJava11Test.java b/src/test/java/com/android/tools/r8/desugar/backports/CharacterBackportJava11Test.java
index f1d51fc..9a03c16 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/CharacterBackportJava11Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/CharacterBackportJava11Test.java
@@ -30,7 +30,8 @@
       Paths.get(ToolHelper.EXAMPLES_JAVA11_JAR_DIR).resolve("backport" + JAR_EXTENSION);
 
   public CharacterBackportJava11Test(TestParameters parameters) {
-    super(parameters, Short.class, TEST_JAR, "backport.CharacterBackportJava11Main");
-    // TODO Once shipped in an actual API level, migrate to CharacterBackportTest
+    super(parameters, Character.class, TEST_JAR, "backport.CharacterBackportJava11Main");
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to CharacterBackportTest.
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava10Test.java
new file mode 100644
index 0000000..309b319
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava10Test.java
@@ -0,0 +1,44 @@
+// 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.backports;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public class ListBackportJava10Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return getTestParameters()
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK10)
+        .withDexRuntimes()
+        .withAllApiLevels()
+        .build();
+  }
+
+  private static final Path TEST_JAR =
+      Paths.get(ToolHelper.EXAMPLES_JAVA10_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+  public ListBackportJava10Test(TestParameters parameters) {
+    super(parameters, List.class, TEST_JAR, "backport.ListBackportJava10Main");
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to ListBackportTest.
+
+    // Available since API 1 and used to test created lists.
+    ignoreInvokes("add");
+    ignoreInvokes("get");
+    ignoreInvokes("set");
+    ignoreInvokes("size");
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava9Test.java
index a861d1f..03843cc0 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava9Test.java
@@ -32,7 +32,8 @@
 
   public ListBackportJava9Test(TestParameters parameters) {
     super(parameters, List.class, TEST_JAR, "backport.ListBackportJava9Main");
-    // TODO Once shipped in an actual API level, migrate to ListBackportTest
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to ListBackportTest.
 
     // Available since API 1 and used to test created lists.
     ignoreInvokes("add");
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava10Test.java
new file mode 100644
index 0000000..e54d7d8
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava10Test.java
@@ -0,0 +1,44 @@
+// 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.backports;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Map;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public class MapBackportJava10Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return getTestParameters()
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK10)
+        .withDexRuntimes()
+        .withAllApiLevels()
+        .build();
+  }
+
+  private static final Path TEST_JAR =
+      Paths.get(ToolHelper.EXAMPLES_JAVA10_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+  public MapBackportJava10Test(TestParameters parameters) {
+    super(parameters, Map.class, TEST_JAR, "backport.MapBackportJava10Main");
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to MapBackportTest.
+
+    // Available since API 1 and used to test created maps.
+    ignoreInvokes("entrySet");
+    ignoreInvokes("get");
+    ignoreInvokes("put");
+    ignoreInvokes("size");
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava9Test.java
index 06e41f8..fb39b49 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/MapBackportJava9Test.java
@@ -32,7 +32,8 @@
 
   public MapBackportJava9Test(TestParameters parameters) {
     super(parameters, Map.class, TEST_JAR, "backport.MapBackportJava9Main");
-    // TODO Once shipped in an actual API level, migrate to MapBackportTest
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to MapBackportTest.
 
     // Available since API 1 and used to test created maps.
     ignoreInvokes("entrySet");
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/MathBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/MathBackportJava9Test.java
index 439ef38..387697e 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/MathBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/MathBackportJava9Test.java
@@ -31,6 +31,7 @@
 
   public MathBackportJava9Test(TestParameters parameters) {
     super(parameters, Math.class, TEST_JAR, "backport.MathBackportJava9Main");
-    // TODO Once shipped in an actual API level, migrate to MathBackportTest
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to MathBackportTest.
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ObjectsBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/ObjectsBackportJava9Test.java
index 7544e87..ef8b990 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/ObjectsBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ObjectsBackportJava9Test.java
@@ -31,6 +31,7 @@
 
   public ObjectsBackportJava9Test(TestParameters parameters) {
     super(parameters, Short.class, TEST_JAR, "backport.ObjectsBackportJava9Main");
-    // TODO Once shipped in an actual API level, migrate to ObjectsBackportTest
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to ObjectsBackportTest.
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava10Test.java
new file mode 100644
index 0000000..25d4081
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava10Test.java
@@ -0,0 +1,45 @@
+// 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.backports;
+
+import com.android.tools.r8.TestParameters;
+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 java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Optional;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public final class OptionalBackportJava10Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return getTestParameters()
+        .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+        .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK10)
+        .build();
+  }
+
+  private static final Path TEST_JAR =
+      Paths.get(ToolHelper.EXAMPLES_JAVA10_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+  public OptionalBackportJava10Test(TestParameters parameters) {
+    super(parameters, Optional.class, TEST_JAR, "backport.OptionalBackportJava10Main");
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to OptionalBackportTest.
+
+    // Available since N as part of library desugaring.
+    ignoreInvokes("empty");
+    ignoreInvokes("get");
+    ignoreInvokes("of");
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava11Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava11Test.java
new file mode 100644
index 0000000..dee14c1
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava11Test.java
@@ -0,0 +1,44 @@
+// 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.backports;
+
+import com.android.tools.r8.TestParameters;
+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 java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Optional;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public final class OptionalBackportJava11Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return getTestParameters()
+        .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+        .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK11)
+        .build();
+  }
+
+  private static final Path TEST_JAR =
+      Paths.get(ToolHelper.EXAMPLES_JAVA11_JAR_DIR).resolve("backport" + JAR_EXTENSION);
+
+  public OptionalBackportJava11Test(TestParameters parameters) {
+    super(parameters, Optional.class, TEST_JAR, "backport.OptionalBackportJava11Main");
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to OptionalBackportTest.
+
+    // Available since N as part of library desugaring.
+    ignoreInvokes("empty");
+    ignoreInvokes("of");
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava9Test.java
index d77052a..31bc82f 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalBackportJava9Test.java
@@ -13,6 +13,7 @@
 import com.android.tools.r8.utils.AndroidApiLevel;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.Optional;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 import org.junit.runners.Parameterized.Parameters;
@@ -32,6 +33,12 @@
       Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
 
   public OptionalBackportJava9Test(TestParameters parameters) {
-    super(parameters, Short.class, TEST_JAR, "backport.OptionalBackportJava9Main");
+    super(parameters, Optional.class, TEST_JAR, "backport.OptionalBackportJava9Main");
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to OptionalBackportTest.
+
+    // Available since N as part of library desugaring.
+    ignoreInvokes("empty");
+    ignoreInvokes("of");
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava10Test.java
new file mode 100644
index 0000000..97d70df
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava10Test.java
@@ -0,0 +1,46 @@
+// 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.backports;
+
+import com.android.tools.r8.TestParameters;
+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 java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Optional;
+import java.util.OptionalDouble;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public final class OptionalDoubleBackportJava10Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return getTestParameters()
+        .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+        .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK10)
+        .build();
+  }
+
+  private static final Path TEST_JAR =
+      Paths.get(ToolHelper.EXAMPLES_JAVA10_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+  public OptionalDoubleBackportJava10Test(TestParameters parameters) {
+    super(parameters, OptionalDouble.class, TEST_JAR, "backport.OptionalDoubleBackportJava10Main");
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to OptionalBackportTest.
+
+    // Available since N as part of library desugaring.
+    ignoreInvokes("empty");
+    ignoreInvokes("getAsDouble");
+    ignoreInvokes("of");
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava11Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava11Test.java
new file mode 100644
index 0000000..981e1e2
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava11Test.java
@@ -0,0 +1,44 @@
+// 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.backports;
+
+import com.android.tools.r8.TestParameters;
+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 java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.OptionalDouble;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public final class OptionalDoubleBackportJava11Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return getTestParameters()
+        .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+        .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK11)
+        .build();
+  }
+
+  private static final Path TEST_JAR =
+      Paths.get(ToolHelper.EXAMPLES_JAVA11_JAR_DIR).resolve("backport" + JAR_EXTENSION);
+
+  public OptionalDoubleBackportJava11Test(TestParameters parameters) {
+    super(parameters, OptionalDouble.class, TEST_JAR, "backport.OptionalDoubleBackportJava11Main");
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to OptionalBackportTest.
+
+    // Available since N as part of library desugaring.
+    ignoreInvokes("empty");
+    ignoreInvokes("of");
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava9Test.java
new file mode 100644
index 0000000..5aa0e1c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalDoubleBackportJava9Test.java
@@ -0,0 +1,45 @@
+// 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.backports;
+
+import com.android.tools.r8.TestParameters;
+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 java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Optional;
+import java.util.OptionalDouble;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public final class OptionalDoubleBackportJava9Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return getTestParameters()
+        .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+        .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK9)
+        .build();
+  }
+
+  private static final Path TEST_JAR =
+      Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+  public OptionalDoubleBackportJava9Test(TestParameters parameters) {
+    super(parameters, OptionalDouble.class, TEST_JAR, "backport.OptionalDoubleBackportJava9Main");
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to OptionalDoubleBackportTest.
+
+    // Available since N as part of library desugaring.
+    ignoreInvokes("empty");
+    ignoreInvokes("of");
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava10Test.java
new file mode 100644
index 0000000..b44f1cf
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava10Test.java
@@ -0,0 +1,46 @@
+// 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.backports;
+
+import com.android.tools.r8.TestParameters;
+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 java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.OptionalInt;
+import java.util.OptionalLong;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public final class OptionalIntBackportJava10Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return getTestParameters()
+        .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+        .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK10)
+        .build();
+  }
+
+  private static final Path TEST_JAR =
+      Paths.get(ToolHelper.EXAMPLES_JAVA10_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+  public OptionalIntBackportJava10Test(TestParameters parameters) {
+    super(parameters, OptionalInt.class, TEST_JAR, "backport.OptionalIntBackportJava10Main");
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to OptionalBackportTest.
+
+    // Available since N as part of library desugaring.
+    ignoreInvokes("empty");
+    ignoreInvokes("getAsInt");
+    ignoreInvokes("of");
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava11Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava11Test.java
new file mode 100644
index 0000000..e594db3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava11Test.java
@@ -0,0 +1,44 @@
+// 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.backports;
+
+import com.android.tools.r8.TestParameters;
+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 java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.OptionalInt;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public final class OptionalIntBackportJava11Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return getTestParameters()
+        .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+        .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK11)
+        .build();
+  }
+
+  private static final Path TEST_JAR =
+      Paths.get(ToolHelper.EXAMPLES_JAVA11_JAR_DIR).resolve("backport" + JAR_EXTENSION);
+
+  public OptionalIntBackportJava11Test(TestParameters parameters) {
+    super(parameters, OptionalInt.class, TEST_JAR, "backport.OptionalIntBackportJava11Main");
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to OptionalBackportTest.
+
+    // Available since N as part of library desugaring.
+    ignoreInvokes("empty");
+    ignoreInvokes("of");
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava9Test.java
new file mode 100644
index 0000000..71a8dd9
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalIntBackportJava9Test.java
@@ -0,0 +1,44 @@
+// 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.backports;
+
+import com.android.tools.r8.TestParameters;
+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 java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.OptionalInt;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public final class OptionalIntBackportJava9Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return getTestParameters()
+        .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+        .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK9)
+        .build();
+  }
+
+  private static final Path TEST_JAR =
+      Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+  public OptionalIntBackportJava9Test(TestParameters parameters) {
+    super(parameters, OptionalInt.class, TEST_JAR, "backport.OptionalIntBackportJava9Main");
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to OptionalIntBackportTest.
+
+    // Available since N as part of library desugaring.
+    ignoreInvokes("empty");
+    ignoreInvokes("of");
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava10Test.java
new file mode 100644
index 0000000..a4bef8c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava10Test.java
@@ -0,0 +1,45 @@
+// 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.backports;
+
+import com.android.tools.r8.TestParameters;
+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 java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.OptionalLong;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public final class OptionalLongBackportJava10Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return getTestParameters()
+        .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+        .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK10)
+        .build();
+  }
+
+  private static final Path TEST_JAR =
+      Paths.get(ToolHelper.EXAMPLES_JAVA10_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+  public OptionalLongBackportJava10Test(TestParameters parameters) {
+    super(parameters, OptionalLong.class, TEST_JAR, "backport.OptionalLongBackportJava10Main");
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to OptionalBackportTest.
+
+    // Available since N as part of library desugaring.
+    ignoreInvokes("empty");
+    ignoreInvokes("getAsLong");
+    ignoreInvokes("of");
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava11Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava11Test.java
new file mode 100644
index 0000000..bc1f4aa
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava11Test.java
@@ -0,0 +1,44 @@
+// 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.backports;
+
+import com.android.tools.r8.TestParameters;
+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 java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.OptionalLong;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public final class OptionalLongBackportJava11Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return getTestParameters()
+        .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+        .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK11)
+        .build();
+  }
+
+  private static final Path TEST_JAR =
+      Paths.get(ToolHelper.EXAMPLES_JAVA11_JAR_DIR).resolve("backport" + JAR_EXTENSION);
+
+  public OptionalLongBackportJava11Test(TestParameters parameters) {
+    super(parameters, OptionalLong.class, TEST_JAR, "backport.OptionalLongBackportJava11Main");
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to OptionalBackportTest.
+
+    // Available since N as part of library desugaring.
+    ignoreInvokes("empty");
+    ignoreInvokes("of");
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava9Test.java
new file mode 100644
index 0000000..b0dfd62
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/OptionalLongBackportJava9Test.java
@@ -0,0 +1,46 @@
+// 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.backports;
+
+import com.android.tools.r8.TestParameters;
+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 java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.OptionalLong;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public final class OptionalLongBackportJava9Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return getTestParameters()
+        .withDexRuntimesStartingFromIncluding(Version.V7_0_0)
+        .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK9)
+        .build();
+  }
+
+  private static final Path TEST_JAR =
+      Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+  public OptionalLongBackportJava9Test(TestParameters parameters) {
+    super(parameters, OptionalLong.class, TEST_JAR, "backport.OptionalLongBackportJava9Main");
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to OptionalLongBackportTest.
+
+    // Available since N as part of library desugaring.
+    ignoreInvokes("empty");
+    ignoreInvokes("getAsLong");
+    ignoreInvokes("isPresent");
+    ignoreInvokes("of");
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava10Test.java b/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava10Test.java
new file mode 100644
index 0000000..5c08b8f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava10Test.java
@@ -0,0 +1,43 @@
+// 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.backports;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Set;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public class SetBackportJava10Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return getTestParameters()
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK10)
+        .withDexRuntimes()
+        .withAllApiLevels()
+        .build();
+  }
+
+  private static final Path TEST_JAR =
+      Paths.get(ToolHelper.EXAMPLES_JAVA10_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+  public SetBackportJava10Test(TestParameters parameters) {
+    super(parameters, Set.class, TEST_JAR, "backport.SetBackportJava10Main");
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to SetBackportTest.
+
+    // Available since API 1 and used to test created sets.
+    ignoreInvokes("add");
+    ignoreInvokes("contains");
+    ignoreInvokes("size");
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava9Test.java
index b248e0b..6947ff2 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava9Test.java
@@ -32,7 +32,8 @@
 
   public SetBackportJava9Test(TestParameters parameters) {
     super(parameters, Set.class, TEST_JAR, "backport.SetBackportJava9Main");
-    // TODO Once shipped in an actual API level, migrate to SetBackportTest
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to SetBackportTest.
 
     // Available since API 1 and used to test created sets.
     ignoreInvokes("add");
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ShortBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/ShortBackportJava9Test.java
index d56ef5b..beffd8a 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/ShortBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ShortBackportJava9Test.java
@@ -31,6 +31,7 @@
 
   public ShortBackportJava9Test(TestParameters parameters) {
     super(parameters, Short.class, TEST_JAR, "backport.ShortBackportJava9Main");
-    // TODO Once shipped in an actual API level, migrate to ShortBackportTest
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to ShortBackportTest.
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/StreamBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/StreamBackportJava9Test.java
index 0f08ff9..073c179 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/StreamBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/StreamBackportJava9Test.java
@@ -34,6 +34,9 @@
 
   public StreamBackportJava9Test(TestParameters parameters) {
     super(parameters, Stream.class, TEST_JAR, "backport.StreamBackportJava9Main");
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to StreamBackportTest.
+
     // Available since N as part of library desugaring.
     ignoreInvokes("of");
     ignoreInvokes("empty");
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/StrictMathBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/StrictMathBackportJava9Test.java
index 43cbf48..2f124e7 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/StrictMathBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/StrictMathBackportJava9Test.java
@@ -31,6 +31,7 @@
 
   public StrictMathBackportJava9Test(TestParameters parameters) {
     super(parameters, Math.class, TEST_JAR, "backport.StrictMathBackportJava9Main");
-    // TODO Once shipped in an actual API level, migrate to MathBackportTest
+    // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
+    // an actual API level, migrate these tests to StrictMathBackportTest.
   }
 }
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 d00811f..4a92fd8 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
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.desugar.desugaredlibrary;
 
+import static org.junit.Assume.assumeTrue;
+
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
@@ -70,6 +72,28 @@
         .assertSuccessWithOutput(EXPECTED_OUTPUT);
   }
 
+  @Test
+  public void testCustomCollectionR8() throws Exception {
+    // Desugared library tests do not make sense in the Cf to Cf, and the JVM is already tested
+    // in the D8 test. Just return.
+    assumeTrue(parameters.isDexRuntime());
+    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
+    testForR8(parameters.getBackend())
+        .addInnerClasses(CustomCollectionInterfaceSuperTest.class)
+        .addKeepMainRule(Main.class)
+        .setMinApi(parameters.getApiLevel())
+        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+        .compile()
+        .assertNoMessages()
+        .addDesugaredCoreLibraryRunClassPath(
+            this::buildDesugaredLibrary,
+            parameters.getApiLevel(),
+            keepRuleConsumer.get(),
+            shrinkDesugaredLibrary)
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
+  }
+
   static class Main {
 
     @SuppressWarnings({
@@ -89,7 +113,7 @@
     }
   }
 
-  interface MyCol1<E> extends Collection<E> {
+  interface Col1Itf<E> extends Collection<E> {
 
     @Override
     default boolean removeIf(Predicate<? super E> filter) {
@@ -98,12 +122,12 @@
     }
   }
 
-  interface MyCol2<E> extends MyCol1<E> {
+  interface Col2Itf<E> extends Col1Itf<E> {
 
     @Override
     default boolean removeIf(Predicate<? super E> filter) {
       System.out.println("removeIf from MyCol2");
-      return MyCol1.super.removeIf(filter);
+      return Col1Itf.super.removeIf(filter);
     }
   }
 
@@ -180,10 +204,10 @@
     public void clear() {}
   }
 
-  static class Col1<E> implements MyCol1<E> {
+  static class Col1<E> implements Col1Itf<E> {
 
     public boolean superRemoveIf(Predicate<? super E> filter) {
-      return MyCol1.super.removeIf(filter);
+      return Col1Itf.super.removeIf(filter);
     }
 
     @Override
@@ -253,10 +277,10 @@
     public void clear() {}
   }
 
-  static class Col2<E> implements MyCol2<E> {
+  static class Col2<E> implements Col2Itf<E> {
 
     public boolean superRemoveIf(Predicate<? super E> filter) {
-      return MyCol2.super.removeIf(filter);
+      return Col2Itf.super.removeIf(filter);
     }
 
     @Override
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
new file mode 100644
index 0000000..616ec2c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MinimalInterfaceSuperTest.java
@@ -0,0 +1,85 @@
+// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.desugar.desugaredlibrary;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.StringUtils;
+import java.util.AbstractCollection;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.function.Predicate;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@SuppressWarnings("ALL")
+@RunWith(Parameterized.class)
+public class MinimalInterfaceSuperTest extends DesugaredLibraryTestBase {
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimes().withAllApiLevels().build();
+  }
+
+  public MinimalInterfaceSuperTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  private static final String EXPECTED_OUTPUT = StringUtils.lines("removeIf from Col1Itf");
+
+  @Test
+  public void testCustomCollectionR8() throws Exception {
+    if (parameters.isCfRuntime()) {
+      testForJvm()
+          .addInnerClasses(MinimalInterfaceSuperTest.class)
+          .run(parameters.getRuntime(), Main.class)
+          .assertSuccessWithOutput(EXPECTED_OUTPUT);
+      return;
+    }
+    testForR8(parameters.getBackend())
+        .addInnerClasses(MinimalInterfaceSuperTest.class)
+        .addKeepMainRule(Main.class)
+        .setMinApi(parameters.getApiLevel())
+        .enableCoreLibraryDesugaring(parameters.getApiLevel())
+        .compile()
+        .assertNoMessages()
+        .addDesugaredCoreLibraryRunClassPath(this::buildDesugaredLibrary, parameters.getApiLevel())
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
+  }
+
+  static class Main {
+    public static void main(String[] args) {
+      Col1<Integer> ints1 = new Col1<>();
+      ints1.removeIf(x -> x == 3);
+    }
+  }
+
+  interface Col1Itf<E> extends Collection<E> {
+    @Override
+    default boolean removeIf(Predicate<? super E> filter) {
+      System.out.println("removeIf from Col1Itf");
+      return Collection.super.removeIf(filter);
+    }
+  }
+
+  static class Col1<E> extends AbstractCollection<E> implements Col1Itf<E> {
+    @NotNull
+    @Override
+    public Iterator<E> iterator() {
+      return Collections.emptyIterator();
+    }
+
+    @Override
+    public int size() {
+      return 0;
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InvokeSuperInDefaultInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InvokeSuperInDefaultInterfaceMethodTest.java
index 3693f87..adaa55f 100644
--- a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InvokeSuperInDefaultInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InvokeSuperInDefaultInterfaceMethodTest.java
@@ -22,7 +22,7 @@
     testForR8(Backend.DEX)
         .addInnerClasses(InvokeSuperInDefaultInterfaceMethodTest.class)
         .addKeepMainRule(TestClass.class)
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableMergeAnnotations()
         .setMinApi(AndroidApiLevel.M)
         .run(TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/graph/initializedclasses/InitializedClassesInInstanceMethodsTest.java b/src/test/java/com/android/tools/r8/graph/initializedclasses/InitializedClassesInInstanceMethodsTest.java
index 0e19132..43015bf 100644
--- a/src/test/java/com/android/tools/r8/graph/initializedclasses/InitializedClassesInInstanceMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/graph/initializedclasses/InitializedClassesInInstanceMethodsTest.java
@@ -51,7 +51,7 @@
                   enableInitializedClassesInInstanceMethodsAnalysis;
             })
         .allowAccessModification()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .setMinApi(parameters.getRuntime())
         .compile()
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/backports/CollectionsMethods.java b/src/test/java/com/android/tools/r8/ir/desugar/backports/CollectionsMethods.java
index dd300da..eac9b74 100644
--- a/src/test/java/com/android/tools/r8/ir/desugar/backports/CollectionsMethods.java
+++ b/src/test/java/com/android/tools/r8/ir/desugar/backports/CollectionsMethods.java
@@ -4,10 +4,18 @@
 
 package com.android.tools.r8.ir.desugar.backports;
 
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
 import java.util.ListIterator;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
 
 public final class CollectionsMethods {
 
@@ -22,4 +30,30 @@
   public static <T> ListIterator<T> emptyListIterator() {
     return Collections.<T>emptyList().listIterator();
   }
+
+  public static <T> List<T> copyOfList(Collection<? extends T> other) {
+    ArrayList<T> list = new ArrayList<>(other.size());
+    for (T item : other) {
+      list.add(Objects.requireNonNull(item));
+    }
+    return Collections.unmodifiableList(list);
+  }
+
+  public static <T> Set<T> copyOfSet(Collection<? extends T> other) {
+    HashSet<T> set = new HashSet<>(other.size());
+    for (T item : other) {
+      set.add(Objects.requireNonNull(item));
+    }
+    return Collections.unmodifiableSet(set);
+  }
+
+  public static <K, V> Map<K, V> copyOfMap(Map<? extends K, ? extends V> other) {
+    HashMap<K, V> map = new HashMap<>(other.size());
+    for (Map.Entry<? extends K, ? extends V> entry : other.entrySet()) {
+      map.put(
+          Objects.requireNonNull(entry.getKey()),
+          Objects.requireNonNull(entry.getValue()));
+    }
+    return Collections.unmodifiableMap(map);
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/backports/MathMethods.java b/src/test/java/com/android/tools/r8/ir/desugar/backports/MathMethods.java
index 2f112ab..a41259d 100644
--- a/src/test/java/com/android/tools/r8/ir/desugar/backports/MathMethods.java
+++ b/src/test/java/com/android/tools/r8/ir/desugar/backports/MathMethods.java
@@ -154,6 +154,33 @@
     return Math.multiplyExact(x, (long) y);
   }
 
+  public static long multiplyFull(int x, int y) {
+    return (long) x * y;
+  }
+
+  public static long multiplyHigh(long x, long y) {
+    // Adapted from Hacker's Delight (2nd ed), 8-2.
+    long xLow = x & 0xFFFFFFFFL;
+    long xHigh = x >> 32;
+    long yLow = y & 0xFFFFFFFFL;
+    long yHigh = y >> 32;
+
+    long lowLow = xLow * yLow;
+    long lowLowCarry = lowLow >>> 32;
+
+    long highLow = xHigh * yLow;
+    long mid1 = highLow + lowLowCarry;
+    long mid1Low = mid1 & 0xFFFFFFFFL;
+    long mid1High = mid1 >> 32;
+
+    long lowHigh = xLow * yHigh;
+    long mid2 = lowHigh + mid1Low;
+    long mid2High = mid2 >> 32;
+
+    long highHigh = xHigh * yHigh;
+    return highHigh + mid1High + mid2High;
+  }
+
   public static int negateExactInt(int value) {
     if (value == Integer.MIN_VALUE) {
       throw new ArithmeticException();
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/backports/OptionalMethods.java b/src/test/java/com/android/tools/r8/ir/desugar/backports/OptionalMethods.java
index 43c749a..6fb1a83 100644
--- a/src/test/java/com/android/tools/r8/ir/desugar/backports/OptionalMethods.java
+++ b/src/test/java/com/android/tools/r8/ir/desugar/backports/OptionalMethods.java
@@ -14,6 +14,9 @@
 import java.util.function.IntConsumer;
 import java.util.function.LongConsumer;
 import java.util.function.Supplier;
+import java.util.stream.DoubleStream;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
 import java.util.stream.Stream;
 
 public class OptionalMethods {
@@ -73,4 +76,44 @@
       return Stream.empty();
     }
   }
+
+  public static IntStream streamInt(OptionalInt receiver) {
+    if (receiver.isPresent()) {
+      return IntStream.of(receiver.getAsInt());
+    } else {
+      return IntStream.empty();
+    }
+  }
+
+  public static LongStream streamLong(OptionalLong receiver) {
+    if (receiver.isPresent()) {
+      return LongStream.of(receiver.getAsLong());
+    } else {
+      return LongStream.empty();
+    }
+  }
+
+  public static DoubleStream streamDouble(OptionalDouble receiver) {
+    if (receiver.isPresent()) {
+      return DoubleStream.of(receiver.getAsDouble());
+    } else {
+      return DoubleStream.empty();
+    }
+  }
+
+  public static boolean isEmpty(Optional<?> receiver) {
+    return !receiver.isPresent();
+  }
+
+  public static boolean isEmptyInt(OptionalInt receiver) {
+    return !receiver.isPresent();
+  }
+
+  public static boolean isEmptyLong(OptionalLong receiver) {
+    return !receiver.isPresent();
+  }
+
+  public static boolean isEmptyDouble(OptionalDouble receiver) {
+    return !receiver.isPresent();
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/DefaultInterfaceIssue143628636Test.java b/src/test/java/com/android/tools/r8/ir/optimize/DefaultInterfaceIssue143628636Test.java
index 945e1af..94de4ba 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/DefaultInterfaceIssue143628636Test.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/DefaultInterfaceIssue143628636Test.java
@@ -42,7 +42,7 @@
   public void test() throws Exception {
     testForR8(parameters.getBackend())
         .enableInliningAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableMergeAnnotations()
         .addInnerClasses(DefaultInterfaceIssue143628636Test.class)
         .addKeepMainRule(TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java b/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java
index 07106f3..e01ede5 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java
@@ -7,7 +7,6 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 
-import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.R8TestBuilder;
 import com.android.tools.r8.TestBase;
@@ -24,6 +23,7 @@
 import com.android.tools.r8.ir.optimize.nonnull.NonNullParamInterface;
 import com.android.tools.r8.ir.optimize.nonnull.NonNullParamInterfaceImpl;
 import com.android.tools.r8.ir.optimize.nonnull.NotPinnedClass;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -43,7 +43,7 @@
 
   @Parameterized.Parameters(name = "{0}")
   public static TestParametersCollection data() {
-    return getTestParameters().withAllRuntimes().build();
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   public NonNullParamTest(TestParameters parameters) {
@@ -54,7 +54,7 @@
     options.enableDevirtualization = false;
   }
 
-  CodeInspector buildAndRun(
+  private CodeInspector buildAndRun(
       Class<?> mainClass,
       Collection<Class<?>> classes,
       ThrowableConsumer<R8FullTestBuilder> configuration)
@@ -65,6 +65,7 @@
         .addProgramClasses(classes)
         .addKeepMainRule(mainClass)
         .addKeepRules(ImmutableList.of("-keepattributes InnerClasses,Signature,EnclosingMethod"))
+        .addTestingAnnotationsAsProgramClasses()
         // All tests are checking if invocations to certain null-check utils are gone.
         .noMinification()
         .addOptionsModification(
@@ -73,7 +74,7 @@
               options.inliningInstructionLimit = 4;
             })
         .apply(configuration)
-        .setMinApi(parameters.getRuntime())
+        .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), mainClass)
         .assertSuccessWithOutput(javaOutput)
         .inspector();
@@ -84,9 +85,7 @@
     Class<?> mainClass = IntrinsicsDeputy.class;
     CodeInspector inspector =
         buildAndRun(
-            mainClass,
-            ImmutableList.of(NeverInline.class, mainClass),
-            R8TestBuilder::enableInliningAnnotations);
+            mainClass, ImmutableList.of(mainClass), R8TestBuilder::enableInliningAnnotations);
 
     ClassSubject mainSubject = inspector.clazz(mainClass);
     assertThat(mainSubject, isPresent());
@@ -120,8 +119,7 @@
     CodeInspector inspector =
         buildAndRun(
             mainClass,
-            ImmutableList.of(
-                NeverInline.class, IntrinsicsDeputy.class, NotPinnedClass.class, mainClass),
+            ImmutableList.of(IntrinsicsDeputy.class, NotPinnedClass.class, mainClass),
             R8TestBuilder::enableInliningAnnotations);
 
     ClassSubject mainSubject = inspector.clazz(mainClass);
@@ -149,8 +147,7 @@
     CodeInspector inspector =
         buildAndRun(
             mainClass,
-            ImmutableList.of(
-                NeverInline.class, IntrinsicsDeputy.class, NotPinnedClass.class, mainClass),
+            ImmutableList.of(IntrinsicsDeputy.class, NotPinnedClass.class, mainClass),
             R8TestBuilder::enableInliningAnnotations);
 
     ClassSubject mainSubject = inspector.clazz(mainClass);
@@ -179,12 +176,11 @@
         buildAndRun(
             mainClass,
             ImmutableList.of(
-                NeverInline.class,
                 IntrinsicsDeputy.class,
                 NonNullParamAfterInvokeVirtual.class,
                 NotPinnedClass.class,
                 mainClass),
-            R8TestBuilder::enableInliningAnnotations);
+            builder -> builder.enableNeverClassInliningAnnotations().enableInliningAnnotations());
 
     ClassSubject mainSubject = inspector.clazz(NonNullParamAfterInvokeVirtual.class);
     assertThat(mainSubject, isPresent());
@@ -192,7 +188,12 @@
     MethodSubject checkViaCall = mainSubject.uniqueMethodWithName("checkViaCall");
     assertThat(checkViaCall, isPresent());
     assertEquals(0, countActCall(checkViaCall));
-    assertEquals(2, countPrintCall(checkViaCall));
+    // With API level >= Q we get a register assignment that allows us to share the print call in a
+    // successor block. See also InternalOptions.canHaveThisJitCodeDebuggingBug().
+    boolean canSharePrintCallInSuccessorBlock =
+        parameters.isDexRuntime()
+            && parameters.getApiLevel().getLevel() >= AndroidApiLevel.Q.getLevel();
+    assertEquals(canSharePrintCallInSuccessorBlock ? 1 : 2, countPrintCall(checkViaCall));
 
     MethodSubject checkViaIntrinsic = mainSubject.uniqueMethodWithName("checkViaIntrinsic");
     assertThat(checkViaIntrinsic, isPresent());
@@ -212,7 +213,6 @@
         buildAndRun(
             mainClass,
             ImmutableList.of(
-                NeverInline.class,
                 IntrinsicsDeputy.class,
                 NonNullParamInterface.class,
                 NonNullParamInterfaceImpl.class,
@@ -223,7 +223,7 @@
                 builder
                     .addOptionsModification(this::disableDevirtualization)
                     .enableInliningAnnotations()
-                    .enableClassInliningAnnotations()
+                    .enableNeverClassInliningAnnotations()
                     .enableMergeAnnotations());
 
     ClassSubject mainSubject = inspector.clazz(NonNullParamAfterInvokeInterface.class);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeInterfaceWithRefinedReceiverTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeInterfaceWithRefinedReceiverTest.java
index b804cbe..4890c6a 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeInterfaceWithRefinedReceiverTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeInterfaceWithRefinedReceiverTest.java
@@ -45,13 +45,15 @@
         .addInnerClasses(InvokeInterfaceWithRefinedReceiverTest.class)
         .addKeepMainRule(MAIN)
         .enableMergeAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
-        .addOptionsModification(o -> {
-          // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single target.
-          o.enableDevirtualization = false;
-          o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-        })
+        .addOptionsModification(
+            o -> {
+              // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single
+              // target.
+              o.enableDevirtualization = false;
+              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+            })
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("null", "C")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeVirtualWithRefinedReceiverTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeVirtualWithRefinedReceiverTest.java
index c69f0c1..a0a436d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeVirtualWithRefinedReceiverTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeVirtualWithRefinedReceiverTest.java
@@ -45,11 +45,12 @@
         .addInnerClasses(InvokeVirtualWithRefinedReceiverTest.class)
         .addKeepMainRule(MAIN)
         .enableMergeAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
-        .addOptionsModification(o -> {
-          o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-        })
+        .addOptionsModification(
+            o -> {
+              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+            })
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("null", "C")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/KeptMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/KeptMethodTest.java
index 3e87f06..51797eb 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/KeptMethodTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/KeptMethodTest.java
@@ -43,11 +43,12 @@
         .addInnerClasses(KeptMethodTest.class)
         .addKeepMainRule(MAIN)
         .addKeepClassAndMembersRules(A.class)
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
-        .addOptionsModification(o -> {
-          o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-        })
+        .addOptionsModification(
+            o -> {
+              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+            })
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("non-null", "non-null")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/WithStaticizerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/WithStaticizerTest.java
index 9b424d3..c1839b9 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/WithStaticizerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/WithStaticizerTest.java
@@ -43,7 +43,7 @@
         .addInnerClasses(WithStaticizerTest.class)
         .addKeepMainRule(MAIN)
         .enableInliningAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("Input")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectNegativeTest.java
index a0bafae..19a9034 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectNegativeTest.java
@@ -43,11 +43,12 @@
     testForR8(parameters.getBackend())
         .addInnerClasses(InvokeDirectNegativeTest.class)
         .addKeepMainRule(MAIN)
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
-        .addOptionsModification(o -> {
-          o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-        })
+        .addOptionsModification(
+            o -> {
+              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+            })
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("null", "non-null")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectPositiveTest.java
index e4200b8..30aec5e 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectPositiveTest.java
@@ -45,11 +45,12 @@
     testForR8(parameters.getBackend())
         .addInnerClasses(InvokeDirectPositiveTest.class)
         .addKeepMainRule(MAIN)
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
-        .addOptionsModification(o -> {
-          o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-        })
+        .addOptionsModification(
+            o -> {
+              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+            })
         .setMinApi(parameters.getApiLevel())
         .addOptionsModification(InternalOptions::enablePropagationOfConstantsAtCallSites)
         .run(parameters.getRuntime(), MAIN)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfaceNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfaceNegativeTest.java
index 7f9aedb..ba6b644 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfaceNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfaceNegativeTest.java
@@ -45,13 +45,15 @@
         .addInnerClasses(InvokeInterfaceNegativeTest.class)
         .addKeepMainRule(MAIN)
         .enableMergeAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
-        .addOptionsModification(o -> {
-          // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single target.
-          o.enableDevirtualization = false;
-          o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-        })
+        .addOptionsModification(
+            o -> {
+              // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single
+              // target.
+              o.enableDevirtualization = false;
+              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+            })
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("null", "non-null")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfacePositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfacePositiveTest.java
index 76d8e03..a966e62 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfacePositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfacePositiveTest.java
@@ -45,14 +45,16 @@
     testForR8(parameters.getBackend())
         .addInnerClasses(InvokeInterfacePositiveTest.class)
         .addKeepMainRule(MAIN)
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .addOptionsModification(InternalOptions::enablePropagationOfConstantsAtCallSites)
-        .addOptionsModification(o -> {
-          // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single target.
-          o.enableDevirtualization = false;
-          o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-        })
+        .addOptionsModification(
+            o -> {
+              // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single
+              // target.
+              o.enableDevirtualization = false;
+              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+            })
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("non-null")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualNegativeTest.java
index b772bff..28523aa 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualNegativeTest.java
@@ -45,11 +45,12 @@
         .addInnerClasses(InvokeVirtualNegativeTest.class)
         .addKeepMainRule(MAIN)
         .enableMergeAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
-        .addOptionsModification(o -> {
-          o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-        })
+        .addOptionsModification(
+            o -> {
+              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+            })
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("null", "non-null", "null", "non-null")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java
index 3541836..ab5d763 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java
@@ -46,11 +46,12 @@
         .addInnerClasses(InvokeVirtualPositiveTest.class)
         .addKeepMainRule(MAIN)
         .enableMergeAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
-        .addOptionsModification(o -> {
-          o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-        })
+        .addOptionsModification(
+            o -> {
+              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+            })
         .setMinApi(parameters.getApiLevel())
         .addOptionsModification(InternalOptions::enablePropagationOfConstantsAtCallSites)
         .run(parameters.getRuntime(), MAIN)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectNegativeTest.java
index f350e73..27db8be 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectNegativeTest.java
@@ -43,11 +43,12 @@
     testForR8(parameters.getBackend())
         .addInnerClasses(InvokeDirectNegativeTest.class)
         .addKeepMainRule(MAIN)
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
-        .addOptionsModification(o -> {
-          o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-        })
+        .addOptionsModification(
+            o -> {
+              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+            })
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("Sub1", "Sub2")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectPositiveTest.java
index 5f0a56c..67bb7db 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectPositiveTest.java
@@ -45,11 +45,12 @@
         .addInnerClasses(InvokeDirectPositiveTest.class)
         .addKeepMainRule(MAIN)
         .enableMergeAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
-        .addOptionsModification(o -> {
-          o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-        })
+        .addOptionsModification(
+            o -> {
+              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+            })
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("Sub1")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfaceNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfaceNegativeTest.java
index 14f9b2f..1493d73 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfaceNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfaceNegativeTest.java
@@ -45,13 +45,15 @@
         .addInnerClasses(InvokeInterfaceNegativeTest.class)
         .addKeepMainRule(MAIN)
         .enableMergeAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
-        .addOptionsModification(o -> {
-          // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single target.
-          o.enableDevirtualization = false;
-          o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-        })
+        .addOptionsModification(
+            o -> {
+              // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single
+              // target.
+              o.enableDevirtualization = false;
+              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+            })
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("Sub1", "Sub2")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfacePositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfacePositiveTest.java
index 9f1308d..24cad5b 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfacePositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfacePositiveTest.java
@@ -45,13 +45,15 @@
         .addInnerClasses(InvokeInterfacePositiveTest.class)
         .addKeepMainRule(MAIN)
         .enableMergeAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
-        .addOptionsModification(o -> {
-          // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single target.
-          o.enableDevirtualization = false;
-          o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-        })
+        .addOptionsModification(
+            o -> {
+              // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single
+              // target.
+              o.enableDevirtualization = false;
+              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+            })
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("A:Sub1", "B:Sub2")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualNegativeTest.java
index e62f6b4..cc0a69f 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualNegativeTest.java
@@ -45,11 +45,12 @@
         .addInnerClasses(InvokeVirtualNegativeTest.class)
         .addKeepMainRule(MAIN)
         .enableMergeAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
-        .addOptionsModification(o -> {
-          o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-        })
+        .addOptionsModification(
+            o -> {
+              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+            })
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("A:Sub1", "A:Sub2", "B:Sub1", "B:Sub2")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualPositiveTest.java
index 81da3d5..f49d16e 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualPositiveTest.java
@@ -45,11 +45,12 @@
         .addInnerClasses(InvokeVirtualPositiveTest.class)
         .addKeepMainRule(MAIN)
         .enableMergeAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
-        .addOptionsModification(o -> {
-          o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-        })
+        .addOptionsModification(
+            o -> {
+              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+            })
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("A:Sub1", "B:Sub1")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectNegativeTest.java
index def280a..5b79156 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectNegativeTest.java
@@ -41,11 +41,12 @@
     testForR8(parameters.getBackend())
         .addInnerClasses(InvokeDirectNegativeTest.class)
         .addKeepMainRule(MAIN)
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
-        .addOptionsModification(o -> {
-          o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-        })
+        .addOptionsModification(
+            o -> {
+              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+            })
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("null", "non-null")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectPositiveTest.java
index e24eadd..9630bab 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectPositiveTest.java
@@ -42,11 +42,12 @@
     testForR8(parameters.getBackend())
         .addInnerClasses(InvokeDirectPositiveTest.class)
         .addKeepMainRule(MAIN)
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
-        .addOptionsModification(o -> {
-          o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-        })
+        .addOptionsModification(
+            o -> {
+              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+            })
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("non-null")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfaceNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfaceNegativeTest.java
index 80b24a5..3fde0f1 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfaceNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfaceNegativeTest.java
@@ -45,13 +45,15 @@
         .addInnerClasses(InvokeInterfaceNegativeTest.class)
         .addKeepMainRule(MAIN)
         .enableMergeAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
-        .addOptionsModification(o -> {
-          // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single target.
-          o.enableDevirtualization = false;
-          o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-        })
+        .addOptionsModification(
+            o -> {
+              // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single
+              // target.
+              o.enableDevirtualization = false;
+              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+            })
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("null", "A")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfacePositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfacePositiveTest.java
index 6cbbad3..17cea42 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfacePositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfacePositiveTest.java
@@ -42,13 +42,15 @@
     testForR8(parameters.getBackend())
         .addInnerClasses(InvokeInterfacePositiveTest.class)
         .addKeepMainRule(MAIN)
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
-        .addOptionsModification(o -> {
-          // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single target.
-          o.enableDevirtualization = false;
-          o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-        })
+        .addOptionsModification(
+            o -> {
+              // To prevent invoke-interface from being rewritten to invoke-virtual w/ a single
+              // target.
+              o.enableDevirtualization = false;
+              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+            })
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("A")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualCascadeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualCascadeTest.java
index c9b215a..d2181d5 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualCascadeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualCascadeTest.java
@@ -42,7 +42,7 @@
         .addInnerClasses(InvokeVirtualCascadeTest.class)
         .addKeepMainRule(MAIN)
         .enableMergeAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualNegativeTest.java
index cd20498..e36d2e9 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualNegativeTest.java
@@ -45,11 +45,12 @@
         .addInnerClasses(InvokeVirtualNegativeTest.class)
         .addKeepMainRule(MAIN)
         .enableMergeAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
-        .addOptionsModification(o -> {
-          o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-        })
+        .addOptionsModification(
+            o -> {
+              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+            })
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("null", "A", "null", "B")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualPositiveTest.java
index 6ab99d7..e05b279 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualPositiveTest.java
@@ -45,11 +45,12 @@
         .addInnerClasses(InvokeVirtualPositiveTest.class)
         .addKeepMainRule(MAIN)
         .enableMergeAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
-        .addOptionsModification(o -> {
-          o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
-        })
+        .addOptionsModification(
+            o -> {
+              o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+            })
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("A", "null")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliningOracleTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliningOracleTest.java
index 0ae036d..d35a11d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliningOracleTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliningOracleTest.java
@@ -25,7 +25,7 @@
             .addInnerClasses(ClassInliningOracleTest.class)
             .addKeepMainRule(TestClass.class)
             .enableInliningAnnotations()
-            .enableClassInliningAnnotations()
+            .enableNeverClassInliningAnnotations()
             .enableMergeAnnotations()
             .enableUnusedArgumentAnnotations()
             .compile()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/extrasubclasses/AbstractClassAlsoImplementedByMissingClassTest.java b/src/test/java/com/android/tools/r8/ir/optimize/extrasubclasses/AbstractClassAlsoImplementedByMissingClassTest.java
index d1d5d5f..65cc34d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/extrasubclasses/AbstractClassAlsoImplementedByMissingClassTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/extrasubclasses/AbstractClassAlsoImplementedByMissingClassTest.java
@@ -52,7 +52,7 @@
             // of A after the R8 compilation.
             .addKeepRules(
                 "-keep class " + A.class.getTypeName() + " { void <init>(); void kept(); }")
-            .enableClassInliningAnnotations()
+            .enableNeverClassInliningAnnotations()
             .setMinApi(parameters.getApiLevel())
             .compile()
             .inspect(this::inspect)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/extrasubclasses/InterfaceAlsoImplementedByMissingClassTest.java b/src/test/java/com/android/tools/r8/ir/optimize/extrasubclasses/InterfaceAlsoImplementedByMissingClassTest.java
index 818b1eb..89586d8 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/extrasubclasses/InterfaceAlsoImplementedByMissingClassTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/extrasubclasses/InterfaceAlsoImplementedByMissingClassTest.java
@@ -50,7 +50,7 @@
             // Keeping I and I.kept() should make it possible to provide an implementation of
             // I after the R8 compilation.
             .addKeepRules("-keep class " + I.class.getTypeName() + " { void kept(); }")
-            .enableClassInliningAnnotations()
+            .enableNeverClassInliningAnnotations()
             .setMinApi(parameters.getApiLevel())
             .compile()
             .inspect(this::inspect)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/DoubleInliningInvokeSuperTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/DoubleInliningInvokeSuperTest.java
index b5109d6..9bc40d7 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/DoubleInliningInvokeSuperTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/DoubleInliningInvokeSuperTest.java
@@ -37,7 +37,7 @@
         .addInnerClasses(DoubleInliningInvokeSuperTest.class)
         .addKeepMainRule(TestClass.class)
         .addKeepRules("-keepclassmembers class * { void fooCaller(...); }")
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .enableMergeAnnotations()
         .setMinApi(parameters.getRuntime())
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineFunctionalInterfaceMethodImplementedByLambdasTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineFunctionalInterfaceMethodImplementedByLambdasTest.java
index 4a9025a..8a999ff 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineFunctionalInterfaceMethodImplementedByLambdasTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineFunctionalInterfaceMethodImplementedByLambdasTest.java
@@ -36,7 +36,7 @@
     testForR8(parameters.getBackend())
         .addInnerClasses(InlineFunctionalInterfaceMethodImplementedByLambdasTest.class)
         .addKeepMainRule(TestClass.class)
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .setMinApi(parameters.getApiLevel())
         .compile()
         .inspect(this::inspect)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineNonReboundFieldTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineNonReboundFieldTest.java
index beb56a7..d0d52ec 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineNonReboundFieldTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineNonReboundFieldTest.java
@@ -27,7 +27,7 @@
             .addProgramClasses(
                 TestClass.class, Greeter.class, Greeting.class, Greeting.getGreetingBase())
             .addKeepMainRule(TestClass.class)
-            .enableClassInliningAnnotations()
+            .enableNeverClassInliningAnnotations()
             .enableMergeAnnotations()
             .run(TestClass.class)
             .assertSuccessWithOutput(expectedOutput)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineSynchronizedTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineSynchronizedTest.java
index b3a7ce8..1cb4d4f 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineSynchronizedTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineSynchronizedTest.java
@@ -39,7 +39,7 @@
     testForR8(parameters.getBackend())
         .addInnerClasses(InlineSynchronizedTest.class)
         .addKeepMainRule(TestClass.class)
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .setMinApi(parameters.getApiLevel())
         .compile()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningOfVirtualMethodOnKeptClassTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningOfVirtualMethodOnKeptClassTest.java
index 2349809..cc347c5 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningOfVirtualMethodOnKeptClassTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningOfVirtualMethodOnKeptClassTest.java
@@ -40,7 +40,7 @@
         .addKeepRules(
             "-keep class " + A.class.getTypeName() + " { void bar(); }",
             "-keep class " + I.class.getTypeName() + " { void baz(); }")
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .setMinApi(parameters.getRuntime())
         .compile()
         .inspect(this::verifyOutput)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/LibraryOverrideInliningTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/LibraryOverrideInliningTest.java
index 1a70cde..0b58101 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/LibraryOverrideInliningTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/LibraryOverrideInliningTest.java
@@ -47,7 +47,7 @@
             options ->
                 options.disableInliningOfLibraryMethodOverrides =
                     disableInliningOfLibraryMethodOverrides)
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .setMinApi(parameters.getRuntime())
         .compile()
         .inspect(
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/SingleTargetAfterInliningTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/SingleTargetAfterInliningTest.java
index 5f1b7a5..9ccdb7f 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/SingleTargetAfterInliningTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/SingleTargetAfterInliningTest.java
@@ -50,7 +50,7 @@
               options.applyInliningToInlineeMaxDepth = maxInliningDepth;
             })
         .enableAlwaysInliningAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableSideEffectAnnotations()
         .setMinApi(parameters.getApiLevel())
         .compile()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/SingleTargetFromExactReceiverTypeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/SingleTargetFromExactReceiverTypeTest.java
index 24f4402..7c9b7b7 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/SingleTargetFromExactReceiverTypeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/SingleTargetFromExactReceiverTypeTest.java
@@ -48,7 +48,7 @@
             "-keepclassmembers class " + A.class.getTypeName() + " {",
             "  void cannotBeInlinedDueToKeepRule();",
             "}")
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .setMinApi(parameters.getRuntime())
         .compile()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/interfacemethods/InlineDefaultInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/interfacemethods/InlineDefaultInterfaceMethodTest.java
index df9ab8d..0e4627b 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/interfacemethods/InlineDefaultInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/interfacemethods/InlineDefaultInterfaceMethodTest.java
@@ -41,7 +41,7 @@
             .addInnerClasses(InlineDefaultInterfaceMethodTest.class)
             .addKeepMainRule(TestClass.class)
             .setMinApi(parameters.getApiLevel())
-            .enableClassInliningAnnotations()
+            .enableNeverClassInliningAnnotations()
             .enableMergeAnnotations()
             .noMinification()
             .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/InstanceFieldValuePropagationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/InstanceFieldValuePropagationTest.java
index b0bf180..5b4c540 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/InstanceFieldValuePropagationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/InstanceFieldValuePropagationTest.java
@@ -42,12 +42,13 @@
     testForR8(parameters.getBackend())
         .addInnerClasses(InstanceFieldValuePropagationTest.class)
         .addKeepMainRule(TestClass.class)
-        .addOptionsModification(options -> {
-          // TODO(b/125282093): Remove options modification once landed.
-          assert !options.enableValuePropagationForInstanceFields;
-          options.enableValuePropagationForInstanceFields = true;
-        })
-        .enableClassInliningAnnotations()
+        .addOptionsModification(
+            options -> {
+              // TODO(b/125282093): Remove options modification once landed.
+              assert !options.enableValuePropagationForInstanceFields;
+              options.enableValuePropagationForInstanceFields = true;
+            })
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .setMinApi(parameters.getApiLevel())
         .compile()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/NoConstructorPropagationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/NoConstructorPropagationTest.java
index 904342a..63939b1 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/NoConstructorPropagationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/NoConstructorPropagationTest.java
@@ -37,7 +37,7 @@
             "-assumenosideeffects class " + Greeter.class.getTypeName() + " {",
             "  <init>(...);",
             "}")
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .setMinApi(parameters.getRuntime())
         .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvokeVirtual.java b/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvokeVirtual.java
index 994c87a..d577644 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvokeVirtual.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamAfterInvokeVirtual.java
@@ -5,8 +5,10 @@
 
 import static com.android.tools.r8.ir.optimize.nonnull.IntrinsicsDeputy.checkParameterIsNotNull;
 
+import com.android.tools.r8.NeverClassInline;
 import com.android.tools.r8.NeverInline;
 
+@NeverClassInline
 public class NonNullParamAfterInvokeVirtual {
 
   @NeverInline
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlinesWithNonNullTest.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlinesWithNonNullTest.java
index bea51f6..59602da 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlinesWithNonNullTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlinesWithNonNullTest.java
@@ -45,7 +45,7 @@
   @Test
   public void testNonNullOnOneSide() throws Exception {
     testForR8(parameters.getBackend())
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .addProgramClasses(TestArg.class, TestClassWithNonNullOnOneSide.class)
         .addKeepMainRule(TestClassWithNonNullOnOneSide.class)
@@ -70,7 +70,7 @@
   @Test
   public void testNonNullOnBothSides() throws Exception {
     testForR8(parameters.getBackend())
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .addProgramClasses(TestArg.class, TestClassWithNonNullOnBothSides.class)
         .addKeepMainRule(TestClassWithNonNullOnBothSides.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/b133215941/B133215941.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/b133215941/B133215941.java
index b380f62..5691577 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/b133215941/B133215941.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/b133215941/B133215941.java
@@ -62,7 +62,7 @@
     String expectedOutput = StringUtils.lines("Hello, world 5");
     testForR8(parameters.getBackend())
         .enableInliningAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableMergeAnnotations()
         .enableSideEffectAnnotations()
         .addInnerClasses(B133215941.class)
@@ -70,13 +70,14 @@
         .addKeepClassAndMembersRules(ClassWithStaticMethod.class)
         .setMinApi(parameters.getRuntime())
         .noMinification()
-        .addOptionsModification(options -> {
-          if (parameters.isCfRuntime()) {
-            assert !options.outline.enabled;
-            options.outline.enabled = true;
-          }
-          options.outline.threshold = 2;
-        })
+        .addOptionsModification(
+            options -> {
+              if (parameters.isCfRuntime()) {
+                assert !options.outline.enabled;
+                options.outline.enabled = true;
+              }
+              options.outline.threshold = 2;
+            })
         .compile()
         .inspect(this::validateOutlining)
         .run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/primitivetypes/PrimitiveTypesTest.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/primitivetypes/PrimitiveTypesTest.java
index f6e72b2..db3ef77 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/primitivetypes/PrimitiveTypesTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/primitivetypes/PrimitiveTypesTest.java
@@ -54,7 +54,7 @@
       throws Exception {
     testForR8(parameters.getBackend())
         .enableInliningAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .addProgramClasses(testClass)
         .addProgramClasses(MyStringBuilder.class)
         .addKeepMainRule(testClass)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/RedundantInstanceFieldLoadAfterStoreTest.java b/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/RedundantInstanceFieldLoadAfterStoreTest.java
index 09f1326..7c39564 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/RedundantInstanceFieldLoadAfterStoreTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/RedundantInstanceFieldLoadAfterStoreTest.java
@@ -39,7 +39,7 @@
     testForR8(parameters.getBackend())
         .addInnerClasses(RedundantInstanceFieldLoadAfterStoreTest.class)
         .addKeepMainRule(TestClass.class)
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .setMinApi(parameters.getRuntime())
         .compile()
         .inspect(
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/CompanionAsArgumentTest.java b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/CompanionAsArgumentTest.java
index 92cc700..be47557 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/CompanionAsArgumentTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/CompanionAsArgumentTest.java
@@ -42,7 +42,7 @@
         .addInnerClasses(CompanionAsArgumentTest.class)
         .addKeepMainRule(MAIN)
         .enableInliningAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("Companion#foo(true)")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InstanceInsideCompanionTest.java b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InstanceInsideCompanionTest.java
index fe55066..f28235b 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InstanceInsideCompanionTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InstanceInsideCompanionTest.java
@@ -43,7 +43,7 @@
         .addInnerClasses(InstanceInsideCompanionTest.class)
         .addKeepMainRule(MAIN)
         .enableInliningAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("Candidate#foo(false)")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InvokeStaticWithNullOutvalueTest.java b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InvokeStaticWithNullOutvalueTest.java
index 2635741..e552581 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InvokeStaticWithNullOutvalueTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InvokeStaticWithNullOutvalueTest.java
@@ -44,7 +44,7 @@
         .addInnerClasses(InvokeStaticWithNullOutvalueTest.class)
         .addKeepMainRule(MAIN)
         .enableInliningAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("Companion#boo", "Companion#foo")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/PrivateInstanceMethodCollisionTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/PrivateInstanceMethodCollisionTest.java
index c790d0a..41a1935 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/PrivateInstanceMethodCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/PrivateInstanceMethodCollisionTest.java
@@ -61,7 +61,7 @@
         .addInnerClasses(PrivateInstanceMethodCollisionTest.class)
         .addKeepMainRule(TestClass.class)
         .enableInliningAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .minification(minification)
         .allowAccessModification(allowAccessModification)
         .setMinApi(parameters.getRuntime())
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/UninstantiatedAnnotatedArgumentsTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/UninstantiatedAnnotatedArgumentsTest.java
index c92103e..035ab54 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/UninstantiatedAnnotatedArgumentsTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/UninstantiatedAnnotatedArgumentsTest.java
@@ -57,7 +57,7 @@
         .addKeepMainRule(TestClass.class)
         .addKeepClassRules(Instantiated.class, Uninstantiated.class)
         .addKeepAttributes("RuntimeVisibleParameterAnnotations")
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableConstantArgumentAnnotations(keepUninstantiatedArguments)
         .enableInliningAnnotations()
         .enableUnusedArgumentAnnotations()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/CollisionWithLibraryMethodsTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/CollisionWithLibraryMethodsTest.java
index 5c89be9..45d858d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/CollisionWithLibraryMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/CollisionWithLibraryMethodsTest.java
@@ -46,7 +46,7 @@
     testForR8(parameters.getBackend())
         .addInnerClasses(CollisionWithLibraryMethodsTest.class)
         .addKeepMainRule(TestClass.class)
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .minification(minification)
         .setMinApi(parameters.getRuntime())
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/PrivateInstanceMethodCollisionTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/PrivateInstanceMethodCollisionTest.java
index 25797a1..073c3b4 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/PrivateInstanceMethodCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/PrivateInstanceMethodCollisionTest.java
@@ -61,7 +61,7 @@
         .addInnerClasses(PrivateInstanceMethodCollisionTest.class)
         .addKeepMainRule(TestClass.class)
         .enableInliningAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .minification(minification)
         .allowAccessModification(allowAccessModification)
         .setMinApi(parameters.getRuntime())
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAnnotatedArgumentsTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAnnotatedArgumentsTest.java
index 86e4d24..09c0de7 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAnnotatedArgumentsTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAnnotatedArgumentsTest.java
@@ -55,7 +55,7 @@
         .addKeepMainRule(TestClass.class)
         .addKeepClassRules(Used.class, Unused.class)
         .addKeepAttributes("RuntimeVisibleParameterAnnotations")
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .enableUnusedArgumentAnnotations(keepUnusedArguments)
         // TODO(b/123060011): Mapping not working in presence of unused argument removal.
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentRemovalWithOverridingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentRemovalWithOverridingTest.java
index a3f1b9b..461ec6b 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentRemovalWithOverridingTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentRemovalWithOverridingTest.java
@@ -46,7 +46,7 @@
     testForR8(parameters.getBackend())
         .addInnerClasses(UnusedArgumentRemovalWithOverridingTest.class)
         .addKeepMainRule(TestClass.class)
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .enableMergeAnnotations()
         .minification(minification)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionTest.java
index 003a06f..08d8c09 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionTest.java
@@ -57,7 +57,7 @@
         .addInnerClasses(UnusedArgumentsCollisionTest.class)
         .addKeepMainRule(TestClass.class)
         .enableInliningAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableMergeAnnotations()
         .minification(minification)
         .setMinApi(parameters.getRuntime())
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsInstanceConstructorTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsInstanceConstructorTest.java
index 5e303bc..ea67170 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsInstanceConstructorTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsInstanceConstructorTest.java
@@ -49,7 +49,7 @@
             .addInnerClasses(UnusedArgumentsInstanceConstructorTest.class)
             .addKeepMainRule(TestClass.class)
             .enableInliningAnnotations()
-            .enableClassInliningAnnotations()
+            .enableNeverClassInliningAnnotations()
             .run(TestClass.class)
             .assertSuccessWithOutput(expectedOutput)
             .inspector();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsObjectTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsObjectTest.java
index 17287a4..794d588 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsObjectTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsObjectTest.java
@@ -110,7 +110,7 @@
 
   @Override
   public void configure(R8FullTestBuilder builder) {
-    builder.enableClassInliningAnnotations().enableInliningAnnotations();
+    builder.enableNeverClassInliningAnnotations().enableInliningAnnotations();
   }
 
   @Override
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInMultifileClassTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInMultifileClassTest.java
new file mode 100644
index 0000000..9280756
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInMultifileClassTest.java
@@ -0,0 +1,176 @@
+// 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.kotlin.metadata;
+
+import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isRenamed;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertNotEquals;
+
+import com.android.tools.r8.R8TestCompileResult;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
+import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.shaking.ProguardKeepAttributes;
+import com.android.tools.r8.utils.codeinspector.AnnotationSubject;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import java.nio.file.Path;
+import java.util.Collection;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class MetadataRenameInMultifileClassTest extends KotlinMetadataTestBase {
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0} target: {1}")
+  public static Collection<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+  }
+
+  public MetadataRenameInMultifileClassTest(
+      TestParameters parameters, KotlinTargetVersion targetVersion) {
+    super(targetVersion);
+    this.parameters = parameters;
+  }
+
+  private static Path multifileLibJar;
+
+  @BeforeClass
+  public static void createLibJar() throws Exception {
+    String multifileLibFolder = PKG_PREFIX + "/multifileclass_lib";
+    multifileLibJar =
+        kotlinc(KOTLINC, KotlinTargetVersion.JAVA_8)
+            .addSourceFiles(
+                getKotlinFileInTest(multifileLibFolder, "signed"),
+                getKotlinFileInTest(multifileLibFolder, "unsigned"))
+            .compile();
+  }
+
+  @Test
+  public void testMetadataInMultifileClass_merged() throws Exception {
+    R8TestCompileResult compileResult =
+        testForR8(parameters.getBackend())
+            .addProgramFiles(multifileLibJar)
+            // Keep UtilKt#comma*Join*(). Let R8 optimize (inline) others, such as joinOf*(String).
+            .addKeepRules("-keep class **.UtilKt")
+            .addKeepRules("-keepclassmembers class * { ** comma*Join*(...); }")
+            .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
+            .compile();
+    String pkg = getClass().getPackage().getName();
+    final String utilClassName = pkg + ".multifileclass_lib.UtilKt";
+    final String signedClassName = pkg + ".multifileclass_lib.UtilKt__SignedKt";
+    compileResult.inspect(inspector -> {
+      ClassSubject util = inspector.clazz(utilClassName);
+      assertThat(util, isPresent());
+      assertThat(util, not(isRenamed()));
+      MethodSubject commaJoinOfInt = util.uniqueMethodWithName("commaSeparatedJoinOfInt");
+      assertThat(commaJoinOfInt, isPresent());
+      assertThat(commaJoinOfInt, not(isRenamed()));
+      MethodSubject joinOfInt = util.uniqueMethodWithName("joinOfInt");
+      assertThat(joinOfInt, not(isPresent()));
+      // API entry is kept, hence the presence of Metadata.
+      AnnotationSubject annotationSubject = util.annotation(METADATA_TYPE);
+      assertThat(annotationSubject, isPresent());
+      // TODO(b/70169921): need further inspection.
+
+      ClassSubject signed = inspector.clazz(signedClassName);
+      assertThat(signed, isPresent());
+      assertThat(signed, isRenamed());
+      commaJoinOfInt = signed.uniqueMethodWithName("commaSeparatedJoinOfInt");
+      assertThat(commaJoinOfInt, isPresent());
+      assertThat(commaJoinOfInt, not(isRenamed()));
+      joinOfInt = signed.uniqueMethodWithName("joinOfInt");
+      assertThat(joinOfInt, isPresent());
+      assertThat(joinOfInt, isRenamed());
+      // API entry is kept, hence the presence of Metadata.
+      annotationSubject = util.annotation(METADATA_TYPE);
+      assertThat(annotationSubject, isPresent());
+      // TODO(b/70169921): need further inspection.
+    });
+
+    Path libJar = compileResult.writeToZip();
+
+    String appFolder = PKG_PREFIX + "/multifileclass_app";
+    ProcessResult kotlinTestCompileResult =
+        kotlinc(parameters.getRuntime().asCf(), KOTLINC, KotlinTargetVersion.JAVA_8)
+            .addClasspathFiles(libJar)
+            .addSourceFiles(getKotlinFileInTest(appFolder, "main"))
+            .setOutputPath(temp.newFolder().toPath())
+            // TODO(b/143687784): update to just .compile() once fixed.
+            .compileRaw();
+    // TODO(b/70169921): should be able to compile!
+    assertNotEquals(0, kotlinTestCompileResult.exitCode);
+    assertThat(kotlinTestCompileResult.stderr, containsString("unresolved reference: join"));
+  }
+
+  @Test
+  public void testMetadataInMultifileClass_renamed() throws Exception {
+    R8TestCompileResult compileResult =
+        testForR8(parameters.getBackend())
+            .addProgramFiles(multifileLibJar)
+            // Keep UtilKt#comma*Join*().
+            .addKeepRules("-keep class **.UtilKt")
+            .addKeepRules("-keepclassmembers class * { ** comma*Join*(...); }")
+            // Keep yet rename joinOf*(String).
+            .addKeepRules(
+                "-keepclassmembers,allowobfuscation class * { ** joinOf*(...); }")
+            .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
+            .compile();
+    String pkg = getClass().getPackage().getName();
+    final String utilClassName = pkg + ".multifileclass_lib.UtilKt";
+    final String signedClassName = pkg + ".multifileclass_lib.UtilKt__SignedKt";
+    compileResult.inspect(inspector -> {
+      ClassSubject util = inspector.clazz(utilClassName);
+      assertThat(util, isPresent());
+      assertThat(util, not(isRenamed()));
+      MethodSubject commaJoinOfInt = util.uniqueMethodWithName("commaSeparatedJoinOfInt");
+      assertThat(commaJoinOfInt, isPresent());
+      assertThat(commaJoinOfInt, not(isRenamed()));
+      MethodSubject joinOfInt = util.uniqueMethodWithName("joinOfInt");
+      assertThat(joinOfInt, isPresent());
+      assertThat(joinOfInt, isRenamed());
+      // API entry is kept, hence the presence of Metadata.
+      AnnotationSubject annotationSubject = util.annotation(METADATA_TYPE);
+      assertThat(annotationSubject, isPresent());
+      // TODO(b/70169921): need further inspection.
+
+      ClassSubject signed = inspector.clazz(signedClassName);
+      assertThat(signed, isPresent());
+      assertThat(signed, isRenamed());
+      commaJoinOfInt = signed.uniqueMethodWithName("commaSeparatedJoinOfInt");
+      assertThat(commaJoinOfInt, isPresent());
+      assertThat(commaJoinOfInt, not(isRenamed()));
+      joinOfInt = signed.uniqueMethodWithName("joinOfInt");
+      assertThat(joinOfInt, isPresent());
+      assertThat(joinOfInt, isRenamed());
+      // API entry is kept, hence the presence of Metadata.
+      annotationSubject = util.annotation(METADATA_TYPE);
+      assertThat(annotationSubject, isPresent());
+      // TODO(b/70169921): need further inspection.
+    });
+
+    Path libJar = compileResult.writeToZip();
+
+    String appFolder = PKG_PREFIX + "/multifileclass_app";
+    ProcessResult kotlinTestCompileResult =
+        kotlinc(parameters.getRuntime().asCf(), KOTLINC, KotlinTargetVersion.JAVA_8)
+            .addClasspathFiles(libJar)
+            .addSourceFiles(getKotlinFileInTest(appFolder, "main"))
+            .setOutputPath(temp.newFolder().toPath())
+            // TODO(b/143687784): update to just .compile() once fixed.
+            .compileRaw();
+    // TODO(b/70169921): should be able to compile!
+    assertNotEquals(0, kotlinTestCompileResult.exitCode);
+    assertThat(kotlinTestCompileResult.stderr, containsString("unresolved reference: join"));
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/multifileclass_app/main.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/multifileclass_app/main.kt
new file mode 100644
index 0000000..ce098bf
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/multifileclass_app/main.kt
@@ -0,0 +1,11 @@
+// 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.kotlin.metadata.multifileclass_app
+
+import com.android.tools.r8.kotlin.metadata.multifileclass_lib.join
+
+fun main() {
+  val s = sequenceOf(1, 2, 3)
+  println(s.join())
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/multifileclass_lib/signed.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/multifileclass_lib/signed.kt
new file mode 100644
index 0000000..81c4994
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/multifileclass_lib/signed.kt
@@ -0,0 +1,16 @@
+// 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.
+@file:kotlin.jvm.JvmMultifileClass
+@file:kotlin.jvm.JvmName("UtilKt")
+package com.android.tools.r8.kotlin.metadata.multifileclass_lib
+
+@kotlin.jvm.JvmName("joinOfInt")
+public fun Sequence<Int>.join(separator: String): String {
+  return fold("") { acc, i -> "$acc$separator$i" }
+}
+
+@kotlin.jvm.JvmName("commaSeparatedJoinOfInt")
+public fun Sequence<Int>.join(): String {
+  return join(", ")
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/multifileclass_lib/unsigned.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/multifileclass_lib/unsigned.kt
new file mode 100644
index 0000000..25dac69
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/multifileclass_lib/unsigned.kt
@@ -0,0 +1,20 @@
+// 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.
+@file:kotlin.jvm.JvmMultifileClass
+@file:kotlin.jvm.JvmName("UtilKt")
+package com.android.tools.r8.kotlin.metadata.multifileclass_lib
+
+@SinceKotlin("1.3")
+@ExperimentalUnsignedTypes
+@kotlin.jvm.JvmName("joinOfUInt")
+public fun Sequence<UInt>.join(separator: String): String {
+  return fold("") { acc, i -> "$acc$separator$i" }
+}
+
+@SinceKotlin("1.3")
+@ExperimentalUnsignedTypes
+@kotlin.jvm.JvmName("commaSeparatedJoinOfUInt")
+public fun Sequence<UInt>.join(): String {
+  return join(", ")
+}
diff --git a/src/test/java/com/android/tools/r8/naming/FieldMinificationCollisionTest.java b/src/test/java/com/android/tools/r8/naming/FieldMinificationCollisionTest.java
index 7b89f71..69b4b03 100644
--- a/src/test/java/com/android/tools/r8/naming/FieldMinificationCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/naming/FieldMinificationCollisionTest.java
@@ -29,7 +29,7 @@
             .addKeepMainRule(TestClass.class)
             .addKeepRules(
                 "-keep class " + B.class.getTypeName() + " { public java.lang.String f2; }")
-            .enableClassInliningAnnotations()
+            .enableNeverClassInliningAnnotations()
             .enableInliningAnnotations()
             .enableMergeAnnotations()
             .run(TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/naming/FieldNamingObfuscationDictionaryTest.java b/src/test/java/com/android/tools/r8/naming/FieldNamingObfuscationDictionaryTest.java
index 59b273a..be7230d 100644
--- a/src/test/java/com/android/tools/r8/naming/FieldNamingObfuscationDictionaryTest.java
+++ b/src/test/java/com/android/tools/r8/naming/FieldNamingObfuscationDictionaryTest.java
@@ -97,7 +97,7 @@
         .addInnerClasses(FieldNamingObfuscationDictionaryTest.class)
         .addKeepRules("-overloadaggressively", "-obfuscationdictionary " + dictionary.toString())
         .addKeepMainRule(Runner.class)
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .setMinApi(parameters.getApiLevel())
         .compile()
         .run(parameters.getRuntime(), Runner.class, "HELLO", "WORLD")
diff --git a/src/test/java/com/android/tools/r8/naming/InterfaceFieldMinificationTest.java b/src/test/java/com/android/tools/r8/naming/InterfaceFieldMinificationTest.java
index 2041fac..4d43352 100644
--- a/src/test/java/com/android/tools/r8/naming/InterfaceFieldMinificationTest.java
+++ b/src/test/java/com/android/tools/r8/naming/InterfaceFieldMinificationTest.java
@@ -23,7 +23,7 @@
             TestClass.class, Greeter.class, Greeting.class, Greeting.getGreetingBase(), Tag.class)
         .addKeepMainRule(TestClass.class)
         .addKeepRules("-keep,allowobfuscation class " + Tag.class.getTypeName() + " { <fields>; }")
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .enableMergeAnnotations()
         .run(TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterHorizontalMergingFieldTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterHorizontalMergingFieldTest.java
index 8503e9b..dc74758 100644
--- a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterHorizontalMergingFieldTest.java
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterHorizontalMergingFieldTest.java
@@ -7,10 +7,10 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.R8TestCompileResult;
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+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.CodeInspector;
 import org.junit.Assume;
@@ -56,7 +56,6 @@
   // Test runner code follows.
 
   private static final Class<?>[] LIBRARY_CLASSES = {
-      NeverInline.class,
       LibraryA.class,
       LibraryB.class,
       LibraryMain.class
@@ -66,33 +65,37 @@
       ProgramClass.class
   };
 
-  private Backend backend;
+  private TestParameters parameters;
 
   @Parameterized.Parameters(name = "{0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  public ApplyMappingAfterHorizontalMergingFieldTest(Backend backend) {
-    this.backend = backend;
+  public ApplyMappingAfterHorizontalMergingFieldTest(TestParameters parameters) {
+    this.parameters = parameters;
   }
 
   @Test
   public void runOnJvm() throws Throwable {
-    Assume.assumeTrue(backend == Backend.CF);
+    Assume.assumeTrue(parameters.isCfRuntime());
     testForJvm()
         .addProgramClasses(LIBRARY_CLASSES)
         .addProgramClasses(PROGRAM_CLASSES)
-        .run(ProgramClass.class)
+        .addTestingAnnotationsAsProgramClasses()
+        .run(parameters.getRuntime(), ProgramClass.class)
         .assertSuccessWithOutput(EXPECTED_SUCCESS);
   }
 
   @Test
   public void b121042934() throws Exception {
-    R8TestCompileResult libraryResult = testForR8(backend)
-        .addProgramClasses(LIBRARY_CLASSES)
-        .addKeepMainRule(LibraryMain.class)
-        .compile();
+    R8TestCompileResult libraryResult =
+        testForR8(parameters.getBackend())
+            .addProgramClasses(LIBRARY_CLASSES)
+            .addTestingAnnotationsAsProgramClasses()
+            .addKeepMainRule(LibraryMain.class)
+            .setMinApi(parameters.getApiLevel())
+            .compile();
 
     CodeInspector inspector = libraryResult.inspector();
     assertThat(inspector.clazz(LibraryMain.class), isPresent());
@@ -100,16 +103,18 @@
     assertTrue(inspector.clazz(LibraryA.class).isPresent()
         != inspector.clazz(LibraryB.class).isPresent());
 
-    testForR8(backend)
+    testForR8(parameters.getBackend())
         .noTreeShaking()
         .noMinification()
         .addProgramClasses(PROGRAM_CLASSES)
         .addApplyMapping(libraryResult.getProguardMap())
         .addLibraryClasses(LIBRARY_CLASSES)
-        .addLibraryFiles(runtimeJar(backend))
+        .addTestingAnnotationsAsLibraryClasses()
+        .addLibraryFiles(runtimeJar(parameters.getBackend()))
+        .setMinApi(parameters.getApiLevel())
         .compile()
         .addRunClasspathFiles(libraryResult.writeToZip())
-        .run(ProgramClass.class)
+        .run(parameters.getRuntime(), ProgramClass.class)
         .assertSuccessWithOutput(EXPECTED_SUCCESS);
   }
 }
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingKeepPrecedenceTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingKeepPrecedenceTest.java
index 854a730..da47d4c 100644
--- a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingKeepPrecedenceTest.java
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingKeepPrecedenceTest.java
@@ -74,7 +74,7 @@
   public void testNaming() throws IOException, CompilationFailedException, ExecutionException {
     testForR8(parameters.getBackend())
         .addInnerClasses(ApplyMappingKeepPrecedenceTest.class)
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .addApplyMapping(
             A.class.getTypeName()
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingMinificationTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingMinificationTest.java
index 572e070..d6382aa 100644
--- a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingMinificationTest.java
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingMinificationTest.java
@@ -96,7 +96,7 @@
             .addKeepRules(
                 "-keepclassmembers class " + A.class.getTypeName() + " { void methodC(); }")
             .enableInliningAnnotations()
-            .enableClassInliningAnnotations()
+            .enableNeverClassInliningAnnotations()
             .addApplyMapping(StringUtils.lines(pgMap))
             .setMinApi(parameters.getRuntime())
             .run(parameters.getRuntime(), C.class)
diff --git a/src/test/java/com/android/tools/r8/naming/b128656974/B128656974.java b/src/test/java/com/android/tools/r8/naming/b128656974/B128656974.java
index 234d00c..f063f9e 100644
--- a/src/test/java/com/android/tools/r8/naming/b128656974/B128656974.java
+++ b/src/test/java/com/android/tools/r8/naming/b128656974/B128656974.java
@@ -25,9 +25,8 @@
   public void testField() throws Exception {
     Class<?> main = TestClassMainForField.class;
     testForR8(Backend.DEX)
-        .addProgramClasses(
-            Greeting.class, Greeting.getGreetingBase(), TestClassSub.class, main)
-        .enableClassInliningAnnotations()
+        .addProgramClasses(Greeting.class, Greeting.getGreetingBase(), TestClassSub.class, main)
+        .enableNeverClassInliningAnnotations()
         .enableMergeAnnotations()
         .addKeepMainRule(main)
         .addKeepRules(
@@ -36,14 +35,15 @@
                 + "{ static java.lang.String a; }")
         .run(main)
         .assertSuccessWithOutput(StringUtils.lines("TestClassSub.greeting", "TestClassSub.a"))
-        .inspect(inspector -> {
-          ClassSubject greetingBase = inspector.clazz(Greeting.getGreetingBase());
-          assertThat(greetingBase, isPresent());
-          FieldSubject greeting = greetingBase.uniqueFieldWithName("greeting");
-          assertThat(greeting, isPresent());
-          assertThat(greeting, isRenamed());
-          assertNotEquals("a", greeting.getFinalName());
-        });
+        .inspect(
+            inspector -> {
+              ClassSubject greetingBase = inspector.clazz(Greeting.getGreetingBase());
+              assertThat(greetingBase, isPresent());
+              FieldSubject greeting = greetingBase.uniqueFieldWithName("greeting");
+              assertThat(greeting, isPresent());
+              assertThat(greeting, isRenamed());
+              assertNotEquals("a", greeting.getFinalName());
+            });
   }
 
   @NeverClassInline
@@ -74,26 +74,24 @@
   public void testMethod() throws Exception {
     Class<?> main = TestClassMainForMethod.class;
     testForR8(Backend.DEX)
-        .addProgramClasses(
-            TestClassBase.class, TestClassSub2.class, main)
+        .addProgramClasses(TestClassBase.class, TestClassSub2.class, main)
         .enableMergeAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .addKeepMainRule(main)
         .addKeepRules(
-            "-keepclassmembernames class "
-                + TestClassSub2.class.getTypeName()
-                + "{ void a(...); }")
+            "-keepclassmembernames class " + TestClassSub2.class.getTypeName() + "{ void a(...); }")
         .run(main)
         .assertSuccessWithOutput(StringUtils.lines("TestClassSub2::a", "TestClassBase::foo"))
-        .inspect(inspector -> {
-          ClassSubject base = inspector.clazz(TestClassBase.class);
-          assertThat(base, isPresent());
-          MethodSubject foo = base.uniqueMethodWithName("foo");
-          assertThat(foo, isPresent());
-          assertThat(foo, isRenamed());
-          assertNotEquals("a", foo.getFinalName());
-        });
+        .inspect(
+            inspector -> {
+              ClassSubject base = inspector.clazz(TestClassBase.class);
+              assertThat(base, isPresent());
+              MethodSubject foo = base.uniqueMethodWithName("foo");
+              assertThat(foo, isPresent());
+              assertThat(foo, isRenamed());
+              assertNotEquals("a", foo.getFinalName());
+            });
   }
 
   @NeverMerge
diff --git a/src/test/java/com/android/tools/r8/naming/b130791310/B130791310.java b/src/test/java/com/android/tools/r8/naming/b130791310/B130791310.java
index 40cd981..b12b05f 100644
--- a/src/test/java/com/android/tools/r8/naming/b130791310/B130791310.java
+++ b/src/test/java/com/android/tools/r8/naming/b130791310/B130791310.java
@@ -9,6 +9,7 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assume.assumeFalse;
 
+import com.android.tools.r8.NeverClassInline;
 import com.android.tools.r8.ProguardTestBuilder;
 import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.TestBase;
@@ -63,6 +64,7 @@
   byte foo();
 }
 
+@NeverClassInline
 class SomeClass implements SomeInterface {
   @Override
   public byte foo() {
@@ -133,7 +135,8 @@
             .addProgramClasses(CLASSES)
             .addLibraryFiles(ToolHelper.getDefaultAndroidJar())
             .addKeepClassAndMembersRules(MAIN)
-            .addKeepRules(RULES);
+            .addKeepRules(RULES)
+            .addTestingAnnotationsAsProgramClasses();
     if (!enableClassMerging) {
         builder.addKeepRules("-optimizations !class/merging/*");
     }
@@ -149,7 +152,8 @@
             .addProgramClasses(CLASSES)
             .addLibraryFiles(ToolHelper.getDefaultAndroidJar())
             .addKeepClassAndMembersRules(MAIN)
-            .addKeepRules(RULES);
+            .addKeepRules(RULES)
+            .enableNeverClassInliningAnnotations();
     if (!enableClassMerging) {
       builder.addOptionsModification(o -> o.enableVerticalClassMerging = false);
     }
diff --git a/src/test/java/com/android/tools/r8/peephole/suffixsharing/IdenticalBlockSuffixSharingWithArrayTypesTest.java b/src/test/java/com/android/tools/r8/peephole/suffixsharing/IdenticalBlockSuffixSharingWithArrayTypesTest.java
index 3f89628..1781d9f 100644
--- a/src/test/java/com/android/tools/r8/peephole/suffixsharing/IdenticalBlockSuffixSharingWithArrayTypesTest.java
+++ b/src/test/java/com/android/tools/r8/peephole/suffixsharing/IdenticalBlockSuffixSharingWithArrayTypesTest.java
@@ -83,7 +83,7 @@
     testForR8(parameters.getBackend())
         .addInnerClasses(IdenticalBlockSuffixSharingWithArrayTypesTest.class)
         .addKeepMainRule(clazz)
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .setMinApi(parameters.getRuntime())
         .compile()
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessTest.java
new file mode 100644
index 0000000..a9dc70f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessTest.java
@@ -0,0 +1,234 @@
+// 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.resolution.access;
+
+import static com.android.tools.r8.TestRuntime.CfVm.JDK11;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRunResult;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ResolutionResult;
+import com.android.tools.r8.graph.ResolutionResult.NoSuchMethodResult;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.transformers.ClassFileTransformer;
+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.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.google.common.collect.ImmutableList;
+import java.util.Collection;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.objectweb.asm.Opcodes;
+
+/** Tests the behavior of invoke-special on interfaces with a direct private definition. */
+@RunWith(Parameterized.class)
+public class NestInvokeSpecialInterfaceMethodAccessTest extends TestBase {
+
+  static final String EXPECTED = StringUtils.lines("I::bar");
+
+  private final TestParameters parameters;
+
+  // If true, all classes are in the same nest, otherwise each is in its own.
+  private final boolean inSameNest;
+
+  // If true, the invoke will reference the actual type defining the method.
+  private final boolean symbolicReferenceIsDefiningType;
+
+  @Parameterized.Parameters(name = "{0}, in-same-nest:{1}, sym-ref-is-def-type:{2}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters()
+            .withCfRuntimesStartingFromIncluding(JDK11)
+            .withDexRuntimes()
+            .withAllApiLevels()
+            .build(),
+        BooleanUtils.values(),
+        BooleanUtils.values());
+  }
+
+  public NestInvokeSpecialInterfaceMethodAccessTest(
+      TestParameters parameters, boolean inSameNest, boolean symbolicReferenceIsDefiningType) {
+    this.parameters = parameters;
+    this.inSameNest = inSameNest;
+    this.symbolicReferenceIsDefiningType = symbolicReferenceIsDefiningType;
+  }
+
+  public Collection<Class<?>> getClasses() {
+    return ImmutableList.of(Main.class);
+  }
+
+  public Collection<byte[]> getTransformedClasses() throws Exception {
+    return ImmutableList.of(
+        withNest(I.class).setPrivate(I.class.getDeclaredMethod("bar")).transform(),
+        withNest(A.class)
+            .transformMethodInsnInMethod(
+                "foo",
+                (opcode, owner, name, descriptor, isInterface, continuation) -> {
+                  assertEquals(Opcodes.INVOKEVIRTUAL, opcode);
+                  assertEquals(DescriptorUtils.getBinaryNameFromJavaType(A.class.getName()), owner);
+                  String newOwner =
+                      symbolicReferenceIsDefiningType
+                          ? DescriptorUtils.getBinaryNameFromJavaType(I.class.getName())
+                          : DescriptorUtils.getBinaryNameFromJavaType(A.class.getName());
+                  boolean newIsInterface = symbolicReferenceIsDefiningType;
+                  continuation.apply(
+                      Opcodes.INVOKESPECIAL, newOwner, name, descriptor, newIsInterface);
+                })
+            .transform());
+  }
+
+  private ClassFileTransformer withNest(Class<?> clazz) throws Exception {
+    if (inSameNest) {
+      // If in the same nest make A host and B a member.
+      return transformer(clazz).setNest(I.class, A.class);
+    }
+    // Otherwise, set the class to be its own host and no additional members.
+    return transformer(clazz).setNest(clazz);
+  }
+
+  @Test
+  public void testResolutionAccess() throws Exception {
+    // White-box test of the R8 resolution and lookup methods.
+    Class<?> definingClass = I.class;
+    Class<?> declaredClass = symbolicReferenceIsDefiningType ? definingClass : A.class;
+    Class<?> callerClass = A.class;
+
+    AppView<AppInfoWithLiveness> appView = getAppView();
+    AppInfoWithLiveness appInfo = appView.appInfo();
+
+    DexProgramClass definingClassDefinition = getDexProgramClass(definingClass, appInfo);
+    DexProgramClass declaredClassDefinition = getDexProgramClass(declaredClass, appInfo);
+    DexProgramClass callerClassDefinition = getDexProgramClass(callerClass, appInfo);
+
+    DexMethod method = getTargetMethodSignature(declaredClass, appInfo);
+    assertCallingClassCallsTarget(callerClass, appInfo, method);
+
+    // Resolve the method from the point of the declared holder.
+    assertEquals(method.holder, declaredClassDefinition.type);
+    ResolutionResult resolutionResult = appInfo.resolveMethod(declaredClassDefinition, method);
+
+    if (!symbolicReferenceIsDefiningType) {
+      // The targeted method is a private interface method and thus not a maximally specific method.
+      assertTrue(resolutionResult instanceof NoSuchMethodResult);
+      return;
+    }
+
+    assertEquals(inSameNest, resolutionResult.isAccessibleFrom(callerClassDefinition, appInfo));
+    DexEncodedMethod targetSpecial =
+        resolutionResult.lookupInvokeSpecialTarget(callerClassDefinition, appInfo);
+    DexEncodedMethod targetSuper =
+        resolutionResult.lookupInvokeSuperTarget(callerClassDefinition, appInfo);
+    if (inSameNest) {
+      assertEquals(definingClassDefinition.type, targetSpecial.method.holder);
+      assertEquals(targetSpecial, targetSuper);
+    } else {
+      assertNull(targetSpecial);
+      assertNull(targetSuper);
+    }
+  }
+
+  private void assertCallingClassCallsTarget(
+      Class<?> callerClass, AppInfoWithLiveness appInfo, DexMethod target) {
+    CodeInspector inspector = new CodeInspector(appInfo.app());
+    MethodSubject foo = inspector.clazz(callerClass).uniqueMethodWithName("foo");
+    assertTrue(
+        foo.streamInstructions().anyMatch(i -> i.isInvokeSpecial() && i.getMethod() == target));
+  }
+
+  private DexMethod getTargetMethodSignature(Class<?> declaredClass, AppInfoWithLiveness appInfo) {
+    return buildMethod(
+        Reference.method(Reference.classFromClass(declaredClass), "bar", ImmutableList.of(), null),
+        appInfo.dexItemFactory());
+  }
+
+  private DexProgramClass getDexProgramClass(Class<?> clazz, AppInfoWithLiveness appInfo) {
+    return appInfo.definitionFor(buildType(clazz, appInfo.dexItemFactory())).asProgramClass();
+  }
+
+  private AppView<AppInfoWithLiveness> getAppView() throws Exception {
+    return computeAppViewWithLiveness(
+        buildClasses(getClasses())
+            .addClassProgramData(getTransformedClasses())
+            .addLibraryFile(TestBase.runtimeJar(parameters.getBackend()))
+            .build(),
+        Main.class);
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForRuntime(parameters)
+        .addProgramClasses(getClasses())
+        .addProgramClassFileData(getTransformedClasses())
+        .run(parameters.getRuntime(), Main.class)
+        .apply(this::checkExpectedResult);
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramClasses(getClasses())
+        .addProgramClassFileData(getTransformedClasses())
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(Main.class)
+        .run(parameters.getRuntime(), Main.class)
+        .apply(this::checkExpectedResult);
+  }
+
+  private void checkExpectedResult(TestRunResult<?> result) {
+    if (!symbolicReferenceIsDefiningType) {
+      result.assertFailureWithErrorThatThrows(NoSuchMethodError.class);
+      return;
+    }
+
+    if (!inSameNest) {
+      // TODO(b/145775365): Desugaring causes change to reported error.
+      // The default method desugar will target $default$bar, but the definition is $private$bar.
+      result.assertFailureWithErrorThatThrows(
+          isDesugaring() ? NoSuchMethodError.class : IllegalAccessError.class);
+      return;
+    }
+
+    result.assertSuccessWithOutput(EXPECTED);
+  }
+
+  private boolean isDesugaring() {
+    return parameters.isDexRuntime() && parameters.getApiLevel().isLessThan(AndroidApiLevel.N);
+  }
+
+  interface I {
+    /* will be private */ default void bar() {
+      System.out.println("I::bar");
+    }
+  }
+
+  static class A implements I {
+    public void foo() {
+      // Rewritten to invoke-special A.bar or I.bar which resolves to private method A.bar
+      // When targeting B.bar => throws NoSuchMethodError.
+      // When targeting A.bar:
+      //   - in same nest => success.
+      //   - not in nest => throws IllegalAccessError.
+      bar();
+    }
+  }
+
+  static class Main {
+    public static void main(String[] args) {
+      new A().foo();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessWithIntermediateTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessWithIntermediateTest.java
new file mode 100644
index 0000000..bae2756
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessWithIntermediateTest.java
@@ -0,0 +1,220 @@
+// 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.resolution.access;
+
+import static com.android.tools.r8.TestRuntime.CfVm.JDK11;
+import static org.hamcrest.core.StringContains.containsString;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRunResult;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ResolutionResult;
+import com.android.tools.r8.graph.ResolutionResult.NoSuchMethodResult;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.transformers.ClassFileTransformer;
+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.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.google.common.collect.ImmutableList;
+import java.util.Collection;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.objectweb.asm.Opcodes;
+
+/** Tests the behavior of invoke-special on interfaces with an indirect private definition. */
+@RunWith(Parameterized.class)
+public class NestInvokeSpecialInterfaceMethodAccessWithIntermediateTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  // If true, all classes are in the same nest, otherwise each is in its own.
+  private final boolean inSameNest;
+
+  // If true, the invoke will reference the actual type defining the method.
+  private final boolean symbolicReferenceIsDefiningType;
+
+  @Parameterized.Parameters(name = "{0}, in-same-nest:{1}, sym-ref-is-def-type:{2}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters()
+            .withCfRuntimesStartingFromIncluding(JDK11)
+            .withDexRuntimes()
+            .withAllApiLevels()
+            .build(),
+        BooleanUtils.values(),
+        BooleanUtils.values());
+  }
+
+  public NestInvokeSpecialInterfaceMethodAccessWithIntermediateTest(
+      TestParameters parameters, boolean inSameNest, boolean symbolicReferenceIsDefiningType) {
+    this.parameters = parameters;
+    this.inSameNest = inSameNest;
+    this.symbolicReferenceIsDefiningType = symbolicReferenceIsDefiningType;
+  }
+
+  public Collection<Class<?>> getClasses() {
+    return ImmutableList.of(Main.class);
+  }
+
+  public Collection<byte[]> getTransformedClasses() throws Exception {
+    return ImmutableList.of(
+        withNest(I.class).setPrivate(I.class.getDeclaredMethod("bar")).transform(),
+        withNest(J.class).transform(),
+        withNest(A.class)
+            .transformMethodInsnInMethod(
+                "foo",
+                (opcode, owner, name, descriptor, isInterface, continuation) -> {
+                  assertEquals(Opcodes.INVOKEVIRTUAL, opcode);
+                  assertEquals(DescriptorUtils.getBinaryNameFromJavaType(A.class.getName()), owner);
+                  String newOwner =
+                      symbolicReferenceIsDefiningType
+                          ? DescriptorUtils.getBinaryNameFromJavaType(I.class.getName())
+                          : DescriptorUtils.getBinaryNameFromJavaType(J.class.getName());
+                  continuation.apply(Opcodes.INVOKESPECIAL, newOwner, name, descriptor, true);
+                })
+            .transform());
+  }
+
+  private ClassFileTransformer withNest(Class<?> clazz) throws Exception {
+    if (inSameNest) {
+      // If in the same nest make A host and B a member.
+      return transformer(clazz).setNest(I.class, J.class, A.class);
+    }
+    // Otherwise, set the class to be its own host and no additional members.
+    return transformer(clazz).setNest(clazz);
+  }
+
+  @Test
+  public void testResolutionAccess() throws Exception {
+    assumeFalse(
+        "b/144410139. Don't test internals for non-verifying input",
+        symbolicReferenceIsDefiningType);
+
+    // White-box test of the R8 resolution and lookup methods.
+    Class<?> definingClass = I.class;
+    Class<?> declaredClass = symbolicReferenceIsDefiningType ? definingClass : J.class;
+    Class<?> callerClass = A.class;
+
+    AppView<AppInfoWithLiveness> appView = getAppView();
+    AppInfoWithLiveness appInfo = appView.appInfo();
+
+    DexProgramClass declaredClassDefinition = getDexProgramClass(declaredClass, appInfo);
+
+    DexMethod method = getTargetMethodSignature(declaredClass, appInfo);
+
+    assertCallingClassCallsTarget(callerClass, appInfo, method);
+
+    // Resolve the method from the point of the declared holder.
+    assertEquals(method.holder, declaredClassDefinition.type);
+    ResolutionResult resolutionResult = appInfo.resolveMethod(declaredClassDefinition, method);
+
+    // The targeted method is a private interface method and thus not a maximally specific method.
+    assertTrue(resolutionResult instanceof NoSuchMethodResult);
+  }
+
+  private void assertCallingClassCallsTarget(
+      Class<?> callerClass, AppInfoWithLiveness appInfo, DexMethod method) {
+    CodeInspector inspector = new CodeInspector(appInfo.app());
+    MethodSubject foo = inspector.clazz(callerClass).uniqueMethodWithName("foo");
+    assertTrue(
+        foo.streamInstructions().anyMatch(i -> i.isInvokeSpecial() && i.getMethod() == method));
+  }
+
+  private DexMethod getTargetMethodSignature(Class<?> declaredClass, AppInfoWithLiveness appInfo) {
+    return buildMethod(
+        Reference.method(Reference.classFromClass(declaredClass), "bar", ImmutableList.of(), null),
+        appInfo.dexItemFactory());
+  }
+
+  private DexProgramClass getDexProgramClass(Class<?> definingClass, AppInfoWithLiveness appInfo) {
+    return appInfo
+        .definitionFor(buildType(definingClass, appInfo.dexItemFactory()))
+        .asProgramClass();
+  }
+
+  private AppView<AppInfoWithLiveness> getAppView() throws Exception {
+    return computeAppViewWithLiveness(
+        buildClasses(getClasses())
+            .addClassProgramData(getTransformedClasses())
+            .addLibraryFile(TestBase.runtimeJar(parameters.getBackend()))
+            .build(),
+        Main.class);
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForRuntime(parameters)
+        .addProgramClasses(getClasses())
+        .addProgramClassFileData(getTransformedClasses())
+        .run(parameters.getRuntime(), Main.class)
+        .apply(result -> checkExpectedResult(result, false));
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramClasses(getClasses())
+        .addProgramClassFileData(getTransformedClasses())
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(Main.class)
+        .run(parameters.getRuntime(), Main.class)
+        .apply(result -> checkExpectedResult(result, true));
+  }
+
+  private void checkExpectedResult(TestRunResult<?> result, boolean isR8) {
+    if (symbolicReferenceIsDefiningType) {
+      assumeTrue(
+          "TODO(b/144410139): Input does not verify. Should compilation throw an error?",
+          parameters.isCfRuntime() && !isR8);
+      result.assertFailureWithErrorThatMatches(containsString(VerifyError.class.getName()));
+    } else if (isDesugaring()) {
+      // TODO(b/145775365): Desugaring results in a reference to a non-existent companion class.
+      result.assertFailureWithErrorThatMatches(
+          containsString(NoClassDefFoundError.class.getName()));
+    } else {
+      result.assertFailureWithErrorThatMatches(containsString(NoSuchMethodError.class.getName()));
+    }
+  }
+
+  private boolean isDesugaring() {
+    return parameters.isDexRuntime() && parameters.getApiLevel().isLessThan(AndroidApiLevel.N);
+  }
+
+  interface I {
+    /* will be private */ default void bar() {
+      System.out.println("I::bar");
+    }
+  }
+
+  interface J extends I {
+    // Intentionally empty.
+  }
+
+  static class A implements J {
+    public void foo() {
+      // Rewritten to invoke-special I.bar or J.bar which resolves to private method I.bar
+      // With sym-ref I.bar the classfile fails verification.
+      // With sym-ref J.bar results in a NoSuchMethodError.
+      bar();
+    }
+  }
+
+  static class Main {
+    public static void main(String[] args) {
+      new A().foo();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessTest.java
new file mode 100644
index 0000000..490b7dc
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessTest.java
@@ -0,0 +1,192 @@
+// 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.resolution.access;
+
+import static com.android.tools.r8.TestRuntime.CfVm.JDK11;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRunResult;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ResolutionResult;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.transformers.ClassFileTransformer;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.google.common.collect.ImmutableList;
+import java.util.Collection;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class NestInvokeSpecialMethodAccessTest extends TestBase {
+
+  static final String EXPECTED = StringUtils.lines("A::bar");
+
+  private final TestParameters parameters;
+  private final boolean inSameNest;
+
+  @Parameterized.Parameters(name = "{0}, in-same-nest:{1}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters()
+            .withCfRuntimesStartingFromIncluding(JDK11)
+            .withDexRuntimes()
+            .withAllApiLevels()
+            .build(),
+        BooleanUtils.values());
+  }
+
+  public NestInvokeSpecialMethodAccessTest(TestParameters parameters, boolean inSameNest) {
+    this.parameters = parameters;
+    this.inSameNest = inSameNest;
+  }
+
+  private Collection<Class<?>> getClasses() {
+    return ImmutableList.of(Main.class);
+  }
+
+  private Collection<byte[]> getTransformedClasses() throws Exception {
+    return ImmutableList.of(
+        withNest(A.class).setPrivate(A.class.getDeclaredMethod("bar")).transform(),
+        withNest(B.class).transform());
+  }
+
+  private ClassFileTransformer withNest(Class<?> clazz) throws Exception {
+    if (inSameNest) {
+      // If in the same nest make A host and B a member.
+      return transformer(clazz).setNest(A.class, B.class);
+    }
+    // Otherwise, set the class to be its own host and no additional members.
+    return transformer(clazz).setNest(clazz);
+  }
+
+  @Test
+  public void testResolutionAccess() throws Exception {
+    // White-box test of the R8 resolution and lookup methods.
+    Class<?> definingClass = A.class;
+    Class<?> declaredClass = A.class;
+    Class<?> callerClass = B.class;
+
+    AppView<AppInfoWithLiveness> appView = getAppView();
+    AppInfoWithLiveness appInfo = appView.appInfo();
+
+    DexClass definingClassDefinition = getDexProgramClass(definingClass, appInfo);
+    DexClass declaredClassDefinition = getDexProgramClass(declaredClass, appInfo);
+    DexProgramClass callerClassDefinition = getDexProgramClass(callerClass, appInfo);
+
+    DexMethod method = getTargetMethodSignature(declaredClass, appInfo);
+
+    assertCallingClassCallsTarget(callerClass, appInfo, method);
+
+    // Resolve the method from the point of the declared holder.
+    assertEquals(method.holder, declaredClassDefinition.type);
+    ResolutionResult resolutionResult = appInfo.resolveMethod(declaredClassDefinition, method);
+
+    // Verify that the resolved method is on the defining class.
+    assertEquals(
+        definingClassDefinition, resolutionResult.asSingleResolution().getResolvedHolder());
+
+    // Verify that the resolved method is accessible if in the same nest.
+    assertEquals(inSameNest, resolutionResult.isAccessibleFrom(callerClassDefinition, appInfo));
+
+    // Verify that looking up the dispatch target returns the defining method.
+    DexEncodedMethod targetSpecial =
+        resolutionResult.lookupInvokeSpecialTarget(callerClassDefinition, appInfo);
+    DexEncodedMethod targetSuper =
+        resolutionResult.lookupInvokeSuperTarget(callerClassDefinition, appInfo);
+    if (inSameNest) {
+      assertEquals(definingClassDefinition.type, targetSpecial.method.holder);
+      assertEquals(targetSpecial, targetSuper);
+    } else {
+      assertNull(targetSpecial);
+      assertNull(targetSuper);
+    }
+  }
+
+  private void assertCallingClassCallsTarget(
+      Class<?> callerClass, AppInfoWithLiveness appInfo, DexMethod target) {
+    CodeInspector inspector = new CodeInspector(appInfo.app());
+    MethodSubject foo = inspector.clazz(callerClass).uniqueMethodWithName("foo");
+    assertTrue(
+        foo.streamInstructions().anyMatch(i -> i.isInvokeSpecial() && i.getMethod() == target));
+  }
+
+  private DexMethod getTargetMethodSignature(Class<?> declaredClass, AppInfoWithLiveness appInfo) {
+    return buildMethod(
+        Reference.method(Reference.classFromClass(declaredClass), "bar", ImmutableList.of(), null),
+        appInfo.dexItemFactory());
+  }
+
+  private DexProgramClass getDexProgramClass(Class<?> definingClass, AppInfoWithLiveness appInfo) {
+    return appInfo
+        .definitionFor(buildType(definingClass, appInfo.dexItemFactory()))
+        .asProgramClass();
+  }
+
+  private AppView<AppInfoWithLiveness> getAppView() throws Exception {
+    return computeAppViewWithLiveness(
+        buildClasses(getClasses()).addClassProgramData(getTransformedClasses()).build(),
+        Main.class);
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForRuntime(parameters)
+        .addProgramClasses(getClasses())
+        .addProgramClassFileData(getTransformedClasses())
+        .run(parameters.getRuntime(), Main.class)
+        .apply(this::checkExpectedResult);
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramClasses(getClasses())
+        .addProgramClassFileData(getTransformedClasses())
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(Main.class)
+        .run(parameters.getRuntime(), Main.class)
+        .apply(this::checkExpectedResult);
+  }
+
+  private void checkExpectedResult(TestRunResult<?> result) {
+    if (inSameNest) {
+      result.assertSuccessWithOutput(EXPECTED);
+    } else {
+      result.assertFailureWithErrorThatThrows(IllegalAccessError.class);
+    }
+  }
+
+  static class A {
+    /* will be private */ void bar() {
+      System.out.println("A::bar");
+    }
+  }
+
+  static class B extends A {
+    public void foo() {
+      // invoke-special to private method.
+      super.bar();
+    }
+  }
+
+  static class Main {
+    public static void main(String[] args) {
+      new B().foo();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java
new file mode 100644
index 0000000..52dbd4b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodAccessWithIntermediateTest.java
@@ -0,0 +1,247 @@
+// 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.resolution.access;
+
+import static com.android.tools.r8.TestRuntime.CfVm.JDK11;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRunResult;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ResolutionResult;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.transformers.ClassFileTransformer;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.google.common.collect.ImmutableList;
+import java.util.Collection;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.objectweb.asm.Opcodes;
+
+/** Tests the behavior of invoke-special among related (non-interface) classes. */
+@RunWith(Parameterized.class)
+public class NestInvokeSpecialMethodAccessWithIntermediateTest extends TestBase {
+
+  static final String EXPECTED = StringUtils.lines("A::bar");
+
+  private final TestParameters parameters;
+
+  // If true, all classes are in the same nest, otherwise each is in its own.
+  private final boolean inSameNest;
+
+  // If true, the invoke will reference the actual type defining the method.
+  private final boolean symbolicReferenceIsDefiningType;
+
+  @Parameterized.Parameters(name = "{0}, in-same-nest:{1}, sym-ref-is-def-type:{2}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters()
+            .withCfRuntimesStartingFromIncluding(JDK11)
+            .withDexRuntimes()
+            .withAllApiLevels()
+            .build(),
+        BooleanUtils.values(),
+        BooleanUtils.values());
+  }
+
+  public NestInvokeSpecialMethodAccessWithIntermediateTest(
+      TestParameters parameters, boolean inSameNest, boolean symbolicReferenceIsDefiningType) {
+    this.parameters = parameters;
+    this.inSameNest = inSameNest;
+    this.symbolicReferenceIsDefiningType = symbolicReferenceIsDefiningType;
+  }
+
+  public Collection<Class<?>> getClasses() {
+    return ImmutableList.of(Main.class);
+  }
+
+  public Collection<byte[]> getTransformedClasses() throws Exception {
+    return ImmutableList.of(
+        withNest(A.class).setPrivate(A.class.getDeclaredMethod("bar")).transform(),
+        withNest(B.class).transform(),
+        withNest(C.class)
+            .transformMethodInsnInMethod(
+                "foo",
+                (opcode, owner, name, descriptor, isInterface, continuation) -> {
+                  assertEquals(Opcodes.INVOKESPECIAL, opcode);
+                  assertEquals(DescriptorUtils.getBinaryNameFromJavaType(B.class.getName()), owner);
+                  String newOwner =
+                      symbolicReferenceIsDefiningType
+                          ? DescriptorUtils.getBinaryNameFromJavaType(A.class.getName())
+                          : DescriptorUtils.getBinaryNameFromJavaType(B.class.getName());
+                  continuation.apply(opcode, newOwner, name, descriptor, isInterface);
+                })
+            .transform());
+  }
+
+  private ClassFileTransformer withNest(Class<?> clazz) throws Exception {
+    if (inSameNest) {
+      // If in the same nest make A host and B a member.
+      return transformer(clazz).setNest(A.class, B.class, C.class);
+    }
+    // Otherwise, set the class to be its own host and no additional members.
+    return transformer(clazz).setNest(clazz);
+  }
+
+  @Test
+  public void testResolutionAccess() throws Exception {
+    // White-box test of the R8 resolution and lookup methods.
+    Class<?> definingClass = A.class;
+    Class<?> declaredClass = symbolicReferenceIsDefiningType ? definingClass : B.class;
+    Class<?> callerClass = C.class;
+
+    AppView<AppInfoWithLiveness> appView = getAppView();
+    AppInfoWithLiveness appInfo = appView.appInfo();
+
+    DexClass definingClassDefinition = getDexProgramClass(definingClass, appInfo);
+    DexClass declaredClassDefinition = getDexProgramClass(declaredClass, appInfo);
+    DexProgramClass callerClassDefinition = getDexProgramClass(callerClass, appInfo);
+
+    DexMethod method = getTargetMethodSignature(declaredClass, appInfo);
+
+    assertCallingClassCallsTarget(callerClass, appInfo, method);
+
+    // Resolve the method from the point of the declared holder.
+    assertEquals(method.holder, declaredClassDefinition.type);
+    ResolutionResult resolutionResult = appInfo.resolveMethod(declaredClassDefinition, method);
+
+    // Verify that the resolved method is on the defining class.
+    assertEquals(
+        definingClassDefinition, resolutionResult.asSingleResolution().getResolvedHolder());
+
+    // Verify that the resolved method is accessible only when in the same nest.
+    assertEquals(inSameNest, resolutionResult.isAccessibleFrom(callerClassDefinition, appInfo));
+
+    // Verify that looking up the dispatch target returns a valid target
+    // iff in the same nest and declaredHolder == definingHolder.
+    DexEncodedMethod targetSpecial =
+        resolutionResult.lookupInvokeSpecialTarget(callerClassDefinition, appInfo);
+    DexEncodedMethod targetSuper =
+        resolutionResult.lookupInvokeSuperTarget(callerClassDefinition, appInfo);
+    if (inSameNest && symbolicReferenceIsDefiningType) {
+      assertEquals(definingClassDefinition.type, targetSpecial.method.holder);
+      assertEquals(targetSpecial, targetSuper);
+    } else {
+      assertNull(targetSpecial);
+      if (!inSameNest) {
+        assertNull(targetSuper);
+      } else {
+        // TODO(b/145775365): The current invoke-super will return the resolution target.
+        assertNotNull(targetSuper);
+      }
+    }
+  }
+
+  private void assertCallingClassCallsTarget(
+      Class<?> callerClass, AppInfoWithLiveness appInfo, DexMethod target) {
+    CodeInspector inspector = new CodeInspector(appInfo.app());
+    MethodSubject foo = inspector.clazz(callerClass).uniqueMethodWithName("foo");
+    assertTrue(
+        foo.streamInstructions().anyMatch(i -> i.isInvokeSpecial() && i.getMethod() == target));
+  }
+
+  private DexMethod getTargetMethodSignature(Class<?> declaredClass, AppInfoWithLiveness appInfo) {
+    return buildMethod(
+        Reference.method(Reference.classFromClass(declaredClass), "bar", ImmutableList.of(), null),
+        appInfo.dexItemFactory());
+  }
+
+  private DexProgramClass getDexProgramClass(Class<?> clazz, AppInfoWithLiveness appInfo) {
+    return appInfo.definitionFor(buildType(clazz, appInfo.dexItemFactory())).asProgramClass();
+  }
+
+  private AppView<AppInfoWithLiveness> getAppView() throws Exception {
+    return computeAppViewWithLiveness(
+        buildClasses(getClasses()).addClassProgramData(getTransformedClasses()).build(),
+        Main.class);
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForRuntime(parameters)
+        .addProgramClasses(getClasses())
+        .addProgramClassFileData(getTransformedClasses())
+        .run(parameters.getRuntime(), Main.class)
+        .apply(result -> checkExpectedResult(result, false));
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramClasses(getClasses())
+        .addProgramClassFileData(getTransformedClasses())
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(Main.class)
+        .run(parameters.getRuntime(), Main.class)
+        .apply(result -> checkExpectedResult(result, true));
+  }
+
+  private void checkExpectedResult(TestRunResult<?> result, boolean isR8) {
+    // If not in the same nest, the error is always illegal access.
+    if (!inSameNest) {
+      result.assertFailureWithErrorThatThrows(IllegalAccessError.class);
+      return;
+    }
+
+    // If in the same nest but the reference is not exact, the error is always no such method.
+    if (!symbolicReferenceIsDefiningType) {
+      // TODO(b/145775365): R8 incorrectly compiles the input to a working program.
+      if (isR8) {
+        result.assertSuccessWithOutput(EXPECTED);
+        return;
+      }
+      // TODO(b/145775365): D8/R8 does not preserve the thrown error.
+      if (parameters.isDexRuntime()) {
+        result.assertFailureWithErrorThatThrows(IllegalAccessError.class);
+        return;
+      }
+      result.assertFailureWithErrorThatThrows(NoSuchMethodError.class);
+      return;
+    }
+
+    // Finally, if in the same nest and the reference is exact match the program runs successfully.
+    result.assertSuccessWithOutput(EXPECTED);
+  }
+
+  static class A {
+    /* will be private */ void bar() {
+      System.out.println("A::bar");
+    }
+  }
+
+  static class B extends A {
+    // Intentionally empty.
+  }
+
+  static class C extends B {
+    public void foo() {
+      // invoke-special A.bar or B.bar which resolves to private method A.bar
+      // Without nests, results in an IllegalAccessError.
+      // With nests and sym-ref B.bar, results in a NoSuchMethodError.
+      // With nests and sym-ref A.bar runs without error.
+      super.bar();
+    }
+  }
+
+  static class Main {
+    public static void main(String[] args) {
+      new C().foo();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodPublicAccessWithIntermediateTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodPublicAccessWithIntermediateTest.java
new file mode 100644
index 0000000..49426c4
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodPublicAccessWithIntermediateTest.java
@@ -0,0 +1,190 @@
+// 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.resolution.access;
+
+import static com.android.tools.r8.TestRuntime.CfVm.JDK11;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRunResult;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ResolutionResult;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.transformers.ClassFileTransformer;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.google.common.collect.ImmutableList;
+import java.util.Collection;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class NestInvokeSpecialMethodPublicAccessWithIntermediateTest extends TestBase {
+
+  static final String EXPECTED = StringUtils.lines("A::bar");
+
+  private final TestParameters parameters;
+  private final boolean inSameNest;
+
+  @Parameterized.Parameters(name = "{0}, in-same-nest:{1}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters()
+            .withCfRuntimesStartingFromIncluding(JDK11)
+            .withDexRuntimes()
+            .withAllApiLevels()
+            .build(),
+        BooleanUtils.values());
+  }
+
+  public NestInvokeSpecialMethodPublicAccessWithIntermediateTest(
+      TestParameters parameters, boolean inSameNest) {
+    this.parameters = parameters;
+    this.inSameNest = inSameNest;
+  }
+
+  public Collection<Class<?>> getClasses() {
+    return ImmutableList.of(Main.class);
+  }
+
+  public Collection<byte[]> getTransformedClasses() throws Exception {
+    return ImmutableList.of(
+        withNest(A.class).transform(),
+        withNest(B.class).transform(),
+        withNest(C.class).transform());
+  }
+
+  private ClassFileTransformer withNest(Class<?> clazz) throws Exception {
+    if (inSameNest) {
+      // If in the same nest make A host and B a member.
+      return transformer(clazz).setNest(A.class, B.class, C.class);
+    }
+    // Otherwise, set the class to be its own host and no additional members.
+    return transformer(clazz).setNest(clazz);
+  }
+
+  @Test
+  public void testResolutionAccess() throws Exception {
+    // White-box test of the R8 resolution and lookup methods.
+    Class<?> definingClass = A.class;
+    Class<?> declaredClass = B.class;
+    Class<?> callerClass = C.class;
+
+    AppView<AppInfoWithLiveness> appView = getAppView();
+
+    AppInfoWithLiveness appInfo = appView.appInfo();
+
+    DexClass definingClassDefinition = getDexProgramClass(definingClass, appInfo);
+    DexClass declaredClassDefinition = getDexProgramClass(declaredClass, appInfo);
+    DexProgramClass callerClassDefinition = getDexProgramClass(callerClass, appInfo);
+
+    DexMethod method = getTargetMethodSignature(declaredClass, appInfo);
+
+    assertCallingClassCallsTarget(callerClass, appInfo, method);
+
+    // Resolve the method from the point of the declared holder.
+    assertEquals(method.holder, declaredClassDefinition.type);
+    ResolutionResult resolutionResult = appInfo.resolveMethod(declaredClassDefinition, method);
+
+    // Verify that the resolved method is on the defining class.
+    assertEquals(
+        definingClassDefinition, resolutionResult.asSingleResolution().getResolvedHolder());
+
+    // Verify that the resolved method is accessible (it is public).
+    assertTrue(resolutionResult.isAccessibleFrom(callerClassDefinition, appInfo));
+
+    // Verify that looking up the dispatch target returns the defining method.
+    DexEncodedMethod targetSpecial =
+        resolutionResult.lookupInvokeSpecialTarget(callerClassDefinition, appInfo);
+    assertEquals(definingClassDefinition.type, targetSpecial.method.holder);
+
+    DexEncodedMethod targetSuper =
+        resolutionResult.lookupInvokeSuperTarget(callerClassDefinition, appInfo);
+    assertEquals(targetSpecial, targetSuper);
+  }
+
+  private void assertCallingClassCallsTarget(
+      Class<?> callerClass, AppInfoWithLiveness appInfo, DexMethod target) {
+    CodeInspector inspector = new CodeInspector(appInfo.app());
+    MethodSubject foo = inspector.clazz(callerClass).uniqueMethodWithName("foo");
+    assertTrue(
+        foo.streamInstructions().anyMatch(i -> i.isInvokeSpecial() && i.getMethod() == target));
+  }
+
+  private DexMethod getTargetMethodSignature(Class<?> declaredClass, AppInfoWithLiveness appInfo) {
+    return buildMethod(
+        Reference.method(Reference.classFromClass(declaredClass), "bar", ImmutableList.of(), null),
+        appInfo.dexItemFactory());
+  }
+
+  private DexProgramClass getDexProgramClass(Class<?> clazz, AppInfoWithLiveness appInfo) {
+    return appInfo.definitionFor(buildType(clazz, appInfo.dexItemFactory())).asProgramClass();
+  }
+
+  private AppView<AppInfoWithLiveness> getAppView() throws Exception {
+    return computeAppViewWithLiveness(
+        buildClasses(getClasses()).addClassProgramData(getTransformedClasses()).build(),
+        Main.class);
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForRuntime(parameters)
+        .addProgramClasses(getClasses())
+        .addProgramClassFileData(getTransformedClasses())
+        .run(parameters.getRuntime(), Main.class)
+        .apply(this::checkExpectedResult);
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramClasses(getClasses())
+        .addProgramClassFileData(getTransformedClasses())
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(Main.class)
+        .run(parameters.getRuntime(), Main.class)
+        .apply(this::checkExpectedResult);
+  }
+
+  private void checkExpectedResult(TestRunResult<?> result) {
+    result.assertSuccessWithOutput(EXPECTED);
+  }
+
+  static class A {
+    public void bar() {
+      System.out.println("A::bar");
+    }
+  }
+
+  static class B extends A {
+    // Intentionally empty.
+  }
+
+  static class C extends B {
+    public void foo() {
+      // invoke-special B.bar which resolves to private method A.bar
+      // Without nests, results in an IllegalAccessError.
+      // With nests, results in a NoSuchMethodError.
+      super.bar();
+    }
+  }
+
+  static class Main {
+    public static void main(String[] args) {
+      new C().foo();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessWithIntermediateClassTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessWithIntermediateClassTest.java
index d6343fc..3e85f1a 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessWithIntermediateClassTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessWithIntermediateClassTest.java
@@ -4,12 +4,8 @@
 package com.android.tools.r8.resolution.access;
 
 import static com.android.tools.r8.TestRuntime.CfVm.JDK11;
-import static org.hamcrest.core.StringContains.containsString;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
 
-import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestRunResult;
@@ -89,31 +85,20 @@
 
   @Test
   public void testR8() throws Exception {
-    R8FullTestBuilder builder =
-        testForR8(parameters.getBackend())
-            .addProgramClasses(getClasses())
-            .addProgramClassFileData(getTransformedClasses())
-            .setMinApi(parameters.getApiLevel())
-            .addKeepMainRule(Main.class);
-    // TODO(b/145196085): R8 fails compilation when the classes are in the same nest.
-    if (inSameNest) {
-      if (parameters.isDexRuntime()) {
-        try {
-          builder.compile();
-        } catch (CompilationFailedException e) {
-          // Expected failure.
-          return;
-        }
-        fail("Expected failure: b/145196085");
-      }
-    }
-    builder
+    testForR8(parameters.getBackend())
+        .addProgramClasses(getClasses())
+        .addProgramClassFileData(getTransformedClasses())
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(Main.class)
         .run(parameters.getRuntime(), Main.class)
         .apply(
             result -> {
-              if (inSameNest) {
-                // TODO(b/145187969): R8 compiles out the errors when in the same nest.
+              if (inSameNest && parameters.isCfRuntime()) {
+                // TODO(b/145187969): R8/CF compiles to a "working" program.
                 result.assertSuccessWithOutput(EXPECTED);
+              } else if (inSameNest && parameters.isDexRuntime()) {
+                // TODO(b/145187969): R8/DEX compiles to a throw null program.
+                result.assertFailureWithErrorThatThrows(NullPointerException.class);
               } else {
                 checkExpectedResult(result);
               }
@@ -123,9 +108,9 @@
   private void checkExpectedResult(TestRunResult<?> result) {
     if (inSameNest && parameters.isCfRuntime()) {
       // TODO(b/145187969): Investigate if the change to NoSuchMethodError is according to spec?
-      result.assertFailureWithErrorThatMatches(containsString(NoSuchMethodError.class.getName()));
+      result.assertFailureWithErrorThatThrows(NoSuchMethodError.class);
     } else {
-      result.assertFailureWithErrorThatMatches(containsString(IllegalAccessError.class.getName()));
+      result.assertFailureWithErrorThatThrows(IllegalAccessError.class);
     }
   }
 
diff --git a/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalInstanceFieldsTest.java b/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalInstanceFieldsTest.java
index 3985648..8ae759f 100644
--- a/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalInstanceFieldsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalInstanceFieldsTest.java
@@ -58,7 +58,7 @@
               options.enableValuePropagationForInstanceFields = true;
             })
         .enableInliningAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableMergeAnnotations()
         .setMinApi(parameters.getRuntime())
         .compile()
diff --git a/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalStaticFieldsTest.java b/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalStaticFieldsTest.java
index 1b54e8a..6f18cdc 100644
--- a/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalStaticFieldsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalStaticFieldsTest.java
@@ -52,46 +52,57 @@
         .addInnerClasses(EffectivelyFinalStaticFieldsTest.class)
         .addKeepMainRule(MAIN)
         .enableInliningAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableMergeAnnotations()
         .setMinApi(parameters.getRuntime())
         .compile()
-        .inspect(codeInspector -> {
-          ClassSubject main = codeInspector.clazz(MAIN);
-          assertThat(main, isPresent());
+        .inspect(
+            codeInspector -> {
+              ClassSubject main = codeInspector.clazz(MAIN);
+              assertThat(main, isPresent());
 
-          MethodSubject mainMethod = main.mainMethod();
-          assertThat(mainMethod, isPresent());
+              MethodSubject mainMethod = main.mainMethod();
+              assertThat(mainMethod, isPresent());
 
-          assertTrue(
-              mainMethod.streamInstructions().noneMatch(
-                  i -> i.isConstString("Dead code: 1", JumboStringMode.ALLOW)));
-          // TODO(b/138913138): effectively final, and default value is set.
-          assertFalse(
-              mainMethod.streamInstructions().noneMatch(
-                  i -> i.isConstString("Dead code: 2", JumboStringMode.ALLOW)));
-          // TODO(b/138913138): not trivial; assigned multiple times, but can determine the value.
-          assertFalse(
-              mainMethod.streamInstructions().noneMatch(
-                  i -> i.isConstString("Dead code: 3", JumboStringMode.ALLOW)));
-          assertTrue(
-              mainMethod.streamInstructions().noneMatch(
-                  i -> i.isConstString("Dead code: 4", JumboStringMode.ALLOW)));
-          assertTrue(
-              mainMethod.streamInstructions().noneMatch(
-                  i -> i.isConstString("Dead code: 5", JumboStringMode.ALLOW)));
-          // TODO(b/138913138): not trivial; assigned multiple times, but within a certain range.
-          assertFalse(
-              mainMethod.streamInstructions().noneMatch(
-                  i -> i.isConstString("Dead code: 6", JumboStringMode.ALLOW)));
-          assertTrue(
-              mainMethod.streamInstructions().noneMatch(
-                  i -> i.isConstString("Dead code: 7", JumboStringMode.ALLOW)));
-          // TODO(b/138913138): effectively final, and default value is set.
-          assertFalse(
-              mainMethod.streamInstructions().noneMatch(
-                  i -> i.isConstString("Dead code: 8", JumboStringMode.ALLOW)));
-        })
+              assertTrue(
+                  mainMethod
+                      .streamInstructions()
+                      .noneMatch(i -> i.isConstString("Dead code: 1", JumboStringMode.ALLOW)));
+              // TODO(b/138913138): effectively final, and default value is set.
+              assertFalse(
+                  mainMethod
+                      .streamInstructions()
+                      .noneMatch(i -> i.isConstString("Dead code: 2", JumboStringMode.ALLOW)));
+              // TODO(b/138913138): not trivial; assigned multiple times, but can determine the
+              // value.
+              assertFalse(
+                  mainMethod
+                      .streamInstructions()
+                      .noneMatch(i -> i.isConstString("Dead code: 3", JumboStringMode.ALLOW)));
+              assertTrue(
+                  mainMethod
+                      .streamInstructions()
+                      .noneMatch(i -> i.isConstString("Dead code: 4", JumboStringMode.ALLOW)));
+              assertTrue(
+                  mainMethod
+                      .streamInstructions()
+                      .noneMatch(i -> i.isConstString("Dead code: 5", JumboStringMode.ALLOW)));
+              // TODO(b/138913138): not trivial; assigned multiple times, but within a certain
+              // range.
+              assertFalse(
+                  mainMethod
+                      .streamInstructions()
+                      .noneMatch(i -> i.isConstString("Dead code: 6", JumboStringMode.ALLOW)));
+              assertTrue(
+                  mainMethod
+                      .streamInstructions()
+                      .noneMatch(i -> i.isConstString("Dead code: 7", JumboStringMode.ALLOW)));
+              // TODO(b/138913138): effectively final, and default value is set.
+              assertFalse(
+                  mainMethod
+                      .streamInstructions()
+                      .noneMatch(i -> i.isConstString("Dead code: 8", JumboStringMode.ALLOW)));
+            })
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines("The end");
   }
diff --git a/src/test/java/com/android/tools/r8/shaking/annotations/AnnotationsOnFieldsTest.java b/src/test/java/com/android/tools/r8/shaking/annotations/AnnotationsOnFieldsTest.java
index 9398f79..d24d8c1 100644
--- a/src/test/java/com/android/tools/r8/shaking/annotations/AnnotationsOnFieldsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/annotations/AnnotationsOnFieldsTest.java
@@ -46,7 +46,7 @@
   @Test
   public void test() throws Exception {
     testForR8Compat(backend)
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .addProgramClasses(CLASSES)
         .addKeepMainRule(MainClass.class)
         .addKeepRules(
diff --git a/src/test/java/com/android/tools/r8/shaking/annotations/PrunedOrMergedAnnotationTest.java b/src/test/java/com/android/tools/r8/shaking/annotations/PrunedOrMergedAnnotationTest.java
index 45b29f7..9b11b86 100644
--- a/src/test/java/com/android/tools/r8/shaking/annotations/PrunedOrMergedAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/annotations/PrunedOrMergedAnnotationTest.java
@@ -52,7 +52,7 @@
         .addKeepAttributes("*Annotation*")
         .addKeepClassAndMembersRules(Factory.class)
         .enableInliningAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines("Hello", "World!")
diff --git a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsVisibleMethodsTest.java b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsVisibleMethodsTest.java
index 8928015..ebf633c 100644
--- a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsVisibleMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsVisibleMethodsTest.java
@@ -151,7 +151,7 @@
         .addKeepRules(config.getKeepRule())
         .noMinification()
         .enableMergeAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .setMinApi(parameters.getRuntime())
         .compile()
diff --git a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsWithMultipleTargetsTest.java b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsWithMultipleTargetsTest.java
index 6806661..29e4588 100644
--- a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsWithMultipleTargetsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsWithMultipleTargetsTest.java
@@ -94,7 +94,7 @@
     testForR8(parameters.getBackend())
         .addInnerClasses(AssumenosideeffectsWithMultipleTargetsTest.class)
         .enableMergeAnnotations()
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .addKeepMainRule(MAIN)
         .addKeepRules(config.getKeepRule())
diff --git a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/StringBuildersAfterAssumenosideeffectsTest.java b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/StringBuildersAfterAssumenosideeffectsTest.java
index 9507055..2787932 100644
--- a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/StringBuildersAfterAssumenosideeffectsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/StringBuildersAfterAssumenosideeffectsTest.java
@@ -18,8 +18,8 @@
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import org.junit.Test;
-import org.junit.runners.Parameterized;
 import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
 @RunWith(Parameterized.class)
 public class StringBuildersAfterAssumenosideeffectsTest extends TestBase {
@@ -43,7 +43,7 @@
 
     testForR8(parameters.getBackend())
         .addInnerClasses(StringBuildersAfterAssumenosideeffectsTest.class)
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .addKeepMainRule(MAIN)
         .addKeepRules(
diff --git a/src/test/java/com/android/tools/r8/shaking/assumevalues/AssumevaluesWithMultipleTargetsTest.java b/src/test/java/com/android/tools/r8/shaking/assumevalues/AssumevaluesWithMultipleTargetsTest.java
index f91de77..eb205d0 100644
--- a/src/test/java/com/android/tools/r8/shaking/assumevalues/AssumevaluesWithMultipleTargetsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/assumevalues/AssumevaluesWithMultipleTargetsTest.java
@@ -155,7 +155,7 @@
   public void testR8() throws Exception {
     testForR8(parameters.getBackend())
         .addProgramClasses(MAIN, Seed.class, Itf.class, Impl1.class, Impl2.class)
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .addKeepMainRule(MAIN)
         .addKeepRules(config.getKeepRule())
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnAccessModifierTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnAccessModifierTest.java
index 268a673..8cb1cf0 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnAccessModifierTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnAccessModifierTest.java
@@ -11,8 +11,6 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeFalse;
 
-import com.android.tools.r8.NeverClassInline;
-import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestShrinkerBuilder;
 import com.android.tools.r8.errors.Unreachable;
@@ -31,12 +29,7 @@
 public class IfOnAccessModifierTest extends ProguardCompatibilityTestBase {
 
   private static final List<Class<?>> CLASSES =
-      ImmutableList.of(
-          ClassForIf.class,
-          ClassForSubsequent.class,
-          MainForAccessModifierTest.class,
-          NeverClassInline.class,
-          NeverInline.class);
+      ImmutableList.of(ClassForIf.class, ClassForSubsequent.class, MainForAccessModifierTest.class);
 
   private final TestParameters parameters;
   private final Shrinker shrinker;
@@ -57,11 +50,12 @@
     switch (shrinker) {
       case PROGUARD6:
         assertTrue(parameters.isCfRuntime());
-        return testForProguard();
+        return testForProguard().addTestingAnnotationsAsProgramClasses();
       case R8:
         return testForR8(parameters.getBackend())
+            .addTestingAnnotationsAsProgramClasses()
             .allowUnusedProguardConfigurationRules()
-            .enableClassInliningAnnotations()
+            .enableNeverClassInliningAnnotations()
             .enableInliningAnnotations();
       default:
         throw new Unreachable();
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/classstaticizer/IfRuleWithClassStaticizerTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/classstaticizer/IfRuleWithClassStaticizerTest.java
index 8d14c5d..b4e4fce 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/classstaticizer/IfRuleWithClassStaticizerTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/classstaticizer/IfRuleWithClassStaticizerTest.java
@@ -56,7 +56,7 @@
                 "}",
                 "-keep class " + Unused.class.getTypeName())
             .enableInliningAnnotations()
-            .enableClassInliningAnnotations()
+            .enableNeverClassInliningAnnotations()
             .run(TestClass.class)
             .assertSuccessWithOutput(expectedOutput)
             .inspector();
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java
index 32b5fdf..54fcadf 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java
@@ -48,7 +48,7 @@
                 "-keep class " + Unused2.class.getTypeName())
             .allowUnusedProguardConfigurationRules()
             .enableInliningAnnotations()
-            .enableClassInliningAnnotations()
+            .enableNeverClassInliningAnnotations()
             .enableMergeAnnotations()
             .setMinApi(AndroidApiLevel.M)
             .run(TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/IfRuleWithVerticalClassMerging.java b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/IfRuleWithVerticalClassMerging.java
index 4dba762..1346579 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/IfRuleWithVerticalClassMerging.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/IfRuleWithVerticalClassMerging.java
@@ -128,7 +128,7 @@
             .addProgramClasses(CLASSES)
             .addKeepMainRule(Main.class)
             .addKeepRules(config)
-            .enableClassInliningAnnotations()
+            .enableNeverClassInliningAnnotations()
             .addOptionsModification(this::configure)
             .run(Main.class)
             .assertSuccessWithOutput("123456")
diff --git a/src/test/java/com/android/tools/r8/shaking/keepparameternames/KeepParameterNamesTest.java b/src/test/java/com/android/tools/r8/shaking/keepparameternames/KeepParameterNamesTest.java
index f618e93..888b231 100644
--- a/src/test/java/com/android/tools/r8/shaking/keepparameternames/KeepParameterNamesTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/keepparameternames/KeepParameterNamesTest.java
@@ -206,7 +206,7 @@
             "In Api.api2",
             "In Api.api3");
     testForR8(parameters.getBackend())
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .enableUnusedArgumentAnnotations()
         .addInnerClasses(KeepParameterNamesTest.class)
diff --git a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByKeepClassMembersNonStaticTestRunner.java b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByKeepClassMembersNonStaticTestRunner.java
index d4b5cdd..cd8f5ba 100644
--- a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByKeepClassMembersNonStaticTestRunner.java
+++ b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByKeepClassMembersNonStaticTestRunner.java
@@ -89,7 +89,7 @@
         testForR8(parameters.getBackend())
             .enableGraphInspector(whyAreYouKeepingConsumer)
             .enableInliningAnnotations()
-            .enableClassInliningAnnotations()
+            .enableNeverClassInliningAnnotations()
             .enableMemberValuePropagationAnnotations()
             .addProgramClasses(CLASS)
             .addKeepMainRule(CLASS)
diff --git a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptSingletonIsNotCyclicTest.java b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptSingletonIsNotCyclicTest.java
index 62ec020..ba1c576 100644
--- a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptSingletonIsNotCyclicTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptSingletonIsNotCyclicTest.java
@@ -68,7 +68,7 @@
     WhyAreYouKeepingConsumer whyAreYouKeepingConsumer = new WhyAreYouKeepingConsumer(null);
     GraphInspector inspector =
         testForR8(parameters.getBackend())
-            .enableClassInliningAnnotations()
+            .enableNeverClassInliningAnnotations()
             .enableGraphInspector(whyAreYouKeepingConsumer)
             .addProgramClasses(testClass, fooClass)
             .addKeepMainRule(testClass)
diff --git a/src/test/java/com/android/tools/r8/shaking/librarymethodoverride/LibraryMethodOverrideTest.java b/src/test/java/com/android/tools/r8/shaking/librarymethodoverride/LibraryMethodOverrideTest.java
index 18188ff..0f8a6bd 100644
--- a/src/test/java/com/android/tools/r8/shaking/librarymethodoverride/LibraryMethodOverrideTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/librarymethodoverride/LibraryMethodOverrideTest.java
@@ -41,7 +41,7 @@
         .addInnerClasses(LibraryMethodOverrideTest.class)
         .addKeepMainRule(TestClass.class)
         .addOptionsModification(options -> options.enableTreeShakingOfLibraryMethodOverrides = true)
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableMergeAnnotations()
         .setMinApi(parameters.getApiLevel())
         .compile()
diff --git a/src/test/java/com/android/tools/r8/shaking/whyareyoukeeping/WhyAreYouKeepingOverriddenMethodTest.java b/src/test/java/com/android/tools/r8/shaking/whyareyoukeeping/WhyAreYouKeepingOverriddenMethodTest.java
index 8a28bdf..2914c4e 100644
--- a/src/test/java/com/android/tools/r8/shaking/whyareyoukeeping/WhyAreYouKeepingOverriddenMethodTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/whyareyoukeeping/WhyAreYouKeepingOverriddenMethodTest.java
@@ -51,7 +51,7 @@
         .addKeepMainRule(main)
         .addKeepRules(
             "-whyareyoukeeping class **.*$" + targetClass.getSimpleName() + " { void gone(); }")
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .enableMergeAnnotations()
         .minification(minification)
@@ -70,7 +70,7 @@
     testForR8(Backend.DEX)
         .addInnerClasses(WhyAreYouKeepingOverriddenMethodTest.class)
         .addKeepMainRule(main)
-        .enableClassInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
         .enableInliningAnnotations()
         .enableMergeAnnotations()
         .minification(minification)
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java
index a9ea1b7..b2c8b6f 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java
@@ -261,6 +261,7 @@
         && ((CfSwitch) instruction).getKind() == CfSwitch.Kind.LOOKUP;
   }
 
+  @Override
   public boolean isInvokeSpecial() {
     return instruction instanceof CfInvoke
         && ((CfInvoke) instruction).getOpcode() == Opcodes.INVOKESPECIAL;
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/DexInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/DexInstructionSubject.java
index c46c123..af63ce8 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/DexInstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/DexInstructionSubject.java
@@ -192,6 +192,11 @@
     return instruction instanceof InvokeStatic || instruction instanceof InvokeStaticRange;
   }
 
+  @Override
+  public boolean isInvokeSpecial() {
+    return false;
+  }
+
   public boolean isInvokeSuper() {
     return instruction instanceof InvokeSuper || instruction instanceof InvokeSuperRange;
   }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java
index 9c67ece..ebe2f02 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java
@@ -36,6 +36,8 @@
 
   boolean isInvokeStatic();
 
+  boolean isInvokeSpecial();
+
   DexMethod getMethod();
 
   boolean isNop();
diff --git a/tools/archive_desugar_jdk_libs.py b/tools/archive_desugar_jdk_libs.py
index f866564..295e006 100755
--- a/tools/archive_desugar_jdk_libs.py
+++ b/tools/archive_desugar_jdk_libs.py
@@ -48,16 +48,16 @@
   return (options, args)
 
 
-def GetVersion():
-  with open(VERSION_FILE, 'r') as version_file:
+def GetVersion(version_file_name):
+  with open(version_file_name, 'r') as version_file:
     lines = [line.strip() for line in version_file.readlines()]
     lines = [line for line in lines if not line.startswith('#')]
     if len(lines) != 1:
       raise Exception('Version file '
-          + VERSION_FILE + ' is expected to have exactly one line')
+          + version_file + ' is expected to have exactly one line')
     version = lines[0].strip()
     utils.check_basic_semver_version(
-        version, 'in version file ' + VERSION_FILE)
+        version, 'in version file ' + version_file_name)
     return version
 
 
@@ -106,7 +106,7 @@
       'https://github.com/'
           + options.github_account + '/' + LIBRARY_NAME, checkout_dir)
     with utils.ChangedWorkingDirectory(checkout_dir):
-      version = GetVersion()
+      version = GetVersion(VERSION_FILE)
 
       destination = archive.GetVersionDestination(
           'gs://', LIBRARY_NAME + '/' + version, is_master)
diff --git a/tools/r8_release.py b/tools/r8_release.py
index 366b908..bdb8242 100755
--- a/tools/r8_release.py
+++ b/tools/r8_release.py
@@ -15,6 +15,7 @@
 import xml.etree.ElementTree as et
 import zipfile
 
+import archive_desugar_jdk_libs
 import update_prebuilds_in_android
 import utils
 
@@ -28,6 +29,7 @@
 DESUGAR_JDK_LIBS_CONFIGURATION = DESUGAR_JDK_LIBS + '_configuration'
 ANDROID_TOOLS_PACKAGE = 'com.android.tools'
 
+GITHUB_DESUGAR_JDK_LIBS = 'https://github.com/google/desugar_jdk_libs'
 
 def prepare_release(args):
   if args.version:
@@ -269,8 +271,7 @@
 
 def g4_change(version, r8version):
   return subprocess.check_output(
-      'g4 change --desc "Update R8 to version %s %s\n\n'
-      'IGNORE_COMPLIANCELINT=b/145307639"' % (version, r8version),
+      'g4 change --desc "Update R8 to version %s %s\n"' % (version, r8version),
       shell=True)
 
 
@@ -297,9 +298,7 @@
   assert args.version
   # Check if an existing client exists.
   if not args.use_existing_work_branch:
-    if ':update-r8:' in subprocess.check_output('g4 myclients', shell=True):
-      print "Remove the existing 'update-r8' client before continuing."
-      sys.exit(1)
+    check_no_google3_client(args, 'update-r8')
 
   def release_google3(options):
     print "Releasing for Google 3"
@@ -417,6 +416,41 @@
   return make_release
 
 
+def prepare_push_desugar_library(args):
+  client_name = 'push-desugar-library'
+  # Check if an existing client exists.
+  check_no_google3_client(args, client_name)
+
+  def push_desugar_library(options):
+    print 'Pushing to %s' % GITHUB_DESUGAR_JDK_LIBS
+
+    google3_base = subprocess.check_output(
+        ['p4', 'g4d', '-f', client_name]).rstrip()
+    third_party_desugar_jdk_libs = \
+        os.path.join(google3_base, 'third_party', 'java_src', 'desugar_jdk_libs')
+    version = archive_desugar_jdk_libs.GetVersion(
+        os.path.join(third_party_desugar_jdk_libs, 'oss', 'VERSION.txt'))
+    if args.push_desugar_library != version:
+      print ("Failed, version of desugared library is %s, but version %s was expected." %
+        (version, args.push_desugar_library))
+      sys.exit(1)
+    with utils.ChangedWorkingDirectory(google3_base):
+      cmd = [
+          'copybara',
+           os.path.join(
+              'third_party',
+              'java_src',
+              'desugar_jdk_libs',
+              'copy.bara.sky'),
+           'push-to-github']
+      if options.dry_run:
+        print "Dry-run, not running '%s'" % ' '.join(cmd)
+      else:
+        subprocess.check_call(cmd)
+
+  return push_desugar_library
+
+
 def download_configuration(hash, archive):
   print
   print 'Downloading %s from GCS' % archive
@@ -445,6 +479,16 @@
   return '%s:%s:%s' % \
       (ANDROID_TOOLS_PACKAGE, DESUGAR_JDK_LIBS_CONFIGURATION, version)
 
+
+def check_no_google3_client(args, client_name):
+  if not args.use_existing_work_branch:
+    clients = subprocess.check_output('g4 myclients', shell=True)
+    if ':%s:' % client_name in clients:
+      print ("Remove the existing '%s' client before continuing, " +
+          "or use option --use-existing-work-branch.") % client_name
+      sys.exit(1)
+
+
 def extract_version_from_pom(pom_file):
     ns = "http://maven.apache.org/POM/4.0.0"
     xml.etree.ElementTree.register_namespace('', ns)
@@ -509,7 +553,7 @@
   cmd = [ADMRT, '--archives']
   cmd.extend(archives)
   cmd.extend(['--action', action])
-  subprocess.check_call()
+  subprocess.check_call(cmd)
 
 
 def branch_change_diff(diff, old_version, new_version):
@@ -639,6 +683,10 @@
   group.add_argument('--version',
                       metavar=('<version>'),
                       help='The new version of R8 (e.g., 1.4.51) to release to selected channels')
+  group.add_argument('--push-desugar-library',
+                      metavar=('<version>'),
+                      help='The expected version of '
+                          + 'com.android.tools:desugar_jdk_libs to push to GitHub')
   group.add_argument('--desugar-library',
                       nargs=2,
                       metavar=('<version>', '<configuration hash>'),
@@ -720,7 +768,8 @@
 
   if (args.google3
       or (args.studio and not args.no_sync)
-      or (args.desugar_library and not args.dry_run)):
+      or (args.desugar_library and not args.dry_run)
+      or (args.push_desugar_library and not args.dry_run)):
     utils.check_prodacces()
 
   if args.google3:
@@ -733,6 +782,9 @@
   if args.desugar_library:
     targets_to_run.append(prepare_desugar_library(args))
 
+  if args.push_desugar_library:
+    targets_to_run.append(prepare_push_desugar_library(args))
+
   final_results = []
   for target_closure in targets_to_run:
     final_results.append(target_closure(args))
diff --git a/tools/run_on_app.py b/tools/run_on_app.py
index 0941623..c31bfea 100755
--- a/tools/run_on_app.py
+++ b/tools/run_on_app.py
@@ -509,6 +509,7 @@
     if 'allow-type-errors' in values:
       extra_args.append('-Dcom.android.tools.r8.allowTypeErrors=1')
     if 'proto-shrinking' in values:
+      extra_args.append('-Dcom.android.tools.r8.applyInliningToInlinee=1')
       extra_args.append('-Dcom.android.tools.r8.fieldBitAccessAnalysis=1')
       extra_args.append('-Dcom.android.tools.r8.generatedExtensionRegistryShrinking=1')
       extra_args.append('-Dcom.android.tools.r8.generatedMessageLiteShrinking=1')