V8十年故事:從農場誕生的星球最強JS引擎
作者 | V8 團隊
譯者 | 無明
出處 | 前端之巔
這個月不僅有谷歌 Chrome 的十歲生日,也有 V8 的十周年紀念日。這篇文章將為你講述 V8 在過去 10 年中經歷的主要里程碑,以及在它誕生之前的那些秘密的歲月。
使用 gource 創建的 V8 代碼庫可視化演化進程,相當精彩,請使用科學上網方式觀看:
https://youtu.be/G0vnrPTuxZA
V8 誕生之前的秘密歲月
2006 年秋天,谷歌聘請 Lars Bak 為 Chrome 瀏覽器構建一個新的 JavaScript 引擎,當時它還只是谷歌內部的一個秘密項目。後來,Lars 從矽谷回到了丹麥的奧胡斯。Lars 想留在丹麥,但那裡沒有谷歌辦事處,於是 Lars 和幾個最初參與該項目的工程師開始在他的農場辦公。新的 JavaScript 運行時被命名為「V8」,靈感源自 50 年代經典的「肌肉車」的引擎。後來,隨著 V8 團隊不斷成長,開發者從農場搬到了奧胡斯的一個現代化的辦公大樓里。然後,整個團隊開始專註於構建地球上最快的 JavaScript 運行時。
V8 項目的啟動和演化
2008 年 9 月 2 日,V8 與 Chrome 在同一天宣布開源。最初的代碼提交日期可追溯到 2008 年 6 月 30 日。在那之前,V8 是在一個私有 CVS 存儲庫上開發的。最初,V8 只支持 ia32 和 ARM 指令集,並使用 SCons 作為構建系統。
2009 年,V8 引入一個名為 Irregexp 的正則表達式引擎,改進了真實世界的正則表達式性能。隨著 x64 移植的引入,支持的指令集數量從兩個增加到三個。2009 年,內嵌 V8 的 Node.js 發布了第一個版本。在最初的 Chrome 漫畫中明確提到了將 V8 嵌入到非瀏覽器項目中的可能性,而 Node.js 做到了!Node.js 成為最受歡迎的 JavaScript 生態系統之一。
2010 年,V8 引入了全新的優化 JIT 編譯器 Crankshaft,從而極大提升了運行時性能。Crankshaft 生成的機器代碼比之前的 V8 編譯器(未命名的)快兩倍,而體積小了 30%。同年,V8 增加了第四個指令集:32 位 MIPS。
2011 年,垃圾回收器性能得到了極大的改善。新的增量垃圾回收器大大減少了停頓時間,同時保持了極佳的峰值性能和低內存使用率。V8 引入了隔離的概念,可以在一個進程中啟動多個 V8 運行時實例,為在 Chrome 中實現輕量級的 Web Worker 鋪平了道路。後來我們從 SCons 轉向 GYP,這是第一次進行 V8 構建系統遷移。我們實現了對 ES5 strict mode 的支持。與此同時,開發工作從奧胡斯移交到了德國慕尼黑。
2012 年是 V8 項目的基準測試年。團隊通過不斷的速度衝刺迭代來優化 V8 的性能,並使用 Sunspider 和 Kraken 基準套件來測量性能。後來,我們自己開發了一個名為 Octane 的基準測試套件(其核心是 V8 Bench),它引領了峰值性能競賽,促進了所有主要 JS 引擎的運行時和 JIT 技術的大幅改進。所有這些努力導致的一個結果是從隨機抽樣轉向了一種基於確定性和計數的技術,用於檢測 V8 運行時分析器中的「熱」函數。
2013 年,一個名為 asm.js 的 JavaScript 子集出現了。由於 asm.js 只支持靜態類型的算術運算、函數調用和基本類型的堆訪問,因此 asm.js 代碼的運行性能是可預測的。我們發布了新版 Octane(Octane 2.0),對現有基準測試進行了更新,並針對 asm.js 等用例增加新的基準測試。Octane 促進了編譯器優化的發展,例如分配摺疊和用於類型轉換和預定的基於分配站點的優化,大大提高了峰值性能。作為內部「Handlepocalypse」計劃的一部分,我們對 V8 Handle API 進行了徹底重寫,提升其易用性和安全性。同年,Chrome 實現的 TypedArrays 從 Blink 轉到了 V8 中。
2014 年,V8 通過並發編譯將 JIT 編譯的一些工作從主線程中移除,以此來減少堵塞,並顯著提升了性能。後來,我們推出了名為 TurboFan 的新優化編譯器的初始版本。同時,我們的合作夥伴將 V8 移植到三個新的指令集架構上:PPC、MIPS64 和 ARM64。繼 Chromium 之後,V8 轉向了另一個構建系統 GN。V8 的測試基礎設施得到了顯著改進,可以使用 Tryserver 在構建開始之前測試每個補丁。在源代碼控制方面,V8 從 SVN 遷移到了 Git。
2015 年是 V8 最繁忙一年,我們實現了代碼緩存和腳本流,大大加快了網頁載入速度。那年晚些時候,我們開始了新解釋器 Ignition 的開發工作。我們嘗試了 strong mode,打算讓它成為 JavaScript 的子集,以實現更強和更可預測的性能保證。我們實現了 strong mode,但後來發現它所帶來的好處並不足以抵消我們所花費的成本。而我們添加的提交隊列卻大大提高了生產力和穩定性。V8 的垃圾回收器也開始與 Blink 等嵌入器合作,以便在空閑時進行垃圾回收。空閑時垃圾回收顯著減少了垃圾回收停頓和內存消耗。當年的 12 月分,第一個 WebAssembly 原型來到了 V8 上。
2016 年,我們發布了最後一組 ES2015(以前稱為「ES6」)特性集(包括 promise、類語法、詞法作用域、解構等),以及一些 ES2016 特性。我們還開始推出新的 Ignition 和 TurboFan 管道,用它來編譯和優化 ES2015 和 ES2016 特性,並將 Ignition 作為低端 Android 設備的默認配置。我們在 PLDI 2016 大會上展示了我們的空閑時垃圾回收工作成功。
我們啟動了 Orinoco 項目,這是一個針對 V8 的並發垃圾回收器,旨在減少主線程垃圾回收時間。我們將性能工作從合成微基準轉向了測量和優化實際性能。出於調試的目的,V8 檢查器從 Chromium 遷移到了 V8,允許任何 V8 嵌入器(不僅僅是 Chromium)使用 Chrome DevTools 來調試在 V8 中運行的 JavaScript。WebAssembly 從原型轉為了實驗支持。V8 獲得了 ACM SIGPLAN 編程語言軟體大獎。在這一年還新增了另一個移植平台:S390。
2017 年,我們終於完成了對 V8 引擎進行的重大修整,默認情況下啟用新的 Ignition 和 TurboFan 管道。這樣就有可能在後續從代碼庫中移除 Crankshaft(130,380 個已刪除的代碼行)和 Full-codegen。我們推出了 Orinoco v1.0,包括並發標記、並發掃描、並行清理和並行壓縮。我們正式將 Node.js 視為 V8 的一等嵌入器。從那以後,如果某些 V8 補丁無法通過 Node.js 測試套件的測試,就不能推出這些補丁。我們的基礎設施提供了正確模糊測試支持,確保任何代碼都能產生一致的結果,無論是在怎樣的配置下運行。
在一個面向整個業界的協調啟動發布中,V8 默認啟用了 WebAssembly。我們實現了對 JavaScript 模塊以及 ES2017 和 ES2018 完整特性集的支持(包括非同步函數、共享內存、非同步迭代,rest/spread 屬性和 RegExp)。
我們提供了對 JavaScript 代碼覆蓋的原生支持,並啟動了 Web Tooling Benchmark,用以幫助我們衡量 V8 的優化對實際開發者工具以及這些工具所生成的 JavaScript 輸出的性能的影響。我們可以藉助用於跟蹤 JavaScript 對象到 C++ DOM 對象的包裝器來解決 Chrome 中長期存在的內存泄漏問題,並有效地處理 JavaScript 和 Blink 堆上對象的閉包傳遞。我們後來使用這個基礎設施來提升開發者工具的堆快照能力。
2018 年,一個行業範圍的安全事件(Spectre/Meltdown 漏洞)顛覆了我們對 CPU 信息安全的認知。V8 工程師進行了大量有關安全攻擊問題的研究,以便更好地理解託管語言所面臨的威脅並提出解決措施。V8 為運行不受信任代碼的嵌入器提供了針對 Specter 和類似側通道攻擊的緩解措施。
最近,我們為 WebAssembly 發布了一個名為 Liftoff 的基線編譯器,它大大減少了 WebAssembly 應用程序的啟動時間,同時提供了可預測的性能。我們發布了 BigInt,一個新的 JavaScript 原始類型,可以實現任意精度的整數。我們實現了嵌入式內置函數,並可以對它們進行惰性反序列化,從而顯著降低 V8 多個隔離的佔用空間。現在可以讓後台線程編譯腳本位元組碼。我們啟動了 Unified V8-Blink Heap 項目,可同步運行跨 V8 和 Blink 的垃圾回收。
性能的起伏
多年來,Chrome 的 V8 Bench 分數顯示出 V8 的變化對性能產生了巨大影響。(我們正在使用 V8 Bench,因為它是仍然可以在最初 Chrome 測試版中運行的少數基準測試之一。)
在過去十年中,我們在這個基準測試中的分數提升了 4 倍!
不過,你可能也注意到其中有兩次出現性能下降,它們分別對應於 V8 歷史上的兩個重大事件。2015 年的性能下降發生在 V8 發布 ES2015 特性基準版的時候,我們更多地關注特性的正確性,而忽略了初始版本的性能。我們以微小的性能回退換來能夠儘快讓開發者用上這些特性。在 2018 年初,因為 Spectre 漏洞,V8 發布了緩解措施以保護用戶免受潛在攻擊,導致性能再次下降。所幸的是,現在 Chrome 正在發布了站點隔離,我們可以禁用這些緩解措施,從而恢復性能。
從圖中我們還可以看出,V8 的性能從 2013 年左右開始趨於平穩。這是否意味著 V8 放棄並停止在性能方面繼續投入?恰恰相反,圖中所示的平穩說明了 V8 團隊從合成微基準(如 V8 Bench 和 Octane)轉向了優化實際性能。V8 Bench 是一個舊的基準測試,它不使用任何現代 JavaScript 功能,與實際的生產代碼也有一定的距離。下面是使用更新的 Speedometer 基準套件得出的結果:
從 2013 年到 2018 年 Chrome 的 Speedometer 1 得分
從 2013 年到 2018 年,V8 Bench 顯示的改進程度微乎其微,但在同一時期,Speedometer 1 得分上升了 4 倍。(我們使用了 Speedometer 1,因為 Speedometer 2 使用了 2013 年還不支持的現代 JavaScript 特性。)
如今,我們有更好的基準測試,可以更準確地反映現代 JavaScript 應用程序。最重要的是,我們會主動測量和優化現有的 Web 應用程序。
總 結
儘管 V8 最初是為谷歌 Chrome 而構建的,但它一直是一個獨立的項目,它有自己的代碼庫,並提供了嵌入式 API,讓其他程序可以使用它的 JavaScript 執行服務。在過去的十年中,這個項目的開放性不僅讓它成為 Web 平台的關鍵技術,也成為其他環境(如 Node.js)的關鍵技術。
Web 的故事可以說是源遠流長,慶祝 Chrome 和 V8 的 10 歲生日是一個重要的里程碑,但 Web 平台的故事已經延續了 25 年。毫無疑問,Web 的故事會繼續傳承下去。我們希望 V8、JavaScript 和 WebAssembly 在後續的 Web 故事中繼續扮演有趣的角色。同時,我們也很期待未來十年將會發生些什麼!
英文原文
https://v8project.blogspot.com/2018/09/10-years.html


※QCon上海2018日程上線:100+海內外實踐案例
※來跟Google Cloud大咖們來場親密接觸:今夜 以AI之名
TAG:InfoQ |