< prev index next >

src/hotspot/share/prims/jvmtiExtensions.cpp

Print this page
*** 21,21 ***
   * questions.
   *
   */
  
  #include "precompiled.hpp"
  #include "prims/jvmtiExport.hpp"
  #include "prims/jvmtiExtensions.hpp"
  
  // the list of extension functions
  GrowableArray<jvmtiExtensionFunctionInfo*>* JvmtiExtensions::_ext_functions;
  
  // the list of extension events
  GrowableArray<jvmtiExtensionEventInfo*>* JvmtiExtensions::_ext_events;
  
  
! // extension function
  static jvmtiError JNICALL IsClassUnloadingEnabled(const jvmtiEnv* env, ...) {
    jboolean* enabled = NULL;
    va_list ap;
  
    va_start(ap, env);
--- 21,28 ---
   * questions.
   *
   */
  
  #include "precompiled.hpp"
+ #include "classfile/javaClasses.inline.hpp"
  #include "prims/jvmtiExport.hpp"
  #include "prims/jvmtiExtensions.hpp"
+ #include "prims/jvmtiThreadState.inline.hpp"
+ #include "runtime/interfaceSupport.inline.hpp"
+ #include "runtime/handles.inline.hpp"
+ #include "runtime/jniHandles.inline.hpp"
  
  // the list of extension functions
  GrowableArray<jvmtiExtensionFunctionInfo*>* JvmtiExtensions::_ext_functions;
  
  // the list of extension events
  GrowableArray<jvmtiExtensionEventInfo*>* JvmtiExtensions::_ext_events;
  
  
! /*
+  * Extension Functions
+  */
  static jvmtiError JNICALL IsClassUnloadingEnabled(const jvmtiEnv* env, ...) {
    jboolean* enabled = NULL;
    va_list ap;
  
    va_start(ap, env);

*** 47,49 ***
    }
    *enabled = (jboolean)ClassUnloading;
    return JVMTI_ERROR_NONE;
  }
  
  // register extension functions and events. In this implementation we
  // have a single extension function (to prove the API) that tests if class
  // unloading is enabled or disabled. We also have a single extension event
  // EXT_EVENT_CLASS_UNLOAD which is used to provide the JVMDI_EVENT_CLASS_UNLOAD
  // event. The function and the event are registered here.
  //
  void JvmtiExtensions::register_extensions() {
    _ext_functions = new (ResourceObj::C_HEAP, mtServiceability) GrowableArray<jvmtiExtensionFunctionInfo*>(1, mtServiceability);
    _ext_events = new (ResourceObj::C_HEAP, mtServiceability) GrowableArray<jvmtiExtensionEventInfo*>(1, mtServiceability);
  
!   // register our extension function
!   static jvmtiParamInfo func_params[] = {
!     { (char*)"IsClassUnloadingEnabled", JVMTI_KIND_OUT,  JVMTI_TYPE_JBOOLEAN, JNI_FALSE }
    };
!   static jvmtiExtensionFunctionInfo ext_func = {
      (jvmtiExtensionFunction)IsClassUnloadingEnabled,
      (char*)"com.sun.hotspot.functions.IsClassUnloadingEnabled",
      (char*)"Tell if class unloading is enabled (-noclassgc)",
!     sizeof(func_params)/sizeof(func_params[0]),
!     func_params,
      0,              // no non-universal errors
      NULL
    };
!   _ext_functions->append(&ext_func);
  
    // register our extension event
  
!   static jvmtiParamInfo event_params[] = {
      { (char*)"JNI Environment", JVMTI_KIND_IN_PTR, JVMTI_TYPE_JNIENV, JNI_FALSE },
      { (char*)"Class", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CCHAR, JNI_FALSE }
    };
!   static jvmtiExtensionEventInfo ext_event = {
      EXT_EVENT_CLASS_UNLOAD,
      (char*)"com.sun.hotspot.events.ClassUnload",
      (char*)"CLASS_UNLOAD event",
!     sizeof(event_params)/sizeof(event_params[0]),
!     event_params
    };
!   _ext_events->append(&ext_event);
  }
  
  
  // return the list of extension functions
  
--- 54,193 ---
    }
    *enabled = (jboolean)ClassUnloading;
    return JVMTI_ERROR_NONE;
  }
  
