{"record":{"id":"f65b30fa52d64345","repo":"oracle/graal","slug":"too-many-loops-in-method","errorCode":null,"errorMessage":"Too many loops in method","messagePattern":"Too many loops in method","errorType":"exception","errorClass":"PermanentBailoutException","httpStatus":null,"severity":"warning","filePath":"compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/BciBlockMapping.java","lineNumber":1729,"sourceCode":"     * The next available loop number.\n     */\n    private int nextLoop;\n\n    /**\n     * Returns the smallest power of 2, strictly greater than value.\n     */\n    private static int nextPowerOfTwo(int value) {\n        assert NumUtil.assertNonNegativeInt(value);\n        return 1 << (32 - Integer.numberOfLeadingZeros(value));\n    }\n\n    private void makeLoopHeader(BciBlock block) {\n        assert !block.isLoopHeader;\n        block.isLoopHeader = true;\n        if (nextLoop >= LOOP_HEADER_MAX_CAPACITY) {\n            // This is an artificial restriction, a sanity check to avoid feeding the compiler an\n            // unreasonable number of loops.\n            throw new PermanentBailoutException(\"Too many loops in method\");\n        }\n        block.loops.set(nextLoop);\n        debug.log(\"makeLoopHeader(%s) -> %s\", block, block.loops);\n        if (loopHeaders == null) {\n            loopHeaders = new BciBlock[Math.max(nextPowerOfTwo(nextLoop), LOOP_HEADER_INITIAL_CAPACITY)];\n        } else if (nextLoop >= loopHeaders.length) {\n            int newLength = nextPowerOfTwo(nextLoop);\n            loopHeaders = Arrays.copyOf(loopHeaders, newLength);\n        }\n        loopHeaders[nextLoop] = block;\n        block.loopId = nextLoop;\n        nextLoop++;\n    }\n\n    private void propagateLoopBits(TraversalStep step, BitSet loopBits) {\n        TraversalStep s = step;\n        while (s != null) {\n            // Original condition: if (s.block.loops & loopBits == loopBits) break;","sourceCodeStart":1711,"sourceCodeEnd":1747,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/BciBlockMapping.java#L1711-L1747","documentation":"Thrown by BciBlockMapping.makeLoopHeader when the number of distinct loops in a method exceeds LOOP_HEADER_MAX_CAPACITY. The loop-header bookkeeping (BitSet per block, loopHeaders array) is sized for a bounded number of loops; exceeding the cap is treated as an artificial sanity limit and permanently bails out compilation rather than feeding the compiler an unreasonable loop structure.","triggerScenarios":"Parsing a method whose bytecode contains more than LOOP_HEADER_MAX_CAPACITY back edges / natural loops, e.g. machine-generated code with hundreds of thousands of loops.","commonSituations":"Bytecode generated by code generators, state-machine compilers, or obfuscators producing extremely high loop counts; pathological test cases (loop-unrolled source generated at build time); rarely, generated query/DSL compilers emitting one loop per case arm.","solutions":["Reduce the number of loops in the offending method (split the method, simplify generated code, or disable extreme loop generation in the generator).","Regenerate the class with the loops batched into inner helper methods.","Let HotSpot fall back to another tier for this method — the bailout is permanent for Graal by design."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Permanent bailout: HotSpot falls back to another compiler for this method.\n// Nothing to catch; reduce loop count in the source/generated bytecode.","preventionTips":["Bound loop counts in generated mega-methods (split into helper methods).","Treat the LOOP_HEADER_MAX_CAPACITY sanity limit as a hard design constraint for generated code."],"tags":["graalvm","bytecode-parsing","loops","bailout","limits"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}