< 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 ***
  jvmtiError
  JvmtiEnv::Deallocate(unsigned char* mem) {
    return deallocate(mem);
  } /* end Deallocate */
  
! // java_thread - protected by ThreadsListHandle and pre-checked
  // 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();
    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);
      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) {
--- 139,50 ---
  jvmtiError
  JvmtiEnv::Deallocate(unsigned char* mem) {
    return deallocate(mem);
  } /* end Deallocate */
  
! // Threads_lock NOT held
  // data - NULL is a valid value, must be checked
  jvmtiError
! 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
!     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 */
  
  
  // data_ptr - pre-checked for NULL
  jvmtiError
  JvmtiEnv::GetThreadLocalStorage(jthread thread, void** data_ptr) {
    JavaThread* current_thread = JavaThread::current();
    if (thread == NULL) {

*** 180,17 ***
      ThreadInVMfromNative __tiv(current_thread);
      VM_ENTRY_BASE(jvmtiError, JvmtiEnv::GetThreadLocalStorage , current_thread)
      debug_only(VMNativeEntryWrapper __vew;)
  
      JavaThread* java_thread = NULL;
      ThreadsListHandle tlh(current_thread);
!     jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, NULL);
      if (err != JVMTI_ERROR_NONE) {
        return err;
      }
  
!     JvmtiThreadState* state = java_thread->jvmti_thread_state();
      *data_ptr = (state == NULL) ? NULL :
        state->env_thread_state(this)->get_agent_thread_local_storage_data();
    }
    return JVMTI_ERROR_NONE;
  } /* end GetThreadLocalStorage */
--- 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 = get_threadOop_and_JavaThread(tlh.list(), thread, &java_thread, &thread_obj);
      if (err != JVMTI_ERROR_NONE) {
        return err;
      }
  
!     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 ***
  
  
  // event_thread - NULL is a valid value, must be checked
  jvmtiError
  JvmtiEnv::SetEventNotificationMode(jvmtiEventMode mode, jvmtiEvent event_type, jthread event_thread,   ...) {
    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);
    } else {
      // We have a specified event_thread.
      JavaThread* java_thread = NULL;
      ThreadsListHandle tlh;
!     jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), event_thread, &java_thread, NULL);
      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);
    }
  
    return JVMTI_ERROR_NONE;
  } /* end SetEventNotificationMode */
  
--- 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.
  
!     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 = get_threadOop_and_JavaThread(tlh.list(), event_thread, &java_thread, &thread_obj);
      if (err != JVMTI_ERROR_NONE) {
        return err;
      }
  
      // global events cannot be controlled at thread level.
      if (JvmtiEventController::is_global_event(event_type)) {
        return JVMTI_ERROR_ILLEGAL_ARGUMENT;
      }
  
!     JvmtiEventController::set_user_enabled(this, java_thread, thread_obj, event_type, enabled);
    }
  
    return JVMTI_ERROR_NONE;
  } /* end SetEventNotificationMode */
  

*** 835,67 ***
  
    //
    // 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;
    ThreadsListHandle tlh(current_thread);
  
    if (thread == NULL) {
      java_thread = current_thread;
!     thread_oop = java_thread->threadObj();
  
      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.
        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;
-     }
    }
! 
!   *thread_state_ptr = state;
    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());
    return JVMTI_ERROR_NONE;
  } /* end GetCurrentThread */
  
  
  // threads_count_ptr - pre-checked for NULL
--- 848,61 ---
  
    //
    // Thread functions
    //
  
  // 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 = 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.
      }
    }
  
!   // 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);
    }
!   // 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* 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 ***
    *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;
    }
!   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;
    }
