8230677: Should disable Escape Analysis if JVMTI capability can_get_owned_monitor_info was taken
Reviewed-by: sspitsyn, dholmes, kvn
This commit is contained in:
parent
9e17946ab2
commit
a683592254
@ -238,6 +238,7 @@ void ciEnv::cache_jvmti_state() {
|
|||||||
_jvmti_can_access_local_variables = JvmtiExport::can_access_local_variables();
|
_jvmti_can_access_local_variables = JvmtiExport::can_access_local_variables();
|
||||||
_jvmti_can_post_on_exceptions = JvmtiExport::can_post_on_exceptions();
|
_jvmti_can_post_on_exceptions = JvmtiExport::can_post_on_exceptions();
|
||||||
_jvmti_can_pop_frame = JvmtiExport::can_pop_frame();
|
_jvmti_can_pop_frame = JvmtiExport::can_pop_frame();
|
||||||
|
_jvmti_can_get_owned_monitor_info = JvmtiExport::can_get_owned_monitor_info();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ciEnv::jvmti_state_changed() const {
|
bool ciEnv::jvmti_state_changed() const {
|
||||||
@ -262,6 +263,10 @@ bool ciEnv::jvmti_state_changed() const {
|
|||||||
JvmtiExport::can_pop_frame()) {
|
JvmtiExport::can_pop_frame()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (!_jvmti_can_get_owned_monitor_info &&
|
||||||
|
JvmtiExport::can_get_owned_monitor_info()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -73,6 +73,7 @@ private:
|
|||||||
bool _jvmti_can_access_local_variables;
|
bool _jvmti_can_access_local_variables;
|
||||||
bool _jvmti_can_post_on_exceptions;
|
bool _jvmti_can_post_on_exceptions;
|
||||||
bool _jvmti_can_pop_frame;
|
bool _jvmti_can_pop_frame;
|
||||||
|
bool _jvmti_can_get_owned_monitor_info; // includes can_get_owned_monitor_stack_depth_info
|
||||||
|
|
||||||
// Cache DTrace flags
|
// Cache DTrace flags
|
||||||
bool _dtrace_extended_probes;
|
bool _dtrace_extended_probes;
|
||||||
@ -347,6 +348,7 @@ public:
|
|||||||
}
|
}
|
||||||
bool jvmti_can_hotswap_or_post_breakpoint() const { return _jvmti_can_hotswap_or_post_breakpoint; }
|
bool jvmti_can_hotswap_or_post_breakpoint() const { return _jvmti_can_hotswap_or_post_breakpoint; }
|
||||||
bool jvmti_can_post_on_exceptions() const { return _jvmti_can_post_on_exceptions; }
|
bool jvmti_can_post_on_exceptions() const { return _jvmti_can_post_on_exceptions; }
|
||||||
|
bool jvmti_can_get_owned_monitor_info() const { return _jvmti_can_get_owned_monitor_info; }
|
||||||
|
|
||||||
// Cache DTrace flags
|
// Cache DTrace flags
|
||||||
void cache_dtrace_flags();
|
void cache_dtrace_flags();
|
||||||
|
@ -102,7 +102,8 @@ void C2Compiler::compile_method(ciEnv* env, ciMethod* target, int entry_bci, Dir
|
|||||||
assert(is_initialized(), "Compiler thread must be initialized");
|
assert(is_initialized(), "Compiler thread must be initialized");
|
||||||
|
|
||||||
bool subsume_loads = SubsumeLoads;
|
bool subsume_loads = SubsumeLoads;
|
||||||
bool do_escape_analysis = DoEscapeAnalysis && !env->should_retain_local_variables();
|
bool do_escape_analysis = DoEscapeAnalysis && !env->should_retain_local_variables()
|
||||||
|
&& !env->jvmti_can_get_owned_monitor_info();
|
||||||
bool eliminate_boxing = EliminateAutoBox;
|
bool eliminate_boxing = EliminateAutoBox;
|
||||||
|
|
||||||
while (!env->failing()) {
|
while (!env->failing()) {
|
||||||
|
@ -1202,6 +1202,7 @@ bool JvmtiExport::_can_post_method_entry = fals
|
|||||||
bool JvmtiExport::_can_post_method_exit = false;
|
bool JvmtiExport::_can_post_method_exit = false;
|
||||||
bool JvmtiExport::_can_pop_frame = false;
|
bool JvmtiExport::_can_pop_frame = false;
|
||||||
bool JvmtiExport::_can_force_early_return = false;
|
bool JvmtiExport::_can_force_early_return = false;
|
||||||
|
bool JvmtiExport::_can_get_owned_monitor_info = false;
|
||||||
|
|
||||||
bool JvmtiExport::_early_vmstart_recorded = false;
|
bool JvmtiExport::_early_vmstart_recorded = false;
|
||||||
|
|
||||||
|
@ -91,6 +91,7 @@ class JvmtiExport : public AllStatic {
|
|||||||
JVMTI_SUPPORT_FLAG(can_force_early_return)
|
JVMTI_SUPPORT_FLAG(can_force_early_return)
|
||||||
|
|
||||||
JVMTI_SUPPORT_FLAG(early_vmstart_recorded)
|
JVMTI_SUPPORT_FLAG(early_vmstart_recorded)
|
||||||
|
JVMTI_SUPPORT_FLAG(can_get_owned_monitor_info) // includes can_get_owned_monitor_stack_depth_info
|
||||||
|
|
||||||
friend class JvmtiEventControllerPrivate; // should only modify these flags
|
friend class JvmtiEventControllerPrivate; // should only modify these flags
|
||||||
JVMTI_SUPPORT_FLAG(should_post_single_step)
|
JVMTI_SUPPORT_FLAG(should_post_single_step)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -367,6 +367,8 @@ void JvmtiManageCapabilities::update() {
|
|||||||
JvmtiExport::set_can_pop_frame(avail.can_pop_frame);
|
JvmtiExport::set_can_pop_frame(avail.can_pop_frame);
|
||||||
JvmtiExport::set_can_force_early_return(avail.can_force_early_return);
|
JvmtiExport::set_can_force_early_return(avail.can_force_early_return);
|
||||||
JvmtiExport::set_should_clean_up_heap_objects(avail.can_generate_breakpoint_events);
|
JvmtiExport::set_should_clean_up_heap_objects(avail.can_generate_breakpoint_events);
|
||||||
|
JvmtiExport::set_can_get_owned_monitor_info(avail.can_get_owned_monitor_info ||
|
||||||
|
avail.can_get_owned_monitor_stack_depth_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
|
@ -0,0 +1,327 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019 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 8230677
|
||||||
|
* @summary Test JVMTI's GetOwnedMonitorInfo with scalar replaced objects and eliminated locks on stack (optimizations based on escape analysis).
|
||||||
|
* @comment Without RFE 8227745 escape analysis needs to be switched off to pass the test. For the implementation of RFE 8227745 it serves as a regression test.
|
||||||
|
* @requires (vm.compMode != "Xcomp" & vm.compiler2.enabled)
|
||||||
|
* @library /test/lib
|
||||||
|
* @compile GetOwnedMonitorInfoWithEATest.java
|
||||||
|
* @run main/othervm/native
|
||||||
|
* -agentlib:GetOwnedMonitorInfoWithEATest
|
||||||
|
* -XX:+UnlockDiagnosticVMOptions
|
||||||
|
* -Xms32m -Xmx32m
|
||||||
|
* -XX:CompileCommand=dontinline,*::dontinline_*
|
||||||
|
* -XX:+PrintCompilation
|
||||||
|
* -XX:+PrintInlining
|
||||||
|
* -XX:-TieredCompilation
|
||||||
|
* -Xbatch
|
||||||
|
* -XX:CICompilerCount=1
|
||||||
|
* -XX:+DoEscapeAnalysis -XX:+EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks -XX:+UseBiasedLocking
|
||||||
|
* GetOwnedMonitorInfoWithEATest
|
||||||
|
* @run main/othervm/native
|
||||||
|
* -agentlib:GetOwnedMonitorInfoWithEATest
|
||||||
|
* -XX:+UnlockDiagnosticVMOptions
|
||||||
|
* -Xms32m -Xmx32m
|
||||||
|
* -XX:CompileCommand=dontinline,*::dontinline_*
|
||||||
|
* -XX:+PrintCompilation
|
||||||
|
* -XX:+PrintInlining
|
||||||
|
* -XX:-TieredCompilation
|
||||||
|
* -Xbatch
|
||||||
|
* -XX:CICompilerCount=1
|
||||||
|
* -XX:+DoEscapeAnalysis -XX:+EliminateAllocations -XX:-EliminateLocks -XX:+EliminateNestedLocks -XX:+UseBiasedLocking -XX:-UseOptoBiasInlining
|
||||||
|
* GetOwnedMonitorInfoWithEATest
|
||||||
|
* @run main/othervm/native
|
||||||
|
* -agentlib:GetOwnedMonitorInfoWithEATest
|
||||||
|
* -XX:+UnlockDiagnosticVMOptions
|
||||||
|
* -Xms32m -Xmx32m
|
||||||
|
* -XX:CompileCommand=dontinline,*::dontinline_*
|
||||||
|
* -XX:+PrintCompilation
|
||||||
|
* -XX:+PrintInlining
|
||||||
|
* -XX:-TieredCompilation
|
||||||
|
* -Xbatch
|
||||||
|
* -XX:CICompilerCount=1
|
||||||
|
* -XX:+DoEscapeAnalysis -XX:-EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks -XX:+UseBiasedLocking
|
||||||
|
* GetOwnedMonitorInfoWithEATest
|
||||||
|
* @run main/othervm/native
|
||||||
|
* -agentlib:GetOwnedMonitorInfoWithEATest
|
||||||
|
* -XX:+UnlockDiagnosticVMOptions
|
||||||
|
* -Xms32m -Xmx32m
|
||||||
|
* -XX:CompileCommand=dontinline,*::dontinline_*
|
||||||
|
* -XX:+PrintCompilation
|
||||||
|
* -XX:+PrintInlining
|
||||||
|
* -XX:-TieredCompilation
|
||||||
|
* -Xbatch
|
||||||
|
* -XX:CICompilerCount=1
|
||||||
|
* -XX:-DoEscapeAnalysis -XX:-EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks -XX:+UseBiasedLocking
|
||||||
|
* GetOwnedMonitorInfoWithEATest
|
||||||
|
* @run main/othervm/native
|
||||||
|
* -agentlib:GetOwnedMonitorInfoWithEATest
|
||||||
|
* -XX:+UnlockDiagnosticVMOptions
|
||||||
|
* -Xms32m -Xmx32m
|
||||||
|
* -XX:CompileCommand=dontinline,*::dontinline_*
|
||||||
|
* -XX:+PrintCompilation
|
||||||
|
* -XX:+PrintInlining
|
||||||
|
* -XX:-TieredCompilation
|
||||||
|
* -Xbatch
|
||||||
|
* -XX:CICompilerCount=1
|
||||||
|
* -XX:+DoEscapeAnalysis -XX:+EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks -XX:-UseBiasedLocking
|
||||||
|
* GetOwnedMonitorInfoWithEATest
|
||||||
|
* @run main/othervm/native
|
||||||
|
* -agentlib:GetOwnedMonitorInfoWithEATest
|
||||||
|
* -XX:+UnlockDiagnosticVMOptions
|
||||||
|
* -Xms32m -Xmx32m
|
||||||
|
* -XX:CompileCommand=dontinline,*::dontinline_*
|
||||||
|
* -XX:+PrintCompilation
|
||||||
|
* -XX:+PrintInlining
|
||||||
|
* -XX:-TieredCompilation
|
||||||
|
* -Xbatch
|
||||||
|
* -XX:CICompilerCount=1
|
||||||
|
* -XX:+DoEscapeAnalysis -XX:-EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks -XX:-UseBiasedLocking
|
||||||
|
* GetOwnedMonitorInfoWithEATest
|
||||||
|
* @run main/othervm/native
|
||||||
|
* -agentlib:GetOwnedMonitorInfoWithEATest
|
||||||
|
* -XX:+UnlockDiagnosticVMOptions
|
||||||
|
* -Xms32m -Xmx32m
|
||||||
|
* -XX:CompileCommand=dontinline,*::dontinline_*
|
||||||
|
* -XX:+PrintCompilation
|
||||||
|
* -XX:+PrintInlining
|
||||||
|
* -XX:-TieredCompilation
|
||||||
|
* -Xbatch
|
||||||
|
* -XX:CICompilerCount=1
|
||||||
|
* -XX:-DoEscapeAnalysis -XX:-EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks -XX:-UseBiasedLocking
|
||||||
|
* GetOwnedMonitorInfoWithEATest
|
||||||
|
*/
|
||||||
|
|
||||||
|
import jdk.test.lib.Asserts;
|
||||||
|
|
||||||
|
public class GetOwnedMonitorInfoWithEATest {
|
||||||
|
|
||||||
|
public static final int COMPILE_THRESHOLD = 20000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Native wrapper arround JVMTI's GetOwnedMonitorInfo().
|
||||||
|
* @param t The thread for which the owned monitors information should be retrieved.
|
||||||
|
* @param ownedMonitors Array filled in by the call with the objects associated
|
||||||
|
* with the monitors owned by the given thread.
|
||||||
|
* @param depths Per owned monitor the depth of the frame were it was locked.
|
||||||
|
* Filled in by the call
|
||||||
|
* @return Number of monitors owned by the given thread.
|
||||||
|
*/
|
||||||
|
public static native int getOwnedMonitorInfo(Thread t, Object[] ownedMonitors);
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
new GetOwnedMonitorInfoWithEATest().runTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runTest() throws Exception {
|
||||||
|
new TestCase_1().run();
|
||||||
|
new TestCase_2().run();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static abstract class TestCaseBase implements Runnable {
|
||||||
|
|
||||||
|
public long checkSum;
|
||||||
|
public boolean doLoop;
|
||||||
|
public volatile long loopCount;
|
||||||
|
public volatile boolean targetIsInLoop;
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
msgHL("Executing test case " + getClass().getName());
|
||||||
|
warmUp();
|
||||||
|
runTest();
|
||||||
|
} catch (Exception e) {
|
||||||
|
Asserts.fail("Unexpected Exception", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void warmUp() {
|
||||||
|
int callCount = COMPILE_THRESHOLD + 1000;
|
||||||
|
doLoop = true;
|
||||||
|
while (callCount-- > 0) {
|
||||||
|
dontinline_testMethod();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void runTest() throws Exception;
|
||||||
|
public abstract void dontinline_testMethod();
|
||||||
|
|
||||||
|
public long dontinline_endlessLoop() {
|
||||||
|
long cs = checkSum;
|
||||||
|
while (doLoop && loopCount-- > 0) {
|
||||||
|
targetIsInLoop = true;
|
||||||
|
checkSum += checkSum % ++cs;
|
||||||
|
}
|
||||||
|
loopCount = 3;
|
||||||
|
targetIsInLoop = false;
|
||||||
|
return checkSum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void waitUntilTargetThreadHasEnteredEndlessLoop() throws Exception {
|
||||||
|
while(!targetIsInLoop) {
|
||||||
|
msg("Target has not yet entered the loop. Sleep 200ms.");
|
||||||
|
try { Thread.sleep(200); } catch (InterruptedException e) { /*ignore */ }
|
||||||
|
}
|
||||||
|
msg("Target has entered the loop.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void terminateEndlessLoop() throws Exception {
|
||||||
|
msg("Terminate endless loop");
|
||||||
|
do {
|
||||||
|
doLoop = false;
|
||||||
|
} while(targetIsInLoop);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void msg(String m) {
|
||||||
|
System.out.println();
|
||||||
|
System.out.println("### " + m);
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void msgHL(String m) {
|
||||||
|
System.out.println();
|
||||||
|
System.out.println("#####################################################");
|
||||||
|
System.out.println("### " + m);
|
||||||
|
System.out.println("###");
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts target thread T and then queries monitor information for T using JVMTI's GetOwnedMonitorInfo().
|
||||||
|
* With escape analysis enabled the jit compiled method {@link #dontinline_testMethod()} has
|
||||||
|
* scalar replaced objects with eliminated (nested) locking in scope when the monitor
|
||||||
|
* information is retrieved. Effectively the objects escape through the JVMTI call. This works
|
||||||
|
* only with RFE 8227745. Without it escape analysis needs to be disabled.
|
||||||
|
*/
|
||||||
|
public static class TestCase_1 extends TestCaseBase {
|
||||||
|
|
||||||
|
public void runTest() throws Exception {
|
||||||
|
loopCount = 1L << 62; // endless loop
|
||||||
|
Thread t1 = new Thread(() -> dontinline_testMethod(), "Target Thread");
|
||||||
|
t1.start();
|
||||||
|
try {
|
||||||
|
waitUntilTargetThreadHasEnteredEndlessLoop();
|
||||||
|
int expectedMonitorCount = 1;
|
||||||
|
int resultSize = expectedMonitorCount + 3;
|
||||||
|
Object[] ownedMonitors = new Object[resultSize];
|
||||||
|
msg("Get monitor info");
|
||||||
|
int monitorCount = getOwnedMonitorInfo(t1, ownedMonitors);
|
||||||
|
terminateEndlessLoop();
|
||||||
|
t1.join();
|
||||||
|
Asserts.assertGreaterThanOrEqual(monitorCount, 0, "getOwnedMonitorsFor() call failed");
|
||||||
|
msg("Monitor info:");
|
||||||
|
for (int i = 0; i < monitorCount; i++) {
|
||||||
|
System.out.println(i + ": cls=" + (ownedMonitors[i] != null ? ownedMonitors[i].getClass() : null));
|
||||||
|
}
|
||||||
|
Asserts.assertEQ(monitorCount, expectedMonitorCount, "unexpected monitor count returned by getOwnedMonitorsFor()");
|
||||||
|
Asserts.assertNotNull(ownedMonitors[0]);
|
||||||
|
Asserts.assertSame(ownedMonitors[0].getClass(), LockCls.class);
|
||||||
|
} finally {
|
||||||
|
terminateEndlessLoop();
|
||||||
|
t1.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dontinline_testMethod() {
|
||||||
|
LockCls l1 = new LockCls(); // to be scalar replaced
|
||||||
|
synchronized (l1) {
|
||||||
|
inlinedTestMethodWithNestedLocking(l1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void inlinedTestMethodWithNestedLocking(LockCls l1) {
|
||||||
|
synchronized (l1) { // nested
|
||||||
|
dontinline_endlessLoop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Similar to {@link TestCase_1}. Additionally the target thread T has got eliminated locking
|
||||||
|
* for a synchronized method of a different type {@linkplain LockCls2}.
|
||||||
|
*/
|
||||||
|
public static class TestCase_2 extends TestCaseBase {
|
||||||
|
|
||||||
|
public void runTest() throws Exception {
|
||||||
|
loopCount = 1L << 62; // endless loop
|
||||||
|
Thread t1 = new Thread(() -> dontinline_testMethod(), "Target Thread");
|
||||||
|
t1.start();
|
||||||
|
try {
|
||||||
|
waitUntilTargetThreadHasEnteredEndlessLoop();
|
||||||
|
int expectedMonitorCount = 2;
|
||||||
|
int resultSize = expectedMonitorCount + 3;
|
||||||
|
Object[] ownedMonitors = new Object[resultSize];
|
||||||
|
msg("Get monitor info");
|
||||||
|
int monitorCount = getOwnedMonitorInfo(t1, ownedMonitors);
|
||||||
|
terminateEndlessLoop();
|
||||||
|
t1.join();
|
||||||
|
Asserts.assertGreaterThanOrEqual(monitorCount, 0, "getOwnedMonitorsFor() call failed");
|
||||||
|
msg("Monitor info:");
|
||||||
|
for (int i = 0; i < monitorCount; i++) {
|
||||||
|
System.out.println(i + ": cls=" + (ownedMonitors[i] != null ? ownedMonitors[i].getClass() : null));
|
||||||
|
}
|
||||||
|
Asserts.assertEQ(monitorCount, expectedMonitorCount, "unexpected monitor count returned by getOwnedMonitorsFor()");
|
||||||
|
Asserts.assertNotNull(ownedMonitors[0]);
|
||||||
|
Asserts.assertSame(ownedMonitors[0].getClass(), LockCls2.class);
|
||||||
|
|
||||||
|
Asserts.assertNotNull(ownedMonitors[1]);
|
||||||
|
Asserts.assertSame(ownedMonitors[1].getClass(), LockCls.class);
|
||||||
|
} finally {
|
||||||
|
terminateEndlessLoop();
|
||||||
|
t1.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dontinline_testMethod() {
|
||||||
|
LockCls l1 = new LockCls();
|
||||||
|
synchronized (l1) {
|
||||||
|
inlinedTestMethodWithNestedLocking(l1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void inlinedTestMethodWithNestedLocking(LockCls l1) {
|
||||||
|
synchronized (l1) {
|
||||||
|
dontinline_testMethod2();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dontinline_testMethod2() {
|
||||||
|
// Call synchronized method. Receiver of the call will be scalar replaced,
|
||||||
|
// and locking will be eliminated. Here we use a different type.
|
||||||
|
new LockCls2().inline_synchronized_testMethod(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class LockCls {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class LockCls2 {
|
||||||
|
public synchronized void inline_synchronized_testMethod(TestCaseBase testCase) {
|
||||||
|
testCase.dontinline_endlessLoop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,166 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "jvmti.h"
|
||||||
|
#include "jni.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef JNI_ENV_ARG
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define JNI_ENV_ARG(x, y) y
|
||||||
|
#define JNI_ENV_PTR(x) x
|
||||||
|
#else
|
||||||
|
#define JNI_ENV_ARG(x,y) x, y
|
||||||
|
#define JNI_ENV_PTR(x) (*x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define FAILED -1
|
||||||
|
|
||||||
|
static jvmtiEnv *jvmti;
|
||||||
|
|
||||||
|
static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved);
|
||||||
|
|
||||||
|
static void ShowErrorMessage(jvmtiEnv *jvmti, jvmtiError errCode, const char *message) {
|
||||||
|
char *errMsg;
|
||||||
|
jvmtiError result;
|
||||||
|
|
||||||
|
result = (*jvmti)->GetErrorName(jvmti, errCode, &errMsg);
|
||||||
|
if (result == JVMTI_ERROR_NONE) {
|
||||||
|
fprintf(stderr, "%s: %s (%d)\n", message, errMsg, errCode);
|
||||||
|
(*jvmti)->Deallocate(jvmti, (unsigned char *)errMsg);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "%s (%d)\n", message, errCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
|
||||||
|
return Agent_Initialize(jvm, options, reserved);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
|
||||||
|
return Agent_Initialize(jvm, options, reserved);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
JNI_OnLoad(JavaVM *jvm, void *reserved) {
|
||||||
|
jint res;
|
||||||
|
JNIEnv *env;
|
||||||
|
|
||||||
|
res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &env),
|
||||||
|
JNI_VERSION_9);
|
||||||
|
if (res != JNI_OK || env == NULL) {
|
||||||
|
fprintf(stderr, "Error: GetEnv call failed(%d)!\n", res);
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return JNI_VERSION_9;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
|
||||||
|
jint res;
|
||||||
|
jvmtiError err;
|
||||||
|
jvmtiCapabilities caps;
|
||||||
|
|
||||||
|
printf("Agent_OnLoad started\n");
|
||||||
|
|
||||||
|
memset(&caps, 0, sizeof(caps));
|
||||||
|
|
||||||
|
res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti),
|
||||||
|
JVMTI_VERSION_9);
|
||||||
|
if (res != JNI_OK || jvmti == NULL) {
|
||||||
|
fprintf(stderr, "Error: wrong result of a valid call to GetEnv!\n");
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
caps.can_get_owned_monitor_info = 1;
|
||||||
|
|
||||||
|
err = (*jvmti)->AddCapabilities(jvmti, &caps);
|
||||||
|
if (err != JVMTI_ERROR_NONE) {
|
||||||
|
ShowErrorMessage(jvmti, err,
|
||||||
|
"Agent_OnLoad: error in JVMTI AddCapabilities");
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = (*jvmti)->GetCapabilities(jvmti, &caps);
|
||||||
|
if (err != JVMTI_ERROR_NONE) {
|
||||||
|
ShowErrorMessage(jvmti, err,
|
||||||
|
"Agent_OnLoad: error in JVMTI GetCapabilities");
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!caps.can_get_owned_monitor_info) {
|
||||||
|
fprintf(stderr, "Warning: GetOwnedMonitorInfo is not implemented\n");
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Agent_OnLoad finished\n");
|
||||||
|
return JNI_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_GetOwnedMonitorInfoWithEATest_getOwnedMonitorInfo(JNIEnv *env, jclass cls, jobject targetThread, jobjectArray resOwnedMonitors) {
|
||||||
|
jvmtiError err;
|
||||||
|
jvmtiThreadInfo threadInfo;
|
||||||
|
jint monitorCount;
|
||||||
|
jobject* monitors;
|
||||||
|
jint idx;
|
||||||
|
|
||||||
|
err = (*jvmti)->GetThreadInfo(jvmti, targetThread, &threadInfo);
|
||||||
|
if (err != JVMTI_ERROR_NONE) {
|
||||||
|
ShowErrorMessage(jvmti, err,
|
||||||
|
"getOwnedMonitorsFor: error in JVMTI GetThreadInfo");
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = (*jvmti)->GetOwnedMonitorInfo(jvmti, targetThread, &monitorCount, &monitors);
|
||||||
|
if (err != JVMTI_ERROR_NONE) {
|
||||||
|
ShowErrorMessage(jvmti, err,
|
||||||
|
"getOwnedMonitorsFor: error in JVMTI GetOwnedMonitorInfo");
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("getOwnedMonitorsFor: %s owns %d monitor(s)\n", threadInfo.name, monitorCount);
|
||||||
|
|
||||||
|
for (idx = 0; idx < monitorCount; idx++) {
|
||||||
|
(*env)->SetObjectArrayElement(env, resOwnedMonitors, idx, monitors[idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
(*jvmti)->Deallocate(jvmti, (unsigned char *) monitors);
|
||||||
|
(*jvmti)->Deallocate(jvmti, (unsigned char *) threadInfo.name);
|
||||||
|
return monitorCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,330 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019 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 8230677
|
||||||
|
* @summary Test JVMTI's GetOwnedMonitorStackDepthInfo with scalar replaced objects and eliminated locks on stack (optimizations based on escape analysis).
|
||||||
|
* @comment Without RFE 8227745 escape analysis needs to be switched off to pass the test. For the implementation of RFE 8227745 it serves as a regression test.
|
||||||
|
* @requires (vm.compMode != "Xcomp" & vm.compiler2.enabled)
|
||||||
|
* @library /test/lib
|
||||||
|
* @compile GetOwnedMonitorStackDepthInfoWithEATest.java
|
||||||
|
* @run main/othervm/native
|
||||||
|
* -agentlib:GetOwnedMonitorStackDepthInfoWithEATest
|
||||||
|
* -XX:+UnlockDiagnosticVMOptions
|
||||||
|
* -Xms32m -Xmx32m
|
||||||
|
* -XX:CompileCommand=dontinline,*::dontinline_*
|
||||||
|
* -XX:+PrintCompilation
|
||||||
|
* -XX:+PrintInlining
|
||||||
|
* -XX:-TieredCompilation
|
||||||
|
* -Xbatch
|
||||||
|
* -XX:CICompilerCount=1
|
||||||
|
* -XX:+DoEscapeAnalysis -XX:+EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks -XX:+UseBiasedLocking
|
||||||
|
* GetOwnedMonitorStackDepthInfoWithEATest
|
||||||
|
* @run main/othervm/native
|
||||||
|
* -agentlib:GetOwnedMonitorStackDepthInfoWithEATest
|
||||||
|
* -XX:+UnlockDiagnosticVMOptions
|
||||||
|
* -Xms32m -Xmx32m
|
||||||
|
* -XX:CompileCommand=dontinline,*::dontinline_*
|
||||||
|
* -XX:+PrintCompilation
|
||||||
|
* -XX:+PrintInlining
|
||||||
|
* -XX:-TieredCompilation
|
||||||
|
* -Xbatch
|
||||||
|
* -XX:CICompilerCount=1
|
||||||
|
* -XX:+DoEscapeAnalysis -XX:+EliminateAllocations -XX:-EliminateLocks -XX:+EliminateNestedLocks -XX:+UseBiasedLocking -XX:-UseOptoBiasInlining
|
||||||
|
* GetOwnedMonitorStackDepthInfoWithEATest
|
||||||
|
* @run main/othervm/native
|
||||||
|
* -agentlib:GetOwnedMonitorStackDepthInfoWithEATest
|
||||||
|
* -XX:+UnlockDiagnosticVMOptions
|
||||||
|
* -Xms32m -Xmx32m
|
||||||
|
* -XX:CompileCommand=dontinline,*::dontinline_*
|
||||||
|
* -XX:+PrintCompilation
|
||||||
|
* -XX:+PrintInlining
|
||||||
|
* -XX:-TieredCompilation
|
||||||
|
* -Xbatch
|
||||||
|
* -XX:CICompilerCount=1
|
||||||
|
* -XX:+DoEscapeAnalysis -XX:-EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks -XX:+UseBiasedLocking
|
||||||
|
* GetOwnedMonitorStackDepthInfoWithEATest
|
||||||
|
* @run main/othervm/native
|
||||||
|
* -agentlib:GetOwnedMonitorStackDepthInfoWithEATest
|
||||||
|
* -XX:+UnlockDiagnosticVMOptions
|
||||||
|
* -Xms32m -Xmx32m
|
||||||
|
* -XX:CompileCommand=dontinline,*::dontinline_*
|
||||||
|
* -XX:+PrintCompilation
|
||||||
|
* -XX:+PrintInlining
|
||||||
|
* -XX:-TieredCompilation
|
||||||
|
* -Xbatch
|
||||||
|
* -XX:CICompilerCount=1
|
||||||
|
* -XX:-DoEscapeAnalysis -XX:-EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks -XX:+UseBiasedLocking
|
||||||
|
* GetOwnedMonitorStackDepthInfoWithEATest
|
||||||
|
* @run main/othervm/native
|
||||||
|
* -agentlib:GetOwnedMonitorStackDepthInfoWithEATest
|
||||||
|
* -XX:+UnlockDiagnosticVMOptions
|
||||||
|
* -Xms32m -Xmx32m
|
||||||
|
* -XX:CompileCommand=dontinline,*::dontinline_*
|
||||||
|
* -XX:+PrintCompilation
|
||||||
|
* -XX:+PrintInlining
|
||||||
|
* -XX:-TieredCompilation
|
||||||
|
* -Xbatch
|
||||||
|
* -XX:CICompilerCount=1
|
||||||
|
* -XX:+DoEscapeAnalysis -XX:+EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks -XX:-UseBiasedLocking
|
||||||
|
* GetOwnedMonitorStackDepthInfoWithEATest
|
||||||
|
* @run main/othervm/native
|
||||||
|
* -agentlib:GetOwnedMonitorStackDepthInfoWithEATest
|
||||||
|
* -XX:+UnlockDiagnosticVMOptions
|
||||||
|
* -Xms32m -Xmx32m
|
||||||
|
* -XX:CompileCommand=dontinline,*::dontinline_*
|
||||||
|
* -XX:+PrintCompilation
|
||||||
|
* -XX:+PrintInlining
|
||||||
|
* -XX:-TieredCompilation
|
||||||
|
* -Xbatch
|
||||||
|
* -XX:CICompilerCount=1
|
||||||
|
* -XX:+DoEscapeAnalysis -XX:-EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks -XX:-UseBiasedLocking
|
||||||
|
* GetOwnedMonitorStackDepthInfoWithEATest
|
||||||
|
* @run main/othervm/native
|
||||||
|
* -agentlib:GetOwnedMonitorStackDepthInfoWithEATest
|
||||||
|
* -XX:+UnlockDiagnosticVMOptions
|
||||||
|
* -Xms32m -Xmx32m
|
||||||
|
* -XX:CompileCommand=dontinline,*::dontinline_*
|
||||||
|
* -XX:+PrintCompilation
|
||||||
|
* -XX:+PrintInlining
|
||||||
|
* -XX:-TieredCompilation
|
||||||
|
* -Xbatch
|
||||||
|
* -XX:CICompilerCount=1
|
||||||
|
* -XX:-DoEscapeAnalysis -XX:-EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks -XX:-UseBiasedLocking
|
||||||
|
* GetOwnedMonitorStackDepthInfoWithEATest
|
||||||
|
*/
|
||||||
|
|
||||||
|
import jdk.test.lib.Asserts;
|
||||||
|
|
||||||
|
public class GetOwnedMonitorStackDepthInfoWithEATest {
|
||||||
|
|
||||||
|
public static final int COMPILE_THRESHOLD = 20000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Native wrapper arround JVMTI's GetOwnedMonitorStackDepthInfo().
|
||||||
|
* @param t The thread for which the owned monitors information should be retrieved.
|
||||||
|
* @param ownedMonitors Array filled in by the call with the objects associated
|
||||||
|
* with the monitors owned by the given thread.
|
||||||
|
* @param depths Per owned monitor the depth of the frame were it was locked.
|
||||||
|
* Filled in by the call
|
||||||
|
* @return Number of monitors owned by the given thread.
|
||||||
|
*/
|
||||||
|
public static native int getOwnedMonitorStackDepthInfo(Thread t, Object[] ownedMonitors, int[] depths);
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
new GetOwnedMonitorStackDepthInfoWithEATest().runTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runTest() throws Exception {
|
||||||
|
new TestCase_1().run();
|
||||||
|
new TestCase_2().run();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static abstract class TestCaseBase implements Runnable {
|
||||||
|
|
||||||
|
public long checkSum;
|
||||||
|
public boolean doLoop;
|
||||||
|
public volatile long loopCount;
|
||||||
|
public volatile boolean targetIsInLoop;
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
msgHL("Executing test case " + getClass().getName());
|
||||||
|
warmUp();
|
||||||
|
runTest();
|
||||||
|
} catch (Exception e) {
|
||||||
|
Asserts.fail("Unexpected Exception", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void warmUp() {
|
||||||
|
int callCount = COMPILE_THRESHOLD + 1000;
|
||||||
|
doLoop = true;
|
||||||
|
while (callCount-- > 0) {
|
||||||
|
dontinline_testMethod();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void runTest() throws Exception;
|
||||||
|
public abstract void dontinline_testMethod();
|
||||||
|
|
||||||
|
public long dontinline_endlessLoop() {
|
||||||
|
long cs = checkSum;
|
||||||
|
while (doLoop && loopCount-- > 0) {
|
||||||
|
targetIsInLoop = true;
|
||||||
|
checkSum += checkSum % ++cs;
|
||||||
|
}
|
||||||
|
loopCount = 3;
|
||||||
|
targetIsInLoop = false;
|
||||||
|
return checkSum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void waitUntilTargetThreadHasEnteredEndlessLoop() throws Exception {
|
||||||
|
while(!targetIsInLoop) {
|
||||||
|
msg("Target has not yet entered the loop. Sleep 200ms.");
|
||||||
|
try { Thread.sleep(200); } catch (InterruptedException e) { /*ignore */ }
|
||||||
|
}
|
||||||
|
msg("Target has entered the loop.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void terminateEndlessLoop() throws Exception {
|
||||||
|
msg("Terminate endless loop");
|
||||||
|
do {
|
||||||
|
doLoop = false;
|
||||||
|
} while(targetIsInLoop);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void msg(String m) {
|
||||||
|
System.out.println();
|
||||||
|
System.out.println("### " + m);
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void msgHL(String m) {
|
||||||
|
System.out.println();
|
||||||
|
System.out.println("#####################################################");
|
||||||
|
System.out.println("### " + m);
|
||||||
|
System.out.println("###");
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts target thread T and then queries monitor information for T using JVMTI's GetOwnedMonitorStackDepthInfo().
|
||||||
|
* With escape analysis enabled the jit compiled method {@link #dontinline_testMethod()} has
|
||||||
|
* scalar replaced objects with eliminated (nested) locking in scope when the monitor
|
||||||
|
* information is retrieved. Effectively the objects escape through the JVMTI call. This works
|
||||||
|
* only with RFE 8227745. Without it escape analysis needs to be disabled.
|
||||||
|
*/
|
||||||
|
public static class TestCase_1 extends TestCaseBase {
|
||||||
|
|
||||||
|
public void runTest() throws Exception {
|
||||||
|
loopCount = 1L << 62; // endless loop
|
||||||
|
Thread t1 = new Thread(() -> dontinline_testMethod(), "Target Thread");
|
||||||
|
try {
|
||||||
|
t1.start();
|
||||||
|
waitUntilTargetThreadHasEnteredEndlessLoop();
|
||||||
|
int expectedMonitorCount = 1;
|
||||||
|
int resultSize = expectedMonitorCount + 3;
|
||||||
|
Object[] ownedMonitors = new Object[resultSize];
|
||||||
|
int[] depths = new int[resultSize];
|
||||||
|
msg("Get monitor info");
|
||||||
|
int monitorCount = getOwnedMonitorStackDepthInfo(t1, ownedMonitors, depths);
|
||||||
|
Asserts.assertGreaterThanOrEqual(monitorCount, 0, "getOwnedMonitorsFor() call failed");
|
||||||
|
msg("Monitor info:");
|
||||||
|
for (int i = 0; i < monitorCount; i++) {
|
||||||
|
System.out.println(i + ": cls=" + (ownedMonitors[i] != null ? ownedMonitors[i].getClass() : null) + " depth=" + depths[i]);
|
||||||
|
}
|
||||||
|
Asserts.assertEQ(monitorCount, expectedMonitorCount, "unexpected monitor count returned by getOwnedMonitorsFor()");
|
||||||
|
Asserts.assertNotNull(ownedMonitors[0]);
|
||||||
|
Asserts.assertSame(ownedMonitors[0].getClass(), LockCls.class);
|
||||||
|
Asserts.assertEQ(depths[0], 1, "unexpected depth for owned monitor at index 0");
|
||||||
|
} finally {
|
||||||
|
terminateEndlessLoop();
|
||||||
|
t1.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dontinline_testMethod() {
|
||||||
|
LockCls l1 = new LockCls(); // to be scalar replaced
|
||||||
|
synchronized (l1) {
|
||||||
|
inlinedTestMethodWithNestedLocking(l1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void inlinedTestMethodWithNestedLocking(LockCls l1) {
|
||||||
|
synchronized (l1) { // nested
|
||||||
|
dontinline_endlessLoop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Similar to {@link TestCase_1}. Additionally the target thread T has got eliminated locking
|
||||||
|
* for a synchronized method of a different type {@linkplain LockCls2}.
|
||||||
|
*/
|
||||||
|
public static class TestCase_2 extends TestCaseBase {
|
||||||
|
|
||||||
|
public void runTest() throws Exception {
|
||||||
|
loopCount = 1L << 62; // endless loop
|
||||||
|
Thread t1 = new Thread(() -> dontinline_testMethod(), "Target Thread");
|
||||||
|
t1.start();
|
||||||
|
try {
|
||||||
|
waitUntilTargetThreadHasEnteredEndlessLoop();
|
||||||
|
int expectedMonitorCount = 2;
|
||||||
|
int resultSize = expectedMonitorCount + 3;
|
||||||
|
Object[] ownedMonitors = new Object[resultSize];
|
||||||
|
int[] depths = new int[resultSize];
|
||||||
|
msg("Get monitor info");
|
||||||
|
int monitorCount = getOwnedMonitorStackDepthInfo(t1, ownedMonitors, depths);
|
||||||
|
terminateEndlessLoop();
|
||||||
|
t1.join();
|
||||||
|
Asserts.assertGreaterThanOrEqual(monitorCount, 0, "getOwnedMonitorsFor() call failed");
|
||||||
|
msg("Monitor info:");
|
||||||
|
for (int i = 0; i < monitorCount; i++) {
|
||||||
|
System.out.println(i + ": cls=" + (ownedMonitors[i] != null ? ownedMonitors[i].getClass() : null) + " depth=" + depths[i]);
|
||||||
|
}
|
||||||
|
Asserts.assertEQ(monitorCount, expectedMonitorCount, "unexpected monitor count returned by getOwnedMonitorsFor()");
|
||||||
|
Asserts.assertNotNull(ownedMonitors[0]);
|
||||||
|
Asserts.assertSame(ownedMonitors[0].getClass(), LockCls2.class);
|
||||||
|
Asserts.assertEQ(depths[0], 1, "unexpected depth for owned monitor at index 0");
|
||||||
|
|
||||||
|
Asserts.assertNotNull(ownedMonitors[1]);
|
||||||
|
Asserts.assertSame(ownedMonitors[1].getClass(), LockCls.class);
|
||||||
|
Asserts.assertEQ(depths[1], 3, "unexpected depth for owned monitor at index 1");
|
||||||
|
} finally {
|
||||||
|
terminateEndlessLoop();
|
||||||
|
t1.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dontinline_testMethod() {
|
||||||
|
LockCls l1 = new LockCls();
|
||||||
|
synchronized (l1) {
|
||||||
|
inlinedTestMethodWithNestedLocking(l1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void inlinedTestMethodWithNestedLocking(LockCls l1) {
|
||||||
|
synchronized (l1) {
|
||||||
|
dontinline_testMethod2();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dontinline_testMethod2() {
|
||||||
|
// Call synchronized method. Receiver of the call will be scalar replaced,
|
||||||
|
// and locking will be eliminated. Here we use a different type.
|
||||||
|
new LockCls2().inline_synchronized_testMethod(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class LockCls {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class LockCls2 {
|
||||||
|
public synchronized void inline_synchronized_testMethod(TestCaseBase testCase) {
|
||||||
|
testCase.dontinline_endlessLoop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,170 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "jvmti.h"
|
||||||
|
#include "jni.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef JNI_ENV_ARG
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define JNI_ENV_ARG(x, y) y
|
||||||
|
#define JNI_ENV_PTR(x) x
|
||||||
|
#else
|
||||||
|
#define JNI_ENV_ARG(x,y) x, y
|
||||||
|
#define JNI_ENV_PTR(x) (*x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define FAILED -1
|
||||||
|
|
||||||
|
static jvmtiEnv *jvmti;
|
||||||
|
|
||||||
|
static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved);
|
||||||
|
|
||||||
|
static void ShowErrorMessage(jvmtiEnv *jvmti, jvmtiError errCode, const char *message) {
|
||||||
|
char *errMsg;
|
||||||
|
jvmtiError result;
|
||||||
|
|
||||||
|
result = (*jvmti)->GetErrorName(jvmti, errCode, &errMsg);
|
||||||
|
if (result == JVMTI_ERROR_NONE) {
|
||||||
|
fprintf(stderr, "%s: %s (%d)\n", message, errMsg, errCode);
|
||||||
|
(*jvmti)->Deallocate(jvmti, (unsigned char *)errMsg);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "%s (%d)\n", message, errCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
|
||||||
|
return Agent_Initialize(jvm, options, reserved);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
|
||||||
|
return Agent_Initialize(jvm, options, reserved);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
JNI_OnLoad(JavaVM *jvm, void *reserved) {
|
||||||
|
jint res;
|
||||||
|
JNIEnv *env;
|
||||||
|
|
||||||
|
res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &env),
|
||||||
|
JNI_VERSION_9);
|
||||||
|
if (res != JNI_OK || env == NULL) {
|
||||||
|
fprintf(stderr, "Error: GetEnv call failed(%d)!\n", res);
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return JNI_VERSION_9;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
|
||||||
|
jint res;
|
||||||
|
jvmtiError err;
|
||||||
|
jvmtiCapabilities caps;
|
||||||
|
|
||||||
|
printf("Agent_OnLoad started\n");
|
||||||
|
|
||||||
|
memset(&caps, 0, sizeof(caps));
|
||||||
|
|
||||||
|
res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti),
|
||||||
|
JVMTI_VERSION_9);
|
||||||
|
if (res != JNI_OK || jvmti == NULL) {
|
||||||
|
fprintf(stderr, "Error: wrong result of a valid call to GetEnv!\n");
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
caps.can_get_owned_monitor_stack_depth_info = 1;
|
||||||
|
|
||||||
|
err = (*jvmti)->AddCapabilities(jvmti, &caps);
|
||||||
|
if (err != JVMTI_ERROR_NONE) {
|
||||||
|
ShowErrorMessage(jvmti, err,
|
||||||
|
"Agent_OnLoad: error in JVMTI AddCapabilities");
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = (*jvmti)->GetCapabilities(jvmti, &caps);
|
||||||
|
if (err != JVMTI_ERROR_NONE) {
|
||||||
|
ShowErrorMessage(jvmti, err,
|
||||||
|
"Agent_OnLoad: error in JVMTI GetCapabilities");
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!caps.can_get_owned_monitor_stack_depth_info) {
|
||||||
|
fprintf(stderr, "Warning: GetOwnedMonitorStackDepthInfo is not implemented\n");
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Agent_OnLoad finished\n");
|
||||||
|
return JNI_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_GetOwnedMonitorStackDepthInfoWithEATest_getOwnedMonitorStackDepthInfo(JNIEnv *env, jclass cls, jobject targetThread, jobjectArray ownedMonitors, jintArray depths) {
|
||||||
|
jvmtiError err;
|
||||||
|
jvmtiThreadInfo threadInfo;
|
||||||
|
jint monitorCount;
|
||||||
|
jvmtiMonitorStackDepthInfo* stackDepthInfo;
|
||||||
|
jint* depthsPtr;
|
||||||
|
jint idx = 0;
|
||||||
|
|
||||||
|
err = (*jvmti)->GetThreadInfo(jvmti, targetThread, &threadInfo);
|
||||||
|
if (err != JVMTI_ERROR_NONE) {
|
||||||
|
ShowErrorMessage(jvmti, err,
|
||||||
|
"getOwnedMonitorsFor: error in JVMTI GetThreadInfo");
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = (*jvmti)->GetOwnedMonitorStackDepthInfo(jvmti, targetThread, &monitorCount, &stackDepthInfo);
|
||||||
|
if (err != JVMTI_ERROR_NONE) {
|
||||||
|
ShowErrorMessage(jvmti, err,
|
||||||
|
"getOwnedMonitorsFor: error in JVMTI GetOwnedMonitorStackDepthInfo");
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("getOwnedMonitorsFor: %s owns %d monitor(s)\n", threadInfo.name, monitorCount);
|
||||||
|
|
||||||
|
depthsPtr = (*env)->GetIntArrayElements(env, depths, NULL);
|
||||||
|
for (idx = 0; idx < monitorCount; idx++) {
|
||||||
|
(*env)->SetObjectArrayElement(env, ownedMonitors, idx, stackDepthInfo[idx].monitor);
|
||||||
|
depthsPtr[idx] = stackDepthInfo[idx].stack_depth;
|
||||||
|
}
|
||||||
|
(*env)->ReleaseIntArrayElements(env, depths, depthsPtr, 0);
|
||||||
|
|
||||||
|
(*jvmti)->Deallocate(jvmti, (unsigned char *) stackDepthInfo);
|
||||||
|
(*jvmti)->Deallocate(jvmti, (unsigned char *) threadInfo.name);
|
||||||
|
return monitorCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user