Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Loom: JVMTI support #15183

Closed
tajila opened this issue Jun 1, 2022 · 81 comments
Closed

Loom: JVMTI support #15183

tajila opened this issue Jun 1, 2022 · 81 comments
Assignees
Labels
comp:vm project:loom Used to track Project Loom related work
Milestone

Comments

@tajila
Copy link
Contributor

tajila commented Jun 1, 2022

Depends on #15177

JVMTI

  • can_support_virtual_threads //new capbility
  • Suspend/ResumeAllVirtualThreads //new APIs
    • finds all vthreads and suspends or resumes them
  • StopThread
    • disallowerd on vthreads
  • GetThreadInfo
    • vthread is always daemon
    • vthread priotity is always normal
  • RunAgentThread
    • cannot be vthread
  • GetThreadGroupChildren
    • does not include vthreads
  • GetAllStackTraces
    • does not include vthreads
  • PopFrame/ForceEarlyReturnXXX/SetLocalXXX
    • allowed to fail if vthread
    • intial approach, do not allow for unmounted vthreads
    • if mounted, should just work, although should behave as pinned
      • cant modify pin state here, since effectively threadlocal
  • GetCurrentThreadCpuTime/GetThreadCpuTime
    • disallowed on vthreads
  • JVMTI_THREAD_STATE_PARKED
    • includes sleep state for vthreads

See https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html

@tajila tajila added AQA Test failures from AdoptOpenJDK Quality Assurance test set project:loom Used to track Project Loom related work comp:vm and removed AQA Test failures from AdoptOpenJDK Quality Assurance test set labels Jun 1, 2022
@tajila tajila added this to the Release 0.34 (Java 19) milestone Jun 7, 2022
@babsingh
Copy link
Contributor

babsingh commented Jun 20, 2022

Revised List

Potentially, the following JVMTI methods are impacted by Loom:

  1. SetThreadLocalStorage (assigned to @EricYangIBM; covered by the TLS work): https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#SetThreadLocalStorage
  2. GetThreadLocalStorage (assigned to @EricYangIBM; covered by the TLS work): https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#GetThreadLocalStorage
  3. SetEventCallbacks (assigned to @EricYangIBM; covered by the TLS work): https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#SetEventCallbacks
  4. SetEventNotificationMode (assigned to @EricYangIBM; covered by the TLS work): https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#SetEventNotificationMode
  5. For JVMTI event callbacks, each jvmtiHook* function invokes prepareForEvent, which accesses J9JVMTIThreadData->threadEventEnable (assigned to @EricYangIBM; covered by the TLS work): https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#jvmtiEventCallbacks.
  6. GetThreadState: https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#GetThreadState
  7. GetCurrentThread: https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#GetCurrentThread
  8. SuspendThread: https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#SuspendThread
  9. SuspendThreadList: https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#SuspendThreadList
  10. SuspendAllVirtualThreads: https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#SuspendAllVirtualThreads
  11. ResumeThread: https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#ResumeThread
  12. ResumeThreadList: https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#ResumeThreadList
  13. ResumeAllVirtualThreads: https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#ResumeAllVirtualThreads
  14. StopThread: https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#StopThread
  15. InterruptThread: https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#InterruptThread
    • Phase 1: Block Virtual Threads for JVMTI Inspection #15690.
    • Phase 2: Ignore the interrupt code for (NULL == targetThread) i.e. a yielded virtual thread, and avoid pinning a yielded virtual thread in jvmtiHelpers.c::getVMThread to evade the omthread_monitor_* costs.
  16. GetThreadInfo: https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#GetThreadInfo
  17. GetOwnedMonitorInfo: https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#GetOwnedMonitorInfo
  18. GetOwnedMonitorStackDepthInfo: https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#GetOwnedMonitorStackDepthInfo
  19. GetCurrentContendedMonitor: https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#GetCurrentContendedMonitor
  20. GetThreadGroupChildren: https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#GetThreadGroupChildren.
  21. GetStackTrace: https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#GetStackTrace
  22. GetThreadListStackTraces: https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#GetThreadListStackTraces
  23. GetFrameCount (assigned to @thallium): https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#GetFrameCount
  24. PopFrame: https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#PopFrame
  25. GetFrameLocation: https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#GetFrameLocation
  26. NotifyFramePop: https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#NotifyFramePop
  27. GetLocal(Object|Instance|Int|Long|Float|Double): https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#GetLocalObject
  28. SetLocal(Object|Int|Long|Float|Double): https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#SetLocalObject
  29. ForceEarlyReturn(Object|Int|Long|Float|Double|Void): https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#ForceEarlyReturnObject
  30. GetCurrentThreadCpuTime: https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#GetCurrentThreadCpuTime
  31. GetThreadCpuTime: https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#GetThreadCpuTime
  32. RunAgentThread: https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#RunAgentThread
  33. GetAllThreads: https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#GetAllThreads
  34. can_support_virtual_threads: https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#jvmtiCapabilities.can_support_virtual_threads
  35. GetAllStackTraces: https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#GetAllStackTraces

