/* * Copyright (c) 2020 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. *
*/
/** * @test * @bug 8227745 * @summary Collection of test cases that check if optimizations based on escape analysis are reverted just before non-escaping objects escape through JVMTI. * @author Richard Reingruber richard DOT reingruber AT sap DOT com * * @requires ((vm.compMode == "Xmixed") & vm.compiler2.enabled) * @library /test/lib /test/hotspot/jtreg * * @run build TestScaffold VMConnection TargetListener TargetAdapter jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run compile -g EATests.java * @run driver EATests * -XX:+UnlockDiagnosticVMOptions * -Xms256m -Xmx256m * -Xbootclasspath/a:. * -XX:CompileCommand=dontinline,*::dontinline_* * -XX:+WhiteBoxAPI * -Xbatch * -XX:+DoEscapeAnalysis -XX:+EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks * @run driver EATests * -XX:+UnlockDiagnosticVMOptions * -Xms256m -Xmx256m * -Xbootclasspath/a:. * -XX:CompileCommand=dontinline,*::dontinline_* * -XX:+WhiteBoxAPI * -Xbatch * -XX:+DoEscapeAnalysis -XX:+EliminateAllocations -XX:-EliminateLocks -XX:+EliminateNestedLocks * @run driver EATests * -XX:+UnlockDiagnosticVMOptions * -Xms256m -Xmx256m * -Xbootclasspath/a:. * -XX:CompileCommand=dontinline,*::dontinline_* * -XX:+WhiteBoxAPI * -Xbatch * -XX:+DoEscapeAnalysis -XX:-EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks * @run driver EATests * -XX:+UnlockDiagnosticVMOptions * -Xms256m -Xmx256m * -Xbootclasspath/a:. * -XX:CompileCommand=dontinline,*::dontinline_* * -XX:+WhiteBoxAPI * -Xbatch * -XX:-DoEscapeAnalysis -XX:-EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks * * @comment Excercise -XX:+DeoptimizeObjectsALot. Mostly to prevent bit-rot because the option is meant to stress object deoptimization * with non-synthetic workloads. * @run driver EATests * -XX:+UnlockDiagnosticVMOptions * -Xms256m -Xmx256m * -Xbootclasspath/a:. * -XX:CompileCommand=dontinline,*::dontinline_* * -XX:+WhiteBoxAPI * -Xbatch * -XX:-DoEscapeAnalysis -XX:-EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks * -XX:+IgnoreUnrecognizedVMOptions -XX:+DeoptimizeObjectsALot *
*/ /** * @test * @bug 8227745 * * @summary This is another configuration of EATests.java to test Graal. Some testcases are expected * to fail because Graal does not provide all information about non-escaping objects in * scope. These are skipped. * * @author Richard Reingruber richard DOT reingruber AT sap DOT com * * @requires ((vm.compMode == "Xmixed") & vm.graal.enabled) * * @library /test/lib /test/hotspot/jtreg * * @run build TestScaffold VMConnection TargetListener TargetAdapter jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run compile -g EATests.java * * @comment Test with Graal. Some testcases are expected to fail because Graal does not provide all information about non-escaping * objects in scope. These are skipped. * @run driver EATests * -XX:+UnlockDiagnosticVMOptions * -Xms256m -Xmx256m * -Xbootclasspath/a:. * -XX:CompileCommand=dontinline,*::dontinline_* * -XX:+WhiteBoxAPI * -Xbatch * -XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler
*/
// // ANALYZING TEST FAILURES // // - Executing just a single test case with the property EATests.onlytestcase. // // Example: java -DEATests.onlytestcase=<test case name> ... EATests // // - Interactive execution allows for attaching a native debugger, e.g. gdb // // Example: java -DEATests.interactive=true ... EATests // // - Java arguments to the test are passed as vm options to the debuggee: // // Example: java ... EATests -XX:+UseNewCode //
///////////////////////////////////////////////////////////////////////////// // // Shared base class for test cases for both, debugger and debuggee. // /////////////////////////////////////////////////////////////////////////////
class EATestCaseBaseShared { // In interactive mode we wait for a keypress before every test case. publicstaticfinalboolean INTERACTIVE =
System.getProperty("EATests.interactive") != null &&
System.getProperty("EATests.interactive").equals("true");
// If the property is given, then just the test case it refers to is executed. // Use it to diagnose test failures. publicstaticfinal String RUN_ONLY_TEST_CASE_PROPERTY = "EATests.onlytestcase"; publicstaticfinal String RUN_ONLY_TEST_CASE = System.getProperty(RUN_ONLY_TEST_CASE_PROPERTY);
///////////////////////////////////////////////////////////////////////////// // // Target main class, i.e. the program to be debugged. // /////////////////////////////////////////////////////////////////////////////
// Materializing test cases, i.e. reallocating objects on the heap new EAMaterializeLocalVariableUponGetTarget() .run(); new EAGetWithoutMaterializeTarget() .run(); new EAMaterializeLocalAtObjectReturnTarget() .run(); new EAMaterializeLocalAtObjectPollReturnReturnTarget() .run(); new EAMaterializeIntArrayTarget() .run(); new EAMaterializeLongArrayTarget() .run(); new EAMaterializeFloatArrayTarget() .run(); new EAMaterializeDoubleArrayTarget() .run(); new EAMaterializeObjectArrayTarget() .run(); new EAMaterializeObjectWithConstantAndNotConstantValuesTarget() .run(); new EAMaterializeObjReferencedBy2LocalsTarget() .run(); new EAMaterializeObjReferencedBy2LocalsAndModifyTarget() .run(); new EAMaterializeObjReferencedBy2LocalsInDifferentVirtFramesTarget() .run(); new EAMaterializeObjReferencedBy2LocalsInDifferentVirtFramesAndModifyTarget() .run(); new EAMaterializeObjReferencedFromOperandStackTarget() .run(); new EAMaterializeLocalVariableUponGetAfterSetIntegerTarget() .run();
// Relocking test cases new EARelockingSimpleTarget() .run(); new EARelockingRecursiveTarget() .run(); new EARelockingNestedInflatedTarget() .run(); new EARelockingNestedInflated_02Target() .run(); new EARelockingArgEscapeLWLockedInCalleeFrameTarget() .run(); new EARelockingArgEscapeLWLockedInCalleeFrame_2Target() .run(); new EAGetOwnedMonitorsTarget() .run(); new EAEntryCountTarget() .run(); new EARelockingObjectCurrentlyWaitingOnTarget() .run();
// Test cases that require deoptimization even though neither // locks nor allocations are eliminated at the point where // escape state is changed. new EADeoptFrameAfterReadLocalObject_01Target() .run(); new EADeoptFrameAfterReadLocalObject_01BTarget() .run(); new EADeoptFrameAfterReadLocalObject_02Target() .run(); new EADeoptFrameAfterReadLocalObject_02BTarget() .run(); new EADeoptFrameAfterReadLocalObject_02CTarget() .run(); new EADeoptFrameAfterReadLocalObject_03Target() .run();
// PopFrame test cases new EAPopFrameNotInlinedTarget() .run(); new EAPopFrameNotInlinedReallocFailureTarget() .run(); new EAPopInlinedMethodWithScalarReplacedObjectsReallocFailureTarget() .run();
// ForceEarlyReturn test cases new EAForceEarlyReturnNotInlinedTarget() .run(); new EAForceEarlyReturnOfInlinedMethodWithScalarReplacedObjectsTarget() .run(); new EAForceEarlyReturnOfInlinedMethodWithScalarReplacedObjectsReallocFailureTarget().run();
// Instances of ReferenceType new EAGetInstancesOfReferenceTypeTarget() .run();
}
}
///////////////////////////////////////////////////////////////////////////// // // Debugger main class // /////////////////////////////////////////////////////////////////////////////
publicclass EATests extends TestScaffold {
public TargetVMOptions targetVMOptions; public ThreadReference targetMainThread;
public TargetVMOptions(EATests env, ClassType testCaseBaseTargetClass) {
Value val;
val = testCaseBaseTargetClass.getValue(testCaseBaseTargetClass.fieldByName("DoEscapeAnalysis"));
DoEscapeAnalysis = ((PrimitiveValue) val).booleanValue(); // Escape analysis is a prerequisite for scalar replacement (EliminateAllocations)
val = testCaseBaseTargetClass.getValue(testCaseBaseTargetClass.fieldByName("EliminateAllocations"));
EliminateAllocations = DoEscapeAnalysis && ((PrimitiveValue) val).booleanValue();
val = testCaseBaseTargetClass.getValue(testCaseBaseTargetClass.fieldByName("DeoptimizeObjectsALot"));
DeoptimizeObjectsALot = ((PrimitiveValue) val).booleanValue();
val = testCaseBaseTargetClass.getValue(testCaseBaseTargetClass.fieldByName("UseJVMCICompiler"));
UseJVMCICompiler = ((PrimitiveValue) val).booleanValue();
val = testCaseBaseTargetClass.getValue(testCaseBaseTargetClass.fieldByName("ZGCIsSelected"));
ZGCIsSelected = ((PrimitiveValue) val).booleanValue();
val = testCaseBaseTargetClass.getValue(testCaseBaseTargetClass.fieldByName("StressReflectiveCode"));
StressReflectiveCode = ((PrimitiveValue) val).booleanValue();
}
}
// Execute known test cases protectedvoid runTests() throws Exception {
String targetProgName = EATestsTarget.class.getName();
msg("starting to main method in class " + targetProgName);
startToMain(targetProgName);
msg("resuming to EATestCaseBaseTarget.staticSetUpDone()V");
targetMainThread = resumeTo("EATestCaseBaseTarget", "staticSetUpDone", "()V").thread();
Location loc = targetMainThread.frame(0).location();
Asserts.assertEQ("staticSetUpDone", loc.method().name());
targetVMOptions = new TargetVMOptions(this, (ClassType) loc.declaringType());
// Materializing test cases, i.e. reallocating objects on the heap new EAMaterializeLocalVariableUponGet() .run(this); new EAGetWithoutMaterialize() .run(this); new EAMaterializeLocalAtObjectReturn() .run(this); new EAMaterializeLocalAtObjectPollReturnReturn() .run(this); new EAMaterializeIntArray() .run(this); new EAMaterializeLongArray() .run(this); new EAMaterializeFloatArray() .run(this); new EAMaterializeDoubleArray() .run(this); new EAMaterializeObjectArray() .run(this); new EAMaterializeObjectWithConstantAndNotConstantValues() .run(this); new EAMaterializeObjReferencedBy2Locals() .run(this); new EAMaterializeObjReferencedBy2LocalsAndModify() .run(this); new EAMaterializeObjReferencedBy2LocalsInDifferentVirtFrames() .run(this); new EAMaterializeObjReferencedBy2LocalsInDifferentVirtFramesAndModify() .run(this); new EAMaterializeObjReferencedFromOperandStack() .run(this); new EAMaterializeLocalVariableUponGetAfterSetInteger() .run(this);
// Relocking test cases new EARelockingSimple() .run(this); new EARelockingRecursive() .run(this); new EARelockingNestedInflated() .run(this); new EARelockingNestedInflated_02() .run(this); new EARelockingArgEscapeLWLockedInCalleeFrame() .run(this); new EARelockingArgEscapeLWLockedInCalleeFrame_2() .run(this); new EAGetOwnedMonitors() .run(this); new EAEntryCount() .run(this); new EARelockingObjectCurrentlyWaitingOn() .run(this);
// Test cases that require deoptimization even though neither // locks nor allocations are eliminated at the point where // escape state is changed. new EADeoptFrameAfterReadLocalObject_01() .run(this); new EADeoptFrameAfterReadLocalObject_01B() .run(this); new EADeoptFrameAfterReadLocalObject_02() .run(this); new EADeoptFrameAfterReadLocalObject_02B() .run(this); new EADeoptFrameAfterReadLocalObject_02C() .run(this); new EADeoptFrameAfterReadLocalObject_03() .run(this);
// PopFrame test cases new EAPopFrameNotInlined() .run(this); new EAPopFrameNotInlinedReallocFailure() .run(this); new EAPopInlinedMethodWithScalarReplacedObjectsReallocFailure() .run(this);
// ForceEarlyReturn test cases new EAForceEarlyReturnNotInlined() .run(this); new EAForceEarlyReturnOfInlinedMethodWithScalarReplacedObjects() .run(this); new EAForceEarlyReturnOfInlinedMethodWithScalarReplacedObjectsReallocFailure().run(this);
// Instances of ReferenceType new EAGetInstancesOfReferenceType() .run(this);
// resume the target listening for events
listenUntilVMDisconnect();
}
// Print a Message publicvoid msg(String m) {
System.out.println();
System.out.println("###(Debugger) " + m);
System.out.println();
}
///////////////////////////////////////////////////////////////////////////// // // Base class for debugger side of test cases. // /////////////////////////////////////////////////////////////////////////////
@Override publicboolean shouldSkip() { // Skip if StressReflectiveCode because it effectively disables escape analysis returnsuper.shouldSkip() || env.targetVMOptions.StressReflectiveCode;
}
publicvoid run(EATests env) { this.env = env; if (shouldSkip()) {
msg("skipping " + testCaseName); return;
} try {
msgHL("Executing test case " + getClass().getName());
env.testFailed = false;
if (INTERACTIVE)
env.waitForInput();
resumeToWarmupDone();
runTestCase();
Asserts.assertTrue(env.targetMainThread.isSuspended(), "must be suspended after the testcase");
resumeToTestCaseDone();
checkPostConditions();
} catch (Exception e) {
Asserts.fail("Unexpected exception in test case " + getClass().getName(), e);
}
}
/** * Set a breakpoint in the given method and resume all threads. The * breakpoint is configured to suspend just the thread that reaches it * instead of all threads. This is important when running with graal.
*/ public BreakpointEvent resumeTo(String clsName, String methodName, String signature) { boolean suspendThreadOnly = true; return env.resumeTo(clsName, methodName, signature, suspendThreadOnly);
}
/** * Retrieve array of primitive values referenced by a local variable in target and compare with * an array of expected values. * @param frame Frame in the target holding the local variable * @param lName Name of the local variable referencing the array to be retrieved * @param desc Array element type given as field descriptor. * @param expVals Array of expected values. * @throws Exception
*/ protectedvoid checkLocalPrimitiveArray(StackFrame frame, String lName, FD desc, Object expVals) throws Exception {
String lType = FD2JDIArrType.get(desc);
Asserts.assertNotNull(lType, "jdi type not found");
Asserts.assertEQ(EATestCaseBaseTarget.TESTMETHOD_DEFAULT_NAME, frame .location().method().name());
List<LocalVariable> localVars = frame.visibleVariables();
msg("Check if the local array variable '" + lName + "' in " + EATestCaseBaseTarget.TESTMETHOD_DEFAULT_NAME + " has the expected elements: "); boolean found = false; for (LocalVariable lv : localVars) { if (lv.name().equals(lName)) {
found = true;
Value lVal = frame.getValue(lv);
Asserts.assertNotNull(lVal);
Asserts.assertEQ(lVal.type().name(), lType);
ArrayReference aRef = (ArrayReference) lVal;
Asserts.assertEQ(3, aRef.length()); // now check the elements for (int i = 0; i < aRef.length(); i++) {
Object actVal = FD2getter.get(desc).apply((PrimitiveValue)aRef.getValue(i));
Object expVal = Array.get(expVals, i);
Asserts.assertEQ(expVal, actVal, "checking element at index " + i);
}
}
}
Asserts.assertTrue(found);
msg("OK.");
}
/** * Retrieve array of objects referenced by a local variable in target and compare with an array * of expected values. * @param frame Frame in the target holding the local variable * @param lName Name of the local variable referencing the array to be retrieved * @param lType Local type, e.g. java.lang.Long[] * @param expVals Array of expected values. * @throws Exception
*/ protectedvoid checkLocalObjectArray(StackFrame frame, String lName, String lType, ObjectReference[] expVals) throws Exception {
Asserts.assertEQ(EATestCaseBaseTarget.TESTMETHOD_DEFAULT_NAME, frame .location().method().name());
List<LocalVariable> localVars = frame.visibleVariables();
msg("Check if the local array variable '" + lName + "' in " + EATestCaseBaseTarget.TESTMETHOD_DEFAULT_NAME + " has the expected elements: "); boolean found = false; for (LocalVariable lv : localVars) { if (lv.name().equals(lName)) {
found = true;
Value lVal = frame.getValue(lv);
Asserts.assertNotNull(lVal);
Asserts.assertEQ(lType, lVal.type().name());
ArrayReference aRef = (ArrayReference) lVal;
Asserts.assertEQ(3, aRef.length()); // now check the elements for (int i = 0; i < aRef.length(); i++) {
ObjectReference actVal = (ObjectReference)aRef.getValue(i);
Asserts.assertSame(expVals[i], actVal, "checking element at index " + i);
}
}
}
Asserts.assertTrue(found);
msg("OK.");
}
/** * Retrieve a reference held by a local variable in the given frame. Check if the frame's method * is the expected method if the retrieved local value has the expected type and is not null. * @param frame The frame to retrieve the local variable value from. * @param expectedMethodName The name of the frames method should match the expectedMethodName. * @param lName The name of the local variable which is read. * @param expectedType Is the expected type of the object referenced by the local variable. * @return * @throws Exception
*/ protected ObjectReference getLocalRef(StackFrame frame, String expectedMethodName, String lName, String expectedType) throws Exception {
Asserts.assertEQ(expectedMethodName, frame.location().method().name());
List<LocalVariable> localVars = frame.visibleVariables();
msg("Get and check local variable '" + lName + "' in " + expectedMethodName);
ObjectReference lRef = null; for (LocalVariable lv : localVars) { if (lv.name().equals(lName)) {
Value lVal = frame.getValue(lv);
Asserts.assertNotNull(lVal);
Asserts.assertEQ(expectedType, lVal.type().name());
lRef = (ObjectReference) lVal; break;
}
}
Asserts.assertNotNull(lRef, "Local variable '" + lName + "' not found");
msg("OK."); return lRef;
}
/** * Retrieve a reference held by a local variable in the given frame. Check if the frame's method * matches {@link EATestCaseBaseTarget#TESTMETHOD_DEFAULT_NAME} if the retrieved local value has * the expected type and is not null. * @param frame The frame to retrieve the local variable value from. * @param expectedMethodName The name of the frames method should match the expectedMethodName. * @param lName The name of the local variable which is read. * @param expectedType Is the expected type of the object referenced by the local variable. * @return * @throws Exception
*/ protected ObjectReference getLocalRef(StackFrame frame, String lType, String lName) throws Exception { return getLocalRef(frame, EATestCaseBaseTarget.TESTMETHOD_DEFAULT_NAME, lName, lType);
}
/** * Set the value of a local variable in the given frame. Check if the frame's method is the expected method. * @param frame The frame holding the local variable. * @param expectedMethodName The expected name of the frame's method. * @param lName The name of the local variable to change. * @param val The new value of the local variable. * @throws Exception
*/ publicvoid setLocal(StackFrame frame, String expectedMethodName, String lName, Value val) throws Exception {
Asserts.assertEQ(expectedMethodName, frame.location().method().name());
List<LocalVariable> localVars = frame.visibleVariables();
msg("Set local variable '" + lName + "' = " + val + " in " + expectedMethodName); for (LocalVariable lv : localVars) { if (lv.name().equals(lName)) {
frame.setValue(lv, val); break;
}
}
msg("OK.");
}
/** * Set the value of a local variable in the given frame. Check if the frame's method matches * {@link EATestCaseBaseTarget#TESTMETHOD_DEFAULT_NAME}. * @param frame The frame holding the local variable. * @param expectedMethodName The expected name of the frame's method. * @param lName The name of the local variable to change. * @param val The new value of the local variable. * @throws Exception
*/ publicvoid setLocal(StackFrame frame, String lName, Value val) throws Exception {
setLocal(frame, EATestCaseBaseTarget.TESTMETHOD_DEFAULT_NAME, lName, val);
}
/** * Check if a field has the expected primitive value. * @param o Object holding the field. * @param desc Field descriptor. * @param fName Field name * @param expVal Expected primitive value * @throws Exception
*/ protectedvoid checkPrimitiveField(ObjectReference o, FD desc, String fName, Object expVal) throws Exception {
msg("check field " + fName);
ReferenceType rt = o.referenceType();
Field fld = rt.fieldByName(fName);
Value val = o.getValue(fld);
Object actVal = FD2getter.get(desc).apply((PrimitiveValue) val);
Asserts.assertEQ(expVal, actVal, "field '" + fName + "' has unexpected value.");
msg("ok");
}
/** * Check if a field references the expected object. * @param obj Object holding the field. * @param fName Field name * @param expVal Object expected to be referenced by the field * @throws Exception
*/ protectedvoid checkObjField(ObjectReference obj, String fName, ObjectReference expVal) throws Exception {
msg("check field " + fName);
ReferenceType rt = obj.referenceType();
Field fld = rt.fieldByName(fName);
Value actVal = obj.getValue(fld);
Asserts.assertEQ(expVal, actVal, "field '" + fName + "' has unexpected value.");
msg("ok");
}
protected Value getField(ObjectReference obj, String fName) throws Exception {
msg("get field " + fName);
ReferenceType rt = obj.referenceType();
Field fld = rt.fieldByName(fName);
Value val = obj.getValue(fld);
msg("result : " + val); return val;
}
/** * Free the memory consumed in the target by {@link EATestCaseBaseTarget#consumedMemory} * @throws Exception
*/ publicvoid freeAllMemory() throws Exception {
msg("free consumed memory");
setField(testCase, "consumedMemory", null);
}
/** * @return The value of {@link EATestCaseBaseTarget#targetIsInLoop}. The target must set that field to true as soon as it * enters the endless loop. * @throws Exception
*/ publicboolean targetHasEnteredEndlessLoop() throws Exception {
Value v = getField(testCase, "targetIsInLoop"); return ((PrimitiveValue) v).booleanValue();
}
/** * Poll {@link EATestCaseBaseTarget#targetIsInLoop} and return if it is found to be true. * @throws Exception
*/ publicvoid waitUntilTargetHasEnteredEndlessLoop() throws Exception { while(!targetHasEnteredEndlessLoop()) {
msg("Target has not yet entered the loop. Sleep 200ms."); try { Thread.sleep(200); } catch (InterruptedException e) { /*ignore */ }
}
}
/** * Set {@link EATestCaseBaseTarget#doLoop} to <code>false</code>. This will allow the target to * leave the endless loop. * @throws Exception
*/ publicvoid terminateEndlessLoop() throws Exception {
msg("terminate loop");
setField(testCase, "doLoop", env.vm().mirrorOf(false));
}
}
///////////////////////////////////////////////////////////////////////////// // // Base class for debuggee side of test cases. // /////////////////////////////////////////////////////////////////////////////
// Some of the fields are only read by the debugger publicstaticfinalboolean UseJVMCICompiler = unbox(WB.getBooleanVMFlag("UseJVMCICompiler"), false); publicstaticfinalboolean DoEscapeAnalysis = unbox(WB.getBooleanVMFlag("DoEscapeAnalysis"), UseJVMCICompiler); publicstaticfinalboolean EliminateAllocations = unbox(WB.getBooleanVMFlag("EliminateAllocations"), UseJVMCICompiler); publicstaticfinalboolean DeoptimizeObjectsALot = WB.getBooleanVMFlag("DeoptimizeObjectsALot"); publicstaticfinalboolean ZGCIsSelected = GC.Z.isSelected(); publicstaticfinalboolean StressReflectiveCode = unbox(WB.getBooleanVMFlag("StressReflectiveCode"), false);
public String testMethodName; publicint testMethodDepth;
// Results produced by dontinline_testMethod() publicint iResult; publiclong lResult; publicfloat fResult; publicdouble dResult;
publicboolean warmupDone;
// an object with an inflated monitor publicstatic XYVal inflatedLock; publicstaticThread inflatorThread; publicstaticboolean inflatedLockIsPermanentlyInflated;
/** * It is a common protocol to have the debugger set a breakpoint in this method and have {@link * #dontinline_testMethod()} call it and then perform some test actions on debugger side. * After that it is checked if a frame of {@link #dontinline_testMethod()} is found at the * expected depth on stack and if it is (not) marked for deoptimization as expected.
*/ publicvoid dontinline_brkpt() { // will set breakpoint here after warmup if (warmupDone) { // check if test method is at expected depth
StackTraceElement[] frames = Thread.currentThread().getStackTrace(); int stackTraceDepth = testMethodDepth + 1; // ignore java.lang.Thread.getStackTrace()
Asserts.assertEQ(testMethodName, frames[stackTraceDepth].getMethodName(),
testCaseName + ": test method not found at depth " + testMethodDepth); // check if the frame is (not) deoptimized as expected if (!DeoptimizeObjectsALot) { if (testFrameShouldBeDeoptimized()) {
Asserts.assertTrue(WB.isFrameDeoptimized(testMethodDepth+1),
testCaseName + ": expected test method frame at depth " + testMethodDepth + " to be deoptimized");
} else {
Asserts.assertFalse(WB.isFrameDeoptimized(testMethodDepth+1),
testCaseName + ": expected test method frame at depth " + testMethodDepth + " not to be deoptimized");
}
}
}
}
/** * Some test cases run busy endless loops by initializing {@link #loopCount} * to {@link Long#MAX_VALUE} after warm-up and then counting down to 0 in their main test method. * During warm-up {@link #loopCount} is initialized to a small value.
*/ publiclong dontinline_endlessLoop() { long cs = checkSum;
doLoop = true; while (loopCount-- > 0 && doLoop) {
targetIsInLoop = true;
checkSum += checkSum % ++cs;
}
loopCount = 3;
targetIsInLoop = false; return checkSum;
}
// Debugger will set breakpoint here to sync with target. publicvoid testCaseDone() {
}
publicvoid compileTestMethod() throws Exception { int callCount = CompilerWhiteBoxTest.THRESHOLD; while (callCount-- > 0) {
dontinline_testMethod();
}
}
publicvoid checkCompLevel() {
java.lang.reflect.Method m = null; try {
m = getClass().getMethod(TESTMETHOD_DEFAULT_NAME);
} catch (NoSuchMethodException | SecurityException e) {
Asserts.fail("could not check compilation level of", e);
} int highestLevel = CompilerUtils.getMaxCompilationLevel(); int compLevel = WB.getMethodCompilationLevel(m); if (!UseJVMCICompiler) {
Asserts.assertEQ(highestLevel, compLevel,
m + " not on expected compilation level");
} else { // Background compilation (-Xbatch) will block a thread with timeout // (see CompileBroker::wait_for_jvmci_completion()). Therefore it is // possible to reach here before the main test method is compiled. // In that case we wait for it to be compiled. while (compLevel != highestLevel) {
msg(TESTMETHOD_DEFAULT_NAME + " is compiled on level " + compLevel + ". Wait until highes level (" + highestLevel + ") is reached."); try { Thread.sleep(200);
} catch (InterruptedException e) { /* ignored */ }
compLevel = WB.getMethodCompilationLevel(m);
}
}
}
// to be overridden as appropriate publicint getExpectedIResult() { return 0;
}
// to be overridden as appropriate publiclong getExpectedLResult() { return 0;
}
// to be overridden as appropriate publicfloat getExpectedFResult() { return 0f;
}
// to be overridden as appropriate publicdouble getExpectedDResult() { return 0d;
}
// The object passed will be ArgEscape if it was NoEscape before. publicfinalvoid dontinline_make_arg_escape(XYVal xy) {
}
/** * Call a method indirectly using reflection. The indirection is a limit for escape * analysis in the sense that the VM need not search beyond for frames that might have * an object being read by an JVMTI agent as ArgEscape. * @param receiver The receiver object of the call. * @param methodName The name of the method to be called.
*/ publicfinalvoid dontinline_call_with_entry_frame(Object receiver, String methodName) {
Asserts.assertTrue(warmupDone, "We want to take the slow path through jni, so don't call in warmup");
// // Tests the following: // // 1. Debugger can obtain a reference to a scalar replaced object R from java thread J. // See runTestCase. // // 2. Subsequent modifications of R by J are noticed by the debugger. // See checkPostConditions. // class EAMaterializeLocalVariableUponGet extends EATestCaseBaseDebugger {
private ObjectReference o;
publicvoid runTestCase() throws Exception {
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
printStack(bpe.thread()); // check 1.
o = getLocalRef(bpe.thread().frame(1), XYVAL_NAME, "xy"); // o is referenced in checkPostConditions() and must not be gc'ed.
o.disableCollection();
checkPrimitiveField(o, FD.I, "x", 4);
checkPrimitiveField(o, FD.I, "y", 2);
}
// Test if an eliminated object can be reallocated in a frame with an active // call that will return another object class EAMaterializeLocalAtObjectReturn extends EATestCaseBaseDebugger { publicvoid runTestCase() throws Exception {
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
printStack(bpe.thread());
ObjectReference o = getLocalRef(bpe.thread().frame(2), XYVAL_NAME, "xy");
checkPrimitiveField(o, FD.I, "x", 4);
checkPrimitiveField(o, FD.I, "y", 2);
}
}
public Integer dontinline_brkpt_return_Integer() { // We can't break directly in this method, as this results in making // the test method not entrant caused by an existing dependency
dontinline_brkpt(); return Integer.valueOf(23);
}
// Test if an eliminated object can be reallocated *just* before a call returns an object. // (See CompiledMethod::is_at_poll_return()) // Details: the callee method has just one safepoint poll at the return. The other safepoint // is at the end of an iteration of the endless loop. We can detect if we suspended the target // there because the local xy is out of scope there. class EAMaterializeLocalAtObjectPollReturnReturn extends EATestCaseBaseDebugger { publicvoid runTestCase() throws Exception {
msg("Resume " + env.targetMainThread);
env.vm().resume();
waitUntilTargetHasEnteredEndlessLoop();
ObjectReference o = null; int retryCount = 0; do {
env.targetMainThread.suspend();
printStack(env.targetMainThread); try {
o = getLocalRef(env.targetMainThread.frame(0), XYVAL_NAME, "xy");
} catch (Exception e) {
++retryCount;
msg("The local variable xy is out of scope because we suspended at the wrong bci. Resume and try again! (" + retryCount + ")");
env.targetMainThread.resume(); if ((retryCount % 10) == 0) { Thread.sleep(200);
}
}
} while (o == null);
checkPrimitiveField(o, FD.I, "x", 4);
checkPrimitiveField(o, FD.I, "y", 2);
terminateEndlessLoop();
}
}
publicvoid dontinline_testMethod() { long result = 0; while (doLoop && loopCount-- > 0) {
targetIsInLoop = true;
XYVal xy = new XYVal(4, 2);
Integer io = // Read xy here triggers reallocation just before the call returns
dontinline_brkpt_return_Integer();
result += xy.x + xy.y + io;
} // Here is a second safepoint. We were suspended here if xy is not in scope.
targetIsInLoop = false;
lResult = result;
}
public Integer dontinline_brkpt_return_Integer() { return Integer.valueOf(23);
}
///////////////////////////////////////////////////////////////////////////// // Test case collection that tests rematerialization of different // array types where the first element is always not constant and the // other elements are constants. Not constant values are stored in // the stack frame for rematerialization whereas constants are kept // in the debug info of the nmethod.
class EAMaterializeIntArrayTarget extends EATestCaseBaseTarget {
// Materialize an object whose fields have constant and not constant values at // the point where the object is materialized. class EAMaterializeObjectWithConstantAndNotConstantValuesTarget extends EATestCaseBaseTarget {
// Two local variables reference the same object. // Check if the debugger obtains the same object when reading the two variables class EAMaterializeObjReferencedBy2LocalsTarget extends EATestCaseBaseTarget {
publicvoid dontinline_testMethod() {
XYVal xy = new XYVal(2, 3);
XYVal alias = xy;
dontinline_brkpt();
iResult = xy.x + alias.x;
}
// Two local variables reference the same object. // Check if it has the expected effect in the target if the debugger modifies the object. class EAMaterializeObjReferencedBy2LocalsAndModifyTarget extends EATestCaseBaseTarget {
// Two local variables of the same compiled frame but in different virtual frames reference the same // object. // Check if the debugger obtains the same object when reading the two variables class EAMaterializeObjReferencedBy2LocalsInDifferentVirtFramesTarget extends EATestCaseBaseTarget {
// Two local variables of the same compiled frame but in different virtual frames reference the same // object. // Check if it has the expected effect in the target if the debugger modifies the object. class EAMaterializeObjReferencedBy2LocalsInDifferentVirtFramesAndModifyTarget extends EATestCaseBaseTarget {
// Test materialization of an object referenced only from expression stack class EAMaterializeObjReferencedFromOperandStackTarget extends EATestCaseBaseTarget {
publicvoid dontinline_testMethod() {
@SuppressWarnings("unused")
XYVal xy1 = new XYVal(2, 3); // Debugger breaks in call to dontinline_brkpt_ret_100() and reads // the value of the local 'xy1'. This triggers materialization // of the object on the operand stack
iResult = testMethodInlined(new XYVal(4, 2), dontinline_brkpt_ret_100());
}
/** * Tests a regression in the implementation by setting the value of a local int which triggers the * creation of a deferred update and then getting the reference to a scalar replaced object. The * issue was that the scalar replaced object was not reallocated. Because of the deferred update it * was assumed that the reallocation already happened.
*/ class EAMaterializeLocalVariableUponGetAfterSetInteger extends EATestCaseBaseDebugger {
// Object ref l1 is retrieved by the debugger at a location where nested locks are omitted. The // accessed object is globally reachable already before the access, therefore no relocking is done. class EARelockingNestedInflatedTarget extends EATestCaseBaseTarget {
/** * Like {@link EARelockingNestedInflated} with the difference that there is * a scalar replaced object in the scope from which the object with eliminated nested locking * is read. This triggers materialization and relocking.
*/ class EARelockingNestedInflated_02 extends EATestCaseBaseDebugger {
/** * Checks if an eliminated lock of an ArgEscape object l1 can be relocked if * l1 is locked in a callee frame.
*/ class EARelockingArgEscapeLWLockedInCalleeFrame extends EATestCaseBaseDebugger {
@Override publicboolean testFrameShouldBeDeoptimized() { // Graal does not provide debug info about arg escape objects, therefore the frame is not deoptimized return !UseJVMCICompiler && super.testFrameShouldBeDeoptimized();
}
}
/** * Similar to {@link EARelockingArgEscapeLWLockedInCalleeFrame}. In addition * the test method has got a scalar replaced object with eliminated locking. * This pattern matches a regression in the implementation.
*/ class EARelockingArgEscapeLWLockedInCalleeFrame_2 extends EATestCaseBaseDebugger {
/** * Test relocking eliminated (nested) locks of an object on which the * target thread currently waits.
*/ class EARelockingObjectCurrentlyWaitingOn extends EATestCaseBaseDebugger {
publicvoid runTestCase() throws Exception {
env.vm().resume(); boolean inWait = false; do { Thread.sleep(100);
env.targetMainThread.suspend();
printStack(env.targetMainThread);
inWait = env.targetMainThread.frame(0).location().method().name().equals("wait0"); if (!inWait) {
msg("Target not yet in java.lang.Object.wait(long).");
env.targetMainThread.resume();
}
} while(!inWait);
StackFrame testMethodFrame = env.targetMainThread.frame(5); // Access triggers relocking of all eliminated locks, including nested locks of l1 which references // the object on which the target main thread is currently waiting.
ObjectReference l0 = getLocalRef(testMethodFrame, EARelockingObjectCurrentlyWaitingOnTarget.ForLocking.class.getName(), "l0");
Asserts.assertEQ(l0.entryCount(), 1, "wrong entry count");
ObjectReference l1 = getLocalRef(testMethodFrame, EARelockingObjectCurrentlyWaitingOnTarget.ForLocking.class.getName(), "l1");
Asserts.assertEQ(l1.entryCount(), 0, "wrong entry count");
setField(testCase, "objToNotifyOn", l1);
}
}
class EARelockingObjectCurrentlyWaitingOnTarget extends EATestCaseBaseTarget {
publicstaticclass ForLocking {
}
publicvolatile Object objToNotifyOn; // debugger assigns value when notify thread should call objToNotifyOn.notifyAll()
publicvoid doNotify() { while (objToNotifyOn == null) { try {
msg("objToNotifyOn is still null"); Thread.sleep(100);
} catch (InterruptedException e) { /* ignored */ }
} synchronized (objToNotifyOn) { // will be received by the target main thread waiting in dontinline_waitWhenWarmupDone
msg("calling objToNotifyOn.notifyAll()");
objToNotifyOn.notifyAll();
}
}
///////////////////////////////////////////////////////////////////////////// // // Test cases that require deoptimization even though neither locks // nor allocations are eliminated at the point where escape state is changed. // /////////////////////////////////////////////////////////////////////////////
/** * Let xy be NoEscape whose allocation cannot be eliminated (simulated by * -XX:-EliminateAllocations). The holding compiled frame has to be deoptimized when debugger * accesses xy because afterwards locking on xy is omitted. * Note: there are no EA based optimizations at the escape point.
*/ class EADeoptFrameAfterReadLocalObject_01 extends EATestCaseBaseDebugger {
class EADeoptFrameAfterReadLocalObject_01Target extends EATestCaseBaseTarget {
publicvoid dontinline_testMethod() {
XYVal xy = new XYVal(1, 1);
dontinline_brkpt(); // Debugger reads xy, when there are no virtual objects or eliminated locks in scope synchronized (xy) { // Locking is eliminated.
xy.x++;
xy.y++;
}
}
}
/** * Similar to {@link EADeoptFrameAfterReadLocalObject_01} with the difference that the debugger * reads xy from an inlined callee. So xy is NoEscape instead of ArgEscape.
*/ class EADeoptFrameAfterReadLocalObject_01BTarget extends EATestCaseBaseTarget {
publicvoid dontinline_testMethod() {
XYVal xy = new XYVal(1, 1);
callee(xy); // Debugger acquires ref to xy from inlined callee // xy is NoEscape, nevertheless the object is not replaced // by scalars if running with -XX:-EliminateAllocations. // In that case there are no EA based optimizations were // the debugger reads the NoEscape object. synchronized (xy) { // Locking is eliminated.
xy.x++;
xy.y++;
}
}
publicvoid callee(XYVal xy) {
dontinline_brkpt(); // Debugger reads xy. // There are no virtual objects or eliminated locks.
}
}
class EADeoptFrameAfterReadLocalObject_01B extends EATestCaseBaseDebugger {
/** * Let xy be ArgEscape. The frame dontinline_testMethod() has to be deoptimized when debugger * acquires xy from dontinline_callee() because afterwards locking on xy is omitted. * Note: there are no EA based optimizations at the escape point.
*/ class EADeoptFrameAfterReadLocalObject_02 extends EATestCaseBaseDebugger {
@Override publicboolean testFrameShouldBeDeoptimized() { // Graal does not provide debug info about arg escape objects, therefore the frame is not deoptimized return !UseJVMCICompiler && super.testFrameShouldBeDeoptimized();
}
}
/** * Similar to {@link EADeoptFrameAfterReadLocalObject_02} there is an ArgEscape object xy, but in * contrast it is not in the parameter list of a call when the debugger reads an object. * Therefore the frame of the test method should not be deoptimized
*/ class EADeoptFrameAfterReadLocalObject_02B extends EATestCaseBaseDebugger {
class EADeoptFrameAfterReadLocalObject_02BTarget extends EATestCaseBaseTarget {
publicvoid dontinline_testMethod() {
XYVal xy = new XYVal(1, 1);
dontinline_make_arg_escape(xy); // because of this call xy is ArgEscape
dontinline_callee(); // xy is ArgEscape, but not a parameter of this call synchronized (xy) { // Locking is eliminated.
xy.x++;
xy.y++;
}
}
publicvoid dontinline_callee() {
@SuppressWarnings("unused")
XYVal xy = new XYVal(2, 2);
dontinline_brkpt(); // Debugger reads xy. // No need to deoptimize the caller frame
}
/** * Similar to {@link EADeoptFrameAfterReadLocalObject_02} there is an ArgEscape object xy in * dontinline_testMethod() which is being passed as parameter when the debugger accesses a local object. * Nevertheless dontinline_testMethod must not be deoptimized because there is an entry frame * between it and the frame accessed by the debugger.
*/ class EADeoptFrameAfterReadLocalObject_02C extends EATestCaseBaseDebugger {
class EADeoptFrameAfterReadLocalObject_02CTarget extends EATestCaseBaseTarget {
publicvoid dontinline_testMethod() {
XYVal xy = new XYVal(1, 1);
dontinline_callee(xy); // xy is ArgEscape and being passed as parameter synchronized (xy) { // Locking is eliminated.
xy.x++;
xy.y++;
}
}
publicvoid dontinline_callee_accessed_by_debugger() {
@SuppressWarnings("unused")
XYVal xy = new XYVal(2, 2);
dontinline_brkpt(); // Debugger reads xy. // No need to deoptimize the caller frame
}
@Override publicvoid setUp() { super.setUp(); // the method depth in debuggee is 11 as it includes all hidden frames // the expected method depth is 6 excluding 5 hidden frames
testMethodDepth = 11-5;
}
/** * Let xy be NoEscape whose allocation cannot be eliminated (e.g. because of * -XX:-EliminateAllocations). The holding compiled frame has to be deoptimized when debugger * accesses xy because the following field accesses get eliminated. Note: there are no EA based * optimizations at the escape point.
*/ class EADeoptFrameAfterReadLocalObject_03 extends EATestCaseBaseDebugger {
class EADeoptFrameAfterReadLocalObject_03Target extends EATestCaseBaseTarget {
publicvoid dontinline_testMethod() {
XYVal xy = new XYVal(0, 1);
dontinline_brkpt(); // Debugger reads xy, when there are no virtual objects or // eliminated locks in scope and modifies xy.x
iResult = xy.x + xy.y; // Loads are replaced by constants 0 and 1.
}
class EAGetOwnedMonitors extends EATestCaseBaseDebugger {
publicvoid runTestCase() throws Exception {
msg("resume");
env.vm().resume();
waitUntilTargetHasEnteredEndlessLoop(); // In contrast to JVMTI, JDWP requires a target thread to be suspended, before the owned monitors can be queried
msg("suspend target");
env.targetMainThread.suspend();
msg("Get owned monitors");
List<ObjectReference> monitors = env.targetMainThread.ownedMonitors();
Asserts.assertEQ(monitors.size(), 1, "unexpected number of owned monitors");
terminateEndlessLoop();
}
}
class EAEntryCount extends EATestCaseBaseDebugger {
publicvoid runTestCase() throws Exception {
msg("resume");
env.vm().resume();
waitUntilTargetHasEnteredEndlessLoop(); // In contrast to JVMTI, JDWP requires a target thread to be suspended, before the owned monitors can be queried
msg("suspend target");
env.targetMainThread.suspend();
msg("Get owned monitors");
List<ObjectReference> monitors = env.targetMainThread.ownedMonitors();
Asserts.assertEQ(monitors.size(), 1, "unexpected number of owned monitors");
msg("Get entry count"); int entryCount = monitors.get(0).entryCount();
Asserts.assertEQ(entryCount, 2, "wrong entry count");
terminateEndlessLoop();
}
}
@Override publicboolean testFrameShouldBeDeoptimized() { // Test is only performed after the frame pop. // Then dontinline_testMethod is interpreted. returnfalse;
}
/** * Pop frames into {@link EAPopFrameNotInlinedReallocFailureTarget#dontinline_testMethod()} which * holds scalar replaced objects. In preparation of the pop frame operations the vm eagerly * reallocates scalar replaced objects to avoid failures when actually popping the frames. We provoke * a reallocation failures and expect {@link VMOutOfMemoryException}.
*/ class EAPopFrameNotInlinedReallocFailure extends EATestCaseBaseDebugger {
publicvoid runTestCase() throws Exception {
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
ThreadReference thread = bpe.thread();
printStack(thread); // frame[0]: EATestCaseBaseTarget.dontinline_brkpt() // frame[1]: EAPopFrameNotInlinedReallocFailureTarget.dontinline_consume_all_memory_brkpt() // frame[2]: EAPopFrameNotInlinedReallocFailureTarget.dontinline_testMethod() // frame[3]: EATestCaseBaseTarget.run() // frame[4]: EATestsTarget.main(java.lang.String[])
msg("PopFrame"); boolean coughtOom = false; try { // try to pop dontinline_consume_all_memory_brkpt thread.popFrames(thread.frame(1));
} catch (VMOutOfMemoryException oom) { // as expected
msg("cought OOM");
coughtOom = true;
}
freeAllMemory(); // We succeeded to pop just one frame. When we continue, we will call dontinline_brkpt() again.
Asserts.assertTrue(coughtOom, "PopFrame should have triggered an OOM exception in target");
String expectedTopFrame = "dontinline_consume_all_memory_brkpt";
Asserts.assertEQ(expectedTopFrame, thread.frame(0).location().method().name());
printStack(thread);
}
@Override publicboolean shouldSkip() { // OOMEs because of realloc failures with DeoptimizeObjectsALot are too random. // And Graal currently doesn't provide all information about non-escaping objects in debug info returnsuper.shouldSkip() ||
!env.targetVMOptions.EliminateAllocations || // With ZGC the OOME is not always thrown as expected
env.targetVMOptions.ZGCIsSelected ||
env.targetVMOptions.DeoptimizeObjectsALot ||
env.targetVMOptions.UseJVMCICompiler;
}
}
class EAPopFrameNotInlinedReallocFailureTarget extends EATestCaseBaseTarget {
@Override publiclong getExpectedLResult() { long n = 10; return 2*n*(n+1)/2;
}
@Override publicboolean shouldSkip() { // OOMEs because of realloc failures with DeoptimizeObjectsALot are too random. // And Graal currently doesn't provide all information about non-escaping objects in debug info returnsuper.shouldSkip() ||
!EliminateAllocations || // With ZGC the OOME is not always thrown as expected
ZGCIsSelected ||
DeoptimizeObjectsALot ||
UseJVMCICompiler;
}
}
/** * Pop inlined top frame dropping into method with scalar replaced opjects.
*/ class EAPopInlinedMethodWithScalarReplacedObjectsReallocFailure extends EATestCaseBaseDebugger {
msg("Pop Frames"); boolean coughtOom = false; try { thread.popFrames(thread.frame(0)); // Request pop frame of inlinedCallForcedToReturn() // reallocation is triggered here
} catch (VMOutOfMemoryException oom) { // as expected
msg("cought OOM");
coughtOom = true;
}
printStack(thread); // frame[0]: EAPopInlinedMethodWithScalarReplacedObjectsReallocFailureTarget.inlinedCallForcedToReturn() // frame[1]: EAPopInlinedMethodWithScalarReplacedObjectsReallocFailureTarget.dontinline_testMethod() // frame[2]: EATestCaseBaseTarget.run()
freeAllMemory();
setField(testCase, "loopCount", env.vm().mirrorOf(0)); // terminate loop
Asserts.assertTrue(coughtOom, "PopFrame should have triggered an OOM exception in target");
String expectedTopFrame = "inlinedCallForcedToReturn";
Asserts.assertEQ(expectedTopFrame, thread.frame(0).location().method().name());
}
@Override publicboolean shouldSkip() { // OOMEs because of realloc failures with DeoptimizeObjectsALot are too random. // And Graal currently doesn't provide all information about non-escaping objects in debug info returnsuper.shouldSkip() ||
!env.targetVMOptions.EliminateAllocations || // With ZGC the OOME is not always thrown as expected
env.targetVMOptions.ZGCIsSelected ||
env.targetVMOptions.DeoptimizeObjectsALot ||
env.targetVMOptions.UseJVMCICompiler;
}
}
class EAPopInlinedMethodWithScalarReplacedObjectsReallocFailureTarget extends EATestCaseBaseTarget {
@Override publicboolean shouldSkip() { // OOMEs because of realloc failures with DeoptimizeObjectsALot are too random. // And Graal currently doesn't provide all information about non-escaping objects in debug info returnsuper.shouldSkip() ||
!EliminateAllocations || // With ZGC the OOME is not always thrown as expected
ZGCIsSelected ||
DeoptimizeObjectsALot ||
UseJVMCICompiler;
}
}
msg("Step out");
env.stepOut(thread); // return from dontinline_brkpt
printStack(thread);
msg("ForceEarlyReturn"); thread.forceEarlyReturn(env.vm().mirrorOf(43)); // return from dontinline_brkpt_iret, // does not trigger reallocation in contrast to PopFrame
msg("Step over line");
env.stepOverLine(thread); // reallocation is triggered here
printStack(thread);
msg("ForceEarlyReturn DONE");
}
@Override publicboolean shouldSkip() { // Graal currently doesn't support Force Early Return returnsuper.shouldSkip() || env.targetVMOptions.UseJVMCICompiler;
}
}
class EAForceEarlyReturnNotInlinedTarget extends EATestCaseBaseTarget {
publicvoid dontinline_testMethod() {
XYVal xy = new XYVal(4, 2); int i = dontinline_brkpt_iret();
iResult = xy.x + xy.y + i;
}
/** * ForceEarlyReturn at safepoint in frame with scalar replaced objects.
*/ class EAForceEarlyReturnOfInlinedMethodWithScalarReplacedObjects extends EATestCaseBaseDebugger {
msg("ForceEarlyReturn"); thread.forceEarlyReturn(env.vm().mirrorOf(43)); // Request force return 43 from inlinedCallForcedToReturn() // reallocation is triggered here
msg("Step over instruction to do the forced return");
env.stepOverInstruction(thread);
printStack(thread);
msg("ForceEarlyReturn DONE");
}
@Override publicboolean shouldSkip() { // Graal currently doesn't support Force Early Return returnsuper.shouldSkip() || env.targetVMOptions.UseJVMCICompiler;
}
}
class EAForceEarlyReturnOfInlinedMethodWithScalarReplacedObjectsTarget extends EATestCaseBaseTarget {
publicint checkSum;
publicvoid dontinline_testMethod() {
XYVal xy = new XYVal(4, 2); int i = inlinedCallForcedToReturn();
iResult = xy.x + xy.y + i;
}
publicint inlinedCallForcedToReturn() { // forced to return 43 int i = checkSum; while (loopCount-- > 0) {
targetIsInLoop = true;
checkSum += checkSum % ++i;
}
loopCount = 3;
targetIsInLoop = false; return checkSum;
}
msg("ForceEarlyReturn"); boolean coughtOom = false; try { thread.forceEarlyReturn(env.vm().mirrorOf(43)); // Request force return 43 from inlinedCallForcedToReturn() // reallocation is triggered here
} catch (VMOutOfMemoryException oom) { // as expected
msg("cought OOM");
coughtOom = true;
}
freeAllMemory();
Asserts.assertTrue(coughtOom, "ForceEarlyReturn should have triggered an OOM exception in target");
printStack(thread);
msg("ForceEarlyReturn(2)"); thread.forceEarlyReturn(env.vm().mirrorOf(43));
msg("Step over instruction to do the forced return");
env.stepOverInstruction(thread);
printStack(thread);
msg("ForceEarlyReturn DONE");
}
@Override publicboolean shouldSkip() { // OOMEs because of realloc failures with DeoptimizeObjectsALot are too random. // And Graal currently doesn't support Force Early Return returnsuper.shouldSkip() ||
!env.targetVMOptions.EliminateAllocations || // With ZGC the OOME is not always thrown as expected
env.targetVMOptions.ZGCIsSelected ||
env.targetVMOptions.DeoptimizeObjectsALot ||
env.targetVMOptions.UseJVMCICompiler;
}
}
class EAForceEarlyReturnOfInlinedMethodWithScalarReplacedObjectsReallocFailureTarget extends EATestCaseBaseTarget {
@Override publicboolean shouldSkip() { // OOMEs because of realloc failures with DeoptimizeObjectsALot are too random. // And Graal currently doesn't support Force Early Return returnsuper.shouldSkip() ||
!EliminateAllocations || // With ZGC the OOME is not always thrown as expected
ZGCIsSelected ||
DeoptimizeObjectsALot ||
UseJVMCICompiler;
}
}
///////////////////////////////////////////////////////////////////////////// // // Get Instances of ReferenceType // /////////////////////////////////////////////////////////////////////////////
/** * Check if instances of a type are found even if they are scalar replaced. To stress the * implementation a little more, the instances should be retrieved while the target is running.
*/ class EAGetInstancesOfReferenceType extends EATestCaseBaseDebugger {
publicvoid runTestCase() throws Exception {
printStack(env.targetMainThread);
ReferenceType cls = ((ClassObjectReference)getField(testCase, "cls")).reflectedType();
msg("reflected type is " + cls);
msg("resume");
env.vm().resume();
waitUntilTargetHasEnteredEndlessLoop(); // do this while thread is running!
msg("Retrieve instances of " + cls.name());
List<ObjectReference> instances = cls.instances(10);
Asserts.assertEQ(instances.size(), 3, "unexpected number of instances of " + cls.name()); // invariant: main thread is suspended at the end of the test case
msg("suspend");
env.targetMainThread.suspend();
terminateEndlessLoop();
}
}
class EAGetInstancesOfReferenceTypeTarget extends EATestCaseBaseTarget {
// End of test case collection /////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////// // Helper classes class XYVal {
publicint x, y;
public XYVal(int x, int y) { this.x = x; this.y = y;
}
/** * Note that we don't use a sync block here because javac would generate an synthetic exception * handler for the synchronized block that catches Throwable E, unlocks and throws E * again. The throw bytecode causes the BCEscapeAnalyzer to set the escape state to GlobalEscape * (see comment on exception handlers in BCEscapeAnalyzer::iterate_blocks())
*/ publicsynchronizedvoid dontinline_sync_method(EATestCaseBaseTarget target) {
target.dontinline_brkpt();
}
/** * Just like {@link #dontinline_sync_method(EATestCaseBaseTarget)} but without the call to * {@link EATestCaseBaseTarget#dontinline_brkpt()}.
*/ publicsynchronizedvoid dontinline_sync_method_no_brkpt(EATestCaseBaseTarget target) {
}
}
class Vector10 { int i0, i1, i2, i3, i4, i5, i6, i7, i8, i9; public Vector10(int j0, int j1, int j2, int j3, int j4, int j5, int j6, int j7, int j8, int j9) {
i0=j0; i1=j1; i2=j2; i3=j3; i4=j4; i5=j5; i6=j6; i7=j7; i8=j8; i9=j9;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.