< prev index next >

src/jdk.jdwp.agent/share/native/libjdwp/util.c

Print this page

        

@@ -176,44 +176,56 @@
 {
     WITH_LOCAL_REFS(env, 6) {
 
         jvmtiError error;
         jclass localClassClass;
+        jclass localFiberClass;
         jclass localThreadClass;
         jclass localThreadGroupClass;
         jclass localClassLoaderClass;
         jclass localStringClass;
         jclass localSystemClass;
+        jclass localInnocuousThreadClass;
         jclass localPropertiesClass;
         jclass localVMSupportClass;
         jobject localAgentProperties;
         jmethodID getAgentProperties;
         jint groupCount;
         jthreadGroup *groups;
         jthreadGroup localSystemThreadGroup;
 
+        gdata->ignoreEvents = JNI_FALSE;
+
         /* Find some standard classes */
 
         localClassClass         = findClass(env,"java/lang/Class");
+        localFiberClass         = findClass(env,"java/lang/Fiber");
         localThreadClass        = findClass(env,"java/lang/Thread");
         localThreadGroupClass   = findClass(env,"java/lang/ThreadGroup");
         localClassLoaderClass   = findClass(env,"java/lang/ClassLoader");
         localStringClass        = findClass(env,"java/lang/String");
         localSystemClass        = findClass(env,"java/lang/System");
         localPropertiesClass    = findClass(env,"java/util/Properties");
+        localInnocuousThreadClass = findClass(env, "jdk/internal/misc/InnocuousThread");
 
         /* Save references */
 
         saveGlobalRef(env, localClassClass,       &(gdata->classClass));
+        saveGlobalRef(env, localFiberClass,       &(gdata->fiberClass));
         saveGlobalRef(env, localThreadClass,      &(gdata->threadClass));
         saveGlobalRef(env, localThreadGroupClass, &(gdata->threadGroupClass));
         saveGlobalRef(env, localClassLoaderClass, &(gdata->classLoaderClass));
         saveGlobalRef(env, localStringClass,      &(gdata->stringClass));
         saveGlobalRef(env, localSystemClass,      &(gdata->systemClass));
+        saveGlobalRef(env, localInnocuousThreadClass, &(gdata->innocuousThreadClass));
 
         /* Find some standard methods */
 
+        gdata->fiberToString =
+                getMethod(env, gdata->fiberClass, "toString", "()Ljava/lang/String;");
+        gdata->fiberTryMountAndSuspend =
+                getMethod(env, gdata->fiberClass, "tryMountAndSuspend", "()Ljava/lang/Thread;");
         gdata->threadConstructor =
                 getMethod(env, gdata->threadClass,
                     "<init>", "(Ljava/lang/ThreadGroup;Ljava/lang/String;)V");
         gdata->threadSetDaemon =
                 getMethod(env, gdata->threadClass, "setDaemon", "(Z)V");

@@ -305,10 +317,16 @@
 {
     if (object == NULL) {
         return JDWP_TAG(OBJECT);
     } else if (JNI_FUNC_PTR(env,IsInstanceOf)(env, object, gdata->stringClass)) {
         return JDWP_TAG(STRING);
+    } else if (JNI_FUNC_PTR(env,IsInstanceOf)(env, object, gdata->fiberClass)) {
+        /* We don't really need to check if it's an instance of a Fiber class since
+         * that would get detected below, but this is a bit faster. At one point
+         * it was thought that we would need to return THREAD here instead of OBJECT,
+         * but that's not the case. */
+        return JDWP_TAG(OBJECT);
     } else if (JNI_FUNC_PTR(env,IsInstanceOf)(env, object, gdata->threadClass)) {
         return JDWP_TAG(THREAD);
     } else if (JNI_FUNC_PTR(env,IsInstanceOf)(env, object, gdata->threadGroupClass)) {
         return JDWP_TAG(THREAD_GROUP);
     } else if (JNI_FUNC_PTR(env,IsInstanceOf)(env, object, gdata->classLoaderClass)) {

@@ -599,18 +617,26 @@
             jvmtiDeallocate(arguments);
         }
         return JNI_TRUE;
     }
 
-    /*
-     * Request the invoke. If there are no errors in the request,
-     * the interrupting thread will actually do the invoke and a
-     * reply will be generated subsequently, so we don't reply here.
-     */
-    error = invoker_requestInvoke(invokeType, (jbyte)options, inStream_id(in),
-                                  thread, clazz, method,
-                                  instance, arguments, argumentCount);
+    /* Don't try this with unmounted fibers. */
+    if (isFiber(thread)) {
+        thread = getFiberThread(thread);
+    }
+    if (thread == NULL) {
+        error = JVMTI_ERROR_THREAD_NOT_SUSPENDED;
+    } else {
+        /*
+         * Request the invoke. If there are no errors in the request,
+         * the interrupting thread will actually do the invoke and a
+         * reply will be generated subsequently, so we don't reply here.
+         */
+        error = invoker_requestInvoke(invokeType, (jbyte)options, inStream_id(in),
+                                      thread, clazz, method,
+                                      instance, arguments, argumentCount);
+    }
     if (error != JVMTI_ERROR_NONE) {
         outStream_setError(out, map2jdwpError(error));
         if ( arguments != NULL ) {
             jvmtiDeallocate(arguments);
         }

@@ -822,10 +848,71 @@
         jvmtiDeallocate(generic_signature);
     }
     return error;
 }
 
+/**
+ * Return fiber that is running on specified thread (must be inside a WITH_LOCAL_REFS)
+ */
+jthread
+getThreadFiber(jthread thread)
+{
+    jthread fiber;
+    jvmtiError error;
+
+    JDI_ASSERT(gdata->fibersSupported);
+    if ( thread == NULL ) {
+        return NULL;
+    }
+    error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadFiber)
+        (gdata->jvmti, thread, &fiber);
+    if (error == JVMTI_ERROR_THREAD_NOT_ALIVE) {
+        /* fiber fixme: get rid of this once we get rid of helperThreads. It should never happen then. */
+        return NULL;
+    } else if ( error != JVMTI_ERROR_NONE ) {
+        EXIT_ERROR(error,"Error calling GetThreadFiber()");
+        return JNI_FALSE;
+    }
+    return fiber;
+}
+
+/**
+ * Return thread that specified fiber is running on (must be inside a WITH_LOCAL_REFS)
+ */
+jthread
+getFiberThread(jthread fiber)
+{
+    jthread thread;
+    jvmtiError error;
+
+    JDI_ASSERT(gdata->fibersSupported);
+    if ( fiber == NULL ) {
+        return NULL;
+    }
+    error = JVMTI_FUNC_PTR(gdata->jvmti,GetFiberThread)
+        (gdata->jvmti, fiber, &thread);
+    if ( error != JVMTI_ERROR_NONE ) {
+        EXIT_ERROR(error,"Error calling GetFiberThread()");
+        return JNI_FALSE;
+    }
+    return thread;
+}
+
+jint
+getThreadFrameCount(jthread thread)
+{
+    jint count = 0;
+    jvmtiError error;
+
+    error = JVMTI_FUNC_PTR(gdata->jvmti,GetFrameCount)
+                    (gdata->jvmti, thread, &count);
+    if (error != JVMTI_ERROR_NONE) {
+        EXIT_ERROR(error, "getting frame count");
+    }
+    return count;
+}
+
 JNIEnv *
 getEnv(void)
 {
     JNIEnv *env = NULL;
     jint rc;

@@ -1584,10 +1671,17 @@
     JNIEnv *env = getEnv();
     return JNI_FUNC_PTR(env,IsInstanceOf)(env, object, gdata->classClass);
 }
 
 jboolean
