< prev index next >

src/hotspot/share/prims/jvmtiEnv.cpp

Print this page
@@ -64,10 +64,11 @@
  #include "runtime/interfaceSupport.inline.hpp"
  #include "runtime/javaCalls.hpp"
  #include "runtime/jfieldIDWorkaround.hpp"
  #include "runtime/jniHandles.inline.hpp"
  #include "runtime/objectMonitor.inline.hpp"
+ #include "runtime/os.hpp"
  #include "runtime/osThread.hpp"
  #include "runtime/reflectionUtils.hpp"
  #include "runtime/signature.hpp"
  #include "runtime/thread.inline.hpp"
  #include "runtime/threadHeapSampler.hpp"

@@ -138,32 +139,50 @@
  jvmtiError
  JvmtiEnv::Deallocate(unsigned char* mem) {
    return deallocate(mem);
  } /* end Deallocate */
  
- // java_thread - protected by ThreadsListHandle and pre-checked
+ // Threads_lock NOT held
  // data - NULL is a valid value, must be checked
  jvmtiError
- JvmtiEnv::SetThreadLocalStorage(JavaThread* java_thread, const void* data) {
-   JvmtiThreadState* state = java_thread->jvmti_thread_state();
+ JvmtiEnv::SetThreadLocalStorage(jthread thread, const void* data) {
+   jvmtiError err = JVMTI_ERROR_NONE;
+   JavaThread* java_thread = NULL;
+   JvmtiThreadState* state = NULL;
+   JvmtiVTMTDisabler vtmt_disabler;
+   oop thread_obj = NULL;
+   JavaThread* current = JavaThread::current();
+ 
+   if (thread == NULL) {
+     java_thread = current;
+     state = java_thread->jvmti_thread_state();
+   } else {
+     ThreadsListHandle tlh;
+     err = get_threadOop_and_JavaThread(tlh.list(), thread, &java_thread, &thread_obj);
+     if (err != JVMTI_ERROR_NONE) {
+       return err;
+     }
+     state = java_lang_Thread::jvmti_thread_state(thread_obj);
+   }
    if (state == NULL) {
      if (data == NULL) {
        // leaving state unset same as data set to NULL
        return JVMTI_ERROR_NONE;
      }
      // otherwise, create the state
-     state = JvmtiThreadState::state_for(java_thread);
+     HandleMark hm(current);
+     Handle thread_handle(current, thread_obj);
+     state = JvmtiThreadState::state_for(java_thread, thread_handle);
      if (state == NULL) {
        return JVMTI_ERROR_THREAD_NOT_ALIVE;
      }
    }
    state->env_thread_state(this)->set_agent_thread_local_storage_data((void*)data);
    return JVMTI_ERROR_NONE;
  } /* end SetThreadLocalStorage */
  
  
- // thread - NOT protected by ThreadsListHandle and NOT pre-checked
  // data_ptr - pre-checked for NULL
  jvmtiError
  JvmtiEnv::GetThreadLocalStorage(jthread thread, void** data_ptr) {
    JavaThread* current_thread = JavaThread::current();
    if (thread == NULL) {

@@ -180,17 +199,22 @@
      ThreadInVMfromNative __tiv(current_thread);
      VM_ENTRY_BASE(jvmtiError, JvmtiEnv::GetThreadLocalStorage , current_thread)
      debug_only(VMNativeEntryWrapper __vew;)
  
      JavaThread* java_thread = NULL;
+     oop thread_obj = NULL;
+     JvmtiVTMTDisabler vtmt_disabler;
      ThreadsListHandle tlh(current_thread);
-     jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, NULL);
+ 
+     jvmtiError err = get_threadOop_and_JavaThread(tlh.list(), thread, &java_thread, &thread_obj);
      if (err != JVMTI_ERROR_NONE) {
        return err;
      }
  
-     JvmtiThreadState* state = java_thread->jvmti_thread_state();
+     HandleMark hm(current_thread);
+     Handle thread_handle(current_thread, thread_obj);
+     JvmtiThreadState* state = JvmtiThreadState::state_for(java_thread, thread_handle);
      *data_ptr = (state == NULL) ? NULL :
        state->env_thread_state(this)->get_agent_thread_local_storage_data();
    }
    return JVMTI_ERROR_NONE;
  } /* end GetThreadLocalStorage */

@@ -214,10 +238,11 @@
  // module_ptr - pre-checked for NULL
  jvmtiError
  JvmtiEnv::GetNamedModule(jobject class_loader, const char* package_name, jobject* module_ptr) {
    JavaThread* THREAD = JavaThread::current(); // For exception macros.
    ResourceMark rm(THREAD);
+ 
    Handle h_loader (THREAD, JNIHandles::resolve(class_loader));
    // Check that loader is a subclass of java.lang.ClassLoader.
    if (h_loader.not_null() && !java_lang_ClassLoader::is_subclass(h_loader->klass())) {
      return JVMTI_ERROR_ILLEGAL_ARGUMENT;
    }

@@ -530,63 +555,51 @@
  
  
  // event_thread - NULL is a valid value, must be checked
  jvmtiError
  JvmtiEnv::SetEventNotificationMode(jvmtiEventMode mode, jvmtiEvent event_type, jthread event_thread,   ...) {
+   bool enabled = (mode == JVMTI_ENABLE);
+ 
+   // event_type must be valid
+   if (!JvmtiEventController::is_valid_event_type(event_type)) {
+     return JVMTI_ERROR_INVALID_EVENT_TYPE;
+   }
+ 
+   // assure that needed capabilities are present
+   if (enabled && !JvmtiUtil::has_event_capability(event_type, get_capabilities())) {
+     return JVMTI_ERROR_MUST_POSSESS_CAPABILITY;
+   }
+ 
+   if (event_type == JVMTI_EVENT_CLASS_FILE_LOAD_HOOK && enabled) {
+     record_class_file_load_hook_enabled();
+   }
+ 
    if (event_thread == NULL) {
      // Can be called at Agent_OnLoad() time with event_thread == NULL
      // when Thread::current() does not work yet so we cannot create a
      // ThreadsListHandle that is common to both thread-specific and
      // global code paths.
  
-     // event_type must be valid
-     if (!JvmtiEventController::is_valid_event_type(event_type)) {
-       return JVMTI_ERROR_INVALID_EVENT_TYPE;
-     }
- 
-     bool enabled = (mode == JVMTI_ENABLE);
- 
-     // assure that needed capabilities are present
-     if (enabled && !JvmtiUtil::has_event_capability(event_type, get_capabilities())) {
-       return JVMTI_ERROR_MUST_POSSESS_CAPABILITY;
-     }
- 
-     if (event_type == JVMTI_EVENT_CLASS_FILE_LOAD_HOOK && enabled) {
-       record_class_file_load_hook_enabled();
-     }
- 
-     JvmtiEventController::set_user_enabled(this, (JavaThread*) NULL, event_type, enabled);
+     JvmtiEventController::set_user_enabled(this, (JavaThread*) NULL, (oop) NULL, event_type, enabled);
    } else {
      // We have a specified event_thread.
      JavaThread* java_thread = NULL;
+     oop thread_obj = NULL;
+     JvmtiVTMTDisabler vtmt_disabler;
      ThreadsListHandle tlh;
-     jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), event_thread, &java_thread, NULL);
+ 
+     jvmtiError err = get_threadOop_and_JavaThread(tlh.list(), event_thread, &java_thread, &thread_obj);
      if (err != JVMTI_ERROR_NONE) {
        return err;
      }
  
-     // event_type must be valid
-     if (!JvmtiEventController::is_valid_event_type(event_type)) {
-       return JVMTI_ERROR_INVALID_EVENT_TYPE;
-     }
- 
      // global events cannot be controlled at thread level.
      if (JvmtiEventController::is_global_event(event_type)) {
        return JVMTI_ERROR_ILLEGAL_ARGUMENT;
      }
  
-     bool enabled = (mode == JVMTI_ENABLE);
- 
-     // assure that needed capabilities are present
-     if (enabled && !JvmtiUtil::has_event_capability(event_type, get_capabilities())) {
-       return JVMTI_ERROR_MUST_POSSESS_CAPABILITY;
-     }
- 
-     if (event_type == JVMTI_EVENT_CLASS_FILE_LOAD_HOOK && enabled) {
-       record_class_file_load_hook_enabled();
-     }
-     JvmtiEventController::set_user_enabled(this, java_thread, event_type, enabled);
+     JvmtiEventController::set_user_enabled(this, java_thread, thread_obj, event_type, enabled);
    }
  
    return JVMTI_ERROR_NONE;
  } /* end SetEventNotificationMode */
  

@@ -835,67 +848,61 @@
  
    //
    // Thread functions
    //
  
