Skip to content

Commit 5daa110

Browse files
authored
Merge pull request eclipse-openj9#21273 from fengxue-IS/jep491-3.1
Jep491 VM support
2 parents 9dce4dc + 172a32e commit 5daa110

16 files changed

+716
-36
lines changed

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

+14
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

+9-4
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

@@ -720,17 +723,19 @@ JVM_IsStaticallyLinked(void)
720723
}
721724

722725
JNIEXPORT void JNICALL
723-
JVM_VirtualThreadPinnedEvent(JNIEnv* env, jclass clazz, jstring op)
726+
JVM_VirtualThreadPinnedEvent(JNIEnv *env, jclass clazz, jstring op)
724727
{
725728
// TODO: emit JFR Event
726729
return;
727730
}
728731

729732
JNIEXPORT jobject JNICALL
730-
JVM_TakeVirtualThreadListToUnblock(JNIEnv* env, jclass ignored)
733+
JVM_TakeVirtualThreadListToUnblock(JNIEnv *env, jclass ignored)
731734
{
732-
// TODO: return the unblocked list
733-
return NULL;
735+
J9VMThread *currentThread = (J9VMThread *)env;
736+
J9JavaVM *vm = currentThread->javaVM;
737+
738+
return vm->internalVMFunctions->takeVirtualThreadListToUnblock(currentThread, vm);
734739
}
735740
#endif /* JAVA_SPEC_VERSION >= 24 */
736741

runtime/oti/ContinuationHelpers.hpp

+30
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

+1
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 */

runtime/oti/j9nonbuilder.h

+43-1
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,15 @@
298298
typedef void(*j9_tls_finalizer_t)(void *);
299299
#endif /* JAVA_SPEC_VERSION >= 19 */
300300

301+
#if JAVA_SPEC_VERSION >= 24
302+
/* Constants from java.lang.VirutalThread.state that are used by the VM.
303+
* The full mapping is under jvmtiInternals.h <JVMTI_VTHREAD_STATE_*>.
304+
*/
305+
#define JAVA_LANG_VIRTUALTHREAD_BLOCKING 12
306+
#define JAVA_LANG_VIRTUALTHREAD_WAITING 13
307+
#define JAVA_LANG_VIRTUALTHREAD_TIMED_WAITING 17
308+
#endif /* JAVA_SPEC_VERSION >= 24 */
309+
301310
typedef enum {
302311
J9FlushCompQueueDataBreakpoint
303312
} J9JITFlushCompilationQueueReason;
@@ -1717,6 +1726,11 @@ typedef struct J9ObjectMonitor {
17171726
#endif /* defined(J9VM_THR_SMART_DEFLATION) */
17181727
j9objectmonitor_t alternateLockword;
17191728
U_32 hash;
1729+
#if JAVA_SPEC_VERSION >= 24
1730+
U_32 virtualThreadWaitCount;
1731+
struct J9VMContinuation* ownerContinuation;
1732+
struct J9VMContinuation* waitingContinuations;
1733+
#endif /* JAVA_SPEC_VERSION >= 24 */
17201734
} J9ObjectMonitor;
17211735

