- 适用于 JDK 24 的 GraalVM(最新)
- 适用于 JDK 25 的 GraalVM(早期访问)
- 适用于 JDK 21 的 GraalVM
- 适用于 JDK 17 的 GraalVM
- 存档
- 开发构建
- Truffle 语言实现框架
- Truffle 分支插桩
- 动态对象模型
- 静态对象模型
- 解释器代码的主机优化
- Truffle 函数内联方法
- 分析 Truffle 解释器
- Truffle 互操作 2.0
- 语言实现
- 使用 Truffle 实现新语言
- Truffle 语言和工具迁移到 Java 模块
- Truffle 原生函数接口
- 优化 Truffle 解释器
- 选项
- 栈上替换
- Truffle 字符串指南
- 特化直方图
- 测试 DSL 特化
- 基于多语言 API 的 TCK
- Truffle 编译队列方法
- Truffle 库指南
- Truffle AOT 概述
- Truffle AOT 编译
- 辅助引擎缓存
- Truffle 语言安全点教程
- 单态化
- 拆分算法
- 单态化用例
- 向运行时报告多态特化
动态对象模型
本指南演示了如何开始使用 GraalVM 20.2.0 中引入的 DynamicObject 和 DynamicObjectLibrary API。完整文档可在 Javadoc 中找到。
动机 #
在实现动态语言时,用户定义的对象/类的对象布局通常无法静态推断,并且需要适应动态添加的成员和变化的类型。这就是动态对象 API 的作用:它负责对象布局,并根据对象的形状(即它们的属性及其值的类型)对对象进行分类。访问节点可以缓存遇到的形状,避免昂贵的检查,并更高效地访问对象属性。
入门 #
客户端语言应为所有语言对象提供一个通用的基类,该基类扩展 DynamicObject
并实现 TruffleObject
。例如
@ExportLibrary(InteropLibrary.class)
public class BasicObject extends DynamicObject implements TruffleObject {
public BasicObject(Shape shape) {
super(shape);
}
@ExportMessage
boolean hasLanguage() {
return true;
}
// ...
}
在此类中导出常见的 InteropLibrary
消息也是有意义的。
内置对象类可以扩展此基类并导出额外的消息,并且像往常一样,提供额外的 Java 字段和方法
@ExportLibrary(InteropLibrary.class)
public class Array extends BasicObject {
private final Object[] elements;
public Array(Shape shape, Object[] elements) {
super(shape);
this.elements = elements;
}
@ExportMessage
boolean hasArrayElements() {
return true;
}
@ExportMessage
long getArraySize() {
return elements.length;
}
// ...
}
动态对象成员可以使用 DynamicObjectLibrary
访问,该库可以通过 Truffle DSL 的 @CachedLibrary
注解以及 DynamicObjectLibrary.getFactory()
+ getUncached()
、create(DynamicObject)
和 createDispatched(int)
获取。以下是如何使用它来实现 InteropLibrary
消息的示例
@ExportLibrary(InteropLibrary.class)
public class SimpleObject extends BasicObject {
public UserObject(Shape shape) {
super(shape);
}
@ExportMessage
boolean hasMembers() {
return true;
}
@ExportMessage
Object readMember(String name,
@CachedLibrary("this") DynamicObjectLibrary objectLibrary)
throws UnknownIdentifierException {
Object result = objectLibrary.getOrDefault(this, name, null);
if (result == null) {
/* Property does not exist. */
throw UnknownIdentifierException.create(name);
}
return result;
}
@ExportMessage
void writeMember(String name, Object value,
@CachedLibrary("this") DynamicObjectLibrary objectLibrary) {
objectLibrary.put(this, name, value);
}
@ExportMessage
boolean isMemberReadable(String member,
@CachedLibrary("this") DynamicObjectLibrary objectLibrary) {
return objectLibrary.containsKey(this, member);
}
// ...
}
为了构造这些对象的实例,您首先需要一个可以传递给 DynamicObject
构造函数的 Shape
。此形状是使用 Shape.newBuilder().build()
创建的。返回的形状描述了对象的初始形状,并构成了一个新形状树的根。当您使用 DynamicObjectLibrary#put
添加新属性时,对象将在此形状树中变异成其他形状。
注意:您应该重用相同的初始形状,因为形状在内部是按根形状缓存的。建议您将初始形状存储在 TruffleLanguage
实例中,以便它们可以在同一引擎的不同上下文中共享。除了单例(如 null
值)之外,应避免使用静态形状。
例如
@TruffleLanguage.Registration(...)
public final class MyLanguage extends TruffleLanguage<MyContext> {
private final Shape initialObjectShape;
private final Shape initialArrayShape;
public MyLanguage() {
this.initialObjectShape = Shape.newBuilder().layout(ExtendedObject.class).build();
this.initialArrayShape = Shape.newBuilder().build();
}
public createObject() {
return new MyObject(initialObjectShape);
}
//...
}
扩展对象布局 #
您可以通过在子类中添加 @DynamicField
注解的 Object
或 long
类型的字段声明,并使用 Shape.newBuilder().layout(ExtendedObject.class).build();
指定*布局类*,来用额外的*动态字段*扩展默认对象布局。在此类及其超类中声明的动态字段将自动用于存储动态对象属性,并允许更快地访问适合此保留空间的属性。注意:您不能直接访问动态字段。始终为此目的使用 DynamicObjectLibrary
。
@ExportLibrary(InteropLibrary.class)
public class ExtendedObject extends SimpleObject {
@DynamicField private Object _obj0;
@DynamicField private Object _obj1;
@DynamicField private Object _obj2;
@DynamicField private long _long0;
@DynamicField private long _long1;
@DynamicField private long _long2;
public ExtendedObject(Shape shape) {
super(shape);
}
}
缓存注意事项 #
为了确保最佳缓存,请避免对多个独立的(get
、put
等)操作重用相同的缓存 DynamicObjectLibrary
。尽量减少每个缓存库实例看到的形状和属性键的数量。当属性键是静态已知(编译最终)时,始终为每个属性键使用单独的 DynamicObjectLibrary
。在连续放置多个属性时,使用分发库(@CachedLibrary(limit=...)
)。例如
public abstract class MakePairNode extends BinaryExpressionNode {
@Specialization
Object makePair(Object left, Object right,
@CachedLanguage MyLanguage language,
@CachedLibrary(limit = "3") DynamicObjectLibrary putLeft,
@CachedLibrary(limit = "3") DynamicObjectLibrary putRight) {
MyObject obj = language.createObject();
putLeft.put(obj, "left", left);
putRight.put(obj, "right", right);
return obj;
}
}
延伸阅读 #
对象模型的高层描述已在 An Object Storage Model for the Truffle Language Implementation Framework 中发布。
有关 Truffle 和 GraalVM 的更多演示文稿和出版物,请参阅 Truffle 出版物。