Skip to content

Commit 3426d78

Browse files
committed
Add support for Object.wait()
Signed-off-by: Jack Lu <[email protected]>
1 parent 5a0566c commit 3426d78

File tree

4 files changed

+127
-11
lines changed

4 files changed

+127
-11
lines changed

runtime/oti/j9nonbuilder.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5398,6 +5398,13 @@ typedef struct J9JITGPRSpillArea {
53985398
typedef uintptr_t ContinuationState;
53995399

54005400
#if JAVA_SPEC_VERSION >= 19
5401+
#define J9VM_CONTINUATION_RETURN_FROM_YIELD 0
5402+
#if JAVA_SPEC_VERSION >= 24
5403+
#define J9VM_CONTINUATION_RETURN_FROM_MONITOR_ENTER 1
5404+
#define J9VM_CONTINUATION_RETURN_FROM_OBJECT_WAIT 2
5405+
#define J9VM_CONTINUATION_RETURN_FROM_SYNC_METHOD 3
5406+
#endif /* JAVA_SPEC_VERSION >= 24 */
5407+
54015408
typedef struct J9VMContinuation {
54025409
UDATA* arg0EA;
54035410
UDATA* bytecodes;
@@ -5414,6 +5421,7 @@ typedef struct J9VMContinuation {
54145421
struct J9VMEntryLocalStorage* oldEntryLocalStorage;
54155422
UDATA dropFlags;
54165423
#if JAVA_SPEC_VERSION >= 24
5424+
UDATA returnState;
54175425
UDATA ownedMonitorCount;
54185426
J9Pool* monitorEnterRecordPool;
54195427
J9MonitorEnterRecord* monitorEnterRecords;

runtime/oti/vm_api.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4549,10 +4549,11 @@ enterContinuation(struct J9VMThread *currentThread, j9object_t continuationObjec
45494549
*
45504550
* @param currentThread
45514551
* @param isFinished true if it is last unmount
4552+
* @param returnState thread execution state when it is re-mounted
45524553
* @return BOOLEAN
45534554
*/
45544555
BOOLEAN
4555-
yieldContinuation(struct J9VMThread *currentThread, BOOLEAN isFinished);
4556+
yieldContinuation(struct J9VMThread *currentThread, BOOLEAN isFinished, UDATA returnState);
45564557

45574558
/**
45584559
* @brief Free the native memory allocated by Continuation.
@@ -4637,6 +4638,17 @@ void
46374638
releaseVThreadInspector(J9VMThread *currentThread, jobject thread);
46384639
#endif /* JAVA_SPEC_VERSION >= 19 */
46394640

4641+
#if JAVA_SPEC_VERSION >= 24
4642+
/**
4643+
* @brief Inflate all monitors and prepare for VirtualThread yield.
4644+
*
4645+
* @param currentThread
4646+
* @param syncObj object to block/wait on
4647+
* @param isObjectWait if the call is from Object.wait()
4648+
*/
4649+
UDATA
4650+
preparePinnedVirtualThreadForUnmount(J9VMThread *currentThread, j9object_t syncObj, BOOLEAN isObjectWait);
4651+
#endif /* JAVA_SPEC_VERSION >= 24 */
46404652
/* ---------------- hookableAsync.c ---------------- */
46414653

46424654
/**

runtime/vm/BytecodeInterpreter.hpp

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1731,7 +1731,7 @@ class INTERPRETER_CLASS
17311731
omrthread_monitor_exit(_vm->blockedVirtualThreadsMutex);
17321732

17331733
/* store the current Continuation state and swap to carrier thread stack */
1734-
yieldContinuation(_currentThread, FALSE);
1734+
yieldContinuation(_currentThread, FALSE, J9VM_CONTINUATION_RETURN_FROM_SYNC_METHOD);
17351735

17361736
VMStructHasBeenUpdated(REGISTER_ARGS);
17371737
restoreInternalNativeStackFrame(REGISTER_ARGS);
@@ -1833,7 +1833,7 @@ class INTERPRETER_CLASS
18331833
omrthread_monitor_exit(_vm->blockedVirtualThreadsMutex);
18341834

18351835
/* store the current Continuation state and swap to carrier thread stack */
1836-
yieldContinuation(_currentThread, FALSE);
1836+
yieldContinuation(_currentThread, FALSE, J9VM_CONTINUATION_RETURN_FROM_MONITOR_ENTER);
18371837

18381838
VMStructHasBeenUpdated(REGISTER_ARGS);
18391839
restoreInternalNativeStackFrame(REGISTER_ARGS);
@@ -1987,7 +1987,7 @@ class INTERPRETER_CLASS
19871987
omrthread_monitor_exit(_vm->blockedVirtualThreadsMutex);
19881988

19891989
/* store the current Continuation state and swap to carrier thread stack */
1990-
yieldContinuation(_currentThread, FALSE);
1990+
yieldContinuation(_currentThread, FALSE, J9VM_CONTINUATION_RETURN_FROM_MONITOR_ENTER);
19911991

19921992
VMStructHasBeenUpdated(REGISTER_ARGS);
19931993
restoreInternalNativeStackFrame(REGISTER_ARGS);
@@ -2382,7 +2382,7 @@ class INTERPRETER_CLASS
23822382
omrthread_monitor_exit(_vm->blockedVirtualThreadsMutex);
23832383

23842384
/* store the current Continuation state and swap to carrier thread stack */
2385-
yieldContinuation(_currentThread, FALSE);
2385+
yieldContinuation(_currentThread, FALSE, J9VM_CONTINUATION_RETURN_FROM_MONITOR_ENTER);
23862386

23872387
VMStructHasBeenUpdated(REGISTER_ARGS);
23882388
restoreInternalNativeStackFrame(REGISTER_ARGS);
@@ -5154,6 +5154,40 @@ class INTERPRETER_CLASS
51545154
j9object_t object = *(j9object_t*)(_sp + 3);
51555155
buildInternalNativeStackFrame(REGISTER_ARGS);
51565156
updateVMStruct(REGISTER_ARGS);
5157+
#if JAVA_SPEC_VERSION >= 24
5158+
if (IS_JAVA_LANG_VIRTUALTHREAD(_currentThread, _currentThread->threadObject)
5159+
&& (0 == _currentThread->continuationPinCount)
5160+
&& (0 == _currentThread->callOutCount)
5161+
) {
5162+
UDATA newState = JAVA_LANG_VIRTUALTHREAD_WAITING;
5163+
if ((millis > 0) || (nanos > 0)) {
5164+
newState = JAVA_LANG_VIRTUALTHREAD_TIMED_WAITING;
5165+
}
5166+
/* Try to yield virtual thread if it will be blocked */
5167+
rc = VM_ContinuationHelpers::preparePinnedVirtualThreadForUnmount(_currentThread, obj, true);
5168+
if (rc != J9_OBJECT_MONITOR_OOM) {
5169+
rc = EXECUTE_BYTECODE;
5170+
/* Handle virutal thread Object.wait call. */
5171+
buildInternalNativeStackFrame(REGISTER_ARGS);
5172+
updateVMStruct(REGISTER_ARGS);
5173+
5174+
J9VMJAVALANGVIRTUALTHREAD_SET_STATE(_currentThread, _currentThread->threadObject, newState);
5175+
5176+
/* store the current Continuation state and swap to carrier thread stack */
5177+
yieldContinuation(_currentThread, FALSE, J9VM_CONTINUATION_RETURN_FROM_OBJECT_WAIT);
5178+
5179+
VMStructHasBeenUpdated(REGISTER_ARGS);
5180+
restoreInternalNativeStackFrame(REGISTER_ARGS);
5181+
/* its going to return as if it were returning from continuation.enterImpl()
5182+
* so we need to push the boolean return val
5183+
*/
5184+
returnSingleFromINL(REGISTER_ARGS, JNI_FALSE, 1);
5185+
} else {
5186+
rc = THROW_MONITOR_ALLOC_FAIL;
5187+
}
5188+
return rc;
5189+
}
5190+
#endif /* JAVA_SPEC_VERSION >= 24 */
51575191
IDATA waitResult = monitorWaitImpl(_currentThread, object, millis, nanos, TRUE);
51585192
VMStructHasBeenUpdated(REGISTER_ARGS);
51595193
if (0 == waitResult) {
@@ -5639,6 +5673,9 @@ class INTERPRETER_CLASS
56395673
VM_BytecodeAction rc = EXECUTE_BYTECODE;
56405674

56415675
j9object_t continuationObject = *(j9object_t*)_sp;
5676+
#if JAVA_SPEC_VERSION >= 24
5677+
bool handleReturnCases = false;
5678+
#endif /* JAVA_SPEC_VERSION >= 24 */
56425679

56435680
buildInternalNativeStackFrame(REGISTER_ARGS);
56445681
updateVMStruct(REGISTER_ARGS);
@@ -5647,6 +5684,11 @@ class INTERPRETER_CLASS
56475684
_sendMethod = J9VMJDKINTERNALVMCONTINUATION_ENTER_METHOD(_currentThread->javaVM);
56485685
rc = GOTO_RUN_METHOD;
56495686
}
5687+
#if JAVA_SPEC_VERSION >= 24
5688+
else {
5689+
handleReturnCases = true;
5690+
}
5691+
#endif /* JAVA_SPEC_VERSION >= 24 */
56505692

56515693
VMStructHasBeenUpdated(REGISTER_ARGS);
56525694

@@ -5655,6 +5697,22 @@ class INTERPRETER_CLASS
56555697
} else if (VM_VMHelpers::exceptionPending(_currentThread)) {
56565698
rc = GOTO_THROW_CURRENT_EXCEPTION;
56575699
}
5700+
#if JAVA_SPEC_VERSION >= 24
5701+
switch (_currentThread->currentContinuation->returnState) {
5702+
case J9VM_CONTINUATION_RETURN_FROM_YIELD:
5703+
case J9VM_CONTINUATION_RETURN_FROM_MONITOR_ENTER:
5704+
break;
5705+
case J9VM_CONTINUATION_RETURN_FROM_OBJECT_WAIT:
5706+
restoreInternalNativeStackFrame(REGISTER_ARGS);
5707+
returnVoidFromINL(REGISTER_ARGS, 4);
5708+
break;
5709+
case J9VM_CONTINUATION_RETURN_FROM_SYNC_METHOD:
5710+
UDATA *bp = ((UDATA*)(((J9SFMethodFrame*)_sp) + 1)) - 1;
5711+
restoreSpecialStackFrameLeavingArgs(REGISTER_ARGS, bp);
5712+
rc = inlineSendTarget(REGISTER_ARGS, VM_MAYBE, VM_MAYBE, VM_MAYBE, VM_MAYBE);
5713+
break;
5714+
}
5715+
#endif /* JAVA_SPEC_VERSION >= 24 */
56585716
return rc;
56595717
}
56605718

@@ -5669,7 +5727,7 @@ class INTERPRETER_CLASS
56695727
updateVMStruct(REGISTER_ARGS);
56705728

56715729
/* store the current Continuation state and swap to carrier thread stack */
5672-
yieldContinuation(_currentThread, isFinished);
5730+
yieldContinuation(_currentThread, isFinished, J9VM_CONTINUATION_RETURN_FROM_YIELD);
56735731

56745732
VMStructHasBeenUpdated(REGISTER_ARGS);
56755733
restoreInternalNativeStackFrame(REGISTER_ARGS);
@@ -8797,7 +8855,7 @@ class INTERPRETER_CLASS
87978855
omrthread_monitor_exit(_vm->blockedVirtualThreadsMutex);
87988856

87998857
/* store the current Continuation state and swap to carrier thread stack */
8800-
yieldContinuation(_currentThread, FALSE);
8858+
yieldContinuation(_currentThread, FALSE, J9VM_CONTINUATION_RETURN_FROM_MONITOR_ENTER);
88018859

88028860
VMStructHasBeenUpdated(REGISTER_ARGS);
88038861
restoreInternalNativeStackFrame(REGISTER_ARGS);

runtime/vm/ContinuationHelpers.cpp

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -253,12 +253,15 @@ enterContinuation(J9VMThread *currentThread, j9object_t continuationObject)
253253

254254
if (started) {
255255
#if JAVA_SPEC_VERSION >= 24
256-
257-
#endif /* JAVA_SPEC_VERSION >= 24 */
256+
preparePinnedVirtualThreadForMount(currentThread, continuationObject);
257+
VM_OutOfLineINL_Helpers::restoreInternalNativeStackFrame(currentThread);
258+
result = FALSE;
259+
#elif
258260
/* resuming Continuation from yieldImpl */
259261
VM_OutOfLineINL_Helpers::restoreInternalNativeStackFrame(currentThread);
260262
VM_OutOfLineINL_Helpers::returnSingle(currentThread, JNI_TRUE, 1);
261263
result = FALSE;
264+
#endif /* JAVA_SPEC_VERSION >= 24 */
262265
} else {
263266
/* start new Continuation execution */
264267
VM_ContinuationHelpers::setStarted(continuationStatePtr);
@@ -284,7 +287,7 @@ enterContinuation(J9VMThread *currentThread, j9object_t continuationObject)
284287
}
285288

286289
BOOLEAN
287-
yieldContinuation(J9VMThread *currentThread, BOOLEAN isFinished)
290+
yieldContinuation(J9VMThread *currentThread, BOOLEAN isFinished, UDATA returnState)
288291
{
289292
BOOLEAN result = TRUE;
290293
J9VMContinuation *continuation = currentThread->currentContinuation;
@@ -331,6 +334,7 @@ yieldContinuation(J9VMThread *currentThread, BOOLEAN isFinished)
331334
/* Notify GC of Continuation stack swap */
332335
currentThread->javaVM->memoryManagerFunctions->postUnmountContinuation(currentThread, continuationObject);
333336
}
337+
continuation->returnState = returnState;
334338

335339
return result;
336340
}
@@ -410,6 +414,9 @@ recycleContinuation(J9JavaVM *vm, J9VMThread *vmThread, J9VMContinuation* contin
410414
vm->cacheFree += 1;
411415
/* Caching failed, free the J9VMContinuation struct. */
412416
freeJavaStack(vm, continuation->stackObject);
417+
#if JAVA_SPEC_VERSION >= 24
418+
pool_kill(continuation->monitorEnterRecordPool);
419+
#endif /* JAVA_SPEC_VERSION >= 24 */
413420
j9mem_free_memory(continuation);
414421
}
415422
}
@@ -649,8 +656,31 @@ updateMonitorInfo(J9VMThread *currentThread, J9ObjectMonitor *objectMonitor)
649656
objectMonitor->vthread = NULL;
650657
}
651658

