JavaScript 性能革命
当 Brendan Eich 在 1995 年 5 月构建 Mocha 时,性能既不是个关注点,也不是个目标。当时还没有任何 JavaScript 程序,为其预期的程序只要能对「基于其他更高效的语言实现的对象」做简单组合就够了。在当时的设想中,JavaScript 并不是用来编写哪怕稍复杂点的算法的。早期的 JavaScript 引擎使用简单的字节码解释器或解析树求值器来直接解释 JavaScript 函数,并使用简单的内存管理方案。它们没有利用 20 世纪 80 年代和 90 年代初为 Lisp、Smalltalk、Self 和其他动态语言开发的复杂的高性能实现技术。对 Netscape / Mozilla 的 SpiderMonkey 和微软的 JScript 引擎而言,其基本架构在十年来基本没有变化。在十年间,新的 ES3 级语言特性得以加入,安全问题也得到了解决。但无论这期间有什么性能提升,它们都可以归功于摩尔定律 [Moore 1975] 下的硬件性能进步。在这一时期的大部分时间里,维护浏览器的 JavaScript 引擎不过是一位软件开发者的兼职工作。
在 2000 年代的前半段,AJAX 式大型 Web 应用的出现,开始严重突破了第一代引擎的性能限制。到 2006 与 2007 年,Web 开发者对性能问题的呼声越来越高,浏览器厂商也开始派出团队来解决其 JavaScript 引擎的性能限制。对性能的度量是提高性能的重要起点,苹果的 WebKitg 团队为此创建了 SunSpider JavaScript 基准测试套件(benchmark suite)[Stachowiak 2007a]。SunSpider 远非完美,由相对较小的测试用例组成,但它来自于实际的 Web 应用代码。在它发布后不久,Web 应用开发者社区就开始经常使用 SunSpider 来比较浏览器的 JavaScript 性能,并对结果进行讨论。浏览器博弈论基本上阻止了浏览器厂商以 JavaScript 特性为基础进行竞争,但他们「可以并且确实」开始在 JavaScript 性能上进行竞争。
不同厂商采取了不同的路线来实现高性能的 JavaScript 引擎。2006 年,Google 开始研发一款最终成为了 Chromeg 的浏览器。Lars Bak 领导了 Chrome 的 V8g JavaScript 引擎的开发。这个引擎建立在他所开发的 Smalltalk、Self 和 Java 虚拟机 [Google 2008b] 的技术基础上。当 Chrome 浏览器于 2008 年 9 月发布时,它成为了代表良好 JavaScript 性能的新基准。同时期的一份报告 [Hobbs 2008] 显示,在当时的 Firefox 版本中,V8 运行 Google 基准测试 [Google 2008a] 的速度比当时发布的 SpiderMonkey 快约 10 倍77。然而在 SunSpider 基准测试中,V8 大约只快了 2 倍。
Mozilla 最初使用的路线称为 TraceMonkey [Gal et al. 2009],这是基于加州大学欧文分校的 Andreas Gal 博士毕业作品的引擎。它使用了现有的 SpiderMonkey 解释器,并在其基础上增加了一个跟踪驱动的 JIT 编译器。这个编译器能动态识别出执行热点,并为其生成优化后的原生代码。苹果的 SquirrelFish Extreme [Stachowiak 2008a](也就是 Nitro)则使用了受 Self 和高性能 Lua 实现启发的技术。微软最初试图逐步重新设计其遗留的 JScript 引擎,以便在 IE8 中使用。但在 IE9 中微软推出了 Chakra,这是一个基于 JIT 的全新 JavaScript 引擎 [Niyogi 2010]。
所有这些努力仅仅是优化 JavaScript 性能的起点。今天,每一个主流浏览器的开发都需要一个实质性的 JavaScript 团队,专注于性能、安全性和 ECMAScript 标准的新语言特性。这些团队所开发的每个引擎都是在兼容的开源许可下发布的。因此这些团队能在彼此的工作基础上分享想法,有时还可以分享完整的子系统。最快的 JavaScript 实现就是这样在他们的竞争中产生的。