1. 程式人生 > >基於方法的JIT編譯之挑戰

基於方法的JIT編譯之挑戰

今天,混合模式的編譯系統採用的常用方法是識別頻繁執行的或者叫熱方法。熱方法傳遞給JIT編譯器以便編譯成機器程式碼。然後,當直譯器看見應用呼叫被編譯過的方法時,它就會分發機器程式碼去執行。

這種面向方法的方法已經採用許多年了,但是仍然需要大量的開發方面的前期投資。直到能夠編譯一門語言中出現的所有功能時,這樣的系統才能提高方法的執行效率。對重要的應用來說,這需要JIT編譯整個語言,包含那些複雜的已經用高階虛擬指令體實現了的功能,例如那些方法呼叫,物件建立,異常處理。

因為一個方法被頻繁執行,並不意味著方法內的所有指令也會頻繁執行。實際上,熱方法的部分割槽域可能是“冷的”,也就是說可能他們永遠也不會執行。編譯冷程式碼除了浪費時間外還有更多的隱含意味。除最高級別的優化外,分析冷程式碼可以證明哪些是熱程式碼,除了這一點好除外,沒有其他更多益處。一個更嚴重的問題是,冷程式碼增加了動態編譯的複雜度。我們給出3個例子。

      首先,對於延遲繫結語言如Java來說,冷程式碼很有可能包含對那些還沒有繫結的外部符號的引用,因此當冷程式碼最終並沒有執行時,生成的程式碼還有支援它執行的環境(Runtime)必須處理延遲繫結的複雜性。 

       第二,某些動態優化如果不執行Profiling資訊是不可能做到的. Foremost amongst these is the optimization of virtual function calls. 因此沒有Profiling資訊,JIT只能為冷程式碼生成相對慢的保守程式碼。這個問題對弱型別(runtime typed)的語言如python來說變得更加重要,因為虛擬指令的運算元型別可能只有在執行時刻才能知道。沒有執行資訊,無論是動態還是靜態的Python編譯器都不能判別簡單算數運算如加法的運算元是什麼型別,是整形、浮點型還是字串型。

      第三,隨著指令的執行,編譯過的方法裡以前認為冷的區域可能變熱。第一次編譯是作出的保守的假設現在對效能卻構成了拖累。直接的方法就是再次編譯這些冷程式碼,這樣做就會對編譯帶來的優勢造成了損害。而且,問題是如此複雜以至於對那些還在方法中執行的執行緒來說,它們需要做什麼?或者未來如何返回到方法?

2 高效直譯器的挑戰

虛擬程式被直譯器載入記憶體之後,它就可以通過分發一條條虛擬程式指定的虛擬指令體(或者叫指令體)來執行。從處理器的觀點看,這種方式並不是典型的工作方式,這是因為使得CPU的控制從一個指令(體)交到另一個指令體的決定因素是那些依賴指令的虛擬程式的資料。這使得處理器很難作出分支預測。Ertl 和 Gregg

 觀察到高效率的直譯器效能受限於指令流水線,同時及其低效的分支預測也會導致指令流水線被清空,這也限制瞭解釋器效能。