为什么需要Javascript引擎?
随着JS承担的工作越来越多,早就已超越创造出的初衷(表单验证)的范畴,因此需要快速的解析和执行JavaScript脚本
V8引擎由此而生
JavaScript引擎主要功能:结合JS语言特性 和 本质 进行编译、执行
这里以Chrome V8为例
基本概要
V8是谷歌开源的
高性能的JavaScript和WebAssembly的引擎,由**C++**代码构成。
它被广泛的应用于Chrome和Node.js中
V8实现了ECMAScript and WebAssembly 规范,其可以独立运行也可以嵌入任意C++程序中
V8编译 和 执行 JavaScript源代码
- 处理对象的内存分配
- 回收不再需要的对象
V8的stop-the-world , generational, accurate garbage collector是V8高性能的关键
V8也如同JavaScript一样提供DOM、data types、operators、objects 和 function
原理
整体流程

首先V8引擎使用Parser经过 词法分析 、 语法分析 生成 Abstract Syntax Tree(抽象语法树)
这棵树是JavaScript代码语法结构的树形表示
与此同时,Ignitioin——解释器,生成语法树的bytecode(字节码)
TurboFan——编译优化器,最后将生成的bytecode 生成优化的机器码
bytecode是对机器码的抽象
最后将最后优化的bytecode交由CPU执行
parser生成语法树
空格——whitespace
在扫描下一个标记之前,会跳过所有空格,以跟踪是否出现了换行符。
然后循环继续扫描tokens 直到找到另一个不是Token::WHITESPACE的字符。
找到后,立马开始扫描相关的token,而不需要显式检查空格。
扫描标识符—Identifier scanning
JS中变量名称——最复杂,也是最常见的token
标识符开始于ID_Start,后面可选的跟上具有属性ID_Continue
但是,这样对ID_Start或者 ID_Continue开销将十分巨大, 我们可以采用缓存map(cache mapping)加快这一速度
关键字——keyword
V8使用Ignition流程图

关键词(Keyword)是语言中特殊的标识符
V8 Scanner 返回与标识符不同的标记
在扫描完成后,我们需要判断这是否是关键字
我们使用ASCII characters来表示可能的关键字的开始和继续(与ID_Start 和 ID_Continue)意义一致
因为关键字列表是静态的,因此我们使用hash计算一个完美的散列函数
V8 使用gperf 去计算这一函数。
Ignition解释器
V8构建了新的Ignition解释器,它以更少的内存开销 执行代码,并以更简单的脚本执行管道铺平了道路。
Ignition是一个寄存器,每个字节码都将其 作为输入和输出指定为显示寄存器操作数,而不是采用堆栈。
通过特定指定的寄存器操作数,来减小字节码的大小
由于许多 JavaScript 表达式涉及从左到右求值的操作链,因此这些操作的临时结果通常可以在整个表达式求值过程中保留在累加器中,从而最大限度地减少加载和存储到显式寄存器的操作的需要。
TurboFan编译器
TurboFan结合cutting-edge intermediate representation 和 multi-layered translation,从而生成比JIT更优的机器码
JavaScript 代码大多以未优化的形式进入编译器管道,并被翻译和优化为逐渐低级的形式,直到生成机器码。
设计的核心是sea-of-nodes internal representation (IR),它可以更加有效的重排和优化。
数值范围分析(Numerical range analysis)帮助TurboFan更好的理解数字运算代码
















