oracle/graal · critical · OutOfRegistersException

LinearScan: no register found

Error message

LinearScan: no register found

What it means

Thrown by LinearScanWalker when register allocation cannot satisfy an interval: no free register exists, the current interval cannot be spilled, and even the retry with register priority 'must have register' (for intervals with a pinned first usage) fails. The allocator assigns a spill slot, dumps/logs the detailed description, and rethrows as OutOfRegistersException so the compilation aborts cleanly instead of producing broken code.

Source

Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/alloc/lsra/LinearScanWalker.java:1060

                    if (firstUsage <= interval.from() + 1) {
                        if (registerPriority.equals(RegisterPriority.LiveAtLoopEnd)) {
                            /*
                             * Tool of last resort: we can not spill the current interval so we try
                             * to spill an active interval that has a usage but do not require a
                             * register.
                             */
                            debug.log("retry with register priority must have register");
                            continue;
                        }
                        String description = generateOutOfRegErrorMsg(interval, firstUsage, availableRegs);
                        /*
                         * assign a reasonable register and do a bailout in product mode to avoid
                         * errors
                         */
                        allocator.assignSpillSlot(interval);
                        debug.dump(DebugContext.INFO_LEVEL, allocator.getLIR(), description);
                        allocator.printIntervals(description);
                        throw new OutOfRegistersException("LinearScan: no register found", description);
                    }

                    splitAndSpillInterval(interval, reg, regUsePos);
                    return;
                } else {
                    if (debug.isLogEnabled()) {
                        debug.log("not able to spill current interval. firstUsage(register): %d, usePos: %d", firstUsage, regUsePos);
                    }
                }
                break;
            }

            // Fortify: Suppress Null Dereference false positive
            assert reg != null;

            boolean needSplit = blockPos[reg.number] <= intervalTo;

            int splitPos = blockPos[reg.number];

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Split the offending method into smaller methods to shorten live ranges and reduce peak register pressure
  2. Reduce inlining pressure around the failing code (e.g., lower inline thresholds or mark hot helpers @TruffleBoundary/not-inlinable)
  3. Run with -Dgraal.Dump=:2 and -Dgraal.PrintInlining=true to confirm which method/method context fails, then target that method
  4. If using a custom RegisterConfiguration, verify the allocatable register set for the affected kind is not accidentally empty or too small
  5. File a GraalVM issue with the dump: the detailed out-of-reg message (generateOutOfRegErrorMsg) identifies the interval and usage

Example fix

// before: many simultaneously live vectors exhaust the SIMD register file
double r = a0.add(a1).add(a2).add(a3)...add(a15).x;

// after: stage intermediates through locals that die early / reorder to shorten live ranges
var t0 = a0.add(a1); var t1 = a2.add(a3);
double r = t0.add(t1).x;
Defensive patterns

Strategy: fallback

Try / catch

try {
    result = compile(method);
} catch (OutOfRegistersException e) {
    // compilation failed cleanly; recompile without the aggressive config or run interpreted
    result = compileWithoutInlining(method); // or mark method non-compilable temporarily
}

Prevention

When it happens

Trigger: A live interval's first usage requires a specific register class where all allocatable registers of that class are occupied by other pinned intervals; trySplitWhenSpillingException / splitAndSpillInterval cannot free anything. Common with highly vector-heavy or floating-point code where the allocatable set for the platform kind is small, or when many intervals have fixed-register constraints at the same program point (e.g., calling conventions, native method handles).

Common situations: Long expressions with many simultaneously-live values of the same kind (SIMD vectors, FP doubles), aggressive inlining producing one huge method, custom backends with a reduced allocatable-register set, or huge method signatures forcing many fixed registers at once.

Related errors


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