Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
3cf315a
[GR-36894] Add nodes for DynamicObject
eregon Sep 18, 2025
e04f4cf
Wrap DynamicObjectLibrary for tests and fix constructor visibility.
woess Oct 3, 2025
43dc25d
Add DynamicObject benchmarks for primitive get and set and field access.
woess Oct 13, 2025
1411b25
No need to enter a context for DynamicObject benchmarking.
woess Oct 31, 2025
1be1c9d
Rename getOrDefault and put to execute and add InliningRoot annotation.
woess Nov 4, 2025
381db41
Add tests for PutNode.executeIfAbsent and executeWithFlagsIfPresent.
woess Nov 6, 2025
951e20b
Use one PutNode per property in CopyPropertiesNode.
woess Nov 6, 2025
9d3eda2
Remove unsafeCast without exact parameter.
woess Oct 16, 2025
23a2cf8
Initialize extension arrays with empty array constant instead of null.
woess Oct 8, 2025
81510bc
Refactor Location classes.
woess Oct 15, 2025
423cb7b
Use final Location get and set.
woess Oct 28, 2025
96f0088
Revise PutNode implementation.
woess Nov 6, 2025
0580d07
Remove HasShapeFlagsNode.
woess Nov 4, 2025
882c06a
Remove AddShapeFlagsNode.
woess Nov 4, 2025
1f4c94d
Throw UnexpectedResultException for boxed values, too.
woess Nov 7, 2025
cbd0289
Improve DynamicObject javadoc.
woess Nov 10, 2025
03eb308
Add system property for shape/key cache limit.
woess Nov 10, 2025
b74426a
Simplify putGeneric and use setInternal.
woess Nov 10, 2025
b073c7c
Unify condition anchor handling.
woess Nov 7, 2025
0657b78
Add UnsafeAccess.hostUnsafeCast and mark extension arrays as non-null.
woess Oct 17, 2025
c272ced
Make store fence unconditional in the interpreter to avoid shared sha…
woess Nov 6, 2025
1c904c3
Fix Truffle DSL not honoring `@SuppressWarnings("deprecation")`.
woess Nov 10, 2025
3e4d25e
Deprecate DynamicObjectLibrary.
woess Nov 10, 2025
dcdc467
Hoist index read.
woess Nov 11, 2025
996dfef
Omit receiver type check and hoist field read.
woess Nov 10, 2025
4069eb4
Add Shape.getFirstProperty().
woess Nov 14, 2025
6664fc1
Update truffle sigtest snapshot.
woess Oct 3, 2025
8810b72
Add DynamicObject API migration guide.
woess Nov 13, 2025
8dd76f0
Update truffle changelog.
woess Nov 13, 2025
4a0cc18
Remove unused SomSupport.
woess Oct 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -36,7 +36,6 @@
import com.oracle.truffle.api.nodes.RootNode;
import com.oracle.truffle.api.nodes.UnexpectedResultException;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.object.DynamicObjectLibrary;
import com.oracle.truffle.api.object.Shape;
import com.oracle.truffle.runtime.OptimizedCallTarget;