!   return JVMTI_ERROR_NONE;
  } /* 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
    JavaThread* current = JavaThread::current();
    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);
      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;
          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
      }
    }
    // 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;
    }
!   if (!java_thread->is_suspended()) {
!     return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
    }
!   if (!JvmtiSuspendControl::resume(java_thread)) {
!     return JVMTI_ERROR_INTERNAL;
    }
    return JVMTI_ERROR_NONE;
  } /* 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) {
    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);
      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 (!java_thread->is_suspended()) {
!       results[i] = JVMTI_ERROR_THREAD_NOT_SUSPENDED;
!       continue;
      }
  
!     if (!JvmtiSuspendControl::resume(java_thread)) {
!       results[i] = JVMTI_ERROR_INTERNAL;
!       continue;
      }
  
!     results[i] = JVMTI_ERROR_NONE;  // indicate successful resume
    }
-   // per-thread resume results returned via results parameter
    return JVMTI_ERROR_NONE;
! } /* end ResumeThreadList */
  
  
  // java_thread - protected by ThreadsListHandle and pre-checked
  jvmtiError
  JvmtiEnv::StopThread(JavaThread* java_thread, jobject exception) {
--- 938,213 ---
    *threads_ptr = jthreads;
    return JVMTI_ERROR_NONE;
  } /* end GetAllThreads */
  
  
  jvmtiError
! 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 (java_thread != NULL && java_thread == JavaThread::current()) {
!     // current thread will be suspended in the ~JvmtiVTMTDisabler
!     vtmt_disabler.set_self_suspend();
    }
!   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) {
!   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++) {
!     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) {
!       if (thread_oop == NULL || err != JVMTI_ERROR_INVALID_THREAD) {
!         results[i] = err;
          continue;
        }
      }
!     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 */
  
  
  jvmtiError
! 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]);
+     }
    }
! 
!   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);
+     }
    }
!   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++) {
!     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) {
!       if (thread_oop == NULL || err != JVMTI_ERROR_INVALID_THREAD) {
!         results[i] = err;
!         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]);
      }
+   }
  
!   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();
  
!   // 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);
+     }
    }
    return JVMTI_ERROR_NONE;
! } /* end ResumeAllVirtualThreads */
  
  
  // java_thread - protected by ThreadsListHandle and pre-checked
  jvmtiError
  JvmtiEnv::StopThread(JavaThread* java_thread, jobject exception) {

*** 1077,75 ***
    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;
    ThreadsListHandle tlh(current_thread);
!   jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, NULL);
    if (err != JVMTI_ERROR_NONE) {
      return err;
    }
    // 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_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);
  
    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();
      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.
        if (thread_oop == NULL) {
          return err;
        }
-       // 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());
  
    oop loader = java_lang_Thread::context_class_loader(thread_obj());
    context_class_loader = Handle(current_thread, loader);
  
    { const char *n;
  
      if (name() != NULL) {
--- 1156,114 ---
    return JVMTI_ERROR_NONE;
  
  } /* end StopThread */
  
  
  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 = 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(thread_obj, true);
    java_thread->interrupt();
  
    return JVMTI_ERROR_NONE;
  } /* end InterruptThread */
  
  
  // 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
    if (thread == NULL) {
!     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 {
      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.
  
    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()));
! 
!   // 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 ***
    }
    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);
    info_ptr->thread_group = jni_reference(thread_group);
  
    return JVMTI_ERROR_NONE;
  } /* end GetThreadInfo */
  
  
! // java_thread - protected by ThreadsListHandle and pre-checked
  // 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) {
    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;
-   }
  
    // 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();
    }
    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
--- 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);
    info_ptr->thread_group = jni_reference(thread_group);
  
    return JVMTI_ERROR_NONE;
  } /* end GetThreadInfo */
  
  
! // Threads_lock NOT held
  // owned_monitor_count_ptr - pre-checked for NULL
  // owned_monitors_ptr - pre-checked for NULL
  jvmtiError
! JvmtiEnv::GetOwnedMonitorInfo(jthread thread, jint* owned_monitor_count_ptr, jobject** owned_monitors_ptr) {
    jvmtiError err = JVMTI_ERROR_NONE;
    JavaThread* calling_thread = JavaThread::current();
!   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);
  
