oracle/graal · warning · PermanentBailoutException

Cannot handle %d variables in %d loops

Error message

Cannot handle %d variables in %d loops

What it means

Thrown by LinearScanLifetimeAnalysisPhase.computeLocalLiveSets when allocating the per-variable/per-loop BitMap2D (variables x loops bits) fails: either the bit count exceeds Integer.MAX_VALUE or the allocation throws OutOfMemoryError. The linear-scan allocator cannot track loop membership for such a huge variable/loop product, so the compilation permanently bails out wrapping the OOM.

Source

Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java:186

    }

    /**
     * Computes local live sets (i.e. {@link BlockData#liveGen} and {@link BlockData#liveKill})
     * separately for each block.
     */
    @SuppressWarnings("try")
    void computeLocalLiveSets() {
        int liveSize = allocator.liveSetSize();
        int variables = allocator.operandSize();
        int loops = allocator.numLoops();
        long nBits = (long) variables * loops;
        try {
            if (nBits > Integer.MAX_VALUE) {
                throw new OutOfMemoryError();
            }
            intervalInLoop = new BitMap2D(variables, loops);
        } catch (OutOfMemoryError e) {
            throw new PermanentBailoutException(e, "Cannot handle %d variables in %d loops", variables, loops);
        }

        try {
            final SparseBitSet liveGenScratch = new SparseBitSet();
            final SparseBitSet liveKillScratch = new SparseBitSet();
            // iterate all blocks
            for (int blockId : allocator.sortedBlocks()) {
                BasicBlock<?> block = allocator.getLIR().getBlockById(blockId);
                try (Indent indent = debug.logAndIndent("compute local live sets for block %s", block)) {

                    liveGenScratch.clear();
                    liveKillScratch.clear();

                    ArrayList<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block);
                    int numInst = instructions.size();

                    ValueConsumer useConsumer = (operand, mode, flags) -> {
                        if (LIRValueUtil.isVariable(operand)) {

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. If variables*loops is genuinely near Integer.MAX_VALUE, refactor the method (split it, reduce loop count) — no flag fixes the structural limit.
  2. If the container is merely low on memory, raise the JVM's heap budget so the bit set allocation succeeds.
  3. Check -XX:CompileCommand filtering for the offending mega-method to exclude it from Graal compilation.
Defensive patterns

Strategy: fallback

Try / catch

// permanent bailout; if caused by heap pressure rather than the 2^31 limit,
// raising -Xmx lets the same method compile on retry.

Prevention

When it happens

Trigger: new BitMap2D(variables, loops) throwing OutOfMemoryError (or nBits > Integer.MAX_VALUE throwing it explicitly) — a method with an enormous number of LIR variables (many virtual registers after register allocation setup) multiplied by many loops, e.g. tens of thousands of variables times thousands of loops.

Common situations: Machine-generated mega-methods (query compilers, state machines, shader-like kernels); methods whose inlining exploded variable counts; memory-constrained containers where even a legal-size allocation fails — the message reports the exact variables/loops counts to distinguish a real limit breach from a tight -Xmx/-XX:MaxHeapSizeForCompilation.

Related errors


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