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;
}