- 適用於 JDK 23 的 GraalVM (最新)
- 適用於 JDK 24 的 GraalVM (搶先體驗)
- 適用於 JDK 21 的 GraalVM
- 適用於 JDK 17 的 GraalVM
- 封存
- 開發版本
- Truffle 語言實作框架
- Truffle 分支檢測
- 動態物件模型
- 靜態物件模型
- 直譯器程式碼的主機最佳化
- Truffle 函式內聯方法
- 剖析 Truffle 直譯器
- Truffle Interop 2.0
- 語言實作
- 使用 Truffle 實作新語言
- Truffle 語言和工具遷移至 Java 模組
- Truffle 原生函式介面
- 最佳化 Truffle 直譯器
- 選項
- 堆疊上替換
- Truffle 字串指南
- 特化直方圖
- 測試 DSL 特化
- 基於 Polyglot 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);
}
// ...
}
為了建構這些物件的執行個體,您首先需要一個 Shape
,您可以將其傳遞至 DynamicObject
建構函式。此形狀是使用 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);
}
//...
}
擴充物件配置 #
您可以使用額外的動態欄位來擴充預設的物件配置,方法是在子類別中加入類型為 Object
或 long
的 @DynamicField
註釋欄位宣告,並使用 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;
}
}
延伸閱讀 #
物件模型的高階描述已在 適用於 Truffle 語言實作框架的物件儲存模型 中發佈。
如需關於 Truffle 和 GraalVM 的更多簡報和出版物,請參閱 Truffle 出版物。