1.4 Node.js与V8引擎
V8引擎采用的是即时编译技术(JIT),直接将JavaScript代码编译成本地平台的机器码。从宏观上看,V8引擎编译过程如图1-3所示。
在该过程中,首先将源码编译成抽象语法树,然后再编译成为本地机器码,并且后一个步骤只依赖前一个步骤。这种编译方式和其他的编译器有很大不同。例如,Java语言编译器是先把源码编译成字节码,再给JVM执行。JVM根据字节码进行优化执行后,交给JRE(Java环境)运行,相比这种运行方式,V8引擎省去了一个步骤,即程序开始运行后,直接解释代码并交给CPU运行。但是这种缺少字节码的运行方式,使代码优化的方式变得更加困难。
图1-3 V8引擎编译过程(宏观)
当JavaScript代码直接交给浏览器或Node执行时,底层CPU并不认识相关的代码,它只认识自己的指令集。指令集对应的是汇编代码,其代码如下:
但是要用汇编语言来写,大概需要300行代码。编译后的汇编代码如图1-4所示。这些汇编代码主要用于执行CPU的相关指令。这时就需要使用JavaScript引擎编译成汇编代码,交给CPU执行。
在众多的JavaScript引擎中,最重要的是V8引擎。
V8引擎由许多子模块构成,是一个相当复杂的项目,其编译过程如下。
图1-4 编译后的汇编代码
◎Parser(分析器):负责将JavaScript源码转换为Abstract Syntax Tree(AST)。
◎Ignition(解释器):负责把AST转换为Bytecode,并进行解释执行;同时收集TurboFan优化编译器所需要的信息,如函数参数类型等。
◎TurboFan(编译器):利用Ignition收集的信息,把Bytecode转换成优化的汇编代码。首先,获取到JS代码,然后将JS代码转换为AST语法树,AST语法树再转换为字节码,字节码直接送入解释器执行,同时监控模块识别是否是热代码,如果是热代码,将会在下一步优化编译器的时候被修改、被优化。经过几次的修改优化,最终形成机器码,送入CPU执行,并输出结果给用户。V8引擎的运行流程如图1-5所示。
图1-5 V8引擎的运行过程