! 
!   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(jobject *),
                        (unsigned char**)owned_monitors_ptr)) == JVMTI_ERROR_NONE) {
        // copy into the returned array

*** 1219,42 ***
  
    return err;
  } /* end GetOwnedMonitorInfo */
  
  
! // java_thread - protected by ThreadsListHandle and pre-checked
  // 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) {
    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;
-   }
  
    // 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();
    }
  
    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) {
        // 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 =
--- 1365,67 ---
  
    return err;
  } /* end GetOwnedMonitorInfo */
  
  
! // Threads_lock NOT held
  // monitor_info_count_ptr - pre-checked for NULL
  // monitor_info_ptr - pre-checked for NULL
  jvmtiError
! JvmtiEnv::GetOwnedMonitorStackDepthInfo(jthread thread, jint* monitor_info_count_ptr, jvmtiMonitorStackDepthInfo** monitor_info_ptr) {
    jvmtiError err = JVMTI_ERROR_NONE;
    JavaThread* calling_thread = JavaThread::current();
!   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);
  
!   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) {
        // 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 ***
  
    return err;
  } /* end GetOwnedMonitorStackDepthInfo */
  
  
! // java_thread - protected by ThreadsListHandle and pre-checked
  // monitor_ptr - pre-checked for NULL
  jvmtiError
! JvmtiEnv::GetCurrentContendedMonitor(JavaThread* java_thread, jobject* monitor_ptr) {
    jvmtiError err = JVMTI_ERROR_NONE;
    JavaThread* calling_thread = JavaThread::current();
  
!   // 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_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);
--- 1443,52 ---
  
    return err;
  } /* end GetOwnedMonitorStackDepthInfo */
  
  
! // Threads_lock NOT held
  // monitor_ptr - pre-checked for NULL
  jvmtiError
! 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;
  
!   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 ***
    }
    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();
--- 1496,10 ---

*** 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 ***
    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;
    }
  
    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
--- 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;
    ThreadPriority max_priority;
  
    name         = java_lang_ThreadGroup::name(group_obj());
    parent_group = Handle(current_thread, java_lang_ThreadGroup::parent(group_obj()));
    max_priority = java_lang_ThreadGroup::maxPriority(group_obj());
  
    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 ***
    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
  
    *group_count_ptr  = ngroups;
    *thread_count_ptr = nthreads;
    *threads_ptr     = new_jthreadArray(nthreads, thread_objs);
    *groups_ptr      = new_jthreadGroupArray(ngroups, group_objs);
--- 1630,12 ---
    ResourceMark rm(current_thread);
    HandleMark hm(current_thread);
  
    Handle group_hdl(current_thread, group_obj);
  
!   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 ***
  
    //
    // Stack Frame functions
    //
  
! // java_thread - protected by ThreadsListHandle and pre-checked
  // 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) {
    jvmtiError err = JVMTI_ERROR_NONE;
  
    // 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);
--- 1652,46 ---
  
    //
    // Stack Frame functions
    //
  
! // 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(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 ***
  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) {
      // Use direct handshake if we need to get only one stack trace.
      JavaThread *current_thread = JavaThread::current();
      ThreadsListHandle tlh(current_thread);
      JavaThread *java_thread;
!     err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), *thread_list, &java_thread, NULL);
      if (err != JVMTI_ERROR_NONE) {
        return err;
      }
  
!     GetSingleStackTraceClosure op(this, current_thread, *thread_list, max_frame_count);
      Handshake::execute(&op, java_thread);
      err = op.result();
      if (err == JVMTI_ERROR_NONE) {
        *stack_info_ptr = op.stack_info();
      }
--- 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;
!     oop thread_obj = NULL;
+     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);
+         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 ***
    }
    return err;
  } /* end GetThreadListStackTraces */
  
  
