1. 程式人生 > >【轉】理解WebKit和Chromium: JavaScript引擎簡介

【轉】理解WebKit和Chromium: JavaScript引擎簡介

正則表達 根據 tco 抽象 由於 介紹 後來 rom 都在

轉載請註明原文地址:http://blog.csdn.net/milado_nju
1. 什麽是JavaScript引擎
什麽是JavaScript引擎?簡單來講,就是能夠提供執行JavaScript代碼的運行環境。要解釋這一概念,需要了解一些編譯原理的基礎概念和現代語言需要的一些新編譯技術。

首先來看C/C++語言。它們是比較悠久的語言了,實際上就是使用編譯器直接將它們編譯成本地代碼,這一切都是由開發人員在代碼編寫完成之後實施。用戶只是使用這些編譯好的本地代碼,這些本地代碼被系統的加載器加載執行,這些本地代碼(也就是機器指令)由操作系統調度CPU直接執行,無需其它額外的輔助虛擬機等。這一過程基本上是從源代碼開始,然後抽象語法樹,之後中間表示,最後到本地代碼。

其次,來看看Python等腳本語言。處理腳本語言通常的做法是開發者將寫好的代碼直接交給用戶,用戶使用腳本的解釋器將腳本文件加載然後解釋執行。當然,現在Python也可以支持將腳本編譯生成中間表示,當然這是後話。所以這表示,對於腳本語言,沒有開發人員的編譯過程,當然也不是絕對,這主要因為使用場景不一樣,它的目的不是高性能。這一過程是源代碼,到抽象語法樹,再到解釋器解釋執行。

然後來看看Java語言。其做法可以理解為比較明顯的兩個階段,首先是像C++語言一樣的編譯器,但是,同C++編譯器生成的本地代碼結果不同,經過編譯器編譯之後的是字節碼,字節碼是平臺無關的。在運行字節碼階段,Java的運行環境也就是Java虛擬機會加載字節碼,使用解釋執行這些字節碼。如果僅是這樣,那Java的性能就差C++太多了。現代Java虛擬機一般都引入了JIT技術,也就是前面說的將字節碼轉變成本地代碼來提高執行效率。這主要兩個階段,第一階段對時間要求不嚴格,第二階段則對每個步驟所花費的時間非常敏感,時間越短越好。

最後回到JavaScript語言上來。前面已經說了它是一種解釋性腳本語言。是的,它的確是,但是隨著眾多工程師不斷投入資源來提高它的速度,這使得它能夠使用了Java虛擬機和C++編譯器中眾多的技術,它的工作方式也在演變。早期也是一樣由解釋器來解釋它們即可,就是將源代碼轉變成抽象語法樹,然後在抽象語法樹上解釋執行。隨著將Java虛擬機的JIT技術引入,現在的做法是將抽象語法樹轉成中間表示(也就是字節碼),然後通過JIT技術轉成本地代碼,這能夠大大的提高了執行效率。當然也有些做法直接從抽象語法樹生成本地代碼的JIT技術,例如V8。這是因為JavaScript跟Java還是有以下一些區別的:

其一當然是類型,JavaScript是無類型的語言,這使得對於對象的表示和屬性的訪問上比Java存在比較大的性能損失。不過現在有一些新的技術,參考C++或者Java的類型系統的優點,構建隱式的類型信息,這些後面逐一介紹。

其二是Java語言通常是將源代碼編譯成字節碼,這個同執行階段是分開的,也就是從源代碼到抽象語法樹到字節碼這段時間的長短是無所謂的(或者說不是特別重要),所以主要是盡可能的生成高效的字節碼即可。而對於JavaScript而言,這些都是在網頁和JavaScript文件下載後同執行階段一起在網頁的加載和渲染過程中來實施的,所以對它們的處理時間也有著很高的要求。

描述JavaScript代碼執行的過程,這一過程中因為不同技術的引入,導致非常復雜,而且因為都是在代碼運行過程中來處理這些步驟,所以每個階段時間越少越好,而且每引入一個階段都是額外的時間開銷,可能最後的本地代碼執行效率很高,但是之前步驟如果耗費太多時間的話,最後的執行結果可能並不會好。所以不同的JavaScript引擎選擇了不同的路徑,這裏先不仔細介紹,後面再描述它們。

所以一個JavaScript引擎不外乎包括以下部分:

第一, 編譯器。主要工作是將源代碼編譯成抽象語法樹,然後在某些引擎中還包含將抽象語法樹轉換成字節碼。

第二, 解釋器。在某些引擎中,解釋器主要是接受字節碼,解釋執行這個字節碼,然後也依賴來及回收機制等。

第三, JIT工具。一個能夠能夠JIT的工具,將字節碼或者抽象語法樹轉換成本地代碼,當然它也需要依賴牢記

第四, 垃圾回收器和分析工具(profiler)。它們負責垃圾回收和收集引擎中的信息,幫助改善引擎的性能和功效。


2. JavaScript引擎和渲染引擎
前面介紹了網頁的工作過程需要使用到兩個引擎,也就是渲染引擎和JavaScript引擎。從模塊上看,目前,它們是兩個獨立的模塊,分別負責不同的事情:JavaScript引擎負責執行JavaScript代碼,而渲染引擎負責渲染網頁。JavaScript引擎提供調用接口被渲染引擎使用,渲染引擎使用JavaScript引擎來處理JavaScript代碼並獲取結果。這當然不是全部,事情不是這麽簡單,JavaScript引擎需要能夠訪問渲染引擎構建的DOM樹,所以JavaScript引擎通常需要提供橋接的接口,而渲染引擎則根據橋接接口來提供讓JavaScript訪問DOM的能力。在現在眾多的HTML5能力中,很多都是通過JavaScript接口提供給開發者的,所以這部分同樣需要根據橋接接口來實現具體類,以便讓JavaScript引擎能夠回調渲染引擎的具體實現。下圖是一個簡單的關於兩者引擎的關系。

