通过将JavaScript转换成LLVM IR代码并在随后对其进行重量级优化,苹果将Safari JavaScript引擎Nitro的速度提升了35%。
\根据webkit.org上的一篇博文,对内部的JavaScript字节码,WebKit以前有三个级别的优化,每个级别都是在运行时使用,依据是要在优化代码段所需的时间和这样做的好处之间取得平衡:
\- LLInt(Low Level Interpreter)——这是一个字节码解释器而不是编译器,它在优化方面做的工作很少。每个函数调用都会通过LLInt处理,如果它包含一个被调用超过了100次的语句,或者函数本身被调用超过6次,那么它会被传递到下个优化级别,即Baseline JIT。\
- Baseline JIT——这是一个简单的JIT,创建的代码执行速度比LLInt快,但它不包含重量级优化。同样,如果发现一个语句执行超过1000次,或者一个函数被调用超过66次,那么编译会传递到下一个优化级别,即DFG JIT。借助“栈上替换(On-Stack Replacement,OSR)”,可以在运行一条语句后切换编译器。\
- DFG JIT(Data Flow Graph JIT)——直到现在,该编译器负责Safari的性能,但只用于需要更多CPU的代码段,因为代码优化需要时间。\
为了进一步提升Nitro的性能,苹果决定将LLVM引入优化链。Chris Lattner是LLVM编译器基础架构的原作者和负责人,他为苹果工作,领导着开发工具部门,苹果此举可能是由他推动的。这个第四层名为FTL JIT(Forth Tier LLVM),它是一个C++模块,最终使用LLVM进行低级别优化。为此,一个函数的字节码通过两个中间阶段转换成LLVM IR——“连续传递风格(Continuation-Passing Style)”(CPS)和“静态单一赋值(Static Single Assignment)”(SSA)——旨在将原先的动态代码转换优化成静态代码,并随后使用LLVM编译器进行处理。这是LLVM第一次用于一门动态语言的剖析制导编译,该做法需要在LLVM中进行若干深层次的修改,据Filip Pizlo说:
\\\将LLVM JIT基础架构用于一门动态语言的剖析制导编译,WebKit FTL JIT是第一个这样做的重点项目。为此,我们需要在WebKit和LLVM中做若干重大修改。与我们现有的JIT相比,LLVM编译代码所需的时间明显更多。WebKit使用了一个复杂的分代垃圾收集器,但LLVM并不支持侵入式垃圾收集算法。性能剖析驱动的编译意味着我们可能在函数运行时调用一个优化编译器,而且我们可能在一个循环的中间将函数的执行转换到经过优化的代码;据我们了解,FTL是第一个为将“热循环(hot-loop)”转换到经LLVM编译的代码做栈上替换的编译器。最后,LLVM先前不支持自修改代码和反优化技巧,而我们依赖它们处理动态代码。
\
苹果做这方面的工作已有一年,他们取得了什么成果呢?据Pizlo说,Safari在Richards基准测试中比DFG快38%,在若干asm.js基准测试中平均快35%。与Chrome或者Firefox上的Octane基准测试相比如何,尚有待观察。Pizlo补充说“有关FTL的工作才刚刚开始——我们仍然需要扩大FTL能够编译的JavaScript操作集,它还有性能潜力可挖。”
\FTL JIT刚刚提交到WebKit主干,变更集编号为167958,读者可以使用WebKit每日构建版对其进行测试。
\