V8是如何执行一段JS代码的


V8是如何执行一段JS代码的

编译器(Compiler),解释器(Interpreter),抽象语法树(AST),
字节码(Bytecode),即时编译器(JIT)

编译器和解释器

编译型语言,经过 编译器 编译,生成机器能读懂的二进制文件,可直接运行.(C/C++,GO)

编译器:源代码 > AST > 中间代码 > (代码优化)二进制 > 直接执行
解释型语言,运行时 需要 解释器 对程序进行动态解释和执行(JS,Python)
解释器:源代码 > (词法分析/语法分析) AST > (词义分析) 字节码 > 解释执行
前两步都是 词法分析/语法分析 生成SAT, 词义分析 生成 中间代码(字节码)
解释型语言生成字节码后就靠解释器执行了,字节码面向解释器,解释器驱动CPU
解释器就是JAVA里的虚拟机,一套代码,不同解释器就能面向不同计算机.

V8如何执行一段JS

V8 同时具有 Ignition解释器TurboFan编译器

第一步,将源代码转换为 抽象语法树,并生成 执行上下文

AST抽象语法树

高级语言 供开发者理解, AST语法树 供 编译器或解释器理解

高级语言 编译过程中 会生生成一个 AST (JS:和执行上下文)

AST 类似于 可执行代码的结构化表示, 编译器或解释器 的后续工作都依赖于AST

AST是一种非常重要的数据结构,Babel可以将ES6代码转换为ES5代码,
核心原理就是, ES6 转 AST, AST 转 ES5的AST,ES5的AST 转 JS源码
ESLint 检查JS编写规范,也是 JS 转 AST,利用AST检查代码规范

AST的生成,分为两个阶段

tokenize分词,词法分析

将源代码拆解为 token,指语法上 不可再分的 最小单个字符或字符串,
var(关键字keyword) myName(标识符identifier) =(token:赋值assignment) “罗紫宇”(字符串Literal),
四个都是token,并且代表的属性还不一样

parse解析,语法分析

token 数据根据语法规则转换为 AST

如果存在语法错误,在这一步会终止,并抛出”语法错误”
这之后会生成该段代码的 执行上下文

第二步,生成字节码

字节码

字节码 介于 AST 和 机器码 之间,需要通过解释器将其转换为机器码才能执行.

最初的V8 直接将AST转换为机器码,执行效率高,但是机器码内存占用太高

执行代码

Ignition解释器 逐行执行字节码,

热点代码,被重复执行多次的代码,TurboFan编译器会将热点代码编译为高效的机器码

字节码+解释器+编译器,Java/Python 的虚拟机也是基于此实现的,称为即时编译(JIT)

V8 对此的具体实现,就是 Ignition 解释执行代码,并在发现 部分代码变热时,
TurboFan 把热点代码转换为机器码,保存起来下次使用

总结

  1. 源代码经过 词法分析/语法分析 生成 AST执行上下文

  2. Ignition解释器 逐行解释执行代码 ,

  3. 期间碰见被多次执行的代码,则通过 TurboFan编译器 编译优化成 执行效率更高的 机器码,以便后续调用


文章作者: 罗紫宇
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 罗紫宇 !
  目录