< prev index next >

src/hotspot/share/prims/jvmtiEnvBase.cpp

Print this page
*** 54,10 ***
--- 54,11 ---
  #include "runtime/threadSMR.hpp"
  #include "runtime/vframe.inline.hpp"
  #include "runtime/vframe_hp.hpp"
  #include "runtime/vmThread.hpp"
  #include "runtime/vmOperations.hpp"
+ #include "services/threadService.hpp"
  
  
  ///////////////////////////////////////////////////////////////
  //
  // JvmtiEnvBase

*** 557,16 ***
  }
  
  // return the vframe on the specified thread and depth, NULL if no such frame
  // The thread and the oops in the returned vframe might not have been process.
  vframe*
! JvmtiEnvBase::vframeForNoProcess(JavaThread* java_thread, jint depth) {
    if (!java_thread->has_last_Java_frame()) {
      return NULL;
    }
!   RegisterMap reg_map(java_thread, true /* update_map */, false /* process_frames */);
!   vframe *vf = java_thread->last_java_vframe(&reg_map);
    int d = 0;
    while ((vf != NULL) && (d < depth)) {
      vf = vf->java_sender();
      d++;
    }
--- 558,17 ---
  }
  
  // return the vframe on the specified thread and depth, NULL if no such frame
  // The thread and the oops in the returned vframe might not have been process.
  vframe*
! JvmtiEnvBase::vframeForNoProcess(JavaThread* java_thread, jint depth, bool for_cont) {
    if (!java_thread->has_last_Java_frame()) {
      return NULL;
    }
!   RegisterMap reg_map(java_thread, true /* update_map */, false /* process_frames */, true /* walk_cont */);
!   vframe *vf = for_cont ? JvmtiEnvBase::get_last_java_vframe(java_thread, &reg_map)
+                         : java_thread->last_java_vframe(&reg_map);
    int d = 0;
    while ((vf != NULL) && (d < depth)) {
      vf = vf->java_sender();
      d++;
    }

*** 605,10 ***
--- 607,210 ---
      found = InstanceKlass::cast(k)->find_field_from_offset(offset, false, fd);
    }
    return found;
  }
  
+ extern "C" bool dbg_is_safe(const void* p, intptr_t errvalue);
+ 
+ javaVFrame*
+ JvmtiEnvBase::check_and_skip_hidden_frames(bool is_in_VTMT, javaVFrame* jvf) {
+   // The second condition is needed to hide notification methods.
+   if (!is_in_VTMT && (jvf == NULL || !jvf->method()->jvmti_mount_transition())) {
+     return jvf; // no frames to skip
+   }
+   javaVFrame* jvf_saved = jvf;
+   // find jvf with a method annotated with @JvmtiMountTransition
+   for ( ; jvf != NULL; jvf = jvf->java_sender()) {
+     if (jvf->method()->jvmti_mount_transition()) {
+       jvf = jvf->java_sender(); // skip annotated method
+       break;
+     }
+     if (jvf->method()->changes_current_thread()) {
+       break;
+     }
+     // skip frame above annotated method
+   }
+   if (jvf == NULL) { // TMP workaround for stability until the root cause is fixed
+     jvf = jvf_saved;
+     assert (jvf != NULL, "");
+     assert (dbg_is_safe(jvf, -1), "");
+     assert (jvf->register_map() != NULL, "");
+     assert (dbg_is_safe(jvf->register_map(), -1), "");
+     jvf->restore_register_map(); // we're returning to a frame we've walked past and might walk from again
+   }
+   return jvf;
+ }
+ 
+ javaVFrame*
+ JvmtiEnvBase::check_and_skip_hidden_frames(JavaThread* jt, javaVFrame* jvf) {
+   jvf = check_and_skip_hidden_frames(jt->is_in_VTMT(), jvf);
+   return jvf;
+ }
+ 
+ javaVFrame*
+ JvmtiEnvBase::check_and_skip_hidden_frames(oop vthread, javaVFrame* jvf) {
+   JvmtiThreadState* state = java_lang_Thread::jvmti_thread_state(vthread);
+   if (state == NULL) {
+     return jvf; // nothing to skip
+   }
+   jvf = check_and_skip_hidden_frames(state->is_in_VTMT(), jvf);
+   return jvf;
+ }
+ 
+ bool
+ JvmtiEnvBase::is_vthread_alive(oop vt) {
+   assert(java_lang_VirtualThread::state(vt) != java_lang_VirtualThread::NEW, "sanity check");
+   return java_lang_VirtualThread::state(vt) != java_lang_VirtualThread::TERMINATED;
+ }
+ 
+ javaVFrame*
+ JvmtiEnvBase::get_vthread_jvf(oop vthread) {
+   assert(java_lang_VirtualThread::state(vthread) != java_lang_VirtualThread::NEW, "sanity check");
+   assert(java_lang_VirtualThread::state(vthread) != java_lang_VirtualThread::TERMINATED, "sanity check");
+ 
+   Thread* cur_thread = Thread::current();
+   oop cont = java_lang_VirtualThread::continuation(vthread);
+   javaVFrame* jvf = NULL;
+ 
+   assert(cont != NULL, "virtual thread continuation must not be NULL");
+ 
+   oop carrier_thread = java_lang_VirtualThread::carrier_thread(vthread);
+   // Returned carrier_thread can be NULL for a mounted continuation.
+   // Then treat it as an unmounted case.
+   if (jdk_internal_vm_Continuation::is_mounted(cont) && carrier_thread != NULL) {
+     JavaThread* java_thread = java_lang_Thread::thread(carrier_thread);
+ 
+     if (!java_thread->has_last_Java_frame()) {
+       // TBD: This is a temporary work around to avoid a guarantee caused by
+       // the native enterSpecial frame on the top. No frames will be found
+       // by the JVMTI functions such as GetStackTrace.
+       return NULL;
+     }
+     vframeStream vfs(java_thread, Handle(cur_thread, Continuation::continuation_scope(cont)));
+     jvf = vfs.at_end() ? NULL : vfs.asJavaVFrame();
+     jvf = check_and_skip_hidden_frames(java_thread, jvf);
+   } else {
+     vframeStream vfs(cont);
+     jvf = vfs.at_end() ? NULL : vfs.asJavaVFrame();
+     jvf = check_and_skip_hidden_frames(vthread, jvf);
+   }
+   return jvf;
+ }
+ 
+ javaVFrame*
+ JvmtiEnvBase::get_last_java_vframe(JavaThread* jt, RegisterMap* reg_map_p) {
+   // Strip vthread frames in case of carrier thread with mounted continuation.
+   javaVFrame *jvf = JvmtiEnvBase::cthread_with_continuation(jt) ?
+                         jt->vthread_carrier_last_java_vframe(reg_map_p) :
+                         jt->last_java_vframe(reg_map_p);
+   jvf = check_and_skip_hidden_frames(jt, jvf);
+   return jvf;
+ }
+ 
+ jint
+ JvmtiEnvBase::get_thread_state(oop thread_oop, JavaThread* jt) {
+   jint state = 0;
+ 
+   if (thread_oop != NULL) {
+     // get most state bits
+     state = (jint)java_lang_Thread::get_thread_status(thread_oop);
+   }
+   if (jt != NULL) {
+     // We have a JavaThread* so add more state bits.
+     JavaThreadState jts = jt->thread_state();
+ 
+     if (jt->is_thread_suspended() ||
+         (jt->vthread() == thread_oop && jt->is_suspended())) {
+       // Suspended non-virtual thread.
+       state |= JVMTI_THREAD_STATE_SUSPENDED;
+     }
+     if (jts == _thread_in_native) {
+       state |= JVMTI_THREAD_STATE_IN_NATIVE;
+     }
+     if (jt->is_interrupted(false)) {
+       state |= JVMTI_THREAD_STATE_INTERRUPTED;
+     }
+   }
+   return state;
+ }
+ 
+ jint
+ JvmtiEnvBase::get_vthread_state(oop thread_oop) {
+   jshort vt_state = java_lang_VirtualThread::state(thread_oop);
+   jint state = (jint) java_lang_VirtualThread::map_state_to_thread_status(vt_state);
+   bool ext_suspended = JvmtiVTSuspender::is_vthread_suspended(thread_oop);
+ 
+   if (ext_suspended && ((state & JVMTI_THREAD_STATE_ALIVE) != 0)) {
+     state &= ~java_lang_VirtualThread::RUNNING;
+     state |= JVMTI_THREAD_STATE_ALIVE | JVMTI_THREAD_STATE_RUNNABLE | JVMTI_THREAD_STATE_SUSPENDED;
+   }
+   if (java_lang_Thread::interrupted(thread_oop)) {
+     state |= JVMTI_THREAD_STATE_INTERRUPTED;
+   }
+   return state;
+ }
+ 
+ int
+ JvmtiEnvBase::get_live_threads(JavaThread* current_thread, Handle group_hdl, Handle **thread_objs_p) {
+   int count = 0;
+   Handle *thread_objs = NULL;
+   ThreadsListEnumerator tle(current_thread, true);
+   int nthreads = tle.num_threads();
+   if (nthreads > 0) {
+     thread_objs = NEW_RESOURCE_ARRAY(Handle, nthreads);
+     NULL_CHECK(thread_objs, JVMTI_ERROR_OUT_OF_MEMORY);
+     for (int i = 0; i < nthreads; i++) {
+       Handle thread = tle.get_threadObj(i);
+       if (thread()->is_a(vmClasses::Thread_klass()) && java_lang_Thread::threadGroup(thread()) == group_hdl()) {
+         thread_objs[count++] = thread;
+       }
+     }
+   }
+   *thread_objs_p = thread_objs;
+   return count;
+ }
+ 
+ int
+ JvmtiEnvBase::get_subgroups(JavaThread* current_thread, Handle group_hdl, Handle **group_objs_p) {
+   ObjectLocker ol(group_hdl, current_thread);
+ 
+   int ngroups  = java_lang_ThreadGroup::ngroups(group_hdl());
+   int nweaks  = java_lang_ThreadGroup::nweaks(group_hdl());
+ 
+   int count = 0;
+   Handle *group_objs = NULL;
+   if (ngroups > 0 || nweaks > 0) {
+     group_objs = NEW_RESOURCE_ARRAY(Handle, ngroups + nweaks);
+     NULL_CHECK(group_objs, JVMTI_ERROR_OUT_OF_MEMORY);
+ 
+     // strongly reachable subgroups
+     if (ngroups > 0) {
+       objArrayOop groups = java_lang_ThreadGroup::groups(group_hdl());
+       for (int j = 0; j < ngroups; j++) {
+         oop group_obj = groups->obj_at(j);
+         assert(group_obj != NULL, "group_obj != NULL");
+         group_objs[count++] = Handle(current_thread, group_obj);
+       }
+     }
+ 
+     // weakly reachable subgroups
+     if (nweaks > 0) {
+       objArrayOop weaks = java_lang_ThreadGroup::weaks(group_hdl());
+       for (int j = 0; j < nweaks; j++) {
+         oop weak_obj = weaks->obj_at(j);
+         assert(weak_obj != NULL, "weak_obj != NULL");
+         oop group_obj = java_lang_ref_Reference::unknown_referent(weak_obj);
+         if (group_obj != NULL) {
+           group_objs[count++] = Handle(current_thread, group_obj);
+         }
+       }
+     }
+   }
+   *group_objs_p = group_objs;
+   return count;
+ }
+ 
  //
  // Object Monitor Information
  //
  
  //

