Skip to content

Commit 1e89c7e

Browse files
authored
Merge pull request #21308 from fengxue-IS/jep491-0.51-base
(v0.51.0) Support JEP491 in VM code path
2 parents 70f26c9 + 775ee1c commit 1e89c7e

File tree

16 files changed

+897
-120
lines changed

16 files changed

+897
-120
lines changed

jcl/src/java.base/share/classes/jdk/internal/vm/Continuation.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ public class Continuation {
3838
private long vmRef; /* J9VMContinuation */
3939
protected Thread vthread; /* Parent VirtualThread */
4040

41+
/*[IF JAVA_SPEC_VERSION >= 24]*/
42+
private Object blocker;
43+
/*[ENDIF] JAVA_SPEC_VERSION >= 24 */
44+
4145
/* The live thread's scopedValueCache is always kept in J9VMThread->scopedValueCache
4246
* whereas the unmounted thread's scopedValueCache is stored in this field. This
4347
* field is modified in ContinuationHelpers.hpp::swapFieldsWithContinuation. This
@@ -71,7 +75,13 @@ public enum Pinned {
7175
/** Holding monitor(s) */
7276
MONITOR(2),
7377
/** In critical section */
78+
/*[IF JAVA_SPEC_VERSION >= 24]*/
79+
CRITICAL_SECTION(3),
80+
/** Exception */
81+
EXCEPTION(4);
82+
/*[ELSE] JAVA_SPEC_VERSION >= 24 */
7483
CRITICAL_SECTION(3);
84+
/*[ENDIF] JAVA_SPEC_VERSION >= 24 */
7585

7686
private final int errorCode;
7787

@@ -250,6 +260,10 @@ private boolean yield0() {
250260
reason = Pinned.MONITOR;
251261
} else if (rcPinned == Pinned.NATIVE.errorCode()) {
252262
reason = Pinned.NATIVE;
263+
/*[IF JAVA_SPEC_VERSION >= 24]*/
264+
} else if (rcPinned == Pinned.EXCEPTION.errorCode()) {
265+
reason = Pinned.EXCEPTION;
266+
/*[ENDIF] JAVA_SPEC_VERSION >= 24 */
253267
} else {
254268
throw new AssertionError("Unknown pinned error code: " + rcPinned);
255269
}

runtime/j9vm/javanextvmi.cpp

Lines changed: 29 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@
3535
#include "VMHelpers.hpp"
3636
#include "ContinuationHelpers.hpp"
3737
#endif /* JAVA_SPEC_VERSION >= 19 */
38+
#if JAVA_SPEC_VERSION >= 24
39+
#include "j9protos.h"
40+
#endif /* JAVA_SPEC_VERSION >= 24 */
3841

3942
extern "C" {
4043

@@ -260,89 +263,27 @@ JVM_IsPreviewEnabled(void)
260263
return isPreviewEnabled;
261264
}
262265

263-
static void
264-
enterVThreadTransitionCritical(J9VMThread *currentThread, jobject thread)
265-
{
266-
J9JavaVM *vm = currentThread->javaVM;
267-
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
268-
MM_ObjectAccessBarrierAPI objectAccessBarrier = MM_ObjectAccessBarrierAPI(currentThread);
269-
j9object_t threadObj = J9_JNI_UNWRAP_REFERENCE(thread);
270-
271-
retry:
272-
if (!VM_VMHelpers::isThreadSuspended(currentThread, threadObj)) {
273-
while (!objectAccessBarrier.inlineMixedObjectCompareAndSwapU64(currentThread, threadObj, vm->virtualThreadInspectorCountOffset, 0, ~(U_64)0)) {
274-
/* Thread is being inspected or unmounted, wait. */
275-
vmFuncs->internalReleaseVMAccess(currentThread);
276-
VM_AtomicSupport::yieldCPU();
277-
/* After wait, the thread may suspend here. */
278-
vmFuncs->internalAcquireVMAccess(currentThread);
279-
threadObj = J9_JNI_UNWRAP_REFERENCE(thread);
280-
}
281-
282-
/* Now we have locked access to virtualThreadInspectorCount, check if the vthread is suspended.
283-
* If suspended, release the access and spin-wait until the vthread is resumed.
284-
* If not suspended, link the current J9VMThread with the virtual thread object.
285-
*/
286-
if (!VM_VMHelpers::isThreadSuspended(currentThread, threadObj)
287-
&& objectAccessBarrier.inlineMixedObjectCompareAndSwapU64(currentThread, threadObj, vm->internalSuspendStateOffset, J9_VIRTUALTHREAD_INTERNAL_STATE_NONE, (U_64)currentThread)
288-
) {
289-
return;
290-
}
291-
J9OBJECT_I64_STORE(currentThread, threadObj, vm->virtualThreadInspectorCountOffset, 0);
292-
}
293-
vmFuncs->internalReleaseVMAccess(currentThread);
294-
/* Spin is used instead of the halt flag as we cannot guarantee suspend flag is still set now.
295-
*
296-
* TODO: Dynamically increase the sleep time to a bounded maximum.
297-
*/
298-
f_threadSleep(10);
299-
/* After wait, the thread may suspend here. */
300-
vmFuncs->internalAcquireVMAccess(currentThread);
301-
threadObj = J9_JNI_UNWRAP_REFERENCE(thread);
302-
goto retry;
303-
}
304-
305-
static void
306-
exitVThreadTransitionCritical(J9VMThread *currentThread, jobject thread)
307-
{
308-
J9JavaVM *vm = currentThread->javaVM;
309-
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
310-
j9object_t vthread = J9_JNI_UNWRAP_REFERENCE(thread);
311-
MM_ObjectAccessBarrierAPI objectAccessBarrier = MM_ObjectAccessBarrierAPI(currentThread);
312-
313-
/* Remove J9VMThread address from internalSuspendedState field, as the thread state is no longer in a transition. */
314-
while (!objectAccessBarrier.inlineMixedObjectCompareAndSwapU64(currentThread, vthread, vm->internalSuspendStateOffset, (U_64)currentThread, J9_VIRTUALTHREAD_INTERNAL_STATE_NONE)) {
315-
/* Wait if the suspend flag is set. */
316-
vmFuncs->internalReleaseVMAccess(currentThread);
317-
VM_AtomicSupport::yieldCPU();
318-
/* After wait, the thread may suspend here. */
319-
vmFuncs->internalAcquireVMAccess(currentThread);
320-
vthread = J9_JNI_UNWRAP_REFERENCE(thread);
321-
}
322-
323-
/* Update to virtualThreadInspectorCount must be after clearing isSuspendedInternal field to retain sync ordering. */
324-
Assert_SC_true(-1 == J9OBJECT_I64_LOAD(currentThread, vthread, vm->virtualThreadInspectorCountOffset));
325-
J9OBJECT_I64_STORE(currentThread, vthread, vm->virtualThreadInspectorCountOffset, 0);
326-
}
327-
328266
static void
329267
setContinuationStateToLastUnmount(J9VMThread *currentThread, jobject thread)
330268
{
331-
enterVThreadTransitionCritical(currentThread, thread);
269+
J9InternalVMFunctions const * const vmFuncs = currentThread->javaVM->internalVMFunctions;
270+
vmFuncs->enterVThreadTransitionCritical(currentThread, thread);
271+
332272
/* Re-fetch reference as enterVThreadTransitionCritical may release VMAccess. */
333273
j9object_t threadObj = J9_JNI_UNWRAP_REFERENCE(thread);
334274
j9object_t continuationObj = J9VMJAVALANGVIRTUALTHREAD_CONT(currentThread, threadObj);
335275
ContinuationState volatile *continuationStatePtr = VM_ContinuationHelpers::getContinuationStateAddress(currentThread, continuationObj);
336276
/* Used in JVMTI to not suspend the virtual thread once it enters the last unmount phase. */
337277
VM_ContinuationHelpers::setLastUnmount(continuationStatePtr);
338-
exitVThreadTransitionCritical(currentThread, thread);
278+
vmFuncs->exitVThreadTransitionCritical(currentThread, thread);
339279
}
340280

341281
/* Caller must have VMAccess. */
342282
static void
343283
virtualThreadMountBegin(JNIEnv *env, jobject thread)
344284
{
345285
J9VMThread *currentThread = (J9VMThread *)env;
286+
J9InternalVMFunctions const * const vmFuncs = currentThread->javaVM->internalVMFunctions;
346287

347288
j9object_t threadObj = J9_JNI_UNWRAP_REFERENCE(thread);
348289
Assert_SC_true(IS_JAVA_LANG_VIRTUALTHREAD(currentThread, threadObj));
@@ -361,7 +302,7 @@ virtualThreadMountBegin(JNIEnv *env, jobject thread)
361302
continuation);
362303
}
363304

