Don't inline methods that are kept.
Bug: 132056258
Bug: 119076934
Change-Id: I238c708aa3e95ba623ed47b604465c13c9a25db4
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index bb002cf..ad7dfb8 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -81,6 +81,7 @@
public boolean isBlackListed(DexMethod method) {
return blackList.contains(appView.graphLense().getOriginalMethodSignature(method))
+ || appView.appInfo().isPinned(method)
|| appView.appInfo().neverInline.contains(method)
|| TwrCloseResourceRewriter.isSynthesizedCloseResourceMethod(method, appView);
}
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index 7d05a19..ab30104 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -690,7 +690,7 @@
public boolean mayPropagateValueFor(DexReference reference) {
assert checkIfObsolete();
- return !neverPropagateValue.contains(reference);
+ return !isPinned(reference) && !neverPropagateValue.contains(reference);
}
private boolean isLibraryOrClasspathField(DexField field) {
diff --git a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
index afb32f4..3dd711d 100644
--- a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
@@ -145,7 +145,11 @@
private static String getMethodLine(MethodReference method) {
// Should we encode modifiers in method references?
StringBuilder builder = new StringBuilder();
- builder.append(method.getMethodName()).append("(");
+ builder
+ .append(method.getReturnType() == null ? "void" : method.getReturnType().getTypeName())
+ .append(' ')
+ .append(method.getMethodName())
+ .append("(");
boolean first = true;
for (TypeReference parameterType : method.getFormalTypes()) {
if (!first) {
diff --git a/src/test/java/com/android/tools/r8/compatproguard/CompatKeepClassMemberNamesTestRunner.java b/src/test/java/com/android/tools/r8/compatproguard/CompatKeepClassMemberNamesTestRunner.java
index c0ca540..efd4467 100644
--- a/src/test/java/com/android/tools/r8/compatproguard/CompatKeepClassMemberNamesTestRunner.java
+++ b/src/test/java/com/android/tools/r8/compatproguard/CompatKeepClassMemberNamesTestRunner.java
@@ -130,7 +130,7 @@
RR extends TestRunResult<RR>,
T extends TestShrinkerBuilder<C, B, CR, RR, T>>
T buildWithMembersRule(TestShrinkerBuilder<C, B, CR, RR, T> builder) {
- return buildWithMembersRuleAllowRenaming(builder).noMinification();
+ return buildWithMembersRuleEnableMinification(builder).noMinification();
}
private <CR extends TestCompileResult<CR, RR>, RR extends TestRunResult<RR>>
@@ -159,6 +159,8 @@
}
@Test
+ @Ignore("b/119076934")
+ // TODO(b/119076934): Fails because the compat rule is applied regardless of mode, keeping Bar.
public void testWithMembersRuleFullR8() throws Exception {
// In full mode for R8 we do *not* expect a -keepclassmembers to cause retention of the class.
assertBarIsAbsent(buildWithMembersRule(testForR8(parameters.getBackend())).compile());
@@ -172,7 +174,7 @@
CR extends TestCompileResult<CR, RR>,
RR extends TestRunResult<RR>,
T extends TestShrinkerBuilder<C, B, CR, RR, T>>
- T buildWithMembersRuleAllowRenaming(TestShrinkerBuilder<C, B, CR, RR, T> builder) {
+ T buildWithMembersRuleEnableMinification(TestShrinkerBuilder<C, B, CR, RR, T> builder) {
return builder
.addProgramClasses(CLASSES)
.addKeepMainRule(MAIN_CLASS)
@@ -180,7 +182,7 @@
}
private <CR extends TestCompileResult<CR, RR>, RR extends TestRunResult<RR>>
- void assertMembersRuleAllowRenamingCompatResult(CR compileResult) throws Exception {
+ void assertMembersRuleEnableMinificationCompatResult(CR compileResult) throws Exception {
compileResult
.inspect(
inspector -> {
@@ -207,23 +209,23 @@
}
@Test
- public void testWithMembersRuleAllowRenamingPG() throws Exception {
- assertMembersRuleAllowRenamingCompatResult(
- buildWithMembersRuleAllowRenaming(testForProguard()).compile());
+ public void testWithMembersRuleEnableMinificationPG() throws Exception {
+ assertMembersRuleEnableMinificationCompatResult(
+ buildWithMembersRuleEnableMinification(testForProguard()).compile());
+ }
+
+ @Test
+ public void testWithMembersRuleEnableMinificationCompatR8() throws Exception {
+ assertMembersRuleEnableMinificationCompatResult(
+ buildWithMembersRuleEnableMinification(testForR8Compat(parameters.getBackend())).compile());
}
@Test
@Ignore("b/119076934")
- // TODO(b/119076934): This fails the Bar.instance() is not inlined check.
- public void testWithMembersRuleAllowRenamingCompatR8() throws Exception {
- assertMembersRuleAllowRenamingCompatResult(
- buildWithMembersRuleAllowRenaming(testForR8Compat(parameters.getBackend())).compile());
- }
-
- @Test
- public void testWithMembersRuleAllowRenamingFullR8() throws Exception {
+ // TODO(b/119076934): Fails because the compat rule is applied regardless of mode, keeping Bar.
+ public void testWithMembersRuleEnableMinificationFullR8() throws Exception {
assertBarIsAbsent(
- buildWithMembersRuleAllowRenaming(testForR8(parameters.getBackend())).compile());
+ buildWithMembersRuleEnableMinification(testForR8(parameters.getBackend())).compile());
}
// Tests for "-keepclassmembers class Bar", i.e, with no members specified.
@@ -268,7 +270,7 @@
RR extends TestRunResult<RR>,
T extends TestShrinkerBuilder<C, B, CR, RR, T>>
T buildWithMemberNamesRule(TestShrinkerBuilder<C, B, CR, RR, T> builder) {
- return buildWithMemberNamesRuleAllowRenaming(builder).noMinification();
+ return buildWithMemberNamesRuleEnableMinification(builder).noMinification();
}
private <CR extends TestCompileResult<CR, RR>, RR extends TestRunResult<RR>>
@@ -319,7 +321,7 @@
CR extends TestCompileResult<CR, RR>,
RR extends TestRunResult<RR>,
T extends TestShrinkerBuilder<C, B, CR, RR, T>>
- T buildWithMemberNamesRuleAllowRenaming(TestShrinkerBuilder<C, B, CR, RR, T> builder) {
+ T buildWithMemberNamesRuleEnableMinification(TestShrinkerBuilder<C, B, CR, RR, T> builder) {
return builder
.addProgramClasses(CLASSES)
.addKeepMainRule(MAIN_CLASS)
@@ -327,7 +329,7 @@
}
private <CR extends TestCompileResult<CR, RR>, RR extends TestRunResult<RR>>
- void assertMemberNamesRuleAllowRenamingCompatResult(CR compileResult) throws Exception {
+ void assertMemberNamesRuleEnableMinificationCompatResult(CR compileResult) throws Exception {
compileResult
.inspect(
inspector -> {
@@ -350,22 +352,23 @@
}
@Test
- public void testWithMemberNamesRuleAllowRenamingPG() throws Exception {
- assertMemberNamesRuleAllowRenamingCompatResult(
- buildWithMemberNamesRuleAllowRenaming(testForProguard()).compile());
+ public void testWithMemberNamesRuleEnableMinificationPG() throws Exception {
+ assertMemberNamesRuleEnableMinificationCompatResult(
+ buildWithMemberNamesRuleEnableMinification(testForProguard()).compile());
}
@Test
@Ignore("b/119076934")
// TODO(b/119076934): This fails the Bar.instance() is not inlined check.
- public void testWithMemberNamesRuleAllowRenamingCompatR8() throws Exception {
- assertMemberNamesRuleAllowRenamingCompatResult(
- buildWithMemberNamesRuleAllowRenaming(testForR8Compat(parameters.getBackend())).compile());
+ public void testWithMemberNamesRuleEnableMinificationCompatR8() throws Exception {
+ assertMemberNamesRuleEnableMinificationCompatResult(
+ buildWithMemberNamesRuleEnableMinification(testForR8Compat(parameters.getBackend()))
+ .compile());
}
@Test
- public void testWithMemberNamesRuleAllowRenamingFullR8() throws Exception {
+ public void testWithMemberNamesRuleEnableMinificationFullR8() throws Exception {
assertBarIsAbsent(
- buildWithMemberNamesRuleAllowRenaming(testForR8(parameters.getBackend())).compile());
+ buildWithMemberNamesRuleEnableMinification(testForR8(parameters.getBackend())).compile());
}
}
diff --git a/src/test/java/com/android/tools/r8/debug/DebugInfoWhenInliningTest.java b/src/test/java/com/android/tools/r8/debug/DebugInfoWhenInliningTest.java
index 635f77e..319327d 100644
--- a/src/test/java/com/android/tools/r8/debug/DebugInfoWhenInliningTest.java
+++ b/src/test/java/com/android/tools/r8/debug/DebugInfoWhenInliningTest.java
@@ -36,6 +36,7 @@
DEX_FORCE_JUMBO
};
+ private static final String CLASS_NAME = "Inlining1";
private static final String SOURCE_FILE = "Inlining1.java";
private DebugTestConfig makeConfig(
@@ -50,7 +51,12 @@
R8Command.builder()
.addProgramFiles(DEBUGGEE_JAR)
.setMode(CompilationMode.RELEASE)
- .setDisableTreeShaking(true)
+ .addProguardConfiguration(
+ ImmutableList.of(
+ "-keep class "
+ + CLASS_NAME
+ + " { public static void main(java.lang.String[]); }"),
+ Origin.unknown())
.setDisableMinification(true)
.addProguardConfiguration(
ImmutableList.of("-keepattributes SourceFile,LineNumberTable"), Origin.unknown());
@@ -175,11 +181,10 @@
private void testEachLine(
DebugTestConfig config, int[] lineNumbers, List<List<SignatureAndLine>> inlineFramesList)
throws Throwable {
- final String className = "Inlining1";
final String mainSignature = "([Ljava/lang/String;)V";
List<Command> commands = new ArrayList<Command>();
- commands.add(breakpoint(className, "main", mainSignature));
+ commands.add(breakpoint(CLASS_NAME, "main", mainSignature));
commands.add(run());
boolean first = true;
assert inlineFramesList == null || inlineFramesList.size() == lineNumbers.length;
@@ -189,13 +194,13 @@
} else {
commands.add(stepOver());
}
- commands.add(checkMethod(className, "main", mainSignature));
+ commands.add(checkMethod(CLASS_NAME, "main", mainSignature));
commands.add(checkLine(SOURCE_FILE, lineNumbers[idx]));
if (inlineFramesList != null) {
commands.add(checkInlineFrames(inlineFramesList.get(idx)));
}
}
commands.add(run());
- runDebugTest(config, className, commands);
+ runDebugTest(config, CLASS_NAME, commands);
}
}
diff --git a/src/test/java/com/android/tools/r8/debuginfo/InliningWithoutPositionsTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/InliningWithoutPositionsTestRunner.java
index 0588b33..3e60ef1 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/InliningWithoutPositionsTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/InliningWithoutPositionsTestRunner.java
@@ -48,6 +48,7 @@
private static final String TEST_CLASS = "InliningWithoutPositionsTestSource";
private static final String TEST_PACKAGE = "com.android.tools.r8.debuginfo";
+ private static final String MAIN_CLASS = TEST_PACKAGE + "." + TEST_CLASS;
@ClassRule public static TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
@@ -123,7 +124,10 @@
.setOutput(outputPath, OutputMode.ClassFile);
}
builder
- .setDisableTreeShaking(true)
+ .addProguardConfiguration(
+ ImmutableList.of(
+ "-keep class " + MAIN_CLASS + " { public static void main(java.lang.String[]); }"),
+ Origin.unknown())
.setDisableMinification(true)
.addProguardConfiguration(
ImmutableList.of("-keepattributes SourceFile,LineNumberTable"), Origin.unknown());
@@ -134,11 +138,11 @@
if (backend == Backend.DEX) {
ArtCommandBuilder artCommandBuilder = new ArtCommandBuilder();
artCommandBuilder.appendClasspath(outputPath.resolve("classes.dex").toString());
- artCommandBuilder.setMainClass(TEST_PACKAGE + "." + TEST_CLASS);
+ artCommandBuilder.setMainClass(MAIN_CLASS);
result = ToolHelper.runArtRaw(artCommandBuilder);
} else {
- result = ToolHelper.runJava(outputPath, TEST_PACKAGE + "." + TEST_CLASS);
+ result = ToolHelper.runJava(outputPath, MAIN_CLASS);
}
assertNotEquals(result.exitCode, 0);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/InstanceOfRemovalTest.java b/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/InstanceOfRemovalTest.java
index 1e33d3c..efd4766 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/InstanceOfRemovalTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/InstanceOfRemovalTest.java
@@ -152,7 +152,6 @@
testForR8(backend)
.addProgramClasses(A.class, B.class, TestClass.class)
.addKeepMainRule(TestClass.class)
- .addKeepAllClassesRule()
.enableInliningAnnotations()
.run(TestClass.class)
.assertSuccessWithOutput(expected)
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 3a5ffdd..d6ca6e1 100644
--- a/src/test/java/com/android/tools/r8/neverreturnsnormally/NeverReturnsNormallyTest.java
+++ b/src/test/java/com/android/tools/r8/neverreturnsnormally/NeverReturnsNormallyTest.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.neverreturnsnormally;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -60,7 +61,6 @@
"-keep class " + TestClass.class.getCanonicalName() + "{",
" public static void main(java.lang.String[]);",
" *** test*(...);",
- " *** throwToBeInlined(...);",
" *** outerTrivial(...);",
"}",
"",
@@ -103,23 +103,27 @@
// Check the instruction used for testInlinedIntoVoidMethod
MethodSubject methodThrowToBeInlined =
clazz.method("int", "throwToBeInlined", ImmutableList.of());
- assertTrue(methodThrowToBeInlined.isPresent());
- Iterator<InstructionSubject> instructions = methodThrowToBeInlined.iterateInstructions();
- // Call, followed by throw null.
- 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"));
- verifyTrailingPattern(instructions);
+ boolean expectedToBePresent = mode == CompilationMode.DEBUG;
+ assertEquals(expectedToBePresent, methodThrowToBeInlined.isPresent());
+ if (expectedToBePresent) {
+ Iterator<InstructionSubject> instructions = methodThrowToBeInlined.iterateInstructions();
+ // Call, followed by throw null.
+ 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"));
+ 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);
+ Iterator<InstructionSubject> instructions =
+ methodTestInlinedIntoVoidMethod.iterateInstructions();
+ InstructionSubject insn = nextInstructionSkippingCfPositionAndLabel(instructions);
if (mode == CompilationMode.DEBUG) {
// Not inlined call to throwToBeInlined.
assertTrue(insn.isInvoke());
diff --git a/src/test/java/com/android/tools/r8/resolution/SingleStaticTargetLookupTest.java b/src/test/java/com/android/tools/r8/resolution/SingleStaticTargetLookupTest.java
new file mode 100644
index 0000000..3686b19
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/resolution/SingleStaticTargetLookupTest.java
@@ -0,0 +1,15 @@
+// Copyright (c) 2019, 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.resolution;
+
+class SingleStaticTargetLookupTest {
+
+ public static String staticFoo() {
+ return "foo";
+ }
+
+ public static void main(String[] args) {
+ System.out.println(staticFoo());
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/resolution/SingleStaticTargetLookupTestRunner.java b/src/test/java/com/android/tools/r8/resolution/SingleStaticTargetLookupTestRunner.java
new file mode 100644
index 0000000..fef40af
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/resolution/SingleStaticTargetLookupTestRunner.java
@@ -0,0 +1,91 @@
+// Copyright (c) 2019, 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.resolution;
+
+import static com.android.tools.r8.references.Reference.methodFromMethod;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.BaseCompilerCommand;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestCompileResult;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRunResult;
+import com.android.tools.r8.TestShrinkerBuilder;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class SingleStaticTargetLookupTestRunner extends TestBase {
+
+ static final String EXPECTED = StringUtils.lines("foo");
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withCfRuntimes().build();
+ }
+
+ public SingleStaticTargetLookupTestRunner(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ public <
+ C extends BaseCompilerCommand,
+ B extends BaseCompilerCommand.Builder<C, B>,
+ CR extends TestCompileResult<CR, RR>,
+ RR extends TestRunResult<RR>,
+ T extends TestShrinkerBuilder<C, B, CR, RR, T>>
+ void test(boolean keepFoo, TestShrinkerBuilder<C, B, CR, RR, T> builder) throws Exception {
+ builder
+ .addProgramClassesAndInnerClasses(SingleStaticTargetLookupTest.class)
+ .addKeepMainRule(SingleStaticTargetLookupTest.class)
+ .apply(
+ b -> {
+ if (keepFoo) {
+ b.addKeepMethodRules(
+ methodFromMethod(SingleStaticTargetLookupTest.class.getMethod("staticFoo")));
+ }
+ })
+ .run(parameters.getRuntime(), SingleStaticTargetLookupTest.class)
+ .assertSuccessWithOutput(EXPECTED)
+ .inspect(
+ inspector -> {
+ ClassSubject clazz = inspector.clazz(SingleStaticTargetLookupTest.class);
+ MethodSubject main = clazz.uniqueMethodWithName("main");
+ MethodSubject staticFoo = clazz.uniqueMethodWithName("staticFoo");
+ assertThat(clazz, isPresent());
+ assertThat(main, isPresent());
+ assertEquals(keepFoo, staticFoo.isPresent());
+ assertEquals(keepFoo, main.streamInstructions().anyMatch(i -> i.isInvokeStatic()));
+ });
+ }
+
+ @Test
+ public void testInlinedPG() throws Exception {
+ test(false, testForProguard());
+ }
+
+ @Test
+ public void testKeptPG() throws Exception {
+ test(true, testForProguard());
+ }
+
+ @Test
+ public void testInlinedR8() throws Exception {
+ test(false, testForR8(parameters.getBackend()));
+ }
+
+ @Test
+ public void testKeptR8() throws Exception {
+ test(true, testForR8(parameters.getBackend()));
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/whyareyoukeeping/WhyAreYouKeepingTest.java b/src/test/java/com/android/tools/r8/shaking/whyareyoukeeping/WhyAreYouKeepingTest.java
index 87f73bd..d78542e 100644
--- a/src/test/java/com/android/tools/r8/shaking/whyareyoukeeping/WhyAreYouKeepingTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/whyareyoukeeping/WhyAreYouKeepingTest.java
@@ -46,7 +46,7 @@
StringUtils.lines(
"com.android.tools.r8.shaking.whyareyoukeeping.A",
"|- is referenced in keep rule:",
- "| -keep class com.android.tools.r8.shaking.whyareyoukeeping.A { foo(); }");
+ "| -keep class com.android.tools.r8.shaking.whyareyoukeeping.A { void foo(); }");
// TODO(b/120959039): This should be "- is invoked from:\n com.android.....A.bar()" etc.
public static final String expectedPathToBaz =
@@ -55,7 +55,7 @@
"|- is reachable from:",
"| com.android.tools.r8.shaking.whyareyoukeeping.A",
"|- is referenced in keep rule:",
- "| -keep class com.android.tools.r8.shaking.whyareyoukeeping.A { foo(); }");
+ "| -keep class com.android.tools.r8.shaking.whyareyoukeeping.A { void foo(); }");
@Parameters(name = "{0}")
public static Backend[] parameters() {