blob: c658673b550e563ab357ddd9dc95f1fc21fdb54f [file] [log] [blame]
Sebastien Hertz14032192018-01-09 15:35:42 +01001// 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
5package inlining_with_proxy;
6
7import java.lang.reflect.InvocationHandler;
8import java.lang.reflect.Method;
9import java.lang.reflect.Proxy;
10
11public 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}