Version 2.0.71
Cherry pick: Reproduce missing propagation in call site optimization
CL: https://r8-review.googlesource.com/c/r8/+/50700
In addition to cherry picking the test case from the CL above, this version includes a fix to InvokeMethod.lookupTargets(), which would incorrectly filter out possible dispatch targets, causing a bug in the call site optimization.
Bug: 154531810
Change-Id: Id4af6e1d2165ea48d010a7b14c3fee6739aa59a8
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index a6e1d74..0bb2d98 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
// This field is accessed from release scripts using simple pattern matching.
// Therefore, changing this field could break our release scripts.
- public static final String LABEL = "2.0.70";
+ public static final String LABEL = "2.0.71";
private Version() {
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java b/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
index e7d2ab1..4ade5fd 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.cf.TypeVerificationHelper;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
@@ -107,23 +108,31 @@
appView.withLiveness(), this.asInvokeMethodWithReceiver());
// TODO(b/140204899): Instead of reprocessing here, pass refined receiver to lookup.
// Leverage refined receiver type if available.
- if (refinedReceiverType != staticReceiverType) {
- ResolutionResult refinedResolution =
- appView.appInfo().resolveMethod(refinedReceiverType, method);
- if (refinedResolution.isSingleResolution()) {
- DexEncodedMethod refinedTarget = refinedResolution.getSingleTarget();
- Set<DexEncodedMethod> result = Sets.newIdentityHashSet();
- for (DexEncodedMethod target : targets) {
- if (target == refinedTarget
- || appView.isSubtype(target.method.holder, refinedReceiverType).isPossiblyTrue()) {
- result.add(target);
- }
- }
- return result;
- }
- // If resolution at the refined type fails, conservatively return the full set of targets.
+ if (refinedReceiverType == staticReceiverType) {
+ return targets;
}
- return targets;
+
+ DexClass refinedReceiverClass = appView.definitionFor(refinedReceiverType);
+ if (refinedReceiverClass == null || refinedReceiverClass.isInterface()) {
+ return targets;
+ }
+
+ ResolutionResult refinedResolution =
+ appView.appInfo().resolveMethod(refinedReceiverType, method);
+ if (!refinedResolution.isSingleResolution()) {
+ // If resolution at the refined type fails, conservatively return the full set of targets.
+ return targets;
+ }
+
+ DexEncodedMethod refinedTarget = refinedResolution.getSingleTarget();
+ Set<DexEncodedMethod> result = Sets.newIdentityHashSet();
+ for (DexEncodedMethod target : targets) {
+ if (target == refinedTarget
+ || appView.isSubtype(target.method.holder, refinedReceiverType).isPossiblyTrue()) {
+ result.add(target);
+ }
+ }
+ return result;
}
public abstract InlineAction computeInlining(
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/PropagationFromSiblingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/PropagationFromSiblingTest.java
new file mode 100644
index 0000000..fb3bc2e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/PropagationFromSiblingTest.java
@@ -0,0 +1,89 @@
+// Copyright (c) 2020, 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.ir.optimize.callsites;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+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 PropagationFromSiblingTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public PropagationFromSiblingTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(PropagationFromSiblingTest.class)
+ .addKeepMainRule(TestClass.class)
+ .addOptionsModification(options -> options.enableUnusedInterfaceRemoval = false)
+ .enableInliningAnnotations()
+ .enableMergeAnnotations()
+ .enableNeverClassInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("Hello world!");
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ getJAsI().m(null); // The null argument is not propagated to A.m() in 2.0.59.
+ new B().m("Hello world!");
+ }
+
+ @NeverInline
+ static I getJAsI() {
+ if (System.currentTimeMillis() > 0) {
+ return new B();
+ }
+ return new C();
+ }
+ }
+
+ interface I {
+ void m(Object o);
+ }
+
+ interface J extends I {}
+
+ @NeverMerge
+ static class A implements I {
+
+ @NeverInline
+ @Override
+ public void m(Object o) {
+ if (o != null) {
+ System.out.println(o.toString());
+ }
+ }
+ }
+
+ @NeverClassInline
+ static class B extends A implements J {}
+
+ static class C implements J {
+
+ @Override
+ public void m(Object o) {}
+ }
+}