364-
enterVThreadTransitionCritical(currentThread, thread);
305+
vmFuncs->enterVThreadTransitionCritical(currentThread, thread);
365306

366307
VM_VMHelpers::virtualThreadHideFrames(currentThread, JNI_TRUE);
367308
}
@@ -372,6 +313,7 @@ virtualThreadMountEnd(JNIEnv *env, jobject thread)
372313
{
373314
J9VMThread *currentThread = (J9VMThread *)env;
374315
J9JavaVM *vm = currentThread->javaVM;
316+
J9InternalVMFunctions const * const vmFuncs = vm->internalVMFunctions;
375317
j9object_t threadObj = J9_JNI_UNWRAP_REFERENCE(thread);
376318

377319
Assert_SC_true(IS_JAVA_LANG_VIRTUALTHREAD(currentThread, threadObj));
@@ -391,7 +333,7 @@ virtualThreadMountEnd(JNIEnv *env, jobject thread)
391333
VM_VMHelpers::virtualThreadHideFrames(currentThread, JNI_FALSE);
392334

393335
/* Allow thread to be inspected again. */
394-
exitVThreadTransitionCritical(currentThread, thread);
336+
vmFuncs->exitVThreadTransitionCritical(currentThread, thread);
395337

396338
TRIGGER_J9HOOK_VM_VIRTUAL_THREAD_MOUNT(vm->hookInterface, currentThread);
397339
}
@@ -402,6 +344,7 @@ virtualThreadUnmountBegin(JNIEnv *env, jobject thread)
402344
{
403345
J9VMThread *currentThread = (J9VMThread *)env;
404346
J9JavaVM *vm = currentThread->javaVM;
347+
J9InternalVMFunctions const * const vmFuncs = vm->internalVMFunctions;
405348

406349
j9object_t threadObj = J9_JNI_UNWRAP_REFERENCE(thread);
407350

@@ -421,16 +364,15 @@ virtualThreadUnmountBegin(JNIEnv *env, jobject thread)
421364

422365
TRIGGER_J9HOOK_VM_VIRTUAL_THREAD_UNMOUNT(vm->hookInterface, currentThread);
423366

424-
enterVThreadTransitionCritical(currentThread, thread);
367+
vmFuncs->enterVThreadTransitionCritical(currentThread, thread);
425368

426-
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
427369
j9object_t carrierThreadObject = currentThread->carrierThreadObject;
428370
/* Virtual thread is being umounted. If its carrier thread is suspended, spin until
429371
* the carrier thread is resumed. The carrier thread should not be mounted until it
430372
* is resumed.
431373
*/
432374
while (VM_VMHelpers::isThreadSuspended(currentThread, carrierThreadObject)) {
433-
exitVThreadTransitionCritical(currentThread, thread);
375+
vmFuncs->exitVThreadTransitionCritical(currentThread, thread);
434376
vmFuncs->internalReleaseVMAccess(currentThread);
435377
/* Spin is used instead of the halt flag; otherwise, the virtual thread will
436378
* show as suspended.
@@ -439,7 +381,7 @@ virtualThreadUnmountBegin(JNIEnv *env, jobject thread)
439381
*/
440382
f_threadSleep(10);
441383
vmFuncs->internalAcquireVMAccess(currentThread);
442-
enterVThreadTransitionCritical(currentThread, thread);
384+
vmFuncs->enterVThreadTransitionCritical(currentThread, thread);
443385
carrierThreadObject = currentThread->carrierThreadObject;
444386
}
445387

@@ -452,7 +394,7 @@ virtualThreadUnmountEnd(JNIEnv *env, jobject thread)
452394
{
453395
J9VMThread *currentThread = (J9VMThread *)env;
454396
J9JavaVM *vm = currentThread->javaVM;
455-
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
397+
J9InternalVMFunctions const * const vmFuncs = vm->internalVMFunctions;
456398

457399
j9object_t threadObj = J9_JNI_UNWRAP_REFERENCE(thread);
458400
j9object_t continuationObj = J9VMJAVALANGVIRTUALTHREAD_CONT(currentThread, threadObj);
@@ -478,7 +420,7 @@ virtualThreadUnmountEnd(JNIEnv *env, jobject thread)
478420
VM_VMHelpers::virtualThreadHideFrames(currentThread, JNI_FALSE);
479421

480422
/* Allow thread to be inspected again. */
481-
exitVThreadTransitionCritical(currentThread, thread);
423+
vmFuncs->exitVThreadTransitionCritical(currentThread, thread);
482424
}
483425
#endif /* JAVA_SPEC_VERSION >= 19 */
484426

@@ -534,14 +476,14 @@ JVM_VirtualThreadHideFrames(
534476
#if JAVA_SPEC_VERSION < 23
535477
Assert_SC_true(vThreadObj == J9_JNI_UNWRAP_REFERENCE(vthread));
536478
#endif /* JAVA_SPEC_VERSION < 23 */
537-
enterVThreadTransitionCritical(currentThread, (jobject)&currentThread->threadObject);
479+
vmFuncs->enterVThreadTransitionCritical(currentThread, (jobject)&currentThread->threadObject);
538480
}
539481

540482
VM_VMHelpers::virtualThreadHideFrames(currentThread, hide);
541483

542484
if (!hide) {
543485
Assert_SC_true(hiddenFrames);
544-
exitVThreadTransitionCritical(currentThread, (jobject)&currentThread->threadObject);
486+
vmFuncs->exitVThreadTransitionCritical(currentThread, (jobject)&currentThread->threadObject);
545487
}
546488

547489
vmFuncs->internalExitVMToJNI(currentThread);
@@ -567,7 +509,7 @@ JVM_VirtualThreadMount(JNIEnv *env, jobject vthread, jboolean hide)
567509
{
568510
J9VMThread *currentThread = (J9VMThread *)env;
569511
J9JavaVM *vm = currentThread->javaVM;
570-
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
512+
J9InternalVMFunctions const * const vmFuncs = vm->internalVMFunctions;
571513

572514
Trc_SC_VirtualThreadMount_Entry(currentThread, vthread, hide);
573515

@@ -589,7 +531,7 @@ JVM_VirtualThreadUnmount(JNIEnv *env, jobject vthread, jboolean hide)
589531
{
590532
J9VMThread *currentThread = (J9VMThread *)env;
591533
J9JavaVM *vm = currentThread->javaVM;
592-
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
534+
J9InternalVMFunctions const * const vmFuncs = vm->internalVMFunctions;
593535

594536
Trc_SC_VirtualThreadUnmount_Entry(currentThread, vthread, hide);
595537

@@ -617,7 +559,7 @@ JVM_VirtualThreadStart(JNIEnv *env, jobject vthread)
617559
{
618560
J9VMThread *currentThread = (J9VMThread *)env;
619561
J9JavaVM *vm = currentThread->javaVM;
620-
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
562+
J9InternalVMFunctions const * const vmFuncs = vm->internalVMFunctions;
621563

622564
Trc_SC_VirtualThreadStart_Entry(currentThread, vthread);
623565

@@ -636,7 +578,7 @@ JVM_VirtualThreadEnd(JNIEnv *env, jobject vthread)
636578
{
637579
J9VMThread *currentThread = (J9VMThread *)env;
638580
J9JavaVM *vm = currentThread->javaVM;
639-
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
581+
J9InternalVMFunctions const * const vmFuncs = vm->internalVMFunctions;
640582

641583
Trc_SC_VirtualThreadEnd_Entry(currentThread, vthread);
642584

@@ -720,17 +662,19 @@ JVM_IsStaticallyLinked(void)
720662
}
721663

722664
JNIEXPORT void JNICALL
723-
JVM_VirtualThreadPinnedEvent(JNIEnv* env, jclass clazz, jstring op)
665+
JVM_VirtualThreadPinnedEvent(JNIEnv *env, jclass clazz, jstring op)
724666
{
725667
// TODO: emit JFR Event
726668
return;
727669
}
728670

729671
JNIEXPORT jobject JNICALL
730-
JVM_TakeVirtualThreadListToUnblock(JNIEnv* env, jclass ignored)
672+
JVM_TakeVirtualThreadListToUnblock(JNIEnv *env, jclass ignored)
731673
{
732-
// TODO: return the unblocked list
733-
return NULL;
674+
J9VMThread *currentThread = (J9VMThread *)env;
675+
J9JavaVM *vm = currentThread->javaVM;
676+
677+
return vm->internalVMFunctions->takeVirtualThreadListToUnblock(currentThread, vm);
734678
}
735679
#endif /* JAVA_SPEC_VERSION >= 24 */
736680

runtime/oti/ContinuationHelpers.hpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030
#define J9VM_CONTINUATION_PINNED_REASON_NATIVE 1
3131
#define J9VM_CONTINUATION_PINNED_REASON_MONITOR 2
3232
#define J9VM_CONTINUATION_PINNED_REASON_CRITICAL_SECTION 3
33+
#if JAVA_SPEC_VERSION >= 24
34+
#define J9VM_CONTINUATION_PINNED_REASON_EXCEPTION 4
35+
#endif /* JAVA_SPEC_VERSION >= 24 */
3336

3437
class VM_ContinuationHelpers {
3538
/*
@@ -88,6 +91,15 @@ class VM_ContinuationHelpers {
8891
j9object_t scopedValueCache = J9VMJDKINTERNALVMCONTINUATION_SCOPEDVALUECACHE(vmThread, continuationObject);
8992
J9VMJDKINTERNALVMCONTINUATION_SET_SCOPEDVALUECACHE(vmThread, continuationObject, vmThread->scopedValueCache);
9093
vmThread->scopedValueCache = scopedValueCache;
94+
95+
#if JAVA_SPEC_VERSION >= 24
96+
if (J9_ARE_ANY_BITS_SET(vmThread->javaVM->extendedRuntimeFlags3, J9_EXTENDED_RUNTIME3_YIELD_PINNED_CONTINUATION)) {
97+
SWAP_MEMBER(ownedMonitorCount, UDATA, vmThread, continuation);
98+
SWAP_MEMBER(monitorEnterRecordPool, J9Pool*, vmThread, continuation);
99+
SWAP_MEMBER(monitorEnterRecords, J9MonitorEnterRecord*, vmThread, continuation);
100+
SWAP_MEMBER(jniMonitorEnterRecords, J9MonitorEnterRecord*, vmThread, continuation);
101+
}
102+
#endif /* JAVA_SPEC_VERSION >= 24 */
91103
}
92104

93105
static VMINLINE ContinuationState volatile *
@@ -261,6 +273,24 @@ class VM_ContinuationHelpers {
261273

262274
return threadObject;
263275
}
276+
277+
#if JAVA_SPEC_VERSION >= 24
278+
/**
279+
* Check if the threadObject mounted on a J9VMThread is a virtual thread and can be yielded.
280+
*
281+
* @param[in] vmThread the J9VMThread
282+
*
283+
* @return true if the virtual thread is yieldable, otherwise false
284+
*/
285+
static VMINLINE bool
286+
isYieldableVirtualThread(J9VMThread *vmThread)
287+
{
288+
return (J9_ARE_ANY_BITS_SET(vmThread->javaVM->extendedRuntimeFlags3, J9_EXTENDED_RUNTIME3_YIELD_PINNED_CONTINUATION)
289+
&& IS_JAVA_LANG_VIRTUALTHREAD(vmThread, vmThread->threadObject)
290+
&& (0 == vmThread->continuationPinCount)
291+
&& (0 == vmThread->callOutCount));
292+
}
293+
#endif /* JAVA_SPEC_VERSION >= 24 */
264294
};
265295

266296
#endif /* CONTINUATIONHELPERS_HPP_ */

runtime/oti/j9consts.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,7 @@ extern "C" {
371371

372372
/* constants for J9JavaVM.extendedRuntimeFlags3 */
373373
#define J9_EXTENDED_RUNTIME3_START_FLIGHT_RECORDING 0x1
374+
#define J9_EXTENDED_RUNTIME3_YIELD_PINNED_CONTINUATION 0x2
374375

375376
#define J9_OBJECT_HEADER_AGE_DEFAULT 0xA /* OBJECT_HEADER_AGE_DEFAULT */
376377
#define J9_OBJECT_HEADER_SHAPE_MASK 0xE /* OBJECT_HEADER_SHAPE_MASK */

0 commit comments

Comments
 (0)