! // java_thread - protected by ThreadsListHandle and pre-checked
  // count_ptr - pre-checked for NULL
  jvmtiError
! JvmtiEnv::GetFrameCount(JavaThread* java_thread, jint* count_ptr) {
    jvmtiError err = JVMTI_ERROR_NONE;
  
!   // retrieve or create JvmtiThreadState.
!   JvmtiThreadState* state = JvmtiThreadState::state_for(java_thread);
!   if (state == NULL) {
!     return JVMTI_ERROR_THREAD_NOT_ALIVE;
    }
  
    // 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);
    } else {
      // get java stack frame count with handshake.
!     GetFrameCountClosure op(this, state, count_ptr);
      Handshake::execute(&op, java_thread);
      err = op.result();
    }
    return err;
  } /* end GetFrameCount */
--- 1775,47 ---
    }
    return err;
  } /* end GetThreadListStackTraces */
  
  
! // Threads_lock NOT held
  // count_ptr - pre-checked for NULL
  jvmtiError
! 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;
  
!   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(java_thread, count_ptr);
    } else {
      // get java stack frame count with handshake.
!     GetFrameCountClosure op(this, count_ptr);
      Handshake::execute(&op, java_thread);
      err = op.result();
    }
    return err;
  } /* end GetFrameCount */

*** 1630,17 ***
    }
    return op.result();
  } /* end PopFrame */
  
  
! // java_thread - protected by ThreadsListHandle and pre-checked
  // 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) {
    jvmtiError err = JVMTI_ERROR_NONE;
  
    // 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);
--- 1847,41 ---
    }
    return op.result();
  } /* end PopFrame */
  
  
! // 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(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 ***
    }
    return err;
  } /* end GetFrameLocation */
  
  
! // java_thread - protected by ThreadsListHandle and pre-checked
  // depth - pre-checked as non-negative
  jvmtiError
! JvmtiEnv::NotifyFramePop(JavaThread* java_thread, jint depth) {
!   JvmtiThreadState *state = JvmtiThreadState::state_for(java_thread);
    if (state == NULL) {
      return JVMTI_ERROR_THREAD_NOT_ALIVE;
    }
  
    SetFramePopClosure op(this, state, depth);
!   MutexLocker mu(JvmtiThreadState_lock);
!   if (java_thread == JavaThread::current()) {
      op.doit(java_thread, true /* self */);
    } else {
      Handshake::execute(&op, java_thread);
    }
    return op.result();
--- 1893,53 ---
    }
    return err;
  } /* end GetFrameLocation */
  
  
! // Threads_lock NOT held, java_thread not protected by lock
  // depth - pre-checked as non-negative
  jvmtiError
! 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(current, JvmtiThreadState_lock);
!   if (java_thread == current) {
      op.doit(java_thread, true /* self */);
    } else {
      Handshake::execute(&op, java_thread);
    }
    return op.result();

*** 1899,114 ***
  
    //
    // Local Variable functions
    //
  
! // java_thread - protected by ThreadsListHandle and pre-checked
  // 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) {
    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);
  
!   VM_GetOrSetLocal op(java_thread, current_thread, depth, slot);
!   VMThread::execute(&op);
!   jvmtiError err = op.result();
!   if (err != JVMTI_ERROR_NONE) {
!     return err;
    } else {
!     *value_ptr = op.value().l;
!     return JVMTI_ERROR_NONE;
    }
  } /* end GetLocalObject */
  
! // java_thread - protected by ThreadsListHandle and pre-checked
  // depth - pre-checked as non-negative
  // value - pre-checked for NULL
  jvmtiError
! JvmtiEnv::GetLocalInstance(JavaThread* java_thread, jint depth, jobject* value_ptr){
    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);
  
