oracle/graal · critical · GraalError
out of registers%s
Error message
out of registers%s
What it means
LIRCompilerBackend.emitLIR catches OutOfRegistersException from LIR generation/register allocation. If allocation was restricted via -Dgraal.RegisterPressure and BailoutOnRegisterPressureFailure is false, it retries unrestricted; otherwise (or if the retry itself fails) it converts the failure into a hard GraalError('out of registers...') listing the restriction. This is an internal compiler error, not a normal bailout — the compilation cannot proceed at all.
Source
Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/gen/LIRCompilerBackend.java:123
} finally {
graph.checkCancellation();
}
}
@SuppressWarnings("try")
public static LIRGenerationResult emitLIR(Backend backend, StructuredGraph graph, Object stub, RegisterConfig registerConfig, LIRSuites lirSuites,
EntryPointDecorator entryPointDecorator) {
String registerPressure = GraalOptions.RegisterPressure.getValue(graph.getOptions());
String[] allocationRestrictedTo = registerPressure == null ? null : registerPressure.split(",");
try {
return emitLIR0(backend, graph, stub, registerConfig, lirSuites, allocationRestrictedTo, entryPointDecorator);
} catch (OutOfRegistersException e) {
if (allocationRestrictedTo != null && !GraalOptions.BailoutOnRegisterPressureFailure.getValue(graph.getOptions())) {
allocationRestrictedTo = null;
return emitLIR0(backend, graph, stub, registerConfig, lirSuites, allocationRestrictedTo, entryPointDecorator);
}
/* If the re-execution fails we convert the exception into a "hard" failure */
throw new GraalError(e, "out of registers%s", allocationRestrictedTo == null ? "" : ": " + Arrays.toString(allocationRestrictedTo));
} finally {
graph.checkCancellation();
}
}
@SuppressWarnings("try")
private static LIRGenerationResult emitLIR0(Backend backend,
StructuredGraph graph,
Object stub,
RegisterConfig registerConfig,
LIRSuites lirSuites,
String[] allocationRestrictedTo, EntryPointDecorator entryPointDecorator) {
DebugContext debug = graph.getDebug();
try (DebugContext.Scope ds = debug.scope("EmitLIR"); DebugCloseable a = EmitLIR.start(debug)) {
assert graph.isAfterStage(StageFlag.VALUE_PROXY_REMOVAL);
ScheduleResult schedule = graph.getLastSchedule();
HIRBlock[] blocks = schedule.getCFG().getBlocks();View on GitHub (pinned to a66e9ccd1d)
Solutions
- Remove or widen the -Dgraal.RegisterPressure restriction — the message lists the exact restricted set that failed.
- If you intentionally restrict allocation, drop -Dgraal.BailoutOnRegisterPressureFailure=true so the compiler can retry with all registers as the fallback.
- If no RegisterPressure was set (message shows no register list), this is a compiler/backend bug — report it with the graph dump and stack trace.
Example fix
# before -Dgraal.RegisterPressure=rax,rbx -Dgraal.BailoutOnRegisterPressureFailure=true # after -Dgraal.RegisterPressure=rax,rbx,rcx,rdx # or remove the option entirely
Defensive patterns
Strategy: fallback
Try / catch
try {
LIRGenerationResult lir = LIRCompilerBackend.emitLIR(backend, graph, stub, registerConfig, lirSuites, decorator);
} catch (GraalError e) {
if (e.getMessage().startsWith("out of registers")) {
// retry without RegisterPressure restriction
LIRGenerationResult lir = LIRCompilerBackend.emitLIR(backend, graph, stub, registerConfig, lirSuites, decorator); // with unrestricted config
} else {
throw e;
}
} Prevention
- Never enable RegisterPressure restrictions without also leaving BailoutOnRegisterPressureFailure=false so the unrestricted retry remains possible.
- Smoke-test restricted-register configurations per backend after every Graal upgrade — LIR constraints change.
When it happens
Trigger: Setting -Dgraal.RegisterPressure to too few registers for the LIR's needs (e.g. a single register for code containing 64-bit operations needing scratch registers), together with -Dgraal.BailoutOnRegisterPressureFailure=true, which skips the unrestricted retry. Also thrown when even unrestricted allocation runs out of registers, which normally indicates a backend bug.
Common situations: Register-allocation experiments and CI fuzzing configurations using RegisterPressure; AArch64/x86 lists that omit mandatory registers needed by specific LIR instructions; changes in LIR instruction constraints after a Graal upgrade making an old restriction list impossible to satisfy.
Related errors
- register %s is not allocatable
- SpectrePHTBarriers can be set to 'AllTargets' if and only if
- Error loading phase plan from %s
- %s must not kill %s
- No options specified for MethodFilter:
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/4517efb267920ef4.
Report an issue: GitHub.