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