*** 625,14 ***
    }
  
    Thread* current_thread = Thread::current();
    ResourceMark rm(current_thread);
    HandleMark   hm(current_thread);
!   RegisterMap  reg_map(java_thread);
  
!   for(javaVFrame *jvf=java_thread->last_java_vframe(&reg_map); jvf != NULL;
!                                                  jvf = jvf->java_sender()) {
      GrowableArray<MonitorInfo*>* mons = jvf->monitors();
      if (!mons->is_empty()) {
        for (int i = 0; i < mons->length(); i++) {
          MonitorInfo *mi = mons->at(i);
          if (mi->owner_is_scalar_replaced()) continue;
--- 827,15 ---
    }
  
    Thread* current_thread = Thread::current();
    ResourceMark rm(current_thread);
    HandleMark   hm(current_thread);
!   RegisterMap  reg_map(java_thread, true, true);
  
!   for (javaVFrame *jvf = java_thread->last_java_vframe(&reg_map);
!        jvf != NULL;
+        jvf = jvf->java_sender()) {
      GrowableArray<MonitorInfo*>* mons = jvf->monitors();
      if (!mons->is_empty()) {
        for (int i = 0; i < mons->length(); i++) {
          MonitorInfo *mi = mons->at(i);
          if (mi->owner_is_scalar_replaced()) continue;

*** 645,12 ***
      }
    }
    return ret;
  }
  
- 
- 
  jvmtiError
  JvmtiEnvBase::get_current_contended_monitor(JavaThread *calling_thread, JavaThread *java_thread, jobject *monitor_ptr) {
    Thread *current_thread = Thread::current();
    assert(java_thread->is_handshake_safe_for(current_thread),
           "call by myself or at handshake");
--- 848,10 ---

*** 682,11 ***
      *monitor_ptr = jni_reference(calling_thread, hobj);
    }
    return JVMTI_ERROR_NONE;
  }
  
- 
  jvmtiError
  JvmtiEnvBase::get_owned_monitors(JavaThread *calling_thread, JavaThread* java_thread,
                                   GrowableArray<jvmtiMonitorStackDepthInfo*> *owned_monitors_list) {
    // Note:
    // calling_thread is the thread that requested the list of monitors for java_thread.
--- 883,10 ---

*** 702,11 ***
      ResourceMark rm(current_thread);
      HandleMark   hm(current_thread);
      RegisterMap  reg_map(java_thread);
  
      int depth = 0;
!     for (javaVFrame *jvf = java_thread->last_java_vframe(&reg_map); jvf != NULL;
           jvf = jvf->java_sender()) {
        if (MaxJavaStackTraceDepth == 0 || depth++ < MaxJavaStackTraceDepth) {  // check for stack too deep
          // add locked objects for this frame into list
          err = get_locked_objects_in_frame(calling_thread, java_thread, jvf, owned_monitors_list, depth-1);
          if (err != JVMTI_ERROR_NONE) {
--- 902,12 ---
      ResourceMark rm(current_thread);
      HandleMark   hm(current_thread);
      RegisterMap  reg_map(java_thread);
  
      int depth = 0;
!     for (javaVFrame *jvf = JvmtiEnvBase::get_last_java_vframe(java_thread, &reg_map);
+          jvf != NULL;
           jvf = jvf->java_sender()) {
        if (MaxJavaStackTraceDepth == 0 || depth++ < MaxJavaStackTraceDepth) {  // check for stack too deep
          // add locked objects for this frame into list
          err = get_locked_objects_in_frame(calling_thread, java_thread, jvf, owned_monitors_list, depth-1);
          if (err != JVMTI_ERROR_NONE) {

*** 722,10 ***
--- 923,40 ---
    err = jmc.error();
  
    return err;
  }
  
+ jvmtiError
+ JvmtiEnvBase::get_owned_monitors(JavaThread* calling_thread, JavaThread* java_thread, javaVFrame* jvf,
+                                  GrowableArray<jvmtiMonitorStackDepthInfo*> *owned_monitors_list) {
+   jvmtiError err = JVMTI_ERROR_NONE;
+ #ifdef ASSERT
+   uint32_t debug_bits = 0;
+ #endif
+   // assert((SafepointSynchronize::is_at_safepoint() ||
+   //         java_thread->is_thread_fully_suspended(false, &debug_bits)),
+   //        "at safepoint or target thread is suspended");
+ 
+   int depth = 0;
+   for ( ; jvf != NULL; jvf = jvf->java_sender()) {
+     if (MaxJavaStackTraceDepth == 0 || depth++ < MaxJavaStackTraceDepth) {  // check for stack too deep
+       // add locked objects for this frame into list
+       err = get_locked_objects_in_frame(calling_thread, java_thread, jvf, owned_monitors_list, depth-1);
+       if (err != JVMTI_ERROR_NONE) {
+         return err;
+       }
+     }
+   }
+ 
+   // Get off stack monitors. (e.g. acquired via jni MonitorEnter).
+   JvmtiMonitorClosure jmc(calling_thread, owned_monitors_list, this);
+   ObjectSynchronizer::monitors_iterate(&jmc, java_thread);
+   err = jmc.error();
+ 
+   return err;
+ }
+ 
  // Save JNI local handles for any objects that this frame owns.
  jvmtiError
  JvmtiEnvBase::get_locked_objects_in_frame(JavaThread* calling_thread, JavaThread* java_thread,
                                   javaVFrame *jvf, GrowableArray<jvmtiMonitorStackDepthInfo*>* owned_monitors_list, jint stack_depth) {
    jvmtiError err = JVMTI_ERROR_NONE;

*** 814,10 ***
--- 1045,72 ---
    }
  
    return err;
  }
  
+ jvmtiError
+ JvmtiEnvBase::get_stack_trace(javaVFrame *jvf,
+                               jint start_depth, jint max_count,
+                               jvmtiFrameInfo* frame_buffer, jint* count_ptr) {
+   Thread *current_thread = Thread::current();
+   ResourceMark rm(current_thread);
+   HandleMark hm(current_thread);
+   int count = 0;
+ 
+   if (start_depth != 0) {
+     if (start_depth > 0) {
+       for (int j = 0; j < start_depth && jvf != NULL; j++) {
+         jvf = jvf->java_sender();
+       }
+       if (jvf == NULL) {
+         // start_depth is deeper than the stack depth
+         return JVMTI_ERROR_ILLEGAL_ARGUMENT;
+       }
+     } else { // start_depth < 0
+       // we are referencing the starting depth based on the oldest
+       // part of the stack.
+       // optimize to limit the number of times that java_sender() is called
+       javaVFrame *jvf_cursor = jvf;
+       javaVFrame *jvf_prev = NULL;
+       javaVFrame *jvf_prev_prev = NULL;
+       int j = 0;
+       while (jvf_cursor != NULL) {
+         jvf_prev_prev = jvf_prev;
+         jvf_prev = jvf_cursor;
+         for (j = 0; j > start_depth && jvf_cursor != NULL; j--) {
+           jvf_cursor = jvf_cursor->java_sender();
+         }
+       }
+       if (j == start_depth) {
+         // previous pointer is exactly where we want to start
+         jvf = jvf_prev;
+       } else {
+         // we need to back up further to get to the right place
+         if (jvf_prev_prev == NULL) {
+           // the -start_depth is greater than the stack depth
+           return JVMTI_ERROR_ILLEGAL_ARGUMENT;
+         }
+         // j now is the number of frames on the stack starting with
+         // jvf_prev, we start from jvf_prev_prev and move older on
+         // the stack that many, the result is -start_depth frames
+         // remaining.
+         jvf = jvf_prev_prev;
+         for (; j < 0; j++) {
+           jvf = jvf->java_sender();
+         }
+       }
+     }
+   }
+   for (; count < max_count && jvf != NULL; count++) {
+     frame_buffer[count].method = jvf->method()->jmethod_id();
+     frame_buffer[count].location = (jvf->method()->is_native() ? -1 : jvf->bci());
+     jvf = jvf->java_sender();
+   }
+   *count_ptr = count;
+   return JVMTI_ERROR_NONE;
+ }
+ 
  jvmtiError
  JvmtiEnvBase::get_stack_trace(JavaThread *java_thread,
                                jint start_depth, jint max_count,
                                jvmtiFrameInfo* frame_buffer, jint* count_ptr) {
  #ifdef ASSERT

*** 826,94 ***
    Thread *current_thread = Thread::current();
    assert(SafepointSynchronize::is_at_safepoint() ||
           java_thread->is_handshake_safe_for(current_thread),
           "call by myself / at safepoint / at handshake");
    int count = 0;
    if (java_thread->has_last_Java_frame()) {
!     RegisterMap reg_map(java_thread);
      ResourceMark rm(current_thread);
!     javaVFrame *jvf = java_thread->last_java_vframe(&reg_map);
!     HandleMark hm(current_thread);
!     if (start_depth != 0) {
-       if (start_depth > 0) {
-         for (int j = 0; j < start_depth && jvf != NULL; j++) {
-           jvf = jvf->java_sender();
-         }
-         if (jvf == NULL) {
-           // start_depth is deeper than the stack depth
-           return JVMTI_ERROR_ILLEGAL_ARGUMENT;
-         }
-       } else { // start_depth < 0
-         // we are referencing the starting depth based on the oldest
-         // part of the stack.
-         // optimize to limit the number of times that java_sender() is called
-         javaVFrame *jvf_cursor = jvf;
-         javaVFrame *jvf_prev = NULL;
-         javaVFrame *jvf_prev_prev = NULL;
-         int j = 0;
-         while (jvf_cursor != NULL) {
-           jvf_prev_prev = jvf_prev;
-           jvf_prev = jvf_cursor;
-           for (j = 0; j > start_depth && jvf_cursor != NULL; j--) {
-             jvf_cursor = jvf_cursor->java_sender();
-           }
-         }
-         if (j == start_depth) {
-           // previous pointer is exactly where we want to start
-           jvf = jvf_prev;
-         } else {
-           // we need to back up further to get to the right place
-           if (jvf_prev_prev == NULL) {
-             // the -start_depth is greater than the stack depth
-             return JVMTI_ERROR_ILLEGAL_ARGUMENT;
-           }
-           // j now is the number of frames on the stack starting with
-           // jvf_prev, we start from jvf_prev_prev and move older on
-           // the stack that many, the result is -start_depth frames
-           // remaining.
-           jvf = jvf_prev_prev;
-           for (; j < 0; j++) {
-             jvf = jvf->java_sender();
-           }
-         }
-       }
-     }
-     for (; count < max_count && jvf != NULL; count++) {
-       frame_buffer[count].method = jvf->method()->jmethod_id();
-       frame_buffer[count].location = (jvf->method()->is_native() ? -1 : jvf->bci());
-       jvf = jvf->java_sender();
-     }
    } else {
      if (start_depth != 0) {
        // no frames and there is a starting depth
!       return JVMTI_ERROR_ILLEGAL_ARGUMENT;
      }
    }
!   *count_ptr = count;
    return JVMTI_ERROR_NONE;
  }
  
  jvmtiError
! JvmtiEnvBase::get_frame_count(JvmtiThreadState *state, jint *count_ptr) {
!   assert((state != NULL),
!          "JavaThread should create JvmtiThreadState before calling this method");
!   *count_ptr = state->count_frames();
    return JVMTI_ERROR_NONE;
  }
  
  jvmtiError
  JvmtiEnvBase::get_frame_location(JavaThread *java_thread, jint depth,
                                   jmethodID* method_ptr, jlocation* location_ptr) {
- #ifdef ASSERT
-   uint32_t debug_bits = 0;
- #endif
    Thread* current_thread = Thread::current();
    assert(java_thread->is_handshake_safe_for(current_thread),
           "call by myself or at handshake");
    ResourceMark rm(current_thread);
  
!   vframe *vf = vframeForNoProcess(java_thread, depth);
    if (vf == NULL) {
      return JVMTI_ERROR_NO_MORE_FRAMES;
    }
  
    // vframeFor should return a java frame. If it doesn't
--- 1119,82 ---
    Thread *current_thread = Thread::current();
    assert(SafepointSynchronize::is_at_safepoint() ||
           java_thread->is_handshake_safe_for(current_thread),
           "call by myself / at safepoint / at handshake");
    int count = 0;
+   jvmtiError err = JVMTI_ERROR_NONE;
+ 
    if (java_thread->has_last_Java_frame()) {
!     RegisterMap reg_map(java_thread, true, true);
      ResourceMark rm(current_thread);
!     javaVFrame *jvf = get_last_java_vframe(java_thread, &reg_map);
! 
!     err = get_stack_trace(jvf, start_depth, max_count, frame_buffer, count_ptr);
    } else {
+     *count_ptr = 0;
      if (start_depth != 0) {
        // no frames and there is a starting depth
!       err = JVMTI_ERROR_ILLEGAL_ARGUMENT;
      }
    }
!   return err;
+ }
+ 
+ jint
+ JvmtiEnvBase::get_frame_count(javaVFrame *jvf) {
+   int count = 0;
+ 
+   while (jvf != NULL) {
+     Method* method = jvf->method();
+     jvf = jvf->java_sender();
+     count++;
+   }
+   return count;
+ }
+ 
+ jvmtiError
+ JvmtiEnvBase::get_frame_count(JavaThread* jt, jint *count_ptr) {
+   Thread *current_thread = Thread::current();
+   assert(current_thread == jt ||
+          SafepointSynchronize::is_at_safepoint() ||
+          jt->is_handshake_safe_for(current_thread),
+          "call by myself / at safepoint / at handshake");
+ 
+   if (!jt->has_last_Java_frame()) { // no Java frames
+     *count_ptr = 0;
+   } else {
+     ResourceMark rm(current_thread);
+     RegisterMap reg_map(jt, true, true);
+     javaVFrame *jvf = get_last_java_vframe(jt, &reg_map);
+ 
+     *count_ptr = get_frame_count(jvf);
+   }
    return JVMTI_ERROR_NONE;
  }
  
  jvmtiError
! JvmtiEnvBase::get_frame_count(oop vthread_oop, jint *count_ptr) {
!   if (!JvmtiEnvBase::is_vthread_alive(vthread_oop)) {
!     return JVMTI_ERROR_THREAD_NOT_ALIVE;
!   }
+   Thread *current_thread = Thread::current();
+   ResourceMark rm(current_thread);
+   javaVFrame *jvf = JvmtiEnvBase::get_vthread_jvf(vthread_oop);
+ 
+   *count_ptr = get_frame_count(jvf);
    return JVMTI_ERROR_NONE;
  }
  
  jvmtiError
  JvmtiEnvBase::get_frame_location(JavaThread *java_thread, jint depth,
                                   jmethodID* method_ptr, jlocation* location_ptr) {
    Thread* current_thread = Thread::current();
    assert(java_thread->is_handshake_safe_for(current_thread),
           "call by myself or at handshake");
    ResourceMark rm(current_thread);
  
!   vframe *vf = vframeForNoProcess(java_thread, depth, true /* for cont */);
    if (vf == NULL) {
      return JVMTI_ERROR_NO_MORE_FRAMES;
    }
  
    // vframeFor should return a java frame. If it doesn't

*** 938,10 ***
--- 1219,99 ---
    *method_ptr = method->jmethod_id();
  
    return JVMTI_ERROR_NONE;
  }
  
+ jvmtiError
+ JvmtiEnvBase::get_frame_location(oop vthread_oop, jint depth,
+                                  jmethodID* method_ptr, jlocation* location_ptr) {
+   if (!JvmtiEnvBase::is_vthread_alive(vthread_oop)) {
+     return JVMTI_ERROR_THREAD_NOT_ALIVE;
+   }
+   Thread* cur_thread = Thread::current();
+   ResourceMark rm(cur_thread);
+   HandleMark hm(cur_thread);
+   javaVFrame *jvf = JvmtiEnvBase::get_vthread_jvf(vthread_oop);
+   int cur_depth = 0;
+ 
+   while (jvf != NULL && cur_depth < depth) {
+     Method* method = jvf->method();
+     jvf = jvf->java_sender();
+     cur_depth++;
+   }
+   assert(depth >= cur_depth, "ran out of frames too soon");
+   if (jvf == NULL) {
+     return JVMTI_ERROR_NO_MORE_FRAMES;
+   }
+   Method* method = jvf->method();
+   if (method->is_native()) {
+     *location_ptr = -1;
+   } else {
+     *location_ptr = jvf->bci();
+   }
+   *method_ptr = method->jmethod_id();
+ 
+   return JVMTI_ERROR_NONE;
+ }
+ 
+ bool
+ JvmtiEnvBase::cthread_with_mounted_vthread(JavaThread* jt) {
+   oop thread_oop = jt->threadObj();
+   assert(thread_oop != NULL, "sanity check");
+   oop mounted_vt = jt->mounted_vthread();
+ 
+   return (mounted_vt != NULL && mounted_vt != thread_oop);
+ }
+ 
+ bool
+ JvmtiEnvBase::cthread_with_continuation(JavaThread* jt) {
+   ContinuationEntry* cont = NULL;
+   if (jt->has_last_Java_frame()) {
+     cont = jt->last_continuation(java_lang_VirtualThread::vthread_scope());
+   }
+   return (cont != NULL && cthread_with_mounted_vthread(jt));
+ }
+ 
+ jvmtiError
+ JvmtiEnvBase::get_threadOop_and_JavaThread(ThreadsList* t_list, jthread thread,
+                                            JavaThread** jt_pp, oop* thread_oop_p) {
+   JavaThread* cur_thread = JavaThread::current();
+   JavaThread* java_thread = NULL;
+   oop thread_oop = NULL;
+ 
+   if (thread == NULL) {
+     java_thread = cur_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(t_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 || err != JVMTI_ERROR_INVALID_THREAD) {
+         return err;
+       }
+     }
+     if (java_thread == NULL && java_lang_VirtualThread::is_instance(thread_oop)) {
+       oop cont = java_lang_VirtualThread::continuation(thread_oop);
+       if (jdk_internal_vm_Continuation::is_mounted(cont)) {
+         oop carrier_thread = java_lang_VirtualThread::carrier_thread(thread_oop);
+         // Returned carrier_thread can be NULL for a mounted continuation.
+         if (carrier_thread != NULL) {
+           java_thread = java_lang_Thread::thread(carrier_thread);
+         }
+       }
+     }
+   }
+   *jt_pp = java_thread;
+   *thread_oop_p = thread_oop;
+   return JVMTI_ERROR_NONE;
+ }
  
  jvmtiError
  JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject object, jvmtiMonitorUsage* info_ptr) {
    assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
    Thread* current_thread = VMThread::vm_thread();

*** 996,11 ***
  
      if (owner != NULL) {
        // This monitor is owned so we have to find the owning JavaThread.
        owning_thread = Threads::owning_thread_from_monitor_owner(tlh.list(), owner);
        assert(owning_thread != NULL, "owning JavaThread must not be NULL");
!       Handle     th(current_thread, owning_thread->threadObj());
        ret.owner = (jthread)jni_reference(calling_thread, th);
      }
  
      if (owning_thread != NULL) {  // monitor is owned
        // The recursions field of a monitor does not reflect recursions
--- 1366,11 ---
  
      if (owner != NULL) {
        // This monitor is owned so we have to find the owning JavaThread.
        owning_thread = Threads::owning_thread_from_monitor_owner(tlh.list(), owner);
        assert(owning_thread != NULL, "owning JavaThread must not be NULL");
!       Handle     th(current_thread, get_vthread_or_thread_oop(owning_thread));
        ret.owner = (jthread)jni_reference(calling_thread, th);
      }
  
      if (owning_thread != NULL) {  // monitor is owned
        // The recursions field of a monitor does not reflect recursions

*** 1059,11 ***
            // robustness: the pending list has gotten smaller
            nWant = wantList->length();
          }
          for (int i = 0; i < nWant; i++) {
            JavaThread *pending_thread = wantList->at(i);
!           Handle th(current_thread, pending_thread->threadObj());
            ret.waiters[i] = (jthread)jni_reference(calling_thread, th);
          }
        }
        if (nWait > 0) {
          // we have threads in Object.wait()
--- 1429,11 ---
            // robustness: the pending list has gotten smaller
            nWant = wantList->length();
          }
          for (int i = 0; i < nWant; i++) {
            JavaThread *pending_thread = wantList->at(i);
!           Handle th(current_thread, get_vthread_or_thread_oop(pending_thread));
            ret.waiters[i] = (jthread)jni_reference(calling_thread, th);
          }
        }
        if (nWait > 0) {
          // we have threads in Object.wait()

*** 1078,11 ***
            JavaThread *w = mon->thread_of_waiter(waiter);
            if (w != NULL) {
              // If the thread was found on the ObjectWaiter list, then
              // it has not been notified. This thread can't change the
              // state of the monitor so it doesn't need to be suspended.
!             Handle th(current_thread, w->threadObj());
              ret.waiters[offset + j] = (jthread)jni_reference(calling_thread, th);
              ret.notify_waiters[j++] = (jthread)jni_reference(calling_thread, th);
            }
            waiter = mon->next_waiter(waiter);
          }
--- 1448,11 ---
            JavaThread *w = mon->thread_of_waiter(waiter);
            if (w != NULL) {
              // If the thread was found on the ObjectWaiter list, then
              // it has not been notified. This thread can't change the
              // state of the monitor so it doesn't need to be suspended.
!             Handle th(current_thread, get_vthread_or_thread_oop(w));
              ret.waiters[offset + j] = (jthread)jni_reference(calling_thread, th);
              ret.notify_waiters[j++] = (jthread)jni_reference(calling_thread, th);
            }
            waiter = mon->next_waiter(waiter);
          }

*** 1101,10 ***
--- 1471,156 ---
    *info_ptr = ret;
  
    return JVMTI_ERROR_NONE;
  }
  
+ jvmtiError
+ JvmtiEnvBase::check_thread_list(jint count, const jthread* list) {
+   if (list == NULL && count != 0) {
+     return JVMTI_ERROR_NULL_POINTER;
+   }
+   for (int i = 0; i < count; i++) {
+     jthread thread = list[i];
+     oop thread_oop = JNIHandles::resolve_external_guard(thread);
+     if (thread_oop == NULL || !thread_oop->is_a(vmClasses::VirtualThread_klass())) {
+       return JVMTI_ERROR_INVALID_THREAD;
+     }
+   }
+   return JVMTI_ERROR_NONE;
+ }
+ 
+ bool
+ JvmtiEnvBase::is_in_thread_list(jint count, const jthread* list, oop jt_oop) {
+   for (int idx = 0; idx < count; idx++) {
+     jthread thread = list[idx];
+     oop thread_oop = JNIHandles::resolve_external_guard(thread);
+     if (thread_oop == jt_oop) {
+       return true;
+     }
+   }
+   return false;
+ }
+ 
+ jvmtiError
+ JvmtiEnvBase::suspend_thread(oop thread_oop, JavaThread* java_thread, bool single_suspend,
+                              int* need_safepoint_p) {
+   JavaThread* current = JavaThread::current();
+   HandleMark hm(current);
+   Handle thread_h(current, thread_oop);
+   bool is_virtual = java_lang_VirtualThread::is_instance(thread_h());
+ 
+   if (is_virtual) {
+     if (single_suspend) {
+       if (JvmtiVTSuspender::is_vthread_suspended(thread_h())) {
+         return JVMTI_ERROR_THREAD_SUSPENDED;
+       }
+       JvmtiVTSuspender::register_vthread_suspend(thread_h());
+       // Check if virtual thread is mounted and there is a java_thread.
+       // A non-NULL java_thread is always passed in the !single_suspend case.
+       oop carrier_thread = java_lang_VirtualThread::carrier_thread(thread_h());
+       java_thread = carrier_thread == NULL ? NULL : java_lang_Thread::thread(carrier_thread);
+     }
+     // The java_thread can be still blocked in VTMT transition after a previous JVMTI resume call.
+     // There is no need to suspend the java_thread in this case. After vthread unblocking,
+     // it will check for ext_suspend request and suspend itself if necessary.
+     if (java_thread == NULL || java_thread->is_suspended()) {
+       // We are done if the virtual thread is unmounted or
+       // the java_thread is externally suspended.
+       return JVMTI_ERROR_NONE;
+     }
+     // The virtual thread is mounted: suspend the java_thread.
+   }
+   // Don't allow hidden thread suspend request.
+   if (java_thread->is_hidden_from_external_view()) {
+     return JVMTI_ERROR_NONE;
+   }
+   // A case of non-virtual thread.
+   if (!is_virtual) {
+     // Thread.suspend() is used in some tests. It sets jt->is_suspended() only.
+     if (java_thread->is_thread_suspended() ||
+         (thread_h() == java_thread->vthread() && java_thread->is_suspended())) {
+       return JVMTI_ERROR_THREAD_SUSPENDED;
+     }
+     java_thread->set_thread_suspended();
+   }
+   assert(JvmtiVTMTDisabler::VTMT_count() == 0, "must be 0");
+   assert(!java_thread->is_in_VTMT(), "sanity check");
+ 
+   if (java_thread == current) {
+     // java_thread will be suspended in the ~JvmtiVTMTDisabler.
+     return JVMTI_ERROR_NONE;
+   }
+   assert(!single_suspend || (!is_virtual && java_thread->is_thread_suspended()) ||
+           (is_virtual && JvmtiVTSuspender::is_vthread_suspended(thread_h())),
+          "sanity check");
+ 
+   if (is_virtual || thread_h() == java_thread->vthread()) {
+     assert(single_suspend || is_virtual, "SuspendAllVirtualThreads should never suspend non-virtual threads");
+     // Case of mounted virtual or attached carrier thread.
+     if (!JvmtiSuspendControl::suspend(java_thread)) {
+       // Thread is already suspended or in process of exiting.
+       if (java_thread->is_exiting()) {
+         // The thread was in the process of exiting.
+         return JVMTI_ERROR_THREAD_NOT_ALIVE;
+       }
+     }
+   }
+   return JVMTI_ERROR_NONE;
+ }
+ 
+ jvmtiError
+ JvmtiEnvBase::resume_thread(oop thread_oop, JavaThread* java_thread, bool single_suspend) {
+   JavaThread* current = JavaThread::current();
+   HandleMark hm(current);
+   Handle thread_h(current, thread_oop);
+   bool is_virtual = java_lang_VirtualThread::is_instance(thread_h());
+ 
+   if (is_virtual) {
+     if (single_suspend) {
+       if (!JvmtiVTSuspender::is_vthread_suspended(thread_h())) {
+         return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
+       }
+       JvmtiVTSuspender::register_vthread_resume(thread_h());
+       // Check if virtual thread is mounted and there is a java_thread.
+       // A non-NULL java_thread is always passed in the !single_suspend case.
+       oop carrier_thread = java_lang_VirtualThread::carrier_thread(thread_h());
+       java_thread = carrier_thread == NULL ? NULL : java_lang_Thread::thread(carrier_thread);
+     }
+     // The java_thread can be still blocked in VTMT transition after a previous JVMTI suspend call.
+     // There is no need to resume the java_thread in this case. After vthread unblocking,
+     // it will check for is_vthread_suspended request and remain resumed if necessary.
+     if (java_thread == NULL || !java_thread->is_suspended()) {
+       // We are done if the virtual thread is unmounted or
+       // the java_thread is not externally suspended.
+       return JVMTI_ERROR_NONE;
+     }
+     // The virtual thread is mounted and java_thread is supended: resume the java_thread.
+   }
+   // Don't allow hidden thread resume request.
+   if (java_thread->is_hidden_from_external_view()) {
+     return JVMTI_ERROR_NONE;
+   }
+   // A case of a non-virtual thread.
+   if (!is_virtual) {
+     if (!java_thread->is_thread_suspended() &&
+         (thread_h() == java_thread->vthread() && !java_thread->is_suspended())) {
+       return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
+     }
+     java_thread->clear_thread_suspended();
+   }
+   assert(!java_thread->is_in_VTMT(), "sanity check");
+   if (is_virtual || thread_h() == java_thread->vthread()) {
+     assert(single_suspend || is_virtual, "ResumeAllVirtualThreads should never resume non-virtual threads");
+     if (java_thread->is_suspended()) {
+       if (!JvmtiSuspendControl::resume(java_thread)) {
+         return JVMTI_ERROR_INTERNAL;
+       }
+     }
+   }
+   return JVMTI_ERROR_NONE;
+ }
+ 
  ResourceTracker::ResourceTracker(JvmtiEnv* env) {
    _env = env;
    _allocations = new (ResourceObj::C_HEAP, mtServiceability) GrowableArray<unsigned char*>(20, mtServiceability);
    _failed = false;
  }

*** 1147,60 ***
  struct StackInfoNode {
    struct StackInfoNode *next;
    jvmtiStackInfo info;
  };
  
  // Create a jvmtiStackInfo inside a linked list node and create a
  // buffer for the frame information, both allocated as resource objects.
  // Fill in both the jvmtiStackInfo and the jvmtiFrameInfo.
  // Note that either or both of thr and thread_oop
  // may be null if the thread is new or has exited.
  void
  MultipleStackTracesCollector::fill_frames(jthread jt, JavaThread *thr, oop thread_oop) {
  #ifdef ASSERT
    Thread *current_thread = Thread::current();
    assert(SafepointSynchronize::is_at_safepoint() ||
           thr->is_handshake_safe_for(current_thread),
!          "call by myself / at safepoint / at handshake");
  #endif
  
    jint state = 0;
    struct StackInfoNode *node = NEW_RESOURCE_OBJ(struct StackInfoNode);
    jvmtiStackInfo *infop = &(node->info);
    node->next = head();
    set_head(node);
    infop->frame_count = 0;
    infop->thread = jt;
  
!   if (thread_oop != NULL) {
!     // get most state bits
!     state = (jint)java_lang_Thread::get_thread_status(thread_oop);
-   }
  
!   if (thr != NULL) {    // add more state bits if there is a JavaThead to query
!     if (thr->is_suspended()) {
!       state |= JVMTI_THREAD_STATE_SUSPENDED;
!     }
!     JavaThreadState jts = thr->thread_state();
-     if (jts == _thread_in_native) {
-       state |= JVMTI_THREAD_STATE_IN_NATIVE;
-     }
-     if (thr->is_interrupted(false)) {
-       state |= JVMTI_THREAD_STATE_INTERRUPTED;
      }
-   }
-   infop->state = state;
- 
-   if (thr != NULL && (state & JVMTI_THREAD_STATE_ALIVE) != 0) {
-     infop->frame_buffer = NEW_RESOURCE_ARRAY(jvmtiFrameInfo, max_frame_count());
-     env()->get_stack_trace(thr, 0, max_frame_count(),
-                            infop->frame_buffer, &(infop->frame_count));
    } else {
!     infop->frame_buffer = NULL;
!     infop->frame_count = 0;
    }
    _frame_count_total += infop->frame_count;
  }
  
  // Based on the stack information in the linked list, allocate memory
  // block to return and fill it from the info in the linked list.
  void
--- 1663,56 ---
  struct StackInfoNode {
    struct StackInfoNode *next;
    jvmtiStackInfo info;
  };
  
+ 
  // Create a jvmtiStackInfo inside a linked list node and create a
  // buffer for the frame information, both allocated as resource objects.
  // Fill in both the jvmtiStackInfo and the jvmtiFrameInfo.
  // Note that either or both of thr and thread_oop
  // may be null if the thread is new or has exited.
  void
  MultipleStackTracesCollector::fill_frames(jthread jt, JavaThread *thr, oop thread_oop) {
  #ifdef ASSERT
    Thread *current_thread = Thread::current();
    assert(SafepointSynchronize::is_at_safepoint() ||
+          thr == NULL ||
           thr->is_handshake_safe_for(current_thread),
!          "unmounted virtual thread / call by myself / at safepoint / at handshake");
  #endif
  
    jint state = 0;
    struct StackInfoNode *node = NEW_RESOURCE_OBJ(struct StackInfoNode);
    jvmtiStackInfo *infop = &(node->info);
+ 
    node->next = head();
    set_head(node);
    infop->frame_count = 0;
+   infop->frame_buffer = NULL;
    infop->thread = jt;
  
!   // Support for virtual threads
!   if (java_lang_VirtualThread::is_instance(thread_oop)) {
!     state = JvmtiEnvBase::get_vthread_state(thread_oop);
  
!     if ((state & JVMTI_THREAD_STATE_ALIVE) != 0) {
!       javaVFrame *jvf = JvmtiEnvBase::get_vthread_jvf(thread_oop);
!       infop->frame_buffer = NEW_RESOURCE_ARRAY(jvmtiFrameInfo, max_frame_count());
!       _result = env()->get_stack_trace(jvf, 0, max_frame_count(),
!                                      infop->frame_buffer, &(infop->frame_count));
      }
    } else {
!     state = JvmtiEnvBase::get_thread_state(thread_oop, thr);
!     if (thr != NULL && (state & JVMTI_THREAD_STATE_ALIVE) != 0) {
+       infop->frame_buffer = NEW_RESOURCE_ARRAY(jvmtiFrameInfo, max_frame_count());
+       _result = env()->get_stack_trace(thr, 0, max_frame_count(),
+                                        infop->frame_buffer, &(infop->frame_count));
+     }
    }
    _frame_count_total += infop->frame_count;
+   infop->state = state;
  }
  
  // Based on the stack information in the linked list, allocate memory
  // block to return and fill it from the info in the linked list.
  void

*** 1250,10 ***
--- 1762,12 ---
      jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), jt, &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) {
          _collector.set_result(err);
          return;
        }
        // We have a valid thread_oop.

