oracle/graal · critical · GraalError
Multiple uses of register: %s %s
Error message
Multiple uses of register: %s %s
What it means
JNIUtil.createHSArray(JNIEnv, boolean[]) allocates a boolean array in the host VM via JNI NewBooleanArray. If the JNI call returns null, allocation failed on the host side (host heap exhausted or a pending host exception), and the helper throws OutOfMemoryError so the failure is not silently ignored. The copy step only runs after the non-null check.
Source
Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/Assembler.java:349
}
public int getReturnAddressSize() {
return target.arch.getReturnAddressSize();
}
public int getMachineCodeCallDisplacementOffset() {
return target.arch.getMachineCodeCallDisplacementOffset();
}
public boolean inlineObjects() {
return target.inlineObjects;
}
public static void guaranteeDifferentRegisters(Register... registers) {
for (int i = 0; i < registers.length - 1; ++i) {
for (int j = i + 1; j < registers.length; ++j) {
if (registers[i].equals(registers[j])) {
throw new GraalError("Multiple uses of register: %s %s", registers[i], Arrays.toString(registers));
}
}
}
}
private CodeSnippetRecord currentCodeSnippet = null;
private EconomicMap<Integer, CodeSnippetRecord> recordedCodeSnippets = null;
/**
* Marks the start of a {@link CodeSnippetRecord}. If invoked again without a corresponding call
* to {@link #stopRecordingCodeSnippet}, the current {@link CodeSnippetRecord} will be
* discarded.
*
* See also {@link #stopRecordingCodeSnippet} and {@link #replayCodeSnippetAt}
*/
public void startRecordingCodeSnippet(CompilationResultBuilder crb) {
// not-yet-finished code snippet will be discarded
currentCodeSnippet = new CodeSnippetRecord(position(), crb.getSitesWatermark());View on GitHub (pinned to a66e9ccd1d)
Solutions
- Increase the host VM heap (-Xmx on the host JVM) or transfer data in smaller chunks.
- Check for and clear pending JNI exceptions before making allocation calls if preceding JNI operations may have failed.
- Catch OutOfMemoryError at the call site, release intermediate host references, and retry with a smaller batch.
Example fix
// before
JBooleanArray hs = JNIUtil.createHSArray(env, hugeArray); // may OOM the host
// after
JBooleanArray hs = WordFactory.nullPointer();
for (int off = 0; off < hugeArray.length; off += CHUNK) {
boolean[] chunk = Arrays.copyOfRange(hugeArray, off, Math.min(off + CHUNK, hugeArray.length));
JBooleanArray part = JNIUtil.createHSArray(env, chunk);
// ... process/append part, releasing it when done
} Defensive patterns
Strategy: try-catch
Validate before calling
// Bound the transfer size before allocating on the host:
if (a != null && a.length > MAX_HOST_CHUNK) {
a = Arrays.copyOf(a, MAX_HOST_CHUNK); // or stream in chunks
} Try / catch
try {
return JNIUtil.createHSArray(jniEnv, a);
} catch (OutOfMemoryError oom) {
// host heap exhausted: free other host refs, reduce batch size, then retry with smaller arrays
releaseCachedHostRefs();
return JNIUtil.createHSArray(jniEnv, Arrays.copyOf(a, a.length / 2));
} Prevention
- Size the host JVM heap (-Xmx) for the largest array you transfer.
- Chunk large array transfers instead of allocating one giant host array.
- Clear pending JNI exceptions before allocation calls so failures are attributed correctly.
When it happens
Trigger: Host VM heap exhausted when copying a large boolean[] into it via createHSArray; a pending JNI exception from an earlier call making NewBooleanArray return null; host VM under -Xmx pressure inside Espresso/libgraal setups.
Common situations: Large array transfers between the guest (native image) and host JVM; host heap sizing too small relative to workload; error paths where an earlier JNI exception was never cleared.
Related errors
- expected %s, got %s
- %s is not an annotation interface
- Cannot look up %s annotation at Native Image runtime
- %s has params
- %s is not an enum type
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/9c45c4cdd08e4479.
Report an issue: GitHub.