6fad6af0de
Reviewed-by: pchilanomate, rkennke
3530 lines
130 KiB
Java
3530 lines
130 KiB
Java
/*
|
|
* Copyright (c) 2020, 2024 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
|
|
* -XX:LockingMode=1
|
|
* @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:LockingMode=1
|
|
* @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:LockingMode=1
|
|
* @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:LockingMode=1
|
|
*
|
|
* @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:LockingMode=2
|
|
* @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:LockingMode=2
|
|
* @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:LockingMode=2
|
|
* @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:LockingMode=2
|
|
*
|
|
* @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
|
|
*
|
|
* @bug 8324881
|
|
* @comment Regression test for using the wrong thread when logging during re-locking from deoptimization.
|
|
*
|
|
* @comment DiagnoseSyncOnValueBasedClasses=2 will cause logging when locking on \@ValueBased objects.
|
|
* @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:LockingMode=1
|
|
* -XX:DiagnoseSyncOnValueBasedClasses=2
|
|
*
|
|
* @comment Re-lock may inflate monitors when re-locking, which cause monitorinflation trace logging.
|
|
* @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:LockingMode=2
|
|
* -Xlog:monitorinflation=trace:file=monitorinflation.log
|
|
*
|
|
* @comment Re-lock may race with deflation.
|
|
* @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:LockingMode=0
|
|
* -XX:GuaranteedAsyncDeflationInterval=1000
|
|
*
|
|
* @bug 8341819
|
|
* @comment Regression test for re-locking racing with deflation with LM_LIGHTWEIGHT.
|
|
* @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:LockingMode=2
|
|
* -XX:GuaranteedAsyncDeflationInterval=1
|
|
*/
|
|
|
|
/**
|
|
* @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
|
|
*/
|
|
|
|
import com.sun.jdi.*;
|
|
import com.sun.jdi.event.*;
|
|
import compiler.testlibrary.CompilerUtils;
|
|
import compiler.whitebox.CompilerWhiteBoxTest;
|
|
|
|
import java.lang.reflect.Array;
|
|
import java.util.Arrays;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.function.Function;
|
|
|
|
import jdk.test.lib.Asserts;
|
|
import jdk.test.whitebox.WhiteBox;
|
|
import jdk.test.whitebox.gc.GC;
|
|
|
|
|
|
//
|
|
// 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.
|
|
public static final boolean 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.
|
|
public static final String RUN_ONLY_TEST_CASE_PROPERTY = "EATests.onlytestcase";
|
|
public static final String RUN_ONLY_TEST_CASE = System.getProperty(RUN_ONLY_TEST_CASE_PROPERTY);
|
|
|
|
public final String testCaseName;
|
|
|
|
public EATestCaseBaseShared() {
|
|
String clName = getClass().getName();
|
|
int tidx = clName.lastIndexOf("Target");
|
|
testCaseName = tidx > 0 ? clName.substring(0, tidx) : clName;
|
|
}
|
|
|
|
public boolean shouldSkip() {
|
|
return EATestCaseBaseShared.RUN_ONLY_TEST_CASE != null &&
|
|
EATestCaseBaseShared.RUN_ONLY_TEST_CASE.length() > 0 &&
|
|
!testCaseName.equals(EATestCaseBaseShared.RUN_ONLY_TEST_CASE);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Target main class, i.e. the program to be debugged.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
class EATestsTarget {
|
|
|
|
public static void main(String[] args) {
|
|
EATestCaseBaseTarget.staticSetUp();
|
|
EATestCaseBaseTarget.staticSetUpDone();
|
|
|
|
// 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 EARelockingWithManyLightweightLocksTarget() .run();
|
|
new EARelockingSimpleWithAccessInOtherThreadTarget() .run();
|
|
new EARelockingSimpleWithAccessInOtherThread_02_DynamicCall_Target() .run();
|
|
new EARelockingRecursiveTarget() .run();
|
|
new EARelockingNestedInflatedTarget() .run();
|
|
new EARelockingNestedInflated_02Target() .run();
|
|
new EARelockingNestedInflated_03Target() .run();
|
|
new EARelockingArgEscapeLWLockedInCalleeFrameTarget() .run();
|
|
new EARelockingArgEscapeLWLockedInCalleeFrame_2Target() .run();
|
|
new EARelockingArgEscapeLWLockedInCalleeFrameNoRecursiveTarget() .run();
|
|
new EAGetOwnedMonitorsTarget() .run();
|
|
new EAEntryCountTarget() .run();
|
|
new EARelockingObjectCurrentlyWaitingOnTarget() .run();
|
|
new EARelockingValueBasedTarget() .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
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
public class EATests extends TestScaffold {
|
|
|
|
public TargetVMOptions targetVMOptions;
|
|
public ThreadReference targetMainThread;
|
|
|
|
EATests(String args[]) {
|
|
super(args);
|
|
}
|
|
|
|
public static void main(String[] args) throws Exception {
|
|
if (EATestCaseBaseShared.RUN_ONLY_TEST_CASE != null) {
|
|
args = Arrays.copyOf(args, args.length + 1);
|
|
args[args.length - 1] = "-D" + EATestCaseBaseShared.RUN_ONLY_TEST_CASE_PROPERTY + "=" + EATestCaseBaseShared.RUN_ONLY_TEST_CASE;
|
|
}
|
|
new EATests(args).startTests();
|
|
}
|
|
|
|
public static class TargetVMOptions {
|
|
|
|
public final boolean UseJVMCICompiler;
|
|
public final boolean EliminateAllocations;
|
|
public final boolean DeoptimizeObjectsALot;
|
|
public final boolean DoEscapeAnalysis;
|
|
public final boolean ZGCIsSelected;
|
|
public final boolean ShenandoahGCIsSelected;
|
|
public final boolean StressReflectiveCode;
|
|
|
|
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("ShenandoahGCIsSelected"));
|
|
ShenandoahGCIsSelected = ((PrimitiveValue) val).booleanValue();
|
|
val = testCaseBaseTargetClass.getValue(testCaseBaseTargetClass.fieldByName("StressReflectiveCode"));
|
|
StressReflectiveCode = ((PrimitiveValue) val).booleanValue();
|
|
}
|
|
|
|
}
|
|
|
|
// Execute known test cases
|
|
protected void 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 EARelockingWithManyLightweightLocks() .run(this);
|
|
new EARelockingSimpleWithAccessInOtherThread() .run(this);
|
|
new EARelockingSimpleWithAccessInOtherThread_02_DynamicCall() .run(this);
|
|
new EARelockingRecursive() .run(this);
|
|
new EARelockingNestedInflated() .run(this);
|
|
new EARelockingNestedInflated_02() .run(this);
|
|
new EARelockingNestedInflated_03() .run(this);
|
|
new EARelockingArgEscapeLWLockedInCalleeFrame() .run(this);
|
|
new EARelockingArgEscapeLWLockedInCalleeFrame_2() .run(this);
|
|
new EARelockingArgEscapeLWLockedInCalleeFrameNoRecursive() .run(this);
|
|
new EAGetOwnedMonitors() .run(this);
|
|
new EAEntryCount() .run(this);
|
|
new EARelockingObjectCurrentlyWaitingOn() .run(this);
|
|
new EARelockingValueBased() .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
|
|
public void msg(String m) {
|
|
System.out.println();
|
|
System.out.println("###(Debugger) " + m);
|
|
System.out.println();
|
|
}
|
|
|
|
// Highlighted message.
|
|
public void msgHL(String m) {
|
|
System.out.println();
|
|
System.out.println();
|
|
System.out.println("##########################################################");
|
|
System.out.println("### " + m);
|
|
System.out.println("### ");
|
|
System.out.println();
|
|
System.out.println();
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Base class for debugger side of test cases.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
abstract class EATestCaseBaseDebugger extends EATestCaseBaseShared {
|
|
|
|
protected EATests env;
|
|
|
|
public ObjectReference testCase;
|
|
|
|
public static final String TARGET_TESTCASE_BASE_NAME = EATestCaseBaseTarget.class.getName();
|
|
|
|
public static final String XYVAL_NAME = XYVal.class.getName();
|
|
|
|
public abstract void runTestCase() throws Exception;
|
|
|
|
@Override
|
|
public boolean shouldSkip() {
|
|
// Skip if StressReflectiveCode because it effectively disables escape analysis
|
|
return super.shouldSkip() || env.targetVMOptions.StressReflectiveCode;
|
|
}
|
|
|
|
public void 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);
|
|
}
|
|
|
|
public void resumeToWarmupDone() throws Exception {
|
|
msg("resuming to " + TARGET_TESTCASE_BASE_NAME + ".warmupDone()V");
|
|
resumeTo(TARGET_TESTCASE_BASE_NAME, "warmupDone", "()V");
|
|
testCase = env.targetMainThread.frame(0).thisObject();
|
|
}
|
|
|
|
public void resumeToTestCaseDone() {
|
|
msg("resuming to " + TARGET_TESTCASE_BASE_NAME + ".testCaseDone()V");
|
|
resumeTo(TARGET_TESTCASE_BASE_NAME, "testCaseDone", "()V");
|
|
}
|
|
|
|
public void checkPostConditions() throws Exception {
|
|
Asserts.assertFalse(env.getExceptionCaught(), "Uncaught exception in Debuggee");
|
|
|
|
String testName = getClass().getName();
|
|
if (!env.testFailed) {
|
|
env.println(testName + ": passed");
|
|
} else {
|
|
throw new Exception(testName + ": failed");
|
|
}
|
|
}
|
|
|
|
public void printStack(ThreadReference thread) throws Exception {
|
|
msg("Debuggee Stack:");
|
|
List<StackFrame> stack_frames = thread.frames();
|
|
int i = 0;
|
|
for (StackFrame ff : stack_frames) {
|
|
System.out.println("frame[" + i++ +"]: " + ff.location().method() + " (bci:" + ff.location().codeIndex() + ")");
|
|
}
|
|
}
|
|
|
|
public void msg(String m) {
|
|
env.msg(m);
|
|
}
|
|
|
|
public void msgHL(String m) {
|
|
env.msgHL(m);
|
|
}
|
|
|
|
// See Field Descriptors in The Java Virtual Machine Specification
|
|
// (https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.3.2)
|
|
enum FD {
|
|
I, // int
|
|
J, // long
|
|
F, // float
|
|
D, // double
|
|
}
|
|
|
|
// Map field descriptor to jdi type string
|
|
public static final Map<FD, String> FD2JDIArrType = Map.of(FD.I, "int[]", FD.J, "long[]", FD.F, "float[]", FD.D, "double[]");
|
|
|
|
// Map field descriptor to PrimitiveValue getter
|
|
public static final Function<PrimitiveValue, Integer> v2I = PrimitiveValue::intValue;
|
|
public static final Function<PrimitiveValue, Long> v2J = PrimitiveValue::longValue;
|
|
public static final Function<PrimitiveValue, Float> v2F = PrimitiveValue::floatValue;
|
|
public static final Function<PrimitiveValue, Double> v2D = PrimitiveValue::doubleValue;
|
|
Map<FD, Function<PrimitiveValue, ?>> FD2getter = Map.of(FD.I, v2I, FD.J, v2J, FD.F, v2F, FD.D, v2D);
|
|
|
|
/**
|
|
* 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
|
|
*/
|
|
protected void 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
|
|
*/
|
|
protected void 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
|
|
*/
|
|
public void 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
|
|
*/
|
|
public void 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
|
|
*/
|
|
protected void 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
|
|
*/
|
|
protected void 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 void setField(ObjectReference obj, String fName, Value val) throws Exception {
|
|
msg("set field " + fName + " = " + val);
|
|
ReferenceType rt = obj.referenceType();
|
|
Field fld = rt.fieldByName(fName);
|
|
obj.setValue(fld, val);
|
|
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
|
|
*/
|
|
public void 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
|
|
*/
|
|
public boolean 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
|
|
*/
|
|
public void 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
|
|
*/
|
|
public void terminateEndlessLoop() throws Exception {
|
|
msg("terminate loop");
|
|
setField(testCase, "doLoop", env.vm().mirrorOf(false));
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Base class for debuggee side of test cases.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
abstract class EATestCaseBaseTarget extends EATestCaseBaseShared implements Runnable {
|
|
|
|
/**
|
|
* The target must set that field to true as soon as it enters the endless loop.
|
|
*/
|
|
public volatile boolean targetIsInLoop;
|
|
|
|
/**
|
|
* Used for busy loops. See {@link #dontinline_endlessLoop()}.
|
|
*/
|
|
public volatile long loopCount;
|
|
|
|
/**
|
|
* Used in {@link EATestCaseBaseDebugger#terminateEndlessLoop()} to signal target to leave the endless loop.
|
|
*/
|
|
public volatile boolean doLoop;
|
|
|
|
public long checkSum;
|
|
|
|
public static final String TESTMETHOD_DEFAULT_NAME = "dontinline_testMethod";
|
|
|
|
public static final WhiteBox WB = WhiteBox.getWhiteBox();
|
|
|
|
public static boolean unbox(Boolean value, boolean dflt) {
|
|
return value == null ? dflt : value;
|
|
}
|
|
|
|
// Some of the fields are only read by the debugger
|
|
public static final boolean UseJVMCICompiler = unbox(WB.getBooleanVMFlag("UseJVMCICompiler"), false);
|
|
public static final boolean DoEscapeAnalysis = unbox(WB.getBooleanVMFlag("DoEscapeAnalysis"), UseJVMCICompiler);
|
|
public static final boolean EliminateAllocations = unbox(WB.getBooleanVMFlag("EliminateAllocations"), UseJVMCICompiler);
|
|
public static final boolean DeoptimizeObjectsALot = WB.getBooleanVMFlag("DeoptimizeObjectsALot");
|
|
public static final boolean ZGCIsSelected = GC.Z.isSelected();
|
|
public static final boolean ShenandoahGCIsSelected = GC.Shenandoah.isSelected();
|
|
public static final boolean StressReflectiveCode = unbox(WB.getBooleanVMFlag("StressReflectiveCode"), false);
|
|
|
|
public String testMethodName;
|
|
public int testMethodDepth;
|
|
|
|
// Results produced by dontinline_testMethod()
|
|
public int iResult;
|
|
public long lResult;
|
|
public float fResult;
|
|
public double dResult;
|
|
|
|
|
|
public boolean warmupDone;
|
|
|
|
// an object with an inflated monitor
|
|
public static XYVal inflatedLock;
|
|
public static Thread inflatorThread;
|
|
public static boolean inflatedLockIsPermanentlyInflated;
|
|
|
|
public static int NOT_CONST_1I = 1;
|
|
public static long NOT_CONST_1L = 1L;
|
|
public static float NOT_CONST_1F = 1.1F;
|
|
public static double NOT_CONST_1D = 1.1D;
|
|
|
|
public static Long NOT_CONST_1_OBJ = Long.valueOf(1);
|
|
|
|
|
|
public static final Long CONST_2_OBJ = Long.valueOf(2);
|
|
public static final Long CONST_3_OBJ = Long.valueOf(3);
|
|
|
|
@Override
|
|
public boolean shouldSkip() {
|
|
// Skip if StressReflectiveCode because it effectively disables escape analysis
|
|
return super.shouldSkip() || StressReflectiveCode;
|
|
}
|
|
|
|
/**
|
|
* Main driver of a test case.
|
|
* <ul>
|
|
* <li> Skips test case if not selected (see {@link EATestCaseBaseShared#RUN_ONLY_TEST_CASE}
|
|
* <li> Call {@link #setUp()}
|
|
* <li> warm-up and compile {@link #dontinline_testMethod()} (see {@link #compileTestMethod()}
|
|
* <li> calling {@link #dontinline_testMethod()}
|
|
* <li> checking the result (see {@link #checkResult()}
|
|
* <ul>
|
|
*/
|
|
public void run() {
|
|
try {
|
|
if (shouldSkip()) {
|
|
msg("skipping " + testCaseName);
|
|
return;
|
|
}
|
|
setUp();
|
|
msg(testCaseName + " is up and running.");
|
|
compileTestMethod();
|
|
msg(testCaseName + " warmup done.");
|
|
warmupDone();
|
|
checkCompLevel();
|
|
dontinline_testMethod();
|
|
checkResult();
|
|
msg(testCaseName + " done.");
|
|
testCaseDone();
|
|
} catch (Exception e) {
|
|
Asserts.fail("Caught unexpected exception", e);
|
|
}
|
|
}
|
|
|
|
public static void staticSetUp() {
|
|
inflatedLock = new XYVal(1, 1);
|
|
synchronized (inflatedLock) {
|
|
inflatorThread = DebuggeeWrapper.newThread(() -> {
|
|
synchronized (inflatedLock) {
|
|
inflatedLockIsPermanentlyInflated = true;
|
|
inflatedLock.notify(); // main thread
|
|
while (true) {
|
|
try {
|
|
// calling wait() on a monitor will cause inflation into a heavy monitor
|
|
inflatedLock.wait();
|
|
} catch (InterruptedException e) { /* ignored */ }
|
|
}
|
|
}
|
|
}, "Lock Inflator (test thread)");
|
|
inflatorThread.setDaemon(true);
|
|
inflatorThread.start();
|
|
|
|
// wait until the lock is permanently inflated by the inflatorThread
|
|
while(!inflatedLockIsPermanentlyInflated) {
|
|
try {
|
|
inflatedLock.wait(); // until inflated
|
|
} catch (InterruptedException e1) { /* ignored */ }
|
|
}
|
|
}
|
|
}
|
|
|
|
// Debugger will set breakpoint here to sync with target.
|
|
public static void staticSetUpDone() {
|
|
}
|
|
|
|
public void setUp() {
|
|
testMethodDepth = 1;
|
|
testMethodName = TESTMETHOD_DEFAULT_NAME;
|
|
}
|
|
|
|
public abstract void dontinline_testMethod() throws Exception;
|
|
|
|
public int dontinline_brkpt_iret() {
|
|
dontinline_brkpt();
|
|
return 42;
|
|
}
|
|
|
|
/**
|
|
* 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.
|
|
*/
|
|
public void 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.
|
|
*/
|
|
public long dontinline_endlessLoop() {
|
|
long cs = checkSum;
|
|
doLoop = true;
|
|
while (loopCount-- > 0 && doLoop) {
|
|
targetIsInLoop = true;
|
|
checkSum += checkSum % ++cs;
|
|
}
|
|
loopCount = 3;
|
|
targetIsInLoop = false;
|
|
return checkSum;
|
|
}
|
|
|
|
public boolean testFrameShouldBeDeoptimized() {
|
|
return DoEscapeAnalysis;
|
|
}
|
|
|
|
public void warmupDone() {
|
|
warmupDone = true;
|
|
}
|
|
|
|
// Debugger will set breakpoint here to sync with target.
|
|
public void testCaseDone() {
|
|
}
|
|
|
|
public void compileTestMethod() throws Exception {
|
|
int callCount = CompilerWhiteBoxTest.THRESHOLD;
|
|
while (callCount-- > 0) {
|
|
dontinline_testMethod();
|
|
}
|
|
}
|
|
|
|
public void 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
|
|
public int getExpectedIResult() {
|
|
return 0;
|
|
}
|
|
|
|
// to be overridden as appropriate
|
|
public long getExpectedLResult() {
|
|
return 0;
|
|
}
|
|
|
|
// to be overridden as appropriate
|
|
public float getExpectedFResult() {
|
|
return 0f;
|
|
}
|
|
|
|
// to be overridden as appropriate
|
|
public double getExpectedDResult() {
|
|
return 0d;
|
|
}
|
|
|
|
private void checkResult() {
|
|
Asserts.assertEQ(getExpectedIResult(), iResult, "checking iResult");
|
|
Asserts.assertEQ(getExpectedLResult(), lResult, "checking lResult");
|
|
Asserts.assertEQ(getExpectedFResult(), fResult, "checking fResult");
|
|
Asserts.assertEQ(getExpectedDResult(), dResult, "checking dResult");
|
|
}
|
|
|
|
public void msg(String m) {
|
|
System.out.println();
|
|
System.out.println("###(Target) " + m);
|
|
System.out.println();
|
|
}
|
|
|
|
// The object passed will be ArgEscape if it was NoEscape before.
|
|
public final void 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.
|
|
*/
|
|
public final void 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");
|
|
|
|
Class<?> cls = receiver.getClass();
|
|
Class<?>[] none = {};
|
|
|
|
java.lang.reflect.Method m;
|
|
try {
|
|
m = cls.getDeclaredMethod(methodName, none);
|
|
m.invoke(receiver);
|
|
} catch (Exception e) {
|
|
Asserts.fail("Call through reflection failed", e);
|
|
}
|
|
}
|
|
|
|
static class LinkedList {
|
|
LinkedList l;
|
|
public long[] array;
|
|
public LinkedList(LinkedList l, int size) {
|
|
this.array = size > 0 ? new long[size] : null;
|
|
this.l = l;
|
|
}
|
|
}
|
|
|
|
public LinkedList consumedMemory;
|
|
|
|
public void consumeAllMemory() {
|
|
msg("consume all memory");
|
|
int size = 128 * 1024 * 1024;
|
|
while(true) {
|
|
try {
|
|
while(true) {
|
|
consumedMemory = new LinkedList(consumedMemory, size);
|
|
}
|
|
} catch(OutOfMemoryError oom) {
|
|
if (size == 0) break;
|
|
}
|
|
size = size / 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Test Cases
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// make sure a compiled frame is not deoptimized if an escaping local is accessed
|
|
class EAGetWithoutMaterializeTarget extends EATestCaseBaseTarget {
|
|
|
|
public XYVal getAway;
|
|
|
|
public void dontinline_testMethod() {
|
|
XYVal xy = new XYVal(4, 2);
|
|
getAway = xy; // allocated object escapes
|
|
dontinline_brkpt();
|
|
iResult = xy.x + xy.y;
|
|
}
|
|
|
|
@Override
|
|
public int getExpectedIResult() {
|
|
return 4 + 2;
|
|
}
|
|
|
|
@Override
|
|
public boolean testFrameShouldBeDeoptimized() {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
class EAGetWithoutMaterialize extends EATestCaseBaseDebugger {
|
|
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
ObjectReference o = getLocalRef(bpe.thread().frame(1), XYVAL_NAME, "xy");
|
|
checkPrimitiveField(o, FD.I, "x", 4);
|
|
checkPrimitiveField(o, FD.I, "y", 2);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// 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;
|
|
|
|
public void 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);
|
|
}
|
|
|
|
@Override
|
|
public void checkPostConditions() throws Exception {
|
|
super.checkPostConditions();
|
|
// check 2.
|
|
checkPrimitiveField(o, FD.I, "x", 5);
|
|
}
|
|
}
|
|
|
|
class EAMaterializeLocalVariableUponGetTarget extends EATestCaseBaseTarget {
|
|
|
|
public void dontinline_testMethod() {
|
|
XYVal xy = new XYVal(4, 2);
|
|
dontinline_brkpt(); // Debugger obtains scalar replaced object at this point.
|
|
xy.x += 1; // Change scalar replaced object after debugger obtained a reference to it.
|
|
iResult = xy.x + xy.y;
|
|
}
|
|
|
|
@Override
|
|
public int getExpectedIResult() {
|
|
return 4 + 2 + 1;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Test if an eliminated object can be reallocated in a frame with an active
|
|
// call that will return another object
|
|
class EAMaterializeLocalAtObjectReturn extends EATestCaseBaseDebugger {
|
|
public void 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);
|
|
}
|
|
}
|
|
|
|
class EAMaterializeLocalAtObjectReturnTarget extends EATestCaseBaseTarget {
|
|
@Override
|
|
public void setUp() {
|
|
super.setUp();
|
|
testMethodDepth = 2;
|
|
}
|
|
|
|
public void dontinline_testMethod() {
|
|
XYVal xy = new XYVal(4, 2);
|
|
Integer io = // Read xy here triggers reallocation
|
|
dontinline_brkpt_return_Integer();
|
|
iResult = xy.x + xy.y + io;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
@Override
|
|
public int getExpectedIResult() {
|
|
return 4 + 2 + 23;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Test if an eliminated object can be reallocated *just* before a call returns an object.
|
|
// (See nmethod::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 {
|
|
public void 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();
|
|
}
|
|
}
|
|
|
|
class EAMaterializeLocalAtObjectPollReturnReturnTarget extends EATestCaseBaseTarget {
|
|
@Override
|
|
public void setUp() {
|
|
super.setUp();
|
|
loopCount = 3;
|
|
doLoop = true;
|
|
}
|
|
|
|
public void warmupDone() {
|
|
super.warmupDone();
|
|
msg("enter 'endless' loop by setting loopCount = Long.MAX_VALUE");
|
|
loopCount = Long.MAX_VALUE; // endless loop
|
|
}
|
|
|
|
public void 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);
|
|
}
|
|
|
|
@Override
|
|
public long getExpectedLResult() {
|
|
return (Long.MAX_VALUE - loopCount) * (4+2+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 {
|
|
|
|
public void dontinline_testMethod() {
|
|
int nums[] = {NOT_CONST_1I , 2, 3};
|
|
dontinline_brkpt();
|
|
iResult = nums[0] + nums[1] + nums[2];
|
|
}
|
|
|
|
@Override
|
|
public int getExpectedIResult() {
|
|
return NOT_CONST_1I + 2 + 3;
|
|
}
|
|
}
|
|
|
|
class EAMaterializeIntArray extends EATestCaseBaseDebugger {
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
int[] expectedVals = {1, 2, 3};
|
|
checkLocalPrimitiveArray(bpe.thread().frame(1), "nums", FD.I, expectedVals);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
class EAMaterializeLongArrayTarget extends EATestCaseBaseTarget {
|
|
|
|
public void dontinline_testMethod() {
|
|
long nums[] = {NOT_CONST_1L , 2, 3};
|
|
dontinline_brkpt();
|
|
lResult = nums[0] + nums[1] + nums[2];
|
|
}
|
|
|
|
@Override
|
|
public long getExpectedLResult() {
|
|
return NOT_CONST_1L + 2 + 3;
|
|
}
|
|
}
|
|
|
|
class EAMaterializeLongArray extends EATestCaseBaseDebugger {
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
long[] expectedVals = {1, 2, 3};
|
|
checkLocalPrimitiveArray(bpe.thread().frame(1), "nums", FD.J, expectedVals);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
class EAMaterializeFloatArrayTarget extends EATestCaseBaseTarget {
|
|
|
|
public void dontinline_testMethod() {
|
|
float nums[] = {NOT_CONST_1F , 2.2f, 3.3f};
|
|
dontinline_brkpt();
|
|
fResult = nums[0] + nums[1] + nums[2];
|
|
}
|
|
|
|
@Override
|
|
public float getExpectedFResult() {
|
|
return NOT_CONST_1F + 2.2f + 3.3f;
|
|
}
|
|
}
|
|
|
|
class EAMaterializeFloatArray extends EATestCaseBaseDebugger {
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
float[] expectedVals = {1.1f, 2.2f, 3.3f};
|
|
checkLocalPrimitiveArray(bpe.thread().frame(1), "nums", FD.F, expectedVals);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
class EAMaterializeDoubleArrayTarget extends EATestCaseBaseTarget {
|
|
|
|
public void dontinline_testMethod() {
|
|
double nums[] = {NOT_CONST_1D , 2.2d, 3.3d};
|
|
dontinline_brkpt();
|
|
dResult = nums[0] + nums[1] + nums[2];
|
|
}
|
|
|
|
@Override
|
|
public double getExpectedDResult() {
|
|
return NOT_CONST_1D + 2.2d + 3.3d;
|
|
}
|
|
}
|
|
|
|
class EAMaterializeDoubleArray extends EATestCaseBaseDebugger {
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
double[] expectedVals = {1.1d, 2.2d, 3.3d};
|
|
checkLocalPrimitiveArray(bpe.thread().frame(1), "nums", FD.D, expectedVals);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
class EAMaterializeObjectArrayTarget extends EATestCaseBaseTarget {
|
|
|
|
public void dontinline_testMethod() {
|
|
Long nums[] = {NOT_CONST_1_OBJ , CONST_2_OBJ, CONST_3_OBJ};
|
|
dontinline_brkpt();
|
|
lResult = nums[0] + nums[1] + nums[2];
|
|
}
|
|
|
|
@Override
|
|
public long getExpectedLResult() {
|
|
return 1 + 2 + 3;
|
|
}
|
|
}
|
|
|
|
class EAMaterializeObjectArray extends EATestCaseBaseDebugger {
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
ReferenceType clazz = bpe.thread().frame(0).location().declaringType();
|
|
ObjectReference[] expectedVals = {
|
|
(ObjectReference) clazz.getValue(clazz.fieldByName("NOT_CONST_1_OBJ")),
|
|
(ObjectReference) clazz.getValue(clazz.fieldByName("CONST_2_OBJ")),
|
|
(ObjectReference) clazz.getValue(clazz.fieldByName("CONST_3_OBJ"))
|
|
};
|
|
checkLocalObjectArray(bpe.thread().frame(1), "nums", "java.lang.Long[]", expectedVals);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Materialize an object whose fields have constant and not constant values at
|
|
// the point where the object is materialized.
|
|
class EAMaterializeObjectWithConstantAndNotConstantValuesTarget extends EATestCaseBaseTarget {
|
|
|
|
public void dontinline_testMethod() {
|
|
ILFDO o = new ILFDO(NOT_CONST_1I, 2,
|
|
NOT_CONST_1L, 2L,
|
|
NOT_CONST_1F, 2.1F,
|
|
NOT_CONST_1D, 2.1D,
|
|
NOT_CONST_1_OBJ, CONST_2_OBJ
|
|
);
|
|
dontinline_brkpt();
|
|
dResult =
|
|
o.i + o.i2 + o.l + o.l2 + o.f + o.f2 + o.d + o.d2 + o.o + o.o2;
|
|
}
|
|
|
|
@Override
|
|
public double getExpectedDResult() {
|
|
return NOT_CONST_1I + 2 + NOT_CONST_1L + 2L + NOT_CONST_1F + 2.1F + NOT_CONST_1D + 2.1D + NOT_CONST_1_OBJ + CONST_2_OBJ;
|
|
}
|
|
}
|
|
|
|
class EAMaterializeObjectWithConstantAndNotConstantValues extends EATestCaseBaseDebugger {
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
ObjectReference o = getLocalRef(bpe.thread().frame(1), "ILFDO", "o");
|
|
checkPrimitiveField(o, FD.I, "i", 1);
|
|
checkPrimitiveField(o, FD.I, "i2", 2);
|
|
checkPrimitiveField(o, FD.J, "l", 1L);
|
|
checkPrimitiveField(o, FD.J, "l2", 2L);
|
|
checkPrimitiveField(o, FD.F, "f", 1.1f);
|
|
checkPrimitiveField(o, FD.F, "f2", 2.1f);
|
|
checkPrimitiveField(o, FD.D, "d", 1.1d);
|
|
checkPrimitiveField(o, FD.D, "d2", 2.1d);
|
|
ReferenceType clazz = bpe.thread().frame(1).location().declaringType();
|
|
ObjectReference[] expVals = {
|
|
(ObjectReference) clazz.getValue(clazz.fieldByName("NOT_CONST_1_OBJ")),
|
|
(ObjectReference) clazz.getValue(clazz.fieldByName("CONST_2_OBJ")),
|
|
};
|
|
checkObjField(o, "o", expVals[0]);
|
|
checkObjField(o, "o2", expVals[1]);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Two local variables reference the same object.
|
|
// Check if the debugger obtains the same object when reading the two variables
|
|
class EAMaterializeObjReferencedBy2LocalsTarget extends EATestCaseBaseTarget {
|
|
|
|
public void dontinline_testMethod() {
|
|
XYVal xy = new XYVal(2, 3);
|
|
XYVal alias = xy;
|
|
dontinline_brkpt();
|
|
iResult = xy.x + alias.x;
|
|
}
|
|
|
|
@Override
|
|
public int getExpectedIResult() {
|
|
return 2 + 2;
|
|
}
|
|
}
|
|
|
|
class EAMaterializeObjReferencedBy2Locals extends EATestCaseBaseDebugger {
|
|
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
ObjectReference xy = getLocalRef(bpe.thread().frame(1), XYVAL_NAME, "xy");
|
|
ObjectReference alias = getLocalRef(bpe.thread().frame(1), XYVAL_NAME, "alias");
|
|
Asserts.assertSame(xy, alias, "xy and alias are expected to reference the same object");
|
|
}
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// 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 {
|
|
|
|
public void dontinline_testMethod() {
|
|
XYVal xy = new XYVal(2, 3);
|
|
XYVal alias = xy;
|
|
dontinline_brkpt(); // debugger: alias.x = 42
|
|
iResult = xy.x + alias.x;
|
|
}
|
|
|
|
@Override
|
|
public int getExpectedIResult() {
|
|
return 42 + 42;
|
|
}
|
|
}
|
|
|
|
class EAMaterializeObjReferencedBy2LocalsAndModify extends EATestCaseBaseDebugger {
|
|
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
ObjectReference alias = getLocalRef(bpe.thread().frame(1), XYVAL_NAME, "alias");
|
|
setField(alias, "x", env.vm().mirrorOf(42));
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// 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 {
|
|
|
|
@Override
|
|
public void setUp() {
|
|
super.setUp();
|
|
testMethodDepth = 2;
|
|
}
|
|
|
|
public void dontinline_testMethod() {
|
|
XYVal xy = new XYVal(2, 3);
|
|
testMethod_inlined(xy);
|
|
iResult += xy.x;
|
|
}
|
|
|
|
public void testMethod_inlined(XYVal xy) {
|
|
XYVal alias = xy;
|
|
dontinline_brkpt();
|
|
iResult = alias.x;
|
|
}
|
|
|
|
@Override
|
|
public int getExpectedIResult() {
|
|
return 2 + 2;
|
|
}
|
|
}
|
|
|
|
class EAMaterializeObjReferencedBy2LocalsInDifferentVirtFrames extends EATestCaseBaseDebugger {
|
|
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
ObjectReference xy = getLocalRef(bpe.thread().frame(2), XYVAL_NAME, "xy");
|
|
ObjectReference alias = getLocalRef(bpe.thread().frame(1), "testMethod_inlined", "alias", XYVAL_NAME);
|
|
Asserts.assertSame(xy, alias, "xy and alias are expected to reference the same object");
|
|
}
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// 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 {
|
|
|
|
@Override
|
|
public void setUp() {
|
|
super.setUp();
|
|
testMethodDepth = 2;
|
|
}
|
|
|
|
public void dontinline_testMethod() {
|
|
XYVal xy = new XYVal(2, 3);
|
|
testMethod_inlined(xy); // debugger: xy.x = 42
|
|
iResult += xy.x;
|
|
}
|
|
|
|
public void testMethod_inlined(XYVal xy) {
|
|
XYVal alias = xy;
|
|
dontinline_brkpt();
|
|
iResult = alias.x;
|
|
}
|
|
|
|
@Override
|
|
public int getExpectedIResult() {
|
|
return 42 + 42;
|
|
}
|
|
}
|
|
|
|
class EAMaterializeObjReferencedBy2LocalsInDifferentVirtFramesAndModify extends EATestCaseBaseDebugger {
|
|
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
ObjectReference alias = getLocalRef(bpe.thread().frame(1), "testMethod_inlined", "alias", XYVAL_NAME);
|
|
setField(alias, "x", env.vm().mirrorOf(42));
|
|
}
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Test materialization of an object referenced only from expression stack
|
|
class EAMaterializeObjReferencedFromOperandStackTarget extends EATestCaseBaseTarget {
|
|
|
|
@Override
|
|
public void setUp() {
|
|
super.setUp();
|
|
testMethodDepth = 2;
|
|
}
|
|
|
|
public void 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());
|
|
}
|
|
|
|
public int testMethodInlined(XYVal xy2, int dontinline_brkpt_ret_100) {
|
|
return xy2.x + dontinline_brkpt_ret_100;
|
|
}
|
|
|
|
public int dontinline_brkpt_ret_100() {
|
|
dontinline_brkpt();
|
|
return 100;
|
|
}
|
|
|
|
@Override
|
|
public int getExpectedIResult() {
|
|
return 4 + 100;
|
|
}
|
|
}
|
|
|
|
class EAMaterializeObjReferencedFromOperandStack extends EATestCaseBaseDebugger {
|
|
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
ObjectReference xy1 = getLocalRef(bpe.thread().frame(2), XYVAL_NAME, "xy1");
|
|
checkPrimitiveField(xy1, FD.I, "x", 2);
|
|
checkPrimitiveField(xy1, FD.I, "y", 3);
|
|
}
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* 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 {
|
|
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
setLocal(bpe.thread().frame(1), "i", env.vm().mirrorOf(43));
|
|
ObjectReference o = getLocalRef(bpe.thread().frame(1), XYVAL_NAME, "xy");
|
|
checkPrimitiveField(o, FD.I, "x", 4);
|
|
checkPrimitiveField(o, FD.I, "y", 2);
|
|
}
|
|
}
|
|
|
|
class EAMaterializeLocalVariableUponGetAfterSetIntegerTarget extends EATestCaseBaseTarget {
|
|
|
|
public void dontinline_testMethod() {
|
|
XYVal xy = new XYVal(4, 2);
|
|
int i = 42;
|
|
dontinline_brkpt();
|
|
iResult = xy.x + xy.y + i;
|
|
}
|
|
|
|
@Override
|
|
public int getExpectedIResult() {
|
|
return 4 + 2 + 43;
|
|
}
|
|
|
|
@Override
|
|
public boolean testFrameShouldBeDeoptimized() {
|
|
return true; // setting local variable i always triggers deoptimization
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Locking Tests
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
class EARelockingSimple extends EATestCaseBaseDebugger {
|
|
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
@SuppressWarnings("unused")
|
|
ObjectReference o = getLocalRef(bpe.thread().frame(1), XYVAL_NAME, "l1");
|
|
}
|
|
}
|
|
|
|
class EARelockingSimpleTarget extends EATestCaseBaseTarget {
|
|
|
|
public void dontinline_testMethod() {
|
|
XYVal l1 = new XYVal(4, 2);
|
|
synchronized (l1) {
|
|
dontinline_brkpt();
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* Like {@link EARelockingSimple}. The difference is that there are many
|
|
* lightweight locked objects when the relocking is done. With
|
|
* <code>-XX:LockingMode=2</code> the lock stack of the thread will be full
|
|
* because of this.
|
|
*/
|
|
|
|
class EARelockingWithManyLightweightLocks extends EATestCaseBaseDebugger {
|
|
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
@SuppressWarnings("unused")
|
|
ObjectReference o = getLocalRef(bpe.thread().frame(1), XYVAL_NAME, "l1");
|
|
}
|
|
}
|
|
|
|
class EARelockingWithManyLightweightLocksTarget extends EATestCaseBaseTarget {
|
|
|
|
static class Lock {
|
|
}
|
|
|
|
public static Lock L0, L1, L2, L3, L4, L5, L6, L7, L8, L9;
|
|
|
|
void allocateLocks() {
|
|
L0 = new Lock();
|
|
L1 = new Lock();
|
|
L2 = new Lock();
|
|
L3 = new Lock();
|
|
L4 = new Lock();
|
|
L5 = new Lock();
|
|
L6 = new Lock();
|
|
L7 = new Lock();
|
|
L8 = new Lock();
|
|
L9 = new Lock();
|
|
}
|
|
|
|
@Override
|
|
public void setUp() {
|
|
super.setUp();
|
|
allocateLocks();
|
|
}
|
|
|
|
@Override
|
|
public void warmupDone() {
|
|
super.warmupDone();
|
|
allocateLocks(); // get rid of already inflated ones
|
|
}
|
|
|
|
public void dontinline_testMethod() {
|
|
XYVal l1 = new XYVal(4, 2);
|
|
synchronized(L0) {
|
|
synchronized(L1) {
|
|
synchronized(L2) {
|
|
synchronized(L3) {
|
|
synchronized(L4) {
|
|
synchronized(L5) {
|
|
synchronized(L6) {
|
|
synchronized(L7) {
|
|
synchronized(L8) {
|
|
synchronized(L9) {
|
|
synchronized (l1) {
|
|
dontinline_brkpt();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// The debugger reads and publishes an object with eliminated locking to an instance field.
|
|
// A 2nd thread in the debuggee finds it there and changes its state using a synchronized method.
|
|
// Without eager relocking the accesses are unsynchronized which can be observed.
|
|
class EARelockingSimpleWithAccessInOtherThread extends EATestCaseBaseDebugger {
|
|
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
String l1ClassName = EARelockingSimpleWithAccessInOtherThreadTarget.SyncCounter.class.getName();
|
|
ObjectReference ctr = getLocalRef(bpe.thread().frame(1), l1ClassName, "l1");
|
|
setField(testCase, "sharedCounter", ctr);
|
|
terminateEndlessLoop();
|
|
}
|
|
}
|
|
|
|
class EARelockingSimpleWithAccessInOtherThreadTarget extends EATestCaseBaseTarget {
|
|
|
|
public static class SyncCounter {
|
|
private int val;
|
|
public synchronized int inc() { return val++; }
|
|
}
|
|
|
|
public volatile SyncCounter sharedCounter;
|
|
|
|
@Override
|
|
public void setUp() {
|
|
super.setUp();
|
|
doLoop = true;
|
|
Thread.ofPlatform().daemon().start(() -> {
|
|
while (doLoop) {
|
|
SyncCounter ctr = sharedCounter;
|
|
if (ctr != null) {
|
|
ctr.inc();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
public void dontinline_testMethod() {
|
|
SyncCounter l1 = new SyncCounter();
|
|
synchronized (l1) { // Eliminated locking
|
|
l1.inc();
|
|
dontinline_brkpt(); // Debugger publishes l1 to sharedCounter.
|
|
iResult = l1.inc(); // Changes by the 2nd thread will be observed if l1
|
|
// was not relocked before passing it to the debugger.
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public int getExpectedIResult() {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// The debugger reads and publishes an object with eliminated locking to an instance field.
|
|
// A 2nd thread in the debuggee finds it there and changes its state using a synchronized method.
|
|
// Without eager relocking the accesses are unsynchronized which can be observed.
|
|
// This is a variant of EARelockingSimpleWithAccessInOtherThread with a dynamic call (not devirtualized).
|
|
class EARelockingSimpleWithAccessInOtherThread_02_DynamicCall extends EATestCaseBaseDebugger {
|
|
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
String l1ClassName = EARelockingSimpleWithAccessInOtherThread_02_DynamicCall_Target.SyncCounter.class.getName();
|
|
ObjectReference ctr = getLocalRef(bpe.thread().frame(2), l1ClassName, "l1");
|
|
setField(testCase, "sharedCounter", ctr);
|
|
terminateEndlessLoop();
|
|
}
|
|
}
|
|
|
|
class EARelockingSimpleWithAccessInOtherThread_02_DynamicCall_Target extends EATestCaseBaseTarget {
|
|
|
|
public static final BrkPtDispatchA[] disp =
|
|
{new BrkPtDispatchA(), new BrkPtDispatchB(), new BrkPtDispatchC(), new BrkPtDispatchD()};
|
|
|
|
public static class BrkPtDispatchA {
|
|
public EATestCaseBaseTarget testCase;
|
|
public void dontinline_brkpt() { testCase.dontinline_brkpt(); }
|
|
}
|
|
|
|
public static class BrkPtDispatchB extends BrkPtDispatchA {
|
|
@Override
|
|
public void dontinline_brkpt() { testCase.dontinline_brkpt(); }
|
|
}
|
|
|
|
public static class BrkPtDispatchC extends BrkPtDispatchA {
|
|
@Override
|
|
public void dontinline_brkpt() { testCase.dontinline_brkpt(); }
|
|
}
|
|
|
|
public static class BrkPtDispatchD extends BrkPtDispatchA {
|
|
@Override
|
|
public void dontinline_brkpt() {
|
|
testCase.dontinline_brkpt();
|
|
}
|
|
}
|
|
|
|
public static class SyncCounter {
|
|
private int val;
|
|
public synchronized int inc() { return val++; }
|
|
}
|
|
|
|
public volatile SyncCounter sharedCounter;
|
|
|
|
@Override
|
|
public void setUp() {
|
|
super.setUp();
|
|
testMethodDepth = 2;
|
|
for (BrkPtDispatchA d : disp) {
|
|
d.testCase = this;
|
|
}
|
|
doLoop = true;
|
|
new Thread(() -> {
|
|
while (doLoop) {
|
|
SyncCounter ctr = sharedCounter;
|
|
if (ctr != null) {
|
|
ctr.inc();
|
|
}
|
|
}
|
|
}).start();
|
|
}
|
|
|
|
public int dispCount;
|
|
public void dontinline_testMethod() {
|
|
SyncCounter l1 = new SyncCounter();
|
|
synchronized (l1) { // Eliminated locking
|
|
l1.inc();
|
|
// Use different types for the subsequent call to prevent devirtualization.
|
|
BrkPtDispatchA d = disp[(dispCount++) & 3];
|
|
d.dontinline_brkpt(); // Dynamic call. Debugger publishes l1 to sharedCounter.
|
|
iResult = l1.inc(); // Changes by the 2nd thread will be observed if l1
|
|
// was not relocked before passing it to the debugger.
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public int getExpectedIResult() {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Test recursive locking
|
|
class EARelockingRecursiveTarget extends EATestCaseBaseTarget {
|
|
|
|
@Override
|
|
public void setUp() {
|
|
super.setUp();
|
|
testMethodDepth = 2;
|
|
}
|
|
|
|
public void dontinline_testMethod() {
|
|
XYVal l1 = new XYVal(4, 2);
|
|
synchronized (l1) {
|
|
testMethod_inlined(l1);
|
|
}
|
|
}
|
|
|
|
public void testMethod_inlined(XYVal l2) {
|
|
synchronized (l2) {
|
|
dontinline_brkpt();
|
|
}
|
|
}
|
|
}
|
|
|
|
class EARelockingRecursive extends EATestCaseBaseDebugger {
|
|
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
@SuppressWarnings("unused")
|
|
ObjectReference o = getLocalRef(bpe.thread().frame(2), XYVAL_NAME, "l1");
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// 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 {
|
|
|
|
@Override
|
|
public void setUp() {
|
|
super.setUp();
|
|
testMethodDepth = 2;
|
|
}
|
|
|
|
@Override
|
|
public boolean testFrameShouldBeDeoptimized() {
|
|
// Access does not trigger deopt., as escape state is already global escape.
|
|
return false;
|
|
}
|
|
|
|
public void dontinline_testMethod() {
|
|
XYVal l1 = inflatedLock;
|
|
synchronized (l1) {
|
|
testMethod_inlined(l1);
|
|
}
|
|
}
|
|
|
|
public void testMethod_inlined(XYVal l2) {
|
|
synchronized (l2) { // eliminated nested locking
|
|
dontinline_brkpt();
|
|
}
|
|
}
|
|
}
|
|
|
|
class EARelockingNestedInflated extends EATestCaseBaseDebugger {
|
|
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
@SuppressWarnings("unused")
|
|
ObjectReference o = getLocalRef(bpe.thread().frame(2), XYVAL_NAME, "l1");
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* 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 {
|
|
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
@SuppressWarnings("unused")
|
|
ObjectReference o = getLocalRef(bpe.thread().frame(2), XYVAL_NAME, "l1");
|
|
}
|
|
}
|
|
|
|
class EARelockingNestedInflated_02Target extends EATestCaseBaseTarget {
|
|
|
|
@Override
|
|
public void setUp() {
|
|
super.setUp();
|
|
testMethodDepth = 2;
|
|
}
|
|
|
|
public void dontinline_testMethod() {
|
|
@SuppressWarnings("unused")
|
|
XYVal xy = new XYVal(1, 1); // scalar replaced
|
|
XYVal l1 = inflatedLock; // read by debugger
|
|
synchronized (l1) {
|
|
testMethod_inlined(l1);
|
|
}
|
|
}
|
|
|
|
public void testMethod_inlined(XYVal l2) {
|
|
synchronized (l2) { // eliminated nested locking
|
|
dontinline_brkpt();
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* Like {@link EARelockingNestedInflated_02} with the difference that the
|
|
* inflation of the lock happens because of contention.
|
|
*/
|
|
class EARelockingNestedInflated_03 extends EATestCaseBaseDebugger {
|
|
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
@SuppressWarnings("unused")
|
|
ObjectReference o = getLocalRef(bpe.thread().frame(2), XYVAL_NAME, "l1");
|
|
}
|
|
}
|
|
|
|
class EARelockingNestedInflated_03Target extends EATestCaseBaseTarget {
|
|
|
|
public XYVal lockInflatedByContention;
|
|
public boolean doLockNow;
|
|
public EATestCaseBaseTarget testCase;
|
|
|
|
@Override
|
|
public void setUp() {
|
|
super.setUp();
|
|
testMethodDepth = 2;
|
|
lockInflatedByContention = new XYVal(1, 1);
|
|
testCase = this;
|
|
}
|
|
|
|
@Override
|
|
public void warmupDone() {
|
|
super.warmupDone();
|
|
// Use new lock. lockInflatedByContention might have been inflated because of recursion.
|
|
lockInflatedByContention = new XYVal(1, 1);
|
|
// Start thread that tries to enter lockInflatedByContention while the main thread owns it -> inflation
|
|
DebuggeeWrapper.newThread(() -> {
|
|
while (true) {
|
|
synchronized (testCase) {
|
|
try {
|
|
if (doLockNow) {
|
|
doLockNow = false; // reset for main thread
|
|
testCase.notify();
|
|
break;
|
|
}
|
|
testCase.wait();
|
|
} catch (InterruptedException e) { /* ignored */ }
|
|
}
|
|
}
|
|
synchronized (lockInflatedByContention) { // will block and trigger inflation
|
|
msg(Thread.currentThread().getName() + ": acquired lockInflatedByContention");
|
|
}
|
|
}, testCaseName + ": Lock Contender (test thread)").start();
|
|
}
|
|
|
|
public void dontinline_testMethod() {
|
|
@SuppressWarnings("unused")
|
|
XYVal xy = new XYVal(1, 1); // scalar replaced
|
|
XYVal l1 = lockInflatedByContention; // read by debugger
|
|
synchronized (l1) {
|
|
testMethod_inlined(l1);
|
|
}
|
|
}
|
|
|
|
public void testMethod_inlined(XYVal l2) {
|
|
synchronized (l2) { // eliminated nested locking
|
|
dontinline_notifyOtherThread();
|
|
dontinline_brkpt();
|
|
}
|
|
}
|
|
|
|
public void dontinline_notifyOtherThread() {
|
|
if (!warmupDone) {
|
|
return;
|
|
}
|
|
synchronized (testCase) {
|
|
doLockNow = true;
|
|
testCase.notify();
|
|
// wait for other thread to reset doLockNow again
|
|
while (doLockNow) {
|
|
try {
|
|
testCase.wait();
|
|
} catch (InterruptedException e) { /* ignored */ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* 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 {
|
|
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
@SuppressWarnings("unused")
|
|
ObjectReference o = getLocalRef(bpe.thread().frame(2), XYVAL_NAME, "l1");
|
|
}
|
|
}
|
|
|
|
class EARelockingArgEscapeLWLockedInCalleeFrameTarget extends EATestCaseBaseTarget {
|
|
|
|
@Override
|
|
public void setUp() {
|
|
super.setUp();
|
|
testMethodDepth = 2;
|
|
}
|
|
|
|
public void dontinline_testMethod() {
|
|
XYVal l1 = new XYVal(1, 1); // ArgEscape
|
|
synchronized (l1) { // eliminated
|
|
l1.dontinline_sync_method(this); // l1 escapes
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean 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 {
|
|
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
@SuppressWarnings("unused")
|
|
ObjectReference o = getLocalRef(bpe.thread().frame(2), XYVAL_NAME, "l1");
|
|
}
|
|
}
|
|
|
|
class EARelockingArgEscapeLWLockedInCalleeFrame_2Target extends EATestCaseBaseTarget {
|
|
|
|
@Override
|
|
public void setUp() {
|
|
super.setUp();
|
|
testMethodDepth = 2;
|
|
}
|
|
|
|
public void dontinline_testMethod() {
|
|
XYVal l1 = new XYVal(1, 1); // ArgEscape
|
|
XYVal l2 = new XYVal(4, 2); // NoEscape, scalar replaced
|
|
synchronized (l1) { // eliminated
|
|
synchronized (l2) { // eliminated
|
|
l1.dontinline_sync_method(this); // l1 escapes
|
|
}
|
|
}
|
|
iResult = l2.x + l2.y;
|
|
}
|
|
|
|
@Override
|
|
public int getExpectedIResult() {
|
|
return 6;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* Similar to {@link EARelockingArgEscapeLWLockedInCalleeFrame_2Target}. It does
|
|
* not use recursive locking and exposed a bug in the lightweight-locking implementation.
|
|
*/
|
|
class EARelockingArgEscapeLWLockedInCalleeFrameNoRecursive extends EATestCaseBaseDebugger {
|
|
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
@SuppressWarnings("unused")
|
|
ObjectReference o = getLocalRef(bpe.thread().frame(2), XYVAL_NAME, "l1");
|
|
}
|
|
}
|
|
|
|
class EARelockingArgEscapeLWLockedInCalleeFrameNoRecursiveTarget extends EATestCaseBaseTarget {
|
|
|
|
@Override
|
|
public void setUp() {
|
|
super.setUp();
|
|
testMethodDepth = 2;
|
|
}
|
|
|
|
public void dontinline_testMethod() {
|
|
XYVal l1 = new XYVal(1, 1); // NoEscape, scalar replaced
|
|
XYVal l2 = new XYVal(4, 2); // NoEscape, scalar replaced
|
|
XYVal l3 = new XYVal(5, 3); // ArgEscape
|
|
synchronized (l1) { // eliminated
|
|
synchronized (l2) { // eliminated
|
|
l3.dontinline_sync_method(this); // l3 escapes
|
|
}
|
|
}
|
|
iResult = l2.x + l2.y;
|
|
}
|
|
|
|
@Override
|
|
public int getExpectedIResult() {
|
|
return 6;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* Test relocking eliminated (nested) locks of an object on which the
|
|
* target thread currently waits.
|
|
*/
|
|
class EARelockingObjectCurrentlyWaitingOn extends EATestCaseBaseDebugger {
|
|
|
|
public void 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 {
|
|
|
|
public static class ForLocking {
|
|
}
|
|
|
|
public volatile Object objToNotifyOn; // debugger assigns value when notify thread should call objToNotifyOn.notifyAll()
|
|
|
|
@Override
|
|
public void setUp() {
|
|
super.setUp();
|
|
testMethodDepth = 2;
|
|
}
|
|
|
|
@Override
|
|
public void warmupDone() {
|
|
super.warmupDone();
|
|
Thread t = new Thread(() -> doNotify());
|
|
t.start();
|
|
}
|
|
|
|
public void 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();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean testFrameShouldBeDeoptimized() {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public void dontinline_testMethod() throws Exception {
|
|
ForLocking l0 = new ForLocking(); // will be scalar replaced; access triggers realloc/relock
|
|
ForLocking l1 = new ForLocking();
|
|
synchronized (l0) {
|
|
synchronized (l1) {
|
|
testMethod_inlined(l1);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void testMethod_inlined(ForLocking l2) throws Exception {
|
|
synchronized (l2) { // eliminated nested locking
|
|
dontinline_waitWhenWarmupDone(l2);
|
|
}
|
|
}
|
|
|
|
public void dontinline_waitWhenWarmupDone(ForLocking l2) throws Exception {
|
|
if (warmupDone) {
|
|
l2.wait();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* Test relocking eliminated @ValueBased object.
|
|
*/
|
|
class EARelockingValueBased extends EATestCaseBaseDebugger {
|
|
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
@SuppressWarnings("unused")
|
|
ObjectReference o = getLocalRef(bpe.thread().frame(1), Integer.class.getName(), "l1");
|
|
}
|
|
}
|
|
|
|
class EARelockingValueBasedTarget extends EATestCaseBaseTarget {
|
|
|
|
public void dontinline_testMethod() {
|
|
Integer l1 = new Integer(255);
|
|
synchronized (l1) {
|
|
dontinline_brkpt();
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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 {
|
|
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
@SuppressWarnings("unused")
|
|
ObjectReference xy = getLocalRef(bpe.thread().frame(1), XYVAL_NAME, "xy");
|
|
}
|
|
}
|
|
|
|
class EADeoptFrameAfterReadLocalObject_01Target extends EATestCaseBaseTarget {
|
|
|
|
public void 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 {
|
|
|
|
@Override
|
|
public void setUp() {
|
|
super.setUp();
|
|
testMethodDepth = 2;
|
|
}
|
|
|
|
public void 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++;
|
|
}
|
|
}
|
|
|
|
public void callee(XYVal xy) {
|
|
dontinline_brkpt(); // Debugger reads xy.
|
|
// There are no virtual objects or eliminated locks.
|
|
}
|
|
}
|
|
|
|
class EADeoptFrameAfterReadLocalObject_01B extends EATestCaseBaseDebugger {
|
|
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
@SuppressWarnings("unused")
|
|
ObjectReference xy = getLocalRef(bpe.thread().frame(1), "callee", "xy", XYVAL_NAME);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* 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 {
|
|
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
@SuppressWarnings("unused")
|
|
ObjectReference xy = getLocalRef(bpe.thread().frame(1), "dontinline_callee", "xy", XYVAL_NAME);
|
|
}
|
|
}
|
|
|
|
class EADeoptFrameAfterReadLocalObject_02Target extends EATestCaseBaseTarget {
|
|
|
|
public void dontinline_testMethod() {
|
|
XYVal xy = new XYVal(1, 1);
|
|
dontinline_callee(xy); // xy is ArgEscape, debugger acquires ref to xy from callee
|
|
synchronized (xy) { // Locking is eliminated.
|
|
xy.x++;
|
|
xy.y++;
|
|
}
|
|
}
|
|
|
|
public void dontinline_callee(XYVal xy) {
|
|
dontinline_brkpt(); // Debugger reads xy.
|
|
// There are no virtual objects or eliminated locks.
|
|
}
|
|
|
|
@Override
|
|
public void setUp() {
|
|
super.setUp();
|
|
testMethodDepth = 2;
|
|
}
|
|
|
|
@Override
|
|
public boolean 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 {
|
|
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
@SuppressWarnings("unused")
|
|
ObjectReference xy = getLocalRef(bpe.thread().frame(1), "dontinline_callee", "xy", XYVAL_NAME);
|
|
}
|
|
}
|
|
|
|
class EADeoptFrameAfterReadLocalObject_02BTarget extends EATestCaseBaseTarget {
|
|
|
|
public void 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++;
|
|
}
|
|
}
|
|
|
|
public void dontinline_callee() {
|
|
@SuppressWarnings("unused")
|
|
XYVal xy = new XYVal(2, 2);
|
|
dontinline_brkpt(); // Debugger reads xy.
|
|
// No need to deoptimize the caller frame
|
|
}
|
|
|
|
@Override
|
|
public void setUp() {
|
|
super.setUp();
|
|
testMethodDepth = 2;
|
|
}
|
|
|
|
@Override
|
|
public boolean testFrameShouldBeDeoptimized() {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* 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 {
|
|
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
@SuppressWarnings("unused")
|
|
ObjectReference xy = getLocalRef(bpe.thread().frame(1), "dontinline_callee_accessed_by_debugger", "xy", XYVAL_NAME);
|
|
}
|
|
}
|
|
|
|
class EADeoptFrameAfterReadLocalObject_02CTarget extends EATestCaseBaseTarget {
|
|
|
|
public void 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++;
|
|
}
|
|
}
|
|
|
|
public void dontinline_callee(XYVal xy) {
|
|
if (warmupDone) {
|
|
dontinline_call_with_entry_frame(this, "dontinline_callee_accessed_by_debugger");
|
|
}
|
|
}
|
|
|
|
public void 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
|
|
public void 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;
|
|
}
|
|
|
|
@Override
|
|
public boolean testFrameShouldBeDeoptimized() {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* 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 {
|
|
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
ObjectReference xy = getLocalRef(bpe.thread().frame(1), XYVAL_NAME, "xy");
|
|
setField(xy, "x", env.vm().mirrorOf(1));
|
|
}
|
|
}
|
|
|
|
class EADeoptFrameAfterReadLocalObject_03Target extends EATestCaseBaseTarget {
|
|
|
|
public void 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.
|
|
}
|
|
|
|
@Override
|
|
public int getExpectedIResult() {
|
|
return 1 + 1;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Monitor info tests
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
class EAGetOwnedMonitorsTarget extends EATestCaseBaseTarget {
|
|
|
|
public long checkSum;
|
|
|
|
public void dontinline_testMethod() {
|
|
XYVal l1 = new XYVal(4, 2);
|
|
synchronized (l1) {
|
|
dontinline_endlessLoop();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setUp() {
|
|
super.setUp();
|
|
testMethodDepth = 2;
|
|
loopCount = 3;
|
|
}
|
|
|
|
public void warmupDone() {
|
|
super.warmupDone();
|
|
msg("enter 'endless' loop by setting loopCount = Long.MAX_VALUE");
|
|
loopCount = Long.MAX_VALUE; // endless loop
|
|
}
|
|
}
|
|
|
|
class EAGetOwnedMonitors extends EATestCaseBaseDebugger {
|
|
|
|
public void 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 EAEntryCountTarget extends EATestCaseBaseTarget {
|
|
|
|
public long checkSum;
|
|
|
|
public void dontinline_testMethod() {
|
|
XYVal l1 = new XYVal(4, 2);
|
|
synchronized (l1) {
|
|
inline_testMethod2(l1);
|
|
}
|
|
}
|
|
|
|
public void inline_testMethod2(XYVal l1) {
|
|
synchronized (l1) {
|
|
dontinline_endlessLoop();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setUp() {
|
|
super.setUp();
|
|
testMethodDepth = 2;
|
|
loopCount = 3;
|
|
}
|
|
|
|
public void warmupDone() {
|
|
super.warmupDone();
|
|
msg("enter 'endless' loop by setting loopCount = Long.MAX_VALUE");
|
|
loopCount = Long.MAX_VALUE; // endless loop
|
|
}
|
|
}
|
|
|
|
class EAEntryCount extends EATestCaseBaseDebugger {
|
|
|
|
public void 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();
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PopFrame tests
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* PopFrame into caller frame with scalar replaced objects.
|
|
*/
|
|
class EAPopFrameNotInlined extends EATestCaseBaseDebugger {
|
|
|
|
public void runTestCase() throws Exception {
|
|
BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V");
|
|
printStack(bpe.thread());
|
|
msg("PopFrame");
|
|
bpe.thread().popFrames(bpe.thread().frame(0));
|
|
msg("PopFrame DONE");
|
|
}
|
|
|
|
@Override
|
|
public boolean shouldSkip() {
|
|
// And Graal currently doesn't support PopFrame
|
|
return super.shouldSkip() || env.targetVMOptions.UseJVMCICompiler;
|
|
}
|
|
}
|
|
|
|
class EAPopFrameNotInlinedTarget extends EATestCaseBaseTarget {
|
|
|
|
public void dontinline_testMethod() {
|
|
XYVal xy = new XYVal(4, 2);
|
|
dontinline_brkpt();
|
|
iResult = xy.x + xy.y;
|
|
}
|
|
|
|
@Override
|
|
public boolean testFrameShouldBeDeoptimized() {
|
|
// Test is only performed after the frame pop.
|
|
// Then dontinline_testMethod is interpreted.
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public int getExpectedIResult() {
|
|
return 4 + 2;
|
|
}
|
|
|
|
@Override
|
|
public boolean shouldSkip() {
|
|
// And Graal currently doesn't support PopFrame
|
|
return super.shouldSkip() || UseJVMCICompiler;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* 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 {
|
|
|
|
public void 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
|
|
public boolean 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
|
|
return super.shouldSkip() ||
|
|
!env.targetVMOptions.EliminateAllocations ||
|
|
// With ZGC or Shenandoah the OOME is not always thrown as expected
|
|
env.targetVMOptions.ZGCIsSelected ||
|
|
env.targetVMOptions.ShenandoahGCIsSelected ||
|
|
env.targetVMOptions.DeoptimizeObjectsALot ||
|
|
env.targetVMOptions.UseJVMCICompiler;
|
|
}
|
|
}
|
|
|
|
class EAPopFrameNotInlinedReallocFailureTarget extends EATestCaseBaseTarget {
|
|
|
|
public boolean doneAlready;
|
|
|
|
public void dontinline_testMethod() {
|
|
long a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // scalar replaced
|
|
Vector10 v = new Vector10(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // scalar replaced
|
|
dontinline_consume_all_memory_brkpt();
|
|
lResult = a[0] + a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8] + a[9]
|
|
+ v.i0 + v.i1 + v.i2 + v.i3 + v.i4 + v.i5 + v.i6 + v.i7 + v.i8 + v.i9;
|
|
}
|
|
|
|
public void dontinline_consume_all_memory_brkpt() {
|
|
if (warmupDone && !doneAlready) {
|
|
doneAlready = true;
|
|
consumeAllMemory(); // provoke reallocation failure
|
|
dontinline_brkpt();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setUp() {
|
|
super.setUp();
|
|
testMethodDepth = 2;
|
|
}
|
|
|
|
@Override
|
|
public long getExpectedLResult() {
|
|
long n = 10;
|
|
return 2*n*(n+1)/2;
|
|
}
|
|
|
|
@Override
|
|
public boolean 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
|
|
return super.shouldSkip() ||
|
|
!EliminateAllocations ||
|
|
// With ZGC or Shenandoah the OOME is not always thrown as expected
|
|
ZGCIsSelected ||
|
|
ShenandoahGCIsSelected ||
|
|
DeoptimizeObjectsALot ||
|
|
UseJVMCICompiler;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* Pop inlined top frame dropping into method with scalar replaced opjects.
|
|
*/
|
|
class EAPopInlinedMethodWithScalarReplacedObjectsReallocFailure extends EATestCaseBaseDebugger {
|
|
|
|
public void runTestCase() throws Exception {
|
|
ThreadReference thread = env.targetMainThread;
|
|
env.vm().resume();
|
|
waitUntilTargetHasEnteredEndlessLoop();
|
|
|
|
thread.suspend();
|
|
printStack(thread);
|
|
// frame[0]: EAPopInlinedMethodWithScalarReplacedObjectsReallocFailureTarget.inlinedCallForcedToReturn()
|
|
// frame[1]: EAPopInlinedMethodWithScalarReplacedObjectsReallocFailureTarget.dontinline_testMethod()
|
|
// frame[2]: EATestCaseBaseTarget.run()
|
|
|
|
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
|
|
public boolean 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
|
|
return super.shouldSkip() ||
|
|
!env.targetVMOptions.EliminateAllocations ||
|
|
// With ZGC or Shenandoah the OOME is not always thrown as expected
|
|
env.targetVMOptions.ZGCIsSelected ||
|
|
env.targetVMOptions.ShenandoahGCIsSelected ||
|
|
env.targetVMOptions.DeoptimizeObjectsALot ||
|
|
env.targetVMOptions.UseJVMCICompiler;
|
|
}
|
|
}
|
|
|
|
class EAPopInlinedMethodWithScalarReplacedObjectsReallocFailureTarget extends EATestCaseBaseTarget {
|
|
|
|
public long checkSum;
|
|
|
|
public void dontinline_testMethod() {
|
|
long a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // scalar replaced
|
|
Vector10 v = new Vector10(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // scalar replaced
|
|
long l = inlinedCallForcedToReturn();
|
|
lResult = a[0] + a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8] + a[9]
|
|
+ v.i0 + v.i1 + v.i2 + v.i3 + v.i4 + v.i5 + v.i6 + v.i7 + v.i8 + v.i9;
|
|
}
|
|
|
|
public long inlinedCallForcedToReturn() {
|
|
long cs = checkSum;
|
|
dontinline_consumeAllMemory();
|
|
while (loopCount-- > 0) {
|
|
targetIsInLoop = true;
|
|
checkSum += checkSum % ++cs;
|
|
}
|
|
loopCount = 3;
|
|
targetIsInLoop = false;
|
|
return checkSum;
|
|
}
|
|
|
|
public void dontinline_consumeAllMemory() {
|
|
if (warmupDone && (loopCount > 3)) {
|
|
consumeAllMemory();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public long getExpectedLResult() {
|
|
long n = 10;
|
|
return 2*n*(n+1)/2;
|
|
}
|
|
|
|
@Override
|
|
public void setUp() {
|
|
super.setUp();
|
|
loopCount = 3;
|
|
}
|
|
|
|
public void warmupDone() {
|
|
super.warmupDone();
|
|
msg("enter 'endless' loop by setting loopCount = Long.MAX_VALUE");
|
|
loopCount = Long.MAX_VALUE; // endless loop
|
|
}
|
|
|
|
@Override
|
|
public boolean 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
|
|
return super.shouldSkip() ||
|
|
!EliminateAllocations ||
|
|
// With ZGC or Shenandoah the OOME is not always thrown as expected
|
|
ZGCIsSelected ||
|
|
ShenandoahGCIsSelected ||
|
|
DeoptimizeObjectsALot ||
|
|
UseJVMCICompiler;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ForceEarlyReturn tests
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* ForceEarlyReturn into caller frame with scalar replaced objects.
|
|
*/
|
|
class EAForceEarlyReturnNotInlined extends EATestCaseBaseDebugger {
|
|
|
|
public void 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]: EATestCaseBaseTarget.dontinline_brkpt_iret()
|
|
// frame[2]: EAForceEarlyReturnNotInlinedTarget.dontinline_testMethod()
|
|
// frame[3]: EATestCaseBaseTarget.run()
|
|
// frame[4]: EATestsTarget.main(java.lang.String[])
|
|
|
|
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
|
|
public boolean shouldSkip() {
|
|
// Graal currently doesn't support Force Early Return
|
|
return super.shouldSkip() || env.targetVMOptions.UseJVMCICompiler;
|
|
}
|
|
}
|
|
|
|
class EAForceEarlyReturnNotInlinedTarget extends EATestCaseBaseTarget {
|
|
|
|
public void dontinline_testMethod() {
|
|
XYVal xy = new XYVal(4, 2);
|
|
int i = dontinline_brkpt_iret();
|
|
iResult = xy.x + xy.y + i;
|
|
}
|
|
|
|
@Override
|
|
public int getExpectedIResult() {
|
|
return 4 + 2 + 43;
|
|
}
|
|
|
|
@Override
|
|
public void setUp() {
|
|
super.setUp();
|
|
testMethodDepth = 2;
|
|
}
|
|
|
|
public boolean testFrameShouldBeDeoptimized() {
|
|
return true; // because of stepping
|
|
}
|
|
|
|
@Override
|
|
public boolean shouldSkip() {
|
|
// Graal currently doesn't support Force Early Return
|
|
return super.shouldSkip() || UseJVMCICompiler;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* ForceEarlyReturn at safepoint in frame with scalar replaced objects.
|
|
*/
|
|
class EAForceEarlyReturnOfInlinedMethodWithScalarReplacedObjects extends EATestCaseBaseDebugger {
|
|
|
|
public void runTestCase() throws Exception {
|
|
ThreadReference thread = env.targetMainThread;
|
|
env.vm().resume();
|
|
waitUntilTargetHasEnteredEndlessLoop();
|
|
|
|
thread.suspend();
|
|
printStack(thread);
|
|
// frame[0]: EAForceEarlyReturnOfInlinedMethodWithScalarReplacedObjectsTarget.inlinedCallForcedToReturn()
|
|
// frame[1]: EAForceEarlyReturnOfInlinedMethodWithScalarReplacedObjectsTarget.dontinline_testMethod()
|
|
// frame[2]: EATestCaseBaseTarget.run()
|
|
|
|
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
|
|
public boolean shouldSkip() {
|
|
// Graal currently doesn't support Force Early Return
|
|
return super.shouldSkip() || env.targetVMOptions.UseJVMCICompiler;
|
|
}
|
|
}
|
|
|
|
class EAForceEarlyReturnOfInlinedMethodWithScalarReplacedObjectsTarget extends EATestCaseBaseTarget {
|
|
|
|
public int checkSum;
|
|
|
|
public void dontinline_testMethod() {
|
|
XYVal xy = new XYVal(4, 2);
|
|
int i = inlinedCallForcedToReturn();
|
|
iResult = xy.x + xy.y + i;
|
|
}
|
|
|
|
public int inlinedCallForcedToReturn() { // forced to return 43
|
|
int i = checkSum;
|
|
while (loopCount-- > 0) {
|
|
targetIsInLoop = true;
|
|
checkSum += checkSum % ++i;
|
|
}
|
|
loopCount = 3;
|
|
targetIsInLoop = false;
|
|
return checkSum;
|
|
}
|
|
|
|
@Override
|
|
public int getExpectedIResult() {
|
|
return 4 + 2 + 43;
|
|
}
|
|
|
|
@Override
|
|
public void setUp() {
|
|
super.setUp();
|
|
testMethodDepth = 2;
|
|
loopCount = 3;
|
|
}
|
|
|
|
public void warmupDone() {
|
|
super.warmupDone();
|
|
msg("enter 'endless' loop by setting loopCount = Long.MAX_VALUE");
|
|
loopCount = Long.MAX_VALUE; // endless loop
|
|
}
|
|
|
|
public boolean testFrameShouldBeDeoptimized() {
|
|
return true; // because of stepping
|
|
}
|
|
|
|
@Override
|
|
public boolean shouldSkip() {
|
|
// Graal currently doesn't support Force Early Return
|
|
return super.shouldSkip() || UseJVMCICompiler;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* ForceEarlyReturn with reallocation failure.
|
|
*/
|
|
class EAForceEarlyReturnOfInlinedMethodWithScalarReplacedObjectsReallocFailure extends EATestCaseBaseDebugger {
|
|
|
|
public void runTestCase() throws Exception {
|
|
ThreadReference thread = env.targetMainThread;
|
|
env.vm().resume();
|
|
waitUntilTargetHasEnteredEndlessLoop();
|
|
|
|
thread.suspend();
|
|
printStack(thread);
|
|
// frame[0]: EAForceEarlyReturnOfInlinedMethodWithScalarReplacedObjectsReallocFailureTarget.inlinedCallForcedToReturn()
|
|
// frame[1]: EAForceEarlyReturnOfInlinedMethodWithScalarReplacedObjectsReallocFailureTarget.dontinline_testMethod()
|
|
// frame[2]: EATestCaseBaseTarget.run()
|
|
|
|
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
|
|
public boolean shouldSkip() {
|
|
// OOMEs because of realloc failures with DeoptimizeObjectsALot are too random.
|
|
// And Graal currently doesn't support Force Early Return
|
|
return super.shouldSkip() ||
|
|
!env.targetVMOptions.EliminateAllocations ||
|
|
// With ZGC or Shenandoah the OOME is not always thrown as expected
|
|
env.targetVMOptions.ZGCIsSelected ||
|
|
env.targetVMOptions.ShenandoahGCIsSelected ||
|
|
env.targetVMOptions.DeoptimizeObjectsALot ||
|
|
env.targetVMOptions.UseJVMCICompiler;
|
|
}
|
|
}
|
|
|
|
class EAForceEarlyReturnOfInlinedMethodWithScalarReplacedObjectsReallocFailureTarget extends EATestCaseBaseTarget {
|
|
|
|
public int checkSum;
|
|
|
|
public void dontinline_testMethod() {
|
|
long a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // scalar replaced
|
|
Vector10 v = new Vector10(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // scalar replaced
|
|
long l = inlinedCallForcedToReturn();
|
|
lResult = a[0] + a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8] + a[9]
|
|
+ v.i0 + v.i1 + v.i2 + v.i3 + v.i4 + v.i5 + v.i6 + v.i7 + v.i8 + v.i9 + l;
|
|
}
|
|
|
|
public long inlinedCallForcedToReturn() { // forced to return 43
|
|
long cs = checkSum;
|
|
dontinline_consumeAllMemory();
|
|
while (loopCount-- > 0) {
|
|
targetIsInLoop = true;
|
|
checkSum += checkSum % ++cs;
|
|
}
|
|
loopCount = 3;
|
|
targetIsInLoop = false;
|
|
return checkSum;
|
|
}
|
|
|
|
public void dontinline_consumeAllMemory() {
|
|
if (warmupDone) {
|
|
consumeAllMemory();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public long getExpectedLResult() {
|
|
long n = 10;
|
|
return 2*n*(n+1)/2 + 43;
|
|
}
|
|
|
|
@Override
|
|
public void setUp() {
|
|
super.setUp();
|
|
testMethodDepth = 2;
|
|
loopCount = 3;
|
|
}
|
|
|
|
public void warmupDone() {
|
|
super.warmupDone();
|
|
msg("enter 'endless' loop by setting loopCount = Long.MAX_VALUE");
|
|
loopCount = Long.MAX_VALUE; // endless loop
|
|
}
|
|
|
|
@Override
|
|
public boolean shouldSkip() {
|
|
// OOMEs because of realloc failures with DeoptimizeObjectsALot are too random.
|
|
// And Graal currently doesn't support Force Early Return
|
|
return super.shouldSkip() ||
|
|
!EliminateAllocations ||
|
|
// With ZGC or Shenandoah the OOME is not always thrown as expected
|
|
ZGCIsSelected ||
|
|
ShenandoahGCIsSelected ||
|
|
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 {
|
|
|
|
public void 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 {
|
|
|
|
public long checkSum;
|
|
|
|
public static Class<LocalXYVal> cls = LocalXYVal.class;
|
|
|
|
public static class LocalXYVal {
|
|
public int x, y;
|
|
|
|
public LocalXYVal(int x, int y) {
|
|
this.x = x; this.y = y;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void dontinline_testMethod() {
|
|
LocalXYVal p1 = new LocalXYVal(4, 2);
|
|
LocalXYVal p2 = new LocalXYVal(5, 3);
|
|
LocalXYVal p3 = new LocalXYVal(6, 4);
|
|
dontinline_endlessLoop();
|
|
iResult = p1.x+p1.y + p2.x+p2.y + p3.x+p3.y;
|
|
}
|
|
|
|
@Override
|
|
public int getExpectedIResult() {
|
|
return 6+8+10;
|
|
}
|
|
|
|
@Override
|
|
public void setUp() {
|
|
super.setUp();
|
|
testMethodDepth = 2;
|
|
loopCount = 3;
|
|
}
|
|
|
|
public void warmupDone() {
|
|
super.warmupDone();
|
|
msg("enter 'endless' loop by setting loopCount = Long.MAX_VALUE");
|
|
loopCount = Long.MAX_VALUE; // endless loop
|
|
}
|
|
}
|
|
|
|
|
|
// End of test case collection
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Helper classes
|
|
class XYVal {
|
|
|
|
public int 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())
|
|
*/
|
|
public synchronized void dontinline_sync_method(EATestCaseBaseTarget target) {
|
|
target.dontinline_brkpt();
|
|
}
|
|
|
|
/**
|
|
* Just like {@link #dontinline_sync_method(EATestCaseBaseTarget)} but without the call to
|
|
* {@link EATestCaseBaseTarget#dontinline_brkpt()}.
|
|
*/
|
|
public synchronized void 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;
|
|
}
|
|
}
|
|
|
|
class ILFDO {
|
|
|
|
public int i;
|
|
public int i2;
|
|
public long l;
|
|
public long l2;
|
|
public float f;
|
|
public float f2;
|
|
public double d;
|
|
public double d2;
|
|
public Long o;
|
|
public Long o2;
|
|
|
|
public ILFDO(int i,
|
|
int i2,
|
|
long l,
|
|
long l2,
|
|
float f,
|
|
float f2,
|
|
double d,
|
|
double d2,
|
|
Long o,
|
|
Long o2) {
|
|
this.i = i;
|
|
this.i2 = i2;
|
|
this.l = l;
|
|
this.l2 = l2;
|
|
this.f = f;
|
|
this.f2 = f2;
|
|
this.d = d;
|
|
this.d2 = d2;
|
|
this.o = o;
|
|
this.o2 = o2;
|
|
}
|
|
|
|
}
|