*** 1263,18 ***
    _collector.allocate_and_fill_stacks(_thread_count);
  }
  
  void
  GetSingleStackTraceClosure::do_thread(Thread *target) {
!   JavaThread *jt = JavaThread::cast(target);
!   oop thread_oop = jt->threadObj();
  
!   if (!jt->is_exiting() && thread_oop != NULL) {
!     ResourceMark rm;
!     _collector.fill_frames(_jthread, jt, thread_oop);
!     _collector.allocate_and_fill_stacks(1);
!   }
  }
  
  void
  VM_GetAllStackTraces::doit() {
    assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
--- 1777,18 ---
    _collector.allocate_and_fill_stacks(_thread_count);
  }
  
  void
  GetSingleStackTraceClosure::do_thread(Thread *target) {
!     JavaThread *jt = JavaThread::cast(target);
!     oop thread_oop = jt->threadObj();
  
!     if (!jt->is_exiting() && thread_oop != NULL) {
!         ResourceMark rm;
!         _collector.fill_frames(_jthread, jt, thread_oop);
!         _collector.allocate_and_fill_stacks(1);
!     }
  }
  
  void
  VM_GetAllStackTraces::doit() {
    assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");

*** 1612,11 ***
  void
  SetFramePopClosure::doit(Thread *target, bool self) {
    ResourceMark rm;
    JavaThread* java_thread = JavaThread::cast(target);
  
!   assert(_state->get_thread() == java_thread, "Must be");
  
    if (!self && !java_thread->is_suspended()) {
      _result = JVMTI_ERROR_THREAD_NOT_SUSPENDED;
      return;
    }
--- 2126,12 ---
  void
  SetFramePopClosure::doit(Thread *target, bool self) {
    ResourceMark rm;
    JavaThread* java_thread = JavaThread::cast(target);
  
!   // TBD: This might need to be corrected for detached carrier and virtual threads.
+   assert(_state->get_thread_or_saved() == java_thread, "Must be");
  
    if (!self && !java_thread->is_suspended()) {
      _result = JVMTI_ERROR_THREAD_NOT_SUSPENDED;
      return;
    }

*** 1624,11 ***
    vframe *vf = JvmtiEnvBase::vframeForNoProcess(java_thread, _depth);
    if (vf == NULL) {
      _result = JVMTI_ERROR_NO_MORE_FRAMES;
      return;
    }
! 
    if (!vf->is_java_frame() || ((javaVFrame*) vf)->method()->is_native()) {
      _result = JVMTI_ERROR_OPAQUE_FRAME;
      return;
    }
  
--- 2139,11 ---
    vframe *vf = JvmtiEnvBase::vframeForNoProcess(java_thread, _depth);
    if (vf == NULL) {
      _result = JVMTI_ERROR_NO_MORE_FRAMES;
      return;
    }
!   vf = JvmtiEnvBase::check_and_skip_hidden_frames(java_thread, (javaVFrame*)vf);
    if (!vf->is_java_frame() || ((javaVFrame*) vf)->method()->is_native()) {
      _result = JVMTI_ERROR_OPAQUE_FRAME;
      return;
    }
  

*** 1659,26 ***
                                                                      jt,
                                                                      _owned_monitor_ptr);
    }
  }
  
  void
  GetStackTraceClosure::do_thread(Thread *target) {
    JavaThread *jt = JavaThread::cast(target);
    if (!jt->is_exiting() && jt->threadObj() != NULL) {
      _result = ((JvmtiEnvBase *)_env)->get_stack_trace(jt,
                                                        _start_depth, _max_count,
                                                        _frame_buffer, _count_ptr);
    }
  }
  
  void
  GetFrameCountClosure::do_thread(Thread *target) {
!   JavaThread* jt = _state->get_thread();
    assert(target == jt, "just checking");
    if (!jt->is_exiting() && jt->threadObj() != NULL) {
!     _result = ((JvmtiEnvBase*)_env)->get_frame_count(_state, _count_ptr);
    }
  }
  
  void
  GetFrameLocationClosure::do_thread(Thread *target) {
--- 2174,90 ---
                                                                      jt,
                                                                      _owned_monitor_ptr);
    }
  }
  
