Version 2.1.54
Cherry-pick: Handle invoke-virtual/range when hoisting bridge methods
CL: https://ci.chromium.org/p/r8/g/main_all/console
Bug: 161403944
Change-Id: I12c06dcf6aab4cdb87f3842f4263378074ceda31
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 7874bb9..3cd22ef 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.1.53";
+ public static final String LABEL = "2.1.54";
private Version() {
}
diff --git a/src/main/java/com/android/tools/r8/code/Instruction.java b/src/main/java/com/android/tools/r8/code/Instruction.java
index 86abac6..9d93b40 100644
--- a/src/main/java/com/android/tools/r8/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/code/Instruction.java
@@ -183,6 +183,14 @@
return null;
}
+ public boolean isInvokeVirtualRange() {
+ return false;
+ }
+
+ public InvokeVirtualRange asInvokeVirtualRange() {
+ return null;
+ }
+
public boolean isSimpleNop() {
return !isPayload() && this instanceof Nop;
}
diff --git a/src/main/java/com/android/tools/r8/code/InvokeVirtualRange.java b/src/main/java/com/android/tools/r8/code/InvokeVirtualRange.java
index 64e9b6d..cd78458 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeVirtualRange.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeVirtualRange.java
@@ -39,6 +39,16 @@
}
@Override
+ public boolean isInvokeVirtualRange() {
+ return true;
+ }
+
+ @Override
+ public InvokeVirtualRange asInvokeVirtualRange() {
+ return this;
+ }
+
+ @Override
public void registerUse(UseRegistry registry) {
registry.registerInvokeVirtual(getMethod());
}
diff --git a/src/main/java/com/android/tools/r8/optimize/BridgeHoisting.java b/src/main/java/com/android/tools/r8/optimize/BridgeHoisting.java
index 31e239b..5f87490 100644
--- a/src/main/java/com/android/tools/r8/optimize/BridgeHoisting.java
+++ b/src/main/java/com/android/tools/r8/optimize/BridgeHoisting.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.cf.code.CfInvoke;
import com.android.tools.r8.code.Instruction;
import com.android.tools.r8.code.InvokeVirtual;
+import com.android.tools.r8.code.InvokeVirtualRange;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.BottomUpClassHierarchyTraversal;
@@ -334,6 +335,12 @@
invoke.A, methodToInvoke, invoke.C, invoke.D, invoke.E, invoke.F, invoke.G);
newInvoke.setOffset(invoke.getOffset());
newInstructions[i] = newInvoke;
+ } else if (instruction.isInvokeVirtualRange()) {
+ InvokeVirtualRange invoke = instruction.asInvokeVirtualRange();
+ InvokeVirtualRange newInvoke =
+ new InvokeVirtualRange(invoke.CCCC, invoke.AA, methodToInvoke);
+ newInvoke.setOffset(invoke.getOffset());
+ newInstructions[i] = newInvoke;
} else {
newInstructions[i] = instruction;
}
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/BridgeHoistingAccessibilityTest.java b/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/BridgeHoistingAccessibilityTest.java
index 16db7d8..410d418 100644
--- a/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/BridgeHoistingAccessibilityTest.java
+++ b/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/BridgeHoistingAccessibilityTest.java
@@ -13,7 +13,9 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.bridgeremoval.hoisting.testclasses.BridgeHoistingAccessibilityTestClasses;
+import com.android.tools.r8.bridgeremoval.hoisting.testclasses.BridgeHoistingAccessibilityTestClasses.AWithRangedInvoke;
import com.android.tools.r8.bridgeremoval.hoisting.testclasses.BridgeHoistingAccessibilityTestClasses.User;
+import com.android.tools.r8.bridgeremoval.hoisting.testclasses.BridgeHoistingAccessibilityTestClasses.UserWithRangedInvoke;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import org.junit.Test;
@@ -45,6 +47,28 @@
.transform(),
transformer(C.class)
.setBridge(C.class.getDeclaredMethod("bridgeC", Object.class))
+ .transform(),
+ transformer(BWithRangedInvoke.class)
+ .setBridge(
+ BWithRangedInvoke.class.getDeclaredMethod(
+ "bridgeB",
+ Object.class,
+ int.class,
+ int.class,
+ int.class,
+ int.class,
+ int.class))
+ .transform(),
+ transformer(CWithRangedInvoke.class)
+ .setBridge(
+ CWithRangedInvoke.class.getDeclaredMethod(
+ "bridgeC",
+ Object.class,
+ int.class,
+ int.class,
+ int.class,
+ int.class,
+ int.class))
.transform())
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
@@ -54,7 +78,7 @@
.compile()
.inspect(this::inspect)
.run(parameters.getRuntime(), TestClass.class)
- .assertSuccessWithOutputLines("Hello world!");
+ .assertSuccessWithOutputLines("Hello world!", "Hello 12345 world! 12345");
}
private void inspect(CodeInspector inspector) {
@@ -69,6 +93,11 @@
ClassSubject cClassSubject = inspector.clazz(C.class);
assertThat(cClassSubject, isPresent());
+
+ ClassSubject axClassSubject = inspector.clazz(AWithRangedInvoke.class);
+ assertThat(axClassSubject, isPresent());
+ assertThat(axClassSubject.uniqueMethodWithName("m"), isPresent());
+ assertThat(axClassSubject.uniqueMethodWithName("bridgeC"), isPresent());
}
static class TestClass {
@@ -77,6 +106,10 @@
C instance = new C();
System.out.print(instance.bridgeB("Hello"));
System.out.println(User.invokeBridgeC(instance));
+
+ CWithRangedInvoke instanceWithRangedInvoke = new CWithRangedInvoke();
+ System.out.print(instanceWithRangedInvoke.bridgeB("Hello ", 1, 2, 3, 4, 5));
+ System.out.println(UserWithRangedInvoke.invokeBridgeC(instanceWithRangedInvoke));
}
}
@@ -102,4 +135,27 @@
return (String) m((String) o);
}
}
+
+ @NeverMerge
+ static class BWithRangedInvoke extends AWithRangedInvoke {
+
+ // This bridge cannot be hoisted to A, since it would then become inaccessible to the call site
+ // in TestClass.main().
+ @NeverInline
+ /*bridge*/ String bridgeB(Object o, int a, int b, int c, int d, int e) {
+ return (String) m((String) o, a, b, c, d, e);
+ }
+ }
+
+ @NeverClassInline
+ public static class CWithRangedInvoke extends BWithRangedInvoke {
+
+ // This bridge is invoked from another package. However, this does not prevent us from hoisting
+ // the bridge to B, although B is not public, since users from outside this package can still
+ // access bridgeC() via class C. From B, the bridge can be hoisted again to A.
+ @NeverInline
+ public /*bridge*/ String bridgeC(Object o, int a, int b, int c, int d, int e) {
+ return (String) m((String) o, a, b, c, d, e);
+ }
+ }
}
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/testclasses/BridgeHoistingAccessibilityTestClasses.java b/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/testclasses/BridgeHoistingAccessibilityTestClasses.java
index bc91e00..55daf92 100644
--- a/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/testclasses/BridgeHoistingAccessibilityTestClasses.java
+++ b/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/testclasses/BridgeHoistingAccessibilityTestClasses.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.NeverMerge;
import com.android.tools.r8.bridgeremoval.hoisting.BridgeHoistingAccessibilityTest;
+import com.android.tools.r8.bridgeremoval.hoisting.BridgeHoistingAccessibilityTest.CWithRangedInvoke;
public class BridgeHoistingAccessibilityTestClasses {
@@ -26,4 +27,21 @@
return instance.bridgeC(" world!");
}
}
+
+ @NeverMerge
+ public static class AWithRangedInvoke {
+
+ @NeverInline
+ public Object m(String arg, int a, int b, int c, int d, int e) {
+ return System.currentTimeMillis() > 0 ? arg + a + b + c + d + e : null;
+ }
+ }
+
+ public static class UserWithRangedInvoke {
+
+ @NeverInline
+ public static String invokeBridgeC(CWithRangedInvoke instance) {
+ return instance.bridgeC(" world! ", 1, 2, 3, 4, 5);
+ }
+ }
}