< prev index next >

src/hotspot/share/prims/jvmtiEnvBase.cpp

Print this page
@@ -650,17 +650,23 @@
    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");

@@ -719,11 +725,11 @@
      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.

@@ -1021,40 +1027,41 @@
  
    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);
  

@@ -1067,24 +1074,40 @@
    {
      // 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);

@@ -1531,13 +1554,17 @@
      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;

@@ -1581,19 +1608,23 @@
      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);
        }
      }

@@ -2507,22 +2538,22 @@
    }
  }
  
  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) {

@@ -2536,10 +2567,17 @@
  }
  
  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 >