+isFiber(jobject object)
+{
+    JNIEnv *env = getEnv();
+    return JNI_FUNC_PTR(env,IsInstanceOf)(env, object, gdata->fiberClass);
+}
+
+jboolean
 isThread(jobject object)
 {
     JNIEnv *env = getEnv();
     return JNI_FUNC_PTR(env,IsInstanceOf)(env, object, gdata->threadClass);
 }

@@ -1963,10 +2057,16 @@
     index2jvmti[EI_MONITOR_CONTENDED_ENTERED    -EI_min] = JVMTI_EVENT_MONITOR_CONTENDED_ENTERED;
     index2jvmti[EI_MONITOR_WAIT       -EI_min] = JVMTI_EVENT_MONITOR_WAIT;
     index2jvmti[EI_MONITOR_WAITED     -EI_min] = JVMTI_EVENT_MONITOR_WAITED;
     index2jvmti[EI_VM_INIT            -EI_min] = JVMTI_EVENT_VM_INIT;
     index2jvmti[EI_VM_DEATH           -EI_min] = JVMTI_EVENT_VM_DEATH;
+    index2jvmti[EI_FIBER_SCHEDULED    -EI_min] = JVMTI_EVENT_FIBER_SCHEDULED;
+    index2jvmti[EI_FIBER_TERMINATED   -EI_min] = JVMTI_EVENT_FIBER_TERMINATED;
+    index2jvmti[EI_FIBER_MOUNT        -EI_min] = JVMTI_EVENT_FIBER_MOUNT;
+    index2jvmti[EI_FIBER_UNMOUNT      -EI_min] = JVMTI_EVENT_FIBER_UNMOUNT;
+    index2jvmti[EI_CONTINUATION_RUN   -EI_min] = JVMTI_EVENT_CONTINUATION_RUN;
+    index2jvmti[EI_CONTINUATION_YIELD -EI_min] = JVMTI_EVENT_CONTINUATION_YIELD;
 
     index2jdwp[EI_SINGLE_STEP         -EI_min] = JDWP_EVENT(SINGLE_STEP);
     index2jdwp[EI_BREAKPOINT          -EI_min] = JDWP_EVENT(BREAKPOINT);
     index2jdwp[EI_FRAME_POP           -EI_min] = JDWP_EVENT(FRAME_POP);
     index2jdwp[EI_EXCEPTION           -EI_min] = JDWP_EVENT(EXCEPTION);

