oracle/graal · info · PermanentBailoutException
concurrent setting of breakpoint
Error message
concurrent setting of breakpoint
What it means
Thrown by BytecodeParser when it encounters the BREAKPOINT opcode (0xc2) in the bytecode stream while parsing. The breakpoint opcode is written into bytecode by debuggers (JVMTI SetBreakpoint) at runtime; a class file parsed with that opcode present means the bytecode was mutated concurrently, so Graal permanently bails out rather than compile transient debug state.
Source
Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/BytecodeParser.java:5975
case INVOKESPECIAL : cpi = stream.readCPI(); genInvokeSpecial(cpi, opcode); break;
case INVOKESTATIC : cpi = stream.readCPI(); genInvokeStatic(cpi, opcode); break;
case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(cpi, opcode); break;
case INVOKEDYNAMIC : cpi = stream.readCPI4(); genInvokeDynamic(cpi, opcode); break;
case NEW : genNewInstance(stream.readCPI()); break;
case NEWARRAY : genNewPrimitiveArray(stream.readLocalIndex()); break;
case ANEWARRAY : genNewObjectArray(stream.readCPI()); break;
case ARRAYLENGTH : genArrayLength(); break;
case ATHROW : genThrow(); break;
case CHECKCAST : genCheckCast(stream.readCPI()); break;
case INSTANCEOF : genInstanceOf(stream.readCPI()); break;
case MONITORENTER : genMonitorEnter(frameState.pop(JavaKind.Object), stream.nextBCI()); break;
case MONITOREXIT : genMonitorExit(frameState.pop(JavaKind.Object), null, stream.nextBCI(), false, true); break;
case MULTIANEWARRAY : genNewMultiArray(stream.readCPI()); break;
case IFNULL : genIfNull(Condition.EQ); break;
case IFNONNULL : genIfNull(Condition.NE); break;
case GOTO_W : genGoto(); break;
case JSR_W : genJsr(stream.readBranchDest()); break;
case BREAKPOINT : throw new PermanentBailoutException("concurrent setting of breakpoint");
default : throw new PermanentBailoutException("Unsupported opcode %d (%s) [bci=%d]", opcode, nameOf(opcode), bci);
}
// @formatter:on
// Checkstyle: resume
}
private void genArrayLength() {
ValueNode array = frameState.pop(JavaKind.Object);
frameState.push(JavaKind.Int, append(genArrayLength(array)));
}
@Override
public ResolvedJavaMethod getMethod() {
return method;
}
@Override
public Bytecode getCode() {View on GitHub (pinned to a66e9ccd1d)
Solutions
- Remove the breakpoint in the debugger and let HotSpot re-attempt compilation of the method.
- Recompile/relaunch without the debugger attached for benchmarking or production JIT behavior.
- If caused by an agent, configure it to use non-breakpoint instrumentation (e.g. class retransformation instead).
Defensive patterns
Strategy: fallback
Try / catch
// transient debugger-induced bailout; HotSpot retries after the breakpoint is removed.
Prevention
- Detach debuggers before benchmarking or production runs.
- Prefer JVMTI class-retransformation agents over breakpoint-based ones on Graal JVMs.
When it happens
Trigger: stream bytecode == Bytecodes.BREAKPOINT during processBytecode — i.e. a breakpoint was set in the method between the moment HotSpot fetched the bytecode and Graal parsing it (concurrent JVMTI SetBreakpoint), or a class file literally containing opcode 0xc2.
Common situations: Attaching a debugger (or a coverage/profiling agent using breakpoints) to a JVM while Graal compiles the same method; race between debugger instrumentation and JIT compilation; class files emitted by bytecode tools that misuse 0xc2.
Related errors
- Can not duplicate block with JSR data
- 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
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/05891c1d00689dad.
Report an issue: GitHub.