< prev index next > src/hotspot/share/prims/jvmtiEnvBase.cpp
Print this page
assert(Continuation::continuation_scope(cont) == java_lang_VirtualThread::vthread_scope(), "must be");
return Continuation::is_continuation_mounted(java_thread, cont) ? java_thread : nullptr;
}
// An unmounted vthread may have an empty stack.
- // Otherwise, it always has the yield0() and yield() frames we need to hide.
- // The methods yield0() and yield() are annotated with the @JvmtiHideEvents.
+ // If unmounted from Java, it always has the yield0() and yield() frames we
+ // need to hide. The methods yield0() and yield() are annotated with the @JvmtiHideEvents.
javaVFrame*
- JvmtiEnvBase::skip_yield_frames_for_unmounted_vthread(javaVFrame* jvf) {
+ JvmtiEnvBase::skip_yield_frames_for_unmounted_vthread(oop vthread, javaVFrame* jvf) {
if (jvf == nullptr) {
return jvf; // empty stack is possible
}
+ if (java_lang_VirtualThread::is_preempted(vthread)) {
+ // Top method should not be from Continuation class.
+ assert(jvf->method()->method_holder() != vmClasses::Continuation_klass(), "");
+ return jvf;
+ }
+
assert(jvf->method()->jvmti_hide_events(), "sanity check");
assert(jvf->method()->method_holder() == vmClasses::Continuation_klass(), "expected Continuation class");
jvf = jvf->java_sender(); // skip yield0 frame
assert(jvf != nullptr && jvf->method()->jvmti_hide_events(), "sanity check");
jvf = vfs.at_end() ? nullptr : vfs.asJavaVFrame();
jvf = check_and_skip_hidden_frames(false, jvf);
} else {
vframeStream vfs(cont);
jvf = vfs.at_end() ? nullptr : vfs.asJavaVFrame();
- jvf = skip_yield_frames_for_unmounted_vthread(jvf);
+ jvf = skip_yield_frames_for_unmounted_vthread(vthread, jvf);
}
return jvf;
}
// Return correct javaVFrame for a carrier (non-virtual) thread.
return err;
}
jvmtiError
- JvmtiEnvBase::get_owned_monitors(JavaThread* calling_thread, JavaThread* java_thread, javaVFrame* jvf,
- GrowableArray<jvmtiMonitorStackDepthInfo*> *owned_monitors_list) {
+ JvmtiEnvBase::get_owned_monitors(JavaThread* calling_thread, JavaThread* carrier, javaVFrame* jvf,
+ GrowableArray<jvmtiMonitorStackDepthInfo*> *owned_monitors_list, oop vthread) {
jvmtiError err = JVMTI_ERROR_NONE;
Thread *current_thread = Thread::current();
- assert(java_thread->is_handshake_safe_for(current_thread),
+ assert(carrier == nullptr || carrier->is_handshake_safe_for(current_thread),
"call by myself or at handshake");
int depth = 0;
for ( ; jvf != nullptr; jvf = jvf->java_sender()) {
if (MaxJavaStackTraceDepth == 0 || depth++ < MaxJavaStackTraceDepth) { // check for stack too deep
// 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(calling_thread, carrier, jvf, owned_monitors_list, depth - 1, vthread);
if (err != JVMTI_ERROR_NONE) {
return err;
}
}
}
// Get off stack monitors. (e.g. acquired via jni MonitorEnter).
JvmtiMonitorClosure jmc(calling_thread, owned_monitors_list, this);
- ObjectSynchronizer::owned_monitors_iterate(&jmc, java_thread);
+ ObjectSynchronizer::owned_monitors_iterate(&jmc, carrier != nullptr ? carrier->threadObj() : vthread);
err = jmc.error();
return err;
}
// Save JNI local handles for any objects that this frame owns.
jvmtiError
- JvmtiEnvBase::get_locked_objects_in_frame(JavaThread* calling_thread, JavaThread* java_thread,
- javaVFrame *jvf, GrowableArray<jvmtiMonitorStackDepthInfo*>* owned_monitors_list, jint stack_depth) {
+ JvmtiEnvBase::get_locked_objects_in_frame(JavaThread* calling_thread, JavaThread* target,
+ javaVFrame *jvf, GrowableArray<jvmtiMonitorStackDepthInfo*>* owned_monitors_list,
+ jint stack_depth, oop vthread) {
jvmtiError err = JVMTI_ERROR_NONE;
Thread* current_thread = Thread::current();
ResourceMark rm(current_thread);
HandleMark hm(current_thread);
{
// The ObjectMonitor* can't be async deflated since we are either
// at a safepoint or the calling thread is operating on itself so
// it cannot leave the underlying wait() call.
// Save object of current wait() call (if any) for later comparison.
- ObjectMonitor *mon = java_thread->current_waiting_monitor();
- if (mon != nullptr) {
- wait_obj = mon->object();
+ if (target != nullptr) {
+ ObjectMonitor *mon = target->current_waiting_monitor();
+ if (mon != nullptr) wait_obj = mon->object();
+ } else {
+ assert(vthread != nullptr, "no vthread oop");
+ oop cont = java_lang_VirtualThread::continuation(vthread);
+ assert(cont != nullptr, "vthread with no continuation");
+ stackChunkOop chunk = jdk_internal_vm_Continuation::tail(cont);
+ assert(chunk != nullptr, "unmounted vthread should have a chunk");
+ ObjectMonitor *mon = chunk->current_waiting_monitor();
+ if (mon != nullptr) wait_obj = mon->object();
}
}
oop pending_obj = nullptr;
{
// The ObjectMonitor* can't be async deflated since we are either
// at a safepoint or the calling thread is operating on itself so
// it cannot leave the underlying enter() call.
// Save object of current enter() call (if any) for later comparison.
- ObjectMonitor *mon = java_thread->current_pending_monitor();
- if (mon != nullptr) {
- pending_obj = mon->object();
+ if (target != nullptr) {
+ ObjectMonitor *mon = target->current_pending_monitor();
+ if (mon != nullptr) pending_obj = mon->object();
+ } else {
+ assert(vthread != nullptr, "no vthread oop");
+ oop cont = java_lang_VirtualThread::continuation(vthread);
+ assert(cont != nullptr, "vthread with no continuation");
+ stackChunkOop chunk = jdk_internal_vm_Continuation::tail(cont);
+ assert(chunk != nullptr, "unmounted vthread should have a chunk");
+ ObjectMonitor *mon = chunk->current_pending_monitor();
+ if (mon != nullptr) pending_obj = mon->object();
}
}
for (int i = 0; i < mons->length(); i++) {
MonitorInfo *mi = mons->at(i);
nWait = 0;
for (ObjectWaiter* waiter = mon->first_waiter();
waiter != nullptr && (nWait == 0 || waiter != mon->first_waiter());
waiter = mon->next_waiter(waiter)) {
JavaThread *w = mon->thread_of_waiter(waiter);
- oop thread_oop = get_vthread_or_thread_oop(w);
- if (thread_oop->is_a(vmClasses::BaseVirtualThread_klass())) {
+ if (w == nullptr) {
skipped++;
+ } else {
+ oop thread_oop = get_vthread_or_thread_oop(w);
+ if (thread_oop->is_a(vmClasses::BaseVirtualThread_klass())) {
+ skipped++;
+ }
}
nWait++;
}
}
ret.waiter_count = nWant;
if (ret.notify_waiter_count > 0) { // we have threads waiting to be notified in Object.wait()
ObjectWaiter *waiter = mon->first_waiter();
jint skipped = 0;
for (int i = 0; i < nWait; i++) {
JavaThread *w = mon->thread_of_waiter(waiter);
- oop thread_oop = get_vthread_or_thread_oop(w);
- bool is_virtual = thread_oop->is_a(vmClasses::BaseVirtualThread_klass());
- assert(w != nullptr, "sanity check");
+ bool is_virtual;
+ if (w == nullptr) {
+ is_virtual = true;
+ } else {
+ oop thread_oop = get_vthread_or_thread_oop(w);
+ is_virtual = thread_oop->is_a(vmClasses::BaseVirtualThread_klass());
+ }
if (is_virtual) {
skipped++;
} else {
// If the thread was found on the ObjectWaiter list, then
// it has not been notified.
- Handle th(current_thread, get_vthread_or_thread_oop(w));
+ Handle th(current_thread, w->threadObj());
ret.notify_waiters[i - skipped] = (jthread)jni_reference(calling_thread, th);
}
waiter = mon->next_waiter(waiter);
}
}
}
}
void
GetOwnedMonitorInfoClosure::do_vthread(Handle target_h) {
- assert(_target_jt != nullptr, "sanity check");
Thread* current = Thread::current();
ResourceMark rm(current); // vframes are resource allocated
HandleMark hm(current);
javaVFrame *jvf = JvmtiEnvBase::get_vthread_jvf(target_h());
- if (!_target_jt->is_exiting() && _target_jt->threadObj() != nullptr) {
+ if (_target_jt == nullptr || (!_target_jt->is_exiting() && _target_jt->threadObj() != nullptr)) {
_result = ((JvmtiEnvBase *)_env)->get_owned_monitors(_calling_thread,
_target_jt,
jvf,
- _owned_monitors_list);
+ _owned_monitors_list,
+ target_h());
}
}
void
GetCurrentContendedMonitorClosure::do_thread(Thread *target) {
}
void
GetCurrentContendedMonitorClosure::do_vthread(Handle target_h) {
if (_target_jt == nullptr) {
+ oop cont = java_lang_VirtualThread::continuation(target_h());
+ assert(cont != nullptr, "vthread with no continuation");
+ stackChunkOop chunk = jdk_internal_vm_Continuation::tail(cont);
+ assert(chunk != nullptr, "unmounted vthread should have a chunk");
+ if (chunk->current_pending_monitor() != nullptr) {
+ *_owned_monitor_ptr = JNIHandles::make_local(_calling_thread, chunk->current_pending_monitor()->object());
+ }
_result = JVMTI_ERROR_NONE; // target virtual thread is unmounted
return;
}
// mounted virtual thread case
do_thread(_target_jt);
< prev index next >