9090import org .graalvm .compiler .nodes .java .UnsafeCompareAndSwapNode ;
9191import org .graalvm .compiler .nodes .type .StampTool ;
9292import org .graalvm .compiler .nodes .util .GraphUtil ;
93+ import org .graalvm .compiler .nodes .virtual .AllocatedObjectNode ;
94+ import org .graalvm .compiler .nodes .virtual .CommitAllocationNode ;
95+ import org .graalvm .compiler .nodes .virtual .VirtualInstanceNode ;
96+ import org .graalvm .compiler .nodes .virtual .VirtualObjectNode ;
9397import org .graalvm .compiler .phases .common .CanonicalizerPhase ;
9498import org .graalvm .compiler .phases .common .IterativeConditionalEliminationPhase ;
9599import org .graalvm .compiler .phases .graph .MergeableState ;
@@ -222,6 +226,29 @@ public void registerUsedElements(boolean registerEmbeddedRoots) {
222226 AnalysisType type = (AnalysisType ) node .instanceClass ();
223227 type .registerAsAllocated (node );
224228
229+ } else if (n instanceof VirtualObjectNode ) {
230+ VirtualObjectNode node = (VirtualObjectNode ) n ;
231+ AnalysisType type = (AnalysisType ) node .type ();
232+ type .registerAsAllocated (node );
233+
234+ } else if (n instanceof CommitAllocationNode ) {
235+ CommitAllocationNode node = (CommitAllocationNode ) n ;
236+ List <ValueNode > values = node .getValues ();
237+ int objectStartIndex = 0 ;
238+ for (VirtualObjectNode virtualObject : node .getVirtualObjects ()) {
239+ AnalysisType type = (AnalysisType ) virtualObject .type ();
240+ if (!type .isArray ()) {
241+ for (int i = 0 ; i < virtualObject .entryCount (); i ++) {
242+ ValueNode value = values .get (objectStartIndex + i );
243+ if (!value .isJavaConstant () || !value .asJavaConstant ().isDefaultForKind ()) {
244+ AnalysisField field = (AnalysisField ) ((VirtualInstanceNode ) virtualObject ).field (i );
245+ field .registerAsWritten (methodFlow );
246+ }
247+ }
248+ }
249+ objectStartIndex += virtualObject .entryCount ();
250+ }
251+
225252 } else if (n instanceof NewArrayNode ) {
226253 NewArrayNode node = (NewArrayNode ) n ;
227254 AnalysisType type = ((AnalysisType ) node .elementType ()).getArrayClass ();
@@ -766,6 +793,8 @@ protected void node(FixedNode n) {
766793 if (node .result () != null && node .result ().getStackKind () == JavaKind .Object ) {
767794 returnFlowBuilder .addUseDependency (state .lookup (node .result ()));
768795 }
796+ } else if (n instanceof CommitAllocationNode ) {
797+ processCommitAllocation ((CommitAllocationNode ) n , state );
769798 } else if (n instanceof NewInstanceNode ) {
770799 processNewInstance ((NewInstanceNode ) n , state );
771800 } else if (n instanceof DynamicNewInstanceNode ) {
@@ -883,34 +912,7 @@ protected void node(FixedNode n) {
883912 }
884913
885914 } else if (n instanceof StoreFieldNode ) { // object.field = value
886- StoreFieldNode node = (StoreFieldNode ) n ;
887- AnalysisField field = (AnalysisField ) node .field ();
888- assert field .isWritten ();
889- if (node .value ().getStackKind () == JavaKind .Object ) {
890- TypeFlowBuilder <?> valueBuilder = state .lookup (node .value ());
891-
892- TypeFlowBuilder <StoreFieldTypeFlow > storeFieldBuilder ;
893- if (node .isStatic ()) {
894- storeFieldBuilder = TypeFlowBuilder .create (bb , node , StoreFieldTypeFlow .class , () -> {
895- FieldTypeFlow fieldFlow = field .getStaticFieldFlow ();
896- StoreStaticFieldTypeFlow storeFieldFlow = new StoreStaticFieldTypeFlow (node , valueBuilder .get (), fieldFlow );
897- methodFlow .addMiscEntry (storeFieldFlow );
898- return storeFieldFlow ;
899- });
900- storeFieldBuilder .addUseDependency (valueBuilder );
901- } else {
902- TypeFlowBuilder <?> objectBuilder = state .lookup (node .object ());
903- storeFieldBuilder = TypeFlowBuilder .create (bb , node , StoreFieldTypeFlow .class , () -> {
904- StoreInstanceFieldTypeFlow storeFieldFlow = new StoreInstanceFieldTypeFlow (node , valueBuilder .get (), objectBuilder .get ());
905- methodFlow .addMiscEntry (storeFieldFlow );
906- return storeFieldFlow ;
907- });
908- storeFieldBuilder .addUseDependency (valueBuilder );
909- storeFieldBuilder .addObserverDependency (objectBuilder );
910- }
911- /* Field stores must not be removed. */
912- typeFlowGraphBuilder .registerSinkBuilder (storeFieldBuilder );
913- }
915+ processStoreField ((StoreFieldNode ) n , state );
914916
915917 } else if (n instanceof LoadIndexedNode ) {
916918 LoadIndexedNode node = (LoadIndexedNode ) n ;
@@ -933,23 +935,7 @@ protected void node(FixedNode n) {
933935 }
934936
935937 } else if (n instanceof StoreIndexedNode ) {
936- StoreIndexedNode node = (StoreIndexedNode ) n ;
937- if (node .value ().getStackKind () == JavaKind .Object ) {
938- AnalysisType arrayType = (AnalysisType ) StampTool .typeOrNull (node .array ());
939- AnalysisType nonNullArrayType = Optional .ofNullable (arrayType ).orElseGet (bb ::getObjectArrayType );
940- TypeFlowBuilder <?> arrayBuilder = state .lookup (node .array ());
941- TypeFlowBuilder <?> valueBuilder = state .lookup (node .value ());
942- TypeFlowBuilder <?> storeIndexedBuilder = TypeFlowBuilder .create (bb , node , StoreIndexedTypeFlow .class , () -> {
943- StoreIndexedTypeFlow storeIndexedFlow = new StoreIndexedTypeFlow (node , nonNullArrayType , arrayBuilder .get (), valueBuilder .get ());
944- methodFlow .addMiscEntry (storeIndexedFlow );
945- return storeIndexedFlow ;
946- });
947- storeIndexedBuilder .addUseDependency (valueBuilder );
948- storeIndexedBuilder .addObserverDependency (arrayBuilder );
949-
950- /* Index stores must not be removed. */
951- typeFlowGraphBuilder .registerSinkBuilder (storeIndexedBuilder );
952- }
938+ processStoreIndexed ((StoreIndexedNode ) n , state );
953939
954940 } else if (n instanceof UnsafePartitionLoadNode ) {
955941 UnsafePartitionLoadNode node = (UnsafePartitionLoadNode ) n ;
@@ -1474,43 +1460,120 @@ protected Object uniqueKey(Node node) {
14741460 return new Object ();
14751461 }
14761462
1463+ protected void processCommitAllocation (CommitAllocationNode commitAllocationNode , TypeFlowsOfNodes state ) {
1464+ Map <VirtualObjectNode , AllocatedObjectNode > allocatedObjects = new HashMap <>();
1465+ for (AllocatedObjectNode allocatedObjectNode : commitAllocationNode .usages ().filter (AllocatedObjectNode .class )) {
1466+ AnalysisType type = (AnalysisType ) allocatedObjectNode .getVirtualObject ().type ();
1467+ processNewInstance (allocatedObjectNode , type , state );
1468+ allocatedObjects .put (allocatedObjectNode .getVirtualObject (), allocatedObjectNode );
1469+ }
1470+
1471+ List <ValueNode > values = commitAllocationNode .getValues ();
1472+ int objectStartIndex = 0 ;
1473+ for (VirtualObjectNode virtualObject : commitAllocationNode .getVirtualObjects ()) {
1474+ AnalysisType type = (AnalysisType ) virtualObject .type ();
1475+ ValueNode object = allocatedObjects .get (virtualObject );
1476+ if (object == null ) {
1477+ /*
1478+ * The AllocatedObjectNode itself is not used directly, so it got removed from the
1479+ * graph. We still need to register field/array stores because otherwise we can miss
1480+ * types that flow into the field/array. We use the VirtualObjectNode as the
1481+ * placeholder for the stores.
1482+ */
1483+ object = virtualObject ;
1484+ }
1485+ for (int i = 0 ; i < virtualObject .entryCount (); i ++) {
1486+ ValueNode value = values .get (objectStartIndex + i );
1487+ if (!value .isJavaConstant () || !value .asJavaConstant ().isDefaultForKind ()) {
1488+ if (type .isArray ()) {
1489+ processStoreIndexed (commitAllocationNode , object , value , state );
1490+ } else {
1491+ AnalysisField field = (AnalysisField ) ((VirtualInstanceNode ) virtualObject ).field (i );
1492+ processStoreField (commitAllocationNode , field , object , value , state );
1493+ }
1494+ }
1495+ }
1496+ objectStartIndex += virtualObject .entryCount ();
1497+ }
1498+ assert values .size () == objectStartIndex ;
1499+ }
1500+
14771501 protected void processNewInstance (NewInstanceNode node , TypeFlowsOfNodes state ) {
1502+ /* Instance fields of a new object are initialized to null state in AnalysisField. */
1503+ processNewInstance (node , (AnalysisType ) node .instanceClass (), state );
1504+ }
14781505
1479- AnalysisType type = (AnalysisType ) node .instanceClass ();
1506+ protected void processNewArray (NewArrayNode node , TypeFlowsOfNodes state ) {
1507+ processNewInstance (node , ((AnalysisType ) node .elementType ()).getArrayClass (), state );
1508+ }
1509+
1510+ protected void processNewInstance (ValueNode node , AnalysisType type , TypeFlowsOfNodes state ) {
14801511 assert type .isInstantiated ();
14811512 Object key = uniqueKey (node );
14821513 BytecodeLocation allocationLabel = bb .analysisPolicy ().createAllocationSite (bb , key , method );
14831514
14841515 TypeFlowBuilder <?> newInstanceBuilder = TypeFlowBuilder .create (bb , node , NewInstanceTypeFlow .class , () -> {
1485- NewInstanceTypeFlow newInstance = createNewInstanceTypeFlow (node , type , allocationLabel );
1486- /* Instance fields of a new object are initialized to null state in AnalysisField. */
1516+ NewInstanceTypeFlow newInstance = new NewInstanceTypeFlow (node , type , allocationLabel );
14871517 methodFlow .addMiscEntry (newInstance );
14881518 return newInstance ;
14891519 });
14901520 state .add (node , newInstanceBuilder );
14911521 }
14921522
1493- protected NewInstanceTypeFlow createNewInstanceTypeFlow ( NewInstanceNode node , AnalysisType type , BytecodeLocation allocationLabel ) {
1494- return new NewInstanceTypeFlow ( node , type , allocationLabel );
1523+ protected void processStoreField ( StoreFieldNode node , TypeFlowsOfNodes state ) {
1524+ processStoreField ( node , ( AnalysisField ) node . field (), node . object (), node . value (), state );
14951525 }
14961526
1497- protected void processNewArray (NewArrayNode node , TypeFlowsOfNodes state ) {
1498- AnalysisType type = ((AnalysisType ) node .elementType ()).getArrayClass ();
1499- assert type .isInstantiated ();
1500-
1501- Object key = uniqueKey (node );
1502- BytecodeLocation allocationLabel = bb .analysisPolicy ().createAllocationSite (bb , key , method );
1527+ protected void processStoreField (ValueNode node , AnalysisField field , ValueNode object , ValueNode value , TypeFlowsOfNodes state ) {
1528+ assert field .isWritten ();
1529+ if (value .getStackKind () == JavaKind .Object ) {
1530+ TypeFlowBuilder <?> valueBuilder = state .lookup (value );
1531+
1532+ TypeFlowBuilder <StoreFieldTypeFlow > storeFieldBuilder ;
1533+ if (field .isStatic ()) {
1534+ storeFieldBuilder = TypeFlowBuilder .create (bb , node , StoreFieldTypeFlow .class , () -> {
1535+ FieldTypeFlow fieldFlow = field .getStaticFieldFlow ();
1536+ StoreStaticFieldTypeFlow storeFieldFlow = new StoreStaticFieldTypeFlow (node , field , valueBuilder .get (), fieldFlow );
1537+ methodFlow .addMiscEntry (storeFieldFlow );
1538+ return storeFieldFlow ;
1539+ });
1540+ storeFieldBuilder .addUseDependency (valueBuilder );
1541+ } else {
1542+ TypeFlowBuilder <?> objectBuilder = state .lookup (object );
1543+ storeFieldBuilder = TypeFlowBuilder .create (bb , node , StoreFieldTypeFlow .class , () -> {
1544+ StoreInstanceFieldTypeFlow storeFieldFlow = new StoreInstanceFieldTypeFlow (node , field , valueBuilder .get (), objectBuilder .get ());
1545+ methodFlow .addMiscEntry (storeFieldFlow );
1546+ return storeFieldFlow ;
1547+ });
1548+ storeFieldBuilder .addUseDependency (valueBuilder );
1549+ storeFieldBuilder .addObserverDependency (objectBuilder );
1550+ }
1551+ /* Field stores must not be removed. */
1552+ typeFlowGraphBuilder .registerSinkBuilder (storeFieldBuilder );
1553+ }
1554+ }
15031555
1504- TypeFlowBuilder <?> newArrayBuilder = TypeFlowBuilder .create (bb , node , NewInstanceTypeFlow .class , () -> {
1505- NewInstanceTypeFlow newArray = createNewArrayTypeFlow (node , type , allocationLabel );
1506- methodFlow .addMiscEntry (newArray );
1507- return newArray ;
1508- });
1509- state .add (node , newArrayBuilder );
1556+ private void processStoreIndexed (StoreIndexedNode node , TypeFlowsOfNodes state ) {
1557+ processStoreIndexed (node , node .array (), node .value (), state );
15101558 }
15111559
1512- protected NewInstanceTypeFlow createNewArrayTypeFlow (NewArrayNode node , AnalysisType type , BytecodeLocation allocationLabel ) {
1513- return new NewInstanceTypeFlow (node , type , allocationLabel );
1560+ private void processStoreIndexed (ValueNode node , ValueNode array , ValueNode value , TypeFlowsOfNodes state ) {
1561+ if (value .getStackKind () == JavaKind .Object ) {
1562+ AnalysisType arrayType = (AnalysisType ) StampTool .typeOrNull (array );
1563+ AnalysisType nonNullArrayType = Optional .ofNullable (arrayType ).orElseGet (bb ::getObjectArrayType );
1564+ TypeFlowBuilder <?> arrayBuilder = state .lookup (array );
1565+ TypeFlowBuilder <?> valueBuilder = state .lookup (value );
1566+ TypeFlowBuilder <?> storeIndexedBuilder = TypeFlowBuilder .create (bb , node , StoreIndexedTypeFlow .class , () -> {
1567+ StoreIndexedTypeFlow storeIndexedFlow = new StoreIndexedTypeFlow (node , nonNullArrayType , arrayBuilder .get (), valueBuilder .get ());
1568+ methodFlow .addMiscEntry (storeIndexedFlow );
1569+ return storeIndexedFlow ;
1570+ });
1571+ storeIndexedBuilder .addUseDependency (valueBuilder );
1572+ storeIndexedBuilder .addObserverDependency (arrayBuilder );
1573+
1574+ /* Index stores must not be removed. */
1575+ typeFlowGraphBuilder .registerSinkBuilder (storeIndexedBuilder );
1576+ }
15141577 }
15151578
15161579 /** Hook for unsafe offset value checks. */
0 commit comments