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
|