Archive

Posts Tagged ‘compiler’

从头写一个JIT?从这篇文章开始吧 :-)

June 15th, 2013 No comments

http://blog.reverberate.org/2012/12/hello-jit-world-joy-of-simple-jits.html

JIT非常的复杂——我学了好多年都没有学会 🙂 ——但是如果你想象一下最简单的JIT是什么样子, 那么它其实就是一个printf语句而已. 根据一些输入, 打印一些二进制的字符串到内存, 恰好这个内存是可执行的, 事就这样成了. 作为Demo, 作者在这篇文章中为 Brainf_ck 这种异类的语言实现了一个简单的JIT.

[译] Baseline Compiler in SpiderMonkey

April 19th, 2013 1 comment

这篇博客是对Mozilla这篇文章的简短编译,有兴趣的读者可以看原文。(PS:现在SpiderMonkey的架构越来越像是V8了。)

本周(2013-4-5)我们终于将 baseline 编译器加入了主分支,进入了 Firefox Nightly 版本。从开始开发到今天差不多半年的时间。

Baseline Compiler 是什么?

可以将 Baseline 编译器看成是 IonMonkey 的一个预备编译器(warm-up)。它的诞生使得我们在未来丢弃 JaegerMonkey 成为可能,也因此使得我们有机会大幅度的减少内存占用(在移除了JaegerMonkey之后)。这还使得我们实现新的语言特性、实现新的优化变得更加容易和直观。

引入了 Baseline 编译器之后我们的 SpiderMonkey 在各个 benchmark 上的性能提高了 5%~10%。你们可以在我们的自动性能评测网站上看到结果

为什么又要做一个JIT?

目前 Firefox 有 JaegerMonkey 和 IonMonkey 两个 JIT(这还不算已经移除的 TraceMonkey)。JaegerMonkey能够生成“很快的”代码,而IonMonkey能够生成“真正快的”代码。如果一段代码运行次数频繁,就使用JaegerMonkey编译它;如果之后运行还是很频繁,那就用IonMonkey再去编译一次。这样能够让重量级的优化用在真正需要的地方。但是这种策略的成功,需要仔细的权衡不同优化界别中编译优化的选择,因为编译本身也是需要耗费大量时间的,重量级的优化尤其如此。

简单来说,JaegerMonkey目前被我们当作简单快速的JIT来使用,但是它的设计初衷并不是这个。而 IonMonkey 跟 JaegerMonkey 之间的协作也存在一些问题。最好的解决方式是设计一个跟IonMonkey设计很接近的快速JIT,而baseline就是为了这个目的设计的。

SpiderMonkey的现状

JavaScript代码在SpiderMonkey中的解析过程大致如下:

  1. JavaScript代码首先被解释器解释执行。解释器很慢,但是它可以保证较快的启动速度,并且可以为JIT收集类型信息。
  2. 当一个函数变得“hot”(执行频率达到一定阈值),则调用JaegerMonkey进行JIT,JaegerMonkey使用解释器收集的类型信息来进行优化。
  3. 当函数已经被JaegerMonkey编译,并且执行次数达到IonMonkey的编译阈值(“really hot”),IonMonkey启动,花费比JaegerMonkey多得多的时间生成比JaegerMonkey好得多的代码。
  4. 如果函数中有变量(或其它东西)的类型发生了变化,那么之前JaegerMonkey和IonMonkey生成的jit代码都会被丢弃;以上的三个过程从头开始。

SpiderMonkey 这么设计是有原因的:解释器虽然很慢,但是能够保证执行的结果总是正确的;而IonMonkey虽然能够让编译之后的代码执行速度变快,但是需要花费很多的时间来编译;如果IonMonkey编译的代码执行次数很少,那么反而会导致总体的运行时间变长;而JaegerMonkey处于两者之间,能够用比IonMonkey少的时间生成比解释器速度快的代码,因此它被作为一个折中。

