1. 程式人生 > >[WebKit] JavaScriptCore解析--高階篇(三) Register Allocation & Trampoline

[WebKit] JavaScriptCore解析--高階篇(三) Register Allocation & Trampoline

Register Allocation

對於一個JIT而言,暫存器分配對系統的消耗通常是一個瓶徑。之前有Graph Coloring Allocators, Chaitin style等分配方式,現在要介紹的是DFG JIT使用的Linear Scan演算法。其基本工作方式是將佔用暫存器的變數根據生命週期長短排列出來,在使用時檢視可以回收哪些暫存器加以利用。

先看一些定義:

Live interval:是某個變數可以存活的一個指令序列,也可以稱為了連續性。這個也依賴於演算法使用的是深度優先還是廣度優先。如下圖,B1~B4代表的是四個Basic Blocks,w/r代表的是讀和寫.

Spilling:當變數儲存到堆疊時就稱為溢位。

Interference: 當兩個活動區間共同存在於一個程式中時,稱他們之間會有干擾。

  

演算法的執行過程簡述如下:

 1. 計算變數的live interval.

 2. 遍歷:

   2.1 如果live interval已經過期就扔掉。

   2.2 分配新的live interval和暫存器。

   2.3 如果無法分配(所需的interval過長等),則spill出去,再選擇較低成本的變數。

複雜度:O(V logR) (V是變數數,R暫存器數)

下面是示意圖:





Trampoline

再介紹一下JIT中應用的Trampoline,蹦床或者彈簧技術,可以達到延遲編譯的效果(其它領域的效果不同,比如編譯器裡的

PLT)。一個“彈簧床”就是一個函式存根,它能在被呼叫的時候,觸發JIT執行。一旦JIT編譯這個函式成為機器碼,那麼“彈簧床”的指標就會被替換為真實函式的指標。

在JSC中,相關程式碼檢視JITStubs.cpp中的實現,如ctiTrampoline等。下面是一個呼叫堆疊:


然後再跳轉到具體的操作(可能會調回到LLInt對應的slow path進行處理):


參考:

 Massimilliano Poletto, Linear Scan Register Allocation

 CS 380C Lecture 14, Register Allocation

系列索引: