Regression test for inlining of an invoke-interface
Bug: 71629503
Change-Id: Ifd25bd11917e315443f28b76f87c86e771719618
diff --git a/src/test/examples/inlining_with_proxy/Main.java b/src/test/examples/inlining_with_proxy/Main.java
new file mode 100644
index 0000000..c658673
--- /dev/null
+++ b/src/test/examples/inlining_with_proxy/Main.java
@@ -0,0 +1,71 @@
+// Copyright (c) 2018, 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 inlining_with_proxy;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+public class Main {
+
+ public static void main(String[] args) {
+ // We need to keep Bar so that Foo has a single implementation class.
+ Bar bar = new Bar();
+ Object proxy = createProxyOfFoo(bar);
+
+ Foo foo = (Foo) proxy;
+
+ // 1st call to foo: since we don't know if foo is null or not, we cannot inline this call.
+ foo.foo();
+
+ // Insert some code to make sure both invokes of foo are in separate basic blocks.
+ // TODO(shertz) this should no longer be required when our type analysis manages invokes in the
+ // same block.
+ if (args != null && args.length > 0) {
+ System.out.println(args[0]);
+ } else {
+ System.out.println("No args");
+ }
+
+ // 2nd call to foo: at this point we know that it is non-null (otherwise the previous call would
+ // have thrown a NPE and leaves this method). However we do not know the exact type of foo,
+ // despite of class Bar being the only implementation of Foo at compilation time. Indeed, the
+ // actual receiver type is the Proxy class we created above.
+ foo.foo();
+
+ // We insert a 3rd call so that the 'double-inlining' condition allows the inlining of the
+ // 2nd call.
+ foo.foo();
+ }
+
+ private static Object createProxyOfFoo(final Object obj) {
+ Object proxyInstance = Proxy
+ .newProxyInstance(Foo.class.getClassLoader(), new Class[]{Foo.class},
+ new InvocationHandler() {
+ @Override
+ public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
+ System.out.println("Invoke " + method + " through proxy");
+ return null;
+ }
+ });
+ System.out.println("Created proxy class " + proxyInstance.getClass().getName()
+ + " which is a runtime implementation of Foo in addition to " + obj.getClass().getName());
+ return proxyInstance;
+ }
+
+ interface Foo {
+ void foo();
+ }
+
+ // This is the ONLY implementation of Foo (except the one created at runtime with Proxy).
+ static class Bar implements Foo {
+
+ @Override
+ public void foo() {
+ System.out.println("Bar.foo");
+ }
+ }
+
+}
diff --git a/src/test/examples/inlining_with_proxy/keep-rules.txt b/src/test/examples/inlining_with_proxy/keep-rules.txt
new file mode 100644
index 0000000..d36a4a3
--- /dev/null
+++ b/src/test/examples/inlining_with_proxy/keep-rules.txt
@@ -0,0 +1,11 @@
+# Copyright (c) 2018, 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.
+
+# Keep the application entry point. Get rid of everything that is not
+# reachable from there.
+-keep public class * {
+ public static void main(...);
+}
+
+-dontobfuscate
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/R8StaticInlining.java b/src/test/java/com/android/tools/r8/ir/optimize/R8InliningRegressionTests.java
similarity index 73%
rename from src/test/java/com/android/tools/r8/ir/optimize/R8StaticInlining.java
rename to src/test/java/com/android/tools/r8/ir/optimize/R8InliningRegressionTests.java
index ca047e6..7011006 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/R8StaticInlining.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/R8InliningRegressionTests.java
@@ -12,41 +12,31 @@
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.FileUtils;
-import com.google.common.collect.ImmutableList;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.Collection;
import org.junit.Assume;
+import org.junit.Ignore;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
/**
* This test verifies that semantic of class initialization is preserved when a static method
* invocation is inlined.
*/
-@RunWith(Parameterized.class)
-public class R8StaticInlining extends TestBase {
+// TODO(shertz) add CF output
+public class R8InliningRegressionTests extends TestBase {
- // TODO(shertz) add CF output
- @Parameters(name = "{0}_{1}")
- public static Collection<String[]> data() {
- return ImmutableList.of(
- new String[]{"staticinlining", "staticinlining.Main"}
- );
- }
-
- private final String folder;
- private final String mainClass;
-
- public R8StaticInlining(String folder, String mainClass) {
- this.folder = folder;
- this.mainClass = mainClass;
+ @Test
+ public void testStaticInlining_b71524812() throws Exception {
+ buildAndTest("staticinlining", "staticinlining.Main");
}
@Test
- public void testInliningOfStatic() throws Exception {
+ @Ignore("b/71629503")
+ public void testInterfaceInlining_b71629503() throws Exception {
+ buildAndTest("inlining_with_proxy", "inlining_with_proxy.Main");
+ }
+
+ private void buildAndTest(String folder, String mainClass) throws Exception {
Assume.assumeTrue(ToolHelper.artSupported());
Path proguardRules = Paths.get(ToolHelper.EXAMPLES_DIR, folder, "keep-rules.txt");