Skip to content

Commit 4de8fab

Browse files
committed
Unify condition anchor handling.
1 parent 9e0776b commit 4de8fab

File tree

3 files changed

+103
-85
lines changed

3 files changed

+103
-85
lines changed

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/ConditionAnchorNode.java

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -29,18 +29,34 @@
2929
import static jdk.graal.compiler.nodeinfo.NodeCycles.CYCLES_0;
3030
import static jdk.graal.compiler.nodeinfo.NodeSize.SIZE_0;
3131

32+
import jdk.graal.compiler.core.common.calc.CanonicalCondition;
3233
import jdk.graal.compiler.core.common.type.StampFactory;
3334
import jdk.graal.compiler.graph.Node;
3435
import jdk.graal.compiler.graph.NodeClass;
3536
import jdk.graal.compiler.nodeinfo.NodeInfo;
3637
import jdk.graal.compiler.nodeinfo.Verbosity;
38+
import jdk.graal.compiler.nodes.calc.CompareNode;
3739
import jdk.graal.compiler.nodes.extended.GuardingNode;
3840
import jdk.graal.compiler.nodes.extended.ValueAnchorNode;
3941
import jdk.graal.compiler.nodes.spi.Canonicalizable;
4042
import jdk.graal.compiler.nodes.spi.CanonicalizerTool;
4143
import jdk.graal.compiler.nodes.spi.Lowerable;
4244
import jdk.graal.compiler.nodes.spi.LoweringTool;
45+
import jdk.graal.compiler.options.OptionValues;
46+
import jdk.vm.ci.meta.ConstantReflectionProvider;
47+
import jdk.vm.ci.meta.MetaAccessProvider;
4348

