| // Copyright (c) 2017, 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; | 
 |  | 
 | import inlining.Nullability.Factor; | 
 | import inlining.pkg.InterfaceImplementationContainer; | 
 | import inlining.pkg.OtherPublicClass; | 
 | import inlining.pkg.PublicClass; | 
 | import inlining.pkg.Subclass; | 
 |  | 
 | public class Inlining { | 
 |  | 
 |   private static void Assert(boolean value) { | 
 |     if (!value) { | 
 |       System.out.println("FAILURE"); | 
 |     } | 
 |   } | 
 |  | 
 |   private static void Assert(int value) { | 
 |     if (value <= 0) { | 
 |       System.out.println("FAILURE"); | 
 |     } | 
 |   } | 
 |  | 
 |   private static void fail(String msg) { | 
 |     System.out.println(msg); | 
 |     System.exit(1); | 
 |   } | 
 |  | 
 |   static void marker0() { | 
 |     System.err.printf(""); | 
 |     System.err.printf(""); | 
 |     System.err.printf(""); | 
 |   } | 
 |  | 
 |   static void marker1() { | 
 |     System.err.printf(""); | 
 |     System.err.printf(""); | 
 |     System.err.printf(""); | 
 |   } | 
 |  | 
 |   static void marker2() { | 
 |     System.err.printf(""); | 
 |     System.err.printf(""); | 
 |     System.err.printf(""); | 
 |   } | 
 |  | 
 |   public static void main(String[] args) { | 
 |     // Ensure the simple methods are called at least three times, to not be inlined due to being | 
 |     // called only once or twice. | 
 |     Assert(intExpression()); | 
 |     Assert(intExpression()); | 
 |     Assert(intExpression()); | 
 |     Assert(longExpression()); | 
 |     Assert(longExpression()); | 
 |     Assert(longExpression()); | 
 |     Assert(doubleExpression()); | 
 |     Assert(floatExpression()); | 
 |     Assert(floatExpression()); | 
 |     Assert(floatExpression()); | 
 |     Assert(stringExpression()); | 
 |     Assert(stringExpression()); | 
 |     Assert(stringExpression()); | 
 |  | 
 |     Assert(intArgumentExpression()); | 
 |     Assert(intArgumentExpression()); | 
 |     Assert(intArgumentExpression()); | 
 |     Assert(longArgumentExpression()); | 
 |     Assert(longArgumentExpression()); | 
 |     Assert(longArgumentExpression()); | 
 |     Assert(doubleArgumentExpression()); | 
 |     Assert(doubleArgumentExpression()); | 
 |     Assert(doubleArgumentExpression()); | 
 |     Assert(floatArgumentExpression()); | 
 |     Assert(floatArgumentExpression()); | 
 |     Assert(floatArgumentExpression()); | 
 |     Assert(stringArgumentExpression()); | 
 |     Assert(stringArgumentExpression()); | 
 |     Assert(stringArgumentExpression()); | 
 |  | 
 |     Assert(intAddExpression()); | 
 |     Assert(intAddExpression()); | 
 |     Assert(intAddExpression()); | 
 |  | 
 |     A b = new B(42); | 
 |     A a = new A(42); | 
 |     Assert(intCmpExpression(a, b)); | 
 |     Assert(intCmpExpression(a, b)); | 
 |     Assert(intCmpExpression(a, b)); | 
 |  | 
 |     // This is only called once! | 
 |     Assert(onlyCalledOnce(10)); | 
 |  | 
 |     // This is only called twice, and is quite small! | 
 |     Assert(onlyCalledTwice(1) == 2); | 
 |     Assert(onlyCalledTwice(1) == 2); | 
 |  | 
 |     InlineConstructor ic = InlineConstructor.create(); | 
 |     Assert(ic != null); | 
 |     InlineConstructor ic2 = InlineConstructor.createMore(); | 
 |     Assert(ic2 != null); | 
 |     InlineConstructorOfInner icoi = new InlineConstructorOfInner(); | 
 |     Assert(icoi != null); | 
 |  | 
 |     // Check that super calls are processed correctly. | 
 |     new B(123).callMethodInSuper(); | 
 |  | 
 |     // Inline calls to package private methods | 
 |     PublicClass.alsoCallsPackagePrivateMethod(); | 
 |     OtherPublicClass.callsMethodThatCallsPackagePrivateMethod(); | 
 |     // Inline calls to protected methods. | 
 |     PublicClass.callsProtectedMethod3(); | 
 |     PublicClass.alsoReadsPackagePrivateField(); | 
 |     OtherPublicClass.callsMethodThatCallsProtectedMethod(); | 
 |     OtherPublicClass.callsMethodThatReadsFieldInPackagePrivateClass(); | 
 |     Subclass.callsMethodThatCallsProtectedMethod(); | 
 |     // Do not inline constructors which set final field. | 
 |     System.out.println(new InlineConstructorFinalField()); | 
 |  | 
 |     // Call method three times to ensure it would not normally be inlined but force inline anyway. | 
 |     int aNumber = longMethodThatWeShouldNotInline("ha", "li", "lo"); | 
 |     aNumber += longMethodThatWeShouldNotInline("zi", "za", "zo"); | 
 |     aNumber += longMethodThatWeShouldNotInline("do", "de", "da"); | 
 |     System.out.println(aNumber); | 
 |  | 
 |     // Call a method that contains a call to a protected method. Should not be inlined. | 
 |     aNumber = new SubClassOfPublicClass().public_protectedMethod(0); | 
 |     System.out.println(aNumber); | 
 |  | 
 |     marker0(); | 
 |     marker0(); | 
 |     marker0(); | 
 |     marker0(); | 
 |     marker0(); | 
 |  | 
 |     Nullability n = new Nullability(2018); | 
 |     Assert(n.inlinable(a)); | 
 |     Assert(n.notInlinable(a)); | 
 |     Assert(n.conditionalOperator(a)); | 
 |     Assert(n.moreControlFlows(a, Factor.ONE)); | 
 |     Assert(n.inlinableWithPublicField(a)); | 
 |     Assert(n.inlinableWithControlFlow(a)); | 
 |     Assert(n.notInlinableDueToMissingNpe(a)); | 
 |     Assert(n.notInlinableDueToSideEffect(a)); | 
 |     Assert(n.notInlinableBecauseHidesNpe()); | 
 |     try { | 
 |       Assert(n.notInlinableDueToMissingNpeBeforeThrow(new IllegalArgumentException())); | 
 |     } catch (IllegalArgumentException expected) { | 
 |       // Expected exception | 
 |     } catch (NullPointerException unexpected) { | 
 |       System.out.println( | 
 |           "Unexpected NullPointerException for notInlinableDueToMissingNpeBeforeThrow"); | 
 |     } catch (Throwable unexpected) { | 
 |       System.out.println("Unexpected exception for notInlinableDueToMissingNpeBeforeThrow"); | 
 |     } | 
 |     try { | 
 |       Assert(n.notInlinableOnThrow(new IllegalArgumentException())); | 
 |     } catch (IllegalArgumentException expected) { | 
 |       // Expected exception | 
 |     } catch (NullPointerException unexpected) { | 
 |       System.out.println("Unexpected NullPointerException for notInlinableOnThrow"); | 
 |     } catch (Throwable unexpected) { | 
 |       System.out.println("Unexpected exception for notInlinableOnThrow"); | 
 |     } | 
 |  | 
 |     marker1(); | 
 |     marker1(); | 
 |     marker1(); | 
 |     marker1(); | 
 |     marker1(); | 
 |  | 
 |     n = maybeNull(); | 
 |     ThrowingA aa = new ThrowingA(a.a()); | 
 |     try { | 
 |       n.inlinable(aa); | 
 |     } catch (NullPointerException npe) { | 
 |       // Expected! | 
 |     } | 
 |     try { | 
 |       n.notInlinable(aa); | 
 |     } catch (NullPointerException npe) { | 
 |       // Expected! | 
 |     } | 
 |     try { | 
 |       n.conditionalOperator(aa); | 
 |     } catch (NullPointerException npe) { | 
 |       // Expected! | 
 |     } | 
 |     try { | 
 |       n.moreControlFlows(aa, Factor.TWO); | 
 |     } catch (NullPointerException npe) { | 
 |       // Expected! | 
 |     } | 
 |     try { | 
 |       n.inlinableWithPublicField(aa); | 
 |     } catch (NullPointerException npe) { | 
 |       // Expected! | 
 |     } | 
 |     try { | 
 |       n.inlinableWithControlFlow(aa); | 
 |     } catch (NullPointerException npe) { | 
 |       // Expected! | 
 |     } | 
 |     try { | 
 |       n.notInlinableDueToMissingNpe(aa); | 
 |     } catch (NullPointerException npe) { | 
 |       // Expected! | 
 |     } | 
 |     try { | 
 |       n.notInlinableDueToSideEffect(aa); | 
 |     } catch (NullPointerException npe) { | 
 |       // Expected! | 
 |     } | 
 |     try { | 
 |       Assert(n.notInlinableBecauseHidesNpe()); | 
 |       fail("Should have thrown NullPointerException"); | 
 |     } catch (NullPointerException expected) { | 
 |       // Expected exception | 
 |     } | 
 |     try { | 
 |       n.notInlinableDueToMissingNpeBeforeThrow(new IllegalArgumentException()); | 
 |     } catch (NullPointerException npe) { | 
 |       // Expected! | 
 |     } catch (Throwable t) { | 
 |       System.out.println("Unexpected exception"); | 
 |     } | 
 |     try { | 
 |       Assert(n.notInlinableDueToMissingNpeBeforeThrow(new IllegalArgumentException())); | 
 |     } catch (NullPointerException expected) { | 
 |       // Expected exception | 
 |     } catch (IllegalArgumentException unexpected) { | 
 |       System.out.println( | 
 |           "Unexpected IllegalArgumentException for notInlinableDueToMissingNpeBeforeThrow"); | 
 |     } catch (Throwable unexpected) { | 
 |       System.out.println("Unexpected exception for notInlinableDueToMissingNpeBeforeThrow"); | 
 |     } | 
 |     try { | 
 |       Assert(n.notInlinableOnThrow(new IllegalArgumentException())); | 
 |     } catch (NullPointerException expected) { | 
 |       // Expected exception | 
 |     } catch (IllegalArgumentException unexpected) { | 
 |       System.out.println("Unexpected IllegalArgumentException for notInlinableOnThrow"); | 
 |     } catch (Throwable unexpected) { | 
 |       System.out.println("Unexpected exception for notInlinableOnThrow"); | 
 |     } | 
 |  | 
 |     marker2(); | 
 |     marker2(); | 
 |     marker2(); | 
 |     marker2(); | 
 |     marker2(); | 
 |  | 
 |     System.out.println(callInterfaceMethod(InterfaceImplementationContainer.getIFace())); | 
 |   } | 
 |  | 
 |   @NeverInline | 
 |   private static Nullability maybeNull() { | 
 |     // Make sure that R8 cannot determine that this method always returns null. | 
 |     return System.currentTimeMillis() < 0 ? new Nullability(42) : null; | 
 |   } | 
 |  | 
 |   private static boolean intCmpExpression(A a, A b) { | 
 |     return a.a() == b.a(); | 
 |   } | 
 |  | 
 |   @CheckDiscarded | 
 |   private static int callInterfaceMethod(IFace i) { | 
 |     return i.foo(); | 
 |   } | 
 |  | 
 |   @CheckDiscarded | 
 |   private static int intConstantInline() { | 
 |     return 42; | 
 |   } | 
 |  | 
 |   @CheckDiscarded | 
 |   private static boolean intExpression() { | 
 |     return 42 == intConstantInline(); | 
 |   } | 
 |  | 
 |   @CheckDiscarded | 
 |   private static long longConstantInline() { | 
 |     return 50000000000L; | 
 |   } | 
 |  | 
 |   @CheckDiscarded | 
 |   private static boolean longExpression() { | 
 |     return 50000000000L == longConstantInline(); | 
 |   } | 
 |  | 
 |   @CheckDiscarded | 
 |   private static double doubleConstantInline() { | 
 |     return 42.42; | 
 |   } | 
 |  | 
 |   @CheckDiscarded | 
 |   private static boolean doubleExpression() { | 
 |     return 42.42 == doubleConstantInline(); | 
 |   } | 
 |  | 
 |   @CheckDiscarded | 
 |   private static float floatConstantInline() { | 
 |     return 21.21F; | 
 |   } | 
 |  | 
 |   @CheckDiscarded | 
 |   private static boolean floatExpression() { | 
 |     return 21.21F == floatConstantInline(); | 
 |   } | 
 |  | 
 |   @CheckDiscarded | 
 |   private static String stringConstantInline() { | 
 |     return "Fisk er godt"; | 
 |   } | 
 |  | 
 |   private static boolean stringExpression() { | 
 |     return "Fisk er godt" == stringConstantInline(); | 
 |   } | 
 |  | 
 |   @CheckDiscarded | 
 |   private static int intArgumentInline(int a, int b, int c) { | 
 |     return b; | 
 |   } | 
 |  | 
 |   @CheckDiscarded | 
 |   private static boolean intArgumentExpression() { | 
 |     return 42 == intArgumentInline(-2, 42, -1); | 
 |   } | 
 |  | 
 |   @CheckDiscarded | 
 |   private static long longArgumentInline(long a, long b, long c) { | 
 |     return c; | 
 |   } | 
 |  | 
 |   @CheckDiscarded | 
 |   private static boolean longArgumentExpression() { | 
 |     return 50000000000L == longArgumentInline(-2L, -1L, 50000000000L); | 
 |   } | 
 |  | 
 |   @CheckDiscarded | 
 |   private static double doubleArgumentInline(double a, double b, double c) { | 
 |     return a; | 
 |   } | 
 |  | 
 |   @CheckDiscarded | 
 |   private static boolean doubleArgumentExpression() { | 
 |     return 42.42 == doubleArgumentInline(42.42, -2.0, -1.0); | 
 |   } | 
 |  | 
 |   @CheckDiscarded | 
 |   private static float floatArgumentInline(float a, float b, float c) { | 
 |     return b; | 
 |   } | 
 |  | 
 |   @CheckDiscarded | 
 |   private static boolean floatArgumentExpression() { | 
 |     return 21.21F == floatArgumentInline(-2.0F, 21.21F, -1.0F); | 
 |   } | 
 |  | 
 |   @CheckDiscarded | 
 |   private static String stringArgumentInline(String a, String b, String c) { | 
 |     return c; | 
 |   } | 
 |  | 
 |   private static boolean stringArgumentExpression() { | 
 |     return "Fisk er godt" == stringArgumentInline("-1", "-1", "Fisk er godt"); | 
 |   } | 
 |  | 
 |   @CheckDiscarded | 
 |   private static int intAddInline(int a, int b) { | 
 |     return a + b; | 
 |   } | 
 |  | 
 |   @CheckDiscarded | 
 |   private static boolean intAddExpression() { | 
 |     return 42 == intAddInline(21, 21); | 
 |   } | 
 |  | 
 |   @CheckDiscarded | 
 |   private static boolean onlyCalledOnce(int count) { | 
 |     int anotherCounter = 0; | 
 |     for (int i = 0; i < count; i++) { | 
 |       anotherCounter += i; | 
 |     } | 
 |     return anotherCounter > count; | 
 |   } | 
 |  | 
 |   @CheckDiscarded | 
 |   private static int onlyCalledTwice(int count) { | 
 |     return count > 0 ? count + 1 : count - 1; | 
 |   } | 
 |  | 
 |   @AlwaysInline | 
 |   @CheckDiscarded | 
 |   private static int longMethodThatWeShouldNotInline(String a, String b, String c) { | 
 |     String result = a + b + c + b + a + c + b; | 
 |     return result.length(); | 
 |   } | 
 | } |