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

  1. Recompile the offending class with a modern compiler (javac >= Java 6 target) so JSR/RET subroutines are inlined into bytecode.
  2. If the bytecode comes from an instrumentation/obfuscation tool, update or configure it to not emit JSR/RET.
  3. 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

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


AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14). Data as JSON: /api/errors/589461bfdd6946bf. Report an issue: GitHub.