在WebKit/Blink項目中,這兩種引擎通過橋接接口來訪問DOM結構,這對性能來說是一個重大的損失,因為每次JavaScript代碼訪問DOM都需要通過復雜和低效的橋接接口來完成。鑒於訪問DOM樹的普遍性,這是一個常見的問題。希望以後可以減少這一方面的開銷。

3. JavaScriptCore引擎和V8引擎
3.1 WebKit中的JavaScript引擎
在WebKit項目中,最初只有JavaScriptCore引擎。在Blink還獨立出來之前,為了支持不同的JavaScript引擎,WebKit設計了一套接口可以切換使用不同的JavaScript引擎(事實上,這一接口會降低性能),所以,WebKit當時可以支持兩種類型的JavaScript引擎,那就是JavaScriptCore引擎和V8引擎。兩者都是基於WebKit所提供的接口來同渲染引擎協同工作。

3.2 JavaScriptCore引擎
JavaScriptCore引擎是WebKit中默認的引擎,在早期階段,它的性能不是特別突出。特別是,它只有解釋器來解釋執行JavaScript代碼。這一效率十分的低效,當然

從2008年開始,JavaScriptCore引擎開始一個新的優化工作,就是重新實現了編譯器和字節碼解釋器,這就是SquirrelFish。該工作對於引擎的性能優化作了比較大的改進。隨後,蘋果內部代號為”Nitro”的JavaScript引擎也是基於JavaScriptCore項目的,它的性能還是非常出色的,鑒於其是內部項目,所以具體還有什麽特別的處理就不得而知了。在這之後,開發者們又將內嵌緩存、基於正則表達式的JIT和簡單的JIT引入到JavaScriptCore中。然後,又陸續加入的字節碼解釋器。可以看出,JavaScriptCore引擎也在不斷的高速發展中。

上圖是JavaScriptCore最簡單的處理部分,它主要是將源代碼翻譯成抽象語法樹,之後是平臺無關的字節碼,在最初的版本中,字節碼會被JavaScriptCore引擎解釋執行。在後面的版本中,逐漸加入了JIT編譯器,將熱點函數生成本地代碼,後面再詳細介紹它們。

3.3 V8引擎
V8是一個開源項目,也是一個JavaScript引擎的實現。最開始是一幫語言方面的專家設計出來的,之後被Google收購,成為了JavaScript引擎和眾多相關技術的引領者。它的目的很簡單,就是為了提高性能,除了性能還是性能。因為之前不管JavaScriptCore引擎還是其它JavaScript引擎,在當時的情況下,它們的性能都不能令人非常滿意。為了達到高性能的JavaScript代碼執行效率從而獲得更好的網頁瀏覽效果,它甚至采用直接將JavaScript編譯成本地代碼的方式。

V8支持眾多的操作系統,包括但是不限於Windows、Linux、Android、Mac OS X等。同時它也是能夠支持眾多的硬件架構,例如IA32、X64、ARM、MIPS等。這麽看下來,它將主流軟硬件平臺一網打盡,由於它是一個開源項目,開發者可以自由的使用它的強大能力,一個例子就是目前炙手可熱的NodeJS項目,它就是基於V8項目的。開源的好處就是大家可以很方便地學習、貢獻和使用,下圖是V8引擎最基礎的代碼執行過程。

從圖中可以看出,首先它也是將源代碼轉變成抽象語法樹的,這一點同JavaScriptCore引擎一樣,之後兩個引擎開始分道揚鑣。不同於JavaScriptCore引擎,V8引擎並不將抽象語法樹轉變成字節碼或者其它中間表示,而是通過JIT編譯器的全代碼生成器(full code generator)從抽象語法樹直接生成本地代碼,所以沒有像Java一樣的虛擬機或者字節碼解釋器。這樣做的原因,主要是因為減少這抽象語法樹到字節碼的轉換時間,這一切都在網頁加載時候完成,雖然可以提高優化的可能,但是這些分析可能帶來巨大的時間浪費。當然,缺點也很明顯,至少包括兩點:第一是某些JavaScript使用場景其實使用解釋器更為合適,因為沒有必要生成本地代碼;第二是因為沒有中間表示,會減少優化的機會因為缺少一個中間表示層。至於有些文章說的喪失了移植性,個人覺得對於JavaScript這種語言來說不是問題,因為並沒有將JavaScript代碼先編譯然後再運行的明顯兩個分開階段的用法,例如像Java語言那樣。但是,針對V8設計思想來說,筆者認為它的理念比較先進,做法雖然比較激進,但是確實給JavaScript引擎設計者們帶來很多新思路。

在之後的版本中,V8工程師們引入了Crankshaft編譯器,它能夠對熱點的JS函數進行生成的分析和優化後再生成本地代碼,原因在於不是所有的JavaScript代碼都合適做如此深層次的優化,因為優化本身也需要花費一定的時間。有關V8的細節,希望以後有時間能夠介紹它們。

目前V8和JavaScriptCore引擎各有特色,相信兩者的發展能夠不斷推進JavaScript語言的執行性能。
---------------------

from:https://blog.csdn.net/milado_nju/article/details/22101681

【轉】理解WebKit和Chromium: JavaScript引擎簡介