+ // Parameters: (jthread thread, jthread* vthread_ptr)
+ static jvmtiError JNICALL GetVirtualThread(const jvmtiEnv* env, ...) {
+   JvmtiEnv* jvmti_env = JvmtiEnv::JvmtiEnv_from_jvmti_env((jvmtiEnv*)env);
+   if (jvmti_env->get_capabilities()->can_support_virtual_threads == 0) {
+     return JVMTI_ERROR_MUST_POSSESS_CAPABILITY;
+   }
+ 
+   JavaThread* current_thread = JavaThread::current();
+   ResourceMark rm(current_thread);
+   jthread thread = NULL;
+   jthread* vthread_ptr = NULL;
+   JavaThread* java_thread = NULL;
+   oop thread_oop = NULL;
+   va_list ap;
+ 
+   va_start(ap, env);
+   thread = va_arg(ap, jthread);
+   vthread_ptr = va_arg(ap, jthread*);
+   va_end(ap);
+ 
+   ThreadInVMfromNative tiv(current_thread);
+   JvmtiVTMTDisabler vtmt_disabler;
+   ThreadsListHandle tlh(current_thread);
+ 
+   jvmtiError err;
+ 
+   *vthread_ptr = NULL;
+   if (thread == NULL) {
+     java_thread = current_thread;
+   } else {
+     err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, NULL);
+     if (err != JVMTI_ERROR_NONE) {
+       return err;
+     }
+   }
+   if (vthread_ptr == NULL) {
+     return JVMTI_ERROR_NULL_POINTER;
+   }
+ 
+   JvmtiThreadState *state = JvmtiThreadState::state_for(java_thread);
+   if (state == NULL) {
+     return JVMTI_ERROR_THREAD_NOT_ALIVE;
+   }
+   oop vthread_oop = java_thread->vthread();
+   if (!java_lang_VirtualThread::is_instance(vthread_oop)) { // not a virtual thread
+     vthread_oop = NULL;
+   }
+   *vthread_ptr = (jthread)JNIHandles::make_local(current_thread, vthread_oop);
+   return JVMTI_ERROR_NONE;
+ }
+ 
+ // Parameters: (jthread vthread, jthread* thread_ptr)
+ static jvmtiError JNICALL GetCarrierThread(const jvmtiEnv* env, ...) {
+   JvmtiEnv* jvmti_env = JvmtiEnv::JvmtiEnv_from_jvmti_env((jvmtiEnv*)env);
+   if (jvmti_env->get_capabilities()->can_support_virtual_threads == 0) {
+     return JVMTI_ERROR_MUST_POSSESS_CAPABILITY;
+   }
+ 
+   JavaThread* current_thread = JavaThread::current();
+   HandleMark hm(current_thread);
+   jthread vthread = NULL;
+   jthread* thread_ptr = NULL;
+   va_list ap;
+ 
+   va_start(ap, env);
+   vthread = va_arg(ap, jthread);
+   thread_ptr = va_arg(ap, jthread*);
+   va_end(ap);
+ 
+   ThreadInVMfromNative tiv(current_thread);
+   JvmtiVTMTDisabler vtmt_disabler;
+ 
+   oop vthread_obj = JNIHandles::resolve_external_guard(vthread);
+ 
+   if (!java_lang_VirtualThread::is_instance(vthread_obj)) {
+     return JVMTI_ERROR_INVALID_THREAD;
+   }
+   if (thread_ptr == NULL) {
+       return JVMTI_ERROR_NULL_POINTER;
+   }
+   VThreadGetThreadClosure op(Handle(current_thread, vthread_obj), thread_ptr);
+   Handshake::execute(&op, current_thread);
+   return op.result();
+ }
+ 
  // register extension functions and events. In this implementation we
  // have a single extension function (to prove the API) that tests if class
  // unloading is enabled or disabled. We also have a single extension event
  // EXT_EVENT_CLASS_UNLOAD which is used to provide the JVMDI_EVENT_CLASS_UNLOAD
  // event. The function and the event are registered here.
  //
  void JvmtiExtensions::register_extensions() {
    _ext_functions = new (ResourceObj::C_HEAP, mtServiceability) GrowableArray<jvmtiExtensionFunctionInfo*>(1, mtServiceability);
    _ext_events = new (ResourceObj::C_HEAP, mtServiceability) GrowableArray<jvmtiExtensionEventInfo*>(1, mtServiceability);
  
!   // register our extension functions
!   static jvmtiParamInfo func_params0[] = {
!     { (char*)"IsClassUnloadingEnabled", JVMTI_KIND_OUT, JVMTI_TYPE_JBOOLEAN, JNI_FALSE }
+   };
+   static jvmtiParamInfo func_params1[] = {
+     { (char*)"GetVirtualThread", JVMTI_KIND_IN, JVMTI_TYPE_JTHREAD, JNI_FALSE },
+     { (char*)"GetVirtualThread", JVMTI_KIND_OUT, JVMTI_TYPE_JTHREAD, JNI_FALSE }
+   };
+   static jvmtiParamInfo func_params2[] = {
+     { (char*)"GetVirtualThread", JVMTI_KIND_IN, JVMTI_TYPE_JTHREAD, JNI_FALSE },
+     { (char*)"GetCarrierThread", JVMTI_KIND_OUT, JVMTI_TYPE_JTHREAD, JNI_FALSE }
+   };
+ 
+   static jvmtiError errors[] = {
+     JVMTI_ERROR_MUST_POSSESS_CAPABILITY,
+     JVMTI_ERROR_INVALID_THREAD
    };
! 
+   static jvmtiExtensionFunctionInfo ext_func0 = {
      (jvmtiExtensionFunction)IsClassUnloadingEnabled,
      (char*)"com.sun.hotspot.functions.IsClassUnloadingEnabled",
      (char*)"Tell if class unloading is enabled (-noclassgc)",
!     sizeof(func_params0)/sizeof(func_params0[0]),
!     func_params0,
      0,              // no non-universal errors
      NULL
    };
! 
+   static jvmtiExtensionFunctionInfo ext_func1 = {
+     (jvmtiExtensionFunction)GetVirtualThread,
+     (char*)"com.sun.hotspot.functions.GetVirtualThread",
+     (char*)"Get virtual thread executed on carrier thread",
+     sizeof(func_params1)/sizeof(func_params1[0]),
+     func_params1,
+     sizeof(errors)/sizeof(jvmtiError),   // non-universal errors
+     errors
+   };
+ 
+   static jvmtiExtensionFunctionInfo ext_func2 = {
+     (jvmtiExtensionFunction)GetCarrierThread,
+     (char*)"com.sun.hotspot.functions.GetCarrierThread",
+     (char*)"Get carrier thread executing virtual thread",
+     sizeof(func_params2)/sizeof(func_params2[0]),
+     func_params2,
+     sizeof(errors)/sizeof(jvmtiError),   // non-universal errors
+     errors
+   };
+ 
+   _ext_functions->append(&ext_func0);
+   _ext_functions->append(&ext_func1);
+   _ext_functions->append(&ext_func2);
  
    // register our extension event
  
!   static jvmtiParamInfo class_unload_event_params[] = {
      { (char*)"JNI Environment", JVMTI_KIND_IN_PTR, JVMTI_TYPE_JNIENV, JNI_FALSE },
      { (char*)"Class", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CCHAR, JNI_FALSE }
    };
!   static jvmtiParamInfo virtual_thread_event_params[] = {
+     { (char*)"JNI Environment", JVMTI_KIND_IN_PTR, JVMTI_TYPE_JNIENV, JNI_FALSE },
+     { (char*)"Virtual Thread", JVMTI_KIND_IN, JVMTI_TYPE_JTHREAD, JNI_FALSE }
+   };
+ 
+   static jvmtiExtensionEventInfo class_unload_ext_event = {
      EXT_EVENT_CLASS_UNLOAD,
      (char*)"com.sun.hotspot.events.ClassUnload",
      (char*)"CLASS_UNLOAD event",
!     sizeof(class_unload_event_params)/sizeof(class_unload_event_params[0]),
!     class_unload_event_params
    };
!   static jvmtiExtensionEventInfo virtual_thread_mount_ext_event = {
+     EXT_EVENT_VIRTUAL_THREAD_MOUNT,
+     (char*)"com.sun.hotspot.events.VirtualThreadMount",
+     (char*)"VIRTUAL_THREAD_MOUNT event",
+     sizeof(virtual_thread_event_params)/sizeof(virtual_thread_event_params[0]),
+     virtual_thread_event_params
+   };
+   static jvmtiExtensionEventInfo virtual_thread_unmount_ext_event = {
+     EXT_EVENT_VIRTUAL_THREAD_UNMOUNT,
+     (char*)"com.sun.hotspot.events.VirtualThreadUnmount",
+     (char*)"VIRTUAL_THREAD_UNMOUNT event",
+     sizeof(virtual_thread_event_params)/sizeof(virtual_thread_event_params[0]),
+     virtual_thread_event_params
+   };
+ 
+   _ext_events->append(&class_unload_ext_event);
+   _ext_events->append(&virtual_thread_mount_ext_event);
+   _ext_events->append(&virtual_thread_unmount_ext_event);
  }
  
  
  // return the list of extension functions
  
< prev index next >