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

  1. Increase the host VM heap (-Xmx on the host JVM) or transfer data in smaller chunks.
  2. Check for and clear pending JNI exceptions before making allocation calls if preceding JNI operations may have failed.
  3. 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

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


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