Skip to content

Commit 8fb7c0c

Browse files
author
Christian Wimmer
committed
Strengthen graphs with constants propagated through static analysis
1 parent 890a261 commit 8fb7c0c

File tree

10 files changed

+108
-25
lines changed

10 files changed

+108
-25
lines changed

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/context/bytecode/ContextSensitiveSingleTypeState.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
import com.oracle.graal.pointsto.typestate.SingleTypeState;
3737
import com.oracle.graal.pointsto.typestate.TypeState;
3838

39+
import jdk.vm.ci.meta.JavaConstant;
40+
3941
public class ContextSensitiveSingleTypeState extends SingleTypeState {
4042
/** The objects of this type state. */
4143
protected final AnalysisObject[] objects;
@@ -145,8 +147,16 @@ public boolean isAllocation() {
145147
}
146148

147149
@Override
148-
public boolean isConstant() {
149-
return objects[0].isConstantContextSensitiveObject();
150+
public JavaConstant asConstant() {
151+
JavaConstant result = null;
152+
for (AnalysisObject object : objects) {
153+
JavaConstant objectConstant = object.asConstant();
154+
if (objectConstant == null || (result != null && !result.equals(objectConstant))) {
155+
return null;
156+
}
157+
result = objectConstant;
158+
}
159+
return result;
150160
}
151161

152162
@Override

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/context/object/AnalysisObject.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -179,12 +179,8 @@ public final boolean isAllocationContextSensitiveObject() {
179179
return this.kind == AnalysisObjectKind.AllocationContextSensitive;
180180
}
181181

182-
public final boolean isConstantContextSensitiveObject() {
183-
return this.kind == AnalysisObjectKind.ConstantContextSensitive;
184-
}
185-
186-
public final boolean isConstantObject() {
187-
return this.kind == AnalysisObjectKind.ConstantObject;
182+
public JavaConstant asConstant() {
183+
return null;
188184
}
189185

190186
public ArrayElementsTypeStore getArrayElementsTypeStore() {

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/context/object/ConstantContextSensitiveObject.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ public ConstantContextSensitiveObject(PointsToAnalysis bb, AnalysisType type, Ja
7979
bb.profileConstantObject(type);
8080
}
8181

82-
public JavaConstant getConstant() {
82+
@Override
83+
public JavaConstant asConstant() {
8384
return constant;
8485
}
8586

@@ -128,7 +129,7 @@ public boolean isEmptyObjectArrayConstant(PointsToAnalysis bb) {
128129
return false;
129130
}
130131

131-
return AnalysisObject.isEmptyObjectArrayConstant(bb, getConstant());
132+
return AnalysisObject.isEmptyObjectArrayConstant(bb, asConstant());
132133
}
133134

134135
@Override

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java

Lines changed: 72 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.graalvm.compiler.core.common.type.StampFactory;
3636
import org.graalvm.compiler.core.common.type.TypeReference;
3737
import org.graalvm.compiler.debug.DebugContext;
38+
import org.graalvm.compiler.debug.GraalError;
3839
import org.graalvm.compiler.graph.Node;
3940
import org.graalvm.compiler.graph.NodeBitMap;
4041
import org.graalvm.compiler.graph.NodeInputList;
@@ -83,6 +84,7 @@
8384
import com.oracle.graal.pointsto.flow.MethodFlowsGraph;
8485
import com.oracle.graal.pointsto.flow.MethodTypeFlow;
8586
import com.oracle.graal.pointsto.flow.TypeFlow;
87+
import com.oracle.graal.pointsto.heap.ImageHeapConstant;
8688
import com.oracle.graal.pointsto.infrastructure.Universe;
8789
import com.oracle.graal.pointsto.meta.AnalysisField;
8890
import com.oracle.graal.pointsto.meta.AnalysisMethod;
@@ -91,9 +93,11 @@
9193
import com.oracle.graal.pointsto.typestate.TypeState;
9294
import com.oracle.svm.util.ImageBuildStatistics;
9395

96+
import jdk.vm.ci.meta.JavaConstant;
9497
import jdk.vm.ci.meta.JavaKind;
9598
import jdk.vm.ci.meta.JavaMethodProfile;
9699
import jdk.vm.ci.meta.JavaTypeProfile;
100+
import jdk.vm.ci.meta.MetaAccessProvider;
97101
import jdk.vm.ci.meta.ResolvedJavaType;
98102

99103
/**
@@ -142,6 +146,11 @@ public StaticAnalysisResults makeOrApplyResults(AnalysisMethod m) {
142146
debug.handle(ex);
143147
}
144148

149+
for (Node node : graph.getNodes()) {
150+
if (node instanceof ValueNode && ((ValueNode) node).stamp(NodeView.DEFAULT) instanceof ConstantObjectStamp) {
151+
throw GraalError.shouldNotReachHere("ConstantObjectStamp must not be visible outside of this class");
152+
}
153+
}
145154
method.setAnalyzedGraph(GraphEncoder.encodeSingleGraph(graph, AnalysisParsedGraph.HOST_ARCHITECTURE));
146155
}
147156

@@ -259,7 +268,13 @@ public void simplify(Node n, SimplifierTool tool) {
259268
* context-sensitive analysis, we will need to change this. But for now, we are
260269
* fine.
261270
*/
262-
updateStampInPlace(node, newStamp, tool);
271+
if (newStamp instanceof ConstantObjectStamp) {
272+
ConstantNode replacement = ConstantNode.forConstant(((ConstantObjectStamp) newStamp).constant, bb.getMetaAccess(), graph);
273+
graph.replaceFixedWithFloating(node, replacement);
274+
tool.addToWorkList(replacement);
275+
} else {
276+
updateStampInPlace(node, newStamp, tool);
277+
}
263278

264279
} else if (n instanceof Invoke) {
265280
Invoke invoke = (Invoke) n;
@@ -390,8 +405,8 @@ private void handleInvoke(Invoke invoke, SimplifierTool tool) {
390405
/* Parameter stamp was empty, so invoke is unreachable. */
391406
return;
392407
} else if (newStamp != null) {
393-
PiNode pi = insertPi(argument, newStamp, beforeInvoke);
394-
if (pi != null) {
408+
ValueNode pi = insertPi(argument, newStamp, beforeInvoke);
409+
if (pi != null && pi != argument) {
395410
callTarget.replaceAllInputs(argument, pi);
396411
}
397412
}
@@ -521,17 +536,20 @@ private void updateStampInPlace(ValueNode node, Stamp newStamp, SimplifierTool t
521536

522537
private void updateStampUsingPiNode(ValueNode node, Stamp newStamp, FixedWithNextNode anchorPoint, SimplifierTool tool) {
523538
if (newStamp != null && node.hasUsages() && !createdPiNodes.isMarked(node)) {
524-
PiNode pi = insertPi(node, newStamp, anchorPoint);
539+
ValueNode pi = insertPi(node, newStamp, anchorPoint);
525540
if (pi != null) {
526541
/*
527542
* The Canonicalizer that drives all of our node processing is iterative. We
528543
* only want to insert the PiNode the first time we handle a node.
529544
*/
530545
createdPiNodes.mark(node);
531546

532-
FrameState anchorState = node instanceof StateSplit ? ((StateSplit) node).stateAfter() : graph.start().stateAfter();
533-
node.replaceAtUsages(pi, usage -> usage != pi && usage != anchorState);
534-
547+
if (pi.isConstant()) {
548+
node.replaceAtUsages(pi);
549+
} else {
550+
FrameState anchorState = node instanceof StateSplit ? ((StateSplit) node).stateAfter() : graph.start().stateAfter();
551+
node.replaceAtUsages(pi, usage -> usage != pi && usage != anchorState);
552+
}
535553
tool.addToWorkList(pi.usages());
536554
}
537555
}
@@ -540,7 +558,16 @@ private void updateStampUsingPiNode(ValueNode node, Stamp newStamp, FixedWithNex
540558
/*
541559
* See comment on {@link StrengthenGraphs} on why anchoring is necessary.
542560
*/
543-
private PiNode insertPi(ValueNode input, Stamp piStamp, FixedWithNextNode anchorPoint) {
561+
private ValueNode insertPi(ValueNode input, Stamp piStamp, FixedWithNextNode anchorPoint) {
562+
if (piStamp instanceof ConstantObjectStamp) {
563+
JavaConstant constant = ((ConstantObjectStamp) piStamp).constant;
564+
if (input.isConstant()) {
565+
assert input.asConstant().equals(constant);
566+
return null;
567+
}
568+
return ConstantNode.forConstant(constant, bb.getMetaAccess(), graph);
569+
}
570+
544571
Stamp oldStamp = input.stamp(NodeView.DEFAULT);
545572
Stamp computedStamp = oldStamp.improveWith(piStamp);
546573
if (oldStamp.equals(computedStamp)) {
@@ -571,6 +598,23 @@ private Stamp strengthenStampFromTypeFlow(ValueNode node, TypeFlow<?> nodeFlow,
571598
}
572599

573600
TypeState nodeTypeState = methodFlow.foldTypeFlow(pta, nodeFlow);
601+
602+
if (!nodeTypeState.canBeNull()) {
603+
JavaConstant constantValue = nodeTypeState.asConstant();
604+
if (constantValue instanceof ImageHeapConstant) {
605+
/*
606+
* Temporary: until the AOT compilation can properly constant fold also
607+
* ImageHeapConstant, we unwrap the ImageHeapConstant to the hosted object. This
608+
* also means we do not constant fold yet when the constant does not wrap a
609+
* hosted object.
610+
*/
611+
constantValue = ((ImageHeapConstant) constantValue).getHostedObject();
612+
}
613+
if (constantValue != null) {
614+
return ConstantObjectStamp.forConstant(constantValue, bb.getMetaAccess());
615+
}
616+
}
617+
574618
node.inferStamp();
575619
ObjectStamp oldStamp = (ObjectStamp) node.stamp(NodeView.DEFAULT);
576620
AnalysisType oldType = (AnalysisType) oldStamp.type();
@@ -732,3 +776,23 @@ private Stamp strengthenStamp(Stamp s) {
732776
}
733777
}
734778
}
779+
780+
/**
781+
* {@link ObjectStamp} cannot represent a real "constant" stamp, so we use this class as a temporary
782+
* holder for a constant. Such a stamp is never stored as the stamp of a node, instead the node is
783+
* replaces with a {@link ConstantNode}.
784+
*/
785+
final class ConstantObjectStamp extends ObjectStamp {
786+
787+
final JavaConstant constant;
788+
789+
static Stamp forConstant(JavaConstant constant, MetaAccessProvider metaAccess) {
790+
ResolvedJavaType type = constant.isNull() ? null : metaAccess.lookupJavaType(constant);
791+
return new ConstantObjectStamp(constant, type, constant.isNonNull(), constant.isNonNull(), constant.isNull(), false);
792+
}
793+
794+
private ConstantObjectStamp(JavaConstant constant, ResolvedJavaType type, boolean exactType, boolean nonNull, boolean alwaysNull, boolean alwaysArray) {
795+
super(type, exactType, nonNull, alwaysNull, alwaysArray);
796+
this.constant = constant;
797+
}
798+
}

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/ConstantTypeState.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,8 @@ public void noteMerge(PointsToAnalysis bb) {
100100
}
101101

102102
@Override
103-
public boolean isConstant() {
104-
return true;
103+
public JavaConstant asConstant() {
104+
return constant;
105105
}
106106

107107
@Override

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/PointsToStats.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,7 @@ public static String asString(TypeState s) {
632632
return "<Null>";
633633
}
634634

635-
String sKind = s.isAllocation() ? "Alloc" : s.isConstant() ? "Const" : s instanceof SingleTypeState ? "Single" : s instanceof MultiTypeState ? "Multi" : "";
635+
String sKind = s.isAllocation() ? "Alloc" : s.asConstant() != null ? "Const" : s instanceof SingleTypeState ? "Single" : s instanceof MultiTypeState ? "Multi" : "";
636636
String sSizeOrType = s instanceof MultiTypeState ? s.typesCount() + "" : s.exactType().toJavaName(false);
637637
int objectsNumber = s.objectsCount();
638638
String canBeNull = s.canBeNull() ? "null" : "!null";

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/TypeState.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,16 @@ public boolean isAllocation() {
115115
return false;
116116
}
117117

118-
public boolean isConstant() {
119-
return false;
118+
/**
119+
* Returns a non-null value when this type state represents a single constant value, or null if
120+
* this type state is not a single constant.
121+
*
122+
* Note that the {@link #canBeNull()} flag still applies when a constant is returned. A type
123+
* state that is a "constant or null" both returns a non-null result for {@link #asConstant()}}
124+
* and true for {@link #canBeNull()}.
125+
*/
126+
public JavaConstant asConstant() {
127+
return null;
120128
}
121129

122130
public boolean isEmpty() {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/GCCause.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ public class GCCause {
4747
@DuplicatedInNativeCode public static final GCCause TestGCInDeoptimizer = new GCCause("TestGCInDeoptimizer", 2);
4848
@DuplicatedInNativeCode public static final GCCause HintedGC = new GCCause("Hint", 3);
4949

50-
protected static GCCause[] GCCauses = new GCCause[]{JavaLangSystemGC, UnitTest, TestGCInDeoptimizer, HintedGC};
50+
@UnknownObjectField(types = GCCause[].class) //
51+
protected static GCCause[] GCCauses;
5152

5253
private final int id;
5354
private final String name;

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/BootModuleLayerSupport.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,15 @@
2828
import org.graalvm.nativeimage.Platform;
2929
import org.graalvm.nativeimage.Platforms;
3030

31+
import com.oracle.svm.core.heap.UnknownObjectField;
32+
3133
public final class BootModuleLayerSupport {
3234

3335
public static BootModuleLayerSupport instance() {
3436
return ImageSingletons.lookup(BootModuleLayerSupport.class);
3537
}
3638

39+
@UnknownObjectField(types = ModuleLayer.class) //
3740
private ModuleLayer bootLayer;
3841

3942
@Platforms(Platform.HOSTED_ONLY.class)

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ModuleLayerFeature.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ public void duringSetup(DuringSetupAccess access) {
120120
.map(Module::getName)
121121
.collect(Collectors.toSet());
122122
Function<String, ClassLoader> clf = moduleLayerFeatureUtils::getClassLoaderForBootLayerModule;
123-
ModuleLayer runtimeBootLayer = synthesizeRuntimeModuleLayer(List.of(ModuleLayer.empty()), accessImpl.imageClassLoader, baseModules, Set.of(), clf, null);
123+
ModuleLayer runtimeBootLayer = synthesizeRuntimeModuleLayer(new ArrayList<>(List.of(ModuleLayer.empty())), accessImpl.imageClassLoader, baseModules, Set.of(), clf, null);
124124
BootModuleLayerSupport.instance().setBootLayer(runtimeBootLayer);
125125

126126
/*

0 commit comments

Comments
 (0)