Sebastien Hertz | 1403219 | 2018-01-09 15:35:42 +0100 | [diff] [blame] | 1 | // Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file |
| 2 | // for details. All rights reserved. Use of this source code is governed by a |
| 3 | // BSD-style license that can be found in the LICENSE file. |
| 4 | |
| 5 | package inlining_with_proxy; |
| 6 | |
| 7 | import java.lang.reflect.InvocationHandler; |
| 8 | import java.lang.reflect.Method; |
| 9 | import java.lang.reflect.Proxy; |
| 10 | |
| 11 | public class Main { |
| 12 | |
| 13 | public static void main(String[] args) { |
| 14 | // We need to keep Bar so that Foo has a single implementation class. |
| 15 | Bar bar = new Bar(); |
| 16 | Object proxy = createProxyOfFoo(bar); |
| 17 | |
| 18 | Foo foo = (Foo) proxy; |
| 19 | |
| 20 | // 1st call to foo: since we don't know if foo is null or not, we cannot inline this call. |
| 21 | foo.foo(); |
| 22 | |
| 23 | // Insert some code to make sure both invokes of foo are in separate basic blocks. |
| 24 | // TODO(shertz) this should no longer be required when our type analysis manages invokes in the |
| 25 | // same block. |
| 26 | if (args != null && args.length > 0) { |
| 27 | System.out.println(args[0]); |
| 28 | } else { |
| 29 | System.out.println("No args"); |
| 30 | } |
| 31 | |
| 32 | // 2nd call to foo: at this point we know that it is non-null (otherwise the previous call would |
| 33 | // have thrown a NPE and leaves this method). However we do not know the exact type of foo, |
| 34 | // despite of class Bar being the only implementation of Foo at compilation time. Indeed, the |
| 35 | // actual receiver type is the Proxy class we created above. |
| 36 | foo.foo(); |
| 37 | |
| 38 | // We insert a 3rd call so that the 'double-inlining' condition allows the inlining of the |
| 39 | // 2nd call. |
| 40 | foo.foo(); |
| 41 | } |
| 42 | |
| 43 | private static Object createProxyOfFoo(final Object obj) { |
| 44 | Object proxyInstance = Proxy |
| 45 | .newProxyInstance(Foo.class.getClassLoader(), new Class[]{Foo.class}, |
| 46 | new InvocationHandler() { |
| 47 | @Override |
| 48 | public Object invoke(Object o, Method method, Object[] objects) throws Throwable { |
| 49 | System.out.println("Invoke " + method + " through proxy"); |
| 50 | return null; |
| 51 | } |
| 52 | }); |
| 53 | System.out.println("Created proxy class " + proxyInstance.getClass().getName() |
| 54 | + " which is a runtime implementation of Foo in addition to " + obj.getClass().getName()); |
| 55 | return proxyInstance; |
| 56 | } |
| 57 | |
| 58 | interface Foo { |
| 59 | void foo(); |
| 60 | } |
| 61 | |
| 62 | // This is the ONLY implementation of Foo (except the one created at runtime with Proxy). |
| 63 | static class Bar implements Foo { |
| 64 | |
| 65 | @Override |
| 66 | public void foo() { |
| 67 | System.out.println("Bar.foo"); |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | } |