Merge commit 'c0b0127d98ec62b55e00c0bdba94652ceb5bca08' into dev-release
diff --git a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
index 5071174..ae4700f 100644
--- a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
+++ b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
@@ -6,6 +6,7 @@
 
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DefaultInstanceInitializerCode;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexField;
@@ -98,13 +99,6 @@
     }
 
     private void checkReferenceToLibraryClass(DexReference reference) {
-      if (reference.isDexMember()) {
-        reference
-            .asDexMember()
-            .getReferencedBaseTypes(appView.dexItemFactory())
-            .forEach(
-                refType -> findReferencedLibraryClasses(appView.graphLens().lookupType(refType)));
-      }
       DexType rewrittenType = appView.graphLens().lookupType(reference.getContextType());
       findReferencedLibraryClasses(rewrittenType);
       if (reference.isDexMethod()) {
@@ -155,6 +149,11 @@
   }
 
   public void processClass(DexProgramClass clazz) {
+    if (appView
+        .getSyntheticItems()
+        .isSyntheticOfKind(clazz.getType(), SyntheticKind.API_MODEL_OUTLINE)) {
+      return;
+    }
     findReferencedLibraryClasses(clazz.type);
     clazz.forEachProgramMethodMatching(
         DexEncodedMethod::hasCode,
@@ -285,14 +284,20 @@
         || !method.isStatic()
         || appView.options().canUseDefaultAndStaticInterfaceMethods();
     DexMethod newMethod = method.getReference().withHolder(clazz.type, appView.dexItemFactory());
-    boolean isVirtualInterfaceMethod = method.isVirtualMethod() && clazz.isInterface();
-    return DexEncodedMethod.syntheticBuilder(method)
-        .setMethod(newMethod)
-        .modifyAccessFlags(MethodAccessFlags::setSynthetic)
-        .applyIf(isVirtualInterfaceMethod, b -> b.modifyAccessFlags(MethodAccessFlags::setAbstract))
-        .applyIf(
-            !isVirtualInterfaceMethod && !method.isAbstract(),
-            b -> b.modifyAccessFlags(MethodAccessFlags::setNative))
-        .build();
+    DexEncodedMethod.Builder methodBuilder =
+        DexEncodedMethod.syntheticBuilder(method)
+            .setMethod(newMethod)
+            .modifyAccessFlags(MethodAccessFlags::setSynthetic);
+    if (method.isInstanceInitializer()) {
+      methodBuilder.setCode(DefaultInstanceInitializerCode.get());
+    } else if (method.isVirtualMethod() && clazz.isInterface()) {
+      methodBuilder.modifyAccessFlags(MethodAccessFlags::setAbstract);
+    } else if (method.isAbstract()) {
+      methodBuilder.modifyAccessFlags(MethodAccessFlags::setAbstract);
+    } else {
+      // To allow us not adding a trivial throwing code body we set the access flag as native.
+      methodBuilder.modifyAccessFlags(MethodAccessFlags::setNative);
+    }
+    return methodBuilder.build();
   }
 }
diff --git a/src/main/java/com/android/tools/r8/contexts/CompilationContext.java b/src/main/java/com/android/tools/r8/contexts/CompilationContext.java
index d3db39a..a34811c 100644
--- a/src/main/java/com/android/tools/r8/contexts/CompilationContext.java
+++ b/src/main/java/com/android/tools/r8/contexts/CompilationContext.java
@@ -34,11 +34,13 @@
   }
 
   private final Consumer<String> testingConsumer;
+  private final Thread mainThread;
   private final Map<String, String> seenSetForTesting = new ConcurrentHashMap<>();
   private int nextProcessorId = 0;
 
   private CompilationContext(InternalOptions options) {
     testingConsumer = options.testing.processingContextsConsumer;
+    mainThread = options.mainThread;
   }
 
   private boolean verifyContext(ContextDescriptorProvider context) {
@@ -63,6 +65,7 @@
   public ProcessorContext createProcessorContext() {
     ProcessorContext processorContext = new ProcessorContext(this, nextProcessorId++);
     assert verifyContext(processorContext);
+    assert mainThread == Thread.currentThread() : "Invoked on another thread than main";
     return processorContext;
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java
index 850b669..b9d02f9 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java
@@ -211,7 +211,17 @@
       if (other.isNull()) {
         return NullOrAbstractValue.create(this);
       }
+      if (isNullOrAbstractValue() && asNullOrAbstractValue().getNonNullValue().equals(other)) {
+        return this;
+      }
+      if (other.isNullOrAbstractValue()
+          && other.asNullOrAbstractValue().getNonNullValue().equals(this)) {
+        return other;
+      }
+      return unknown();
     }
+    assert !isNullOrAbstractValue();
+    assert !other.isNullOrAbstractValue();
     if (allowNonConstantNumbers
         && isConstantOrNonConstantNumberValue()
         && other.isConstantOrNonConstantNumberValue()) {
@@ -230,7 +240,7 @@
       }
       return numberFromSetValueBuilder.build(factory);
     }
-    return UnknownValue.getInstance();
+    return unknown();
   }
 
   public abstract AbstractValue rewrittenWithLens(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java
index d56be1a..da44c03 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java
@@ -92,13 +92,18 @@
     if (clazz == null || !clazz.isLibraryClass()) {
       return appView.computedMinApiLevel();
     }
-    ComputedApiLevel apiLevel =
+    ComputedApiLevel methodApiLevel =
         apiLevelCompute.computeApiLevelForLibraryReference(
             cfInvoke.getMethod(), ComputedApiLevel.unknown());
-    if (apiLevel.isGreaterThan(appView.computedMinApiLevel())) {
-      return apiLevel;
+    if (appView.computedMinApiLevel().isGreaterThanOrEqualTo(methodApiLevel)) {
+      return appView.computedMinApiLevel();
     }
-    return appView.computedMinApiLevel();
+    // Compute the api level of the holder to see if the method will be stubbed.
+    ComputedApiLevel holderApiLevel =
+        apiLevelCompute.computeApiLevelForLibraryReference(holderType, ComputedApiLevel.unknown());
+    return methodApiLevel.isGreaterThan(holderApiLevel)
+        ? methodApiLevel
+        : appView.computedMinApiLevel();
   }
 
   private Collection<CfInstruction> desugarLibraryCall(
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java
index 9e79ee0..5022d48 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.kotlin;
 
 import static com.android.tools.r8.kotlin.KotlinMetadataUtils.isValidMethodDescriptor;
+import static com.android.tools.r8.kotlin.KotlinMetadataUtils.toDefaultJvmMethodSignature;
 import static com.android.tools.r8.utils.FunctionUtils.forEachApply;
 
 import com.android.tools.r8.graph.AppView;
@@ -18,6 +19,8 @@
 import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.Reporter;
 import com.google.common.collect.ImmutableList;
+import com.google.common.math.IntMath;
+import java.math.RoundingMode;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -87,7 +90,7 @@
         }
         continue;
       }
-      keepIfInline(kmFunction.getFlags(), method, keepByteCode);
+      keepIfInline(kmFunction.getFlags(), method, signature, methodSignatureMap, keepByteCode);
       method.setKotlinMemberInfo(kotlinFunctionInfo);
       originalAssignmentTracker.add(method.getReference());
     }
@@ -138,8 +141,24 @@
   }
 
   private static void keepIfInline(
-      int flags, DexEncodedMethod method, Consumer<DexEncodedMethod> keepByteCode) {
+      int flags,
+      DexEncodedMethod method,
+      JvmMethodSignature signature,
+      Map<String, DexEncodedMethod> methodSignatureMap,
+      Consumer<DexEncodedMethod> keepByteCode) {
     if (Flags.IS_INLINE.get(flags)) {
+      // Check if we can find a default method. If there are more than 32 arguments another int
+      // index will be added to the default method.
+      for (int i = 1;
+          i <= IntMath.divide(method.getParameters().size(), 32, RoundingMode.CEILING);
+          i++) {
+        DexEncodedMethod defaultValueMethod =
+            methodSignatureMap.get(toDefaultJvmMethodSignature(signature, i).toString());
+        if (defaultValueMethod != null) {
+          keepByteCode.accept(defaultValueMethod);
+          return;
+        }
+      }
       keepByteCode.accept(method);
     }
   }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java
index 2d6f39a..1d927fe 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java
@@ -21,6 +21,7 @@
 import com.android.tools.r8.shaking.ProguardKeepRuleType;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.Pair;
+import com.google.common.base.Strings;
 import kotlinx.metadata.KmExtensionType;
 import kotlinx.metadata.KmProperty;
 import kotlinx.metadata.KmPropertyExtensionVisitor;
@@ -99,13 +100,21 @@
     return new JvmMethodSignature(method.name.toString(), descBuilder.toString());
   }
 