Expand Down Expand Up @@ -79,7 +78,7 @@ private TestDynamicObject newInstanceWithoutFields() {
@Test
public void testFieldLocation() {
TestDynamicObject obj = newInstanceWithFields();
DynamicObjectLibrary.getUncached().put(obj, "key", 22);
DynamicObject.PutNode.getUncached().execute(obj, "key", 22);

Object[] args = {obj, 22};
OptimizedCallTarget callTarget = makeCallTarget(new TestDynamicObjectGetAndPutNode(), "testFieldStoreLoad");
Expand Down Expand Up @@ -107,7 +106,7 @@ public void testFieldLocation() {
@Test
public void testArrayLocation() {
TestDynamicObject obj = newInstanceWithoutFields();
DynamicObjectLibrary.getUncached().put(obj, "key", 22);
DynamicObject.PutNode.getUncached().execute(obj, "key", 22);

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

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

@Override
public int execute(VirtualFrame frame) {
Expand All @@ -148,22 +148,22 @@ public int execute(VirtualFrame frame) {
DynamicObject obj = (DynamicObject) arg0;
if (frame.getArguments().length > 1) {
Object arg1 = frame.getArguments()[1];
dynamicObjectLibrary.put(obj, "key", (int) arg1);
putNode.execute(obj, "key", (int) arg1);
}
int val;
while (true) {
val = getInt(obj, "key");
if (val >= 42) {
break;
}
dynamicObjectLibrary.put(obj, "key", val + 2);
putNode.execute(obj, "key", val + 2);
}
return val;
}

private int getInt(DynamicObject obj, Object key) {
try {
return dynamicObjectLibrary.getIntOrDefault(obj, key, null);
return getNode.executeInt(obj, key, null);
} catch (UnexpectedResultException e) {
throw CompilerDirectives.shouldNotReachHere();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -29,35 +29,81 @@
import static jdk.graal.compiler.nodeinfo.NodeCycles.CYCLES_0;
import static jdk.graal.compiler.nodeinfo.NodeSize.SIZE_0;

import jdk.graal.compiler.core.common.calc.CanonicalCondition;
import jdk.graal.compiler.core.common.type.StampFactory;
import jdk.graal.compiler.graph.Node;
import jdk.graal.compiler.graph.NodeClass;
import jdk.graal.compiler.nodeinfo.NodeInfo;
import jdk.graal.compiler.nodeinfo.Verbosity;
import jdk.graal.compiler.nodes.calc.CompareNode;
import jdk.graal.compiler.nodes.extended.GuardingNode;
import jdk.graal.compiler.nodes.extended.ValueAnchorNode;
import jdk.graal.compiler.nodes.spi.Canonicalizable;
import jdk.graal.compiler.nodes.spi.CanonicalizerTool;
import jdk.graal.compiler.nodes.spi.Lowerable;
import jdk.graal.compiler.nodes.spi.LoweringTool;
import jdk.graal.compiler.options.OptionValues;
import jdk.vm.ci.meta.ConstantReflectionProvider;
import jdk.vm.ci.meta.MetaAccessProvider;

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

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

public ConditionAnchorNode(LogicNode condition) {
this(condition, false);
}

public ConditionAnchorNode(LogicNode condition, boolean negated) {
super(TYPE, StampFactory.forVoid());
this.negated = negated;
this.condition = condition;
}

/**
* Creates a condition anchor from a boolean value representing the guarding condition.
*
* Note: The caller must handle the case where no anchor is needed for constant true.
*
* @param booleanValue the condition as a boolean value
*/
public static FixedWithNextNode create(ValueNode booleanValue, ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, NodeView view) {
if (booleanValue.isConstant()) {
return new ValueAnchorNode();
} else {
return create(CompareNode.createCompareNode(constantReflection, metaAccess, options, null, CanonicalCondition.EQ, booleanValue, ConstantNode.forBoolean(true), view));
}
}

/**
* Creates a condition anchor from a logical comparison representing the guarding condition.
*
* @param condition the condition
* @see #canonical(CanonicalizerTool, Node)
*/
public static FixedWithNextNode create(LogicNode condition) {
if (condition instanceof LogicConstantNode) {
/*
* Even if the condition is true, an anchor that has usages must still exist since it's
* possible the condition is true for control flow reasons so the Pi stamp is also only
* valid for those reasons.
*/
return new ValueAnchorNode();
} else {
return new ConditionAnchorNode(condition, false);
}
}

public LogicNode condition() {
return condition;
}
Expand All @@ -77,14 +123,12 @@ public String toString(Verbosity verbosity) {

@Override
public Node canonical(CanonicalizerTool tool, Node forValue) {
if (forValue instanceof LogicNegationNode) {
LogicNegationNode negation = (LogicNegationNode) forValue;
if (forValue instanceof LogicNegationNode negation) {
return new ConditionAnchorNode(negation.getValue(), !negated);
}
if (forValue instanceof LogicConstantNode) {
LogicConstantNode c = (LogicConstantNode) forValue;
if (forValue instanceof LogicConstantNode c) {
// An anchor that still has usages must still exist since it's possible the condition is
// true for control flow reasons so the Pi stamp is also only valid for those reason.
// true for control flow reasons so the Pi stamp is also only valid for those reasons.
if (c.getValue() == negated || hasUsages()) {
return new ValueAnchorNode();
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
import com.oracle.truffle.compiler.TruffleCompilationTask;

import jdk.graal.compiler.core.common.NumUtil;
import jdk.graal.compiler.core.common.calc.CanonicalCondition;
import jdk.graal.compiler.core.common.memory.MemoryOrderMode;
import jdk.graal.compiler.core.common.type.IntegerStamp;
import jdk.graal.compiler.core.common.type.ObjectStamp;
Expand All @@ -63,7 +62,6 @@
import jdk.graal.compiler.nodes.FixedGuardNode;
import jdk.graal.compiler.nodes.FrameState;
import jdk.graal.compiler.nodes.InvokeNode;
import jdk.graal.compiler.nodes.LogicConstantNode;
import jdk.graal.compiler.nodes.LogicNode;
import jdk.graal.compiler.nodes.NamedLocationIdentity;
import jdk.graal.compiler.nodes.NodeView;
Expand All @@ -72,7 +70,6 @@
import jdk.graal.compiler.nodes.StructuredGraph;
import jdk.graal.compiler.nodes.ValueNode;
import jdk.graal.compiler.nodes.ValuePhiNode;
import jdk.graal.compiler.nodes.calc.CompareNode;
import jdk.graal.compiler.nodes.calc.ConditionalNode;
import jdk.graal.compiler.nodes.calc.IntegerMulHighNode;
import jdk.graal.compiler.nodes.calc.RoundNode;
Expand Down Expand Up @@ -1216,41 +1213,26 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec
ResolvedJavaType javaType = constantReflection.asJavaType(clazz.asConstant());
if (javaType == null) {
b.push(JavaKind.Object, object);
return true;
} else {
TypeReference type;
if (isExactType.asJavaConstant().asInt() != 0) {
assert javaType.isConcrete() || javaType.isArray() : "exact type is not a concrete class: " + javaType;
GraalError.guarantee(javaType.isConcrete(), "exact type is not a concrete class: %s", javaType);
type = TypeReference.createExactTrusted(javaType);
} else {
type = TypeReference.createTrusted(b.getAssumptions(), javaType);
}

boolean trustedNonNull = nonNull.asJavaConstant().asInt() != 0 && Options.TruffleTrustedNonNullCast.getValue(b.getOptions());
Stamp piStamp = StampFactory.object(type, trustedNonNull);

ConditionAnchorNode valueAnchorNode = null;
if (condition.isConstant() && condition.asJavaConstant().asInt() == 1) {
// Nothing to do.
} else {
boolean skipAnchor = false;
LogicNode compareNode = CompareNode.createCompareNode(object.graph(), CanonicalCondition.EQ, condition, ConstantNode.forBoolean(true, object.graph()), constantReflection,
NodeView.DEFAULT);

if (compareNode instanceof LogicConstantNode) {
LogicConstantNode logicConstantNode = (LogicConstantNode) compareNode;
if (logicConstantNode.getValue()) {
skipAnchor = true;
}
}

if (!skipAnchor) {
valueAnchorNode = b.add(new ConditionAnchorNode(compareNode));
}
ValueNode guard = null;
// If the condition is the constant true then no guard is needed
if (!condition.isConstant() || condition.asJavaConstant().asInt() == 0) {
guard = b.add(ConditionAnchorNode.create(condition, constantReflection, b.getMetaAccess(), b.getOptions(), NodeView.DEFAULT));
}

b.addPush(JavaKind.Object, trustedBox(type, types, PiNode.create(object, piStamp, valueAnchorNode)));
b.addPush(JavaKind.Object, trustedBox(type, types, PiNode.create(object, piStamp, guard)));
return true;
}
return true;
} else if (canDelayIntrinsification) {
return false;
} else {
Expand Down Expand Up @@ -1308,9 +1290,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec
ValueNode guard = null;
// If the condition is the constant true then no guard is needed
if (!condition.isConstant() || condition.asJavaConstant().asInt() == 0) {
LogicNode compare = b.add(CompareNode.createCompareNode(b.getConstantReflection(), b.getMetaAccess(), b.getOptions(), null, CanonicalCondition.EQ, condition,
ConstantNode.forBoolean(true, object.graph()), NodeView.DEFAULT));
guard = b.add(new ConditionAnchorNode(compare));
guard = b.add(ConditionAnchorNode.create(condition, b.getConstantReflection(), b.getMetaAccess(), b.getOptions(), NodeView.DEFAULT));
}
b.addPush(returnKind, b.add(new GuardedUnsafeLoadNode(b.addNonNullCast(object), offset, returnKind, locationIdentity, guard, forceLocation)));
return true;
Expand Down
Loading