- // thread - NOT protected by ThreadsListHandle and NOT pre-checked
  // thread_state_ptr - pre-checked for NULL
  jvmtiError
  JvmtiEnv::GetThreadState(jthread thread, jint* thread_state_ptr) {
    JavaThread* current_thread = JavaThread::current();
    JavaThread* java_thread = NULL;
    oop thread_oop = NULL;
+   JvmtiVTMTDisabler vtmt_disabler;
    ThreadsListHandle tlh(current_thread);
  
    if (thread == NULL) {
      java_thread = current_thread;
-     thread_oop = java_thread->threadObj();
+     thread_oop = get_vthread_or_thread_oop(java_thread);
  
      if (thread_oop == NULL || !thread_oop->is_a(vmClasses::Thread_klass())) {
        return JVMTI_ERROR_INVALID_THREAD;
      }
    } else {
      jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, &thread_oop);
      if (err != JVMTI_ERROR_NONE) {
        // We got an error code so we don't have a JavaThread *, but
        // only return an error from here if we didn't get a valid
        // thread_oop.
+       // In a vthread case the cv_external_thread_to_JavaThread is expected to correctly set
+       // the thread_oop and return JVMTI_ERROR_INVALID_THREAD which we ignore here.
        if (thread_oop == NULL) {
          return err;
        }
        // We have a valid thread_oop so we can return some thread state.
      }
    }
  
-   // get most state bits
-   jint state = (jint)java_lang_Thread::get_thread_status(thread_oop);
- 
-   if (java_thread != NULL) {
-     // We have a JavaThread* so add more state bits.
-     JavaThreadState jts = java_thread->thread_state();
- 
-     if (java_thread->is_suspended()) {
-       state |= JVMTI_THREAD_STATE_SUSPENDED;
-     }
-     if (jts == _thread_in_native) {
-       state |= JVMTI_THREAD_STATE_IN_NATIVE;
-     }
-     if (java_thread->is_interrupted(false)) {
-       state |= JVMTI_THREAD_STATE_INTERRUPTED;
-     }
+   // Support for virtual thread
+   if (java_lang_VirtualThread::is_instance(thread_oop)) {
+     *thread_state_ptr = JvmtiEnvBase::get_vthread_state(thread_oop);
+   } else {
+     *thread_state_ptr = JvmtiEnvBase::get_thread_state(thread_oop, java_thread);
    }
- 
-   *thread_state_ptr = state;
+   // java_thread can be suspended only if its virtual or carrier thread object is suspended.
+   assert(java_thread == NULL || !java_thread->is_suspended() ||
+          (*thread_state_ptr | JVMTI_THREAD_STATE_SUSPENDED) != 0, "sanity check");
    return JVMTI_ERROR_NONE;
  } /* end GetThreadState */
  
  
  // thread_ptr - pre-checked for NULL
  jvmtiError
  JvmtiEnv::GetCurrentThread(jthread* thread_ptr) {
-   JavaThread* current_thread  = JavaThread::current();
-   *thread_ptr = (jthread)JNIHandles::make_local(current_thread, current_thread->threadObj());
+   JavaThread* cur_thread = JavaThread::current();
+   oop thread_oop = get_vthread_or_thread_oop(cur_thread);
+ 
+   *thread_ptr = (jthread)JNIHandles::make_local(cur_thread, thread_oop);
    return JVMTI_ERROR_NONE;
  } /* end GetCurrentThread */
  
  
  // threads_count_ptr - pre-checked for NULL

@@ -931,141 +938,213 @@
    *threads_ptr = jthreads;
    return JVMTI_ERROR_NONE;
  } /* end GetAllThreads */
  
  
- // java_thread - protected by ThreadsListHandle and pre-checked
  jvmtiError
