Skip to content

Commit da130d2

Browse files
eregonwoess
authored andcommitted
[GR-36894] Add DynamicObject nodes.
PullRequest: graal/21195
2 parents e9feeeb + 4a0cc18 commit da130d2

File tree

60 files changed

+6128
-1449
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+6128
-1449
lines changed

compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/DynamicObjectPartialEvaluationTest.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2022, 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
@@ -36,7 +36,6 @@
3636
import com.oracle.truffle.api.nodes.RootNode;
3737
import com.oracle.truffle.api.nodes.UnexpectedResultException;
3838
import com.oracle.truffle.api.object.DynamicObject;
39-
import com.oracle.truffle.api.object.DynamicObjectLibrary;
4039
import com.oracle.truffle.api.object.Shape;
4140
import com.oracle.truffle.runtime.OptimizedCallTarget;
4241

@@ -79,7 +78,7 @@ private TestDynamicObject newInstanceWithoutFields() {
7978
@Test
8079
public void testFieldLocation() {
8180
TestDynamicObject obj = newInstanceWithFields();
82-
DynamicObjectLibrary.getUncached().put(obj, "key", 22);
81+
DynamicObject.PutNode.getUncached().execute(obj, "key", 22);
8382

8483
Object[] args = {obj, 22};
8584
OptimizedCallTarget callTarget = makeCallTarget(new TestDynamicObjectGetAndPutNode(), "testFieldStoreLoad");
@@ -107,7 +106,7 @@ public void testFieldLocation() {
107106
@Test
108107
public void testArrayLocation() {
109108
TestDynamicObject obj = newInstanceWithoutFields();
110-
DynamicObjectLibrary.getUncached().put(obj, "key", 22);
109+
DynamicObject.PutNode.getUncached().execute(obj, "key", 22);
111110

112111
Object[] args = {obj, 22};
113112
OptimizedCallTarget callTarget = makeCallTarget(new TestDynamicObjectGetAndPutNode(), "testArrayStoreLoad");
@@ -137,7 +136,8 @@ private static OptimizedCallTarget makeCallTarget(AbstractTestNode testNode, Str
137136
}
138137

139138
static class TestDynamicObjectGetAndPutNode extends AbstractTestNode {
140-
@Child DynamicObjectLibrary dynamicObjectLibrary = DynamicObjectLibrary.getFactory().createDispatched(3);
139+
@Child DynamicObject.GetNode getNode = DynamicObject.GetNode.create();
140+
@Child DynamicObject.PutNode putNode = DynamicObject.PutNode.create();
141141

142142
@Override
143143
public int execute(VirtualFrame frame) {
@@ -148,22 +148,22 @@ public int execute(VirtualFrame frame) {
148148
DynamicObject obj = (DynamicObject) arg0;
149149
if (frame.getArguments().length > 1) {
150150
Object arg1 = frame.getArguments()[1];
151-
dynamicObjectLibrary.put(obj, "key", (int) arg1);
151+
putNode.execute(obj, "key", (int) arg1);
152152
}
153153
int val;
154154
while (true) {
155155
val = getInt(obj, "key");
156156
if (val >= 42) {
157157
break;
158158
}
159-
dynamicObjectLibrary.put(obj, "key", val + 2);
159+
putNode.execute(obj, "key", val + 2);
160160
}
161161
return val;
162162
}
163163

164164
private int getInt(DynamicObject obj, Object key) {
165165
try {
166-
return dynamicObjectLibrary.getIntOrDefault(obj, key, null);
166+
return getNode.executeInt(obj, key, null);
167167
} catch (UnexpectedResultException e) {
168168
throw CompilerDirectives.shouldNotReachHere();
169169
}

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

Lines changed: 54 additions & 10 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,35 +29,81 @@
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

4763
public static final NodeClass<ConditionAnchorNode> TYPE = NodeClass.create(ConditionAnchorNode.class);
4864
@Input(Condition) LogicNode condition;
4965
protected boolean negated;
5066

51-
public ConditionAnchorNode(LogicNode condition) {
52-
this(condition, false);
53-
}
54-
5567
public ConditionAnchorNode(LogicNode condition, boolean negated) {
5668
super(TYPE, StampFactory.forVoid());
5769
this.negated = negated;
5870
this.condition = condition;
5971
}
6072

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

78124
@Override
79125
public Node canonical(CanonicalizerTool tool, Node forValue) {
80-
if (forValue instanceof LogicNegationNode) {
81-
LogicNegationNode negation = (LogicNegationNode) forValue;
126+
if (forValue instanceof LogicNegationNode negation) {
82127
return new ConditionAnchorNode(negation.getValue(), !negated);
83128
}
84-
if (forValue instanceof LogicConstantNode) {
85-
LogicConstantNode c = (LogicConstantNode) forValue;
129+
if (forValue instanceof LogicConstantNode c) {
86130
// 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.
131+
// true for control flow reasons so the Pi stamp is also only valid for those reasons.
88132
if (c.getValue() == negated || hasUsages()) {
89133
return new ValueAnchorNode();
90134
} else {

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

Lines changed: 9 additions & 29 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,41 +1213,26 @@ 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) {
1222-
assert javaType.isConcrete() || javaType.isArray() : "exact type is not a concrete class: " + javaType;
1220+
GraalError.guarantee(javaType.isConcrete(), "exact type is not a concrete class: %s", javaType);
12231221
type = TypeReference.createExactTrusted(javaType);
12241222
} else {
12251223
type = TypeReference.createTrusted(b.getAssumptions(), javaType);
12261224
}
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;

0 commit comments

Comments
 (0)