Skip to content

Commit 435dd93

Browse files
author
Christian Wimmer
committed
Run escape analysis before static analysis
1 parent 50dda19 commit 435dd93

19 files changed

+376
-182
lines changed

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/AccessFieldTypeFlow.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
*/
2525
package com.oracle.graal.pointsto.flow;
2626

27-
import org.graalvm.compiler.nodes.java.AccessFieldNode;
27+
import org.graalvm.compiler.nodes.ValueNode;
2828

2929
import com.oracle.graal.pointsto.PointsToAnalysis;
3030
import com.oracle.graal.pointsto.meta.AnalysisField;
@@ -38,10 +38,10 @@ public abstract class AccessFieldTypeFlow extends TypeFlow<BytecodePosition> {
3838
/** The field that this flow stores into or loads from. */
3939
protected final AnalysisField field;
4040

41-
protected AccessFieldTypeFlow(AccessFieldNode node) {
41+
protected AccessFieldTypeFlow(ValueNode node, AnalysisField field) {
4242
/* The declared type of a field access node is the field declared type. */
43-
super(node.getNodeSourcePosition(), ((AnalysisField) node.field()).getType());
44-
this.field = (AnalysisField) node.field();
43+
super(node.getNodeSourcePosition(), field.getType());
44+
this.field = field;
4545
}
4646

4747
protected AccessFieldTypeFlow(AccessFieldTypeFlow original, MethodFlowsGraph methodFlows) {

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/AnalysisParsedGraph.java

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -141,14 +141,19 @@ public static AnalysisParsedGraph parseBytecode(BigBang bb, AnalysisMethod metho
141141
}
142142
}
143143

144+
@SuppressWarnings("try")
144145
private static AnalysisParsedGraph optimizeAndEncode(BigBang bb, AnalysisMethod method, StructuredGraph graph, boolean isIntrinsic) {
145-
/*
146-
* Must be called before any other thread can access the graph, i.e., before the graph is
147-
* published.
148-
*/
149-
bb.getHostVM().methodAfterParsingHook(bb, method, graph);
150-
151-
EncodedGraph encodedGraph = GraphEncoder.encodeSingleGraph(graph, HOST_ARCHITECTURE);
152-
return new AnalysisParsedGraph(encodedGraph, isIntrinsic);
146+
try (DebugContext.Scope s = graph.getDebug().scope("ClosedWorldAnalysis", graph, method)) {
147+
/*
148+
* Must be called before any other thread can access the graph, i.e., before the graph
149+
* is published.
150+
*/
151+
bb.getHostVM().methodAfterParsingHook(bb, method, graph);
152+
153+
EncodedGraph encodedGraph = GraphEncoder.encodeSingleGraph(graph, HOST_ARCHITECTURE);
154+
return new AnalysisParsedGraph(encodedGraph, isIntrinsic);
155+
} catch (Throwable e) {
156+
throw graph.getDebug().handle(e);
157+
}
153158
}
154159
}

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/LoadFieldTypeFlow.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
import com.oracle.graal.pointsto.PointsToAnalysis;
3030
import com.oracle.graal.pointsto.flow.context.object.AnalysisObject;
31+
import com.oracle.graal.pointsto.meta.AnalysisField;
3132
import com.oracle.graal.pointsto.typestate.TypeState;
3233

3334
import jdk.vm.ci.code.BytecodePosition;
@@ -38,7 +39,7 @@
3839
public abstract class LoadFieldTypeFlow extends AccessFieldTypeFlow {
3940

4041
protected LoadFieldTypeFlow(LoadFieldNode node) {
41-
super(node);
42+
super(node, (AnalysisField) node.field());
4243
}
4344

4445
protected LoadFieldTypeFlow(MethodFlowsGraph methodFlows, LoadFieldTypeFlow original) {

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java

Lines changed: 127 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@
9090
import org.graalvm.compiler.nodes.java.UnsafeCompareAndSwapNode;
9191
import org.graalvm.compiler.nodes.type.StampTool;
9292
import 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;
9397
import org.graalvm.compiler.phases.common.CanonicalizerPhase;
9498
import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase;
9599
import 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. */

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/StoreFieldTypeFlow.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,20 @@
2424
*/
2525
package com.oracle.graal.pointsto.flow;
2626

27-
import org.graalvm.compiler.nodes.java.StoreFieldNode;
27+
import org.graalvm.compiler.nodes.ValueNode;
2828

2929
import com.oracle.graal.pointsto.PointsToAnalysis;
3030
import com.oracle.graal.pointsto.flow.context.object.AnalysisObject;
31+
import com.oracle.graal.pointsto.meta.AnalysisField;
3132
import com.oracle.graal.pointsto.typestate.TypeState;
3233

3334
/**
3435
* Implements a field store operation type flow.
3536
*/
3637
public abstract class StoreFieldTypeFlow extends AccessFieldTypeFlow {
3738

38-
protected StoreFieldTypeFlow(StoreFieldNode node) {
39-
super(node);
39+
protected StoreFieldTypeFlow(ValueNode node, AnalysisField field) {
40+
super(node, field);
4041
}
4142

4243
protected StoreFieldTypeFlow(StoreFieldTypeFlow original, MethodFlowsGraph methodFlows) {
@@ -60,8 +61,8 @@ public static class StoreStaticFieldTypeFlow extends StoreFieldTypeFlow {
6061
/** The flow of the input value. */
6162
private final TypeFlow<?> valueFlow;
6263

63-
StoreStaticFieldTypeFlow(StoreFieldNode node, TypeFlow<?> valueFlow, FieldTypeFlow fieldFlow) {
64-
super(node);
64+
StoreStaticFieldTypeFlow(ValueNode node, AnalysisField field, TypeFlow<?> valueFlow, FieldTypeFlow fieldFlow) {
65+
super(node, field);
6566
this.valueFlow = valueFlow;
6667
this.fieldFlow = fieldFlow;
6768
}
@@ -107,8 +108,8 @@ public static class StoreInstanceFieldTypeFlow extends StoreFieldTypeFlow {
107108
/** The flow of the store operation receiver object. */
108109
private TypeFlow<?> objectFlow;
109110

110-
StoreInstanceFieldTypeFlow(StoreFieldNode node, TypeFlow<?> valueFlow, TypeFlow<?> objectFlow) {
111-
super(node);
111+
StoreInstanceFieldTypeFlow(ValueNode node, AnalysisField field, TypeFlow<?> valueFlow, TypeFlow<?> objectFlow) {
112+
super(node, field);
112113
this.valueFlow = valueFlow;
113114
this.objectFlow = objectFlow;
114115
}

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMetaAccess.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ public class AnalysisMetaAccess extends UniverseMetaAccess {
4040

4141
public AnalysisMetaAccess(AnalysisUniverse analysisUniverse, MetaAccessProvider originalMetaAccess) {
4242
super(analysisUniverse, originalMetaAccess);
43+
44+
/* Make sure that Object type is added to the universe before any other types. */
45+
lookupJavaType(Object.class);
46+
/* Cloneable is needed before any other instance class can be created. */
47+
lookupJavaType(Cloneable.class);
4348
}
4449

4550
@Override

0 commit comments

Comments
 (0)