You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
321 lines
10 KiB
321 lines
10 KiB
/*
|
|
* Copyright (C) 2016 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
public class Main {
|
|
public static void main(String[] args) {
|
|
System.loadLibrary(args[0]);
|
|
new SubMain();
|
|
if ($noinline$returnInt() != 53) {
|
|
throw new Error("Unexpected return value");
|
|
}
|
|
if ($noinline$returnFloat() != 42.2f) {
|
|
throw new Error("Unexpected return value");
|
|
}
|
|
if ($noinline$returnDouble() != Double.longBitsToDouble(0xF000000000001111L)) {
|
|
throw new Error("Unexpected return value ");
|
|
}
|
|
if ($noinline$returnLong() != 0xFFFF000000001111L) {
|
|
throw new Error("Unexpected return value");
|
|
}
|
|
|
|
try {
|
|
$noinline$deopt();
|
|
} catch (Exception e) {}
|
|
DeoptimizationController.stopDeoptimization();
|
|
|
|
$noinline$inlineCache(new Main(), /* isSecondInvocation */ false);
|
|
if ($noinline$inlineCache(new SubMain(), /* isSecondInvocation */ true) != SubMain.class) {
|
|
throw new Error("Unexpected return value");
|
|
}
|
|
|
|
$noinline$inlineCache2(new Main(), /* isSecondInvocation */ false);
|
|
if ($noinline$inlineCache2(new SubMain(), /* isSecondInvocation */ true) != SubMain.class) {
|
|
throw new Error("Unexpected return value");
|
|
}
|
|
|
|
// Test polymorphic inline cache to the same target (inlineCache3).
|
|
$noinline$inlineCache3(new Main(), /* isSecondInvocation */ false);
|
|
$noinline$inlineCache3(new SubMain(), /* isSecondInvocation */ false);
|
|
if ($noinline$inlineCache3(new SubMain(), /* isSecondInvocation */ true) != null) {
|
|
throw new Error("Unexpected return value");
|
|
}
|
|
|
|
$noinline$stackOverflow(new Main(), /* isSecondInvocation */ false);
|
|
$noinline$stackOverflow(new SubMain(), /* isSecondInvocation */ true);
|
|
|
|
$opt$noinline$testOsrInlineLoop(null);
|
|
System.out.println("b28210356 passed.");
|
|
}
|
|
|
|
public static int $noinline$returnInt() {
|
|
// If we are running in non-JIT mode, or were unlucky enough to get this method
|
|
// already JITted, skip the wait for OSR code.
|
|
boolean interpreting = isInInterpreter("$noinline$returnInt");
|
|
int i = 0;
|
|
for (; i < 100000; ++i) {
|
|
}
|
|
if (interpreting) {
|
|
while (!isInOsrCode("$noinline$returnInt")) {}
|
|
}
|
|
System.out.println(i);
|
|
return 53;
|
|
}
|
|
|
|
public static float $noinline$returnFloat() {
|
|
// If we are running in non-JIT mode, or were unlucky enough to get this method
|
|
// already JITted, skip the wait for OSR code.
|
|
boolean interpreting = isInInterpreter("$noinline$returnFloat");
|
|
int i = 0;
|
|
for (; i < 200000; ++i) {
|
|
}
|
|
if (interpreting) {
|
|
while (!isInOsrCode("$noinline$returnFloat")) {}
|
|
}
|
|
System.out.println(i);
|
|
return 42.2f;
|
|
}
|
|
|
|
public static double $noinline$returnDouble() {
|
|
// If we are running in non-JIT mode, or were unlucky enough to get this method
|
|
// already JITted, skip the wait for OSR code.
|
|
boolean interpreting = isInInterpreter("$noinline$returnDouble");
|
|
int i = 0;
|
|
for (; i < 300000; ++i) {
|
|
}
|
|
if (interpreting) {
|
|
while (!isInOsrCode("$noinline$returnDouble")) {}
|
|
}
|
|
System.out.println(i);
|
|
return Double.longBitsToDouble(0xF000000000001111L);
|
|
}
|
|
|
|
public static long $noinline$returnLong() {
|
|
// If we are running in non-JIT mode, or were unlucky enough to get this method
|
|
// already JITted, skip the wait for OSR code.
|
|
boolean interpreting = isInInterpreter("$noinline$returnLong");
|
|
int i = 0;
|
|
for (; i < 400000; ++i) {
|
|
}
|
|
if (interpreting) {
|
|
while (!isInOsrCode("$noinline$returnLong")) {}
|
|
}
|
|
System.out.println(i);
|
|
return 0xFFFF000000001111L;
|
|
}
|
|
|
|
public static void $noinline$deopt() {
|
|
// If we are running in non-JIT mode, or were unlucky enough to get this method
|
|
// already JITted, skip the wait for OSR code.
|
|
boolean interpreting = isInInterpreter("$noinline$deopt");
|
|
int i = 0;
|
|
for (; i < 100000; ++i) {
|
|
}
|
|
if (interpreting) {
|
|
while (!isInOsrCode("$noinline$deopt")) {}
|
|
}
|
|
DeoptimizationController.startDeoptimization();
|
|
}
|
|
|
|
public static Class<?> $noinline$inlineCache(Main m, boolean isSecondInvocation) {
|
|
// If we are running in non-JIT mode, or were unlucky enough to get this method
|
|
// already JITted, just return the expected value.
|
|
if (!isInInterpreter("$noinline$inlineCache")) {
|
|
return SubMain.class;
|
|
}
|
|
|
|
ensureHasProfilingInfo("$noinline$inlineCache");
|
|
|
|
// Ensure that we have OSR code to jump to.
|
|
if (isSecondInvocation) {
|
|
ensureHasOsrCode("$noinline$inlineCache");
|
|
}
|
|
|
|
// This call will be optimized in the OSR compiled code
|
|
// to check and deoptimize if m is not of type 'Main'.
|
|
Main other = m.inlineCache();
|
|
|
|
// Jump to OSR compiled code. The second run
|
|
// of this method will have 'm' as a SubMain, and the compiled
|
|
// code we are jumping to will have wrongly optimize other as being a
|
|
// 'Main'.
|
|
if (isSecondInvocation) {
|
|
while (!isInOsrCode("$noinline$inlineCache")) {}
|
|
}
|
|
|
|
// We used to wrongly optimize this call and assume 'other' was a 'Main'.
|
|
return other.returnClass();
|
|
}
|
|
|
|
public static Class<?> $noinline$inlineCache2(Main m, boolean isSecondInvocation) {
|
|
// If we are running in non-JIT mode, or were unlucky enough to get this method
|
|
// already JITted, just return the expected value.
|
|
if (!isInInterpreter("$noinline$inlineCache2")) {
|
|
return SubMain.class;
|
|
}
|
|
|
|
ensureHasProfilingInfo("$noinline$inlineCache2");
|
|
|
|
// Ensure that we have OSR code to jump to.
|
|
if (isSecondInvocation) {
|
|
ensureHasOsrCode("$noinline$inlineCache2");
|
|
}
|
|
|
|
// This call will be optimized in the OSR compiled code
|
|
// to check and deoptimize if m is not of type 'Main'.
|
|
Main other = m.inlineCache2();
|
|
|
|
// Jump to OSR compiled code. The second run
|
|
// of this method will have 'm' as a SubMain, and the compiled
|
|
// code we are jumping to will have wrongly optimize other as being null.
|
|
if (isSecondInvocation) {
|
|
while (!isInOsrCode("$noinline$inlineCache2")) {}
|
|
}
|
|
|
|
// We used to wrongly optimize this code and assume 'other' was always null.
|
|
return (other == null) ? null : other.returnClass();
|
|
}
|
|
|
|
public static Class<?> $noinline$inlineCache3(Main m, boolean isSecondInvocation) {
|
|
// If we are running in non-JIT mode, or were unlucky enough to get this method
|
|
// already JITted, just return the expected value.
|
|
if (!isInInterpreter("$noinline$inlineCache3")) {
|
|
return null;
|
|
}
|
|
|
|
ensureHasProfilingInfo("$noinline$inlineCache3");
|
|
|
|
// Ensure that we have OSR code to jump to.
|
|
if (isSecondInvocation) {
|
|
ensureHasOsrCode("$noinline$inlineCache3");
|
|
}
|
|
|
|
// This call will be optimized in the OSR compiled code
|
|
// to check and deoptimize if m is not of type 'Main'.
|
|
Main other = m.inlineCache3();
|
|
|
|
// Jump to OSR compiled code. The second run
|
|
// of this method will have 'm' as a SubMain, and the compiled
|
|
// code we are jumping to will have wrongly optimize other as being null.
|
|
if (isSecondInvocation) {
|
|
while (!isInOsrCode("$noinline$inlineCache3")) {}
|
|
}
|
|
|
|
// We used to wrongly optimize this code and assume 'other' was always null.
|
|
return (other == null) ? null : other.returnClass();
|
|
}
|
|
|
|
public Main inlineCache() {
|
|
return new Main();
|
|
}
|
|
|
|
public Main inlineCache2() {
|
|
return null;
|
|
}
|
|
|
|
public Main inlineCache3() {
|
|
return null;
|
|
}
|
|
|
|
public Class<?> returnClass() {
|
|
return Main.class;
|
|
}
|
|
|
|
public void otherInlineCache() {
|
|
return;
|
|
}
|
|
|
|
public static void $noinline$stackOverflow(Main m, boolean isSecondInvocation) {
|
|
// If we are running in non-JIT mode, or were unlucky enough to get this method
|
|
// already JITted, just return the expected value.
|
|
if (!isInInterpreter("$noinline$stackOverflow")) {
|
|
return;
|
|
}
|
|
|
|
// We need a ProfilingInfo object to populate the 'otherInlineCache' call.
|
|
ensureHasProfilingInfo("$noinline$stackOverflow");
|
|
|
|
if (isSecondInvocation) {
|
|
// Ensure we have an OSR code and we jump to it.
|
|
while (!isInOsrCode("$noinline$stackOverflow")) {}
|
|
}
|
|
|
|
for (int i = 0; i < (isSecondInvocation ? 10000000 : 1); ++i) {
|
|
// The first invocation of $noinline$stackOverflow will populate the inline
|
|
// cache with Main. The second invocation of the method, will see a SubMain
|
|
// and will therefore trigger deoptimization.
|
|
m.otherInlineCache();
|
|
}
|
|
}
|
|
|
|
public static void $opt$noinline$testOsrInlineLoop(String[] args) {
|
|
// Regression test for inlining a method with a loop to a method without a loop in OSR mode.
|
|
assertIntEquals(12, $opt$inline$testRemoveSuspendCheck(12, 5));
|
|
// Since we cannot have a loop directly in this method, we need to force the OSR
|
|
// compilation from native code.
|
|
ensureHasProfilingInfo("$opt$noinline$testOsrInlineLoop");
|
|
ensureHasOsrCode("$opt$noinline$testOsrInlineLoop");
|
|
}
|
|
|
|
public static int $opt$inline$testRemoveSuspendCheck(int x, int y) {
|
|
// For this test we need an inlined loop and have DCE re-run loop analysis
|
|
// after inlining.
|
|
while (y > 0) {
|
|
while ($opt$inline$inlineFalse() || !$opt$inline$inlineTrue()) {
|
|
x++;
|
|
}
|
|
y--;
|
|
}
|
|
return x;
|
|
}
|
|
|
|
public static boolean $opt$inline$inlineTrue() {
|
|
return true;
|
|
}
|
|
|
|
public static boolean $opt$inline$inlineFalse() {
|
|
return false;
|
|
}
|
|
|
|
public static void assertIntEquals(int expected, int result) {
|
|
if (expected != result) {
|
|
throw new Error("Expected: " + expected + ", found: " + result);
|
|
}
|
|
}
|
|
|
|
public static native boolean isInOsrCode(String methodName);
|
|
public static native boolean isInInterpreter(String methodName);
|
|
public static native void ensureHasProfilingInfo(String methodName);
|
|
public static native void ensureHasOsrCode(String methodName);
|
|
}
|
|
|
|
class SubMain extends Main {
|
|
public Class<?> returnClass() {
|
|
return SubMain.class;
|
|
}
|
|
|
|
public Main inlineCache() {
|
|
return new SubMain();
|
|
}
|
|
|
|
public Main inlineCache2() {
|
|
return new SubMain();
|
|
}
|
|
|
|
public void otherInlineCache() {
|
|
return;
|
|
}
|
|
}
|