{"record":{"id":"286445dac36a77b3","repo":"oracle/graal","slug":"osr-compilation-without-osr-entry-loop","errorCode":null,"errorMessage":"OSR compilation without OSR entry loop.","messagePattern":"OSR compilation without OSR entry loop\\.","errorType":"exception","errorClass":"PermanentBailoutException","httpStatus":null,"severity":"error","filePath":"compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/phases/OnStackReplacementPhase.java","lineNumber":139,"sourceCode":"        if (graph.getEntryBCI() == JVMCICompiler.INVOCATION_ENTRY_BCI) {\n            // This happens during inlining in a OSR method, because the same phase plan will be\n            // used.\n            assert graph.getNodes(EntryMarkerNode.TYPE).isEmpty();\n            return;\n        }\n        debug.dump(DebugContext.DETAILED_LEVEL, graph, \"OnStackReplacement initial at bci %d\", graph.getEntryBCI());\n\n        final EntryMarkerNode originalOSRNode = getEntryMarker(graph);\n        final LoopBeginNode originalOSRLoop = osrLoop(originalOSRNode, providers);\n        final boolean currentOSRWithLocks = osrWithLocks(originalOSRNode);\n\n        if (originalOSRLoop == null) {\n            /*\n             * OSR with Locks: We do not have an OSR loop for the original OSR bci. Therefore we\n             * cannot decide where to deopt and which framestate will be used. In the worst case the\n             * framestate of the OSR entry would be used.\n             */\n            throw new PermanentBailoutException(\"OSR compilation without OSR entry loop.\");\n        }\n\n        if (!supportOSRWithLocks(graph.getOptions()) && currentOSRWithLocks) {\n            throw new PermanentBailoutException(\"OSR with locks disabled.\");\n        }\n\n        EntryMarkerNode osr = OnStackReplacementUtils.peelEntryLoops(graph, providers.getLoopsDataProvider(), () -> getEntryMarker(graph), loop -> {\n        },\n                        (iterations, maxIterations) -> {\n                            throw GraalError.shouldNotReachHere(iterations + \" \" + maxIterations); // ExcludeFromJacocoGeneratedReport\n                        }, \"OnStackReplacement loop peeling result\");\n\n        StartNode start = graph.start();\n        FrameState osrState = osr.stateAfter();\n        OSRStartNode osrStart;\n        try (DebugCloseable context = osr.withNodeSourcePosition()) {\n            osr.setStateAfter(null);\n            osrStart = graph.add(new OSRStartNode());","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/phases/OnStackReplacementPhase.java#L121-L157","documentation":"PermanentBailoutException thrown by OnStackReplacementPhase when an OSR compilation's EntryMarkerNode cannot be associated with any loop in the CFG (osrLoop() returns null). Graal can only compile an OSR entry if the bytecode position sits inside a loop it can identify; without it there is no safe point to deoptimize to or frame state to use, so the compilation is permanently bailed out (the method keeps running interpreted).","triggerScenarios":"A HotSpot OSR compilation request (compile_at_bci with a non-negative OSR bci) where after parsing the OSR entry marker's block belongs to no CFGLoop — e.g. the loop was removed/optimized away during parsing, or the entry bci no longer lies inside a natural loop because of prior transformations.","commonSituations":"Long-running loops in startup/warmup code that trigger OSR while the graph shape confuses loop detection; changes in frontend parsing or loop peeling logic in compiler development; rarely, exotic bytecode from instrumentation agents.","solutions":["Treat it as non-fatal: it is a bailout — HotSpot falls back to the interpreter for this OSR; no user action is strictly required.","If it recurs noisily, disable Graal OSR for the method/class (-Dgraal.CompileLocally... or use -XX:-UseJVMCICompiler for that run) to confirm.","Compiler developers: dump the graph (-Dgraal.Dump=:1 around OSR) and inspect why the entry marker is loop-less before OnStackReplacementPhase runs."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Compiler-internal; callers of CompilationTask/CompilationResult may treat bailouts as expected:\ntry {\n    compileResult = compile(task);\n} catch (PermanentBailoutException e) { // e.g. 'OSR compilation without OSR entry loop.'\n    // expected for some OSR shapes: method stays interpreted, request returns failure gracefully\n}","preventionTips":["Monitor bailout counts in CI rather than failing on them; OSR bails are safe fallbacks.","Compiler devs: keep -Dgraal.Dump/:2 enabled when reproducing OSR bailout reports."],"tags":["graalvm","osr","compiler","bailout"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}