@@ -1984,10 +2084,19 @@
     index2jdwp[EI_MONITOR_CONTENDED_ENTERED           -EI_min] = JDWP_EVENT(MONITOR_CONTENDED_ENTERED);
     index2jdwp[EI_MONITOR_WAIT        -EI_min] = JDWP_EVENT(MONITOR_WAIT);
     index2jdwp[EI_MONITOR_WAITED      -EI_min] = JDWP_EVENT(MONITOR_WAITED);
     index2jdwp[EI_VM_INIT             -EI_min] = JDWP_EVENT(VM_INIT);
     index2jdwp[EI_VM_DEATH            -EI_min] = JDWP_EVENT(VM_DEATH);
+    /* Just map FIBER_SCHEDULED/TERMINATED to THREAD_START/END. */
+    index2jdwp[EI_FIBER_SCHEDULED     -EI_min] = JDWP_EVENT(THREAD_START);
+    index2jdwp[EI_FIBER_TERMINATED    -EI_min] = JDWP_EVENT(THREAD_END);
+    /* fiber fixme: these don't actually map to anything in JDWP. Need a way to make them
+     * produce an error if referenced. */
+    index2jdwp[EI_FIBER_MOUNT         -EI_min] = -1;
+    index2jdwp[EI_FIBER_UNMOUNT       -EI_min] = -1;
+    index2jdwp[EI_CONTINUATION_RUN    -EI_min] = -1;
+    index2jdwp[EI_CONTINUATION_YIELD  -EI_min] = -1;
 }
 
 jdwpEvent
 eventIndex2jdwp(EventIndex i)
 {

@@ -2004,10 +2113,73 @@
         EXIT_ERROR(AGENT_ERROR_INVALID_INDEX,"bad EventIndex");
     }
     return index2jvmti[i-EI_min];
 }
 
