oracle/graal · error · PermanentBailoutException
NormalizeCompareNode connected to %s (%s %s %s)
Error message
NormalizeCompareNode connected to %s (%s %s %s)
What it means
During CompareNode canonicalization, comparing an AbstractNormalizeCompareNode against a constant is only supported for the specific subclass overloads (e.g., Integer/Float CompareNode); the base-class fallback optimizeNormalizeCompare throws PermanentBailoutException listing the node, constant, normalize node, and mirrored flag. Hitting it means an unexpected comparison shape reached a compare node that cannot fold it — an internal invariant, not user configuration.
Source
Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/CompareNode.java:289
return supported;
}
private static ConstantNode canonicalConvertConstant(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, CanonicalCondition condition, ConvertNode convert,
Constant constant, NodeView view) {
if (convert.preservesOrder(condition, constant, constantReflection)) {
Constant reverseConverted = convert.reverse(constant, constantReflection);
if (reverseConverted != null && convert.convert(reverseConverted, constantReflection).equals(constant)) {
return ConstantNode.forConstant(convert.getValue().stamp(view), reverseConverted, metaAccess);
}
}
return null;
}
@SuppressWarnings("unused")
protected LogicNode optimizeNormalizeCompare(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth,
Constant constant, AbstractNormalizeCompareNode normalizeNode, boolean mirrored, NodeView view) {
throw new PermanentBailoutException("NormalizeCompareNode connected to %s (%s %s %s)", this, constant, normalizeNode, mirrored);
}
private static LogicNode optimizeConditional(Constant constant, ConditionalNode conditionalNode, ConstantReflectionProvider constantReflection, Condition cond, boolean unorderedIsTrue) {
Constant trueConstant = conditionalNode.trueValue().asConstant();
Constant falseConstant = conditionalNode.falseValue().asConstant();
if (falseConstant != null && trueConstant != null && constantReflection != null) {
Stamp compareStamp = conditionalNode.trueValue().stamp(NodeView.DEFAULT);
TriState trueResult = cond.foldCondition(compareStamp, trueConstant, constant, constantReflection, unorderedIsTrue);
TriState falseResult = cond.foldCondition(compareStamp, falseConstant, constant, constantReflection, unorderedIsTrue);
if (trueResult.isKnown() && trueResult.equals(falseResult)) {
return LogicConstantNode.forBoolean(trueResult.toBoolean());
} else {
if (trueResult.isTrue() && falseResult.isFalse()) {
return conditionalNode.condition();
} else if (trueResult.isFalse() && falseResult.isTrue()) {
return LogicNegationNode.create(conditionalNode.condition());View on GitHub (pinned to a66e9ccd1d)
Solutions
- File a GraalVM issue with -Dgraal.Dump=:2 output: the message already identifies the compare node, constant, and normalize node
- Work around by restructuring the comparison at the source level (e.g., use explicit Integer.compare/compareTo instead of chained relational expressions with unary minus patterns that form NormalizeCompare nodes)
- If developing custom nodes, override optimizeNormalizeCompare in your CompareNode subclass instead of relying on the throwing default
Example fix
// before: exotic pattern that folds to normalize-compare against a constant boolean b = (a < b ? -1 : a > b ? 1 : 0) == SOME_CONST; // after: plain comparison the canonicalizer handles boolean b = SOME_CONST == Integer.compare(a, b);
Defensive patterns
Strategy: try-catch
Try / catch
try { compile(m); } catch (PermanentBailoutException e) { /* internal canonicalization invariant: report upstream with -Dgraal.Dump=:2 */ fallbackToBaseline(m, e); } Prevention
- Prefer direct Integer.compare/compareTo over normalize-compare-shaped relational chains
- Custom CompareNode subclasses must override optimizeNormalizeCompare
- Always attach Graal dumps when reporting this class of failure
When it happens
Trigger: A CompareNode subclass whose canonicalization delegates to the generic optimizeNormalizeCompare (i.e., no constant-folding support for the type combination) encounters normalize(x,y) OP constant during canonicalization. This requires a node/intrinsic producing an unusual normalize-compare usage pattern, typically from generated graphs or new node types.
Common situations: Custom Graal plugins or languages introducing new compare node types; rare shapes in auto-generated (bytecode-generated) code; effectively never in normal application compilation — essentially a bug-class error.
Related errors
- too many iterations in computeGlobalLiveSets
- Frame size (%d) exceeded maximum allowed frame size (%d).
- Graal implementation restriction: Method with %s loop explos
- Graal implementation restriction: Method with %s loop explos
- Unable to decode some instructions in
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/d30e7ee5b8161d48.
Report an issue: GitHub.