blob: c658673b550e563ab357ddd9dc95f1fc21fdb54f [file] [log] [blame]
// 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");
}
}
}