17221736
typedef struct J9ClassWalkState {
@@ -5329,6 +5343,10 @@ typedef struct J9InternalVMFunctions {
53295343
struct J9Class * (*initializeSnapshotClassObject)(struct J9JavaVM *javaVM, struct J9ClassLoader *classLoader, struct J9Class *clazz);
53305344
BOOLEAN (*loadWarmClassFromSnapshot)(struct J9VMThread *vmThread, struct J9ClassLoader *classLoader, struct J9Class *clazz);
53315345
#endif /* defined(J9VM_OPT_SNAPSHOTS) */
5346+
#if JAVA_SPEC_VERSION >= 24
5347+
struct J9ObjectMonitor * (*monitorTablePeek)(struct J9JavaVM *vm, j9object_t object);
5348+
jobject (*takeVirtualThreadListToUnblock)(struct J9VMThread *currentThread, struct J9JavaVM *vm);
5349+
#endif /* JAVA_SPEC_VERSION >= 24 */
53325350
} J9InternalVMFunctions;
53335351

53345352
/* Jazz 99339: define a new structure to replace JavaVM so as to pass J9NativeLibrary to JVMTIEnv */
@@ -5407,6 +5425,13 @@ typedef struct J9JITGPRSpillArea {
54075425
typedef uintptr_t ContinuationState;
54085426

54095427
#if JAVA_SPEC_VERSION >= 19
5428+
#define J9VM_CONTINUATION_RETURN_FROM_YIELD 1
5429+
#if JAVA_SPEC_VERSION >= 24
5430+
#define J9VM_CONTINUATION_RETURN_FROM_MONITOR_ENTER 0
5431+
#define J9VM_CONTINUATION_RETURN_FROM_OBJECT_WAIT 2
5432+
#define J9VM_CONTINUATION_RETURN_FROM_SYNC_METHOD 3
5433+
#endif /* JAVA_SPEC_VERSION >= 24 */
5434+
54105435
typedef struct J9VMContinuation {
54115436
UDATA* arg0EA;
54125437
UDATA* bytecodes;
@@ -5422,6 +5447,16 @@ typedef struct J9VMContinuation {
54225447
struct J9I2JState i2jState;
54235448
struct J9VMEntryLocalStorage* oldEntryLocalStorage;
54245449
UDATA dropFlags;
5450+
UDATA returnState;
5451+
#if JAVA_SPEC_VERSION >= 24
5452+
IDATA waitingMonitorEnterCount;
5453+
UDATA ownedMonitorCount;
5454+
struct J9Pool* monitorEnterRecordPool;
5455+
struct J9MonitorEnterRecord* monitorEnterRecords;
5456+
struct J9MonitorEnterRecord* jniMonitorEnterRecords;
5457+
j9object_t vthread;
5458+
struct J9VMContinuation* nextWaitingContinuation;
5459+
#endif /* JAVA_SPEC_VERSION >= 24 */
54255460
} J9VMContinuation;
54265461
#endif /* JAVA_SPEC_VERSION >= 19 */
54275462

@@ -6341,6 +6376,10 @@ typedef struct J9JavaVM {
63416376
#if defined(J9VM_OPT_JFR)
63426377
UDATA loadedClassCount;
63436378
#endif /* defined(J9VM_OPT_JFR) */
6379+
#if JAVA_SPEC_VERSION >= 24
6380+
J9VMContinuation *blockedContinuations;
6381+
omrthread_monitor_t blockedVirtualThreadsMutex;
6382+
#endif /* JAVA_SPEC_VERSION >= 24 */
63446383
} J9JavaVM;
63456384

63466385
#define J9JFR_SAMPLER_STATE_UNINITIALIZED 0
@@ -6380,7 +6419,10 @@ typedef struct J9JavaVM {
63806419
#if defined(J9VM_OPT_CRIU_SUPPORT)
63816420
#define J9_OBJECT_MONITOR_CRIU_SINGLE_THREAD_MODE_THROW 2
63826421
#endif /* defined(J9VM_OPT_CRIU_SUPPORT) */
6383-
#define J9_OBJECT_MONITOR_BLOCKING 3
6422+
#if JAVA_SPEC_VERSION >= 24
6423+
#define J9_OBJECT_MONITOR_YIELD_VIRTUAL 3
6424+
#endif /* JAVA_SPEC_VERSION >= 24 */
6425+
#define J9_OBJECT_MONITOR_BLOCKING 4
63846426

63856427
#if (JAVA_SPEC_VERSION >= 16) || defined(J9VM_OPT_CRIU_SUPPORT)
63866428
#define J9_OBJECT_MONITOR_ENTER_FAILED(rc) ((UDATA)(rc) < J9_OBJECT_MONITOR_BLOCKING)

runtime/oti/jvminit.h

+6
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,12 @@ enum INIT_STAGE {
471471
#define VMOPT_XXNOSHOWUNMOUNTEDTHREADSTACKS "-XX:-ShowUnmountedThreadStacks"
472472
#endif /* JAVA_SPEC_VERSION >= 21 */
473473

474+
#if JAVA_SPEC_VERSION >= 24
475+
/* Option to toggle on/off the feature to yield pinned virtual threads. */
476+
#define VMOPT_XXYIELDPINNEDVIRTUALTHREADS "-XX:+YieldPinnedVirtualThreads"
477+
#define VMOPT_XXNOYIELDPINNEDVIRTUALTHREADS "-XX:-YieldPinnedVirtualThreads"
478+
#endif /* JAVA_SPEC_VERSION >= 24 */
479+
474480
/* Option to turn on exception on synchronization on instances of value-based classes */
475481
#define VMOPT_XXDIAGNOSE_SYNC_ON_VALUEBASED_CLASSES_EQUALS1 "-XX:DiagnoseSyncOnValueBasedClasses=1"
476482
/* Option to turn on warning on synchronization on instances of value-based classes */

runtime/oti/vm_api.h

+58-2
Original file line numberDiff line numberDiff line change
@@ -2451,6 +2451,26 @@ monitorTableAt(J9VMThread* vmStruct, j9object_t object);
24512451
void
24522452
cacheObjectMonitorForLookup(J9JavaVM* vm, J9VMThread* vmStruct, J9ObjectMonitor* objectMonitor);
24532453

2454+
/* ---------------- thrinfo.c ---------------- */
2455+
2456+
/**
2457+
* @brief Search the monitor tables in vm->monitorTable for the inflated monitor corresponding to an
2458+
* object. Similar to monitorTableAt(), but doesn't add the monitor if it isn't found in the hashtable.
2459+
*
2460+
* This function may block on vm->monitorTableMutex.
2461+
* This function can work out-of-process.
2462+
*
2463+
* @param[in] vm the JavaVM. For out-of-process: may be a local or target pointer.
2464+
* vm->monitorTable must be a target value.
2465+
* @param[in] object the object. For out-of-process: a target pointer.
2466+
*
2467+
* @return a J9ObjectMonitor from the monitor hashtable or a NULL if there is no corresponding monitor
2468+
* in vm->monitorTable.
2469+
*
2470+
* @see monitorTablePeekMonitor in util_internal.h
2471+
*/
2472+
J9ObjectMonitor *
2473+
monitorTablePeek(J9JavaVM *vm, j9object_t object);
24542474

24552475
/* ---------------- PackageIDHashTable.c ---------------- */
24562476

@@ -4579,12 +4599,13 @@ enterContinuation(struct J9VMThread *currentThread, j9object_t continuationObjec
45794599
/**
45804600
* @brief Suspends the Continuation runnable.
45814601
*
4582-
* @param currentThread
4602+
* @param currentThread the thread whose Continuation is being yielded
45834603
* @param isFinished true if it is last unmount
4604+
* @param returnState thread execution state when it is re-mounted
45844605
* @return BOOLEAN
45854606
*/
45864607
BOOLEAN
4587-
yieldContinuation(struct J9VMThread *currentThread, BOOLEAN isFinished);
4608+
yieldContinuation(struct J9VMThread *currentThread, BOOLEAN isFinished, UDATA returnState);
45884609

45894610
/**
45904611
* @brief Free the native memory allocated by Continuation.
@@ -4669,6 +4690,41 @@ void
46694690
releaseVThreadInspector(J9VMThread *currentThread, jobject thread);
46704691
#endif /* JAVA_SPEC_VERSION >= 19 */
46714692

4693+
#if JAVA_SPEC_VERSION >= 24
4694+
/**
4695+
* @brief Attach all yielded VirtualThread monitors to carrier thread.
4696+
*
4697+
* @param currentThread the current thread
4698+
* @param continuationObject the Continuation object
4699+
*/
4700+
void
4701+
preparePinnedVirtualThreadForMount(J9VMThread *currentThread, j9object_t continuationObject);
4702+
4703+
/**
4704+
* @brief Inflate all monitors and prepare the VirtualThread to yield.
4705+
*
4706+
* @param currentThread the current thread
4707+
* @param syncObj object to block/wait on
4708+
* @param isObjectWait if the call is from Object.wait()
4709+
*
4710+
* @return J9_OBJECT_MONITOR_YIELD_VIRTUAL if the can be successfully yielded;
4711+
* otherwise, an error code is returned
4712+
*/
4713+
UDATA
4714+
preparePinnedVirtualThreadForUnmount(J9VMThread *currentThread, j9object_t syncObj, BOOLEAN isObjectWait);
4715+
4716+
/**
4717+
* @brief Find a list of virtual thread to be unblocked. This is a helper method for
4718+
* JVM_TakeVirtualThreadListToUnblock (see javanextvmi.cpp).
4719+
*
4720+
* @param currentThread the current thread
4721+
* @param vm pointer to J9JavaVM
4722+
*
4723+
* @return a list of virtual threads to be unblocked
4724+
*/
4725+
jobject
4726+
takeVirtualThreadListToUnblock(J9VMThread *currentThread, J9JavaVM *vm);
4727+
#endif /* JAVA_SPEC_VERSION >= 24 */
46724728
/* ---------------- hookableAsync.c ---------------- */
46734729

46744730
/**

runtime/oti/vmconstantpool.xml

+8
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,11 @@ SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-ex
265265
<fieldref class="java/lang/VirtualThread" name="carrierThread" signature="Ljava/lang/Thread;" versions="19-"/>
266266
<fieldref class="java/lang/VirtualThread" name="cont" signature="Ljdk/internal/vm/Continuation;" versions="19-"/>
267267

268+
<!-- Field references for Synchronize Virtual Threads without Pinning (JEP491). -->
269+
<fieldref class="java/lang/VirtualThread" name="blockPermit" signature="Z" versions="24-"/>
270+
<fieldref class="java/lang/VirtualThread" name="next" signature="Ljava/lang/VirtualThread;" versions="24-"/>
271+
<fieldref class="java/lang/VirtualThread" name="onWaitingList" signature="Z" versions="24-"/>
272+
268273
<fieldref class="java/lang/Throwable" name="cause" signature="Ljava/lang/Throwable;"/>
269274
<fieldref class="java/lang/Throwable" name="detailMessage" signature="Ljava/lang/String;"/>
270275
<fieldref class="java/lang/Throwable" name="walkback" signature="Ljava/lang/Object;"/>
@@ -426,6 +431,9 @@ SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-ex
426431
<fieldref class="jdk/internal/vm/Continuation" name="vthread" signature="Ljava/lang/Thread;" versions="19-"/>
427432
<fieldref class="jdk/internal/vm/Continuation" name="scopedValueCache" signature="[Ljava/lang/Object;" versions="19-"/>
428433

434+
<!-- Field references for Synchronize Virtual Threads without Pinning (JEP491). -->
435+
<fieldref class="jdk/internal/vm/Continuation" name="blocker" signature="Ljava/lang/Object;" versions="24-"/>
436+
429437
<!-- Field references needed to support Foreign Linker API. -->
430438
<fieldref class="java/lang/invoke/NativeMethodHandle" name="invokeCache" signature="[Ljava/lang/Object;" flags="opt_openjdkFfi" versions="22-"/>
431439
<fieldref class="java/lang/invoke/NativeMethodHandle" name="nep" signature="Ljava/lang/invoke/MethodHandle;" flags="opt_openjdkFfi" versions="22-"/>

runtime/util/util_internal.h

-18
Original file line numberDiff line numberDiff line change
@@ -198,24 +198,6 @@ char *node_key(node *aNode);
198198
J9ThreadAbstractMonitor *
199199
monitorTablePeekMonitor(J9JavaVM *vm, j9object_t object);
200200

201-
/**
202-
* Search the monitor tables in vm->monitorTableList for the inflated monitor corresponding to an object.
203-
* Similar to monitorTableAt(), but doesn't add the monitor if it isn't found in the hashtable.
204-
*
205-
* This function may block on vm->monitorTableMutex.
206-
* This function can work out-of-process.
207-
*
208-
* @param[in] vm the JavaVM. For out-of-process: may be a local or target pointer.
209-
* vm->monitorTable must be a target value.
210-
* @param[in] object the object. For out-of-process: a target pointer.
211-
* @returns a J9ObjectMonitor from the monitor hashtable
212-
* @retval NULL There is no corresponding monitor in vm->monitorTable.
213-
*
214-
* @see monitorTablePeekMonitor
215-
*/
216-
J9ObjectMonitor *
217-
monitorTablePeek(J9JavaVM *vm, j9object_t object);
218-
219201
#ifdef __cplusplus
220202
}
221203
#endif

0 commit comments

Comments
 (0)