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