Prerequisite test cleanups for call site optimization info propagation.
These tests have call sites that always pass either null or non-null
instances. Their expectations will be updated (towards better results.)
Bug: 139246447
Change-Id: I13e42f48f9b3361de6d38ff6ecb2095c00011836
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetClassTest.java b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetClassTest.java
index 893e20d..71063f4 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetClassTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetClassTest.java
@@ -140,20 +140,19 @@
}
private void test(
- TestRunResult result,
- int expectedGetClassCount,
- int expectedConstClassCount,
- int expectedGetClassCountForCall,
- int expectedConstClassCountForCall) throws Exception {
+ TestRunResult<?> result, boolean isR8, boolean isRelease) throws Exception {
CodeInspector codeInspector = result.inspector();
ClassSubject mainClass = codeInspector.clazz(MAIN);
MethodSubject mainMethod = mainClass.mainMethod();
assertThat(mainMethod, isPresent());
- assertEquals(expectedGetClassCount, countGetClass(mainMethod));
- assertEquals(expectedConstClassCount, countConstClass(mainMethod));
+ int expectedCount = isR8 ? (isRelease ? 0 : 5) : 6;
+ assertEquals(expectedCount, countGetClass(mainMethod));
+ expectedCount = isR8 ? (isRelease ? (parameters.isCfRuntime() ? 7 : 5) : 1) : 0;
+ assertEquals(expectedCount, countConstClass(mainMethod));
- MethodSubject getMainClass = mainClass.method(
- "java.lang.Class", "getMainClass", ImmutableList.of(MAIN.getCanonicalName()));
+ boolean expectToBeOptimized = isR8 && isRelease;
+
+ MethodSubject getMainClass = mainClass.uniqueMethodWithName("getMainClass");
assertThat(getMainClass, isPresent());
// Because of nullable argument, getClass() should remain.
assertEquals(1, countGetClass(getMainClass));
@@ -162,8 +161,8 @@
MethodSubject call = mainClass.method("java.lang.Class", "call", ImmutableList.of());
assertThat(call, isPresent());
// Because of local, only R8 release mode can rewrite getClass() to const-class.
- assertEquals(expectedGetClassCountForCall, countGetClass(call));
- assertEquals(expectedConstClassCountForCall, countConstClass(call));
+ assertEquals(expectToBeOptimized ? 0 : 1, countGetClass(call));
+ assertEquals(expectToBeOptimized ? 1 : 0, countConstClass(call));
}
@Test
@@ -178,7 +177,7 @@
.setMinApi(parameters.getRuntime())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutput(JAVA_OUTPUT);
- test(result, 6, 0, 1, 0);
+ test(result, false, false);
// D8 release.
result =
@@ -188,7 +187,7 @@
.setMinApi(parameters.getRuntime())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutput(JAVA_OUTPUT);
- test(result, 6, 0, 1, 0);
+ test(result, false, true);
}
@Test
@@ -203,7 +202,7 @@
.noMinification()
.setMinApi(parameters.getRuntime())
.run(parameters.getRuntime(), MAIN);
- test(result, 5, 1, 1, 0);
+ test(result, true, false);
// The number of expected const-class instructions differs because constant canonicalization is
// only enabled for the DEX backend.
@@ -219,7 +218,7 @@
.setMinApi(parameters.getRuntime())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutput(JAVA_OUTPUT);
- test(result, 0, expectedConstClassCount, 0, 1);
+ test(result, true, true);
// R8 release, minification.
result =
@@ -230,6 +229,6 @@
.setMinApi(parameters.getRuntime())
// We are not checking output because it can't be matched due to minification. Just run.
.run(parameters.getRuntime(), MAIN);
- test(result, 0, expectedConstClassCount, 0, 1);
+ test(result, true, true);
}
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java b/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java
index e92d393..b07d8f1 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java
@@ -76,21 +76,18 @@
instructionSubject.isConstString("null", JumboStringMode.ALLOW)).count();
}
- private void test(
- TestRunResult result,
- int expectedStringValueOfCountInMain,
- int expectedNullCount,
- int expectedNullStringCountInMain,
- int expectedStringValueOfCountInConsumer,
- int expectedNullStringCountInConsumer)
- throws Exception {
+ private void test(TestRunResult<?> result, boolean isR8, boolean isRelease) throws Exception {
CodeInspector codeInspector = result.inspector();
ClassSubject mainClass = codeInspector.clazz(MAIN);
MethodSubject mainMethod = mainClass.mainMethod();
assertThat(mainMethod, isPresent());
- assertEquals(expectedStringValueOfCountInMain, countCall(mainMethod, "String", "valueOf"));
- assertEquals(expectedNullCount, countConstNullNumber(mainMethod));
- assertEquals(expectedNullStringCountInMain, countNullStringNumber(mainMethod));
+ int expectedCount = isR8 ? 3 : (isRelease ? 5 : 7);
+ assertEquals(expectedCount, countCall(mainMethod, "String", "valueOf"));
+ // Due to the different behavior regarding constant canonicalization.
+ expectedCount = isR8 ? (parameters.isCfRuntime() ? 2 : 1) : 1;
+ assertEquals(expectedCount, countConstNullNumber(mainMethod));
+ expectedCount = isR8 ? (parameters.isCfRuntime() ? 2 : 1) : (isRelease ? 1 : 0);
+ assertEquals(expectedCount, countNullStringNumber(mainMethod));
MethodSubject hideNPE = mainClass.uniqueMethodWithName("hideNPE");
assertThat(hideNPE, isPresent());
@@ -99,8 +96,10 @@
MethodSubject uninit = mainClass.uniqueMethodWithName("consumeUninitialized");
assertThat(uninit, isPresent());
- assertEquals(expectedStringValueOfCountInConsumer, countCall(uninit, "String", "valueOf"));
- assertEquals(expectedNullStringCountInConsumer, countNullStringNumber(uninit));
+ expectedCount = isR8 ? 0 : 1;
+ assertEquals(expectedCount, countCall(uninit, "String", "valueOf"));
+ expectedCount = isR8 ? 1 : 0;
+ assertEquals(expectedCount, countNullStringNumber(uninit));
}
@Test
@@ -115,7 +114,7 @@
.addOptionsModification(options -> options.enableNonNullTracking = true)
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutput(JAVA_OUTPUT);
- test(result, 7, 1, 0, 1, 0);
+ test(result, false, false);
result =
testForD8()
@@ -125,7 +124,7 @@
.addOptionsModification(options -> options.enableNonNullTracking = true)
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutput(JAVA_OUTPUT);
- test(result, 5, 1, 1, 1, 0);
+ test(result, false, true);
}
@Test
@@ -141,10 +140,7 @@
.addOptionsModification(this::configure)
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutput(JAVA_OUTPUT);
- // Due to the different behavior regarding constant canonicalization.
- int expectedNullCount = parameters.isCfRuntime() ? 2 : 1;
- int expectedNullStringCount = parameters.isCfRuntime() ? 2 : 1;
- test(result, 3, expectedNullCount, expectedNullStringCount, 0, 1);
+ test(result, true, true);
}
static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java b/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
index e961c0e..a3ec1a2 100644
--- a/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
+++ b/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
@@ -28,6 +28,7 @@
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.FieldSubject;
@@ -232,15 +233,31 @@
}
protected String keepAllMembers(String className) {
- return "-keep class " + className + " {" + System.lineSeparator()
- + " *;" + System.lineSeparator()
- + "}";
+ return StringUtils.lines(
+ "-keep class " + className + " {",
+ " *;",
+ "}");
+ }
+
+ protected String keepMainMethod(String className) {
+ return StringUtils.lines(
+ "-keepclasseswithmembers class " + className + " {",
+ " public static void main(...);",
+ "}");
}
protected String keepClassMethod(String className, MethodSignature methodSignature) {
- return "-keep class " + className + " {" + System.lineSeparator()
- + methodSignature.toString() + ";" + System.lineSeparator()
- + "}";
+ return StringUtils.lines(
+ "-keep class " + className + " {",
+ methodSignature.toString() + ";",
+ "}");
+ }
+
+ protected String neverInlineMethod(String className, MethodSignature methodSignature) {
+ return StringUtils.lines(
+ "-neverinline class " + className + " {",
+ methodSignature.toString() + ";",
+ "}");
}
protected void runTest(String folder, String mainClass,
diff --git a/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java b/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java
index b4b0c06..97ec186 100644
--- a/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java
@@ -12,7 +12,6 @@
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Streams;
import org.junit.Test;
public class SimplifyIfNotNullKotlinTest extends AbstractR8KotlinTestBase {
@@ -32,14 +31,15 @@
ImmutableList.of("java.util.Collection", STRING, STRING, "java.lang.Integer"));
final String mainClassName = ex1.getClassName();
- final String extraRules = keepAllMembers(mainClassName);
+ final String extraRules =
+ keepMainMethod(mainClassName) + neverInlineMethod(mainClassName, testMethodSignature);
runTest(FOLDER, mainClassName, extraRules, app -> {
CodeInspector codeInspector = new CodeInspector(app);
ClassSubject clazz = checkClassIsKept(codeInspector, ex1.getClassName());
MethodSubject testMethod = checkMethodIsKept(clazz, testMethodSignature);
- long ifzCount = Streams.stream(testMethod.iterateInstructions())
- .filter(i -> i.isIfEqz() || i.isIfNez()).count();
+ long ifzCount =
+ testMethod.streamInstructions().filter(i -> i.isIfEqz() || i.isIfNez()).count();
long paramNullCheckCount =
countCall(testMethod, "ArrayIteratorKt", "checkParameterIsNotNull");
if (allowAccessModification) {
@@ -61,14 +61,14 @@
new MethodSignature("aOrDefault", STRING, ImmutableList.of(STRING, STRING));
final String mainClassName = ex2.getClassName();
- final String extraRules = keepAllMembers(mainClassName);
+ final String extraRules =
+ keepMainMethod(mainClassName) + neverInlineMethod(mainClassName, testMethodSignature);
runTest(FOLDER, mainClassName, extraRules, app -> {
CodeInspector codeInspector = new CodeInspector(app);
ClassSubject clazz = checkClassIsKept(codeInspector, ex2.getClassName());
MethodSubject testMethod = checkMethodIsKept(clazz, testMethodSignature);
- long ifzCount = Streams.stream(testMethod.iterateInstructions())
- .filter(InstructionSubject::isIfEqz).count();
+ long ifzCount = testMethod.streamInstructions().filter(InstructionSubject::isIfEqz).count();
long paramNullCheckCount =
countCall(testMethod, "Intrinsics", "checkParameterIsNotNull");
if (allowAccessModification) {
@@ -90,18 +90,17 @@
new MethodSignature("neverThrowNPE", "void", ImmutableList.of("non_null.Foo"));
final String mainClassName = ex3.getClassName();
- final String extraRules = keepAllMembers(mainClassName);
+ final String extraRules =
+ keepMainMethod(mainClassName) + neverInlineMethod(mainClassName, testMethodSignature);
runTest(FOLDER, mainClassName, extraRules, app -> {
CodeInspector codeInspector = new CodeInspector(app);
ClassSubject clazz = checkClassIsKept(codeInspector, ex3.getClassName());
MethodSubject testMethod = checkMethodIsKept(clazz, testMethodSignature);
- long ifzCount = Streams.stream(testMethod.iterateInstructions())
- .filter(InstructionSubject::isIfEqz).count();
+ long ifzCount = testMethod.streamInstructions().filter(InstructionSubject::isIfEqz).count();
// !! operator inside explicit null check should be gone.
// One explicit null-check as well as 4 bar? accesses.
assertEquals(5, ifzCount);
});
}
-
}
diff --git a/src/test/java/com/android/tools/r8/shaking/ReturnTypeTest.java b/src/test/java/com/android/tools/r8/shaking/ReturnTypeTest.java
index 0cc2128..244199e 100644
--- a/src/test/java/com/android/tools/r8/shaking/ReturnTypeTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ReturnTypeTest.java
@@ -5,26 +5,17 @@
package com.android.tools.r8.shaking;
import static com.android.tools.r8.utils.codeinspector.Matchers.isRenamed;
-import static junit.framework.TestCase.assertEquals;
-import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assume.assumeTrue;
-import com.android.tools.r8.DexIndexedConsumer;
-import com.android.tools.r8.OutputMode;
-import com.android.tools.r8.R8Command;
import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.ProcessResult;
-import com.android.tools.r8.VmTestRunner;
-import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import com.google.common.collect.ImmutableList;
-import java.nio.file.Path;
-import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
class B112517039ReturnType extends Exception {
}
@@ -52,42 +43,49 @@
}
}
-@RunWith(VmTestRunner.class)
+@RunWith(Parameterized.class)
public class ReturnTypeTest extends TestBase {
+ private static final String JAVA_OUTPUT = StringUtils.lines(
+ "Ewwo!",
+ "NullPointerException"
+ );
+ private static final Class<?> MAIN = B112517039Main.class;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimes().build();
+ }
+
+ private final TestParameters parameters;
+
+ public ReturnTypeTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
@Test
- public void testFromJavac() throws Exception {
- String mainName = B112517039Main.class.getCanonicalName();
- ProcessResult javaResult = ToolHelper.runJava(ToolHelper.getClassPathForTests(), mainName);
- assertEquals(0, javaResult.exitCode);
- assertThat(javaResult.stdout, containsString("Ewwo!"));
- assertThat(javaResult.stdout, containsString("NullPointerException"));
+ public void testJVMOutput() throws Exception {
+ assumeTrue("Only run JVM reference on CF runtimes", parameters.isCfRuntime());
+ testForJvm()
+ .addTestClasspath()
+ .run(parameters.getRuntime(), MAIN)
+ .assertSuccessWithOutput(JAVA_OUTPUT);
+ }
- List<String> config = ImmutableList.of(
- "-printmapping",
- "-keep class " + mainName + " {",
- " public static void main(...);",
- "}"
- );
- R8Command.Builder builder = R8Command.builder();
- builder.addProgramFiles(ToolHelper.getClassFilesForTestDirectory(
- ToolHelper.getPackageDirectoryForTestPackage(B112517039Main.class.getPackage()),
- path -> path.getFileName().toString().startsWith("B112517039")));
- builder.setProgramConsumer(DexIndexedConsumer.emptyConsumer());
- builder.setMinApiLevel(ToolHelper.getMinApiLevelForDexVm().getLevel());
- builder.addProguardConfiguration(config, Origin.unknown());
- AndroidApp processedApp = ToolHelper.runR8(builder.build(), options -> {
- options.enableInlining = false;
- });
-
- Path outDex = temp.getRoot().toPath().resolve("dex.zip");
- processedApp.writeToZip(outDex, OutputMode.DexIndexed);
- ProcessResult artResult = ToolHelper.runArtNoVerificationErrorsRaw(outDex.toString(), mainName);
- assertEquals(0, artResult.exitCode);
- assertThat(javaResult.stdout, containsString("Ewwo!"));
- assertThat(javaResult.stdout, containsString("NullPointerException"));
-
- CodeInspector inspector = new CodeInspector(processedApp);
- ClassSubject returnType = inspector.clazz(B112517039ReturnType.class);
- assertThat(returnType, isRenamed());
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(
+ B112517039ReturnType.class, B112517039I.class, B112517039Caller.class, MAIN)
+ .addKeepMainRule(MAIN)
+ .setMinApi(parameters.getRuntime())
+ .addOptionsModification(o -> {
+ o.enableInlining = false;
+ })
+ .run(parameters.getRuntime(), MAIN)
+ .assertSuccessWithOutput(JAVA_OUTPUT)
+ .inspect(inspector -> {
+ ClassSubject returnType = inspector.clazz(B112517039ReturnType.class);
+ assertThat(returnType, isRenamed());
+ });
}
}
diff --git a/src/test/java/com/android/tools/r8/shaking/array/DeadArrayLengthTest.java b/src/test/java/com/android/tools/r8/shaking/array/DeadArrayLengthTest.java
index 085ad52..3286e69 100644
--- a/src/test/java/com/android/tools/r8/shaking/array/DeadArrayLengthTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/array/DeadArrayLengthTest.java
@@ -4,10 +4,12 @@
package com.android.tools.r8.shaking.array;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assume.assumeTrue;
+import com.android.tools.r8.NeverInline;
import com.android.tools.r8.NeverPropagateValue;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
@@ -17,7 +19,6 @@
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import com.google.common.collect.Streams;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -38,28 +39,31 @@
this.parameters = parameters;
}
- private void inspect(CodeInspector inspector) {
+ private void inspect(CodeInspector inspector, boolean isR8) {
ClassSubject main = inspector.clazz(MAIN);
assertThat(main, isPresent());
MethodSubject nonNull = main.uniqueMethodWithName("clearlyNonNull");
assertThat(nonNull, isPresent());
- assertEquals(
- 0,
- Streams.stream(nonNull.iterateInstructions(InstructionSubject::isArrayLength)).count());
+ assertEquals(0, countArrayLength(nonNull));
MethodSubject nullable = main.uniqueMethodWithName("isNullable");
- assertThat(nullable, isPresent());
- assertEquals(
- 1,
- Streams.stream(nullable.iterateInstructions(InstructionSubject::isArrayLength)).count());
+ if (isR8) {
+ // Replaced with null-throwing code at the call site.
+ assertThat(nullable, not(isPresent()));
+ } else {
+ assertThat(nullable, isPresent());
+ assertEquals(1, countArrayLength(nullable));
+ }
MethodSubject nullCheck = main.uniqueMethodWithName("afterNullCheck");
assertThat(nullCheck, isPresent());
// TODO(b/120920488): could be zero if we extend non-null to first dead code removal.
- assertEquals(
- 1,
- Streams.stream(nullCheck.iterateInstructions(InstructionSubject::isArrayLength)).count());
+ assertEquals(1, countArrayLength(nullCheck));
+ }
+
+ private long countArrayLength(MethodSubject method) {
+ return method.streamInstructions().filter(InstructionSubject::isArrayLength).count();
}
@Test
@@ -71,23 +75,25 @@
.setMinApi(parameters.getRuntime())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutput(EXPECTED_OUTPUT)
- .inspect(this::inspect);
+ .inspect(codeInspector -> inspect(codeInspector, false));
}
@Test
public void testR8() throws Exception {
testForR8(parameters.getBackend())
.addProgramClasses(MAIN)
- .addKeepClassAndMembersRules(MAIN)
+ .addKeepMainRule(MAIN)
+ .enableInliningAnnotations()
.enableMemberValuePropagationAnnotations()
.noMinification()
.setMinApi(parameters.getRuntime())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutput(EXPECTED_OUTPUT)
- .inspect(this::inspect);
+ .inspect(codeInspector -> inspect(codeInspector, true));
}
static class TestClass {
+ @NeverInline
@NeverPropagateValue
static int clearlyNonNull(int size) {
int[] array = new int[size];
@@ -95,6 +101,7 @@
return System.currentTimeMillis() > 0 ? 1 : -1;
}
+ @NeverInline
@NeverPropagateValue
static int isNullable(int[] args) {
// Not used, but can't be dead due to the potential NPE.
@@ -102,6 +109,7 @@
return System.currentTimeMillis() > 0 ? 2 : -2;
}
+ @NeverInline
@NeverPropagateValue
static int afterNullCheck(int[] args) {
if (args != null) {