oracle/graal · warning · PermanentBailoutException
Can not duplicate block with JSR data
Error message
Can not duplicate block with JSR data
What it means
Thrown by BciBlock.duplicate() when the bytecode block mapping tries to duplicate a BciBlock that carries JSR (subroutine) data. Block duplication is used to make irreducible loops reducible; JSR/RET subroutine state cannot be safely cloned (the jsrData tracks subroutine-specific return addresses), so such duplication permanently bails out the compilation.
Source
Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/BciBlockMapping.java:436
if (block.jsrData != null) {
block.jsrData = block.jsrData.copy();
}
block.successors = new ArrayList<>();
for (var sux : successors) {
block.addSuccessor(sux);
}
block.loops = (BitSet) block.loops.clone();
return block;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
public BciBlock duplicate() {
try {
BciBlock block = (BciBlock) super.clone();
if (block.jsrData != null) {
throw new PermanentBailoutException("Can not duplicate block with JSR data");
}
block.successors = new ArrayList<>();
for (var sux : successors) {
block.addSuccessor(sux);
}
block.loops = new BitSet();
block.loopId = 0;
block.id = UNASSIGNED_ID;
block.isLoopHeader = false;
block.visited = false;
block.active = false;
block.predecessorCount = 0;
block.loopIdChain = null;
block.duplicate = true;
return block;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}View on GitHub (pinned to a66e9ccd1d)
Solutions
- Recompile the offending class with a modern compiler (javac >= Java 6 target) so JSR/RET subroutines are inlined into bytecode.
- If the bytecode comes from an instrumentation/obfuscation tool, update or configure it to not emit JSR/RET.
- Accept that Graal permanently bails out on this method — HotSpot falls back to C2/interpreter; no Graal flag fixes JSR duplication.
Defensive patterns
Strategy: fallback
Try / catch
// PermanentBailoutException is handled by HotSpot: Graal stops, C2/interpreter takes over. // No caller-level catch is useful; fix the bytecode instead.
Prevention
- Compile classes with javac targeting Java 6+ so JSR/RET is inlined away.
- Avoid bytecode tools that emit JSR/RET in code that will be hot-compiled.
When it happens
Trigger: Compiling (or parsing for graph building) a method that combines old-style JSR/RET subroutines with an irreducible control-flow graph, forcing BciBlockMapping's duplication pass (MaxDuplicationFactor > 1.0) to clone a block whose jsrData is non-null.
Common situations: Methods produced by old bytecode generators, bytecode-instrumentation tools, or obfuscators that still emit JSR/RET plus unstructured jumps; extremely rare in modern javac output (JSR deprecated since Java 6).
Related errors
- Too many loops in method
- Irreducible
- Non-reducible loop requires too much duplication. Setting %s
- Block that is reached by a fall through end of code is reach
- cannot link call from %s
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/589461bfdd6946bf.
Report an issue: GitHub.