!   VM_GetReceiver op(java_thread, current_thread, depth);
!   VMThread::execute(&op);
!   jvmtiError err = op.result();
!   if (err != JVMTI_ERROR_NONE) {
!     return err;
    } else {
!     *value_ptr = op.value().l;
!     return JVMTI_ERROR_NONE;
    }
  } /* end GetLocalInstance */
  
  
! // java_thread - protected by ThreadsListHandle and pre-checked
  // 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) {
    // rm object is created to clean up the javaVFrame created in
    // doit_prologue(), but after doit() is finished with it.
!   ResourceMark rm;
  
!   VM_GetOrSetLocal op(java_thread, depth, slot, T_INT);
!   VMThread::execute(&op);
!   *value_ptr = op.value().i;
!   return op.result();
  } /* end GetLocalInt */
  
  
! // java_thread - protected by ThreadsListHandle and pre-checked
  // 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) {
    // rm object is created to clean up the javaVFrame created in
    // doit_prologue(), but after doit() is finished with it.
!   ResourceMark rm;
  
!   VM_GetOrSetLocal op(java_thread, depth, slot, T_LONG);
!   VMThread::execute(&op);
!   *value_ptr = op.value().j;
!   return op.result();
  } /* end GetLocalLong */
  
  
! // java_thread - protected by ThreadsListHandle and pre-checked
  // 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) {
    // rm object is created to clean up the javaVFrame created in
    // doit_prologue(), but after doit() is finished with it.
!   ResourceMark rm;
  
!   VM_GetOrSetLocal op(java_thread, depth, slot, T_FLOAT);
!   VMThread::execute(&op);
!   *value_ptr = op.value().f;
!   return op.result();
  } /* end GetLocalFloat */
  
  
! // java_thread - protected by ThreadsListHandle and pre-checked
  // 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) {
    // rm object is created to clean up the javaVFrame created in
    // doit_prologue(), but after doit() is finished with it.
!   ResourceMark rm;
  
!   VM_GetOrSetLocal op(java_thread, depth, slot, T_DOUBLE);
!   VMThread::execute(&op);
!   *value_ptr = op.value().d;
!   return op.result();
  } /* end GetLocalDouble */
  
  
  // java_thread - protected by ThreadsListHandle and pre-checked
  // depth - pre-checked as non-negative
--- 2171,252 ---
  
    //
    // Local Variable functions
    //
  
! // Threads_lock NOT held
  // depth - pre-checked as non-negative
  // value_ptr - pre-checked for NULL
  jvmtiError
! 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);
  
!   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 {
!     // 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 */
  
! // Threads_lock NOT held
  // depth - pre-checked as non-negative
  // value - pre-checked for NULL
  jvmtiError
! 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);
  
!   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 {
!     // 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 */
  
  
! // Threads_lock NOT held
  // depth - pre-checked as non-negative
  // value_ptr - pre-checked for NULL
  jvmtiError
! 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(current_thread);
+   HandleMark hm(current_thread);
+   oop thread_obj = JNIHandles::resolve_external_guard(thread);
  
!   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 */
  
  
! // Threads_lock NOT held
  // depth - pre-checked as non-negative
  // value_ptr - pre-checked for NULL
  jvmtiError
! 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(current_thread);
+   HandleMark hm(current_thread);
+   oop thread_obj = JNIHandles::resolve_external_guard(thread);
  
!   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 */
  
  
! // Threads_lock NOT held
  // depth - pre-checked as non-negative
  // value_ptr - pre-checked for NULL
  jvmtiError
! 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(current_thread);
+   HandleMark hm(current_thread);
+   oop thread_obj = JNIHandles::resolve_external_guard(thread);
  
!   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 */
  
  
! // Threads_lock NOT held
  // depth - pre-checked as non-negative
  // value_ptr - pre-checked for NULL
  jvmtiError
! 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(current_thread);
+   HandleMark hm(current_thread);
+   oop thread_obj = JNIHandles::resolve_external_guard(thread);
  
!   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 >