@@ -923,14 +923,108 @@ preparePinnedVirtualThreadForUnmount(J9VMThread *currentThread, j9object_t syncO
923
923
UDATA result = J9_OBJECT_MONITOR_YIELD_VIRTUAL;
924
924
J9ObjectMonitor *syncObjectMonitor = NULL ;
925
925
J9ObjectMonitor *enteredMonitorsList = NULL ;
926
- j9objectmonitor_t lock = 0 ;
927
- j9object_t continuationObj = NULL ;
928
926
UDATA monitorCount = 0 ;
929
927
J9JavaVM *vm = currentThread->javaVM ;
930
928
931
929
if (NULL != syncObj) {
930
+ j9objectmonitor_t volatile *lwEA = VM_ObjectMonitor::inlineGetLockAddress (currentThread, syncObj);
931
+ j9objectmonitor_t lock = J9_LOAD_LOCKWORD (currentThread, lwEA);
932
+ omrthread_monitor_t monitor = NULL ;
933
+
932
934
enterVThreadTransitionCritical (currentThread, (jobject)¤tThread->threadObject );
935
+
936
+ if (J9_LOCK_IS_INFLATED (lock)) {
937
+ syncObjectMonitor = J9_INFLLOCK_OBJECT_MONITOR (lock);
938
+ } else {
939
+ if (isObjectWait) {
940
+ syncObjectMonitor = objectMonitorInflate (currentThread, syncObj, lock);
941
+ if (NULL == syncObjectMonitor) {
942
+ result = J9_OBJECT_MONITOR_OOM;
943
+ goto done;
944
+ }
945
+ } else {
946
+ /* This must be a monitor enter case, so this implies that a monitor entry was
947
+ * created as the non-blocking path would have failed.
948
+ * Since a monitor can only be inflated by a thread that owns it, we can't directly
949
+ * inflate the blocking monitor.
950
+ */
951
+ restart:
952
+ #if defined(J9VM_THR_LOCK_RESERVATION)
953
+ {
954
+ while (OBJECT_HEADER_LOCK_RESERVED == (lock & (OBJECT_HEADER_LOCK_RESERVED | OBJECT_HEADER_LOCK_INFLATED))) {
955
+ cancelLockReservation (currentThread);
956
+ /* Calculate the new lock word, since the object may have moved. */
957
+ syncObj = J9VMTHREAD_BLOCKINGENTEROBJECT (currentThread, currentThread);
958
+ lwEA = VM_ObjectMonitor::inlineGetLockAddress (currentThread, syncObj);
959
+ lock = J9_LOAD_LOCKWORD (currentThread, lwEA);
960
+ if (VM_ObjectMonitor::inlineFastInitAndEnterMonitor (currentThread, lwEA)) {
961
+ result = (UDATA)syncObj;
962
+ goto done;
963
+ }
964
+ }
965
+ }
966
+ #endif /* J9VM_THR_LOCK_RESERVATION */
967
+ syncObjectMonitor = monitorTableAt (currentThread, syncObj);
968
+ monitor = syncObjectMonitor->monitor ;
969
+
970
+ /* Try acquire the inflated monitor */
971
+ if (0 == omrthread_monitor_try_enter (monitor)) {
972
+ /* If the INFLATED bit is set, then it is already inflated and we own the object monitor. */
973
+ if (J9_ARE_ANY_BITS_SET (((J9ThreadMonitor *)monitor)->flags , J9THREAD_MONITOR_INFLATED)) {
974
+ currentThread->ownedMonitorCount += 1 ;
975
+ result = (UDATA)syncObj;
976
+ goto done;
977
+ }
978
+
979
+ /* Loop until either lock is inflated or FLC bit is set. */
980
+ while (!J9_LOCK_IS_INFLATED (lock)) {
981
+ /* The monitor isn't inflated yet, but we can update the lockword now. */
982
+ UDATA newLockword = 0 ;
983
+ UDATA count = J9_FLATLOCK_COUNT (lock);
984
+ if (0 == count) {
985
+ /* Lock is unlocked, so try to directly acquire it as a flatlock. */
986
+ newLockword = (UDATA)currentThread;
987
+ } else {
988
+ /* Change the lock to flat with FLC bit set so it will be inflated during exit. */
989
+ newLockword = (UDATA)J9_FLATLOCK_OWNER (lock)
990
+ | ((count - 1 ) << OBJECT_HEADER_LOCK_V2_RECURSION_OFFSET)
991
+ | OBJECT_HEADER_LOCK_FLC;
992
+ }
993
+ j9objectmonitor_t const oldValue = lock;
994
+ lock = VM_ObjectMonitor::compareAndSwapLockword (currentThread, lwEA, lock, (j9objectmonitor_t )newLockword);
995
+ if (lock == oldValue) {
996
+ /* CAS succeeded, we can proceed with using the inflated monitor. */
997
+ VM_ObjectMonitor::incrementCancelCounter (J9OBJECT_CLAZZ (currentThread, syncObj));
998
+
999
+ if (J9_FLATLOCK_OWNER (lock) == currentThread) {
1000
+ /* Lock is acquired. */
1001
+ currentThread->ownedMonitorCount += 1 ;
1002
+ result = (UDATA)syncObj;
1003
+ goto done;
1004
+ }
1005
+ break ;
1006
+ #if defined(J9VM_THR_LOCK_RESERVATION)
1007
+ } else if (OBJECT_HEADER_LOCK_RESERVED == (lock & (OBJECT_HEADER_LOCK_RESERVED | OBJECT_HEADER_LOCK_INFLATED))) {
1008
+ /* Lock is now reserved, exit the inflated monitor and restart to cancel lock reservation. */
1009
+ omrthread_monitor_exit (monitor);
1010
+ goto restart;
1011
+ #endif /* J9VM_THR_LOCK_RESERVATION */
1012
+ }
1013
+ /* CAS failed, another thread must have updated the lockword, retry the check. */
1014
+ }
1015
+ } else {
1016
+ /* Inflated monitor owned by another thread, so the lockword update will be completed by them. */
1017
+ lock = J9_LOAD_LOCKWORD (currentThread, lwEA);
1018
+ /* We can safely continue if the lock is inflated or FLC bit is set. */
1019
+ if (0 == (lock & (OBJECT_HEADER_LOCK_FLC | OBJECT_HEADER_LOCK_INFLATED))) {
1020
+ goto restart;
1021
+ }
1022
+ }
1023
+ }
1024
+ }
933
1025
}
1026
+
1027
+ /* Walk all owned monitors and detach from current carrier thread. */
934
1028
if (currentThread->ownedMonitorCount > 0 ) {
935
1029
J9StackWalkState walkState;
936
1030
@@ -979,28 +1073,7 @@ preparePinnedVirtualThreadForUnmount(J9VMThread *currentThread, j9object_t syncO
979
1073
}
980
1074
981
1075
if (NULL != syncObj) {
982
- if (!LN_HAS_LOCKWORD (currentThread, syncObj)) {
983
- syncObjectMonitor = monitorTablePeek (vm, syncObj);
984
- if (NULL != syncObjectMonitor) {
985
- lock = J9_LOAD_LOCKWORD (currentThread, &syncObjectMonitor->alternateLockword );
986
- } else {
987
- lock = 0 ;
988
- }
989
- } else {
990
- lock = J9OBJECT_MONITOR (currentThread, syncObj);
991
- }
992
-
993
- if (!J9_LOCK_IS_INFLATED (lock)) {
994
- syncObjectMonitor = objectMonitorInflate (currentThread, syncObj, lock);
995
- if (NULL == syncObjectMonitor) {
996
- result = J9_OBJECT_MONITOR_OOM;
997
- goto done;
998
- }
999
- } else {
1000
- syncObjectMonitor = J9_INFLLOCK_OBJECT_MONITOR (lock);
1001
- }
1002
-
1003
- continuationObj = J9VMJAVALANGVIRTUALTHREAD_CONT (currentThread, currentThread->threadObject );
1076
+ j9object_t continuationObj = J9VMJAVALANGVIRTUALTHREAD_CONT (currentThread, currentThread->threadObject );
1004
1077
J9VMJDKINTERNALVMCONTINUATION_SET_BLOCKER (currentThread, continuationObj, syncObj);
1005
1078
1006
1079
if (isObjectWait) {
@@ -1024,19 +1097,24 @@ preparePinnedVirtualThreadForUnmount(J9VMThread *currentThread, j9object_t syncO
1024
1097
currentThread->currentContinuation ->objectWaitMonitor = syncObjectMonitor;
1025
1098
omrthread_monitor_exit (vm->blockedVirtualThreadsMutex );
1026
1099
} else {
1100
+ /* Increment the wait count on inflated monitor. */
1027
1101
VM_AtomicSupport::addU32 (&syncObjectMonitor->virtualThreadWaitCount , 1 );
1102
+ currentThread->currentContinuation ->objectWaitMonitor = syncObjectMonitor;
1028
1103
}
1029
-
1030
- /* Clear the blocking object on the carrier thread. */
1031
- J9VMTHREAD_SET_BLOCKINGENTEROBJECT (currentThread, currentThread, NULL );
1032
1104
}
1033
1105
1034
1106
/* Subtract the detached monitor from the carrier thread's lockedmonitorcount. */
1035
1107
currentThread->osThread ->lockedmonitorcount -= monitorCount;
1036
1108
1037
1109
done:
1038
- if ((NULL != syncObj) && (J9_OBJECT_MONITOR_YIELD_VIRTUAL != result)) {
1039
- exitVThreadTransitionCritical (currentThread, (jobject)¤tThread->threadObject );
1110
+ if (NULL != syncObj) {
1111
+ if (J9_OBJECT_MONITOR_YIELD_VIRTUAL != result) {
1112
+ exitVThreadTransitionCritical (currentThread, (jobject)¤tThread->threadObject );
1113
+ }
1114
+ if (!isObjectWait) {
1115
+ /* Clear the blocking object on the carrier thread. */
1116
+ J9VMTHREAD_SET_BLOCKINGENTEROBJECT (currentThread, currentThread, NULL );
1117
+ }
1040
1118
}
1041
1119
return result;
1042
1120
}
0 commit comments