38
38
import org .graalvm .collections .EconomicSet ;
39
39
import org .graalvm .collections .Pair ;
40
40
41
+ import jdk .graal .compiler .core .common .type .AbstractObjectStamp ;
41
42
import jdk .graal .compiler .core .common .type .Stamp ;
42
43
import jdk .graal .compiler .debug .Assertions ;
43
44
import jdk .graal .compiler .debug .CounterKey ;
77
78
import jdk .graal .compiler .nodes .calc .ConditionalNode ;
78
79
import jdk .graal .compiler .nodes .calc .FloatingNode ;
79
80
import jdk .graal .compiler .nodes .cfg .ControlFlowGraph ;
81
+ import jdk .graal .compiler .nodes .extended .GuardedNode ;
80
82
import jdk .graal .compiler .nodes .extended .GuardingNode ;
81
83
import jdk .graal .compiler .nodes .loop .InductionVariable ;
82
84
import jdk .graal .compiler .nodes .spi .Canonicalizable ;
@@ -615,11 +617,16 @@ private boolean processNode(Node node, Tool tool, NodeBitMap singleShotList) {
615
617
if (tryCanonicalize (node , nodeClass , tool )) {
616
618
return true ;
617
619
}
618
- if (node instanceof ValueNode ) {
619
- ValueNode valueNode = (ValueNode ) node ;
620
+ if (node instanceof ValueNode valueNode ) {
620
621
boolean improvedStamp = tryInferStamp (valueNode , tool );
621
622
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
+ */
623
630
ConstantNode stampConstant = ConstantNode .forConstant (valueNode .stamp (NodeView .DEFAULT ), constant , tool .context .getMetaAccess (), graph );
624
631
valueNode .replaceAtUsages (stampConstant , InputType .Value );
625
632
GraphUtil .tryKillUnused (valueNode );
@@ -640,6 +647,16 @@ private boolean processNode(Node node, Tool tool, NodeBitMap singleShotList) {
640
647
return false ;
641
648
}
642
649
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
+
643
660
public static boolean gvn (Node node , NodeClass <?> nodeClass ) {
644
661
if (nodeClass .valueNumberable ()) {
645
662
Node newNode = node .graph ().findDuplicate (node );
0 commit comments