+ void
+ VM_VThreadGetStackTrace::doit() {
+   if (!JvmtiEnvBase::is_vthread_alive(_vthread_h())) {
+     _result = JVMTI_ERROR_THREAD_NOT_ALIVE;
+     return;
+   }
+   ResourceMark rm;
+   javaVFrame* jvf = JvmtiEnvBase::get_vthread_jvf(_vthread_h());
+ 
+   _result = ((JvmtiEnvBase *)_env)->get_stack_trace(jvf,
+                                                     _start_depth, _max_count,
+                                                     _frame_buffer, _count_ptr);
+ }
+ 
  void
  GetStackTraceClosure::do_thread(Thread *target) {
    JavaThread *jt = JavaThread::cast(target);
    if (!jt->is_exiting() && jt->threadObj() != NULL) {
      _result = ((JvmtiEnvBase *)_env)->get_stack_trace(jt,
                                                        _start_depth, _max_count,
                                                        _frame_buffer, _count_ptr);
    }
  }
  
+ #ifdef ASSERT
+ void
+ PrintStackTraceClosure::do_thread_impl(Thread *target) {
+   JavaThread *java_thread = JavaThread::cast(target);
+   Thread *current_thread = Thread::current();
+ 
+   ResourceMark rm (current_thread);
+   const char* tname = JvmtiTrace::safe_get_thread_name(java_thread);
+   oop t_oop = java_thread->mounted_vthread();
+   t_oop = t_oop == NULL ? java_thread->threadObj() : t_oop;
+   bool is_vt_suspended = java_lang_VirtualThread::is_instance(t_oop) && JvmtiVTSuspender::is_vthread_suspended(t_oop);
+ 
+   tty->print_cr("%s(%s) exiting: %d is_susp: %d is_thread_susp: %d is_vthread_susp: %d is_VTMT_disabler: %d, is_in_VTMT = %d",
+                 tname, java_thread->name(), java_thread->is_exiting(),
+                 java_thread->is_suspended(), java_thread->is_thread_suspended(), is_vt_suspended,
+                 java_thread->is_VTMT_disabler(), java_thread->is_in_VTMT());
+ 
+   if (java_thread->has_last_Java_frame()) {
+     RegisterMap reg_map(java_thread, true, true);
+     ResourceMark rm(current_thread);
+     HandleMark hm(current_thread);
+     javaVFrame *jvf = JvmtiEnvBase::get_last_java_vframe(java_thread, &reg_map);
+     while (jvf != NULL) {
+       tty->print_cr("  %s:%d",
+                     jvf->method()->external_name(),
+                     jvf->method()->line_number_from_bci(jvf->bci()));
+       jvf = jvf->java_sender();
+     }
+   }
+   tty->print_cr("");
+ }
+ 
+ void
+ PrintStackTraceClosure::do_thread(Thread *target) {
+   JavaThread *java_thread = JavaThread::cast(target);
+   Thread *current_thread = Thread::current();
+ 
+   assert(SafepointSynchronize::is_at_safepoint() ||
+       java_thread->is_handshake_safe_for(current_thread),
+          "call by myself / at safepoint / at handshake");
+ 
+   PrintStackTraceClosure::do_thread_impl(target);
+ }
+ #endif
+ 
+ void
+ VM_VThreadGetFrameCount::doit() {
+   _result = ((JvmtiEnvBase*)_env)->get_frame_count(_vthread_h(), _count_ptr);
+ }
+ 
  void
  GetFrameCountClosure::do_thread(Thread *target) {
!   JavaThread* jt = JavaThread::cast(target);
    assert(target == jt, "just checking");
    if (!jt->is_exiting() && jt->threadObj() != NULL) {
!     _result = ((JvmtiEnvBase*)_env)->get_frame_count(jt, _count_ptr);
    }
  }
  
  void
  GetFrameLocationClosure::do_thread(Thread *target) {

*** 1686,5 ***
--- 2265,95 ---
    if (!jt->is_exiting() && jt->threadObj() != NULL) {
      _result = ((JvmtiEnvBase*)_env)->get_frame_location(jt, _depth,
                                                          _method_ptr, _location_ptr);
    }
  }