659+
void
660+
preparePinnedVirtualThreadForMount(J9VMThread *currentThread, j9object_t contObj)
661+
{
662+
if (0 < currentThread->ownedMonitorCount) {
663+
J9MonitorEnterRecord monitorRecords = currentThread->monitorEnterRecords;
664+
while (monitorRecords) {
665+
j9object_t object = monitorRecords->object;
666+
j9objectmonitor_t lock = 0;
667+
J9ObjectMonitor *objectMonitor = NULL;
668+
669+
if (!LN_HAS_LOCKWORD(currentThread, object)) {
670+
objectMonitor = monitorTablePeek(currentThread->javaVM, object);
671+
} else {
672+
lwEA = J9OBJECT_MONITOR_EA(currentThread, object);
673+
lock = J9_LOAD_LOCKWORD(currentThread, lwEA);
674+
objectMonitor = J9_INFLLOCK_OBJECT_MONITOR(lock);
675+
}
676+
updateMonitorInfo(currentThread, objectMonitor);
677+
}
678+
}
679+
J9VMJDKINTERALVMCONTINUATION_SET_BLOCKER(currentThread, contObj, NULL);
680+
}
681+
652682
UDATA
653-
preparePinnedVirtualThreadForUnmount(J9VMThread *currentThread, j9object_t syncObj)
683+
preparePinnedVirtualThreadForUnmount(J9VMThread *currentThread, j9object_t syncObj, BOOLEAN isObjectWait)
654684
{
655685
UDATA result = J9_OBJECT_MONTIOR_YIELD_VIRTUAL;
656686
if (0 < currentThread->ownedMonitorCount) {
@@ -708,6 +738,14 @@ preparePinnedVirtualThreadForUnmount(J9VMThread *currentThread, j9object_t syncO
708738
j9object_t continuationObj = J9VMJAVALANGVIRTUALTHREAD_CONT(currentThread, currentThread->threadObject);
709739
J9VMJDKINTERALVMCONTINUATION_SET_BLOCKER(currentThread, continuationObj, syncObj);
710740

741+
if (isObjectWait) {
742+
/* Add thread object to monitor's waiting list. */
743+
omrthread_monitor_enter(currentThread->javaVM->blockedVirtualThreadsMutex);
744+
J9VMJAVALANGVIRTUALTHREAD_SET_NEXT(currentThread, currentThread->threadObject, syncObjectMonitor->waitingVirtualThreads);
745+
syncObjectMonitor->waitingVirtualThreads = currentThread->threadObject;
746+
omrthread_monitor_exit(currentThread->javaVM->blockedVirtualThreadsMutex);
747+
}
748+
711749
done:
712750
return result;
713751
}

0 commit comments

Comments
 (0)