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_post_on_exceptions = JvmtiExport::can_post_on_exceptions();
|
||||
_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 {
|
||||
@ -262,6 +263,10 @@ bool ciEnv::jvmti_state_changed() const {
|
||||
JvmtiExport::can_pop_frame()) {
|
||||
return true;
|
||||
}
|
||||
if (!_jvmti_can_get_owned_monitor_info &&
|
||||
JvmtiExport::can_get_owned_monitor_info()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -73,6 +73,7 @@ private:
|
||||
bool _jvmti_can_access_local_variables;
|
||||
bool _jvmti_can_post_on_exceptions;
|
||||
bool _jvmti_can_pop_frame;
|
||||
bool _jvmti_can_get_owned_monitor_info; // includes can_get_owned_monitor_stack_depth_info
|
||||
|
||||
// Cache DTrace flags
|
||||
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_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
|
||||
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");
|
||||
|
||||
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;
|
||||
|
||||
while (!env->failing()) {
|
||||
|
@ -1202,6 +1202,7 @@ bool JvmtiExport::_can_post_method_entry = fals
|
||||
bool JvmtiExport::_can_post_method_exit = false;
|
||||
bool JvmtiExport::_can_pop_frame = false;
|
||||
bool JvmtiExport::_can_force_early_return = false;
|
||||
bool JvmtiExport::_can_get_owned_monitor_info = 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(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
|
||||
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.
|
||||
*
|
||||
* 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_force_early_return(avail.can_force_early_return);
|
||||
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
|
||||
|
@ -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