+  static JvmMethodSignature toDefaultJvmMethodSignature(
+      JvmMethodSignature methodSignature, int intArguments) {
+    return new JvmMethodSignature(
+        methodSignature.getName() + "$default",
+        methodSignature
+            .getDesc()
+            .replace(")", Strings.repeat("I", intArguments) + "Ljava/lang/Object;)"));
+  }
+
   static class KmPropertyProcessor {
     private JvmFieldSignature fieldSignature = null;
     // Custom getter via @get:JvmName("..."). Otherwise, null.
     private JvmMethodSignature getterSignature = null;
     // Custom getter via @set:JvmName("..."). Otherwise, null.
     private JvmMethodSignature setterSignature = null;
-
     KmPropertyProcessor(KmProperty kmProperty) {
       kmProperty.accept(
           new KmPropertyVisitor() {
diff --git a/src/main/java/com/android/tools/r8/synthesis/CommittedSyntheticsCollection.java b/src/main/java/com/android/tools/r8/synthesis/CommittedSyntheticsCollection.java
index 6961fb0..ef9ae30 100644
--- a/src/main/java/com/android/tools/r8/synthesis/CommittedSyntheticsCollection.java
+++ b/src/main/java/com/android/tools/r8/synthesis/CommittedSyntheticsCollection.java
@@ -179,6 +179,15 @@
   boolean containsTypeOfKind(DexType type, SyntheticKind kind) {
     List<SyntheticProgramClassReference> synthetics = nonLegacyClasses.get(type);
     if (synthetics == null) {
+      List<SyntheticMethodReference> syntheticMethodReferences = nonLegacyMethods.get(type);
+      if (syntheticMethodReferences == null) {
+        return false;
+      }
+      for (SyntheticMethodReference syntheticMethodReference : syntheticMethodReferences) {
+        if (syntheticMethodReference.getKind() == kind) {
+          return true;
+        }
+      }
       return false;
     }
     for (SyntheticProgramClassReference synthetic : synthetics) {
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 7bc38a4..7ce8109 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -315,6 +315,9 @@
     return 16383;
   }
 
+  // We assume options will always be created on the main thread.
+  public Thread mainThread = Thread.currentThread();
+
   public boolean enableSwitchRewriting = true;
   public boolean enableStringSwitchConversion = true;
   public int minimumStringSwitchSize = 3;
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/InterfaceTypeToClassTypeLensCodeRewriterHelperImpl.java b/src/main/java/com/android/tools/r8/verticalclassmerging/InterfaceTypeToClassTypeLensCodeRewriterHelperImpl.java
index e97d8c5..bff70f5 100644
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/InterfaceTypeToClassTypeLensCodeRewriterHelperImpl.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/InterfaceTypeToClassTypeLensCodeRewriterHelperImpl.java
@@ -163,8 +163,9 @@
                   operand, block, originalType, rewrittenType, isCodeFullyRewrittenWithLens);
           assert !needsCastForOperand.isUnknown();
           if (needsCastForOperand.isTrue()) {
-            insertCastForOperand(
-                operand, rewrittenType, instruction, blockIterator, block, instructionIterator);
+            instructionIterator =
+                insertCastForOperand(
+                    operand, rewrittenType, instruction, blockIterator, block, instructionIterator);
           }
         }
       }
@@ -181,7 +182,7 @@
         .addLast(new WorklistItem(operandIndex, originalType, rewrittenType));
   }
 
-  private void insertCastForOperand(
+  private InstructionListIterator insertCastForOperand(
       Value operand,
       DexType castType,
       Instruction rewrittenUser,
@@ -199,10 +200,11 @@
             .setPosition(rewrittenUser)
             .build();
     if (block.hasCatchHandlers()) {
-      instructionIterator
-          .splitCopyCatchHandlers(code, blockIterator, appView.options())
-          .listIterator(code)
-          .add(checkCast);
+      BasicBlock splitBlock =
+          instructionIterator.splitCopyCatchHandlers(code, blockIterator, appView.options());
+      instructionIterator.previous();
+      instructionIterator.add(checkCast);
+      instructionIterator = splitBlock.listIterator(code);
     } else {
       instructionIterator.add(checkCast);
     }
@@ -210,6 +212,7 @@
 
     Instruction next = instructionIterator.next();
     assert next == rewrittenUser;
+    return instructionIterator;
   }
 
   private boolean isOperandRewrittenWithLens(
diff --git a/src/test/java/com/android/tools/r8/D8TestCompileResult.java b/src/test/java/com/android/tools/r8/D8TestCompileResult.java
index 3908d64..6d7634c 100644
--- a/src/test/java/com/android/tools/r8/D8TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/D8TestCompileResult.java
@@ -5,10 +5,7 @@
 
 import com.android.tools.r8.ToolHelper.ProcessResult;
 import com.android.tools.r8.utils.AndroidApp;
-import java.io.IOException;
-import java.nio.file.Path;
 import java.util.Set;
-import java.util.concurrent.ExecutionException;
 
 public class D8TestCompileResult extends TestCompileResult<D8TestCompileResult, D8TestRunResult> {
   private final String proguardMap;
@@ -57,13 +54,4 @@
   public D8TestRunResult createRunResult(TestRuntime runtime, ProcessResult result) {
     return new D8TestRunResult(app, runtime, result, proguardMap);
   }
-
-  public D8TestRunResult runWithJaCoCo(
-      Path output, TestRuntime runtime, String mainClass, String... args)
-      throws IOException, ExecutionException {
-    setSystemProperty("jacoco-agent.destfile", output.toString());
-    setSystemProperty("jacoco-agent.dumponexit", "true");
-    setSystemProperty("jacoco-agent.output", "file");
-    return run(runtime, mainClass, args);
-  }
 }
diff --git a/src/test/java/com/android/tools/r8/KotlinCompilerTool.java b/src/test/java/com/android/tools/r8/KotlinCompilerTool.java
index b6bcf5c..180b043 100644
--- a/src/test/java/com/android/tools/r8/KotlinCompilerTool.java
+++ b/src/test/java/com/android/tools/r8/KotlinCompilerTool.java
@@ -180,6 +180,8 @@
   private final List<Path> classpath = new ArrayList<>();
   private final List<String> additionalArguments = new ArrayList<>();
   private boolean useJvmAssertions;
+  // TODO(b/211590675): We should enable assertions by default.
+  private boolean enableAssertions = true;
   private Path output = null;
 
   private KotlinCompilerTool(
@@ -250,6 +252,11 @@
     return this;
   }
 
+  public KotlinCompilerTool disableAssertions() {
+    this.enableAssertions = false;
+    return this;
+  }
+
   public KotlinCompilerTool addSourceFilesWithNonKtExtension(
       TemporaryFolder temp, Collection<Path> files) {
     return addSourceFiles(
@@ -325,6 +332,9 @@
   private ProcessResult compileInternal(Path output) throws IOException {
     List<String> cmdline = new ArrayList<>();
     cmdline.add(jdk.getJavaExecutable().toString());
+    if (enableAssertions) {
+      cmdline.add("-ea");
+    }
     cmdline.add("-cp");
     cmdline.add(compiler.getCompiler().toString());
     cmdline.add(ToolHelper.K2JVMCompiler);
diff --git a/src/test/java/com/android/tools/r8/TestCompileResult.java b/src/test/java/com/android/tools/r8/TestCompileResult.java
index ebf30b6..5b6996d 100644
--- a/src/test/java/com/android/tools/r8/TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/TestCompileResult.java
@@ -217,6 +217,14 @@
         ObjectArrays.concat(mainClassSubject.getFinalName(), args));
   }
 
+  public RR runWithJaCoCo(Path output, TestRuntime runtime, String mainClass, String... args)
+      throws IOException, ExecutionException {
+    setSystemProperty("jacoco-agent.destfile", output.toString());
+    setSystemProperty("jacoco-agent.dumponexit", "true");
+    setSystemProperty("jacoco-agent.output", "file");
+    return run(runtime, mainClass, args);
+  }
+
   public CR addRunClasspathFiles(Path... classpath) {
     return addRunClasspathFiles(Arrays.asList(classpath));
   }
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelDesugaredLibraryReferenceTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelDesugaredLibraryReferenceTest.java
index c3c1940..0d451cb 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelDesugaredLibraryReferenceTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelDesugaredLibraryReferenceTest.java
@@ -65,7 +65,10 @@
             shrinkDesugaredLibrary)
         .run(parameters.getRuntime(), Executor.class)
         .assertSuccessWithOutputLines("Z")
-        .inspect(ApiModelingTestHelper.verifyThat(parameters, printZone).inlinedInto(main));
+        .inspect(
+            inspector ->
+                ApiModelingTestHelper.verifyThat(inspector, parameters, printZone)
+                    .inlinedInto(main));
   }
 
   static class Executor {
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelInlineInSameClassDifferentApiLevelTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelInlineInSameClassDifferentApiLevelTest.java
index 8002d8c..911731b 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelInlineInSameClassDifferentApiLevelTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelInlineInSameClassDifferentApiLevelTest.java
@@ -47,7 +47,7 @@
         .apply(ApiModelingTestHelper::enableApiCallerIdentification)
         .enableInliningAnnotations()
         .compile()
-        .inspect(verifyThat(parameters, callApi).inlinedInto(callCallApi))
+        .inspect(inspector -> verifyThat(inspector, parameters, callApi).inlinedInto(callCallApi))
         .addRunClasspathClasses(Api.class)
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines("Api::apiLevel22");
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelInlineInSameClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelInlineInSameClassTest.java
index 1ccb626..8d4e2f1 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelInlineInSameClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelInlineInSameClassTest.java
@@ -53,10 +53,10 @@
         .apply(setMockApiLevelForMethod(apiMethod, AndroidApiLevel.L_MR1))
         .apply(ApiModelingTestHelper::enableApiCallerIdentification)
         .compile()
-        .inspect(verifyThat(parameters, notCallingApi).inlinedIntoFromApiLevel(main, L_MR1))
         .inspect(
             inspector -> {
               // No matter the api level, we should always inline callingApi into notCallingApi.
+              verifyThat(inspector, parameters, notCallingApi).inlinedIntoFromApiLevel(main, L_MR1);
               assertThat(inspector.method(callingApi), not(isPresent()));
               if (parameters.isDexRuntime()
                   && parameters.getApiLevel().isGreaterThanOrEqualTo(L_MR1)) {
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelInlineMethodWithApiTypeTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelInlineMethodWithApiTypeTest.java
index 03b2f3e..9d667c1 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelInlineMethodWithApiTypeTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelInlineMethodWithApiTypeTest.java
@@ -52,8 +52,12 @@
         .addRunClasspathClasses(ApiType.class)
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines(ApiType.class.getName())
-        .inspect(verifyThat(parameters, apiCallerApiLevel22).inlinedInto(apiCallerCallerApiLevel22))
-        .inspect(inspector -> assertThat(inspector.clazz(OtherCaller.class), not(isPresent())));
+        .inspect(
+            inspector -> {
+              verifyThat(inspector, parameters, apiCallerApiLevel22)
+                  .inlinedInto(apiCallerCallerApiLevel22);
+              assertThat(inspector.clazz(OtherCaller.class), not(isPresent()));
+            });
   }
 
   public static class ApiType {}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassInstanceInitTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassInstanceInitTest.java
new file mode 100644
index 0000000..7c60172
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassInstanceInitTest.java
@@ -0,0 +1,97 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.apimodel;
+
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer;
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.not;
+import static org.junit.Assume.assumeFalse;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ApiModelMockClassInstanceInitTest extends TestBase {
+
+  private final AndroidApiLevel mockLevel = AndroidApiLevel.M;
+
+  @Parameter public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    // TODO(b/197078995): Make this work on 12.
+    assumeFalse(
+        parameters.isDexRuntime() && parameters.getDexRuntimeVersion().isEqualTo(Version.V12_0_0));
+    boolean isMockApiLevel =
+        parameters.isDexRuntime() && parameters.getApiLevel().isGreaterThanOrEqualTo(mockLevel);
+    testForR8(parameters.getBackend())
+        .addProgramClasses(Main.class, TestClass.class)
+        .addLibraryClasses(LibraryClass.class)
+        .addDefaultRuntimeLibrary(parameters)
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(Main.class)
+        .addAndroidBuildVersion()
+        .apply(ApiModelingTestHelper::enableStubbingOfClasses)
+        .apply(setMockApiLevelForClass(LibraryClass.class, mockLevel))
+        .apply(setMockApiLevelForDefaultInstanceInitializer(LibraryClass.class, mockLevel))
+        .enableInliningAnnotations()
+        .compile()
+        .applyIf(isMockApiLevel, b -> b.addBootClasspathClasses(LibraryClass.class))
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLinesIf(isMockApiLevel, "LibraryClass::foo")
+        .assertSuccessWithOutputLinesIf(!isMockApiLevel, "NoClassDefFoundError")
+        .inspect(
+            inspector ->
+                verifyThat(inspector, parameters, LibraryClass.class).stubbedUntil(mockLevel))
+        .applyIf(
+            !isMockApiLevel
+                && parameters.isDexRuntime()
+                && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V7_0_0),
+            result -> result.assertStderrMatches(not(containsString("This dex file is invalid"))));
+  }
+
+  // Only present from api level 23.
+  public static class LibraryClass {
+
+    public void foo() {
+      System.out.println("LibraryClass::foo");
+    }
+  }
+
+  public static class TestClass {
+
+    @NeverInline
+    public static void test() {
+      try {
+        new LibraryClass().foo();
+      } catch (ExceptionInInitializerError | NoClassDefFoundError er) {
+        System.out.println("NoClassDefFoundError");
+      }
+    }
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) {
+      TestClass.test();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassTest.java
index 3c5ad21..dddfcbc 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassTest.java
@@ -60,7 +60,9 @@
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLinesIf(isMockApiLevel, "LibraryClass::foo")
         .assertSuccessWithOutputLinesIf(!isMockApiLevel, "Hello World")
-        .inspect(verifyThat(parameters, LibraryClass.class).stubbedUntil(mockLevel));
+        .inspect(
+            inspector ->
+                verifyThat(inspector, parameters, LibraryClass.class).stubbedUntil(mockLevel));
   }
 
   // Only present from api level 23.
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java
index 2268036..474874c 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java
@@ -59,7 +59,9 @@
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLinesIf(isMockApiLevel, "ProgramClass::foo")
         .assertSuccessWithOutputLinesIf(!isMockApiLevel, "Hello World")
-        .inspect(verifyThat(parameters, LibraryClass.class).stubbedUntil(mockLevel));
+        .inspect(
+            inspector ->
+                verifyThat(inspector, parameters, LibraryClass.class).stubbedUntil(mockLevel));
   }
 
   // Only present from api level 23.
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java
index a5f30c2..6c8b93d 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java
@@ -73,9 +73,13 @@
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLinesIf(isMockApiLevel, "ProgramClass::foo")
         .assertSuccessWithOutputLinesIf(!isMockApiLevel, "Hello World")
-        .inspect(verifyThat(parameters, LibraryClass.class).stubbedUntil(lowerMockApiLevel))
-        .inspect(verifyThat(parameters, LibraryInterface.class).stubbedUntil(lowerMockApiLevel))
-        .inspect(verifyThat(parameters, OtherLibraryClass.class).stubbedUntil(mockApiLevel));
+        .inspect(
+            inspector -> {
+              verifyThat(inspector, parameters, LibraryClass.class).stubbedUntil(lowerMockApiLevel);
+              verifyThat(inspector, parameters, LibraryInterface.class)
+                  .stubbedUntil(lowerMockApiLevel);
+              verifyThat(inspector, parameters, OtherLibraryClass.class).stubbedUntil(mockApiLevel);
+            });
   }
 
   // Only present from api level 23.
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoDesugaredLibraryReferenceTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoDesugaredLibraryReferenceTest.java
index e752764..45d2bec 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoDesugaredLibraryReferenceTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoDesugaredLibraryReferenceTest.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.apimodel;
 
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
 import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.TestParameters;
@@ -68,8 +69,10 @@
             parameters.getDexRuntimeVersion().isNewerThan(Version.V7_0_0),
             result -> result.assertSuccessWithOutputLines("~"))
         .inspect(
-            ApiModelingTestHelper.verifyThat(parameters, printZone)
-                .inlinedIntoFromApiLevel(main, AndroidApiLevel.O));
+            inspector -> {
+              verifyThat(inspector, parameters, printZone)
+                  .inlinedIntoFromApiLevel(main, AndroidApiLevel.O);
+            });
   }
 
   static class Executor {
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelInstanceFieldTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelInstanceFieldTest.java
index 9446479..ecbd92e 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelInstanceFieldTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelInstanceFieldTest.java
@@ -54,7 +54,10 @@
         .apply(setMockApiLevelForDefaultInstanceInitializer(Api.class, L_MR1))
         .apply(ApiModelingTestHelper::enableApiCallerIdentification)
         .compile()
-        .inspect(verifyThat(parameters, apiCaller).inlinedIntoFromApiLevel(apiCallerCaller, L_MR1))
+        .inspect(
+            inspector ->
+                verifyThat(inspector, parameters, apiCaller)
+                    .inlinedIntoFromApiLevel(apiCallerCaller, L_MR1))
         .addRunClasspathClasses(Api.class)
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines("Hello World!");
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelInterfaceTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelInterfaceTest.java
index a480188..d39b038 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelInterfaceTest.java
@@ -53,8 +53,9 @@
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines("A::noApiCall", "ApiCaller::callInterfaceMethod")
         .inspect(
-            verifyThat(parameters, apiCaller)
-                .inlinedIntoFromApiLevel(apiCallerCaller, AndroidApiLevel.L_MR1));
+            inspector ->
+                verifyThat(inspector, parameters, apiCaller)
+                    .inlinedIntoFromApiLevel(apiCallerCaller, AndroidApiLevel.L_MR1));
   }
 
   public interface Api {
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelIntoLowerDirectTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelIntoLowerDirectTest.java
index e79cfed..98aa240 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelIntoLowerDirectTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelIntoLowerDirectTest.java
@@ -48,7 +48,8 @@
         .apply(ApiModelingTestHelper::enableApiCallerIdentification)
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines("A::apiLevel21", "B::apiLevel22")
-        .inspect(verifyThat(parameters, apiLevel22).inlinedInto(apiLevel21));
+        .inspect(
+            inspector -> verifyThat(inspector, parameters, apiLevel22).inlinedInto(apiLevel21));
   }
 
   // This tests that program classes where we directly mock the methods to have an api level will
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelStaticFieldTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelStaticFieldTest.java
index 28a2b00..f4465a4 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelStaticFieldTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelStaticFieldTest.java
@@ -51,8 +51,9 @@
         .apply(ApiModelingTestHelper::enableApiCallerIdentification)
         .compile()
         .inspect(
-            verifyThat(parameters, apiCaller)
-                .inlinedIntoFromApiLevel(apiCallerCaller, AndroidApiLevel.L_MR1))
+            inspector ->
+                verifyThat(inspector, parameters, apiCaller)
+                    .inlinedIntoFromApiLevel(apiCallerCaller, AndroidApiLevel.L_MR1))
         .addRunClasspathClasses(Api.class)
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines("Hello World!");
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelStaticTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelStaticTest.java
index b5c7134..16f24fa 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelStaticTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelStaticTest.java
@@ -50,8 +50,9 @@
         .apply(ApiModelingTestHelper::enableApiCallerIdentification)
         .compile()
         .inspect(
-            verifyThat(parameters, apiCaller)
-                .inlinedIntoFromApiLevel(apiCallerCaller, AndroidApiLevel.L_MR1))
+            inspector ->
+                verifyThat(inspector, parameters, apiCaller)
+                    .inlinedIntoFromApiLevel(apiCallerCaller, AndroidApiLevel.L_MR1))
         .addRunClasspathClasses(Api.class)
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines(
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelSuperTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelSuperTest.java
index e1cf2e2..4979620 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelSuperTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelSuperTest.java
@@ -68,7 +68,9 @@
                 }))
         .compile()
         // We do not inline overrides calling super.
