3838import org .graalvm .collections .EconomicSet ;
3939import org .graalvm .collections .Pair ;
4040
41+ import jdk .graal .compiler .core .common .type .AbstractObjectStamp ;
4142import jdk .graal .compiler .core .common .type .Stamp ;
4243import jdk .graal .compiler .debug .Assertions ;
4344import jdk .graal .compiler .debug .CounterKey ;
7778import jdk .graal .compiler .nodes .calc .ConditionalNode ;
7879import jdk .graal .compiler .nodes .calc .FloatingNode ;
7980import jdk .graal .compiler .nodes .cfg .ControlFlowGraph ;
81+ import jdk .graal .compiler .nodes .extended .GuardedNode ;
8082import jdk .graal .compiler .nodes .extended .GuardingNode ;
8183import jdk .graal .compiler .nodes .loop .InductionVariable ;
8284import jdk .graal .compiler .nodes .spi .Canonicalizable ;
@@ -615,11 +617,16 @@ private boolean processNode(Node node, Tool tool, NodeBitMap singleShotList) {
615617 if (tryCanonicalize (node , nodeClass , tool )) {
616618 return true ;
617619 }
618- if (node instanceof ValueNode ) {
619- ValueNode valueNode = (ValueNode ) node ;
620+ if (node instanceof ValueNode valueNode ) {
620621 boolean improvedStamp = tryInferStamp (valueNode , tool );
621622 Constant constant = valueNode .stamp (NodeView .DEFAULT ).asConstant ();
622- if (constant != null && !(node instanceof ConstantNode )) {
623+ if (constant != null && !(node instanceof ConstantNode ) && !isAnchoredNullConstant (valueNode )) {
624+ /*
625+ * Do not fold always-null Pis to null constants. Doing so could lead to dependent
626+ * reads floating above safety checks, potentially causing runtime segfaults. By
627+ * contrast, folding integer constants that could cause out-of-bounds reads is safe
628+ * as JVMCI detects these and fails gracefully.
629+ */
623630 ConstantNode stampConstant = ConstantNode .forConstant (valueNode .stamp (NodeView .DEFAULT ), constant , tool .context .getMetaAccess (), graph );
624631 valueNode .replaceAtUsages (stampConstant , InputType .Value );
625632 GraphUtil .tryKillUnused (valueNode );
@@ -640,6 +647,16 @@ private boolean processNode(Node node, Tool tool, NodeBitMap singleShotList) {
640647 return false ;
641648 }
642649
650+ /**
651+ * Tests if {@code node} is an always-null value that is anchored.
652+ */
653+ private static boolean isAnchoredNullConstant (ValueNode node ) {
654+ if (node instanceof GuardedNode guarded && guarded .getGuard () != null ) {
655+ return node .stamp (NodeView .DEFAULT ).isObjectStamp () && ((AbstractObjectStamp ) node .stamp (NodeView .DEFAULT )).alwaysNull ();
656+ }
657+ return false ;
658+ }
659+
643660 public static boolean gvn (Node node , NodeClass <?> nodeClass ) {
644661 if (nodeClass .valueNumberable ()) {
645662 Node newNode = node .graph ().findDuplicate (node );
0 commit comments