+ 
+ void
+ VThreadGetOwnedMonitorInfoClosure::do_thread(Thread *target) {
+   if (!JvmtiEnvBase::is_vthread_alive(_vthread_h())) {
+     _result = JVMTI_ERROR_THREAD_NOT_ALIVE;
+     return;
+   }
+   JavaThread* java_thread = JavaThread::cast(target);
+   Thread* cur_thread = Thread::current();
+   ResourceMark rm(cur_thread);
+   HandleMark hm(cur_thread);
+ 
+   javaVFrame *jvf = JvmtiEnvBase::get_vthread_jvf(_vthread_h());
+ 
+   if (!java_thread->is_exiting() && java_thread->threadObj() != NULL) {
+     _result = ((JvmtiEnvBase *)_env)->get_owned_monitors((JavaThread*)target,
+                                                          java_thread,
+                                                          jvf,
+                                                          _owned_monitors_list);
+   }
+ }
+ 
+ void
+ VThreadGetCurrentContendedMonitorClosure::do_thread(Thread *target) {
+   JavaThread* java_thread = JavaThread::cast(target);
+ 
+   if (!java_thread->is_exiting() && java_thread->threadObj() != NULL) {
+     _result = ((JvmtiEnvBase *)_env)->get_current_contended_monitor((JavaThread*)target,
+                                                                     java_thread,
+                                                                     _owned_monitor_ptr);
+   }
+ }
+ 
+ void
+ VThreadGetThreadClosure::do_thread(Thread *target) {
+   oop carrier_thread = java_lang_VirtualThread::carrier_thread(_vthread_h());
+   *_carrier_thread_ptr = (jthread)JNIHandles::make_local(target, carrier_thread);}
+ 
+ void
+ VThreadGetStackTraceClosure::do_thread(Thread *target) {
+   assert(target->is_Java_thread(), "just checking");
+   if (!JvmtiEnvBase::is_vthread_alive(_vthread_h())) {
+     _result = JVMTI_ERROR_THREAD_NOT_ALIVE;
+     return;
+   }
+   Thread* cur_thread = Thread::current();
+   ResourceMark rm(cur_thread);
+   HandleMark hm(cur_thread);
+ 
+   javaVFrame *jvf = JvmtiEnvBase::get_vthread_jvf(_vthread_h());
+   _result = ((JvmtiEnvBase *)_env)->get_stack_trace(jvf,
+                                                     _start_depth, _max_count,
+                                                     _frame_buffer, _count_ptr);
+ }
+ 
+ void
+ VThreadGetFrameCountClosure::do_thread(Thread *target) {
+   assert(target->is_Java_thread(), "just checking");
+   _result = ((JvmtiEnvBase*)_env)->get_frame_count(_vthread_h(), _count_ptr);
+ }
+ 
+ void
+ VThreadGetFrameLocationClosure::do_thread(Thread *target) {
+   assert(target->is_Java_thread(), "just checking");
+   _result = ((JvmtiEnvBase*)_env)->get_frame_location(_vthread_h(), _depth,
+                                                       _method_ptr, _location_ptr);
+ }
+ 
+ void
+ VThreadGetThreadStateClosure::do_thread(Thread *target) {
+   assert(target->is_Java_thread(), "just checking");
+   jshort vthread_state = java_lang_VirtualThread::state(_vthread_h());
+   oop carrier_thread_oop = java_lang_VirtualThread::carrier_thread(_vthread_h());
+   jint state;
+ 
+   if (vthread_state == java_lang_VirtualThread::RUNNING && carrier_thread_oop != NULL) {
+     state = (jint) java_lang_Thread::get_thread_status(carrier_thread_oop);
+     JavaThread* java_thread = java_lang_Thread::thread(carrier_thread_oop);
+     if (java_thread->is_suspended()) {
+       state |= JVMTI_THREAD_STATE_SUSPENDED;
+     }
+   } else {
+     state = (jint) java_lang_VirtualThread::map_state_to_thread_status(vthread_state);
+   }
+   if (java_lang_Thread::interrupted(_vthread_h())) {
+     state |= JVMTI_THREAD_STATE_INTERRUPTED;
+   }
+   *_state_ptr = state;
+   _result = JVMTI_ERROR_NONE;
+ }
< prev index next >