Skip to content

Commit 68d6e0b

Browse files
committed
[GR-59875] Fix graph strengthening for open world.
PullRequest: graal/19527
2 parents 7a35200 + 141b386 commit 68d6e0b

File tree

5 files changed

+46
-22
lines changed

5 files changed

+46
-22
lines changed

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

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ public static void registerUsedElements(PointsToAnalysis bb, StructuredGraph gra
354354
JavaConstant root = cn.asJavaConstant();
355355
if (cn.hasUsages() && cn.isJavaConstant() && root.getJavaKind() == JavaKind.Object && root.isNonNull()) {
356356
assert StampTool.isExactType(cn) : cn;
357-
if (!ignoreConstant(cn)) {
357+
if (!ignoreConstant(bb, cn)) {
358358
AnalysisType type = (AnalysisType) StampTool.typeOrNull(cn, bb.getMetaAccess());
359359
type.registerAsInstantiated(new EmbeddedRootScan(AbstractAnalysisEngine.sourcePosition(cn), root));
360360
registerEmbeddedRoot(bb, cn);
@@ -402,20 +402,23 @@ public static void registerUsedElements(PointsToAnalysis bb, StructuredGraph gra
402402
* do not want to make the receiver class reachable, because as long as the receiver class is
403403
* not reachable for any other "real" reason we know that isAssignableFrom will always return
404404
* false. So in {@link StrengthenGraphs} we can then constant-fold the
405-
* {@link ClassIsAssignableFromNode} to false.
405+
* {@link ClassIsAssignableFromNode} to false. We only apply this optimization for
406+
* {@link ClassIsAssignableFromNode} if it's a closed type world, for open world we cannot fold
407+
* the type check since the type may be used later.
406408
*
407409
* Similarly, a class should not be marked as reachable only so that we can add the class name
408410
* to the error message of a {@link ClassCastException}. In {@link StrengthenGraphs} we can
409411
* re-write the Class constant to a String constant, i.e., only embed the class name and not the
410-
* full java.lang.Class object in the image.
412+
* full java.lang.Class object in the image. We can apply this optimization optimistically for
413+
* both closed and open type world.
411414
*
412415
* {@link FrameState} are only used for debugging. We do not want to have larger images just so
413416
* that users can see a constant value in the debugger.
414417
*/
415-
protected static boolean ignoreConstant(ConstantNode node) {
418+
protected static boolean ignoreConstant(PointsToAnalysis bb, ConstantNode node) {
416419
for (var u : node.usages()) {
417420
if (u instanceof ClassIsAssignableFromNode usage) {
418-
if (usage.getOtherClass() == node || usage.getThisClass() != node) {
421+
if (!bb.getHostVM().isClosedTypeWorld() || usage.getOtherClass() == node || usage.getThisClass() != node) {
419422
return false;
420423
}
421424
} else if (u instanceof BytecodeExceptionNode usage) {
@@ -458,10 +461,23 @@ protected static boolean needsUnsafeRegistration(FieldOffsetProvider node) {
458461
return false;
459462
}
460463

464+
/**
465+
* In closed type world, just using a type in an instanceof type check doesn't mark the type as
466+
* reachable. Assuming the type is not otherwise made reachable, this allows the graph
467+
* strengthening to eliminate the type check completely by replacing a stamp with an unreachable
468+
* type with an empty stamp (see StrengthenSimplifier#strengthenStamp).
469+
* <p>
470+
* However, in open world we cannot make assumptions about types that may become reachable
471+
* later. Therefore, we must mark the instanceof checked type as reachable. Moreover, stamp
472+
* strengthening based on reachability status of types must be disabled.
473+
*/
461474
protected static boolean ignoreInstanceOfType(PointsToAnalysis bb, AnalysisType type) {
462475
if (bb.getHostVM().ignoreInstanceOfTypeDisallowed()) {
463476
return false;
464477
}
478+
if (!bb.getHostVM().isClosedTypeWorld()) {
479+
return false;
480+
}
465481
if (type == null) {
466482
return false;
467483
}

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

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -506,20 +506,28 @@ public void simplify(Node n, SimplifierTool tool) {
506506
tool.addToWorkList(replacement);
507507
}
508508

509-
} else if (n instanceof ClassIsAssignableFromNode) {
510-
ClassIsAssignableFromNode node = (ClassIsAssignableFromNode) n;
511-
AnalysisType nonReachableType = asConstantNonReachableType(node.getThisClass(), tool);
512-
if (nonReachableType != null) {
513-
node.replaceAndDelete(LogicConstantNode.contradiction(graph));
509+
} else if (n instanceof ClassIsAssignableFromNode node) {
510+
if (isClosedTypeWorld) {
511+
/*
512+
* If the constant receiver of a Class#isAssignableFrom is an unreachable type
513+
* we can constant-fold the ClassIsAssignableFromNode to false. See also
514+
* MethodTypeFlowBuilder#ignoreConstant where we avoid marking the corresponding
515+
* type as reachable just because it is used by the ClassIsAssignableFromNode.
516+
* We only apply this optimization if it's a closed type world, for open world
517+
* we cannot fold the type check since the type may be used later.
518+
*/
519+
AnalysisType nonReachableType = asConstantNonReachableType(node.getThisClass(), tool);
520+
if (nonReachableType != null) {
521+
node.replaceAndDelete(LogicConstantNode.contradiction(graph));
522+
}
514523
}
515-
516-
} else if (n instanceof BytecodeExceptionNode) {
524+
} else if (n instanceof BytecodeExceptionNode node) {
517525
/*
518526
* We do not want a type to be reachable only to be used for the error message of a
519527
* ClassCastException. Therefore, in that case we replace the java.lang.Class with a
520-
* java.lang.String that is then used directly in the error message.
528+
* java.lang.String that is then used directly in the error message. We can apply
529+
* this optimization optimistically for both closed and open type world.
521530
*/
522-
BytecodeExceptionNode node = (BytecodeExceptionNode) n;
523531
if (node.getExceptionKind() == BytecodeExceptionNode.BytecodeExceptionKind.CLASS_CAST) {
524532
AnalysisType nonReachableType = asConstantNonReachableType(node.getArguments().get(1), tool);
525533
if (nonReachableType != null) {
@@ -1085,7 +1093,8 @@ private Stamp strengthenStamp(Stamp s) {
10851093
return null;
10861094
}
10871095

1088-
if (!originalType.isReachable()) {
1096+
/* In open world the type may become reachable later. */
1097+
if (isClosedTypeWorld && !originalType.isReachable()) {
10891098
/* We must be in dead code. */
10901099
if (stamp.nonNull()) {
10911100
/* We must be in dead code. */

substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/GraalGraphObjectReplacer.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -456,8 +456,8 @@ public void updateSubstrateDataAfterCompilation(HostedUniverse hUniverse, Provid
456456
}
457457
HostedType hType = hUniverse.lookup(aType);
458458

459-
if (hType.getUniqueConcreteImplementation() != null) {
460-
sType.setTypeCheckData(hType.getUniqueConcreteImplementation().getHub());
459+
if (hType.getSingleImplementor() != null) {
460+
sType.setSingleImplementor(hType.getSingleImplementor().getHub());
461461
}
462462

463463
if (sType.getInstanceFieldCount() > 1) {

substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateType.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ public SubstrateField[] getRawAllInstanceFields() {
8787
}
8888

8989
@Platforms(Platform.HOSTED_ONLY.class)
90-
public void setTypeCheckData(DynamicHub uniqueConcreteImplementation) {
90+
public void setSingleImplementor(DynamicHub uniqueConcreteImplementation) {
9191
this.uniqueConcreteImplementation = uniqueConcreteImplementation;
9292
}
9393

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedType.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,9 @@ public abstract class HostedType extends HostedElement implements SharedType, Wr
133133
* this type is never instantiated and does not have any instantiated subtype, i.e., if no value
134134
* of this type can ever exist. Equal to this type if this type is instantiated, i.e, this type
135135
* cannot be strengthened.
136+
*
137+
* For open world the strengthen stamp type is equal to this type itself if the type is not a
138+
* leaf type, i.e., it cannot be extended.
136139
*/
137140
protected HostedType strengthenStampType;
138141

@@ -276,10 +279,6 @@ public HostedMethod[] getAllDeclaredMethods() {
276279
return allDeclaredMethods;
277280
}
278281

279-
public HostedType getUniqueConcreteImplementation() {
280-
return uniqueConcreteImplementation;
281-
}
282-
283282
public void loadTypeID(int newTypeID) {
284283
this.typeID = newTypeID;
285284
this.loadedFromPriorLayer = true;

0 commit comments

Comments
 (0)