@babsingh
Copy link
Contributor

Task 1: Handle error cases

re #15183 (comment)

Examples:
29. GetCurrentThreadCpuTime: https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#GetCurrentThreadCpuTime
30. GetThreadCpuTime: https://download.java.net/java/early_access/jdk19/docs/specs/jvmti.html#GetThreadCpuTime

Return JVMTI_ERROR_UNSUPPORTED_OPERATION for virtual threads
vmconstantpool.xml:
    <classref name="java/lang/VirtualThread"/>

bool isVirtualThread(J9VMThread *vmThread, jthread jthrd) {
   bool result = false;
   if (isSameOrSuperClassOf(
           J9VMJAVALANGVIRTUALTHREAD_OR_NULL(vmThread->javaVM),
           J9OBJECT_CLAZZ(vmThread, *(j9object_t *)jthrd)
   ) {
      result = true;
   }
   return result;
}

@babsingh
Copy link
Contributor

@tajila Will J9VMThread->threadObject always be up-to-date for Loom?

jvmtiGetCurrentThreadCpuTime(jvmtiEnv *env, jlong *nanos_ptr) {
    ...
    J9VMThread * currentThread = NULL;
    j9object_t threadObject = NULL;
    jvmtiError rc = JVMTI_ERROR_NONE;

    rc = getCurrentVMThread(vm, &currentThread);
    if (JVMTI_ERROR_NONE != rc) {
        return rc;
    } 
    threadObject = currentThread->threadObject;

    if (isSameOrSuperClassOf(
           J9VMJAVALANGVIRTUALTHREAD_OR_NULL(currentThread->javaVM),
           J9OBJECT_CLAZZ(currentThread, threadObject)
   ) {
       return JVMTI_ERROR_UNSUPPORTED_OPERATION;
   }
   ...
}

@tajila
Copy link
Contributor Author

tajila commented Jun 20, 2022

@tajila Will J9VMThread->threadObject always be up-to-date for Loom?

yes

EricYangIBM added a commit to EricYangIBM/openj9 that referenced this issue Jun 24, 2022
Return JVMTI_ERROR_UNSUPPORTED_OPERATION from JVMTI functions that do not
accept virtual threads as their current thread or parameters.

Issue: eclipse-openj9#15183
Signed-off-by: Eric Yang <eric.yang@ibm.com>
@EricYangIBM
Copy link
Contributor

Is there a priority for functions to update or should I just go down the list in the spec?

@babsingh
Copy link
Contributor

babsingh commented Jun 27, 2022

Is there a priority for functions to update or should I just go down the list in the spec?

Some functions will require the changes for #15177. You can support the easiest ones first, and the ones not dependent on #15177.

@EricYangIBM
Copy link
Contributor

Looking at the first three thread functions, do they need to be updated?

  1. GetThreadState
    Are there any changes needed for getVMThreadStateHelper()? Thread flags used differently for virtual threads?
  2. GetCurrentState
    Depends on vm->internalVMFunctions->currentVMThread, I don't think it needs any other changes. https://github.com/eclipse-openj9/openj9/blob/master/runtime/jvmti/jvmtiThread.c#L1096
  3. GetAllThreads
    Iterates over J9VMThread.linkNext, does this include virtual threads? https://github.com/eclipse-openj9/openj9/blob/master/runtime/jvmti/jvmtiThread.c#L163

@babsingh
Copy link
Contributor

re #15183 (comment):

  1. GetThreadState: There are some differences between Thread.state and VirtualThread.state. Example: A virtual thread that is sleeping, in Thread.sleep, may have JVMTI_THREAD_STATE_PARKED set instead of JVMTI_THREAD_STATE_SLEEPING. JVMTI_THREAD_STATE_RUNNABLE means that a thread is runnable. A virtual thread has two similar states: RUNNABLE and RUNNING. Also, a virtual thread has a PINNED state.
  2. GetCurrentThread: ((J9VMThread *)(vm->internalVMFunctions->currentVMThread()))->threadObject should provide the correct Java programming language thread. No change needed for this method.
  3. GetAllThreads: J9VMThread.linkNext should only include platform and carrier threads. It should not have virtual threads. The JVMTI doc tells us to ignore virtual threads for this method. So, no change is needed for this method.

We can also use the JVMTI tests in the extensions repo to verify our functionality. These tests have been updated for Project Loom.

Other Project Loom related JVMTI tests: https://github.com/ibmruntimes/openj9-openjdk-jdk19/tree/openj9/test/hotspot/jtreg/serviceability/jvmti/thread

@EricYangIBM
Copy link
Contributor

How will we implement Get/SetThreadLocalStorage for virtual threads? The tls for platform threads is attached to omr thread.

@babsingh
Copy link
Contributor

babsingh commented Jun 30, 2022

How will we implement Get/SetThreadLocalStorage for virtual threads? The tls for platform threads is attached to omr thread.

It can be moved as a hidden field into java.lang.Thread (class). In the Loom world, this will allow us to associate a pointer value with each environment-thread pair.

Old:
   struct J9Thread {
         void* tls[J9THREAD_MAX_TLS_KEYS];

New:
    Add hidden field into java.lang.Thread to store the above TLS array. It can be dynamically initialized.

Old:
    #define THREAD_DATA_FOR_VMTHREAD(j9env, vmThread) \
	((J9JVMTIThreadData *) omrthread_tls_get((vmThread)->osThread, (j9env)->tlsKey))

New:
    Get TLS from java.lang.Thread's hidden field
    (J9JVMTIThreadData *)READU(TLS[j9env->tlsKey - 1]);

We will also need to account for the initialization and destruction of the native structures associated to this hidden field.

@tajila @gacholio Can you provide feedback on the above approach?

@gacholio
Copy link
Contributor

At a glance, no, this is not correct. Our TLS is effectively useless in the presence of vthreads, so we will simply have to stop using it in many places.

Correct answer here is probably to add a hidden field to Thread to contain the JVMTI data itself, not some fake TLS implementation.

@babsingh
Copy link
Contributor

babsingh commented Jun 30, 2022

Correct answer here is probably to add a hidden field to Thread to contain the JVMTI data itself, not some fake TLS implementation.

Will JVMTI data be a struct as follows?

struct JVMTIThreadData {
   List of {J9JVMTIEnv, J9JVMTIThreadData} pairs;
   Other thread specific JVMTI details if needed;
}

@gacholio
Copy link
Contributor

To avoid searching a list, we could essentially reimplement TLS - store a fixed-size array in the Thread hidden field, and manage the keys ourselves. This will mean freeing the TLS when the Thread is collected (which may be a pain).

@EricYangIBM
Copy link
Contributor

Currently the TLS data struct gets allocated for each existing os thread when a jvmti env is allocated (allocateEnvironment in jvmtiHelpers.c) and new threads when a J9VMThread is created. TLS gets deallocated upon jvmti env deallocation or J9VMThread death. (J9HOOK_VM_THREAD_CREATED and J9HOOK_VM_THREAD_DESTROY)
Could we change these hooks to when a Thread is started/destroyed? Or maybe use the J9HOOK_VM_THREAD_STARTED/J9HOOK_VM_THREAD_END events instead?
Also I don't think the jvmtiEventThreadStart ThreadStart; and jvmtiEventThreadEnd ThreadEnd; callback functions exist/are used (same with the virtual thread versions), could they be used?

Also note the TLS only has to exist while the thread is alive (JVMTI_ERROR_THREAD_NOT_ALIVE)

@gacholio
Copy link
Contributor

gacholio commented Jul 5, 2022

J9HOOK_VM_THREAD_CREATED is special in that it's fired under lock (it does not report any JVMTI events) and is allowed to fail (e.g. malloc fail for TLS).

thallium pushed a commit to thallium/openj9-openjdk-jdk19 that referenced this issue Sep 21, 2022
The VirtualThread natives are needed to keep a list of every live virtual
thread for JVM TI. Since JVM TI agents can be attached at any time, enable
these natives by default.

Issue: eclipse-openj9/openj9#15183
Signed-off-by: Eric Yang <eric.yang@ibm.com>
thallium added a commit to thallium/openj9 that referenced this issue Sep 21, 2022
Traverse the thread list before acquireExclusiveVMAccess and
after releaseExclusiveVMAccess to ensure virtual thread transition
completion.

Update live thread check for virtual thread

Update surrounding code style

Issues: eclipse-openj9#15759 eclipse-openj9#15183

Signed-off-by: Gengchen Tuo <gengchen.tuo@ibm.com>
thallium added a commit to thallium/openj9 that referenced this issue Sep 22, 2022
Adds virtual thread support for GetOrSetLocal and NotifyFramePop

As walkState->walkThread will be used by some jit functions after
stackwalk, we can't use walkContinuationStackFrames which will cause
dangling pointer. Instead we need to stack-allocate manually if a
J9VMContinuation needs to be walked, so we created a helper
getJ9VMContinuationToWalk to get the J9VMContinuation.

Also fix coding style of surrounding code

Issues: eclipse-openj9#15759 eclipse-openj9#15183

Co-authored-by: Babneet Singh <sbabneet@ca.ibm.com>
Signed-off-by: Gengchen Tuo <gengchen.tuo@ibm.com>
babsingh added a commit to babsingh/openj9 that referenced this issue Sep 26, 2022
targetThread is NULL only for virtual threads, as per the assertion in
getVMThread, when mustBeAlive is TRUE. vmThreadForTLS is only used to
acquire J9JavaVM in createThreadData and jvmtiTLSGet. If targetThread
is NULL, currentThread is passed to createThreadData and jvmtiTLSGet
for retrieving J9JavaVM in JDK19+.

Related: eclipse-openj9#15541
Related: eclipse-openj9#15183

Signed-off-by: Babneet Singh <sbabneet@ca.ibm.com>
babsingh added a commit to babsingh/openj9 that referenced this issue Sep 27, 2022
targetThread is NULL only for virtual threads, as per the assertion in
getVMThread, when mustBeAlive is TRUE. vmThreadForTLS is only used to
acquire J9JavaVM in createThreadData and jvmtiTLSGet. If targetThread
is NULL, currentThread is passed to createThreadData and jvmtiTLSGet
for retrieving J9JavaVM in JDK19+.

Related: eclipse-openj9#15541
Related: eclipse-openj9#15183

Signed-off-by: Babneet Singh <sbabneet@ca.ibm.com>
@tajila tajila closed this as completed Oct 18, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
comp:vm project:loom Used to track Project Loom related work
Projects
None yet
Development

No branches or pull requests

4 participants