| JDK 21 | JDK 22 |
|---|---|
| 21.0.2Fixed | 22 b24Fixed |
|
Relates :
|
|
|
Relates :
|
|
|
Relates :
|
|
|
Relates :
|
|
|
Relates :
|
While working on recursive-locking support for lightweight locking (-XX:LockingMode=2), we hit an assert that we have an inconsistent lock stack.
One of the problematic tests is the following:
```
class EARelockingArgEscapeLWLockedInCalleeFrame_2Target extends EATestCaseBaseTarget {
...
public void dontinline_testMethod() {
XYVal l1 = new XYVal(1, 1); // ArgEscape
XYVal l2 = new XYVal(4, 2); // NoEscape, scalar replaced
synchronized (l1) { // eliminated
synchronized (l2) { // eliminated
l1.dontinline_sync_method(this); // l1 escapes
}
}
iResult = l2.x + l2.y;
}
```
The test runs the above method enough time to for it to get C2 compiled. Then it attaches a debugger and adds a breakpoint deeper inside dontlinine_sync_method.
What we see in gdb is that `l1` is an existing object that has been pushed onto the deoptee thread's locking stack because of the dontinline_sync_method call. We then try to "replay" `synchronized (l1)` and `synchronized (l2)` in Deoptimization::relock_objects. This gives us the incorrect lock order [l1, l1, l2] while the actual code has the [l1, l2, l1] lock order. This then messes up the lock stack in the unlock path when we perform our recursive lock handling.
The lightweight code in openjdk/jdk works because the recursive lock gets inflated and removed from the lock stack. However, I can get the upstream lightweight locking to assert by removing the recursive locking in the test case:
```
class EARelockingArgEscapeLWLockedInCalleeFrame_2Target extends EATestCaseBaseTarget {
...
public void dontinline_testMethod() {
XYVal l1 = new XYVal(1, 1);
XYVal l2 = new XYVal(4, 2);
XYVal l3 = new XYVal(5, 3);
synchronized (l1) {
synchronized (l2) {
l3.dontinline_sync_method(this);
}
}
iResult = l2.x + l2.y;
}
```
This asserts with the following:
```
# Internal Error (/home/stefank/git/jdk/open/src/hotspot/share/runtime/lockStack.inline.hpp:86), pid=265437, tid=265440
# assert(contains(o)) failed: entry must be present: 0x00000000ffa00130
...
V [libjvm.so+0x1743709] LockStack::remove(oop)+0x3e9 (lockStack.inline.hpp:86)
V [libjvm.so+0x173f78d] ObjectSynchronizer::exit(oop, BasicLock*, JavaThread*)+0x2fd (synchronizer.cpp:590)
V [libjvm.so+0xe7667c] InterpreterRuntime::monitorexit(BasicObjectLock*)+0x18c (interpreterRuntime.cpp:779)
j EARelockingArgEscapeLWLockedInCalleeFrame_2Target.dontinline_testMethod()V+47
j EATestCaseBaseTarget.run()V+64
|