这样的设计很完美,不是么?

不,有几个重要的问题。

问题

  • JaegerMonkey和IonMonkey都没有能力收集类型信息,但是它们依赖类型信息来生成代码。
  • JaegerMonkey和IonMonkey的调用规范是不一样的,这导致两个JIT生成的代码之间的相互调用成本很高。
  • 解释器收集类型信息的功能具有局限性,并不能满足IonMonkey的需求。
  • 类型推断机制需要大量的内存,而类型推断的作者 Brian Hackett 表示把 JaegerMonkey 抛开之后事情会简单很多。
  • 很多 JavaScript 代码执行的次数很少,连 JaegerMonkey 不会被调用。SpiderMonkey 在 SunSpider 测试集得分上落后很大程度上就是因为这个原因。
  • JaegerMonkey 写得太复杂了,我们真的不想继续维护了 🙂

解决方案

我们使用 Baseline JIT 解决这些问题。它的优点:

  • 代码比JaegerMonkey和IonMonkey都简单;
  • 不会失效(invalidate);
  • 可以收集类型信息,inline cache机制可以帮助收集更多类型信息;
  • 比解释器快10~100倍

致谢

Baseline was developed by Jan De Mooij and myself(注:Kannan Vijayan), with significant contributions by Tom Schuster and Brian Hackett. Development was greatly helped by our awesome fuzz testers Christian Holler and Gary Kwong.

And of course it must be noted Baseline by itself would not serve a purpose. The fantastic work done by the IonMonkey team, and the rest of the JS team provides a reason for Baseline’s existence.

[译]IonMonkey in Firefox 18

September 13th, 2012 No comments

注:本文是对David Anderson这篇博客文章的翻译。David介绍了IonMonkey的性能提升的内部架构,同时表示将在未来几周写更多的文章介绍IonMonkey。本博客将持续关注并翻译。

今天我们在Firefox 18中启用了我们最新的JavaScript JIT编译器,IonMonkey。IonMonkey不仅对JavaScript的执行性能有很大的提高,也是我们的编译器架构有了很大的进步。IonMonkey花费了超过一年的时间开发,我们都超级兴奋。

SpiderMonkey跟JIT的关系源远流长,但是你会发现SpiderMonkey的JIT编译器中缺少一个现代编译器,例如Java或C++编译器中都有的步骤。无论是老的TraceMonkey(作者注1)还是新的JaegerMonkey,都基本上是直接把JavaScript(从字节码)翻译到机器码。没有中间步骤,所以编译器也就没有办法看到翻译的结果,也就无法进一步的优化它们。

IonMonkey提供了一个全新的框架,使得我们可以做到这一点。它可以分成以下三步:

  1. 将JavaScript翻译成中间表示(IR);
  2. 运行多种算法优化IR;
  3. 将IR翻译成机器码。

让我们开心的不仅仅是性能和可维护性的提升,而且使得未来的JS编译器研究更加的简便。现在,有了IonMonkey,你就能够写一个新的优化,插入到流水线中,看看效果如何了。(译注:估计是受到了LLVM的启发?)

性能测试

IonMonkey针对的是长时间运行的程序,对于短程序还是用JaegerMonkey。我(David Anderson)在我跑着Windows 7专业版的MAC Pro笔记本上(译注1)运行了Google的V8基准测试和Kraken基准测试,性能提升了26%。Firefox 17运行了2602ms,Firefox 18运行了1921ms。效果如下图所示,越高越好。

IonMonkey-Kraken-result

Kraken基准测试结果

Google V8测试上Firefox 15得分为8474,Firefox 17得分为9511.Firefox 18得分最高,为10188,比Firefox 17快7%,比Firefox 15快50%。

V8基准测试结果

我们还有很多的工作需要去做。未来的一段时间我们将继续对IonMonkey进行测试,包括基准测试和真实的程序。

团队