+
+char*
+eventIndex2EventName(EventIndex ei)
+{
+    switch ( ei ) {
+        case EI_SINGLE_STEP:
+            return "EI_SINGLE_STEP";
+        case EI_BREAKPOINT:
+            return "EI_BREAKPOINT";
+        case EI_FRAME_POP:
+            return "EI_FRAME_POP";
+        case EI_EXCEPTION:
+            return "EI_EXCEPTION";
+        case EI_THREAD_START:
+            return "EI_THREAD_START";
+        case EI_THREAD_END:
+            return "EI_THREAD_END";
+        case EI_CLASS_PREPARE:
+            return "EI_CLASS_PREPARE";
+        case EI_GC_FINISH:
+            return "EI_GC_FINISH";
+        case EI_CLASS_LOAD:
+            return "EI_CLASS_LOAD";
+        case EI_FIELD_ACCESS:
+            return "EI_FIELD_ACCESS";
+        case EI_FIELD_MODIFICATION:
+            return "EI_FIELD_MODIFICATION";
+        case EI_EXCEPTION_CATCH:
+            return "EI_EXCEPTION_CATCH";
+        case EI_METHOD_ENTRY:
+            return "EI_METHOD_ENTRY";
+        case EI_METHOD_EXIT:
+            return "EI_METHOD_EXIT";
+        case EI_MONITOR_CONTENDED_ENTER:
+            return "EI_MONITOR_CONTENDED_ENTER";
+        case EI_MONITOR_CONTENDED_ENTERED:
+            return "EI_MONITOR_CONTENDED_ENTERED";
+        case EI_MONITOR_WAIT:
+            return "EI_MONITOR_WAIT";
+        case EI_MONITOR_WAITED:
+            return "EI_MONITOR_WAITED";
+        case EI_VM_INIT:
+            return "EI_VM_INIT";
+        case EI_VM_DEATH:
+            return "EI_VM_DEATH";
+        case EI_FIBER_SCHEDULED:
+            return "EI_FIBER_SCHEDULED";
+        case EI_FIBER_TERMINATED:
+            return "EI_FIBER_TERMINATED";
+        case EI_FIBER_MOUNT:
+            return "EI_FIBER_MOUNT";
+        case EI_FIBER_UNMOUNT:
+            return "EI_FIBER_UNMOUNT";
+        case EI_CONTINUATION_RUN:
+            return "EI_CONTINUATION_RUN";
+        case EI_CONTINUATION_YIELD:
+            return "EI_CONTINUATION_YIELD";
+        default:
+            JDI_ASSERT(JNI_FALSE);
+            return "Bad EI";
+    }
+}
+
 EventIndex
 jdwp2EventIndex(jdwpEvent eventType)
 {
     switch ( eventType ) {
         case JDWP_EVENT(SINGLE_STEP):

@@ -2109,10 +2281,25 @@
             return EI_MONITOR_WAITED;
         case JVMTI_EVENT_VM_INIT:
             return EI_VM_INIT;
         case JVMTI_EVENT_VM_DEATH:
             return EI_VM_DEATH;
+        /* fiber events */
+        case JVMTI_EVENT_FIBER_SCHEDULED:
+            return EI_FIBER_SCHEDULED;
+        case JVMTI_EVENT_FIBER_TERMINATED:
+            return EI_FIBER_TERMINATED;
+        case JVMTI_EVENT_FIBER_MOUNT:
+            return EI_FIBER_MOUNT;
+        case JVMTI_EVENT_FIBER_UNMOUNT:
+            return EI_FIBER_UNMOUNT;
+        /* continuation events */
+        case JVMTI_EVENT_CONTINUATION_RUN:
+            return EI_CONTINUATION_RUN;
+        case JVMTI_EVENT_CONTINUATION_YIELD:
+            return EI_CONTINUATION_YIELD;
+
         default:
             EXIT_ERROR(AGENT_ERROR_INVALID_INDEX,"JVMTI to EventIndex mapping");
             break;
     }
     return (EventIndex)0;
< prev index next >