8242425: JVMTI monitor operations should use Thread-Local Handshakes

Reviewed-by: sspitsyn, dholmes
This commit is contained in:
Yasumasa Suenaga 2020-04-20 13:57:11 +09:00
parent fc728278c2
commit efcb6bd20e
4 changed files with 61 additions and 93 deletions

View file

@ -1200,21 +1200,19 @@ JvmtiEnv::GetThreadInfo(jthread thread, jvmtiThreadInfo* info_ptr) {
jvmtiError jvmtiError
JvmtiEnv::GetOwnedMonitorInfo(JavaThread* java_thread, jint* owned_monitor_count_ptr, jobject** owned_monitors_ptr) { JvmtiEnv::GetOwnedMonitorInfo(JavaThread* java_thread, jint* owned_monitor_count_ptr, jobject** owned_monitors_ptr) {
jvmtiError err = JVMTI_ERROR_NONE; jvmtiError err = JVMTI_ERROR_NONE;
JavaThread* calling_thread = JavaThread::current();
// growable array of jvmti monitors info on the C-heap // growable array of jvmti monitors info on the C-heap
GrowableArray<jvmtiMonitorStackDepthInfo*> *owned_monitors_list = GrowableArray<jvmtiMonitorStackDepthInfo*> *owned_monitors_list =
new (ResourceObj::C_HEAP, mtInternal) GrowableArray<jvmtiMonitorStackDepthInfo*>(1, true); new (ResourceObj::C_HEAP, mtInternal) GrowableArray<jvmtiMonitorStackDepthInfo*>(1, true);
// It is only safe to perform the direct operation on the current // It is only safe to perform the direct operation on the current
// thread. All other usage needs to use a vm-safepoint-op for safety. // thread. All other usage needs to use a direct handshake for safety.
if (java_thread == calling_thread) { if (java_thread == JavaThread::current()) {
err = get_owned_monitors(calling_thread, java_thread, owned_monitors_list); err = get_owned_monitors(java_thread, owned_monitors_list);
} else { } else {
// JVMTI get monitors info at safepoint. Do not require target thread to // get owned monitors info with handshake
// be suspended. GetOwnedMonitorInfoClosure op(this, owned_monitors_list);
VM_GetOwnedMonitorInfo op(this, calling_thread, java_thread, owned_monitors_list); Handshake::execute_direct(&op, java_thread);
VMThread::execute(&op);
err = op.result(); err = op.result();
} }
jint owned_monitor_count = owned_monitors_list->length(); jint owned_monitor_count = owned_monitors_list->length();
@ -1246,21 +1244,19 @@ JvmtiEnv::GetOwnedMonitorInfo(JavaThread* java_thread, jint* owned_monitor_count
jvmtiError jvmtiError
JvmtiEnv::GetOwnedMonitorStackDepthInfo(JavaThread* java_thread, jint* monitor_info_count_ptr, jvmtiMonitorStackDepthInfo** monitor_info_ptr) { JvmtiEnv::GetOwnedMonitorStackDepthInfo(JavaThread* java_thread, jint* monitor_info_count_ptr, jvmtiMonitorStackDepthInfo** monitor_info_ptr) {
jvmtiError err = JVMTI_ERROR_NONE; jvmtiError err = JVMTI_ERROR_NONE;
JavaThread* calling_thread = JavaThread::current();
// growable array of jvmti monitors info on the C-heap // growable array of jvmti monitors info on the C-heap
GrowableArray<jvmtiMonitorStackDepthInfo*> *owned_monitors_list = GrowableArray<jvmtiMonitorStackDepthInfo*> *owned_monitors_list =
new (ResourceObj::C_HEAP, mtInternal) GrowableArray<jvmtiMonitorStackDepthInfo*>(1, true); new (ResourceObj::C_HEAP, mtInternal) GrowableArray<jvmtiMonitorStackDepthInfo*>(1, true);
// It is only safe to perform the direct operation on the current // It is only safe to perform the direct operation on the current
// thread. All other usage needs to use a vm-safepoint-op for safety. // thread. All other usage needs to use a direct handshake for safety.
if (java_thread == calling_thread) { if (java_thread == JavaThread::current()) {
err = get_owned_monitors(calling_thread, java_thread, owned_monitors_list); err = get_owned_monitors(java_thread, owned_monitors_list);
} else { } else {
// JVMTI get owned monitors info at safepoint. Do not require target thread to // get owned monitors info with handshake
// be suspended. GetOwnedMonitorInfoClosure op(this, owned_monitors_list);
VM_GetOwnedMonitorInfo op(this, calling_thread, java_thread, owned_monitors_list); Handshake::execute_direct(&op, java_thread);
VMThread::execute(&op);
err = op.result(); err = op.result();
} }
@ -1295,16 +1291,15 @@ JvmtiEnv::GetOwnedMonitorStackDepthInfo(JavaThread* java_thread, jint* monitor_i
jvmtiError jvmtiError
JvmtiEnv::GetCurrentContendedMonitor(JavaThread* java_thread, jobject* monitor_ptr) { JvmtiEnv::GetCurrentContendedMonitor(JavaThread* java_thread, jobject* monitor_ptr) {
jvmtiError err = JVMTI_ERROR_NONE; jvmtiError err = JVMTI_ERROR_NONE;
JavaThread* calling_thread = JavaThread::current();
// It is only safe to perform the direct operation on the current // It is only safe to perform the direct operation on the current
// thread. All other usage needs to use a vm-safepoint-op for safety. // thread. All other usage needs to use a direct handshake for safety.
if (java_thread == calling_thread) { if (java_thread == JavaThread::current()) {
err = get_current_contended_monitor(calling_thread, java_thread, monitor_ptr); err = get_current_contended_monitor(java_thread, monitor_ptr);
} else { } else {
// get contended monitor information at safepoint. // get contended monitor information with handshake
VM_GetCurrentContendedMonitor op(this, calling_thread, java_thread, monitor_ptr); GetCurrentContendedMonitorClosure op(this, monitor_ptr);
VMThread::execute(&op); Handshake::execute_direct(&op, java_thread);
err = op.result(); err = op.result();
} }
return err; return err;

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2003, 2020, 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
@ -647,13 +647,11 @@ JvmtiEnvBase::count_locked_objects(JavaThread *java_thread, Handle hobj) {
jvmtiError jvmtiError
JvmtiEnvBase::get_current_contended_monitor(JavaThread *calling_thread, JavaThread *java_thread, jobject *monitor_ptr) { JvmtiEnvBase::get_current_contended_monitor(JavaThread *java_thread, jobject *monitor_ptr) {
#ifdef ASSERT JavaThread *current_jt = JavaThread::current();
uint32_t debug_bits = 0; assert(current_jt == java_thread ||
#endif current_jt == java_thread->active_handshaker(),
assert((SafepointSynchronize::is_at_safepoint() || "call by myself or at direct handshake");
java_thread->is_thread_fully_suspended(false, &debug_bits)),
"at safepoint or target thread is suspended");
oop obj = NULL; oop obj = NULL;
ObjectMonitor *mon = java_thread->current_waiting_monitor(); ObjectMonitor *mon = java_thread->current_waiting_monitor();
if (mon == NULL) { if (mon == NULL) {
@ -675,23 +673,21 @@ JvmtiEnvBase::get_current_contended_monitor(JavaThread *calling_thread, JavaThre
*monitor_ptr = NULL; *monitor_ptr = NULL;
} else { } else {
HandleMark hm; HandleMark hm;
Handle hobj(Thread::current(), obj); Handle hobj(current_jt, obj);
*monitor_ptr = jni_reference(calling_thread, hobj); *monitor_ptr = jni_reference(current_jt, hobj);
} }
return JVMTI_ERROR_NONE; return JVMTI_ERROR_NONE;
} }
jvmtiError jvmtiError
JvmtiEnvBase::get_owned_monitors(JavaThread *calling_thread, JavaThread* java_thread, JvmtiEnvBase::get_owned_monitors(JavaThread* java_thread,
GrowableArray<jvmtiMonitorStackDepthInfo*> *owned_monitors_list) { GrowableArray<jvmtiMonitorStackDepthInfo*> *owned_monitors_list) {
jvmtiError err = JVMTI_ERROR_NONE; jvmtiError err = JVMTI_ERROR_NONE;
#ifdef ASSERT JavaThread *current_jt = JavaThread::current();
uint32_t debug_bits = 0; assert(current_jt == java_thread ||
#endif current_jt == java_thread->active_handshaker(),
assert((SafepointSynchronize::is_at_safepoint() || "call by myself or at direct handshake");
java_thread->is_thread_fully_suspended(false, &debug_bits)),
"at safepoint or target thread is suspended");
if (java_thread->has_last_Java_frame()) { if (java_thread->has_last_Java_frame()) {
ResourceMark rm; ResourceMark rm;
@ -703,7 +699,7 @@ JvmtiEnvBase::get_owned_monitors(JavaThread *calling_thread, JavaThread* java_th
jvf = jvf->java_sender()) { jvf = jvf->java_sender()) {
if (MaxJavaStackTraceDepth == 0 || depth++ < MaxJavaStackTraceDepth) { // check for stack too deep if (MaxJavaStackTraceDepth == 0 || depth++ < MaxJavaStackTraceDepth) { // check for stack too deep
// add locked objects for this frame into list // add locked objects for this frame into list
err = get_locked_objects_in_frame(calling_thread, java_thread, jvf, owned_monitors_list, depth-1); err = get_locked_objects_in_frame(current_jt, java_thread, jvf, owned_monitors_list, depth-1);
if (err != JVMTI_ERROR_NONE) { if (err != JVMTI_ERROR_NONE) {
return err; return err;
} }
@ -712,7 +708,7 @@ JvmtiEnvBase::get_owned_monitors(JavaThread *calling_thread, JavaThread* java_th
} }
// Get off stack monitors. (e.g. acquired via jni MonitorEnter). // Get off stack monitors. (e.g. acquired via jni MonitorEnter).
JvmtiMonitorClosure jmc(java_thread, calling_thread, owned_monitors_list, this); JvmtiMonitorClosure jmc(java_thread, current_jt, owned_monitors_list, this);
ObjectSynchronizer::monitors_iterate(&jmc); ObjectSynchronizer::monitors_iterate(&jmc);
err = jmc.error(); err = jmc.error();
@ -1542,24 +1538,13 @@ VM_SetFramePop::doit() {
} }
void void
VM_GetOwnedMonitorInfo::doit() { GetOwnedMonitorInfoClosure::do_thread(Thread *target) {
_result = JVMTI_ERROR_THREAD_NOT_ALIVE; _result = ((JvmtiEnvBase *)_env)->get_owned_monitors((JavaThread *)target, _owned_monitors_list);
ThreadsListHandle tlh;
if (_java_thread != NULL && tlh.includes(_java_thread)
&& !_java_thread->is_exiting() && _java_thread->threadObj() != NULL) {
_result = ((JvmtiEnvBase *)_env)->get_owned_monitors(_calling_thread, _java_thread,
_owned_monitors_list);
}
} }
void void
VM_GetCurrentContendedMonitor::doit() { GetCurrentContendedMonitorClosure::do_thread(Thread *target) {
_result = JVMTI_ERROR_THREAD_NOT_ALIVE; _result = ((JvmtiEnvBase *)_env)->get_current_contended_monitor((JavaThread *)target, _owned_monitor_ptr);
ThreadsListHandle tlh;
if (_java_thread != NULL && tlh.includes(_java_thread)
&& !_java_thread->is_exiting() && _java_thread->threadObj() != NULL) {
_result = ((JvmtiEnvBase *)_env)->get_current_contended_monitor(_calling_thread,_java_thread,_owned_monitor_ptr);
}
} }
void void

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2003, 2020, 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
@ -292,7 +292,8 @@ class JvmtiEnvBase : public CHeapObj<mtInternal> {
// get a field descriptor for the specified class and field // get a field descriptor for the specified class and field
static bool get_field_descriptor(Klass* k, jfieldID field, fieldDescriptor* fd); static bool get_field_descriptor(Klass* k, jfieldID field, fieldDescriptor* fd);
// JVMTI API helper functions which are called at safepoint or thread is suspended. // JVMTI API helper functions which are called when target thread is suspended
// or at safepoint / thread local handshake.
jvmtiError get_frame_count(JvmtiThreadState *state, jint *count_ptr); jvmtiError get_frame_count(JvmtiThreadState *state, jint *count_ptr);
jvmtiError get_frame_location(JavaThread* java_thread, jint depth, jvmtiError get_frame_location(JavaThread* java_thread, jint depth,
jmethodID* method_ptr, jlocation* location_ptr); jmethodID* method_ptr, jlocation* location_ptr);
@ -301,10 +302,9 @@ class JvmtiEnvBase : public CHeapObj<mtInternal> {
jvmtiError get_stack_trace(JavaThread *java_thread, jvmtiError get_stack_trace(JavaThread *java_thread,
jint stack_depth, jint max_count, jint stack_depth, jint max_count,
jvmtiFrameInfo* frame_buffer, jint* count_ptr); jvmtiFrameInfo* frame_buffer, jint* count_ptr);
jvmtiError get_current_contended_monitor(JavaThread *calling_thread, jvmtiError get_current_contended_monitor(JavaThread *java_thread,
JavaThread *java_thread,
jobject *monitor_ptr); jobject *monitor_ptr);
jvmtiError get_owned_monitors(JavaThread *calling_thread, JavaThread* java_thread, jvmtiError get_owned_monitors(JavaThread* java_thread,
GrowableArray<jvmtiMonitorStackDepthInfo*> *owned_monitors_list); GrowableArray<jvmtiMonitorStackDepthInfo*> *owned_monitors_list);
jvmtiError check_top_frame(JavaThread* current_thread, JavaThread* java_thread, jvmtiError check_top_frame(JavaThread* current_thread, JavaThread* java_thread,
jvalue value, TosState tos, Handle* ret_ob_h); jvalue value, TosState tos, Handle* ret_ob_h);
@ -376,27 +376,21 @@ public:
}; };
// VM operation to get monitor information with stack depth. // HandshakeClosure to get monitor information with stack depth.
class VM_GetOwnedMonitorInfo : public VM_Operation { class GetOwnedMonitorInfoClosure : public HandshakeClosure {
private: private:
JvmtiEnv *_env; JvmtiEnv *_env;
JavaThread* _calling_thread;
JavaThread *_java_thread;
jvmtiError _result; jvmtiError _result;
GrowableArray<jvmtiMonitorStackDepthInfo*> *_owned_monitors_list; GrowableArray<jvmtiMonitorStackDepthInfo*> *_owned_monitors_list;
public: public:
VM_GetOwnedMonitorInfo(JvmtiEnv* env, JavaThread* calling_thread, GetOwnedMonitorInfoClosure(JvmtiEnv* env,
JavaThread* java_thread, GrowableArray<jvmtiMonitorStackDepthInfo*>* owned_monitor_list)
GrowableArray<jvmtiMonitorStackDepthInfo*>* owned_monitor_list) { : HandshakeClosure("GetOwnedMonitorInfo"),
_env = env; _env(env),
_calling_thread = calling_thread; _result(JVMTI_ERROR_NONE),
_java_thread = java_thread; _owned_monitors_list(owned_monitor_list) {}
_owned_monitors_list = owned_monitor_list; void do_thread(Thread *target);
_result = JVMTI_ERROR_NONE;
}
VMOp_Type type() const { return VMOp_GetOwnedMonitorInfo; }
void doit();
jvmtiError result() { return _result; } jvmtiError result() { return _result; }
}; };
@ -425,25 +419,21 @@ public:
}; };
// VM operation to get current contended monitor. // HandshakeClosure to get current contended monitor.
class VM_GetCurrentContendedMonitor : public VM_Operation { class GetCurrentContendedMonitorClosure : public HandshakeClosure {
private: private:
JvmtiEnv *_env; JvmtiEnv *_env;
JavaThread *_calling_thread;
JavaThread *_java_thread;
jobject *_owned_monitor_ptr; jobject *_owned_monitor_ptr;
jvmtiError _result; jvmtiError _result;
public: public:
VM_GetCurrentContendedMonitor(JvmtiEnv *env, JavaThread *calling_thread, JavaThread *java_thread, jobject *mon_ptr) { GetCurrentContendedMonitorClosure(JvmtiEnv *env, jobject *mon_ptr)
_env = env; : HandshakeClosure("GetCurrentContendedMonitor"),
_calling_thread = calling_thread; _env(env),
_java_thread = java_thread; _owned_monitor_ptr(mon_ptr),
_owned_monitor_ptr = mon_ptr; _result(JVMTI_ERROR_THREAD_NOT_ALIVE) {}
}
VMOp_Type type() const { return VMOp_GetCurrentContendedMonitor; }
jvmtiError result() { return _result; } jvmtiError result() { return _result; }
void doit(); void do_thread(Thread *target);
}; };
// VM operation to get stack trace at safepoint. // VM operation to get stack trace at safepoint.

View file

@ -80,9 +80,7 @@
template(RedefineClasses) \ template(RedefineClasses) \
template(UpdateForPopTopFrame) \ template(UpdateForPopTopFrame) \
template(SetFramePop) \ template(SetFramePop) \
template(GetOwnedMonitorInfo) \
template(GetObjectMonitorUsage) \ template(GetObjectMonitorUsage) \
template(GetCurrentContendedMonitor) \
template(GetStackTrace) \ template(GetStackTrace) \
template(GetMultipleStackTraces) \ template(GetMultipleStackTraces) \
template(GetAllStackTraces) \ template(GetAllStackTraces) \