V8 是由谷歌收购并使用 C++开发并开源的JS虚拟机引擎,简单来说就是JS引擎。
为什么需要JS引擎?
CPU并不认识我们编写JS代码,不同的CPU只认识自己对应的指令集,所以需要JS引擎中的编译器和解释器将js代码编译成CPU认识的指令集,此外他还要负责执行以及内存的管理。
编译器和解释器?
机器不能直接理解我们写的代码,所以在执行程序前,需要将我们所写的代码翻译成机器能读懂的语言(二进制)。我们平时所编写的都是高级语言,高级语言分编译性语言和解释性语言。
解释性语言:专门的解释器在代码每次执行时对程序进行动态翻译和执行,执行效率低,方便程序移植,代表性语言为JS,Python等。
编译性语言:运用专门的编译器在代码执行前一次性编译成二进制文件,运行时直接运行该二进制文件,不需重新编译,执行效率高,缺点是一般无法移植到其他平台。代表性C/C++,Go等。
早期的V8
两个编译器
1. Full-codegen编译器
2. Crankshaft编译器
Full-codegen将JS源码编译生成机器码,在执行过程中,Profiler线程标记出热点函数交给Crankshaft进行代码优化。
随着技术的发展,对js性能要求越来越高,如今的V8引擎是解释器和编译器配合使用的,称为即时编译。
JIT(Just In Time Compiler,即时编译器):将执行频率高的方法或语句块通过JIT编译成本地机器码,提高代码执行效率。
V8执行JS的过程
- 将源代码转换为AST(抽象语法树)
- 词法分析:将源码拆成一个个词法单元(token),token指的是语法上不可能再分的,最小的单个字符或字符串
- 语法分析:通过上一步生成的token数据,根据语法规则转为AST,如果有错误,这一步会终止并抛出异常
- 解释器Ignition根据AST生成字节码并执行
(早期是直接转成机器码) - 标记重复执行的热点代码,将标记的代码通过Turbofan优化编译器编译成效率更高的二进制代码,再次执行此代码时执行的就是机器码,提升代码的执行效率
> AST:AST是一种数据结构,对于编译器和解释器,它们能理解的是AST。
字节码:高级语言转二进制代码的中间代码,提高解释型语言执行效率。
为什么增加字节码作为中间代码的转换?
- 移动端的流行和网页的复杂化,AST转机器码的过程中导致占用内存空间非常大
- 早期两个编译器需要针对不同CPU架构编写代码,而字节码作为中间代码不针对某个特定类型机器码
