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

  1. Remove or widen the -Dgraal.RegisterPressure restriction — the message lists the exact restricted set that failed.
  2. If you intentionally restrict allocation, drop -Dgraal.BailoutOnRegisterPressureFailure=true so the compiler can retry with all registers as the fallback.
  3. 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

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


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