Harden assertion configuration analysis to allow input stack maps

Change-Id: I871a48c1474cd083e5939f080a1ca55affe92efe
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFrame.java b/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
index 72f5be9..f1058d6 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
@@ -76,6 +76,16 @@
     private FrameType() {}
   }
 
+  @Override
+  public boolean isFrame() {
+    return true;
+  }
+
+  @Override
+  public CfFrame asFrame() {
+    return this;
+  }
+
   private static class InitializedType extends FrameType {
 
     private final DexType type;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
index 05f1181..041409b 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
@@ -87,6 +87,14 @@
     return false;
   }
 
+  public CfFrame asFrame() {
+    return null;
+  }
+
+  public boolean isFrame() {
+    return false;
+  }
+
   public CfPosition asPosition() {
     return null;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/ClassInitializerAssertionEnablingAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/ClassInitializerAssertionEnablingAnalysis.java
index 6b03d33..c57a3da 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/ClassInitializerAssertionEnablingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/ClassInitializerAssertionEnablingAnalysis.java
@@ -167,8 +167,8 @@
         i < code.instructions.size() && nextExpectedInstructionIndex < sequence.size();
         i++) {
       instruction = code.instructions.get(i);
-      if (instruction.isLabel()) {
-        // Just ignore labels.
+      if (instruction.isLabel() || instruction.isFrame()) {
+        // Just ignore labels and frames.
         continue;
       }
       if (instruction.getClass() != sequence.get(nextExpectedInstructionIndex)) {
diff --git a/src/test/java/com/android/tools/r8/TestBuilder.java b/src/test/java/com/android/tools/r8/TestBuilder.java
index e9ac10d..21ab2b1 100644
--- a/src/test/java/com/android/tools/r8/TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestBuilder.java
@@ -12,7 +12,6 @@
 import java.util.Collection;
 import java.util.List;
 import java.util.concurrent.ExecutionException;
-import java.util.function.Consumer;
 
 public abstract class TestBuilder<RR extends TestRunResult, T extends TestBuilder<RR, T>> {
 
@@ -39,10 +38,21 @@
     return self();
   }
 
-  public T ifTrue(boolean value, Consumer<T> consumer) {
+  public T applyIf(boolean value, ThrowableConsumer<T> consumer) {
     T self = self();
     if (value) {
-      consumer.accept(self);
+      consumer.acceptWithRuntimeException(self);
+    }
+    return self;
+  }
+
+  public T applyIf(
+      boolean value, ThrowableConsumer<T> trueConsumer, ThrowableConsumer<T> falseConsumer) {
+    T self = self();
+    if (value) {
+      trueConsumer.acceptWithRuntimeException(self);
+    } else {
+      falseConsumer.acceptWithRuntimeException(self);
     }
     return self;
   }
diff --git a/src/test/java/com/android/tools/r8/code/PassThroughTest.java b/src/test/java/com/android/tools/r8/code/PassThroughTest.java
index 30b8b6e..673f3a2 100644
--- a/src/test/java/com/android/tools/r8/code/PassThroughTest.java
+++ b/src/test/java/com/android/tools/r8/code/PassThroughTest.java
@@ -69,7 +69,7 @@
         .addProgramClasses(Main.class)
         .addKeepAllClassesRule()
         .enableInliningAnnotations()
-        .ifTrue(keepDebug, TestShrinkerBuilder::addKeepAllAttributes)
+        .applyIf(keepDebug, TestShrinkerBuilder::addKeepAllAttributes)
         .compile()
         .writeToZip(outputJar)
         .run(parameters.getRuntime(), Main.class)
@@ -86,7 +86,7 @@
         .addProgramClasses(Main.class)
         .addKeepAllClassesRule()
         .enableInliningAnnotations()
-        .ifTrue(keepDebug, TestShrinkerBuilder::addKeepAllAttributes)
+        .applyIf(keepDebug, TestShrinkerBuilder::addKeepAllAttributes)
         .addOptionsModification(
             internalOptions -> {
               internalOptions.testing.cfByteCodePassThrough =
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepPathTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepPathTest.java
index b8c4186..600ff8e 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepPathTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepPathTest.java
@@ -67,7 +67,7 @@
         .addProgramFiles(libJars.get(targetVersion))
         .addProgramFiles(ToolHelper.getKotlinStdlibJar())
         .addKeepRules("-keep class " + LIB_CLASS_NAME)
-        .ifTrue(keepMetadata, TestShrinkerBuilder::addKeepKotlinMetadata)
+        .applyIf(keepMetadata, TestShrinkerBuilder::addKeepKotlinMetadata)
         .addKeepRuntimeVisibleAnnotations()
         .allowDiagnosticWarningMessages()
         .compile()
@@ -81,7 +81,7 @@
         .addProgramFiles(libJars.get(targetVersion))
         .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
         .addKeepRules("-keep class " + LIB_CLASS_NAME)
-        .ifTrue(keepMetadata, TestShrinkerBuilder::addKeepKotlinMetadata)
+        .applyIf(keepMetadata, TestShrinkerBuilder::addKeepKotlinMetadata)
         .addKeepRuntimeVisibleAnnotations()
         .compile()
         .inspect(inspector -> inspect(inspector, keepMetadata));
@@ -94,7 +94,7 @@
         .addLibraryFiles(ToolHelper.getKotlinStdlibJar())
         .addLibraryFiles(ToolHelper.getJava8RuntimeJar())
         .addKeepRules("-keep class " + LIB_CLASS_NAME)
-        .ifTrue(keepMetadata, TestShrinkerBuilder::addKeepKotlinMetadata)
+        .applyIf(keepMetadata, TestShrinkerBuilder::addKeepKotlinMetadata)
         .addKeepRuntimeVisibleAnnotations()
         .compile()
         .inspect(inspector -> inspect(inspector, keepMetadata));
diff --git a/src/test/java/com/android/tools/r8/naming/DontUseMixedCaseClassNamesExistingClassTest.java b/src/test/java/com/android/tools/r8/naming/DontUseMixedCaseClassNamesExistingClassTest.java
index b16347d..6804b54 100644
--- a/src/test/java/com/android/tools/r8/naming/DontUseMixedCaseClassNamesExistingClassTest.java
+++ b/src/test/java/com/android/tools/r8/naming/DontUseMixedCaseClassNamesExistingClassTest.java
@@ -51,7 +51,7 @@
         .addKeepClassRulesWithAllowObfuscation(A.class)
         .addKeepMainRule(Main.class)
         .addKeepRules("-classobfuscationdictionary " + dictionary.toString())
-        .ifTrue(dontUseMixedCase, b -> b.addKeepRules("-dontusemixedcaseclassnames"))
+        .applyIf(dontUseMixedCase, b -> b.addKeepRules("-dontusemixedcaseclassnames"))
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines(EXPECTED)
         .inspect(
diff --git a/src/test/java/com/android/tools/r8/naming/b155249069/DontUseMixedCaseClassNamesExistingClassPackageTest.java b/src/test/java/com/android/tools/r8/naming/b155249069/DontUseMixedCaseClassNamesExistingClassPackageTest.java
index a55ef4b..f662aa6 100644
--- a/src/test/java/com/android/tools/r8/naming/b155249069/DontUseMixedCaseClassNamesExistingClassPackageTest.java
+++ b/src/test/java/com/android/tools/r8/naming/b155249069/DontUseMixedCaseClassNamesExistingClassPackageTest.java
@@ -54,7 +54,7 @@
         .addKeepClassRulesWithAllowObfuscation(A.class)
         .addKeepMainRule(Main.class)
         .addKeepRules("-packageobfuscationdictionary " + packageDictionary.toString())
-        .ifTrue(dontUseMixedCase, b -> b.addKeepRules("-dontusemixedcaseclassnames"))
+        .applyIf(dontUseMixedCase, b -> b.addKeepRules("-dontusemixedcaseclassnames"))
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines("A.A.foo()", "package_b.B.foo()")
         .inspect(
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinTest.java b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinTest.java
index 873788c..a0049f4 100644
--- a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinTest.java
@@ -183,38 +183,27 @@
       boolean enableJvmAssertions)
       throws Exception {
 
-    if (kotlinStdlibAsLibrary) {
-      testForR8(parameters.getBackend())
-          .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
-          .addProgramFiles(kotlinClasses.get(kotlinCompilationKey))
-          .addKeepMainRule(testClassKt)
-          .addKeepClassAndMembersRules(class1, class2)
-          .setMinApi(parameters.getApiLevel())
-          .apply(builderConsumer)
-          .noMinification()
-          .addRunClasspathFiles(kotlinStdlibLibraryForRuntime())
-          .compile()
-          .enableRuntimeAssertions(enableJvmAssertions)
-          .run(parameters.getRuntime(), testClassKt)
-          .inspect(inspector)
-          .assertSuccessWithOutputLines(outputLines);
-    } else {
-      testForR8(parameters.getBackend())
-          .addProgramFiles(ToolHelper.getKotlinStdlibJar())
-          .addProgramFiles(kotlinClasses.get(kotlinCompilationKey))
-          .addKeepMainRule(testClassKt)
-          .addKeepClassAndMembersRules(class1, class2)
-          .setMinApi(parameters.getApiLevel())
-          .apply(builderConsumer)
-          .noMinification()
-          .allowDiagnosticWarningMessages()
-          .compile()
-          .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
-          .enableRuntimeAssertions(enableJvmAssertions)
-          .run(parameters.getRuntime(), testClassKt)
-          .inspect(inspector)
-          .assertSuccessWithOutputLines(outputLines);
-    }
+    testForR8(parameters.getBackend())
+        .applyIf(
+            kotlinStdlibAsLibrary,
+            b -> {
+              b.addClasspathFiles(ToolHelper.getKotlinStdlibJar());
+              b.addRunClasspathFiles(kotlinStdlibLibraryForRuntime());
+            },
+            b -> b.addProgramFiles(ToolHelper.getKotlinStdlibJar()))
+        .addProgramFiles(kotlinClasses.get(kotlinCompilationKey))
+        .addKeepMainRule(testClassKt)
+        .addKeepClassAndMembersRules(class1, class2)
+        .setMinApi(parameters.getApiLevel())
+        .apply(builderConsumer)
+        .allowDiagnosticWarningMessages(!kotlinStdlibAsLibrary)
+        .addRunClasspathFiles(kotlinStdlibLibraryForRuntime())
+        .compile()
+        .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
+        .enableRuntimeAssertions(enableJvmAssertions)
+        .run(parameters.getRuntime(), testClassKt)
+        .inspect(inspector)
+        .assertSuccessWithOutputLines(outputLines);
   }
 
   private List<String> allAssertionsExpectedLines() {
@@ -484,7 +473,30 @@
   }
 
   @Test
-  public void testAssertionsForCf() throws Exception {
+  public void testAssertionsForCfEnableWithStackMap() throws Exception {
+    Assume.assumeTrue(parameters.isCfRuntime());
+    Assume.assumeTrue(useJvmAssertions);
+    Assume.assumeTrue(kotlinCompilationKey.targetVersion == KotlinTargetVersion.JAVA_8);
+    // Compile time enabling or disabling assertions means the -ea flag has no effect.
+    runR8Test(
+        builder -> {
+          builder.addAssertionsConfiguration(AssertionsConfiguration.Builder::enableAllAssertions);
+          builder.addOptionsModification(options -> options.testing.readInputStackMaps = true);
+        },
+        inspector -> checkAssertionCodeEnabled(inspector, true),
+        allAssertionsExpectedLines());
+    runR8Test(
+        builder -> {
+          builder.addAssertionsConfiguration(AssertionsConfiguration.Builder::enableAllAssertions);
+          builder.addOptionsModification(options -> options.testing.readInputStackMaps = true);
+        },
+        inspector -> checkAssertionCodeEnabled(inspector, true),
+        allAssertionsExpectedLines(),
+        true);
+  }
+
+  @Test
+  public void testAssertionsForCfPassThrough() throws Exception {
     Assume.assumeTrue(parameters.isCfRuntime());
     // Leaving assertion code means assertions are controlled by the -ea flag.
     runR8Test(
@@ -500,6 +512,11 @@
         inspector -> checkAssertionCodeLeft(inspector, true),
         allAssertionsExpectedLines(),
         true);
+  }
+
+  @Test
+  public void testAssertionsForCfEnable() throws Exception {
+    Assume.assumeTrue(parameters.isCfRuntime());
     // Compile time enabling or disabling assertions means the -ea flag has no effect.
     runR8Test(
         builder ->
@@ -514,6 +531,11 @@
         inspector -> checkAssertionCodeEnabled(inspector, true),
         allAssertionsExpectedLines(),
         true);
+  }
+
+  @Test
+  public void testAssertionsForCfDisable() throws Exception {
+    Assume.assumeTrue(parameters.isCfRuntime());
     runR8Test(
         builder ->
             builder.addAssertionsConfiguration(