-        .inspect(verifyThat(parameters, apiCaller).notInlinedInto(apiCallerCaller))
+        .inspect(
+            inspector ->
+                verifyThat(inspector, parameters, apiCaller).notInlinedInto(apiCallerCaller))
         .addRunClasspathClasses(Api.class)
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines("A::noApiCall", "ApiCaller::apiLevel22", "Api::apiLevel22");
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelVirtualTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelVirtualTest.java
index a366d8a..2311f12 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelVirtualTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfHigherApiLevelVirtualTest.java
@@ -55,8 +55,9 @@
         .apply(ApiModelingTestHelper::enableApiCallerIdentification)
         .compile()
         .inspect(
-            verifyThat(parameters, apiCaller)
-                .inlinedIntoFromApiLevel(apiCallerCaller, AndroidApiLevel.L_MR1))
+            inspector ->
+                verifyThat(inspector, parameters, apiCaller)
+                    .inlinedIntoFromApiLevel(apiCallerCaller, AndroidApiLevel.L_MR1))
         .addRunClasspathClasses(Api.class)
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines(
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfStaticInterfaceMethodsTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfStaticInterfaceMethodsTest.java
index 086cfa4..498ef4c 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfStaticInterfaceMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoInliningOfStaticInterfaceMethodsTest.java
@@ -64,16 +64,17 @@
                 ClassSubject companion = inspector.companionClassFor(ApiCaller.class);
                 assertThat(companion, isPresent());
                 FoundClassSubject foundCompanion = companion.asFoundClassSubject();
-                verifyThat(parameters, callApiLevel22)
+                verifyThat(inspector, parameters, callApiLevel22)
                     .setHolder(foundCompanion)
                     .inlinedIntoFromApiLevel(noApiCallTo22, L_MR1);
-                verifyThat(parameters, callApiLevel26)
+                verifyThat(inspector, parameters, callApiLevel26)
                     .setHolder(foundCompanion)
                     .inlinedIntoFromApiLevel(noApiCallTo26, O);
               } else {
-                verifyThat(parameters, callApiLevel22)
+                verifyThat(inspector, parameters, callApiLevel22)
                     .inlinedIntoFromApiLevel(noApiCallTo22, L_MR1);
-                verifyThat(parameters, callApiLevel26).inlinedIntoFromApiLevel(noApiCallTo26, O);
+                verifyThat(inspector, parameters, callApiLevel26)
+                    .inlinedIntoFromApiLevel(noApiCallTo26, O);
               }
             })
         .addRunClasspathClasses(Api.class)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoMockForOutlineTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoMockForOutlineTest.java
