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
- Split the offending method into smaller methods to shorten live ranges and reduce peak register pressure
- Reduce inlining pressure around the failing code (e.g., lower inline thresholds or mark hot helpers @TruffleBoundary/not-inlinable)
- Run with -Dgraal.Dump=:2 and -Dgraal.PrintInlining=true to confirm which method/method context fails, then target that method
- If using a custom RegisterConfiguration, verify the allocatable register set for the affected kind is not accidentally empty or too small
- 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
- Avoid extremely long expressions with many simultaneously-live values of one kind; stage intermediates
- Watch -Dgraal.PrintInlining output for methods that inline into giant units
- If building a custom backend, validate allocatable-register sets for every kind you emit
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
- Cannot handle %d variables in %d loops
- Out-of-memory during live set allocation of size %d
- too many iterations in computeGlobalLiveSets
- There are no allocatable registers for kind %s, consider ass
- register %s is not allocatable
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/035b1a223a2d5666.
Report an issue: GitHub.