Enable CF for NeverReturnsNormallyTest.

Change-Id: Ic4e317c1a5a4bf92451c3adb11a47dfc153a9e07
diff --git a/src/test/java/com/android/tools/r8/neverreturnsnormally/NeverReturnsNormallyTest.java b/src/test/java/com/android/tools/r8/neverreturnsnormally/NeverReturnsNormallyTest.java
index 1251972..9350f2b 100644
--- a/src/test/java/com/android/tools/r8/neverreturnsnormally/NeverReturnsNormallyTest.java
+++ b/src/test/java/com/android/tools/r8/neverreturnsnormally/NeverReturnsNormallyTest.java
@@ -7,13 +7,16 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import com.android.tools.r8.ClassFileConsumer;
 import com.android.tools.r8.CompilationMode;
 import com.android.tools.r8.DexIndexedConsumer;
 import com.android.tools.r8.R8Command;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.cf.code.CfStackInstruction.Opcode;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.dexinspector.CfInstructionSubject;
 import com.android.tools.r8.utils.dexinspector.ClassSubject;
 import com.android.tools.r8.utils.dexinspector.DexInspector;
 import com.android.tools.r8.utils.dexinspector.DexInstructionSubject;
@@ -22,17 +25,43 @@
 import com.android.tools.r8.utils.dexinspector.InvokeInstructionSubject;
 import com.android.tools.r8.utils.dexinspector.MethodSubject;
 import com.google.common.collect.ImmutableList;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.Iterator;
 import java.util.function.BiConsumer;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
 
+@RunWith(Parameterized.class)
 public class NeverReturnsNormallyTest extends TestBase {
+
+  private Backend backend;
+
+  @Parameters(name = "Backend: {0}")
+  public static Collection<Backend> data() {
+    return Arrays.asList(Backend.values());
+  }
+
+  public NeverReturnsNormallyTest(Backend backend) {
+    this.backend = backend;
+  }
+
   private void runTest(
       BiConsumer<DexInspector, CompilationMode> inspection,
       boolean enableClassInliner, CompilationMode mode) throws Exception {
     R8Command.Builder builder = R8Command.builder();
     builder.addProgramFiles(ToolHelper.getClassFileForTestClass(TestClass.class));
-    builder.setProgramConsumer(DexIndexedConsumer.emptyConsumer());
+    assert (backend == Backend.DEX || backend == Backend.CF);
+    builder.setProgramConsumer(
+        backend == Backend.DEX
+            ? DexIndexedConsumer.emptyConsumer()
+            : ClassFileConsumer.emptyConsumer());
+    builder.addLibraryFiles(
+        backend == Backend.DEX
+            ? ToolHelper.getDefaultAndroidJar()
+            : ToolHelper.getJava8RuntimeJar());
     builder.setMode(mode);
     builder.addProguardConfiguration(
         ImmutableList.of(
@@ -48,18 +77,28 @@
             "}",
             "",
             "-dontobfuscate",
-            "-allowaccessmodification"
-        ),
+            "-allowaccessmodification"),
         Origin.unknown());
-    AndroidApp app = ToolHelper.runR8(builder.build(),
-        opts -> opts.enableClassInlining = enableClassInliner);
-    inspection.accept(new DexInspector(app), mode);
+    AndroidApp app =
+        ToolHelper.runR8(builder.build(), opts -> opts.enableClassInlining = enableClassInliner);
+    inspection.accept(
+        new DexInspector(
+            app,
+            options -> {
+              options.enableCfFrontend = true;
+            }),
+        mode);
 
-    // Run on Art to check generated code against verifier.
-    runOnArt(app, TestClass.class);
+    if (backend == Backend.DEX) {
+      // Run on Art to check generated code against verifier.
+      runOnArt(app, TestClass.class);
+    } else {
+      runOnJava(app, TestClass.class);
+    }
   }
 
   private void validate(DexInspector inspector, CompilationMode mode) {
+    assert (backend == Backend.DEX || backend == Backend.CF);
     ClassSubject clazz = inspector.clazz(TestClass.class);
     assertTrue(clazz.isPresent());
 
@@ -79,39 +118,34 @@
     assertTrue(methodThrowToBeInlined.isPresent());
     Iterator<InstructionSubject> instructions = methodThrowToBeInlined.iterateInstructions();
     // Call, followed by throw null.
-    assertTrue(nextInstruction(instructions).isConstString(JumboStringMode.ALLOW));
-    InstructionSubject insn = nextInstruction(instructions);
+    InstructionSubject insn = nextInstructionSkippingCfPositionAndLabel(instructions);
+    assertTrue(insn != null && insn.isConstString(JumboStringMode.ALLOW));
+    insn = nextInstruction(instructions);
     assertTrue(insn.isInvoke());
     assertTrue(((InvokeInstructionSubject) insn)
         .invokedMethod().name.toString().equals("throwNpe"));
-    insn = nextInstruction(instructions);
-    assertTrue(insn instanceof DexInstructionSubject && ((DexInstructionSubject) insn).isConst4());
-    assertTrue(nextInstruction(instructions).isThrow());
-    assertFalse(instructions.hasNext());
+    verifyTrailingPattern(instructions);
 
     // Check the instruction used for testInlinedIntoVoidMethod
     MethodSubject methodTestInlinedIntoVoidMethod =
         clazz.method("void", "testInlinedIntoVoidMethod", ImmutableList.of());
     assertTrue(methodTestInlinedIntoVoidMethod.isPresent());
     instructions = methodTestInlinedIntoVoidMethod.iterateInstructions();
+    insn = nextInstructionSkippingCfPositionAndLabel(instructions);
     if (mode == CompilationMode.DEBUG) {
       // Not inlined call to throwToBeInlined.
-      insn = nextInstruction(instructions);
       assertTrue(insn.isInvoke());
       assertTrue(((InvokeInstructionSubject) insn)
           .invokedMethod().name.toString().equals("throwToBeInlined"));
     } else {
       // Inlined code from throwToBeInlined.
-      assertTrue(nextInstruction(instructions).isConstString(JumboStringMode.ALLOW));
+      assertTrue(insn.isConstString(JumboStringMode.ALLOW));
       insn = nextInstruction(instructions);
       assertTrue(insn.isInvoke());
       assertTrue(((InvokeInstructionSubject) insn)
           .invokedMethod().name.toString().equals("throwNpe"));
     }
-    insn = nextInstruction(instructions);
-    assertTrue(insn instanceof DexInstructionSubject && ((DexInstructionSubject) insn).isConst4());
-    assertTrue(nextInstruction(instructions).isThrow());
-    assertFalse(instructions.hasNext());
+    verifyTrailingPattern(instructions);
 
     // Check the instruction used for testInlinedIntoVoidMethod
     MethodSubject methodOuterTrivial =
@@ -119,14 +153,11 @@
     assertTrue(methodOuterTrivial.isPresent());
     instructions = methodOuterTrivial.iterateInstructions();
     // Call, followed by [nop, goto]
-    insn = nextInstruction(instructions);
+    insn = nextInstructionSkippingCfPositionAndLabel(instructions);
     assertTrue(insn.isInvoke());
     assertTrue(((InvokeInstructionSubject) insn)
         .invokedMethod().name.toString().equals("innerNotReachable"));
-    insn = nextInstruction(instructions);
-    assertTrue(insn instanceof DexInstructionSubject && ((DexInstructionSubject) insn).isConst4());
-    assertTrue(nextInstruction(instructions).isThrow());
-    assertFalse(instructions.hasNext());
+    verifyTrailingPattern(instructions);
   }
 
   private InstructionSubject nextInstruction(Iterator<InstructionSubject> instructions) {
@@ -134,6 +165,39 @@
     return instructions.next();
   }
 
