阅读 118

V8引擎系列(1):interpreter/compiler pipeline

本系列会对v8相关做一下整理,分为以下四部分

  1. interpreter/compiler pipeline

包括从源码经过解释和编译的流程,主要是解释器Ignition,优化编译器TurboFan,无优化编译器Sparkplug,以及中间代码bytecode

  1. object model

包括v8为了加快属性访问进行的优化,主要是Shape, Inline Cache, and ValidityCell

  1. memory structure and gc

包括在v8中的内存结构和垃圾回收算法,主要是垃圾回收过程和parallel, incremental and concurrent相关策略。

  1. 基于v8的代码优化方法和内存泄漏

js引擎通用工作流程

image.png

  1. 整个流程从我们写的源码开始,解释器将源码解析为AST
  2. 解析器基于AST生成中间代码bytecode,并解释执行
  3. 为了更快的执行,编译器将bytecode以及相关profiling data编译为执行更为高效的机器代码。

在具体的bytecode到最终的机器代码过程,不同js引擎会稍有不同,比如SpiderMonkey先后有两个编译器处理。

理解bytecode

bytecode是编译过程中与机器无关的中间代码。如果bytecode的设计和cpu的计算模型一样,则更容易编译成机器码,因此解释器通常是register 或 stack machines,在v8中的解释器Ignition就是一个带累加寄存器的register machine

bytecode 可以通过解析器直接解释执行,但效率较差,具体细节可以参考 DLS Keynote: Ignition: Jump-starting an Interpreter for V8

引入bytecode的原因是bytecode生成的速度比机器码生成的速度快,而且同样的源码处理后占用的内存小。 后面引入一个或多个编译器的原因是机器码的运行速度比bytecode快。

v8中的工作流程

在v8中,解释器是Ignition,在执行bytecode时收集profiling data,当一个函数变hot后(比如因为频繁执行),bytecode和profiling data传递给编译器TurboFan,编译优化为机器代码执行。

以上说的是之前的方案,实际的使用过程中,尽管TurboFan速度很快,但对于js初始执行的性能,编译器没机会进行优化,而解释器Ignition尽管也很快,但其有一些开销无法避免,比如bytecode解码的开销。 因此在当前流程中又引入了一层新的编译器:Sparkplug。

image.png

Sparkplug在设计上兼容Ignition的stack frames等(改造较小,但运行快),且没过多优化(编译时间短),将v8在real-world benchmarks的性能提高了5–15%。
Sparkplug在Chrome 91中可用。

参考

文章分类
前端
文章标签