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