Skip to content

Commit 5a88a79

Browse files
committed
[GR-60297] Fix Reachability Analysis in Native Image
PullRequest: graal/20825
2 parents 1fb2046 + 3f1a26b commit 5a88a79

File tree

6 files changed

+141
-194
lines changed

6 files changed

+141
-194
lines changed

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

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ public class MethodTypeFlowBuilder {
184184
protected StructuredGraph graph;
185185
private NodeBitMap processedNodes;
186186
private Map<PhiNode, TypeFlowBuilder<?>> loopPhiFlows;
187-
private final MethodFlowsGraph.GraphKind graphKind;
187+
private final GraphKind graphKind;
188188
private boolean processed = false;
189189
private final boolean newFlowsGraph;
190190

@@ -240,28 +240,7 @@ private boolean parse(Object reason, boolean forceReparse) {
240240
graph = InlineBeforeAnalysis.decodeGraph(bb, method, analysisParsedGraph);
241241

242242
try (DebugContext.Scope s = graph.getDebug().scope("MethodTypeFlowBuilder", graph)) {
243-
CanonicalizerPhase canonicalizerPhase = CanonicalizerPhase.create();
244-
canonicalizerPhase.apply(graph, bb.getProviders(method));
245-
if (PointstoOptions.ConditionalEliminationBeforeAnalysis.getValue(bb.getOptions())) {
246-
/*
247-
* Removing unnecessary conditions before the static analysis runs reduces the size
248-
* of the type flow graph. For example, this removes redundant null checks: the
249-
* bytecode parser emits explicit null checks before e.g., all method calls, field
250-
* access, array accesses; many of those dominate each other.
251-
*/
252-
new IterativeConditionalEliminationPhase(canonicalizerPhase, false).apply(graph, bb.getProviders(method));
253-
}
254-
if (PointstoOptions.EscapeAnalysisBeforeAnalysis.getValue(bb.getOptions())) {
255-
if (method.isOriginalMethod()) {
256-
/*
257-
* Deoptimization Targets cannot have virtual objects in frame states.
258-
*
259-
* Also, more work is needed to enable PEA in Runtime Compiled Methods.
260-
*/
261-
new BoxNodeIdentityPhase().apply(graph, bb.getProviders(method));
262-
new PartialEscapePhase(false, canonicalizerPhase, bb.getOptions()).apply(graph, bb.getProviders(method));
263-
}
264-
}
243+
optimizeGraphBeforeAnalysis(bb, method, graph);
265244

266245
if (!bb.getUniverse().hostVM().validateGraph(bb, graph)) {
267246
graph = null;
@@ -277,8 +256,33 @@ private boolean parse(Object reason, boolean forceReparse) {
277256
}
278257
}
279258

280-
public static void registerUsedElements(PointsToAnalysis bb, StructuredGraph graph, boolean usePredicates) {
281-
PointsToAnalysisMethod method = (PointsToAnalysisMethod) graph.method();
259+
public static void optimizeGraphBeforeAnalysis(AbstractAnalysisEngine bb, AnalysisMethod method, StructuredGraph graph) {
260+
CanonicalizerPhase canonicalizerPhase = CanonicalizerPhase.create();
261+
canonicalizerPhase.apply(graph, bb.getProviders(method));
262+
if (PointstoOptions.ConditionalEliminationBeforeAnalysis.getValue(bb.getOptions())) {
263+
/*
264+
* Removing unnecessary conditions before the static analysis runs reduces the size of
265+
* the type flow graph. For example, this removes redundant null checks: the bytecode
266+
* parser emits explicit null checks before e.g., all method calls, field access, array
267+
* accesses; many of those dominate each other.
268+
*/
269+
new IterativeConditionalEliminationPhase(canonicalizerPhase, false).apply(graph, bb.getProviders(method));
270+
}
271+
if (PointstoOptions.EscapeAnalysisBeforeAnalysis.getValue(bb.getOptions())) {
272+
if (method.isOriginalMethod()) {
273+
/*
274+
* Deoptimization Targets cannot have virtual objects in frame states.
275+
*
276+
* Also, more work is needed to enable PEA in Runtime Compiled Methods.
277+
*/
278+
new BoxNodeIdentityPhase().apply(graph, bb.getProviders(method));
279+
new PartialEscapePhase(false, canonicalizerPhase, bb.getOptions()).apply(graph, bb.getProviders(method));
280+
}
281+
}
282+
}
283+
284+
public static void registerUsedElements(AbstractAnalysisEngine bb, StructuredGraph graph, boolean usePredicates) {
285+
var method = (AnalysisMethod) graph.method();
282286
HostedProviders providers = bb.getProviders(method);
283287
for (Node n : graph.getNodes()) {
284288
if (n instanceof InstanceOfNode) {
@@ -295,7 +299,8 @@ public static void registerUsedElements(PointsToAnalysis bb, StructuredGraph gra
295299
type.registerAsInstantiated(AbstractAnalysisEngine.sourcePosition(node));
296300
for (var f : type.getInstanceFields(true)) {
297301
var field = (AnalysisField) f;
298-
field.getInitialFlow().addState(bb, TypeState.defaultValueForKind(bb, field.getStorageKind()));
302+
PointsToAnalysis pta = (PointsToAnalysis) bb;
303+
field.getInitialFlow().addState(pta, TypeState.defaultValueForKind(pta, field.getStorageKind()));
299304
}
300305
}
301306

@@ -416,7 +421,7 @@ public static void registerUsedElements(PointsToAnalysis bb, StructuredGraph gra
416421
* {@link FrameState} are only used for debugging. We do not want to have larger images just so
417422
* that users can see a constant value in the debugger.
418423
*/
419-
protected static boolean ignoreConstant(PointsToAnalysis bb, ConstantNode node) {
424+
protected static boolean ignoreConstant(AbstractAnalysisEngine bb, ConstantNode node) {
420425
for (var u : node.usages()) {
421426
if (u instanceof ClassIsAssignableFromNode usage) {
422427
if (!bb.getHostVM().isClosedTypeWorld() || usage.getOtherClass() == node || usage.getThisClass() != node) {
@@ -472,7 +477,7 @@ protected static boolean needsUnsafeRegistration(FieldOffsetProvider node) {
472477
* later. Therefore, we must mark the instanceof checked type as reachable. Moreover, stamp
473478
* strengthening based on reachability status of types must be disabled.
474479
*/
475-
protected static boolean ignoreInstanceOfType(PointsToAnalysis bb, AnalysisType type) {
480+
protected static boolean ignoreInstanceOfType(AbstractAnalysisEngine bb, AnalysisType type) {
476481
if (bb.getHostVM().ignoreInstanceOfTypeDisallowed()) {
477482
return false;
478483
}
@@ -493,11 +498,11 @@ protected static boolean ignoreInstanceOfType(PointsToAnalysis bb, AnalysisType
493498
return true;
494499
}
495500

496-
private static void registerEmbeddedRoot(PointsToAnalysis bb, ConstantNode cn) {
501+
private static void registerEmbeddedRoot(AbstractAnalysisEngine bb, ConstantNode cn) {
497502
bb.getUniverse().registerEmbeddedRoot(cn.asJavaConstant(), AbstractAnalysisEngine.sourcePosition(cn));
498503
}
499504

500-
private static void registerForeignCall(PointsToAnalysis bb, ForeignCallsProvider foreignCallsProvider, ForeignCallDescriptor foreignCallDescriptor, ResolvedJavaMethod from) {
505+
private static void registerForeignCall(AbstractAnalysisEngine bb, ForeignCallsProvider foreignCallsProvider, ForeignCallDescriptor foreignCallDescriptor, ResolvedJavaMethod from) {
501506
Optional<AnalysisMethod> targetMethod = bb.getHostVM().handleForeignCall(foreignCallDescriptor, foreignCallsProvider);
502507
targetMethod.ifPresent(analysisMethod -> bb.addRootMethod(analysisMethod, true, from));
503508
}
@@ -725,7 +730,7 @@ protected void apply(boolean forceReparse, Object reason) {
725730
}
726731

727732
boolean insertPlaceholderFlows = bb.getHostVM().getMultiMethodAnalysisPolicy().insertPlaceholderParamAndReturnFlows(method.getMultiMethodKey());
728-
if (graphKind == MethodFlowsGraph.GraphKind.STUB) {
733+
if (graphKind == GraphKind.STUB) {
729734
AnalysisError.guarantee(insertPlaceholderFlows, "placeholder flows must be enabled for STUB graphkinds.");
730735
insertPlaceholderParamAndReturnFlows();
731736
return;

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import com.oracle.graal.pointsto.meta.AnalysisField;
5353
import com.oracle.graal.pointsto.meta.AnalysisMethod;
5454
import com.oracle.graal.pointsto.meta.AnalysisType;
55+
import com.oracle.graal.pointsto.meta.PointsToAnalysisField;
5556
import com.oracle.graal.pointsto.meta.PointsToAnalysisMethod;
5657
import com.oracle.graal.pointsto.typestate.PrimitiveConstantTypeState;
5758
import com.oracle.graal.pointsto.typestate.TypeState;
@@ -437,15 +438,15 @@ public void simplify(Node n, SimplifierTool tool) {
437438
Object newStampOrConstant = strengthenStampFromTypeFlow(node, parameterFlows[node.index()], anchorPoint, tool);
438439
updateStampUsingPiNode(node, newStampOrConstant, anchorPoint, tool);
439440

440-
} else if (n instanceof LoadFieldNode node) {
441+
} else if (n instanceof LoadFieldNode node && node.field() instanceof PointsToAnalysisField field) {
441442
/*
442443
* First step: it is beneficial to strengthen the stamp of the LoadFieldNode because
443444
* then there is no artificial anchor after which the more precise type is
444445
* available. However, the memory load will be a floating node later, so we can only
445446
* update the stamp directly to the stamp that is correct for the whole method and
446447
* all inlined methods.
447448
*/
448-
Object fieldNewStampOrConstant = strengthenStampFromTypeFlow(node, ((AnalysisField) node.field()).getSinkFlow(), node, tool);
449+
Object fieldNewStampOrConstant = strengthenStampFromTypeFlow(node, field.getSinkFlow(), node, tool);
449450
if (fieldNewStampOrConstant instanceof JavaConstant) {
450451
ConstantNode replacement = ConstantNode.forConstant((JavaConstant) fieldNewStampOrConstant, bb.getMetaAccess(), graph);
451452
graph.replaceFixedWithFloating(node, replacement);

0 commit comments

Comments
 (0)