40

V8十年故事:从农场诞生的星球最强JS引擎

 5 years ago
source link: http://www.infoq.com/cn/articles/v8-10-years?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

这个月不仅是谷歌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测试版中运行的少数基准测试之一。)

9421-1537642522797.png

从2008年到2018年的Chrome V8 Bench分数

在过去十年中,我们在这个基准测试中的分数提升了4倍!

不过,你可能也注意到其中有两次出现性能下降,它们分别对应于V8历史上的两个重大事件。2015年的性能下降发生在V8发布ES2015特性基准版的时候,我们更多地关注特性的正确性,而忽略了初始版本的性能。我们以微小的性能回退换来能够尽快让开发者用上这些特性。在2018年初,因为Spectre漏洞,V8发布了缓解措施以保护用户免受潜在攻击,导致性能再次下降。所幸的是,现在Chrome正在发布了站点隔离,我们可以禁用这些缓解措施,从而恢复性能。

从图中我们还可以看出,V8的性能从2013年左右开始趋于平稳。这是否意味着V8放弃并停止在性能方面继续投入?恰恰相反!图中所示的平稳说明了V8团队从合成微基准(如V8 Bench和Octane)转向了优化实际性能。V8 Bench是一个旧的基准测试,它不使用任何现代JavaScript功能,与实际的生产代码也有一定的距离。下面是使用更新的Speedometer基准套件得出的结果:

7422-1537642522213.png

从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

感谢覃云对本文的审校。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK