作為JavaScript欄目開發人員,深入了解 JavaScript 引擎的工作原理有助于你了解自己代碼的性能特征。這篇文章對所有 JavaScript 引擎中常見的一些關鍵基礎知識進行了介紹,不僅僅局限于 V8 引擎。
JavaScript 引擎的工作流程 (pipeline)
這一切都要從你寫的 JavaScript 代碼開始。JavaScript 引擎解析源代碼并將其轉換為抽象語法樹(AST)。基于 AST,解釋器便可以開始工作并生成字節碼。就在此時,引擎開始真正地運行 JavaScript 代碼。為了讓它運行得更快,字節碼能與分析數據一起發送到優化編譯器。優化編譯器基于現有的分析數據做出某些特定的假設,然后生成高度優化的機器碼。
如果某個時刻某一個假設被證明是不正確的,那么優化編譯器將取消優化并返回到解釋器階段。
JavaScript 引擎中的解釋器/編譯器工作流程
現在,讓我們來看實際執行 JavaScript 代碼的這部分流程,即代碼被解釋和優化的部分,并討論其在主要的 JavaScript 引擎之間存在的一些差異。
一般來說,JavaSciript 引擎都有一個包含解釋器和優化編譯器的處理流程。其中,解釋器可以快速生成未優化的字節碼,而優化編譯器會耗費更長的時間,但最終可生成高度優化的機器碼。這個通用流程和 Chrome 和 Node.js 中使用的 Javascript 引擎, V8 的工作流程幾乎一致:
V8 中的解釋器稱為 Ignition,負責生成和執行字節碼。當它運行字節碼時,它收集分析數據,這些數據可用于后面加快代碼的執行速度。當一個函數變為 hot 時,例如當它經常運行時,生成的字節碼和分析數據將傳遞給我們的優化編譯器 Turbofan,以根據分析數據生成高度優化的機器代碼。
Mozilla 在 Firefox 和 Spidernode 中使用的 JavaScript 引擎 SpiderMonkey ,則不太一樣。它們有兩個優化編譯器,而不是一個。解釋器先通過 Baseline 編譯器,生成一些優化的代碼。然后,結合運行代碼時收集的分析數據,IonMonkey 編譯器可以生成更高程度優化的代碼。如果嘗試優化失敗,IonMonkey 將返回到 Baseline 階段的代碼。
Chakra,在 Edge 中使用的 Microsoft 的 JavaScript 引擎,非常相似的,也有2個優化編譯器。解釋器優化代碼到 SimpleJIT(JIT 代表 Just-In-Time 編譯器,即時編譯器),SimpleJIT 會生成稍微優化的代碼。而 FullJIT 結合分析數據,可以生成更為優化的代碼。JavaScriptCore(縮寫為 JSC),在 Safari 和 React Native 中使用的 Apple 的 JavaScript 引擎,它通過三種不同的優化編譯器將其發揮到極致。低層解釋器 LLInt 優化代碼到 Baseline 編譯器中,然后優化代碼到 DFG(Data Flow Graph)編譯器中,DFG(Data Flow Graph)編譯器又可以將優化后的代碼傳到 FTL(Faster Than Light)編譯器中。
為什么有些引擎有