{"record":{"id":"586708bbe7d194dd","repo":"oracle/graal","slug":"unbalanced-monitor-enter-exit-in-osr-compilation-w","errorCode":null,"errorMessage":"Unbalanced monitor enter-exit in OSR compilation with locks: ","messagePattern":"Unbalanced monitor enter-exit in OSR compilation with locks: ","errorType":"exception","errorClass":"PermanentBailoutException","httpStatus":null,"severity":"error","filePath":"compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/phases/OnStackReplacementPhase.java","lineNumber":237,"sourceCode":"            OsrWithLocksCount.increment(debug);\n            try (DebugCloseable context = osrStart.withNodeSourcePosition()) {\n                for (int i = osrState.monitorIdCount() - 1; i >= 0; --i) {\n                    MonitorIdNode id = osrState.monitorIdAt(i);\n                    ValueNode lockedObject = osrState.lockAt(i);\n                    OSRMonitorEnterNode osrMonitorEnter = graph.add(new OSRMonitorEnterNode(lockedObject, id));\n                    osrMonitorEnter.setStateAfter(osrStart.stateAfter());\n                    FixedNode oldNext = osrStart.next();\n                    oldNext.replaceAtPredecessor(null);\n                    osrMonitorEnter.setNext(oldNext);\n                    osrStart.setNext(osrMonitorEnter);\n                }\n            }\n\n            debug.dump(DebugContext.DETAILED_LEVEL, graph, \"After inserting OSR monitor enters\");\n            try {\n                new VerifyLockDepthPhase().run(graph);\n            } catch (VerifyLockDepthPhase.LockStructureError e) {\n                throw new PermanentBailoutException(\"Unbalanced monitor enter-exit in OSR compilation with locks: \" + e.getMessage());\n            }\n        }\n        debug.dump(DebugContext.DETAILED_LEVEL, graph, \"OnStackReplacement result\");\n        new DeadCodeEliminationPhase(Required).apply(graph);\n        /*\n         * There must not be any parameter nodes left after OSR compilation.\n         */\n        assert graph.getNodes(ParameterNode.TYPE).count() == 0 : \"OSR Compilation contains references to parameters.\";\n    }\n\n    /**\n     * Generates a speculative type check on {@code osrLocal} for {@code narrowedStamp}.\n     *\n     * @return a {@link PiNode} that narrows the type of {@code osrLocal} to {@code narrowedStamp}\n     */\n    private static ValueNode narrowOsrLocal(StructuredGraph graph, Stamp narrowedStamp, ValueNode osrLocal, SpeculationReason reason,\n                    OSRStartNode osrStart, EntryProxyNode proxy, FrameState osrState) {\n","sourceCodeStart":219,"sourceCodeEnd":255,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/phases/OnStackReplacementPhase.java#L219-L255","documentation":"PermanentBailoutException thrown when VerifyLockDepthPhase, run after OnStackReplacementPhase re-inserts monitor enters for the OSR entry, reports a LockStructureError. The error message is prefixed with 'Unbalanced monitor enter-exit in OSR compilation with locks: ' and describes the exact lock-depth violation. It means the reconstructed lock ordering at the OSR entry would not match the interpreter's monitor stack, so compiled code could not legally acquire/release the monitors.","triggerScenarios":"OSR compilation of a method with monitors where re-materializing monitorenter nodes at OSR start yields a lock depth that does not return to zero or mismatches per exception path — typically nested/conditional synchronization on the OSR path with SupportOSRWithLocks enabled.","commonSituations":"Complex synchronized control flow (locks acquired conditionally inside the loop, nested monitors, try/finally around monitorexit) hitting OSR; usually not actionable by end users — it is a compiler limitation that safely falls back to the interpreter.","solutions":["No JVM action needed: the bailout is safe; HotSpot continues interpreting the method.","Simplify the synchronization structure around the hot loop (hoist synchronized out of the loop) to make OSR+locks verifiable.","Compiler developers: reproduce with -Dgraal.Dump=:2 and inspect 'After inserting OSR monitor enters' to see which path breaks lock-depth balance."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    compileResult = compile(task);\n} catch (PermanentBailoutException e) {\n    if (e.getMessage().startsWith(\"Unbalanced monitor enter-exit\")) {\n        // safe fallback: interpreter continues; log and move on\n    }\n}","preventionTips":["Keep monitor nesting shallow and unconditional around hot loops.","Report recurring OSR-lock bails with graal dumps attached so the compiler team can fix the shape."],"tags":["graalvm","osr","locks","verification","bailout"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}