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