8383import com .oracle .graal .pointsto .flow .MethodFlowsGraph ;
8484import com .oracle .graal .pointsto .flow .MethodTypeFlow ;
8585import com .oracle .graal .pointsto .flow .TypeFlow ;
86+ import com .oracle .graal .pointsto .heap .ImageHeapConstant ;
8687import com .oracle .graal .pointsto .infrastructure .Universe ;
8788import com .oracle .graal .pointsto .meta .AnalysisField ;
8889import com .oracle .graal .pointsto .meta .AnalysisMethod ;
9192import com .oracle .graal .pointsto .typestate .TypeState ;
9293import com .oracle .svm .util .ImageBuildStatistics ;
9394
95+ import jdk .vm .ci .meta .JavaConstant ;
9496import jdk .vm .ci .meta .JavaKind ;
9597import jdk .vm .ci .meta .JavaMethodProfile ;
9698import jdk .vm .ci .meta .JavaTypeProfile ;
105107 * processing the graph.
106108 *
107109 * From the single-method view that the compiler has when later compiling the graph, static analysis
108- * results appear "out of thin air": At some some random point in the graph, we suddenly have a more
110+ * results appear "out of thin air": At some random point in the graph, we suddenly have a more
109111 * precise type (= stamp) for a value. Since many nodes are floating, and even currently fixed nodes
110112 * might float later, we need to be careful that all information coming from the type flow graph
111113 * remains properly anchored to the point where the static analysis actually proved the information.
@@ -246,20 +248,26 @@ public void simplify(Node n, SimplifierTool tool) {
246248 if (n instanceof ParameterNode ) {
247249 ParameterNode node = (ParameterNode ) n ;
248250 StartNode anchorPoint = graph .start ();
249- Stamp newStamp = strengthenStampFromTypeFlow (node , parameterFlows [node .index ()], anchorPoint , tool );
250- updateStampUsingPiNode (node , newStamp , anchorPoint , tool );
251+ Object newStampOrConstant = strengthenStampFromTypeFlow (node , parameterFlows [node .index ()], anchorPoint , tool );
252+ updateStampUsingPiNode (node , newStampOrConstant , anchorPoint , tool );
251253
252254 } else if (n instanceof LoadFieldNode || n instanceof LoadIndexedNode ) {
253255 FixedWithNextNode node = (FixedWithNextNode ) n ;
254- Stamp newStamp = strengthenStampFromTypeFlow (node , getNodeFlow (node ), node , tool );
256+ Object newStampOrConstant = strengthenStampFromTypeFlow (node , getNodeFlow (node ), node , tool );
255257 /*
256258 * Even though the memory load will be a floating node later, we can update the
257259 * stamp directly because the type information maintained by the static analysis
258260 * about memory is not flow-sensitive and not context-sensitive. If we ever revive a
259261 * context-sensitive analysis, we will need to change this. But for now, we are
260262 * fine.
261263 */
262- updateStampInPlace (node , newStamp , tool );
264+ if (newStampOrConstant instanceof JavaConstant ) {
265+ ConstantNode replacement = ConstantNode .forConstant ((JavaConstant ) newStampOrConstant , bb .getMetaAccess (), graph );
266+ graph .replaceFixedWithFloating (node , replacement );
267+ tool .addToWorkList (replacement );
268+ } else {
269+ updateStampInPlace (node , (Stamp ) newStampOrConstant , tool );
270+ }
263271
264272 } else if (n instanceof Invoke ) {
265273 Invoke invoke = (Invoke ) n ;
@@ -385,13 +393,13 @@ private void handleInvoke(Invoke invoke, SimplifierTool tool) {
385393 NodeInputList <ValueNode > arguments = callTarget .arguments ();
386394 for (int i = 0 ; i < arguments .size (); i ++) {
387395 ValueNode argument = arguments .get (i );
388- Stamp newStamp = strengthenStampFromTypeFlow (argument , invokeFlow .getActualParameters ()[i ], beforeInvoke , tool );
396+ Object newStampOrConstant = strengthenStampFromTypeFlow (argument , invokeFlow .getActualParameters ()[i ], beforeInvoke , tool );
389397 if (node .isDeleted ()) {
390398 /* Parameter stamp was empty, so invoke is unreachable. */
391399 return ;
392- } else if (newStamp != null ) {
393- PiNode pi = insertPi (argument , newStamp , beforeInvoke );
394- if (pi != null ) {
400+ } else if (newStampOrConstant != null ) {
401+ ValueNode pi = insertPi (argument , newStampOrConstant , beforeInvoke );
402+ if (pi != null && pi != argument ) {
395403 callTarget .replaceAllInputs (argument , pi );
396404 }
397405 }
@@ -423,8 +431,8 @@ private void handleInvoke(Invoke invoke, SimplifierTool tool) {
423431 optimizeReturnedParameter (callees , arguments , node , tool );
424432
425433 FixedWithNextNode anchorPointAfterInvoke = (FixedWithNextNode ) (invoke instanceof InvokeWithExceptionNode ? invoke .next () : invoke );
426- Stamp newStamp = strengthenStampFromTypeFlow (node , invokeFlow .getResult (), anchorPointAfterInvoke , tool );
427- updateStampUsingPiNode (node , newStamp , anchorPointAfterInvoke , tool );
434+ Object newStampOrConstant = strengthenStampFromTypeFlow (node , invokeFlow .getResult (), anchorPointAfterInvoke , tool );
435+ updateStampUsingPiNode (node , newStampOrConstant , anchorPointAfterInvoke , tool );
428436 }
429437
430438 /**
@@ -519,19 +527,22 @@ private void updateStampInPlace(ValueNode node, Stamp newStamp, SimplifierTool t
519527 }
520528 }
521529
522- private void updateStampUsingPiNode (ValueNode node , Stamp newStamp , FixedWithNextNode anchorPoint , SimplifierTool tool ) {
523- if (newStamp != null && node .hasUsages () && !createdPiNodes .isMarked (node )) {
524- PiNode pi = insertPi (node , newStamp , anchorPoint );
530+ private void updateStampUsingPiNode (ValueNode node , Object newStampOrConstant , FixedWithNextNode anchorPoint , SimplifierTool tool ) {
531+ if (newStampOrConstant != null && node .hasUsages () && !createdPiNodes .isMarked (node )) {
532+ ValueNode pi = insertPi (node , newStampOrConstant , anchorPoint );
525533 if (pi != null ) {
526534 /*
527535 * The Canonicalizer that drives all of our node processing is iterative. We
528536 * only want to insert the PiNode the first time we handle a node.
529537 */
530538 createdPiNodes .mark (node );
531539
532- FrameState anchorState = node instanceof StateSplit ? ((StateSplit ) node ).stateAfter () : graph .start ().stateAfter ();
533- node .replaceAtUsages (pi , usage -> usage != pi && usage != anchorState );
534-
540+ if (pi .isConstant ()) {
541+ node .replaceAtUsages (pi );
542+ } else {
543+ FrameState anchorState = node instanceof StateSplit ? ((StateSplit ) node ).stateAfter () : graph .start ().stateAfter ();
544+ node .replaceAtUsages (pi , usage -> usage != pi && usage != anchorState );
545+ }
535546 tool .addToWorkList (pi .usages ());
536547 }
537548 }
@@ -540,7 +551,17 @@ private void updateStampUsingPiNode(ValueNode node, Stamp newStamp, FixedWithNex
540551 /*
541552 * See comment on {@link StrengthenGraphs} on why anchoring is necessary.
542553 */
543- private PiNode insertPi (ValueNode input , Stamp piStamp , FixedWithNextNode anchorPoint ) {
554+ private ValueNode insertPi (ValueNode input , Object newStampOrConstant , FixedWithNextNode anchorPoint ) {
555+ if (newStampOrConstant instanceof JavaConstant ) {
556+ JavaConstant constant = (JavaConstant ) newStampOrConstant ;
557+ if (input .isConstant ()) {
558+ assert input .asConstant ().equals (constant );
559+ return null ;
560+ }
561+ return ConstantNode .forConstant (constant , bb .getMetaAccess (), graph );
562+ }
563+
564+ Stamp piStamp = (Stamp ) newStampOrConstant ;
544565 Stamp oldStamp = input .stamp (NodeView .DEFAULT );
545566 Stamp computedStamp = oldStamp .improveWith (piStamp );
546567 if (oldStamp .equals (computedStamp )) {
@@ -553,7 +574,7 @@ private PiNode insertPi(ValueNode input, Stamp piStamp, FixedWithNextNode anchor
553574 return graph .unique (new PiNode (input , piStamp , anchor ));
554575 }
555576
556- private Stamp strengthenStampFromTypeFlow (ValueNode node , TypeFlow <?> nodeFlow , FixedWithNextNode anchorPoint , SimplifierTool tool ) {
577+ private Object strengthenStampFromTypeFlow (ValueNode node , TypeFlow <?> nodeFlow , FixedWithNextNode anchorPoint , SimplifierTool tool ) {
557578 PointsToAnalysis pta = getAnalysis ();
558579 if (node .getStackKind () != JavaKind .Object ) {
559580 return null ;
@@ -571,6 +592,23 @@ private Stamp strengthenStampFromTypeFlow(ValueNode node, TypeFlow<?> nodeFlow,
571592 }
572593
573594 TypeState nodeTypeState = methodFlow .foldTypeFlow (pta , nodeFlow );
595+
596+ if (!nodeTypeState .canBeNull ()) {
597+ JavaConstant constantValue = nodeTypeState .asConstant ();
598+ if (constantValue instanceof ImageHeapConstant ) {
599+ /*
600+ * GR-42996: until the AOT compilation can properly constant fold also
601+ * ImageHeapConstant, we unwrap the ImageHeapConstant to the hosted object. This
602+ * also means we do not constant fold yet when the constant does not wrap a
603+ * hosted object.
604+ */
605+ constantValue = ((ImageHeapConstant ) constantValue ).getHostedObject ();
606+ }
607+ if (constantValue != null ) {
608+ return constantValue ;
609+ }
610+ }
611+
574612 node .inferStamp ();
575613 ObjectStamp oldStamp = (ObjectStamp ) node .stamp (NodeView .DEFAULT );
576614 AnalysisType oldType = (AnalysisType ) oldStamp .type ();
0 commit comments