- 適用於 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 語言安全點教學課程
- 單態化
- 分割演算法
- 單態化使用案例
- 向執行階段回報多型特殊化
Truffle AOT 概述
Truffle 中支援幾種不同的 AOT 預先初始化、編譯和快取方式。本文檔旨在概述這些功能。
請注意,這裡提到的一些功能僅在 Oracle GraalVM 中支援。
第一個內容的預先初始化 #
原生映像檔允許在映像檔建置時,在靜態初始化程式中執行 Java 程式碼。執行靜態初始化之後,會將從靜態欄位參照的值快照並持續保存在映像檔中。內容預先初始化利用此功能,在映像檔建置時建立和初始化語言內容,以供在執行階段的隔離區或程序中建立的第一個內容使用。這通常會顯著縮短第一個內容的初始化時間。
可以透過在映像檔建置時設定系統屬性 -Dpolyglot.image-build-time.PreinitializeContexts=ruby,llvm
來啟用內容預先初始化。語言需要實作 TruffleLanguage.patchContext 並傳回 true 以支援內容預先初始化。此外,語言需要謹慎,不要繫結任何主機特定的資料,或建立不允許儲存在原生映像檔中的物件,例如 java.lang.Thread 執行個體。
如需更多資訊,請參閱 TruffleLanguage.patchContext javadoc。
在同一個隔離區/程序內共用程式碼 #
可以使用 Polyglot 引擎來決定內容之間程式碼共用的範圍。可以在參考手冊中找到如何執行此操作的範例。當為 Polyglot 內容初始化語言時,會從引擎要求新的語言執行個體。如果語言支援 ContextPolicy.SHARED,則語言執行個體會重複用於引擎執行個體。來源剖析快取與語言執行個體相關聯,因此每個語言執行個體會進行一次剖析。語言可以透過實作 TruffleLanguage.areOptionsCompatible,選擇不允許將語言執行個體重複用於新的額外內容。這讓語言可以假設特定內容選項對於語言建立的所有根節點都是編譯的最終選項。此規則的例外是 InteropLibrary
,其中的節點可以在語言執行個體之間無條件共用。
支援獨立於內容的程式碼 #
程式碼共用需要所有程式碼資料結構都獨立於其內容。例如,如果程式碼可以在一個內容中執行,然後在新的內容中再次執行而不會最佳化程式碼,則程式碼是獨立於內容的。驗證語言實作內容獨立性的良好測試方法是建立具有明確引擎的內容、執行測試應用程式,然後驗證當執行相同的確定性應用程式時,第二個內容不會導致最佳化。
Truffle 框架透過呼叫 TruffleLanguage.initializeMultipleContexts,通常甚至在建立第一個內容之前,宣告在多個內容中使用語言執行個體的可能性。當使用明確引擎或將 --engine.CacheStore
設定為 true
時,框架可以在建立第一個內容之前初始化多個內容。
支援獨立於內容的程式碼時,應滿足下列準則
- 必須停用對執行階段值身分的所有猜測,且已初始化多個內容,因為當與第二個內容搭配使用時,它們將導致保證最佳化。
- 函式內嵌快取應修改並實作為雙層內嵌快取。第一層猜測函式執行個體的身分,第二層猜測底層 CallTarget 執行個體。如果初始化多個內容,則必須停用第一層快取,因為這會不必要地導致最佳化。
- DynamicObject 根 Shape 執行個體應儲存在語言執行個體中,而不是語言內容中。否則,任何在形狀上的內嵌快取都不會穩定,最終會進入泛型狀態。
- 所有 Node 實作都不得儲存相依於內容的資料結構或相依於內容的執行階段值。
- 來源的載入和剖析 (即使使用語言內部內建功能) 都應使用 TruffleLanguage.Env.parse 來針對每個語言執行個體快取來源剖析。
- 所有假設執行個體都應儲存在語言執行個體中,而不是內容中。初始化多個內容時,使用內容參照讀取的內容執行個體可能不再是常數。在這種情況下,從內容讀取的任何假設都不會折疊,並且它們會造成顯著的執行階段效能負擔。在單一和多個內容模式下,編譯器都可以折疊語言的假設。
預期為多個內容建立的 AST 會編譯為效率較低的機器碼,因為它不允許猜測執行階段值的身分。例如,不必猜測內嵌快取中的函式執行個體,而是需要猜測包含的 CallTarget。這會比較慢,因為它需要額外讀取以存取儲存在函式中的 CallTarget。建立獨立於內容的程式碼可能很昂貴,因此,如果未初始化多個內容,仍應執行對執行階段值的猜測。
SimpleLanguage 和 JavaScript 是兩個已經支援獨立於內容的程式碼的語言,可能有助於針對具體問題提供指南。
具有輔助引擎快取的持續獨立於內容的程式碼 (Oracle GraalVM) #
Oracle GraalVM 支援將程式碼資料結構持續保存到磁碟。這使得幾乎可以消除隔離區/程序中第一次執行應用程式的暖機時間。SVM 輔助映像檔功能用於將必要的資料結構持續保存和載入到磁碟。持續保存映像檔可能需要大量的時間,因為需要執行編譯。但是,載入的設計目標是盡可能快,通常幾乎是瞬間完成。
即使在沒有明確引擎的情況下建立內容,也可以使用選項啟用引擎快取並使其運作。
有關引擎快取的更多資訊,請參閱引擎快取教學課程。
無分析的編譯 #
依預設,如果建立語言函式但從未執行,則在將它們儲存在輔助引擎快取映像檔時,不會編譯它們。輔助引擎快取支援觸發載入但從未執行的根節點的編譯。在這種情況下,框架會呼叫 RootNode.prepareForAOT 方法。
有關如何準備語言實作以進行編譯而無需事先執行的更多資訊,請參閱 AOT 教學課程。請注意,並非每個語言都可以無需事先執行就進行編譯並產生有效率的機器碼。靜態類型語言通常更適合此用途。
應用程式快照 #
計畫也支援將 Polyglot 內容執行個體的執行階段值持續保存到磁碟。一旦實作此功能,將會在這裡顯示更多資訊。