{"record":{"id":"f36a795cd9ae8e4b","repo":"oracle/graal","slug":"graal-implementation-restriction-method-with-s-l-f36a79","errorCode":null,"errorMessage":"Graal implementation restriction: Method with %s loop explosion %s","messagePattern":"Graal implementation restriction: Method with (.+?) loop explosion (.+?)","errorType":"exception","errorClass":"PermanentBailoutException","httpStatus":null,"severity":"error","filePath":"compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/GraphDecoder.java","lineNumber":3308,"sourceCode":"            case Int -> loopVariablePhi;\n            case Long -> graph.addOrUnique(NarrowNode.create(loopVariablePhi, Integer.SIZE, NodeView.DEFAULT));\n            default -> throw bailout(\"must have a loop variable of type int or long. \" + loopVariablePhi);\n        };\n    }\n\n    /**\n     * Validates that {@code switchValue} conforms to one of the shapes produced by {@link #asIntSwitchValue}.\n     */\n    private static boolean isIntSwitchValue(ValueNode switchValue, ValuePhiNode loopVariablePhi) {\n        return switch (loopVariablePhi.getStackKind()) {\n            case Int -> switchValue == loopVariablePhi;\n            case Long -> switchValue instanceof NarrowNode narrow && narrow.getValue() == loopVariablePhi && narrow.getResultBits() == Integer.SIZE;\n            default -> throw bailout(\"switch value did not conform to expected shape. \" + switchValue);\n        };\n    }\n\n    private static RuntimeException bailout(String msg) {\n        throw new PermanentBailoutException(\"Graal implementation restriction: Method with %s loop explosion %s\", LoopExplosionPlugin.LoopExplosionKind.MERGE_EXPLODE, msg);\n    }\n\n    private static IntegerSwitchNode createSwitch(ValueNode switchedValue, SortedMap<Integer, AbstractBeginNode> dispatchTable, AbstractBeginNode defaultSuccessor) {\n        int numKeys = dispatchTable.size();\n        int numSuccessors = numKeys + 1;\n\n        AbstractBeginNode[] switchSuccessors = new AbstractBeginNode[numSuccessors];\n        int[] switchKeys = new int[numKeys];\n        double[] switchKeyProbabilities = new double[numSuccessors];\n        int[] switchKeySuccessors = new int[numSuccessors];\n\n        int idx = 0;\n        for (Map.Entry<Integer, AbstractBeginNode> entry : dispatchTable.entrySet()) {\n            switchSuccessors[idx] = entry.getValue();\n            switchKeys[idx] = entry.getKey();\n            switchKeyProbabilities[idx] = 1d / numKeys;\n            switchKeySuccessors[idx] = idx;\n            idx++;","sourceCodeStart":3290,"sourceCodeEnd":3326,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/GraphDecoder.java#L3290-L3326","documentation":"During merge-explode loop reconstruction, GraphDecoder rebuilds loop back-edges as an IntegerSwitchNode over the loop-variable phi (createSwitch). isIntSwitchValue validates the switched value is exactly the int phi, or a NarrowNode narrowing a long phi to 32 bits. Any other shape is an internal inconsistency, reported through bailout() as a PermanentBailoutException prefixed 'Graal implementation restriction: Method with MERGE_EXPLODE loop explosion ...'.","triggerScenarios":"A MERGE_EXPLODE loop whose induction variable phi is widened or transformed so the switch dispatch value is no longer the raw phi nor a 32-bit Narrow of it (e.g., an unexpected SignExtendNode, a char/byte phi widened elsewhere, or a compiler pass altering the shape between encoding and decoding).","commonSituations":"Truffle interpreter loops under merge explosion where the loop counter is a long used in ways that produce a different narrowing chain; Graal version changes to integer conversion canonicalization; hand-written substitutions with unusual induction variables.","solutions":["Simplify the loop variable of the merge-exploded method: use a plain int counter so the switch value stays the raw phi","File a GraalVM issue with the method: the message includes the offending switchValue node, which the maintainers need","Switch the method to FULL_UNROLL or DUP_WITHOUT_EXIT explosion to bypass the switch reconstruction entirely"],"exampleFix":"// before: long counter with char-based update -> switch value not the phi / Narrow(phi)\n@LoopExplosionKind(MERGE_EXPLODE)\nvoid loop() { long i = 0; while (c(i)) { i = nextChar(i); } }\n\n// after: plain int induction variable\n@LoopExplosionKind(MERGE_EXPLODE)\nvoid loop() { for (int i = 0; c(i); i++) { } }","handlingStrategy":"validation","validationCode":"// In interpreter code destined for MERGE_EXPLODE: keep induction variables as plain int\nif (kind == MERGE_EXPLODE && usesNonIntInductionVariable(method)) {\n    warnOrReject(\"merge-explode switch reconstruction requires int (or 32-bit-narrowed long) counters\");\n}","typeGuard":null,"tryCatchPattern":"try { pe(method); } catch (PermanentBailoutException e) { /* internal shape violation: simplify counter, then retry; else file issue */ throw e; }","preventionTips":["Use plain int loop counters in merge-exploded loops","Avoid widening chains (char/byte/long round-trips) on the induction variable","Report unexpected shapes upstream with the printed switchValue node"],"tags":["graalvm","partial-evaluation","loop-explosion","graph-decoder","permanent-bailout"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}