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");
+ }
+ }
+
+}