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