+  private InstructionSubject nextInstructionSkippingCfPositionAndLabel(
+      Iterator<InstructionSubject> instructions) {
+    InstructionSubject insn = null;
+    while (instructions.hasNext()) {
+      insn = instructions.next();
+      if (!(insn instanceof CfInstructionSubject)) {
+        break;
+      }
+      CfInstructionSubject cfInsn = (CfInstructionSubject) insn;
+      if (!cfInsn.isLabel() && !cfInsn.isPosition()) {
+        break;
+      }
+    }
+    return insn;
+  }
+
+  private void verifyTrailingPattern(Iterator<InstructionSubject> instructions) {
+    InstructionSubject insn = nextInstruction(instructions);
+    if (backend == Backend.DEX) {
+      assertTrue(
+          insn instanceof DexInstructionSubject && ((DexInstructionSubject) insn).isConst4());
+    } else {
+      assertTrue(insn instanceof CfInstructionSubject);
+      assertTrue(((CfInstructionSubject) insn).isStackInstruction(Opcode.Pop));
+      assertTrue(instructions.hasNext());
+      insn = instructions.next();
+      assertTrue(insn instanceof CfInstructionSubject);
+      assertTrue(((CfInstructionSubject) insn).isConstNull());
+    }
+    assertTrue(nextInstruction(instructions).isThrow());
+    assertFalse(instructions.hasNext());
+  }
+
   @Test
   public void test() throws Exception {
     runTest(this::validate, true, CompilationMode.DEBUG);
diff --git a/src/test/java/com/android/tools/r8/utils/dexinspector/CfInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/dexinspector/CfInstructionSubject.java
index 3e74981..cfc07f7 100644
--- a/src/test/java/com/android/tools/r8/utils/dexinspector/CfInstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/dexinspector/CfInstructionSubject.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.utils.dexinspector;
 
+import com.android.tools.r8.cf.code.CfConstNull;
 import com.android.tools.r8.cf.code.CfConstString;
 import com.android.tools.r8.cf.code.CfFieldInstruction;
 import com.android.tools.r8.cf.code.CfGoto;
@@ -16,6 +17,7 @@
 import com.android.tools.r8.cf.code.CfNop;
 import com.android.tools.r8.cf.code.CfPosition;
 import com.android.tools.r8.cf.code.CfReturnVoid;
+import com.android.tools.r8.cf.code.CfStackInstruction;
 import com.android.tools.r8.cf.code.CfThrow;
 import org.objectweb.asm.Opcodes;
 
@@ -117,6 +119,15 @@
     return instruction instanceof CfPosition;
   }
 
+  public boolean isStackInstruction(CfStackInstruction.Opcode opcode) {
+    return instruction instanceof CfStackInstruction
+        && ((CfStackInstruction) instruction).getOpcode() == opcode;
+  }
+
+  public boolean isConstNull() {
+    return instruction instanceof CfConstNull;
+  }
+
   public boolean isIfNull() {
     return instruction instanceof CfIf && ((CfIf) instruction).getOpcode() == Opcodes.IFNULL;
   }