49+
/**
50+
* A {@link ConditionAnchorNode} is used to anchor a floatable unsafe load or {@linkplain PiNode
51+
* unsafe cast} in the control flow and associate it with a control flow dependency (i.e. a guard),
52+
* represented as a boolean condition. Conditional Elimination then tries to find a guard that
53+
* corresponds to this condition, and rewires the condition anchor's usages to that guard. If no
54+
* such relationship can be established, the condition anchor is replaced with an unconditional
55+
* {@link ValueAnchorNode}.
56+
*
57+
* @see jdk.graal.compiler.phases.common.ConditionalEliminationPhase
58+
* @see jdk.graal.compiler.nodes.extended.GuardedUnsafeLoadNode
59+
*/
4460
@NodeInfo(nameTemplate = "ConditionAnchor(!={p#negated})", allowedUsageTypes = Guard, cycles = CYCLES_0, size = SIZE_0)
4561
public final class ConditionAnchorNode extends FixedWithNextNode implements Canonicalizable.Unary<Node>, Lowerable, GuardingNode {
4662

@@ -58,6 +74,37 @@ public ConditionAnchorNode(LogicNode condition, boolean negated) {
5874
this.condition = condition;
5975
}
6076

77+
/**
78+
* Creates a condition anchor from a boolean value representing the guarding condition.
79+
*
80+
* Note: The caller must handle the case where no anchor is needed for constant true.
81+
*/
82+
public static FixedWithNextNode create(ValueNode condition, ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, NodeView view) {
83+
if (condition.isConstant()) {
84+
return new ValueAnchorNode();
85+
} else {
86+
return create(CompareNode.createCompareNode(constantReflection, metaAccess, options, null, CanonicalCondition.EQ, condition, ConstantNode.forBoolean(true), view));
87+
}
88+
}
89+
90+
/**
91+
* Creates a condition anchor from a logical comparison.
92+
*
93+
* @see #canonical(CanonicalizerTool, Node)
94+
*/
95+
public static FixedWithNextNode create(LogicNode compareNode) {
96+
if (compareNode instanceof LogicConstantNode) {
97+
/*
98+
* Even if the condition is true, an anchor that has usages must still exist since it's
99+
* possible the condition is true for control flow reasons so the Pi stamp is also only
100+
* valid for those reasons.
101+
*/
102+
return new ValueAnchorNode();
103+
} else {
104+
return new ConditionAnchorNode(compareNode);
105+
}
106+
}
107+
61108
public LogicNode condition() {
62109
return condition;
63110
}
@@ -77,14 +124,12 @@ public String toString(Verbosity verbosity) {
77124

78125
@Override
79126
public Node canonical(CanonicalizerTool tool, Node forValue) {
80-
if (forValue instanceof LogicNegationNode) {
81-
LogicNegationNode negation = (LogicNegationNode) forValue;
127+
if (forValue instanceof LogicNegationNode negation) {
82128
return new ConditionAnchorNode(negation.getValue(), !negated);
83129
}
84-
if (forValue instanceof LogicConstantNode) {
85-
LogicConstantNode c = (LogicConstantNode) forValue;
130+
if (forValue instanceof LogicConstantNode c) {
86131
// An anchor that still has usages must still exist since it's possible the condition is
87-
// true for control flow reasons so the Pi stamp is also only valid for those reason.
132+
// true for control flow reasons so the Pi stamp is also only valid for those reasons.
88133
if (c.getValue() == negated || hasUsages()) {
89134
return new ValueAnchorNode();
90135
} else {

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/substitutions/TruffleGraphBuilderPlugins.java

Lines changed: 8 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242
import com.oracle.truffle.compiler.TruffleCompilationTask;
4343

4444
import jdk.graal.compiler.core.common.NumUtil;
45-
import jdk.graal.compiler.core.common.calc.CanonicalCondition;
4645
import jdk.graal.compiler.core.common.memory.MemoryOrderMode;
4746
import jdk.graal.compiler.core.common.type.IntegerStamp;
4847
import jdk.graal.compiler.core.common.type.ObjectStamp;
@@ -63,7 +62,6 @@
6362
import jdk.graal.compiler.nodes.FixedGuardNode;
6463
import jdk.graal.compiler.nodes.FrameState;
6564
import jdk.graal.compiler.nodes.InvokeNode;
66-
import jdk.graal.compiler.nodes.LogicConstantNode;
6765
import jdk.graal.compiler.nodes.LogicNode;
6866
import jdk.graal.compiler.nodes.NamedLocationIdentity;
6967
import jdk.graal.compiler.nodes.NodeView;
@@ -72,7 +70,6 @@
7270
import jdk.graal.compiler.nodes.StructuredGraph;
7371
import jdk.graal.compiler.nodes.ValueNode;
7472
import jdk.graal.compiler.nodes.ValuePhiNode;
75-
import jdk.graal.compiler.nodes.calc.CompareNode;
7673
import jdk.graal.compiler.nodes.calc.ConditionalNode;
7774
import jdk.graal.compiler.nodes.calc.IntegerMulHighNode;
7875
import jdk.graal.compiler.nodes.calc.RoundNode;
@@ -1216,6 +1213,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec
12161213
ResolvedJavaType javaType = constantReflection.asJavaType(clazz.asConstant());
12171214
if (javaType == null) {
12181215
b.push(JavaKind.Object, object);
1216+
return true;
12191217
} else {
12201218
TypeReference type;
12211219
if (isExactType.asJavaConstant().asInt() != 0) {
@@ -1227,30 +1225,14 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec
12271225

12281226
boolean trustedNonNull = nonNull.asJavaConstant().asInt() != 0 && Options.TruffleTrustedNonNullCast.getValue(b.getOptions());
12291227
Stamp piStamp = StampFactory.object(type, trustedNonNull);
1230-
1231-
ConditionAnchorNode valueAnchorNode = null;
1232-
if (condition.isConstant() && condition.asJavaConstant().asInt() == 1) {
1233-
// Nothing to do.
1234-
} else {
1235-
boolean skipAnchor = false;
1236-
LogicNode compareNode = CompareNode.createCompareNode(object.graph(), CanonicalCondition.EQ, condition, ConstantNode.forBoolean(true, object.graph()), constantReflection,
1237-
NodeView.DEFAULT);
1238-
1239-
if (compareNode instanceof LogicConstantNode) {
1240-
LogicConstantNode logicConstantNode = (LogicConstantNode) compareNode;
1241-
if (logicConstantNode.getValue()) {
1242-
skipAnchor = true;
1243-
}
1244-
}
1245-
1246-
if (!skipAnchor) {
1247-
valueAnchorNode = b.add(new ConditionAnchorNode(compareNode));
1248-
}
1228+
ValueNode guard = null;
1229+
// If the condition is the constant true then no guard is needed
1230+
if (!condition.isConstant() || condition.asJavaConstant().asInt() == 0) {
1231+
guard = b.add(ConditionAnchorNode.create(condition, constantReflection, b.getMetaAccess(), b.getOptions(), NodeView.DEFAULT));
12491232
}
1250-
1251-
b.addPush(JavaKind.Object, trustedBox(type, types, PiNode.create(object, piStamp, valueAnchorNode)));
1233+
b.addPush(JavaKind.Object, trustedBox(type, types, PiNode.create(object, piStamp, guard)));
1234+
return true;
12521235
}
1253-
return true;
12541236
} else if (canDelayIntrinsification) {
12551237
return false;
12561238
} else {
@@ -1308,9 +1290,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec
13081290
ValueNode guard = null;
13091291
// If the condition is the constant true then no guard is needed
13101292
if (!condition.isConstant() || condition.asJavaConstant().asInt() == 0) {
1311-
LogicNode compare = b.add(CompareNode.createCompareNode(b.getConstantReflection(), b.getMetaAccess(), b.getOptions(), null, CanonicalCondition.EQ, condition,
1312-
ConstantNode.forBoolean(true, object.graph()), NodeView.DEFAULT));
1313-
guard = b.add(new ConditionAnchorNode(compare));
1293+
guard = b.add(ConditionAnchorNode.create(condition, b.getConstantReflection(), b.getMetaAccess(), b.getOptions(), NodeView.DEFAULT));
13141294
}
13151295
b.addPush(returnKind, b.add(new GuardedUnsafeLoadNode(b.addNonNullCast(object), offset, returnKind, locationIdentity, guard, forceLocation)));
13161296
return true;

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/substitutions/TruffleInvocationPlugins.java

Lines changed: 44 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737

3838
import jdk.graal.compiler.core.common.Stride;
3939
import jdk.graal.compiler.core.common.StrideUtil;
40-
import jdk.graal.compiler.core.common.calc.CanonicalCondition;
4140
import jdk.graal.compiler.core.common.calc.FloatConvert;
4241
import jdk.graal.compiler.core.common.spi.ConstantFieldProvider;
4342
import jdk.graal.compiler.core.common.type.Stamp;
@@ -48,14 +47,11 @@
4847
import jdk.graal.compiler.nodes.ComputeObjectAddressNode;
4948
import jdk.graal.compiler.nodes.ConditionAnchorNode;
5049
import jdk.graal.compiler.nodes.ConstantNode;
51-
import jdk.graal.compiler.nodes.LogicConstantNode;
52-
import jdk.graal.compiler.nodes.LogicNode;
5350
import jdk.graal.compiler.nodes.NamedLocationIdentity;
5451
import jdk.graal.compiler.nodes.NodeView;
5552
import jdk.graal.compiler.nodes.PiNode;
5653
import jdk.graal.compiler.nodes.ValueNode;
5754
import jdk.graal.compiler.nodes.calc.AddNode;
58-
import jdk.graal.compiler.nodes.calc.CompareNode;
5955
import jdk.graal.compiler.nodes.calc.FloatConvertNode;
6056
import jdk.graal.compiler.nodes.calc.LeftShiftNode;
6157
import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext;
@@ -116,58 +112,55 @@ public static void register(Architecture architecture, InvocationPlugins plugins
116112
private static void registerFramePlugins(InvocationPlugins plugins) {
117113
plugins.registerIntrinsificationPredicate(t -> t.getName().equals("Lcom/oracle/truffle/api/impl/FrameWithoutBoxing;"));
118114
InvocationPlugins.Registration r = new InvocationPlugins.Registration(plugins, "com.oracle.truffle.api.impl.FrameWithoutBoxing");
119-
r.register(new OptionalInlineOnlyInvocationPlugin("unsafeCast", Object.class, Class.class, boolean.class, boolean.class, boolean.class) {
120-
@Override
121-
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object, ValueNode clazz, ValueNode condition, ValueNode nonNull,
122-
ValueNode isExactType) {
123-
if (!clazz.isConstant() || !nonNull.isConstant() || !isExactType.isConstant()) {
124-
b.push(JavaKind.Object, object);
125-
return true;
126-
}
127-
if (!Options.TruffleTrustedTypeCast.getValue(b.getOptions())) {
128-
b.push(JavaKind.Object, object);
129-
return true;
130-
}
131-
ConstantReflectionProvider constantReflection = b.getConstantReflection();
132-
ResolvedJavaType javaType = constantReflection.asJavaType(clazz.asConstant());
133-
if (javaType == null) {
134-
b.push(JavaKind.Object, object);
135-
return true;
136-
}
137-
138-
TypeReference type;
139-
if (isExactType.asJavaConstant().asInt() != 0) {
140-
assert javaType.isConcrete() || javaType.isArray() : "exact type is not a concrete class: " + javaType;
141-
type = TypeReference.createExactTrusted(javaType);
142-
} else {
143-
type = TypeReference.createTrusted(b.getAssumptions(), javaType);
144-
}
115+
r.register(new UnsafeCastPlugin("unsafeCast", true));
116+
}
145117

146-
boolean trustedNonNull = nonNull.asJavaConstant().asInt() != 0 && Options.TruffleTrustedNonNullCast.getValue(b.getOptions());
147-
Stamp piStamp = StampFactory.object(type, trustedNonNull);
118+
private static final class UnsafeCastPlugin extends OptionalInlineOnlyInvocationPlugin {
119+
private final boolean injectTrustedFinal;
148120

149-
ConditionAnchorNode valueAnchorNode = null;
150-
if (condition.isConstant() && condition.asJavaConstant().asInt() == 1) {
151-
// Nothing to do.
152-
} else {
153-
boolean skipAnchor = false;
154-
LogicNode compareNode = CompareNode.createCompareNode(object.graph(), CanonicalCondition.EQ, condition, ConstantNode.forBoolean(true, object.graph()), constantReflection,
155-
NodeView.DEFAULT);
156-
if (compareNode instanceof LogicConstantNode) {
157-
LogicConstantNode logicConstantNode = (LogicConstantNode) compareNode;
158-
if (logicConstantNode.getValue()) {
159-
skipAnchor = true;
160-
}
161-
}
162-
if (!skipAnchor) {
163-
valueAnchorNode = b.add(new ConditionAnchorNode(compareNode));
164-
}
165-
}
121+
UnsafeCastPlugin(String name, boolean injectTrustedFinal) {
122+
super(name, Object.class, Class.class, boolean.class, boolean.class, boolean.class);
123+
this.injectTrustedFinal = injectTrustedFinal;
124+
}
166125

167-
b.addPush(JavaKind.Object, PiNode.create(castTrustedFinalFrameField(b, object), piStamp, valueAnchorNode));
126+
@Override
127+
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object, ValueNode clazz, ValueNode condition, ValueNode nonNull,
128+
ValueNode isExactType) {
129+
if (!clazz.isConstant() || !nonNull.isConstant() || !isExactType.isConstant()) {
130+
b.push(JavaKind.Object, object);
168131
return true;
169132
}
170-
});
133+
if (!Options.TruffleTrustedTypeCast.getValue(b.getOptions())) {
134+
b.push(JavaKind.Object, object);
135+
return true;
136+
}
137+
ConstantReflectionProvider constantReflection = b.getConstantReflection();
138+
ResolvedJavaType javaType = constantReflection.asJavaType(clazz.asConstant());
139+
if (javaType == null) {
140+
b.push(JavaKind.Object, object);
141+
return true;
142+
}
143+
144+
TypeReference type;
145+
if (isExactType.asJavaConstant().asInt() != 0) {
146+
assert javaType.isConcrete() || javaType.isArray() : "exact type is not a concrete class: " + javaType;
147+
type = TypeReference.createExactTrusted(javaType);
148+
} else {
149+
type = TypeReference.createTrusted(b.getAssumptions(), javaType);
150+
}
151+
152+
boolean trustedNonNull = nonNull.asJavaConstant().asInt() != 0 && Options.TruffleTrustedNonNullCast.getValue(b.getOptions());
153+
Stamp piStamp = StampFactory.object(type, trustedNonNull);
154+
155+
ValueNode guard = null;
156+
// If the condition is the constant true then no guard is needed
157+
if (!condition.isConstant() || condition.asJavaConstant().asInt() == 0) {
158+
guard = b.add(ConditionAnchorNode.create(condition, b.getConstantReflection(), b.getMetaAccess(), b.getOptions(), NodeView.DEFAULT));
159+
}
160+
ValueNode trustedObject = injectTrustedFinal ? castTrustedFinalFrameField(b, object) : object;
161+
b.addPush(JavaKind.Object, PiNode.create(trustedObject, piStamp, guard));
162+
return true;
163+
}
171164
}
172165

173166
/**

0 commit comments

Comments
 (0)