Google Docs 和 Gmail 等現代網站執行的 JavaScript 量大到讓引擎速度出現兩個各自獨立的瓶頸。Firefox 的 C++ 位元組碼解譯器速度慢,且不收集型別資訊;而 Baseline JIT 會將每個函式編譯成機器碼,在負載沉重的頁面上,這意味著要編譯數千個函式,於是時間都花在編譯而非執行上。最佳化 Ion JIT 唯有在 Baseline JIT 已蒐集型別資料後才會變快。

顯而易見的修正方案各有代價:加快 C++ 解譯器,它仍無法提供最佳化器任何型別資料;延後或移轉 Baseline 編譯,冷路徑或退出(bailout)會變得有風險;在 JIT 程式碼中途恢復 Ion 退出,每項功能都需要額外的中繼資料,以及供除錯器和例外處理使用的複雜程式碼。Mozilla 改為新增一個層級:Baseline 解譯器,介於 C++ 解譯器與 Baseline JIT 之間。

讓這件事成本低廉的關鍵做法,並非從頭撰寫一個解譯器。Baseline JIT 是範本 JIT:每個位元組碼指令早已對應到一段大致固定的機器碼序列。Mozilla 將這些相同的序列產生進一個執行緒化解譯器迴圈,共用同一個範本化程式碼產生器、相同的框架配置,以及同一個 JitScript 結構,該結構存放兩個層級都會用到的行內快取與剖析資料。

由於解譯現在會蒐集型別資訊,Baseline JIT 的暖機門檻得以從 10 提高到 100,大幅減少需要編譯的函式數量。Firefox Nightly 測得頁面載入速度提升 2-8%、開發者工具測試速度提升 2-10%、節省記憶體,且程式碼更簡單:Ion 退出改在解譯器中恢復,許多複雜的除錯器與例外處理機制也遭到刪除。

從與快速層級相同的程式碼產生器產生這個低成本層級,讓快取與型別資料保持共用

重複使用 JIT 的程式碼產生器,意味著解譯器行為與行內快取在構造上就與 JIT 一致,無須維護第二套實作來保持同步。

解譯現在會蒐集 JIT 以往所蒐集的相同型別資料,因此最佳化層級無須等待編譯即可取得其剖析資料。

將 JIT 暖機門檻提高十倍,大幅減少了在大量使用 JS 的頁面上需要編譯的函式數量。

退出、除錯器支援與例外處理變得更簡單,因為 Ion 改在解譯器中恢復,而非在 JIT 程式碼中途恢復,所需的中繼資料更少。

進入中間層級的成本很低:JitScript 配置的執行速度至少比 Baseline JIT 編譯快 10 倍。

不要手寫介於慢速與快速之間的中間層級:從快速層級自身的範本產生它,快取、框架與行為在構造上就會保持一致

Baseline 解譯器於 2019 年 7 月進入 Firefox Nightly,並預定在同年 10 月的 Firefox 70 正式版推出。Mozilla 的測量顯示頁面載入速度提升 2-8%、開發者工具測試速度提升 2-10%,另外還節省了記憶體。它所促成的清理工作也加快了 Baseline JIT 編譯,而團隊所說的下一步,是將該編譯工作移出主執行緒。

追溯依據

參考來源

  1. The Baseline Interpreter: a faster JS interpreter in Firefox 70 Mozilla Hacks · hacks.mozilla.org ·
  2. Hacker News discussion: The Baseline Interpreter: a faster JS interpreter in Firefox 70 Hacker News · news.ycombinator.com ·