new file mode 100644
index 0000000..a4cbd4b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoMockForOutlineTest.java
@@ -0,0 +1,118 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.apimodel;
+
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer;
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assume.assumeFalse;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.testing.AndroidBuildVersion;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import java.lang.reflect.Method;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ApiModelNoMockForOutlineTest extends TestBase {
+
+  private final AndroidApiLevel classApiLevel = AndroidApiLevel.K;
+  private final AndroidApiLevel methodApiLevel = AndroidApiLevel.M;
+
+  @Parameter public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    assumeFalse(
+        parameters.isDexRuntime() && parameters.getDexRuntimeVersion().isEqualTo(Version.V12_0_0));
+    boolean isMethodApiLevel =
+        parameters.isDexRuntime()
+            && parameters.getApiLevel().isGreaterThanOrEqualTo(methodApiLevel);
+    Method methodOn23 = LibraryClass.class.getDeclaredMethod("methodOn23");
+    Method mainMethod = Main.class.getDeclaredMethod("main", String[].class);
+    testForR8(parameters.getBackend())
+        .addProgramClasses(Main.class)
+        .addLibraryClasses(LibraryClass.class)
+        .addDefaultRuntimeLibrary(parameters)
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(Main.class)
+        .addAndroidBuildVersion()
+        .apply(setMockApiLevelForClass(LibraryClass.class, classApiLevel))
+        .apply(setMockApiLevelForDefaultInstanceInitializer(LibraryClass.class, classApiLevel))
+        .apply(setMockApiLevelForMethod(methodOn23, methodApiLevel))
+        .apply(ApiModelingTestHelper::enableOutliningOfMethods)
+        .apply(ApiModelingTestHelper::enableStubbingOfClasses)
+        .enableInliningAnnotations()
+        .compile()
+        .applyIf(
+            parameters.isDexRuntime()
+                && parameters
+                    .getRuntime()
+                    .maxSupportedApiLevel()
+                    .isGreaterThanOrEqualTo(classApiLevel),
+            b -> b.addBootClasspathClasses(LibraryClass.class))
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLinesIf(!isMethodApiLevel, "Hello World")
+        .assertSuccessWithOutputLinesIf(isMethodApiLevel, "LibraryClass::methodOn23", "Hello World")
+        .inspect(
+            inspector -> {
+              assertThat(inspector.method(mainMethod), isPresent());
+              verifyThat(inspector, parameters, methodOn23)
+                  .isOutlinedFromUntil(mainMethod, methodApiLevel);
+              verifyThat(inspector, parameters, LibraryClass.class).stubbedUntil(classApiLevel);
+              if (parameters.isDexRuntime() && parameters.getApiLevel().isLessThan(classApiLevel)) {
+                // We never trace outlined method for stubs so this holds by default.
+                ClassSubject mockedLibraryClass = inspector.clazz(LibraryClass.class);
+                assertThat(mockedLibraryClass, isPresent());
+                MethodSubject mockedMethodOn23 =
+                    mockedLibraryClass.uniqueMethodWithName("methodOn23");
+                assertThat(mockedMethodOn23, isAbsent());
+              }
+            });
+  }
+
+  // Only present from api level 19.
+  public static class LibraryClass {
+
+    public void methodOn23() {
+      System.out.println("LibraryClass::methodOn23");
+    }
+  }
+
+  public static class Main {
+
+    @NeverInline
+    public static Object create() {
+      return AndroidBuildVersion.VERSION >= 23 ? new LibraryClass() : null;
+    }
+
+    public static void main(String[] args) {
+      Object libraryClass = create();
+      if (libraryClass != null) {
+        ((LibraryClass) libraryClass).methodOn23();
+      }
+      System.out.println("Hello World");
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoOutlineForFullyMockedTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoOutlineForFullyMockedTest.java
new file mode 100644
index 0000000..91c55e4
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoOutlineForFullyMockedTest.java
@@ -0,0 +1,108 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.apimodel;
+
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer;
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assume.assumeFalse;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.testing.AndroidBuildVersion;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.lang.reflect.Method;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ApiModelNoOutlineForFullyMockedTest extends TestBase {
+
+  private final AndroidApiLevel libraryApiLevel = AndroidApiLevel.M;
+
+  @Parameter public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    assumeFalse(
+        parameters.isDexRuntime() && parameters.getDexRuntimeVersion().isEqualTo(Version.V12_0_0));
+    boolean isLibraryApiLevel =
+        parameters.isDexRuntime()
+            && parameters.getApiLevel().isGreaterThanOrEqualTo(libraryApiLevel);
+    Method methodOn23 = LibraryClass.class.getDeclaredMethod("methodOn23");
+    Method mainMethod = Main.class.getDeclaredMethod("main", String[].class);
+    testForR8(parameters.getBackend())
+        .addProgramClasses(Main.class)
+        .addLibraryClasses(LibraryClass.class)
+        .addDefaultRuntimeLibrary(parameters)
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(Main.class)
+        .addAndroidBuildVersion()
+        .apply(setMockApiLevelForClass(LibraryClass.class, libraryApiLevel))
+        .apply(setMockApiLevelForDefaultInstanceInitializer(LibraryClass.class, libraryApiLevel))
+        .apply(setMockApiLevelForMethod(methodOn23, libraryApiLevel))
+        .apply(ApiModelingTestHelper::enableOutliningOfMethods)
+        .apply(ApiModelingTestHelper::enableStubbingOfClasses)
+        .enableInliningAnnotations()
+        .compile()
+        .applyIf(
+            parameters.isDexRuntime()
+                && parameters
+                    .getRuntime()
+                    .maxSupportedApiLevel()
+                    .isGreaterThanOrEqualTo(libraryApiLevel),
+            b -> b.addBootClasspathClasses(LibraryClass.class))
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLinesIf(!isLibraryApiLevel, "Hello World")
+        .assertSuccessWithOutputLinesIf(
+            isLibraryApiLevel, "LibraryClass::methodOn23", "Hello World")
+        .inspect(
+            inspector -> {
+              assertThat(inspector.method(mainMethod), isPresent());
+              // TODO(b/211720912): We should never outline since the library class and method is
+              //  introduced at the same level.
+              verifyThat(inspector, parameters, methodOn23).isNotOutlinedFrom(mainMethod);
+              verifyThat(inspector, parameters, LibraryClass.class).stubbedUntil(libraryApiLevel);
+            });
+  }
+
+  // Only present from api level 23.
+  public static class LibraryClass {
+
+    public void methodOn23() {
+      System.out.println("LibraryClass::methodOn23");
+    }
+  }
+
+  public static class Main {
+
+    @NeverInline
+    public static Object create() {
+      return AndroidBuildVersion.VERSION >= 23 ? new LibraryClass() : null;
+    }
+
+    public static void main(String[] args) {
+      Object libraryClass = create();
+      if (libraryClass != null) {
+        ((LibraryClass) libraryClass).methodOn23();
+      }
+      System.out.println("Hello World");
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineDuplicateMethodTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineDuplicateMethodTest.java
index e0afd34..0760cad 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineDuplicateMethodTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineDuplicateMethodTest.java
@@ -86,7 +86,8 @@
                       : 3;
               assertEquals(classCount, inspector.allClasses().size());
               Method testMethod = TestClass.class.getDeclaredMethod("test");
-              verifyThat(parameters, adeddOn23).isOutlinedFromUntil(testMethod, methodApiLevel);
+              verifyThat(inspector, parameters, adeddOn23)
+                  .isOutlinedFromUntil(testMethod, methodApiLevel);
               if (parameters.isDexRuntime()
                   && parameters.getApiLevel().isLessThan(methodApiLevel)) {
                 // Verify that we invoke the synthesized outline addedOn23 twice.
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodAndStubClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodAndStubClassTest.java
index 051f793..a3e2d46 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodAndStubClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodAndStubClassTest.java
@@ -69,11 +69,13 @@
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLinesIf(libraryClassNotStubbed, "LibraryClass::foo")
         .assertSuccessWithOutputLinesIf(!libraryClassNotStubbed, "Hello World")
-        .inspect(verifyThat(parameters, LibraryClass.class).stubbedUntil(libraryClassLevel))
         .inspect(
-            verifyThat(parameters, apiMethod)
-                .isOutlinedFromUntil(
-                    Main.class.getDeclaredMethod("main", String[].class), libraryMethodLevel));
+            inspector -> {
+              verifyThat(inspector, parameters, LibraryClass.class).stubbedUntil(libraryClassLevel);
+              verifyThat(inspector, parameters, apiMethod)
+                  .isOutlinedFromUntil(
+                      Main.class.getDeclaredMethod("main", String[].class), libraryMethodLevel);
+            });
   }
 
   // Only present from api level 23.
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodMissingClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodMissingClassTest.java
index 9d0f7cf..7755822 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodMissingClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodMissingClassTest.java
@@ -113,10 +113,13 @@
                                       .matches(methodSubject))
                       .findFirst();
               assertFalse(synthesizedMissingNotReferenced.isPresent());
-              verifyThat(parameters, addedOn23).isOutlinedFromUntil(testMethod, AndroidApiLevel.M);
-              verifyThat(parameters, addedOn27)
+              verifyThat(inspector, parameters, addedOn23).isNotOutlinedFrom(testMethod);
+              verifyThat(inspector, parameters, addedOn27)
                   .isOutlinedFromUntil(testMethod, AndroidApiLevel.O_MR1);
-              verifyThat(parameters, LibraryClass.class.getDeclaredMethod("missingAndReferenced"))
+              verifyThat(
+                      inspector,
+                      parameters,
+                      LibraryClass.class.getDeclaredMethod("missingAndReferenced"))
                   .isOutlinedFrom(testMethod);
               if (parameters.getApiLevel().isLessThan(AndroidApiLevel.O_MR1)) {
                 assertEquals(5, inspector.allClasses().size());
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelTypeReferenceInvokeTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelTypeReferenceInvokeTest.java
index ef4737d..25f0c3a 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelTypeReferenceInvokeTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelTypeReferenceInvokeTest.java
@@ -52,8 +52,9 @@
         .addAndroidBuildVersion()
         .compile()
         .inspect(
-            verifyThat(parameters, apiCaller)
-                .inlinedIntoFromApiLevel(apiCallerCaller, AndroidApiLevel.M))
+            inspector ->
+                verifyThat(inspector, parameters, apiCaller)
+                    .inlinedIntoFromApiLevel(apiCallerCaller, AndroidApiLevel.M))
         .addRunClasspathClasses(LibraryClass.class)
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLinesIf(
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java
index 70d4f36..7077a21 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java
@@ -19,7 +19,6 @@
 import com.android.tools.r8.references.MethodReference;
 import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.ThrowingConsumer;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.CodeMatchers;
 import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
@@ -150,49 +149,56 @@
     };
   }
 
-  static ApiModelingClassVerificationHelper verifyThat(TestParameters parameters, Class<?> clazz) {
-    return new ApiModelingClassVerificationHelper(parameters, clazz);
+  static ApiModelingClassVerificationHelper verifyThat(
+      CodeInspector inspector, TestParameters parameters, Class<?> clazz) {
+    return new ApiModelingClassVerificationHelper(inspector, parameters, clazz);
   }
 
-  static ApiModelingMethodVerificationHelper verifyThat(TestParameters parameters, Method method) {
-    return new ApiModelingMethodVerificationHelper(parameters, Reference.methodFromMethod(method));
+  static ApiModelingMethodVerificationHelper verifyThat(
+      CodeInspector inspector, TestParameters parameters, Method method) {
+    return new ApiModelingMethodVerificationHelper(
+        inspector, parameters, Reference.methodFromMethod(method));
   }
 
   public static class ApiModelingClassVerificationHelper {
 
+    private final CodeInspector inspector;
     private final Class<?> classOfInterest;
     private final TestParameters parameters;
 
-    public ApiModelingClassVerificationHelper(TestParameters parameters, Class<?> classOfInterest) {
+    public ApiModelingClassVerificationHelper(
+        CodeInspector inspector, TestParameters parameters, Class<?> classOfInterest) {
+      this.inspector = inspector;
       this.parameters = parameters;
       this.classOfInterest = classOfInterest;
     }
 
-    public ThrowingConsumer<CodeInspector, Exception> stubbedUntil(AndroidApiLevel finalApiLevel) {
-      return inspector -> {
-        assertThat(
-            inspector.clazz(classOfInterest),
-            notIf(
-                isPresent(),
-                parameters.isCfRuntime()
-                    || parameters.getApiLevel().isGreaterThanOrEqualTo(finalApiLevel)));
-      };
+    public void stubbedUntil(AndroidApiLevel finalApiLevel) {
+      assertThat(
+          inspector.clazz(classOfInterest),
+          notIf(
+              isPresent(),
+              parameters.isCfRuntime()
+                  || parameters.getApiLevel().isGreaterThanOrEqualTo(finalApiLevel)));
     }
   }
 
   public static class ApiModelingMethodVerificationHelper {
 
+    private final CodeInspector inspector;
     private final MethodReference methodOfInterest;
     private final TestParameters parameters;
 
     private ApiModelingMethodVerificationHelper(
-        TestParameters parameters, MethodReference methodOfInterest) {
+        CodeInspector inspector, TestParameters parameters, MethodReference methodOfInterest) {
+      this.inspector = inspector;
       this.methodOfInterest = methodOfInterest;
       this.parameters = parameters;
     }
 
     public ApiModelingMethodVerificationHelper setHolder(FoundClassSubject classSubject) {
       return new ApiModelingMethodVerificationHelper(
+          inspector,
           parameters,
           Reference.method(
               classSubject.getFinalReference(),
@@ -201,68 +207,62 @@
               methodOfInterest.getReturnType()));
     }
 
-    ThrowingConsumer<CodeInspector, Exception> inlinedIntoFromApiLevel(
-        Method method, AndroidApiLevel apiLevel) {
-      return parameters.isDexRuntime() && parameters.getApiLevel().isGreaterThanOrEqualTo(apiLevel)
-          ? inlinedInto(method)
-          : notInlinedInto(method);
+    void inlinedIntoFromApiLevel(Method method, AndroidApiLevel apiLevel) {
+      if (parameters.isDexRuntime() && parameters.getApiLevel().isGreaterThanOrEqualTo(apiLevel)) {
+        inlinedInto(method);
+      } else {
+        notInlinedInto(method);
+      }
     }
 
-    ThrowingConsumer<CodeInspector, Exception> notInlinedInto(Method method) {
-      return inspector -> {
-        MethodSubject candidate = inspector.method(methodOfInterest);
-        assertThat(candidate, isPresent());
-        MethodSubject target = inspector.method(method);
-        assertThat(target, isPresent());
-        assertThat(target, CodeMatchers.invokesMethod(candidate));
-      };
+    void notInlinedInto(Method method) {
+      MethodSubject candidate = inspector.method(methodOfInterest);
+      assertThat(candidate, isPresent());
+      MethodSubject target = inspector.method(method);
+      assertThat(target, isPresent());
+      assertThat(target, CodeMatchers.invokesMethod(candidate));
     }
 
-    ThrowingConsumer<CodeInspector, Exception> inlinedInto(Method method) {
-      return inspector -> {
-        MethodSubject candidate = inspector.method(methodOfInterest);
-        if (!candidate.isPresent()) {
-          return;
-        }
-        MethodSubject target = inspector.method(method);
-        assertThat(target, isPresent());
-        assertThat(target, not(CodeMatchers.invokesMethod(candidate)));
-      };
+    void inlinedInto(Method method) {
+      MethodSubject candidate = inspector.method(methodOfInterest);
+      if (!candidate.isPresent()) {
+        return;
+      }
+      MethodSubject target = inspector.method(method);
+      assertThat(target, isPresent());
+      assertThat(target, not(CodeMatchers.invokesMethod(candidate)));
     }
 
-    ThrowingConsumer<CodeInspector, Exception> isOutlinedFromUntil(
-        Method method, AndroidApiLevel apiLevel) {
-      return parameters.isDexRuntime() && parameters.getApiLevel().isLessThan(apiLevel)
-          ? isOutlinedFrom(method)
-          : isNotOutlinedFrom(method);
+    void isOutlinedFromUntil(Method method, AndroidApiLevel apiLevel) {
+      if (parameters.isDexRuntime() && parameters.getApiLevel().isLessThan(apiLevel)) {
+        isOutlinedFrom(method);
+      } else {
+        isNotOutlinedFrom(method);
+      }
     }
 
-    ThrowingConsumer<CodeInspector, Exception> isOutlinedFrom(Method method) {
-      return inspector -> {
-        // Check that the call is in a synthetic class.
-        List<FoundMethodSubject> outlinedMethod =
-            inspector.allClasses().stream()
-                .flatMap(clazz -> clazz.allMethods().stream())
-                .filter(
-                    methodSubject ->
-                        methodSubject.isSynthetic()
-                            && invokesMethodWithName(methodOfInterest.getMethodName())
-                                .matches(methodSubject))
-                .collect(Collectors.toList());
-        assertEquals(1, outlinedMethod.size());
-        // Assert that method invokes the outline
-        MethodSubject caller = inspector.method(method);
-        assertThat(caller, isPresent());
-        assertThat(caller, invokesMethod(outlinedMethod.get(0)));
-      };
+    void isOutlinedFrom(Method method) {
+      // Check that the call is in a synthetic class.
+      List<FoundMethodSubject> outlinedMethod =
+          inspector.allClasses().stream()
+              .flatMap(clazz -> clazz.allMethods().stream())
+              .filter(
+                  methodSubject ->
+                      methodSubject.isSynthetic()
+                          && invokesMethodWithName(methodOfInterest.getMethodName())
+                              .matches(methodSubject))
+              .collect(Collectors.toList());
+      assertEquals(1, outlinedMethod.size());
+      // Assert that method invokes the outline
+      MethodSubject caller = inspector.method(method);
+      assertThat(caller, isPresent());
+      assertThat(caller, invokesMethod(outlinedMethod.get(0)));
     }
 
-    ThrowingConsumer<CodeInspector, Exception> isNotOutlinedFrom(Method method) {
-      return inspector -> {
-        MethodSubject caller = inspector.method(method);
-        assertThat(caller, isPresent());
-        assertThat(caller, invokesMethodWithName(methodOfInterest.getMethodName()));
-      };
+    void isNotOutlinedFrom(Method method) {
+      MethodSubject caller = inspector.method(method);
+      assertThat(caller, isPresent());
+      assertThat(caller, invokesMethodWithName(methodOfInterest.getMethodName()));
     }
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicGetDeclaredMethodsTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicGetDeclaredMethodsTest.java
new file mode 100644
index 0000000..de9685e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicGetDeclaredMethodsTest.java
@@ -0,0 +1,154 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.desugar.constantdynamic;
+
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.DesugarTestConfiguration;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.cf.CfVersion;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.StringUtils;
+import java.io.IOException;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Method;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ConstantDynamicGetDeclaredMethodsTest extends TestBase {
+
+  @Parameter() public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build());
+  }
+
+  private static final String EXPECTED_OUTPUT =
+      StringUtils.lines(
+          "Hello, world!",
+          "myConstant",
+          "3",
+          "java.lang.invoke.MethodHandles$Lookup",
+          "java.lang.String",
+          "java.lang.Class");
+  private static final String EXPECTED_OUTPUT_R8 =
+      StringUtils.lines("Hello, world!", "No myConstant method");
+
+  private static final Class<?> MAIN_CLASS = A.class;
+
+  @Test
+  public void testReference() throws Exception {
+    assumeTrue(parameters.isCfRuntime());
+    assumeTrue(parameters.getRuntime().asCf().isNewerThanOrEqual(CfVm.JDK11));
+    assumeTrue(parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
+
+    testForJvm()
+        .addProgramClassFileData(getTransformedClasses())
+        .run(parameters.getRuntime(), MAIN_CLASS)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
+  }
+
+  @Test
+  public void testDesugaring() throws Exception {
+    testForDesugaring(parameters)
+        .addProgramClassFileData(getTransformedClasses())
+        .run(parameters.getRuntime(), MAIN_CLASS)
+        // TODO(b/210485236): This should never fail.
+        .applyIf(
+            // When not desugaring the CF code requires JDK 11.
+            DesugarTestConfiguration::isNotDesugared,
+            r -> {
+              if (parameters.isCfRuntime()
+                  && parameters.getRuntime().asCf().isNewerThanOrEqual(CfVm.JDK11)) {
+                r.assertSuccessWithOutput(EXPECTED_OUTPUT);
+              } else {
+                r.assertFailureWithErrorThatThrows(UnsupportedClassVersionError.class);
+              }
+            },
+            c ->
+                DesugarTestConfiguration.isDesugared(c)
+                    && parameters.isDexRuntime()
+                    && parameters.asDexRuntime().getVersion().isOlderThan(Version.V8_1_0),
+            r -> r.assertFailureWithErrorThatThrows(ClassNotFoundException.class),
+            r -> r.assertSuccessWithOutput(EXPECTED_OUTPUT));
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    assumeTrue(parameters.isDexRuntime());
+    testForR8(parameters.getBackend())
+        .addProgramClassFileData(getTransformedClasses())
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(MAIN_CLASS)
+        .applyIf(
+            parameters.getApiLevel().isLessThan(AndroidApiLevel.O),
+            b -> b.addDontWarn(MethodHandles.Lookup.class))
+        .run(parameters.getRuntime(), MAIN_CLASS)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT_R8);
+  }
+
+  @Test
+  public void testR8KeepBootstrapMethod() throws Exception {
+    assumeTrue(parameters.isDexRuntime());
+    testForR8(parameters.getBackend())
+        .addProgramClassFileData(getTransformedClasses())
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(MAIN_CLASS)
+        .addKeepMethodRules(MAIN_CLASS, "myConstant(...)")
+        .applyIf(
+            parameters.getApiLevel().isLessThan(AndroidApiLevel.O),
+            b -> b.addDontWarn(MethodHandles.Lookup.class))
+        .run(parameters.getRuntime(), MAIN_CLASS)
+        // TODO(b/210485236): This should never fail.
+        .applyIf(
+            parameters.getDexRuntimeVersion().isOlderThan(Version.V8_1_0),
+            b -> b.assertFailureWithErrorThatThrows(ClassNotFoundException.class),
+            b -> b.assertSuccessWithOutput(EXPECTED_OUTPUT));
+  }
+
+  private byte[] getTransformedClasses() throws IOException {
+    return transformer(A.class)
+        .setVersion(CfVersion.V11)
+        .transformConstStringToConstantDynamic(
+            "condy", A.class, "myConstant", "constantName", Object.class)
+        .transform();
+  }
+
+  public static class A {
+
+    public static Object f() {
+      return "condy"; // Will be transformed to Constant_DYNAMIC.
+    }
+
+    public static void main(String[] args) {
+      System.out.println(f());
+      Method[] methods = A.class.getDeclaredMethods();
+      for (Method method : methods) {
+        if (method.getName().equals("myConstant")) {
+          System.out.println(method.getName());
+          System.out.println(method.getParameterTypes().length);
+          for (int j = 0; j < method.getParameterTypes().length; j++) {
+            System.out.println(method.getParameterTypes()[j].getName());
+          }
+          return;
+        }
+      }
+      System.out.println("No myConstant method");
+    }
+
+    private static Object myConstant(MethodHandles.Lookup lookup, String name, Class<?> type) {
+      return "Hello, world!";
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/JacocoConstantDynamicGetDeclaredMethods.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/JacocoConstantDynamicGetDeclaredMethods.java
new file mode 100644
index 0000000..79fc834
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/JacocoConstantDynamicGetDeclaredMethods.java
@@ -0,0 +1,193 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.desugar.constantdynamic;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.cf.CfVersion;
+import com.android.tools.r8.jacoco.JacocoClasses;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.StringUtils;
+import java.io.IOException;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Method;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class JacocoConstantDynamicGetDeclaredMethods extends TestBase {
+
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimes().withAllApiLevels().build();
+  }
+
+  public static final String jacocoBootstrapMethodName = "$jacocoInit";
+
+  public static JacocoClasses testClasses;
+
+  private static final String MAIN_CLASS = TestRunner.class.getTypeName();
+  private static final String EXPECTED_OUTPUT =
+      StringUtils.lines(
+          jacocoBootstrapMethodName,
+          "3",
+          "java.lang.invoke.MethodHandles$Lookup",
+          "java.lang.String",
+          "java.lang.Class");
+
+  @BeforeClass
+  public static void setUpInput() throws IOException {
+    testClasses = testClasses(getStaticTemp());
+  }
+
+  private void checkJacocoReport(Path agentOutput) throws IOException {
+    // TODO(sgjesse): Need to figure out why there is no instrumentation output for newer VMs.
+    if (parameters.isCfRuntime()
+        || parameters.getRuntime().asDex().getVm().isOlderThanOrEqual(DexVm.ART_4_4_4_HOST)) {
+      assertEquals(2, testClasses.generateReport(agentOutput).size());
+    } else {
+      assertFalse(Files.exists(agentOutput));
+    }
+  }
+
+  @Test
+  public void testJvm() throws Exception {
+    assumeTrue(
+        parameters.isCfRuntime()
+            && (parameters.getRuntime().asCf().isNewerThanOrEqual(CfVm.JDK11)));
+
+    // Run non-instrumented code with an agent causing on the fly instrumentation on the JVM.
+    Path output = temp.newFolder().toPath();
+    Path agentOutputOnTheFly = output.resolve("on-the-fly");
+    testForJvm()
+        .addProgramFiles(testClasses.getOriginal())
+        .enableJaCoCoAgent(ToolHelper.JACOCO_AGENT, agentOutputOnTheFly)
+        .run(parameters.getRuntime(), MAIN_CLASS)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
+    checkJacocoReport(agentOutputOnTheFly);
+
+    // Run the instrumented code.
+    Path agentOutputOffline = output.resolve("offline");
+    testForJvm()
+        .addProgramFiles(testClasses.getInstrumented())
+        .configureJaCoCoAgentForOfflineInstrumentedCode(ToolHelper.JACOCO_AGENT, agentOutputOffline)
+        .run(parameters.getRuntime(), MAIN_CLASS)
+        .assertSuccessWithOutput(EXPECTED_OUTPUT);
+    checkJacocoReport(agentOutputOffline);
+  }
+
+  @Test
+  public void testD8() throws Exception {
+    assumeTrue(parameters.getRuntime().isDex());
+    Path agentOutput = temp.newFolder().toPath().resolve("jacoco.exec");
+    testForD8(parameters.getBackend())
+        .addProgramFiles(testClasses.getInstrumented())
+        .addProgramFiles(ToolHelper.JACOCO_AGENT)
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .runWithJaCoCo(agentOutput, parameters.getRuntime(), MAIN_CLASS)
+        // TODO(b/210485236): This should never fail.
+        .applyIf(
+            parameters.getDexRuntimeVersion().isOlderThan(Version.V8_1_0),
+            b -> b.assertFailureWithErrorThatThrows(ClassNotFoundException.class),
+            b -> b.assertSuccessWithOutput(EXPECTED_OUTPUT));
+    checkJacocoReport(agentOutput);
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    assumeTrue(parameters.getRuntime().isDex());
+    Path agentOutput = temp.newFolder().toPath().resolve("jacoco.exec");
+    testForR8(parameters.getBackend())
+        .addProgramFiles(testClasses.getInstrumented())
+        .addProgramFiles(ToolHelper.JACOCO_AGENT)
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRules(TestRunner.class)
+        .applyIf(
+            parameters.getApiLevel().isLessThan(AndroidApiLevel.O),
+            b -> b.addDontWarn(MethodHandles.Lookup.class))
+        .addDontWarn("java.lang.management.ManagementFactory", "javax.management.**")
+        .compile()
+        .runWithJaCoCo(agentOutput, parameters.getRuntime(), MAIN_CLASS)
+        .inspect(
+            inspector -> {
+              assertThat(
+                  inspector.clazz(TestRunner.class).uniqueMethodWithName(jacocoBootstrapMethodName),
+                  isAbsent());
+            })
+        .assertSuccessWithOutputLines("No " + jacocoBootstrapMethodName + " method");
+    checkJacocoReport(agentOutput);
+  }
+
+  @Test
+  public void testR8KeepingJacocoInit() throws Exception {
+    assumeTrue(parameters.getRuntime().isDex());
+    Path agentOutput = temp.newFolder().toPath().resolve("jacoco.exec");
+    testForR8(parameters.getBackend())
+        .addProgramFiles(testClasses.getInstrumented())
+        .addProgramFiles(ToolHelper.JACOCO_AGENT)
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRules(TestRunner.class)
+        .addKeepRules("-keep class ** { *** " + jacocoBootstrapMethodName + "(...); }")
+        .applyIf(
+            parameters.getApiLevel().isLessThan(AndroidApiLevel.O),
+            b -> b.addDontWarn(MethodHandles.Lookup.class))
+        .addDontWarn(
+            "java.lang.instrument.ClassFileTransformer",
+            "java.lang.management.ManagementFactory",
+            "javax.management.**")
+        .compile()
+        .runWithJaCoCo(agentOutput, parameters.getRuntime(), MAIN_CLASS)
+        // TODO(b/210485236): This should never fail.
+        .applyIf(
+            parameters.getDexRuntimeVersion().isOlderThan(Version.V8_1_0),
+            b -> b.assertFailureWithErrorThatThrows(ClassNotFoundException.class),
+            b -> b.assertSuccessWithOutput(EXPECTED_OUTPUT));
+    checkJacocoReport(agentOutput);
+  }
+
+  private static JacocoClasses testClasses(TemporaryFolder temp) throws IOException {
+    return new JacocoClasses(
+        transformer(TestRunner.class).setVersion(CfVersion.V11).transform(), temp);
+  }
+
+  static class TestRunner {
+
+    public static void main(String[] args) {
+      Method[] methods = TestRunner.class.getDeclaredMethods();
+      for (Method method : methods) {
+        if (method.getName().equals(jacocoBootstrapMethodName)) {
+          System.out.println(method.getName());
+          System.out.println(method.getParameterTypes().length);
+          for (int j = 0; j < method.getParameterTypes().length; j++) {
+            System.out.println(method.getParameterTypes()[j].getName());
+          }
+          return;
+        }
+      }
+      System.out.println("No " + jacocoBootstrapMethodName + " method");
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/JacocoConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/JacocoConstantDynamicTest.java
index 266745e..9c33f50 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/JacocoConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/JacocoConstantDynamicTest.java
@@ -3,9 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.desugar.constantdynamic;
 
-import static com.android.tools.r8.utils.DescriptorUtils.JAVA_PACKAGE_SEPARATOR;
-import static com.android.tools.r8.utils.FileUtils.CLASS_EXTENSION;
-import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assume.assumeTrue;
@@ -15,12 +12,10 @@
 import com.android.tools.r8.TestRuntime.CfVm;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.DexVm;
-import com.android.tools.r8.ToolHelper.ProcessResult;
 import com.android.tools.r8.cf.CfVersion;
+import com.android.tools.r8.jacoco.JacocoClasses;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
-import com.android.tools.r8.utils.ZipUtils;
-import java.io.File;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -141,60 +136,6 @@
         temp);
   }
 
-  // Two sets of class files with and without JaCoCo off line instrumentation.
-  private static class JacocoClasses {
-    private final Path dir;
-
-    private final Path originalJar;
-    private final Path instrumentedJar;
-
-    // Create JacocoClasses with just one class provided as bytes.
-    private JacocoClasses(byte[] clazz, TemporaryFolder temp) throws IOException {
-      dir = temp.newFolder().toPath();
-
-      // Write the class to a .class file with package sub-directories.
-      String typeName = extractClassName(clazz);
-      int lastDotIndex = typeName.lastIndexOf('.');
-      String pkg = typeName.substring(0, lastDotIndex);
-      String baseFileName = typeName.substring(lastDotIndex + 1) + CLASS_EXTENSION;
-      Path original = dir.resolve("original");
-      Files.createDirectories(original);
-      Path packageDir = original.resolve(pkg.replace(JAVA_PACKAGE_SEPARATOR, File.separatorChar));
-      Files.createDirectories(packageDir);
-      Path classFile = packageDir.resolve(baseFileName);
-      Files.write(classFile, clazz);
-
-      // Run offline instrumentation.
-      Path instrumented = dir.resolve("instrumented");
-      Files.createDirectories(instrumented);
-      runJacocoInstrumentation(original, instrumented);
-      originalJar = dir.resolve("original" + JAR_EXTENSION);
-      ZipUtils.zip(originalJar, original);
-      instrumentedJar = dir.resolve("instrumented" + JAR_EXTENSION);
-      ZipUtils.zip(instrumentedJar, instrumented);
-    }
-
-    public Path getOriginal() {
-      return originalJar;
-    }
-
-    public Path getInstrumented() {
-      return instrumentedJar;
-    }
-
-    public List<String> generateReport(Path jacocoExec) throws IOException {
-      Path report = dir.resolve("report.scv");
-      ProcessResult result = ToolHelper.runJaCoCoReport(originalJar, jacocoExec, report);
-      assertEquals(result.toString(), 0, result.exitCode);
-      return Files.readAllLines(report);
-    }
-
-    private void runJacocoInstrumentation(Path input, Path outdir) throws IOException {
-      ProcessResult result = ToolHelper.runJaCoCoInstrument(input, outdir);
-      assertEquals(result.toString(), 0, result.exitCode);
-    }
-  }
-
   static class TestRunner {
 
     public static void main(String[] args) {
diff --git a/src/test/java/com/android/tools/r8/internal/GMSCoreV10Test.java b/src/test/java/com/android/tools/r8/internal/GMSCoreV10Test.java
index 9fe8e54..0622a2a 100644
--- a/src/test/java/com/android/tools/r8/internal/GMSCoreV10Test.java
+++ b/src/test/java/com/android/tools/r8/internal/GMSCoreV10Test.java
@@ -3,11 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.internal;
 
-import static com.android.tools.r8.utils.AssertionUtils.assertNotNull;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.core.AnyOf.anyOf;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.D8TestBuilder;
 import com.android.tools.r8.D8TestCompileResult;
@@ -21,9 +20,7 @@
 import com.google.common.collect.Sets;
 import java.nio.file.Path;
 import java.nio.file.Paths;
-import java.util.Collections;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.Set;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -60,35 +57,36 @@
 
   @Test
   public void testR8Determinism() throws Exception {
-    Map<String, String> idsRoundOne = new ConcurrentHashMap<>();
+    Set<String> idsRoundOne = Sets.newConcurrentHashSet();
     R8TestCompileResult compileResult =
         compileWithR8(
             builder ->
                 builder.addOptionsModification(
                     options ->
                         options.testing.processingContextsConsumer =
-                            id -> assertNull(idsRoundOne.put(id, id))));
+                            id -> assertTrue(idsRoundOne.add(id))));
 
     compileResult.runDex2Oat(parameters.getRuntime()).assertNoVerificationErrors();
 
-    Map<String, String> idsRoundTwo = new ConcurrentHashMap<>();
+    Set<String> idsRoundTwo = Sets.newConcurrentHashSet();
     R8TestCompileResult otherCompileResult =
         compileWithR8(
             builder ->
                 builder.addOptionsModification(
                     options ->
                         options.testing.processingContextsConsumer =
-                            id -> {
-                              assertNotNull(idsRoundOne.get(id));
-                              assertNull(idsRoundTwo.put(id, id));
-                            }));
+                            id -> assertTrue(idsRoundTwo.add(id))));
 
-    // Verify that the result of the two compilations was the same.
-    assertEquals(
-        Collections.emptySet(),
-        Sets.symmetricDifference(idsRoundOne.keySet(), idsRoundTwo.keySet()));
-    assertIdenticalApplications(compileResult.getApp(), otherCompileResult.getApp());
-    assertEquals(compileResult.getProguardMap(), otherCompileResult.getProguardMap());
+    uploadJarsToCloudStorageIfTestFails(
+        (ignored1, ignored2) -> {
+          // Verify that the result of the two compilations was the same.
+          assertEquals(idsRoundOne, idsRoundTwo);
+          assertIdenticalApplications(compileResult.getApp(), otherCompileResult.getApp());
+          assertEquals(compileResult.getProguardMap(), otherCompileResult.getProguardMap());
+          return true;
+        },
+        compileResult.writeToZip(),
+        otherCompileResult.writeToZip());
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InterfaceInvokeWithObjectReceiverInliningTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InterfaceInvokeWithObjectReceiverInliningTest.java
index 8573c7b..cc1ded1 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InterfaceInvokeWithObjectReceiverInliningTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InterfaceInvokeWithObjectReceiverInliningTest.java
@@ -75,7 +75,7 @@
         .setMinApi(parameters.getApiLevel())
         .compile()
         .run(parameters.getRuntime(), Main.class)
-        .assertSuccessWithOutputLines("0");
+        .assertSuccessWithOutputLines("0", "0");
   }
 
   private static byte[] getTransformedMain() throws IOException {
@@ -98,6 +98,13 @@
     public static void main(String[] args) {
       // Transformed from `I get(int)` to `Object get(int)`.
       get(args.length).m();
+
+      // Transformed from `I get(int)` to `Object get(int)`.
+      try {
+        get(args.length).m();
+      } catch (Exception e) {
+        throw new RuntimeException();
+      }
     }
 
     // @Keep
diff --git a/src/test/java/com/android/tools/r8/jacoco/JacocoClasses.java b/src/test/java/com/android/tools/r8/jacoco/JacocoClasses.java
new file mode 100644
index 0000000..b98cc63
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/jacoco/JacocoClasses.java
@@ -0,0 +1,77 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.jacoco;
+
+import static com.android.tools.r8.utils.DescriptorUtils.JAVA_PACKAGE_SEPARATOR;
+import static com.android.tools.r8.utils.FileUtils.CLASS_EXTENSION;
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.utils.ZipUtils;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+import org.junit.rules.TemporaryFolder;
+
+// Two sets of class files with and without JaCoCo offline instrumentation.
+public class JacocoClasses {
+
+  private final TemporaryFolder temp;
+  private final Path dir;
+
+  private final Path originalJar;
+  private final Path instrumentedJar;
+
+  // Create JacocoClasses with just one class provided as bytes.
+  public JacocoClasses(byte[] clazz, TemporaryFolder temp) throws IOException {
+    this.temp = temp;
+    dir = temp.newFolder().toPath();
+
+    // Write the class to a .class file with package sub-directories.
+    String typeName = TestBase.extractClassName(clazz);
+    int lastDotIndex = typeName.lastIndexOf('.');
+    String pkg = typeName.substring(0, lastDotIndex);
+    String baseFileName = typeName.substring(lastDotIndex + 1) + CLASS_EXTENSION;
+    Path original = dir.resolve("original");
+    Files.createDirectories(original);
+    Path packageDir = original.resolve(pkg.replace(JAVA_PACKAGE_SEPARATOR, File.separatorChar));
+    Files.createDirectories(packageDir);
+    Path classFile = packageDir.resolve(baseFileName);
+    Files.write(classFile, clazz);
+
+    // Run offline instrumentation.
+    Path instrumented = dir.resolve("instrumented");
+    Files.createDirectories(instrumented);
+    runJacocoInstrumentation(original, instrumented);
+    originalJar = dir.resolve("original" + JAR_EXTENSION);
+    ZipUtils.zip(originalJar, original);
+    instrumentedJar = dir.resolve("instrumented" + JAR_EXTENSION);
+    ZipUtils.zip(instrumentedJar, instrumented);
+  }
+
+  public Path getOriginal() {
+    return originalJar;
+  }
+
+  public Path getInstrumented() {
+    return instrumentedJar;
+  }
+
+  public List<String> generateReport(Path jacocoExec) throws IOException {
+    Path report = temp.newFolder().toPath().resolve("report.scv");
+    ProcessResult result = ToolHelper.runJaCoCoReport(originalJar, jacocoExec, report);
+    assertEquals(result.toString(), 0, result.exitCode);
+    return Files.readAllLines(report);
+  }
+
+  private void runJacocoInstrumentation(Path input, Path outdir) throws IOException {
+    ProcessResult result = ToolHelper.runJaCoCoInstrument(input, outdir);
+    assertEquals(result.toString(), 0, result.exitCode);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAllowAccessModificationTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAllowAccessModificationTest.java
index 21c1cce..29b0027 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAllowAccessModificationTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAllowAccessModificationTest.java
@@ -121,6 +121,7 @@
             .addSourceFiles(
                 getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
             .setOutputPath(temp.newFolder().toPath())
+            .disableAssertions()
             .compileRaw();
     assertEquals(1, mainResult.exitCode);
     assertThat(mainResult.stderr, containsString("cannot access 'LibReference'"));
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineBlockTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineBlockTest.java
new file mode 100644
index 0000000..5396f4d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineBlockTest.java
@@ -0,0 +1,86 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.kotlin.metadata;
+
+import com.android.tools.r8.KotlinTestParameters;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.StringUtils;
+import java.nio.file.Path;
+import java.util.Collection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class MetadataRewriteCrossinlineBlockTest extends KotlinMetadataTestBase {
+
+  private final String EXPECTED =
+      StringUtils.lines(
+          "foo", "42", "42", "0", "42", "42", "42", "42", "42", "42", "42", "42", "42", "42", "42",
+          "42", "42", "42", "42", "42", "42", "42", "42", "42", "42", "42", "42", "42", "42", "42",
+          "42", "42", "42", "42");
+  private static final String PKG_LIB = PKG + ".crossinline_block_lib";
+  private static final String PKG_APP = PKG + ".crossinline_block_app";
+
+  @Parameterized.Parameters(name = "{0}, {1}")
+  public static Collection<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withCfRuntimes().build(),
+        getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
+  }
+
+  public MetadataRewriteCrossinlineBlockTest(
+      TestParameters parameters, KotlinTestParameters kotlinParameters) {
+    super(kotlinParameters);
+    this.parameters = parameters;
+  }
+
+  private static final KotlinCompileMemoizer libJars =
+      getCompileMemoizer(
+          getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib"));
+  private final TestParameters parameters;
+
+  @Test
+  public void smokeTest() throws Exception {
+    Path libJar = libJars.getForConfiguration(kotlinc, targetVersion);
+    Path output =
+        kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
+            .addClasspathFiles(libJar)
+            .addSourceFiles(
+                getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
+            .setOutputPath(temp.newFolder().toPath())
+            .compile();
+    testForJvm()
+        .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
+        .addClasspath(output)
+        .run(parameters.getRuntime(), PKG_APP + ".MainKt")
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  @Test
+  public void testMetadataForLib() throws Exception {
+    Path libJar =
+        testForR8Compat(parameters.getBackend())
+            .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
+            .addClasspathFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinAnnotationJar())
+            .addKeepAllClassesRule()
+            .addKeepAllAttributes()
+            .compile()
+            .writeToZip();
+    Path output =
+        kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
+            .addClasspathFiles(libJar)
+            .addSourceFiles(
+                getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
+            .setOutputPath(temp.newFolder().toPath())
+            .compile();
+    testForJvm()
+        .addRunClasspathFiles(kotlinc.getKotlinStdlibJar(), libJar)
+        .addClasspath(output)
+        .run(parameters.getRuntime(), PKG_APP + ".MainKt")
+        .assertSuccessWithOutput(EXPECTED);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/crossinline_block_app/main.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/crossinline_block_app/main.kt
new file mode 100644
index 0000000..b349233
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/crossinline_block_app/main.kt
@@ -0,0 +1,22 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.kotlin.metadata.crossinline_block_app
+
+import com.android.tools.r8.kotlin.metadata.crossinline_block_lib.bar
+import com.android.tools.r8.kotlin.metadata.crossinline_block_lib.foo
+
+fun main(args : Array<String>) {
+  if (args.isEmpty()) {
+    call("foo")
+    bar(bar3 = 0)
+  } else {
+    call("bar")
+  }
+}
+
+fun call(name: String) {
+  foo { name }
+  println(name)
+}
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/crossinline_block_lib/lib.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/crossinline_block_lib/lib.kt
new file mode 100644
index 0000000..d7efaaf
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/crossinline_block_lib/lib.kt
@@ -0,0 +1,82 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.kotlin.metadata.crossinline_block_lib
+
+public inline fun foo(
+  bar: String? = null,
+  crossinline block: () -> String? = { null }
+) {
+  block()
+}
+
+public inline fun bar(
+  bar1: Int = 42,
+  bar2: Int = 42,
+  bar3: Int = 42,
+  bar4: Int = 42,
+  bar5: Int = 42,
+  bar6: Int = 42,
+  bar7: Int = 42,
+  bar8: Int = 42,
+  bar9: Int = 42,
+  bar10: Int = 42,
+  bar11: Int = 42,
+  bar12: Int = 42,
+  bar13: Int = 42,
+  bar14: Int = 42,
+  bar15: Int = 42,
+  bar16: Int = 42,
+  bar17: Int = 42,
+  bar18: Int = 42,
+  bar19: Int = 42,
+  bar20: Int = 42,
+  bar21: Int = 42,
+  bar22: Int = 42,
+  bar23: Int = 42,
+  bar24: Int = 42,
+  bar25: Int = 42,
+  bar26: Int = 42,
+  bar27: Int = 42,
+  bar28: Int = 42,
+  bar29: Int = 42,
+  bar30: Int = 42,
+  bar31: Int = 42,
+  bar32: Int = 42,
+  bar33: Int = 42
+) {
+  println(bar1)
+  println(bar2)
+  println(bar3)
+  println(bar4)
+  println(bar5)
+  println(bar6)
+  println(bar7)
+  println(bar8)
+  println(bar9)
+  println(bar10)
+  println(bar11)
+  println(bar12)
+  println(bar13)
+  println(bar14)
+  println(bar15)
+  println(bar16)
+  println(bar17)
+  println(bar18)
+  println(bar19)
+  println(bar20)
+  println(bar21)
+  println(bar22)
+  println(bar23)
+  println(bar24)
+  println(bar25)
+  println(bar26)
+  println(bar27)
+  println(bar28)
+  println(bar29)
+  println(bar30)
+  println(bar31)
+  println(bar32)
+  println(bar33)
+}
\ No newline at end of file
diff --git a/tools/run_on_app.py b/tools/run_on_app.py
index 440cd97..50dba8d 100755
--- a/tools/run_on_app.py
+++ b/tools/run_on_app.py
@@ -740,7 +740,16 @@
   if options.print_dexsegments:
     dex_files = glob(os.path.join(outdir, '*.dex'))
     utils.print_dexsegments(options.print_dexsegments, dex_files)
+    if not options.golem:
+      print('{}-Total(CodeSize): {}'.format(
+              options.print_dexsegments, compute_size_of_dex_files(dex_files)))
   return 0
 
+def compute_size_of_dex_files(dex_files):
+  dex_size = 0
+  for dex_file in dex_files:
+    dex_size += os.path.getsize(dex_file)
+  return dex_size
+
 if __name__ == '__main__':
   sys.exit(main(sys.argv[1:]))