< prev index next >

src/hotspot/share/prims/jvmtiEnvBase.cpp

Print this page
*** 783,10 ***
--- 783,11 ---
  }
  
  jint
  JvmtiEnvBase::get_vthread_state(oop thread_oop, JavaThread* java_thread) {
    jint state = 0;
+   bool is_mon_responsible = java_lang_VirtualThread::recheckInterval(thread_oop) > 0;
    bool ext_suspended = JvmtiVTSuspender::is_vthread_suspended(thread_oop);
    jint interrupted = java_lang_Thread::interrupted(thread_oop);
  
    if (java_thread != nullptr) {
      // If virtual thread is blocked on a monitor enter the BLOCKED_ON_MONITOR_ENTER bit

*** 795,10 ***
--- 796,12 ---
      oop ct_oop = java_lang_VirtualThread::carrier_thread(thread_oop);
      jint filtered_bits = JVMTI_THREAD_STATE_SUSPENDED | JVMTI_THREAD_STATE_INTERRUPTED;
  
      // This call can trigger a safepoint, so thread_oop must not be used after it.
      state = get_thread_state_base(ct_oop, java_thread) & ~filtered_bits;
+   } else if (is_mon_responsible) {
+     state = (jint) JavaThreadStatus::BLOCKED_ON_MONITOR_ENTER;
    } else {
      int vt_state = java_lang_VirtualThread::state(thread_oop);
      state = (jint)java_lang_VirtualThread::map_state_to_thread_status(vt_state);
    }
    // Ensure the thread has not exited after retrieving suspended/interrupted values.

*** 1012,40 ***
  
    return err;
  }
  
  jvmtiError
! JvmtiEnvBase::get_owned_monitors(JavaThread* calling_thread, JavaThread* java_thread, javaVFrame* jvf,
!                                  GrowableArray<jvmtiMonitorStackDepthInfo*> *owned_monitors_list) {
    jvmtiError err = JVMTI_ERROR_NONE;
    Thread *current_thread = Thread::current();
!   assert(java_thread->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);
        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);
    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) {
    jvmtiError err = JVMTI_ERROR_NONE;
    Thread* current_thread = Thread::current();
    ResourceMark rm(current_thread);
    HandleMark   hm(current_thread);
  
--- 1015,47 ---
  
    return err;
  }
  
  jvmtiError
! 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(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, carrier, jvf, owned_monitors_list, depth - 1, vthread);
        if (err != JVMTI_ERROR_NONE) {
          return err;
        }
      }
    }
  
+   if (carrier == nullptr) {
+     // vthread gets pinned if monitors are acquired via jni MonitorEnter
+     // so nothing else to do for unmounted case.
+     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, carrier);
    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* 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);
  

*** 1058,24 ***
    {
      // 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();
      }
    }
    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();
      }
    }
  
    for (int i = 0; i < mons->length(); i++) {
      MonitorInfo *mi = mons->at(i);
--- 1068,32 ---
    {
      // 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.
!     if (target != nullptr) {
!       ObjectMonitor *mon = target->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.
!     if (target != nullptr) {
!       ObjectMonitor *mon = target->current_pending_monitor();
!       if (mon != nullptr) pending_obj = mon->object();
+     } else {
+       assert(vthread != nullptr, "no vthread oop");
+       oop oopCont = java_lang_VirtualThread::continuation(vthread);
+       assert(oopCont != nullptr, "vthread with no continuation");
+       stackChunkOop chunk = jdk_internal_vm_Continuation::tail(oopCont);
+       assert(chunk != nullptr, "unmounted vthread should have a chunk");
+       ObjectMonitor *mon = chunk->objectMonitor();
+       if (mon != nullptr) pending_obj = mon->object();
      }
    }
  
    for (int i = 0; i < mons->length(); i++) {
      MonitorInfo *mi = mons->at(i);

*** 2483,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) {
      _result = ((JvmtiEnvBase *)_env)->get_owned_monitors(_calling_thread,
                                                           _target_jt,
                                                           jvf,
!                                                          _owned_monitors_list);
    }
  }
  
  void
  GetCurrentContendedMonitorClosure::do_thread(Thread *target) {
--- 2501,22 ---
    }
  }
  
  void
  GetOwnedMonitorInfoClosure::do_vthread(Handle target_h) {
    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 == nullptr || (!_target_jt->is_exiting() && _target_jt->threadObj() != nullptr)) {
      _result = ((JvmtiEnvBase *)_env)->get_owned_monitors(_calling_thread,
                                                           _target_jt,
                                                           jvf,
!                                                          _owned_monitors_list,
+                                                          target_h());
    }
  }
  
  void
  GetCurrentContendedMonitorClosure::do_thread(Thread *target) {

*** 2512,10 ***
--- 2530,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->objectMonitor() != nullptr) {
+       *_owned_monitor_ptr = JNIHandles::make_local(_calling_thread, chunk->objectMonitor()->object());
+     }
      _result = JVMTI_ERROR_NONE; // target virtual thread is unmounted
      return;
    }
    // mounted virtual thread case
    do_thread(_target_jt);

*** 2625,10 ***
--- 2650,11 ---
    _result = ((JvmtiEnvBase*)_env)->get_frame_location(target_h(), _depth,
                                                        _method_ptr, _location_ptr);
  }
  
  void
+ 
  VirtualThreadGetThreadClosure::do_thread(Thread *target) {
    assert(target->is_Java_thread(), "just checking");
    JavaThread *jt = JavaThread::cast(target);
    oop carrier_thread = java_lang_VirtualThread::carrier_thread(_vthread_h());
    *_carrier_thread_ptr = (jthread)JNIHandles::make_local(jt, carrier_thread);
< prev index next >