blob: 1335e3ea36f1553ead038fa72b4e39df9493d131 [file] [log] [blame]
// 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();
}
}