Skip to content

Commit 3b07be0

Browse files
[GR-57334] Update JavaMonitor to jdk-24+11.
PullRequest: graal/18630
2 parents 7ee886c + a55bb5b commit 3b07be0

File tree

2 files changed

+50
-33
lines changed

2 files changed

+50
-33
lines changed

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646

4747
/**
4848
* {@link JavaMonitor} is based on the code of {@link java.util.concurrent.locks.ReentrantLock} as
49-
* of JDK 21+26.
49+
* of JDK 24+11.
5050
*
5151
* Only the relevant methods from the JDK sources have been kept. Some additional Native
5252
* Image-specific functionality has been added.

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitorQueuedSynchronizer.java

Lines changed: 49 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141

4242
/**
4343
* {@link JavaMonitorQueuedSynchronizer} is based on the code of
44-
* {@link java.util.concurrent.locks.AbstractQueuedLongSynchronizer} as of JDK 21+26. This class
44+
* {@link java.util.concurrent.locks.AbstractQueuedLongSynchronizer} as of JDK 24+11. This class
4545
* could be merged with {@link JavaMonitor} but we keep it separate because that way diffing against
4646
* the JDK sources is easier.
4747
*
@@ -60,7 +60,7 @@
6060
*/
6161
@BasedOnJDKClass(AbstractQueuedLongSynchronizer.class)
6262
abstract class JavaMonitorQueuedSynchronizer {
63-
// Node.status field values
63+
// Node status bits, also used as argument and return values
6464
static final int WAITING = 1; // must be 1
6565
static final int CANCELLED = 0x80000000; // must be negative
6666
static final int COND = 2; // in a condition wait
@@ -71,38 +71,38 @@ abstract class JavaMonitorQueuedSynchronizer {
7171
// see AbstractQueuedLongSynchronizer.Node
7272
@BasedOnJDKClass(value = AbstractQueuedLongSynchronizer.class, innerClass = "Node")
7373
abstract static class Node {
74-
volatile Node prev;
75-
volatile Node next;
76-
Thread waiter;
77-
volatile int status;
74+
volatile Node prev; // initially attached via casTail
75+
volatile Node next; // visibly nonnull when signallable
76+
Thread waiter; // visibly nonnull when enqueued
77+
volatile int status; // written by owner, atomic bit ops by others
7878

7979
// see AbstractQueuedLongSynchronizer.Node.casPrev(Node, Node)
80-
final boolean casPrev(Node c, Node v) {
80+
final boolean casPrev(Node c, Node v) { // for cleanQueue
8181
return U.weakCompareAndSetReference(this, PREV, c, v);
8282
}
8383

8484
// see AbstractQueuedLongSynchronizer.Node.casNext(Node, Node)
85-
final boolean casNext(Node c, Node v) {
85+
final boolean casNext(Node c, Node v) { // for cleanQueue
8686
return U.weakCompareAndSetReference(this, NEXT, c, v);
8787
}
8888

8989
// see AbstractQueuedLongSynchronizer.Node.getAndUnsetStatus(int)
90-
final int getAndUnsetStatus(int v) {
90+
final int getAndUnsetStatus(int v) { // for signalling
9191
return U.getAndBitwiseAndInt(this, STATUS, ~v);
9292
}
9393

9494
// see AbstractQueuedLongSynchronizer.Node.setPrevRelaxed(Node)
95-
final void setPrevRelaxed(Node p) {
95+
final void setPrevRelaxed(Node p) { // for off-queue assignment
9696
U.putReference(this, PREV, p);
9797
}
9898

9999
// see AbstractQueuedLongSynchronizer.Node.setStatusRelaxed(int)
100-
final void setStatusRelaxed(int s) {
100+
final void setStatusRelaxed(int s) { // for off-queue assignment
101101
U.putInt(this, STATUS, s);
102102
}
103103

104104
// see AbstractQueuedLongSynchronizer.Node.clearStatus()
105-
final void clearStatus() {
105+
final void clearStatus() { // for reducing unneeded signals
106106
U.putIntOpaque(this, STATUS, 0);
107107
}
108108

@@ -119,7 +119,7 @@ static final class ExclusiveNode extends Node {
119119
// see AbstractQueuedLongSynchronizer.ConditionNode
120120
@BasedOnJDKClass(value = AbstractQueuedLongSynchronizer.class, innerClass = "ConditionNode")
121121
static final class ConditionNode extends Node {
122-
ConditionNode nextWaiter;
122+
ConditionNode nextWaiter; // link to next waiting node
123123
long notifierJfrTid;
124124

125125
// see AbstractQueuedLongSynchronizer.ConditionNode.isReleasable()
@@ -153,16 +153,17 @@ protected final long getState() {
153153

154154
// see AbstractQueuedLongSynchronizer.setState(long)
155155
protected final void setState(long newState) {
156-
this.state = newState;
156+
state = newState;
157157
}
158158

159159
/**
160-
* For {@linkplain JavaMonitorConditionObject#await conditional waiting}, returns the number of
161-
* acquisitions, which is subsequently passed to {@link #tryRelease} to entirely release
162-
* ownership, and later to {@link #tryAcquire} to regain ownership after waiting.
160+
* Used for {@linkplain JavaMonitorConditionObject#await conditional waiting}. Returns the
161+
* number of acquisitions, which is subsequently passed to {@link #tryRelease} to entirely
162+
* release ownership, and later to {@link #tryAcquire} to regain ownership after waiting.
163163
*
164-
* While {@code AbstractQueuedLongSynchronizer} calls {@link #getState()} assuming that it
165-
* encodes the acquisition count, this method allows for more flexibility in implementations.
164+
* Note that {@code AbstractQueuedLongSynchronizer} calls {@link #getState()} instead, assuming
165+
* that the state encodes the acquisition count. This method allows for more flexibility in
166+
* implementations.
166167
*/
167168
protected abstract long getAcquisitions();
168169

@@ -205,13 +206,13 @@ final void enqueue(ConditionNode node) {
205206
boolean unpark = false;
206207
for (Node t;;) {
207208
if ((t = tail) == null && (t = tryInitializeHead()) == null) {
208-
unpark = true; // wake up to spin on OOME
209+
unpark = true; // wake up to spin on OOME
209210
break;
210211
}
211-
node.setPrevRelaxed(t); // avoid unnecessary fence
212+
node.setPrevRelaxed(t); // avoid unnecessary fence
212213
if (casTail(t, node)) {
213214
t.next = node;
214-
if (t.status < 0) { // wake up to clean link
215+
if (t.status < 0) { // wake up to clean link
215216
unpark = true;
216217
}
217218
break;
@@ -279,14 +280,15 @@ protected int getSpinAttempts(int parks) {
279280
return (1 << parks) - 1;
280281
}
281282

282-
// see AbstractQueuedLongSynchronizer.acquire(Node, long, boolean, boolean, boolean, long)
283+
// see AbstractQueuedLongSynchronizer.acquire(Node, long, false, false, false, 0L)
283284
@SuppressWarnings("all")
284285
final int acquire(Node node, long arg) {
285286
Thread current = Thread.currentThread();
287+
/* Spinning logic is SVM-specific. */
286288
int parks = 0;
287289
int spins = getSpinAttempts(parks);
288290
boolean first = false;
289-
Node pred = null;
291+
Node pred = null; // predecessor of node when enqueued
290292

291293
for (;;) {
292294
if (!first && (pred = (node == null) ? null : node.prev) != null && !(first = (head == pred))) {
@@ -302,6 +304,7 @@ final int acquire(Node node, long arg) {
302304
boolean acquired;
303305
try {
304306
if (spins > 0) {
307+
/* Spinning logic is SVM-specific. */
305308
spins = trySpinAcquire(spins, arg);
306309
acquired = (spins == SPIN_SUCCESS);
307310
assert !acquired || isHeldExclusively();
@@ -323,11 +326,11 @@ final int acquire(Node node, long arg) {
323326
}
324327
}
325328
Node t;
326-
if ((t = tail) == null) { // initialize queue
329+
if ((t = tail) == null) { // initialize queue
327330
if (tryInitializeHead() == null) {
328331
return acquireOnOOME(arg);
329332
}
330-
} else if (node == null) { // allocate; retry before enqueue
333+
} else if (node == null) { // allocate; retry before enqueue
331334
try {
332335
node = new ExclusiveNode();
333336
} catch (OutOfMemoryError oome) {
@@ -346,22 +349,28 @@ final int acquire(Node node, long arg) {
346349
} else if (node.status == 0) {
347350
node.status = WAITING; // enable signal and recheck
348351
} else {
352+
/* Spinning logic is SVM-specific. */
349353
parks++;
350354
spins = getSpinAttempts(parks);
351-
LockSupport.park(this);
355+
try {
356+
LockSupport.park(this);
357+
} catch (Error | RuntimeException ex) {
358+
cancelAcquire(node); // cancel & rethrow
359+
throw ex;
360+
}
352361
node.clearStatus();
353362
}
354363
}
355364
}
356365

357-
// see AbstractQueuedLongSynchronizer.acquireOnOOME(boolean, long)
366+
// see AbstractQueuedLongSynchronizer.acquireOnOOME(false, long)
358367
private int acquireOnOOME(long arg) {
359368
for (long nanos = 1L;;) {
360369
if (tryAcquire(arg)) {
361370
return 1;
362371
}
363-
U.park(false, nanos); // must use Unsafe park to sleep
364-
if (nanos < 1L << 30) { // max about 1 second
372+
U.park(false, nanos); // must use Unsafe park to sleep
373+
if (nanos < 1L << 30) { // max about 1 second
365374
nanos <<= 1;
366375
}
367376
}
@@ -401,7 +410,7 @@ private void cleanQueue() {
401410
}
402411
}
403412

404-
// see AbstractQueuedLongSynchronizer.cancelAcquire(Node, boolean, boolean)
413+
// see AbstractQueuedLongSynchronizer.cancelAcquire(Node, false, false)
405414
private int cancelAcquire(Node node) {
406415
if (node != null) {
407416
node.waiter = null;
@@ -446,23 +455,29 @@ public final class JavaMonitorConditionObject {
446455

447456
static final long OOME_COND_WAIT_DELAY = 10L * 1000L * 1000L; // 10 ms
448457

458+
JavaMonitorConditionObject() {
459+
}
460+
449461
// see AbstractQueuedLongSynchronizer.ConditionObject.doSignal(ConditionNode, boolean)
450462
@SuppressWarnings("all")
451463
private void doSignal(ConditionNode first, boolean all) {
452464
while (first != null) {
453465
ConditionNode next = first.nextWaiter;
466+
454467
if ((firstWaiter = next) == null) {
455468
lastWaiter = null;
456469
} else {
457470
first.nextWaiter = null; // GC assistance
458471
}
459472
if ((first.getAndUnsetStatus(COND) & COND) != 0) {
473+
/* JFR-related code is SVM-specific. */
460474
first.notifierJfrTid = SubstrateJVM.getCurrentThreadId();
461475
enqueue(first);
462476
if (!all) {
463477
break;
464478
}
465479
}
480+
466481
first = next;
467482
}
468483
}
@@ -562,6 +577,7 @@ private ConditionNode newConditionNode() {
562577
// see AbstractQueuedLongSynchronizer.ConditionObject.await()
563578
@SuppressWarnings("all")
564579
public void await(Object obj) throws InterruptedException {
580+
/* JFR-related code is SVM-specific. */
565581
long startTicks = JfrTicks.elapsedTicks();
566582
if (Thread.interrupted()) {
567583
JavaMonitorWaitEvent.emit(startTicks, obj, 0, 0L, false);
@@ -601,6 +617,7 @@ public void await(Object obj) throws InterruptedException {
601617
// see AbstractQueuedLongSynchronizer.ConditionObject.await(long, TimeUnit)
602618
@SuppressWarnings("all")
603619
public boolean await(Object obj, long time, TimeUnit unit) throws InterruptedException {
620+
/* JFR-related code is SVM-specific. */
604621
long startTicks = JfrTicks.elapsedTicks();
605622
long nanosTimeout = unit.toNanos(time);
606623
if (Thread.interrupted()) {
@@ -643,7 +660,7 @@ public boolean await(Object obj, long time, TimeUnit unit) throws InterruptedExc
643660

644661
// Unsafe
645662
private static final Unsafe U = Unsafe.getUnsafe();
646-
static final long STATE = U.objectFieldOffset(JavaMonitorQueuedSynchronizer.class, "state");
663+
private static final long STATE = U.objectFieldOffset(JavaMonitorQueuedSynchronizer.class, "state");
647664
private static final long HEAD = U.objectFieldOffset(JavaMonitorQueuedSynchronizer.class, "head");
648665
private static final long TAIL = U.objectFieldOffset(JavaMonitorQueuedSynchronizer.class, "tail");
649666
}

0 commit comments

Comments
 (0)