- JvmtiEnv::SuspendThread(JavaThread* java_thread) {
-   // don't allow hidden thread suspend request.
-   if (java_thread->is_hidden_from_external_view()) {
-     return JVMTI_ERROR_NONE;
-   }
-   if (java_thread->is_suspended()) {
-     return JVMTI_ERROR_THREAD_SUSPENDED;
+ JvmtiEnv::SuspendThread(jthread thread) {
+   JavaThread* java_thread = NULL;
+   oop thread_oop = NULL;
+   JvmtiVTMTDisabler vtmt_disabler;
+   ThreadsListHandle tlh;
+ 
+   jvmtiError err = get_threadOop_and_JavaThread(tlh.list(), thread, &java_thread, &thread_oop);
+   if (err != JVMTI_ERROR_NONE) {
+     return err;
    }
-   if (!JvmtiSuspendControl::suspend(java_thread)) {
-     // Either the thread is already suspended or
-     // it was in the process of exiting.
-     if (java_thread->is_exiting()) {
-       return JVMTI_ERROR_THREAD_NOT_ALIVE;
-     }
-     return JVMTI_ERROR_THREAD_SUSPENDED;
+   if (java_thread != NULL && java_thread == JavaThread::current()) {
+     // current thread will be suspended in the ~JvmtiVTMTDisabler
+     vtmt_disabler.set_self_suspend();
    }
-   return JVMTI_ERROR_NONE;
+   err = suspend_thread(thread_oop,
+                        java_thread,
+                        true,  // single suspend
+                        NULL); // no need for extra safepoint
+   return err;
  } /* end SuspendThread */
  
  
  // request_count - pre-checked to be greater than or equal to 0
  // request_list - pre-checked for NULL
  // results - pre-checked for NULL
  jvmtiError
  JvmtiEnv::SuspendThreadList(jint request_count, const jthread* request_list, jvmtiError* results) {
-   int self_index = -1;
-   int needSafepoint = 0;  // > 0 if we need a safepoint
+   oop thread_oop = NULL;
+   JavaThread *java_thread = NULL;
    JavaThread* current = JavaThread::current();
+ 
+   JvmtiVTMTDisabler vtmt_disabler;
    ThreadsListHandle tlh(current);
+ 
    for (int i = 0; i < request_count; i++) {
-     JavaThread *java_thread = NULL;
-     jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), request_list[i], &java_thread, NULL);
+     jthread thread = request_list[i];
+     jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, &thread_oop);
      if (err != JVMTI_ERROR_NONE) {
-       results[i] = err;
-       continue;
-     }
-     // don't allow hidden thread suspend request.
-     if (java_thread->is_hidden_from_external_view()) {
-       results[i] = JVMTI_ERROR_NONE;  // indicate successful suspend
-       continue;
-     }
-     if (java_thread->is_suspended()) {
-       results[i] = JVMTI_ERROR_THREAD_SUSPENDED;
-       continue;
-     }
-     if (java_thread == current) {
-       self_index = i;
-       continue;
-     }
-     if (!JvmtiSuspendControl::suspend(java_thread)) {
-       // Either the thread is already suspended or
-       // it was in the process of exiting.
-       if (java_thread->is_exiting()) {
-         results[i] = JVMTI_ERROR_THREAD_NOT_ALIVE;
+       if (thread_oop == NULL || err != JVMTI_ERROR_INVALID_THREAD) {
+         results[i] = err;
          continue;
        }
-       results[i] = JVMTI_ERROR_THREAD_SUSPENDED;
-       continue;
      }
-     results[i] = JVMTI_ERROR_NONE;  // indicate successful suspend
-   }
-   if (self_index >= 0) {
-     if (!JvmtiSuspendControl::suspend(current)) {
-       // Either the thread is already suspended or
-       // it was in the process of exiting.
-       if (current->is_exiting()) {
-         results[self_index] = JVMTI_ERROR_THREAD_NOT_ALIVE;
-       } else {
-         results[self_index] = JVMTI_ERROR_THREAD_SUSPENDED;
-       }
-     } else {
-       results[self_index] = JVMTI_ERROR_NONE;  // indicate successful suspend
+     if (java_thread == current) {
+       // current thread will be suspended in the ~JvmtiVTMTDisabler
+       vtmt_disabler.set_self_suspend();
      }
+     results[i] = suspend_thread(thread_oop,
+                                 java_thread,
+                                 true, // single suspend
+                                 NULL);
    }
    // per-thread suspend results returned via results parameter
    return JVMTI_ERROR_NONE;
  } /* end SuspendThreadList */
  
  
- // java_thread - protected by ThreadsListHandle and pre-checked
  jvmtiError
- JvmtiEnv::ResumeThread(JavaThread* java_thread) {
-   // don't allow hidden thread resume request.
-   if (java_thread->is_hidden_from_external_view()) {
-     return JVMTI_ERROR_NONE;
+ JvmtiEnv::SuspendAllVirtualThreads(jint except_count, const jthread* except_list) {
+   jvmtiError err = JvmtiEnvBase::check_thread_list(except_count, except_list);
+   if (err != JVMTI_ERROR_NONE) {
+     return err;
+   }
+   if (!JvmtiExport::can_support_virtual_threads()) {
+     return JVMTI_ERROR_MUST_POSSESS_CAPABILITY;
+   }
+   ResourceMark rm;
+   JvmtiVTMTDisabler vtmt_disabler;
+   GrowableArray<jthread>* elist = new GrowableArray<jthread>(except_count);
+ 
+   // Collect threads from except_list which resumed status must be restored.
+   for (int idx = 0; idx < except_count; idx++) {
+     jthread thread = except_list[idx];
+     oop thread_oop = JNIHandles::resolve_external_guard(thread);
+     if (!JvmtiVTSuspender::is_vthread_suspended(thread_oop)) {
+         // is resumed, so its resumed status must be restored
+         elist->append(except_list[idx]);
+     }
    }
-   if (!java_thread->is_suspended()) {
-     return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
+ 
+   for (JavaThreadIteratorWithHandle jtiwh; JavaThread *java_thread = jtiwh.next(); ) {
+     oop vt_oop = java_thread->mounted_vthread();
+     if (!java_thread->is_exiting() &&
+         !java_thread->is_jvmti_agent_thread() &&
+         !java_thread->is_hidden_from_external_view() &&
+         vt_oop != NULL &&
+         java_lang_VirtualThread::is_instance(vt_oop) &&
+         JvmtiEnvBase::is_vthread_alive(vt_oop) &&
+         !JvmtiVTSuspender::is_vthread_suspended(vt_oop) &&
+         !is_in_thread_list(except_count, except_list, vt_oop)
+     ) {
+       suspend_thread(vt_oop,
+                      java_thread,
+                      false, // suspend all
+                      NULL);
+     }
    }
-   if (!JvmtiSuspendControl::resume(java_thread)) {
-     return JVMTI_ERROR_INTERNAL;
+   JvmtiVTSuspender::register_all_vthreads_suspend();
+ 
+   // Restore resumed state for threads from except list that were resumed before.
+   for (int idx = 0; idx < elist->length(); idx++) {
+     jthread thread = elist->at(idx);
+     oop thread_oop = JNIHandles::resolve_external_guard(thread);
+     if (JvmtiVTSuspender::is_vthread_suspended(thread_oop)) {
+       JvmtiVTSuspender::register_vthread_resume(thread_oop);
+     }
    }
    return JVMTI_ERROR_NONE;
+ } /* end SuspendAllVirtualThreads */
+ 
+ 
+ jvmtiError
+ JvmtiEnv::ResumeThread(jthread thread) {
+   JavaThread* java_thread = NULL;
+   oop thread_oop = NULL;
+   JvmtiVTMTDisabler vtmt_disabler;
+   ThreadsListHandle tlh;
+ 
+   jvmtiError err = get_threadOop_and_JavaThread(tlh.list(), thread, &java_thread, &thread_oop);
+   if (err != JVMTI_ERROR_NONE) {
+     return err;
+   }
+   err = resume_thread(thread_oop, java_thread, true); // single suspend
+   return err;
  } /* end ResumeThread */
  
  
  // request_count - pre-checked to be greater than or equal to 0
  // request_list - pre-checked for NULL
  // results - pre-checked for NULL
  jvmtiError
  JvmtiEnv::ResumeThreadList(jint request_count, const jthread* request_list, jvmtiError* results) {
+   oop thread_oop = NULL;
+   JavaThread* java_thread = NULL;
+   JvmtiVTMTDisabler vtmt_disabler;
    ThreadsListHandle tlh;
+ 
    for (int i = 0; i < request_count; i++) {
-     JavaThread* java_thread = NULL;
-     jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), request_list[i], &java_thread, NULL);
+     jthread thread = request_list[i];
+     jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, &thread_oop);
      if (err != JVMTI_ERROR_NONE) {
-       results[i] = err;
-       continue;
-     }
-     // don't allow hidden thread resume request.
-     if (java_thread->is_hidden_from_external_view()) {
-       results[i] = JVMTI_ERROR_NONE;  // indicate successful resume
-       continue;
+       if (thread_oop == NULL || err != JVMTI_ERROR_INVALID_THREAD) {
+         results[i] = err;
+         continue;
+       }
      }
-     if (!java_thread->is_suspended()) {
-       results[i] = JVMTI_ERROR_THREAD_NOT_SUSPENDED;
-       continue;
+     results[i] = resume_thread(thread_oop, java_thread, true); // single suspend
+   }
+   // per-thread resume results returned via results parameter
+   return JVMTI_ERROR_NONE;
+ } /* end ResumeThreadList */
+ 
+ 
+ jvmtiError
+ JvmtiEnv::ResumeAllVirtualThreads(jint except_count, const jthread* except_list) {
+   jvmtiError err = JvmtiEnvBase::check_thread_list(except_count, except_list);
+   if (err != JVMTI_ERROR_NONE) {
+     return err;
+   }
+   if (!JvmtiExport::can_support_virtual_threads()) {
+     return JVMTI_ERROR_MUST_POSSESS_CAPABILITY;
+   }
+   ResourceMark rm;
+   JvmtiVTMTDisabler vtmt_disabler;
+   GrowableArray<jthread>* elist = new GrowableArray<jthread>(except_count);
+ 
+   // Collect threads from except_list which suspended status must be restored.
+   for (int idx = 0; idx < except_count; idx++) {
+     jthread thread = except_list[idx];
+     oop thread_oop = JNIHandles::resolve_external_guard(thread);
+     if (JvmtiVTSuspender::is_vthread_suspended(thread_oop)) {
+       // is suspended, so its suspended status must be restored
+       elist->append(except_list[idx]);
      }
+   }
  
-     if (!JvmtiSuspendControl::resume(java_thread)) {
-       results[i] = JVMTI_ERROR_INTERNAL;
-       continue;
+   for (JavaThreadIteratorWithHandle jtiwh; JavaThread *java_thread = jtiwh.next(); ) {
+     oop vt_oop = java_thread->mounted_vthread();
+     if (!java_thread->is_exiting() &&
+         !java_thread->is_jvmti_agent_thread() &&
+         !java_thread->is_hidden_from_external_view() &&
+         vt_oop != NULL &&
+         java_lang_VirtualThread::is_instance(vt_oop) &&
+         JvmtiEnvBase::is_vthread_alive(vt_oop) &&
+         JvmtiVTSuspender::is_vthread_suspended(vt_oop) &&
+         !is_in_thread_list(except_count, except_list, vt_oop)
+     ) {
+       resume_thread(vt_oop, java_thread, false); // suspend all
      }
+   }
+   JvmtiVTSuspender::register_all_vthreads_resume();
  
-     results[i] = JVMTI_ERROR_NONE;  // indicate successful resume
+   // Restore suspended state for threads from except list that were suspended before.
+   for (int idx = 0; idx < elist->length(); idx++) {
+     jthread thread = elist->at(idx);
+     oop thread_oop = JNIHandles::resolve_external_guard(thread);
+     if (!JvmtiVTSuspender::is_vthread_suspended(thread_oop)) {
+       JvmtiVTSuspender::register_vthread_suspend(thread_oop);
+     }
    }
-   // per-thread resume results returned via results parameter
    return JVMTI_ERROR_NONE;
- } /* end ResumeThreadList */
+ } /* end ResumeAllVirtualThreads */
  
  
  // java_thread - protected by ThreadsListHandle and pre-checked
  jvmtiError
  JvmtiEnv::StopThread(JavaThread* java_thread, jobject exception) {

@@ -1077,75 +1156,114 @@
    return JVMTI_ERROR_NONE;
  
  } /* end StopThread */
  
  
- // thread - NOT protected by ThreadsListHandle and NOT pre-checked
  jvmtiError
  JvmtiEnv::InterruptThread(jthread thread) {
    JavaThread* current_thread  = JavaThread::current();
    JavaThread* java_thread = NULL;
+   oop thread_obj = NULL;
+   HandleMark hm(current_thread);
+ 
+   JvmtiVTMTDisabler vtmt_disabler;
    ThreadsListHandle tlh(current_thread);
-   jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, NULL);
+ 
+   jvmtiError err = get_threadOop_and_JavaThread(tlh.list(), thread, &java_thread, &thread_obj);
    if (err != JVMTI_ERROR_NONE) {
      return err;
    }
+ 
+   // Support for virtual threads
+   if (java_lang_VirtualThread::is_instance(thread_obj)) {
+     Handle obj(current_thread, thread_obj);
+     JavaValue result(T_VOID);
+     JavaCalls::call_virtual(&result,
+                             obj,
+                             vmClasses::Thread_klass(),
+                             vmSymbols::interrupt_method_name(),
+                             vmSymbols::void_method_signature(),
+                             current_thread);
+ 
+     return JVMTI_ERROR_NONE;
+   }
+ 
    // Really this should be a Java call to Thread.interrupt to ensure the same
    // semantics, however historically this has not been done for some reason.
    // So we continue with that (which means we don't interact with any Java-level
    // Interruptible object) but we must set the Java-level interrupted state.
-   java_lang_Thread::set_interrupted(JNIHandles::resolve(thread), true);
+   java_lang_Thread::set_interrupted(thread_obj, true);
    java_thread->interrupt();
  
    return JVMTI_ERROR_NONE;
  } /* end InterruptThread */
  
  
- // thread - NOT protected by ThreadsListHandle and NOT pre-checked
  // info_ptr - pre-checked for NULL
  jvmtiError
  JvmtiEnv::GetThreadInfo(jthread thread, jvmtiThreadInfo* info_ptr) {
    JavaThread* current_thread = JavaThread::current();
    ResourceMark rm(current_thread);
    HandleMark hm(current_thread);
+   JavaThread* java_thread = NULL;
+   oop thread_oop = NULL;
  
    ThreadsListHandle tlh(current_thread);
  
    // if thread is NULL the current thread is used
-   oop thread_oop = NULL;
    if (thread == NULL) {
-     thread_oop = current_thread->threadObj();
+     java_thread = JavaThread::current();
+     thread_oop = get_vthread_or_thread_oop(java_thread);
      if (thread_oop == NULL || !thread_oop->is_a(vmClasses::Thread_klass())) {
        return JVMTI_ERROR_INVALID_THREAD;
      }
    } else {
-     JavaThread* java_thread = NULL;
      jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, &thread_oop);
      if (err != JVMTI_ERROR_NONE) {
        // We got an error code so we don't have a JavaThread *, but
        // only return an error from here if we didn't get a valid
        // thread_oop.
+       // In the virtual thread case the cv_external_thread_to_JavaThread is expected to correctly set
+       // the thread_oop and return JVMTI_ERROR_INVALID_THREAD which we ignore here.
        if (thread_oop == NULL) {
          return err;
        }
-       // We have a valid thread_oop so we can return some thread info.
      }
    }
+   // We have a valid thread_oop so we can return some thread info.
  
    Handle thread_obj(current_thread, thread_oop);
    Handle name;
    ThreadPriority priority;
    Handle     thread_group;
    Handle context_class_loader;
    bool          is_daemon;
  
    name = Handle(current_thread, java_lang_Thread::name(thread_obj()));
-   priority = java_lang_Thread::priority(thread_obj());
-   thread_group = Handle(current_thread, java_lang_Thread::threadGroup(thread_obj()));
-   is_daemon = java_lang_Thread::is_daemon(thread_obj());
+ 
+   // Support for virtual threads
+   if (java_lang_VirtualThread::is_instance(thread_obj())) {
+     priority = (ThreadPriority)JVMTI_THREAD_NORM_PRIORITY;
+     is_daemon = true;
+     if (java_lang_VirtualThread::state(thread_obj()) == java_lang_VirtualThread::TERMINATED) {
+       thread_group = Handle(current_thread, NULL);
+     } else {
+       thread_group = Handle(current_thread, java_lang_Thread_VirtualThreads::get_THREAD_GROUP());
+     }
+   } else {
+     priority = java_lang_Thread::priority(thread_obj());
+     is_daemon = java_lang_Thread::is_daemon(thread_obj());
+     if (java_lang_Thread::get_thread_status(thread_obj()) == JavaThreadStatus::TERMINATED) {
+       thread_group = Handle(current_thread, NULL);
+     } else {
+       thread_group = Handle(current_thread, java_lang_Thread::threadGroup(thread_obj()));
+     }
+   }
  
    oop loader = java_lang_Thread::context_class_loader(thread_obj());
+   if (loader == java_lang_Thread_ClassLoaders::get_NOT_SUPPORTED())
+     loader = NULL;
    context_class_loader = Handle(current_thread, loader);
  
    { const char *n;
  
      if (name() != NULL) {

@@ -1163,44 +1281,72 @@
    }
    info_ptr->is_daemon = is_daemon;
    info_ptr->priority  = priority;
  
    info_ptr->context_class_loader = (context_class_loader.is_null()) ? NULL :
-                                      jni_reference(context_class_loader);
+                                     jni_reference(context_class_loader);
    info_ptr->thread_group = jni_reference(thread_group);
  
    return JVMTI_ERROR_NONE;
  } /* end GetThreadInfo */
  
  
- // java_thread - protected by ThreadsListHandle and pre-checked
+ // Threads_lock NOT held
  // owned_monitor_count_ptr - pre-checked for NULL
  // owned_monitors_ptr - pre-checked for NULL
  jvmtiError
- JvmtiEnv::GetOwnedMonitorInfo(JavaThread* java_thread, jint* owned_monitor_count_ptr, jobject** owned_monitors_ptr) {
+ JvmtiEnv::GetOwnedMonitorInfo(jthread thread, jint* owned_monitor_count_ptr, jobject** owned_monitors_ptr) {
    jvmtiError err = JVMTI_ERROR_NONE;
    JavaThread* calling_thread = JavaThread::current();
- 
-   EscapeBarrier eb(true, calling_thread, java_thread);
-   if (!eb.deoptimize_objects(MaxJavaStackTraceDepth)) {
-     return JVMTI_ERROR_OUT_OF_MEMORY;
-   }
+   JavaThread* java_thread = NULL;
+   HandleMark hm(calling_thread);
+   oop thread_oop = NULL;
  
    // growable array of jvmti monitors info on the C-heap
    GrowableArray<jvmtiMonitorStackDepthInfo*> *owned_monitors_list =
        new (ResourceObj::C_HEAP, mtServiceability) GrowableArray<jvmtiMonitorStackDepthInfo*>(1, mtServiceability);
  
-   // It is only safe to perform the direct operation on the current
-   // thread. All other usage needs to use a direct handshake for safety.
-   if (java_thread == calling_thread) {
-     err = get_owned_monitors(calling_thread, java_thread, owned_monitors_list);
+ 
+   JvmtiVTMTDisabler vtmt_disabler;
+   ThreadsListHandle tlh(calling_thread);
+ 
+   err = get_threadOop_and_JavaThread(tlh.list(), thread, &java_thread, &thread_oop);
+   if (err != JVMTI_ERROR_NONE) {
+     return err;
+   }
+ 
+   // Support for virtual threads
+   if (java_lang_VirtualThread::is_instance(thread_oop)) {
+     // there is no monitor info to collect if target virtual thread is unmounted
+     if (java_thread != NULL) {
+       VThreadGetOwnedMonitorInfoClosure op(this,
+                                            Handle(calling_thread, thread_oop),
+                                            owned_monitors_list);
+       Handshake::execute(&op, java_thread);
+       err = op.result();
+     }
    } else {
-     // get owned monitors info with handshake
-     GetOwnedMonitorInfoClosure op(calling_thread, this, owned_monitors_list);
-     Handshake::execute(&op, java_thread);
-     err = op.result();
+     EscapeBarrier eb(true, calling_thread, java_thread);
+     if (!eb.deoptimize_objects(MaxJavaStackTraceDepth)) {
+       return JVMTI_ERROR_OUT_OF_MEMORY;
+     }
+ 
+     if (JvmtiEnvBase::cthread_with_continuation(java_thread)) {
+       // Carrier thread with a mounted continuation case.
+       // No contended monitor can be owned by carrier thread in this case.
+     } else if (java_thread == calling_thread) {
+       // It is only safe to make a direct call on the current thread.
+       // All other usage needs to use a direct handshake for safety.
+       err = get_owned_monitors(calling_thread, java_thread, owned_monitors_list);
+     } else {
+       // get owned monitors info with handshake
+       GetOwnedMonitorInfoClosure op(calling_thread, this, owned_monitors_list);
+       Handshake::execute(&op, java_thread);
+       err = op.result();
+     }
    }
+ 
    jint owned_monitor_count = owned_monitors_list->length();
    if (err == JVMTI_ERROR_NONE) {
      if ((err = allocate(owned_monitor_count * sizeof(jobject *),
                        (unsigned char**)owned_monitors_ptr)) == JVMTI_ERROR_NONE) {
        // copy into the returned array

@@ -1219,42 +1365,67 @@
  
    return err;
  } /* end GetOwnedMonitorInfo */
  
  
- // java_thread - protected by ThreadsListHandle and pre-checked
+ // Threads_lock NOT held
  // monitor_info_count_ptr - pre-checked for NULL
  // monitor_info_ptr - pre-checked for NULL
  jvmtiError
- JvmtiEnv::GetOwnedMonitorStackDepthInfo(JavaThread* java_thread, jint* monitor_info_count_ptr, jvmtiMonitorStackDepthInfo** monitor_info_ptr) {
+ JvmtiEnv::GetOwnedMonitorStackDepthInfo(jthread thread, jint* monitor_info_count_ptr, jvmtiMonitorStackDepthInfo** monitor_info_ptr) {
    jvmtiError err = JVMTI_ERROR_NONE;
    JavaThread* calling_thread = JavaThread::current();
- 
-   EscapeBarrier eb(true, calling_thread, java_thread);
-   if (!eb.deoptimize_objects(MaxJavaStackTraceDepth)) {
-     return JVMTI_ERROR_OUT_OF_MEMORY;
-   }
+   JavaThread* java_thread = NULL;
+   HandleMark hm(calling_thread);
+   oop thread_oop = NULL;
  
    // growable array of jvmti monitors info on the C-heap
    GrowableArray<jvmtiMonitorStackDepthInfo*> *owned_monitors_list =
           new (ResourceObj::C_HEAP, mtServiceability) GrowableArray<jvmtiMonitorStackDepthInfo*>(1, mtServiceability);
  
-   // It is only safe to perform the direct operation on the current
-   // thread. All other usage needs to use a direct handshake for safety.
-   if (java_thread == calling_thread) {
-     err = get_owned_monitors(calling_thread, java_thread, owned_monitors_list);
-   } else {
-     // get owned monitors info with handshake
-     GetOwnedMonitorInfoClosure op(calling_thread, this, owned_monitors_list);
-     Handshake::execute(&op, java_thread);
-     err = op.result();
+   JvmtiVTMTDisabler vtmt_disabler;
+   ThreadsListHandle tlh(calling_thread);
+ 
+   err = get_threadOop_and_JavaThread(tlh.list(), thread, &java_thread, &thread_oop);
+   if (err != JVMTI_ERROR_NONE) {
+     return err;
    }
  
+   // Support for virtual threads
+   if (java_lang_VirtualThread::is_instance(thread_oop)) {
+     // there is no monitor info to collect if target virtual thread is unmounted
+     if (java_thread != NULL) {
+       VThreadGetOwnedMonitorInfoClosure op(this,
+                                            Handle(calling_thread, thread_oop),
+                                            owned_monitors_list);
+       Handshake::execute(&op, java_thread);
+       err = op.result();
+     }
+   } else {
+     EscapeBarrier eb(true, calling_thread, java_thread);
+     if (!eb.deoptimize_objects(MaxJavaStackTraceDepth)) {
+       return JVMTI_ERROR_OUT_OF_MEMORY;
+     }
+ 
+     if (JvmtiEnvBase::cthread_with_continuation(java_thread)) {
+       // Carrier thread with a mounted continuation case.
+       // No contended monitor can be owned by carrier thread in this case.
+     } else if (java_thread == calling_thread) {
+       // It is only safe to make a direct call on the current thread.
+       // All other usage needs to use a direct handshake for safety.
+       err = get_owned_monitors(calling_thread, java_thread, owned_monitors_list);
+     } else {
+       // get owned monitors info with handshake
+       GetOwnedMonitorInfoClosure op(calling_thread, this, owned_monitors_list);
+       Handshake::execute(&op, java_thread);
+       err = op.result();
+     }
+   }
    jint owned_monitor_count = owned_monitors_list->length();
    if (err == JVMTI_ERROR_NONE) {
      if ((err = allocate(owned_monitor_count * sizeof(jvmtiMonitorStackDepthInfo),
-                       (unsigned char**)monitor_info_ptr)) == JVMTI_ERROR_NONE) {
+                         (unsigned char**)monitor_info_ptr)) == JVMTI_ERROR_NONE) {
        // copy to output array.
        for (int i = 0; i < owned_monitor_count; i++) {
          (*monitor_info_ptr)[i].monitor =
            ((jvmtiMonitorStackDepthInfo*)owned_monitors_list->at(i))->monitor;
          (*monitor_info_ptr)[i].stack_depth =

@@ -1272,20 +1443,52 @@
  
    return err;
  } /* end GetOwnedMonitorStackDepthInfo */
  
  
- // java_thread - protected by ThreadsListHandle and pre-checked
+ // Threads_lock NOT held
  // monitor_ptr - pre-checked for NULL
  jvmtiError
- JvmtiEnv::GetCurrentContendedMonitor(JavaThread* java_thread, jobject* monitor_ptr) {
+ JvmtiEnv::GetCurrentContendedMonitor(jthread thread, jobject* monitor_ptr) {
    jvmtiError err = JVMTI_ERROR_NONE;
    JavaThread* calling_thread = JavaThread::current();
+   JavaThread* java_thread = NULL;
+   HandleMark hm(calling_thread);
+   oop thread_oop = NULL;
  
-   // It is only safe to perform the direct operation on the current
-   // thread. All other usage needs to use a direct handshake for safety.
-   if (java_thread == calling_thread) {
+   JvmtiVTMTDisabler vtmt_disabler;
+   ThreadsListHandle tlh(calling_thread);
+ 
+   err = get_threadOop_and_JavaThread(tlh.list(), thread, &java_thread, &thread_oop);
+   if (err != JVMTI_ERROR_NONE) {
+     return err;
+   }
+ 
+   // Support for virtual threads
+   if (java_lang_VirtualThread::is_instance(thread_oop)) {
+     // there is no monitor info to collect if target virtual thread is unmounted
+     if (java_thread != NULL) {
+       VThreadGetCurrentContendedMonitorClosure op(this,
+                                                   Handle(calling_thread, thread_oop),
+                                                   monitor_ptr);
+       Handshake::execute(&op, java_thread);
+       err = op.result();
+     } else {
+       *monitor_ptr = NULL;
+       if (!JvmtiEnvBase::is_vthread_alive(thread_oop)) {
+         err = JVMTI_ERROR_THREAD_NOT_ALIVE;
+       }
+     }
+     return err;
+   }
+   if (JvmtiEnvBase::cthread_with_continuation(java_thread)) {
+     // Carrier thread with a mounted continuation case.
+     // No contended monitor can be owned by carrier thread in this case.
+     *monitor_ptr = NULL;
+   } else if (java_thread == calling_thread) {
+     // It is only safe to make a direct call on the current thread.
+     // All other usage needs to use a direct handshake for safety.
      err = get_current_contended_monitor(calling_thread, java_thread, monitor_ptr);
    } else {
      // get contended monitor information with handshake
      GetCurrentContendedMonitorClosure op(calling_thread, this, monitor_ptr);
      Handshake::execute(&op, java_thread);

@@ -1293,11 +1496,10 @@
    }
    return err;
  } /* end GetCurrentContendedMonitor */
  
  
- // thread - NOT protected by ThreadsListHandle and NOT pre-checked
  // proc - pre-checked for NULL
  // arg - NULL is a valid value, must be checked
  jvmtiError
  JvmtiEnv::RunAgentThread(jthread thread, jvmtiStartFunction proc, const void* arg, jint priority) {
    JavaThread* current_thread = JavaThread::current();

@@ -1318,10 +1520,13 @@
  
    if (java_thread != NULL) {
      // 'thread' refers to an existing JavaThread.
      return JVMTI_ERROR_INVALID_THREAD;
    }
+   if (java_lang_VirtualThread::is_instance(thread_oop)) {
+     return JVMTI_ERROR_INVALID_THREAD;
+   }
  
    if (priority < JVMTI_THREAD_MIN_PRIORITY || priority > JVMTI_THREAD_MAX_PRIORITY) {
      return JVMTI_ERROR_INVALID_PRIORITY;
    }
  

@@ -1383,34 +1588,31 @@
    Handle group_obj (current_thread, JNIHandles::resolve_external_guard(group));
    NULL_CHECK(group_obj(), JVMTI_ERROR_INVALID_THREAD_GROUP);
  
    const char* name;
    Handle parent_group;
-   bool is_daemon;
    ThreadPriority max_priority;
  
    name         = java_lang_ThreadGroup::name(group_obj());
    parent_group = Handle(current_thread, java_lang_ThreadGroup::parent(group_obj()));
-   is_daemon    = java_lang_ThreadGroup::is_daemon(group_obj());
    max_priority = java_lang_ThreadGroup::maxPriority(group_obj());
  
-   info_ptr->is_daemon    = is_daemon;
-   info_ptr->max_priority = max_priority;
-   info_ptr->parent       = jni_reference(parent_group);
- 
    if (name != NULL) {
      info_ptr->name = (char*)jvmtiMalloc(strlen(name)+1);
      NULL_CHECK(info_ptr->name, JVMTI_ERROR_OUT_OF_MEMORY);
      strcpy(info_ptr->name, name);
    } else {
      info_ptr->name = NULL;
    }
  
+   info_ptr->parent       = jni_reference(parent_group);
+   info_ptr->max_priority = max_priority;
+   info_ptr->is_daemon    = JNI_FALSE;
+ 
    return JVMTI_ERROR_NONE;
  } /* end GetThreadGroupInfo */
  
- 
  // thread_count_ptr - pre-checked for NULL
  // threads_ptr - pre-checked for NULL
  // group_count_ptr - pre-checked for NULL
  // groups_ptr - pre-checked for NULL
  jvmtiError

@@ -1428,60 +1630,12 @@
    ResourceMark rm(current_thread);
    HandleMark hm(current_thread);
  
    Handle group_hdl(current_thread, group_obj);
  
-   { // Cannot allow thread or group counts to change.
-     ObjectLocker ol(group_hdl, current_thread);
- 
-     nthreads = java_lang_ThreadGroup::nthreads(group_hdl());
-     ngroups  = java_lang_ThreadGroup::ngroups(group_hdl());
- 
-     if (nthreads > 0) {
-       ThreadsListHandle tlh(current_thread);
-       objArrayOop threads = java_lang_ThreadGroup::threads(group_hdl());
-       assert(nthreads <= threads->length(), "too many threads");
-       thread_objs = NEW_RESOURCE_ARRAY(Handle,nthreads);
-       for (int i = 0, j = 0; i < nthreads; i++) {
-         oop thread_obj = threads->obj_at(i);
-         assert(thread_obj != NULL, "thread_obj is NULL");
-         JavaThread *java_thread = NULL;
-         jvmtiError err = JvmtiExport::cv_oop_to_JavaThread(tlh.list(), thread_obj, &java_thread);
-         if (err == JVMTI_ERROR_NONE) {
-           // Have a valid JavaThread*.
-           if (java_thread->is_hidden_from_external_view()) {
-             // Filter out hidden java threads.
-             hidden_threads++;
-             continue;
-           }
-         } else {
-           // We couldn't convert thread_obj into a JavaThread*.
-           if (err == JVMTI_ERROR_INVALID_THREAD) {
-             // The thread_obj does not refer to a java.lang.Thread object
-             // so skip it.
-             hidden_threads++;
-             continue;
-           }
-           // We have a valid thread_obj, but no JavaThread*; the caller
-           // can still have limited use for the thread_obj.
-         }
-         thread_objs[j++] = Handle(current_thread, thread_obj);
-       }
-       nthreads -= hidden_threads;
-     } // ThreadsListHandle is destroyed here.
- 
-     if (ngroups > 0) {
-       objArrayOop groups = java_lang_ThreadGroup::groups(group_hdl());
-       assert(ngroups <= groups->length(), "too many groups");
-       group_objs = NEW_RESOURCE_ARRAY(Handle,ngroups);
-       for (int i = 0; i < ngroups; i++) {
-         oop group_obj = groups->obj_at(i);
-         assert(group_obj != NULL, "group_obj != NULL");
-         group_objs[i] = Handle(current_thread, group_obj);
-       }
-     }
-   } // ThreadGroup unlocked here
+   nthreads = get_live_threads(current_thread, group_hdl, &thread_objs);
+   ngroups = get_subgroups(current_thread, group_hdl, &group_objs);
  
    *group_count_ptr  = ngroups;
    *thread_count_ptr = nthreads;
    *threads_ptr     = new_jthreadArray(nthreads, thread_objs);
    *groups_ptr      = new_jthreadGroupArray(ngroups, group_objs);

@@ -1498,17 +1652,46 @@
  
    //
    // Stack Frame functions
    //
  
- // java_thread - protected by ThreadsListHandle and pre-checked
+ // Threads_lock NOT held
  // max_frame_count - pre-checked to be greater than or equal to 0
  // frame_buffer - pre-checked for NULL
  // count_ptr - pre-checked for NULL
  jvmtiError
- JvmtiEnv::GetStackTrace(JavaThread* java_thread, jint start_depth, jint max_frame_count, jvmtiFrameInfo* frame_buffer, jint* count_ptr) {
+ JvmtiEnv::GetStackTrace(jthread thread, jint start_depth, jint max_frame_count, jvmtiFrameInfo* frame_buffer, jint* count_ptr) {
    jvmtiError err = JVMTI_ERROR_NONE;
+   JavaThread* java_thread = NULL;
+   JavaThread* current_thread = JavaThread::current();
+   HandleMark hm(current_thread);
+   oop thread_obj = NULL;
+ 
+   JvmtiVTMTDisabler vtmt_disabler;
+   ThreadsListHandle tlh(current_thread);
+ 
+   err = get_threadOop_and_JavaThread(tlh.list(), thread, &java_thread, &thread_obj);
+   if (err != JVMTI_ERROR_NONE) {
+     return err;
+   }
+ 
+   // Support for virtual threads
+   if (java_lang_VirtualThread::is_instance(thread_obj)) {
+     if (java_thread == NULL) { // target virtual thread is unmounted
+       ResourceMark rm(current_thread);
+ 
+       VM_VThreadGetStackTrace op(this, Handle(current_thread, thread_obj),
+                                  start_depth, max_frame_count,
+                                  frame_buffer, count_ptr);
+       VMThread::execute(&op);
+       return op.result();
+     }
+     VThreadGetStackTraceClosure op(this, Handle(current_thread, thread_obj),
+                                    start_depth, max_frame_count, frame_buffer, count_ptr);
+     Handshake::execute(&op, java_thread);
+     return op.result();
+   }
  
    // It is only safe to perform the direct operation on the current
    // thread. All other usage needs to use a direct handshake for safety.
    if (java_thread == JavaThread::current()) {
      err = get_stack_trace(java_thread, start_depth, max_frame_count, frame_buffer, count_ptr);

@@ -1548,20 +1731,36 @@
  jvmtiError
  JvmtiEnv::GetThreadListStackTraces(jint thread_count, const jthread* thread_list, jint max_frame_count, jvmtiStackInfo** stack_info_ptr) {
    jvmtiError err = JVMTI_ERROR_NONE;
  
    if (thread_count == 1) {
+     JvmtiVTMTDisabler vtmt_disabler;
+ 
      // Use direct handshake if we need to get only one stack trace.
      JavaThread *current_thread = JavaThread::current();
      ThreadsListHandle tlh(current_thread);
+     jthread thread = thread_list[0];
      JavaThread *java_thread;
-     err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), *thread_list, &java_thread, NULL);
+     oop thread_obj = NULL;
+     err = get_threadOop_and_JavaThread(tlh.list(), thread, &java_thread, &thread_obj);
      if (err != JVMTI_ERROR_NONE) {
        return err;
      }
  
-     GetSingleStackTraceClosure op(this, current_thread, *thread_list, max_frame_count);
+     // Support for virtual threads
+     if (java_lang_VirtualThread::is_instance(thread_obj)) {
+       if (java_thread == NULL) { // target virtual thread is unmounted
+         ResourceMark rm(current_thread);
+         MultipleStackTracesCollector collector(this, max_frame_count);
+         collector.fill_frames(thread, java_thread, thread_obj);
+         collector.allocate_and_fill_stacks(1);
+         *stack_info_ptr = collector.stack_info();
+         return collector.result();
+       }
+     }
+ 
+     GetSingleStackTraceClosure op(this, current_thread, thread, max_frame_count);
      Handshake::execute(&op, java_thread);
      err = op.result();
      if (err == JVMTI_ERROR_NONE) {
        *stack_info_ptr = op.stack_info();
      }

@@ -1576,29 +1775,47 @@
    }
    return err;
  } /* end GetThreadListStackTraces */
  
  
- // java_thread - protected by ThreadsListHandle and pre-checked
+ // Threads_lock NOT held
  // count_ptr - pre-checked for NULL
  jvmtiError
- JvmtiEnv::GetFrameCount(JavaThread* java_thread, jint* count_ptr) {
+ JvmtiEnv::GetFrameCount(jthread thread, jint* count_ptr) {
    jvmtiError err = JVMTI_ERROR_NONE;
+   JavaThread* java_thread = NULL;
+   JavaThread* current_thread = JavaThread::current();
+   HandleMark hm(current_thread);
+   oop thread_obj = NULL;
  
-   // retrieve or create JvmtiThreadState.
-   JvmtiThreadState* state = JvmtiThreadState::state_for(java_thread);
-   if (state == NULL) {
-     return JVMTI_ERROR_THREAD_NOT_ALIVE;
+   JvmtiVTMTDisabler vtmt_disabler;
+   ThreadsListHandle tlh(current_thread);
+ 
+   err = get_threadOop_and_JavaThread(tlh.list(), thread, &java_thread, &thread_obj);
+   if (err != JVMTI_ERROR_NONE) {
+     return err;
+   }
+ 
+   // Support for virtual threads
+   if (java_lang_VirtualThread::is_instance(thread_obj)) {
+     if (java_thread == NULL) { // target virtual thread is unmounted
+       VM_VThreadGetFrameCount op(this, Handle(current_thread, thread_obj),  count_ptr);
+       VMThread::execute(&op);
+       return op.result();
+     }
+     VThreadGetFrameCountClosure op(this, Handle(current_thread, thread_obj), count_ptr);
+     Handshake::execute(&op, java_thread);
+     return op.result();
    }
  
    // It is only safe to perform the direct operation on the current
    // thread. All other usage needs to use a direct handshake for safety.
    if (java_thread == JavaThread::current()) {
-     err = get_frame_count(state, count_ptr);
+     err = get_frame_count(java_thread, count_ptr);
    } else {
      // get java stack frame count with handshake.
-     GetFrameCountClosure op(this, state, count_ptr);
+     GetFrameCountClosure op(this, count_ptr);
      Handshake::execute(&op, java_thread);
      err = op.result();
    }
    return err;
  } /* end GetFrameCount */

@@ -1630,17 +1847,41 @@
    }
    return op.result();
  } /* end PopFrame */
  
  
- // java_thread - protected by ThreadsListHandle and pre-checked
+ // Threads_lock NOT held
  // depth - pre-checked as non-negative
  // method_ptr - pre-checked for NULL
  // location_ptr - pre-checked for NULL
  jvmtiError
- JvmtiEnv::GetFrameLocation(JavaThread* java_thread, jint depth, jmethodID* method_ptr, jlocation* location_ptr) {
+ JvmtiEnv::GetFrameLocation(jthread thread, jint depth, jmethodID* method_ptr, jlocation* location_ptr) {
    jvmtiError err = JVMTI_ERROR_NONE;
+   JavaThread* java_thread = NULL;
+   JavaThread* current_thread = JavaThread::current();
+   HandleMark hm(current_thread);
+   oop thread_obj = NULL;
+ 
+   JvmtiVTMTDisabler vtmt_disabler;
+   ThreadsListHandle tlh(current_thread);
+ 
+   err = get_threadOop_and_JavaThread(tlh.list(), thread, &java_thread, &thread_obj);
+   if (err != JVMTI_ERROR_NONE) {
+     return err;
+   }
+ 
+   // Support for virtual threads
+   if (java_lang_VirtualThread::is_instance(thread_obj)) {
+     if (java_thread == NULL) { // target virtual thread is unmounted
+       err = get_frame_location(thread_obj, depth, method_ptr, location_ptr);
+       return err;
+     }
+     VThreadGetFrameLocationClosure op(this, Handle(current_thread, thread_obj),
+                                       depth, method_ptr, location_ptr);
+     Handshake::execute(&op, java_thread);
+     return op.result();
+   }
  
    // It is only safe to perform the direct operation on the current
    // thread. All other usage needs to use a direct handshake for safety.
    if (java_thread == JavaThread::current()) {
      err = get_frame_location(java_thread, depth, method_ptr, location_ptr);

@@ -1652,22 +1893,53 @@
    }
    return err;
  } /* end GetFrameLocation */
  
  
- // java_thread - protected by ThreadsListHandle and pre-checked
+ // Threads_lock NOT held, java_thread not protected by lock
  // depth - pre-checked as non-negative
  jvmtiError
- JvmtiEnv::NotifyFramePop(JavaThread* java_thread, jint depth) {
-   JvmtiThreadState *state = JvmtiThreadState::state_for(java_thread);
+ JvmtiEnv::NotifyFramePop(jthread thread, jint depth) {
+   jvmtiError err = JVMTI_ERROR_NONE;
+   ResourceMark rm;
+   JavaThread* java_thread = NULL;
+   oop thread_obj = NULL;
+   JvmtiVTMTDisabler vtmt_disabler;
+   ThreadsListHandle tlh;
+ 
+   err = get_threadOop_and_JavaThread(tlh.list(), thread, &java_thread, &thread_obj);
+   if (err != JVMTI_ERROR_NONE) {
+     return err;
+   }
+ 
+   JavaThread* current = JavaThread::current();
+   HandleMark hm(current);
+   Handle thread_handle(current, thread_obj);
+ 
+   // Support for virtual threads
+   if (java_lang_VirtualThread::is_instance(thread_obj)) {
+     if (java_thread == NULL) {
+       // java_thread is NULL if virtual thread is unmounted
+       JvmtiThreadState *state = JvmtiThreadState::state_for(java_thread, thread_handle);
+       if (state == NULL) {
+         return JVMTI_ERROR_THREAD_NOT_ALIVE;
+       }
+       MutexLocker mu(JvmtiThreadState_lock);
+       int frame_number = state->count_frames() - depth;
+       state->env_thread_state(this)->set_frame_pop(frame_number);
+       return JVMTI_ERROR_NONE;
+     }
+   }
+ 
+   JvmtiThreadState *state = JvmtiThreadState::state_for(java_thread, thread_handle);
    if (state == NULL) {
      return JVMTI_ERROR_THREAD_NOT_ALIVE;
    }
  
    SetFramePopClosure op(this, state, depth);
-   MutexLocker mu(JvmtiThreadState_lock);
-   if (java_thread == JavaThread::current()) {
+   MutexLocker mu(current, JvmtiThreadState_lock);
+   if (java_thread == current) {
      op.doit(java_thread, true /* self */);
    } else {
      Handshake::execute(&op, java_thread);
    }
    return op.result();

@@ -1899,114 +2171,252 @@
  
    //
    // Local Variable functions
    //
  
- // java_thread - protected by ThreadsListHandle and pre-checked
+ // Threads_lock NOT held
  // depth - pre-checked as non-negative
  // value_ptr - pre-checked for NULL
  jvmtiError
- JvmtiEnv::GetLocalObject(JavaThread* java_thread, jint depth, jint slot, jobject* value_ptr) {
+ JvmtiEnv::GetLocalObject(jthread thread, jint depth, jint slot, jobject* value_ptr) {
+   jvmtiError err = JVMTI_ERROR_NONE;
+   JavaThread* java_thread = NULL;
    JavaThread* current_thread = JavaThread::current();
    // rm object is created to clean up the javaVFrame created in
    // doit_prologue(), but after doit() is finished with it.
    ResourceMark rm(current_thread);
+   HandleMark hm(current_thread);
+   oop thread_obj = JNIHandles::resolve_external_guard(thread);
  
-   VM_GetOrSetLocal op(java_thread, current_thread, depth, slot);
-   VMThread::execute(&op);
-   jvmtiError err = op.result();
-   if (err != JVMTI_ERROR_NONE) {
-     return err;
+   if (java_lang_VirtualThread::is_instance(thread_obj)) {
+     // Support for virtual threads
+     VM_VirtualThreadGetOrSetLocal op(this, Handle(current_thread, thread_obj),
+                                    current_thread, depth, slot);
+     VMThread::execute(&op);
+     err = op.result();
+     if (err == JVMTI_ERROR_NONE) {
+       *value_ptr = op.value().l;
+     }
    } else {
-     *value_ptr = op.value().l;
-     return JVMTI_ERROR_NONE;
+     // Support for ordinary threads
+     ThreadsListHandle tlh(current_thread);
+     err = get_JavaThread(tlh.list(), thread, &java_thread);
+     if (err != JVMTI_ERROR_NONE) {
+       return err;
+     }
+     VM_GetOrSetLocal op(java_thread, current_thread, depth, slot);
+     VMThread::execute(&op);
+     err = op.result();
+     if (err == JVMTI_ERROR_NONE) {
+       *value_ptr = op.value().l;
+     }
    }
+   return err;
  } /* end GetLocalObject */
  
- // java_thread - protected by ThreadsListHandle and pre-checked
+ // Threads_lock NOT held
  // depth - pre-checked as non-negative
  // value - pre-checked for NULL
  jvmtiError
- JvmtiEnv::GetLocalInstance(JavaThread* java_thread, jint depth, jobject* value_ptr){
+ JvmtiEnv::GetLocalInstance(jthread thread, jint depth, jobject* value_ptr){
+   jvmtiError err = JVMTI_ERROR_NONE;
+   JavaThread* java_thread = NULL;
    JavaThread* current_thread = JavaThread::current();
    // rm object is created to clean up the javaVFrame created in
    // doit_prologue(), but after doit() is finished with it.
    ResourceMark rm(current_thread);
+   HandleMark hm(current_thread);
+   oop thread_obj = JNIHandles::resolve_external_guard(thread);
  
-   VM_GetReceiver op(java_thread, current_thread, depth);
-   VMThread::execute(&op);
-   jvmtiError err = op.result();
-   if (err != JVMTI_ERROR_NONE) {
-     return err;
+   if (java_lang_VirtualThread::is_instance(thread_obj)) {
+     // Support for virtual threads
+     VM_VirtualThreadGetReceiver op(this, Handle(current_thread, thread_obj),
+                                  current_thread, depth);
+     VMThread::execute(&op);
+     err = op.result();
+     if (err == JVMTI_ERROR_NONE) {
+       *value_ptr = op.value().l;
+     }
    } else {
-     *value_ptr = op.value().l;
-     return JVMTI_ERROR_NONE;
+     // Support for ordinary threads
+     ThreadsListHandle tlh(current_thread);
+     err = get_JavaThread(tlh.list(), thread, &java_thread);
+     if (err != JVMTI_ERROR_NONE) {
+       return err;
+     }
+     VM_GetReceiver op(java_thread, current_thread, depth);
+     VMThread::execute(&op);
+     err = op.result();
+     if (err == JVMTI_ERROR_NONE) {
+       *value_ptr = op.value().l;
+     }
    }
+   return err;
  } /* end GetLocalInstance */
  
  
- // java_thread - protected by ThreadsListHandle and pre-checked
+ // Threads_lock NOT held
  // depth - pre-checked as non-negative
  // value_ptr - pre-checked for NULL
  jvmtiError
- JvmtiEnv::GetLocalInt(JavaThread* java_thread, jint depth, jint slot, jint* value_ptr) {
+ JvmtiEnv::GetLocalInt(jthread thread, jint depth, jint slot, jint* value_ptr) {
+   jvmtiError err = JVMTI_ERROR_NONE;
+   JavaThread* java_thread = NULL;
+   JavaThread* current_thread = JavaThread::current();
    // rm object is created to clean up the javaVFrame created in
    // doit_prologue(), but after doit() is finished with it.
-   ResourceMark rm;
+   ResourceMark rm(current_thread);
+   HandleMark hm(current_thread);
+   oop thread_obj = JNIHandles::resolve_external_guard(thread);
  
-   VM_GetOrSetLocal op(java_thread, depth, slot, T_INT);
-   VMThread::execute(&op);
-   *value_ptr = op.value().i;
-   return op.result();
+   if (java_lang_VirtualThread::is_instance(thread_obj)) {
+     // Support for virtual threads
+     VM_VirtualThreadGetOrSetLocal op(this, Handle(current_thread, thread_obj),
+                                    depth, slot, T_INT);
+     VMThread::execute(&op);
+     err = op.result();
+     if (err == JVMTI_ERROR_NONE) {
+       *value_ptr = op.value().i;
+     }
+   } else {
+     // Support for ordinary threads
+     ThreadsListHandle tlh(current_thread);
+     err = get_JavaThread(tlh.list(), thread, &java_thread);
+     if (err != JVMTI_ERROR_NONE) {
+       return err;
+     }
+     VM_GetOrSetLocal op(java_thread, depth, slot, T_INT);
+     VMThread::execute(&op);
+     err = op.result();
+     if (err == JVMTI_ERROR_NONE) {
+       *value_ptr = op.value().i;
+     }
+   }
+   return err;
  } /* end GetLocalInt */
  
  
- // java_thread - protected by ThreadsListHandle and pre-checked
+ // Threads_lock NOT held
  // depth - pre-checked as non-negative
  // value_ptr - pre-checked for NULL
  jvmtiError
- JvmtiEnv::GetLocalLong(JavaThread* java_thread, jint depth, jint slot, jlong* value_ptr) {
+ JvmtiEnv::GetLocalLong(jthread thread, jint depth, jint slot, jlong* value_ptr) {
+   jvmtiError err = JVMTI_ERROR_NONE;
+   JavaThread* java_thread = NULL;
+   JavaThread* current_thread = JavaThread::current();
    // rm object is created to clean up the javaVFrame created in
    // doit_prologue(), but after doit() is finished with it.
-   ResourceMark rm;
+   ResourceMark rm(current_thread);
+   HandleMark hm(current_thread);
+   oop thread_obj = JNIHandles::resolve_external_guard(thread);
  
-   VM_GetOrSetLocal op(java_thread, depth, slot, T_LONG);
-   VMThread::execute(&op);
-   *value_ptr = op.value().j;
-   return op.result();
+   if (java_lang_VirtualThread::is_instance(thread_obj)) {
+     // Support for virtual threads
+     VM_VirtualThreadGetOrSetLocal op(this, Handle(current_thread, thread_obj),
+                                    depth, slot, T_LONG);
+     VMThread::execute(&op);
+     err = op.result();
+     if (err == JVMTI_ERROR_NONE) {
+       *value_ptr = op.value().j;
+     }
+   } else {
+     // Support for ordinary threads
+     ThreadsListHandle tlh(current_thread);
+     err = get_JavaThread(tlh.list(), thread, &java_thread);
+     if (err != JVMTI_ERROR_NONE) {
+       return err;
+     }
+     VM_GetOrSetLocal op(java_thread, depth, slot, T_LONG);
+     VMThread::execute(&op);
+     err = op.result();
+     if (err == JVMTI_ERROR_NONE) {
+       *value_ptr = op.value().j;
+     }
+   }
+   return err;
  } /* end GetLocalLong */
  
  
- // java_thread - protected by ThreadsListHandle and pre-checked
+ // Threads_lock NOT held
  // depth - pre-checked as non-negative
  // value_ptr - pre-checked for NULL
  jvmtiError
- JvmtiEnv::GetLocalFloat(JavaThread* java_thread, jint depth, jint slot, jfloat* value_ptr) {
+ JvmtiEnv::GetLocalFloat(jthread thread, jint depth, jint slot, jfloat* value_ptr) {
+   jvmtiError err = JVMTI_ERROR_NONE;
+   JavaThread* java_thread = NULL;
+   JavaThread* current_thread = JavaThread::current();
    // rm object is created to clean up the javaVFrame created in
    // doit_prologue(), but after doit() is finished with it.
-   ResourceMark rm;
+   ResourceMark rm(current_thread);
+   HandleMark hm(current_thread);
+   oop thread_obj = JNIHandles::resolve_external_guard(thread);
  
-   VM_GetOrSetLocal op(java_thread, depth, slot, T_FLOAT);
-   VMThread::execute(&op);
-   *value_ptr = op.value().f;
-   return op.result();
+   if (java_lang_VirtualThread::is_instance(thread_obj)) {
+     // Support for virtual threads
+     VM_VirtualThreadGetOrSetLocal op(this, Handle(current_thread, thread_obj),
+                                    depth, slot, T_FLOAT);
+     VMThread::execute(&op);
+     err = op.result();
+     if (err == JVMTI_ERROR_NONE) {
+       *value_ptr = op.value().f;
+     }
+   } else {
+     // Support for ordinary threads
+     ThreadsListHandle tlh(current_thread);
+     err = get_JavaThread(tlh.list(), thread, &java_thread);
+     if (err != JVMTI_ERROR_NONE) {
+       return err;
+     }
+     VM_GetOrSetLocal op(java_thread, depth, slot, T_FLOAT);
+     VMThread::execute(&op);
+     err = op.result();
+     if (err == JVMTI_ERROR_NONE) {
+       *value_ptr = op.value().f;
+     }
+   }
+   return err;
  } /* end GetLocalFloat */
  
  
- // java_thread - protected by ThreadsListHandle and pre-checked
+ // Threads_lock NOT held
  // depth - pre-checked as non-negative
  // value_ptr - pre-checked for NULL
  jvmtiError
- JvmtiEnv::GetLocalDouble(JavaThread* java_thread, jint depth, jint slot, jdouble* value_ptr) {
+ JvmtiEnv::GetLocalDouble(jthread thread, jint depth, jint slot, jdouble* value_ptr) {
+   jvmtiError err = JVMTI_ERROR_NONE;
+   JavaThread* java_thread = NULL;
+   JavaThread* current_thread = JavaThread::current();
    // rm object is created to clean up the javaVFrame created in
    // doit_prologue(), but after doit() is finished with it.
-   ResourceMark rm;
+   ResourceMark rm(current_thread);
+   HandleMark hm(current_thread);
+   oop thread_obj = JNIHandles::resolve_external_guard(thread);
  
-   VM_GetOrSetLocal op(java_thread, depth, slot, T_DOUBLE);
-   VMThread::execute(&op);
-   *value_ptr = op.value().d;
-   return op.result();
+   if (java_lang_VirtualThread::is_instance(thread_obj)) {
+     // Support for virtual threads
+     VM_VirtualThreadGetOrSetLocal op(this, Handle(current_thread, thread_obj),
+                                    depth, slot, T_DOUBLE);
+     VMThread::execute(&op);
+     err = op.result();
+     if (err == JVMTI_ERROR_NONE) {
+       *value_ptr = op.value().d;
+     }
+   } else {
+     // Support for ordinary threads
+     ThreadsListHandle tlh(current_thread);
+     err = get_JavaThread(tlh.list(), thread, &java_thread);
+     if (err != JVMTI_ERROR_NONE) {
+       return err;
+     }
+     VM_GetOrSetLocal op(java_thread, depth, slot, T_DOUBLE);
+     VMThread::execute(&op);
+     err = op.result();
+     if (err == JVMTI_ERROR_NONE) {
+       *value_ptr = op.value().d;
+     }
+   }
+   return err;
  } /* end GetLocalDouble */
  
  
  // java_thread - protected by ThreadsListHandle and pre-checked
  // depth - pre-checked as non-negative

@@ -3303,10 +3713,20 @@
  
  
  // nanos_ptr - pre-checked for NULL
  jvmtiError
  JvmtiEnv::GetCurrentThreadCpuTime(jlong* nanos_ptr) {
+   Thread* thread = Thread::current();
+ 
+   // Surprizingly the GetCurrentThreadCpuTime is used by non-JavaThread's.
+   if (thread->is_Java_thread()) {
+     oop thread_obj = get_vthread_or_thread_oop(JavaThread::cast(thread));
+ 
+     if (java_lang_VirtualThread::is_instance(thread_obj)) {
+       return JVMTI_ERROR_INVALID_THREAD;
+     }
+   }
    *nanos_ptr = os::current_thread_cpu_time();
    return JVMTI_ERROR_NONE;
  } /* end GetCurrentThreadCpuTime */
  
  
< prev index next >