2008 年 8 月,Mozilla 推出了 TraceMonkey。这个新引擎在 Firefox 3.5 中发布,标志着下一代网页浏览器和网页应用性能新纪元的到来。在推出新引擎后不久,Google 推出了搭载 Chrome 的 V8。Apple 也发布了用于 Safari 的引擎,甚至 Opera 也在最新浏览器测试版中发布了新引擎。
这些新引擎的直接结果是出现了新的应用程序类型。人们开始尝试 将 Processing 带到网页,尝试 实时音频处理,游戏 等。 (有关一些好的示例,请查看我们的 Canvas 演示 列表。)
Mozilla 在 JavaScript 引擎与这些新应用程序的交互方面学到了两点
- 我们采用的跟踪方法往往与某些代码风格的交互不佳。(例如,上面的 NES 游戏示例在我们引擎中的性能非常糟糕——它本质上是一个巨大的 switch 语句。)
- 当我们能够“保持跟踪” (稍后详细介绍) 时,TraceMonkey 比其他所有引擎都更出色。
Mozilla 的引擎从根本上与其他所有引擎不同:其他所有引擎都使用称为“基于方法的 JIT” 的方法。也就是说,它们接收所有传入的 JS 代码,将其编译为机器代码,然后执行。Firefox 使用“跟踪 JIT”。我们解释所有传入的 JS 代码,并在解释时进行记录。当我们检测到一个热路径时,我们将该路径转换为机器代码,然后执行该内部部分。(有关跟踪的更多 背景信息,请参阅去年的 hacks 中的这篇文章。)
跟踪 JIT 的缺点是我们必须在达到某些条件时在解释器和机器代码之间来回切换。当我们必须从机器代码跳转回解释器时,我们称之为“被踢出跟踪”。当然,解释器比运行原生机器代码要慢得多。事实证明,这种情况发生的频率比任何人预期的都要高。
因此,我们在第二代引擎中做的事情是将两种方法的最佳元素结合起来
- 我们使用 WebKit JS 引擎的一些代码块,构建了一个完整的基于方法的 JIT 来执行 JavaScript 代码。这应该让我们获得与其他引擎类似的快速基线 JS 性能。最重要的是,它将保持一致——不再需要在跟踪状态之间跳转,也不再需要在解释代码上花费大量时间。
- 我们将把我们的跟踪引擎连接到机器代码的后面,以生成用于内部循环的超快速代码。这意味着我们将能够在保持基于方法的 JIT 的一致性的同时,仍然拥有跟踪引擎的优势。
这项工作仍处于非常早期的阶段,目前甚至不值得进行演示,但我们认为有必要发布这篇文章,以便人们了解正在进行的基本内容。
您可以在 David Mandelin 和 David Anderson 的博客以及 新引擎的项目页面 中找到有关此内容的更多信息。
25 条评论