第二章 相關研究
2.3 一個 Java 虛擬機器:CVM
2.3.1 CVM 的介紹
本篇論文因為希望能夠比較兩種指令選取的機制:以BURS 的樹狀樣式比 對配合動態規劃的演算法為基礎的指令選取機制和以我們GLR parser 為基礎的 指令選取機制,因此我們需要一個在指令選取的部分就是使用BURS 演算法的 編譯器。我們選擇了一個應用在嵌入式環境,稱作CVM(CDC Virtual Machine) 的Java 虛擬機器所含有的一個即時編譯器(just-in-time compiler),此即時編譯器 在指令選取的部分就是使用BURS 演算法。
在 CVM 中,不只含有一個傳統的直譯器(interpreter),也有一個動態編譯器 (dynamic compiler),也就是即時編譯器(just-in-compiler)。當一個 Java 程式碼被 當成CVM 的輸入時,會被轉成一連串的 Java byte-codes,然後這些 bytecodes 會 被執行,執行時CVM 有一個 profile 機制去辨認出哪些 Java 程式碼相對應的 bytecodes 執行的次數是比較多的,而在超過一個門檻值時,就會認為這些程式 碼是比較常執行的,而這樣比較常被執行的程式碼就稱作「Hot method」。
並非經常被執行的程式碼都會交由直譯器來處理,而經常被執行的「Hot method」則是交由即時編譯器來處理:將相關的 bytecodes 翻譯成目標機器的原 生指令(native machine codes),如此一來就不需要每次執行那些 Hot method 時都 還要重新翻譯,也就是可以直接執行該bytecodes 編譯好的原生機器碼來取代原 本bytecodes 直譯的過程。
CVM 這樣的 Java 虛擬機器使用直譯器和即時編譯器的主要理由在於執行一 段bytecodes 編譯好的原生機器碼會比原本 bytecodes 直譯再執行的過程還要快,
但如果以bytecodes 的編譯時間及執行時間和 bytecodes 直譯再執行的過程相比,
則前者反而比較慢,因此就出現了一個取捨的問題,哪些程式碼會經常執行或者 僅執行一兩次而已。因此CVM 使用一套測量機制來去辨認出哪些程式碼執行的 次數是比較多的,也就值得花時間由即時編譯器去進行編譯,否則由直譯器在程 式碼要被執行時再來直譯就可以。
2.3.2 CVM 的即時編譯器
CVM 的即時編譯器產生原生機器碼的元件可以分成兩部分,也就是前端和 後端。前端部分的元件會將一段Java bytecodes 轉換成一種樹狀的 Intermediate Representation,而許多關於 bytecodes 的資訊,例如資料型態和數值等都隱藏在 這個Intermediate Representation(IR)中。前端元件也會處理其他的事情,像是驗 證和安全檢查的工作、針對IR 去進行多種最佳化的工作。後端部分主要是利用
由Java Code Select(JCS)這個剖析器產生器(parser generator)所產生出來的一個目 的碼產生器(code generator)去剖析由前端所產生出來的 IR。在剖析的過程中會執 行相關的函式去產生目標機器的原生指令。
後端部分還有三個重要的元件:暫存器管理者(Register Manager)、常數池管 理者(Constant Pool Manager)和堆疊管理者(Stack Manager)。暫存器管理者主要負 責的是持續追蹤在編譯過程中所有暫存器的使用情況,也使用一個資料結構來去 紀錄已評估過的計算表示式(evaluated expressions)目前是儲存在記憶體或者是暫 存器中。常數池管理者則是用來管理所產生出來的原生機器碼所參考道的32 位 元或64 位元的常數。堆疊管理者則負責管理在編譯時會被推入到 Java expression stack 中的一些方法的參數。後端部分的元件可以利用堆疊管理者和暫存器管理 者所負責的事項來去追蹤在Java 堆疊中被當作參數使用的一些數值。
Figure 2.7 即時編譯器的架構
接下來則是要分別介紹在CVM 的即時編譯器中和我們研究相關的元件,包 括IR 產生器(IR generator),Java Code Select 以及目的碼產生器。
2.3.2.1 即時編譯器的 IR
Java 虛擬機器是一個以堆疊為基礎的架構(stack-based architecture),因此 Java
bytecodes 在設計上就有堆疊的概念在裡頭。在評估一個計算表示式時會使用一
intermediate representation,而所有隱含的 Java 語意(Java semantics)都會顯現在這 樣的表示法中。這樣樹狀的表示法架構很適合用來表示將堆疊導向的bytecodes 轉換成以暫存器為基礎的底層機器架構的原生碼。這樣的IR 比起堆疊導向的 bytecodes 來說,也是更為適合去分析和操控程式碼,亦即,進行最佳化的處理 或是移除一些重複的計算過程。IR 其實是一連串的表示樹(expression tree)所組成 的,而這些表示樹如果以後序追蹤的方式來看的話,其實就容易看出所代表的
2.3.2.2 Java Code Select 和目的碼產生器
Java Code Select (JCS)是一個產生剖析器的工具,其功能類似 Yacc 或 Bison,
但不同的是 Yacc 或 Bison 所建立出來的剖析器是以字串樣式比對(pattern matching with streams)為基礎,JCS 所產生出來的剖析器則是以樹狀樣式比對為 基礎(pattern matching with tree-based data structures)。
JCS 所接受的輸入是一個稱作 JIT grammar 的指令文法(instruction
grammar),文法中的每個規則都會有一個數值成本,然後,JCS 就能依此產生一 個目的碼產生器,稱作JIT code generator。這個目的碼產生器其實就是個剖析器,
以由下往上且由左而右的樣式比對方式去針對Intermediate Representation 來進行 剖析。
由於JCS 是以 BURS(Bottom-Up Rewrite System)這樣的樹狀樣式比對演算法 為基礎,所以在產生目的碼產生器的同時,其實也產生了一個BURS 的 tree automaton(tree automaton)以供使用。而在建造 tree automaton 的時候,已經利用 成本的觀念來去決定每個情況下最佳的指令序列,因此目的碼產生器在執行時剖 析IR,只需要兩個階段就可以找出該 IR 最佳的指令序列,然後再去執行相關的
函式以產生原生機器碼。
目的碼產生器在真正產生原生機器碼之前會設定一些細節或者是限制。然 後,目的碼產生器就會呼叫在目的碼發出器(code emitter)中的相關函式去真正產 生原生機器碼。目的碼發出器是位在即時編譯器的最底層,能為特定的硬體架構 去產生其相關的目標機器指令。