对于我们而言IonMonkey最酷的部分就是我们是一个高度协作的团队。2011年6月的时候我们创建了一个大概的计划,然后估计大概需要一年的时间完成。我们招了四个实习生——Andrew Drake, Ryan Pearl, Andy ScheFirefox , 和 Hannes Verschore ——他们都参与实现了IonMonkey的核心组件,现在代码库中还有他们的代码。

2011年8月下旬我们开始组建全职团队,包括Jan de Mooij, Nicolas Pierron, Marty Rosenberg, Sean Stangl, Kannan Vijayan,还有我自己。(还有原SpiderMonkey开发者Chris Leary,2012年暑期实习生Eric Faust)。过去一年中我们齐头并进,搭出了总体的架构,确保其设计和代码质量都达到了最好,并且确实提升了JS的性能。

感谢我们所有的团队成员,大家为了一个目标一起合作的感觉太棒了。

技术

未来的几周我们将会发一些帖子介绍IonMonkey的主要组成以及工作原理。简而言之我将着重介绍IonMonkey中现有的优化技术:

  • Loop-Invariant Code Motion (LICM)(循环不变量外提);
  • Sparse Global Value Numbering (GVN), (稀疏全局值编号?);
  • Linear Scan Register Allocation (LSRA), 线性扫描式寄存器分配算法;
  • Dead Code Elimination (DCE), 死代码删除;
  • Range Analysis; 边界分析(译注2);

另外,我想指出IonMonkey能够运行在所有的Tier-1平台(译注3)上。编译器架构在设计上考虑了平台移植性的问题,大多数平台无关的代码都被抽取了出来,基本上只有汇编器是需要平台相关的。我们对此深感自豪。

何时,何地?

IonMonkey将在Firefox 18默认开始,Firefox 18现在是Firefox Nightly状态,将在10月8号变成Aurora,在11月10号进入beta版本。

作者注1:TM其实是有一个中间层额,但是能力非常的有限(limited),无法处理after-the-fact类型的优化。

译者注1:这个配置,想起来“普通青年Thinkpad+Windows,文艺青年Mac Pro + Mac OS……”

译者注2:参见Ryan Pearl和Michael Sullivan的这篇论文(PDF)

译者注3:Tier-1平台包括以下配置

  • Android Linux/ARMv7 and ARMv6 (gcc)
  • Linux/x86 and x86-64 (gcc)
  • OS X/x86 and x86-64 (clang)
  • Windows/x86 (msvc)

 

IonMonkey并入Mozilla-Central主分支

September 12th, 2012 No comments

根据Firefox JS Engine邮件列表中的这封邮件(墙),Mozilla的(第三个)JavaScript编译器IonMonkey已经基本成熟,在昨天并入了Mozilla-Central主分支。在更新了mozilla代码库之后能够看到js/src目录下新增加了一个“ion”目录,里面包含了IonMonkey的代码。

目前IonMonkey目录中包含了148个文件,其中C++头文件91个。代码共43613行。

使用hg命令可以看到是Ehsan Akhgari(博客)进行的合并:
changeset: 106839:d50bf1edaabe
parent: 106838:7612ff8a7fce
parent: 106791:fdfaef738a00
user: Ehsan Akhgari <ehsan AT mozilla.com>
date: Tue Sep 11 16:38:44 2012 -0400
summary: Merge IonMonkey into mozilla-inbound

目前IonMonkey已经能够在Firefox中默认使用,但是单独编译的JS Shell还无法启用,虽然在测试的时候可以用“–ion”(默认开启)和“–no-ion”来开启或关闭IonMonkey。

IonMonkey是Mozilla开发的下一代JS编译器,主要的设计目标有两个

  1. 良好的工程设计,能够方便的添加新的优化;
  2. 允许为了生成高效的代码而进行的Specializaion。

关于IonMonkey的介绍可以看这里这里,和这里

LLVM 3.0 发布

December 16th, 2011 No comments