truffle/docs/DynamicObjectLibraryMigration.md
DynamicObjectLibrary has been deprecated in 25.1, and replaced with new, lighter-weight node-based APIs, found as subclasses of DynamicObject.
Each DynamicObjectLibrary message has an equivalent node replacement.
DynamicObjectLibrary message | DynamicObject node equivalent | Purpose |
|---|---|---|
getOrDefault(obj, key, def) | DynamicObject.GetNode.execute(obj, key, def) | Gets the value of a property or a default value if absent |
getIntOrDefault(obj, key, def) | DynamicObject.GetNode.executeInt(obj, key, def) | Gets the value of a property as int or throws UnexpectedResultException |
getLongOrDefault(obj, key, def) | DynamicObject.GetNode.executeLong(obj, key, def) | Gets the value of a property as long or throws UnexpectedResultException |
getDoubleOrDefault(obj, key, def) | DynamicObject.GetNode.executeDouble(obj, key, def) | Gets the value of a property as double or throws UnexpectedResultException |
put(obj, key, val) | DynamicObject.PutNode.execute(obj, key, val) | Adds a new property of sets the value of an existing property |
putWithFlags(obj, key, val, flags) | DynamicObject.PutNode.executeWithFlags(obj, key, val, flags) | Adds a new property or sets the value and flags of an existing property |
putIfPresent(obj, key, val) | DynamicObject.PutNode.executeIfPresent(obj, key, val) | Sets the value of a property, if present |
putConstant(obj, key, val, flags) | DynamicObject.PutConstantNode.executeWithFlags(obj, key, val, flags) | Adds or replaces a property with a constant shape-bound value, use sparingly |
containsKey(obj, key) | DynamicObject.ContainsKeyNode.execute(obj, key) | Checks for the existence of a property |
removeKey(obj, key) | DynamicObject.RemoveKeyNode.execute(obj, key) | Removes a property |
getPropertyFlagsOrDefault(obj, key, def) | DynamicObject.GetPropertyFlagsNode.execute(obj, key, def) | Gets the flags of a property or a default value if absent |
setPropertyFlags(obj, key, flags) | DynamicObject.SetPropertyFlagsNode.execute(obj, key, flags) | Updates the flags or a property |
getKeyArray(obj) | DynamicObject.GetKeyArrayNode.execute(obj) | Returns an array of the keys of all the non-hidden properties |
getProperty(obj, key) | DynamicObject.GetPropertyNode.execute(obj, key) | Gets the property descriptor or null if absent |
getPropertyArray(obj) | DynamicObject.GetPropertyArrayNode.execute(obj) | Returns an array of the property descriptors of all the non-hidden properties |
getShapeFlags(obj) | DynamicObject.GetShapeFlagsNode.execute(obj) | Gets the language-specific shape flags |
setShapeFlags(obj, flags) | DynamicObject.SetShapeFlagsNode.execute(obj, flags) | Sets the language-specific shape flags |
getDynamicType(obj) | DynamicObject.GetDynamicTypeNode.execute(obj) | Gets the language-specific dynamic type identifier |
setDynamicType(obj, type) | DynamicObject.SetDynamicTypeNode.execute(obj, type) | Sets the language-specific dynamic type identifier |
updateShape(obj) | DynamicObject.UpdateShapeNode.execute(obj) | Updates the shape if the object has an obsolete shape |
resetShape(obj, rootShape) | DynamicObject.ResetShapeNode.execute(obj, rootShape) | Resets the object to an empty shape |
markShared(obj) | DynamicObject.MarkSharedNode.execute(obj) | Marks the object as shared |
isShared(obj) | DynamicObject.IsSharedNode.execute(obj) | Queries the object's shared state |
getShape(obj) | obj.getShape() | No node equivalent, use direct API |
Note: Unlike DynamicObjectLibrary, cached property keys are always compared by identity (==) rather than equality (equals).
If you rely on key equality, cache the key using an equals guard and pass the cached canonical key to the node.
abstract class GetUniqueKeyNode extends Node {
abstract Object execute(DynamicObject receiver, Object key);
@Specialization
static Object doCached(MyDynamicObject receiver, Symbol key,
@Cached DynamicObject.GetNode getNode) {
return getNode.execute(receiver, key, NULL_VALUE);
}
}
@ImportStatic(TruffleString.Encoding.class)
abstract class GetStringKeyNode extends Node {
abstract Object execute(DynamicObject receiver, Object key);
@Specialization(guards = "equalNode.execute(key, cachedKey, UTF_16)", limit = "3")
static Object doCached(MyDynamicObject receiver, TruffleString key,
@Cached("key") TruffleString cachedKey,
@Cached TruffleString.EqualNode equalNode,
@Shared @Cached DynamicObject.GetNode getNode) {
return getNode.execute(receiver, cachedKey, NULL_VALUE);
}
@Specialization(replaces = "doCached")
static Object doGeneric(MyDynamicObject receiver, TruffleString key,
@Shared @Cached DynamicObject.GetNode getNode) {
return getNode.execute(receiver, key, NULL_VALUE);
}
}
Note that key interning is not required since only the cached code path compares keys by identity (==), the generic code path still uses equals to compare the property keys.
abstract class GetUnboxedNode extends Node {
abstract int executeInt(DynamicObject receiver, Object key) throws UnexpectedResultException;
abstract Object execute(DynamicObject receiver, Object key);
@Specialization(rewriteOn = UnexpectedResultException.class)
static int doInt(MyDynamicObject receiver, Symbol key,
@Shared @Cached DynamicObject.GetNode getNode) throws UnexpectedResultException {
return getNode.executeInt(receiver, key, NULL_VALUE);
}
@Specialization(replaces = "doInt")
static Object doGeneric(MyDynamicObject receiver, Symbol key,
@Shared @Cached DynamicObject.GetNode getNode) {
return getNode.execute(receiver, key, NULL_VALUE);
}
}
abstract class SetUniqueKeyNode extends Node {
abstract void execute(DynamicObject receiver, Object key, Object value);
@Specialization
static void doCached(MyDynamicObject receiver, Symbol key, Object value,
@Cached DynamicObject.PutNode putNode) {
putNode.execute(receiver, key, value);
}
}
@ImportStatic(TruffleString.Encoding.class)
abstract class SetStringKeyNode extends Node {
abstract void execute(DynamicObject receiver, Object key, Object value);
@Specialization(guards = "equalNode.execute(key, cachedKey, UTF_16)", limit = "3")
static void doCached(MyDynamicObject receiver, TruffleString key, Object value,
@Cached("key") TruffleString cachedKey,
@Cached TruffleString.EqualNode equalNode,
@Cached DynamicObject.PutNode putNode) {
putNode.execute(receiver, cachedKey, value);
}
@Specialization(replaces = "doCached")
static void doGeneric(MyDynamicObject receiver, TruffleString key,
@Shared @Cached DynamicObject.PutNode getNode) {
putNode.execute(receiver, key, value);
}
}
Note that key interning is not required since only the cached code path compares keys by identity (==), the generic code path still uses equals to compare the property keys.