【v8】v8处理js的流程分析

发布时间:2024年01月18日

简言

记录下学习v8处理js流程分析的过程。
V8 是 Google 开源的 JavaScript 引擎,被广泛应用于各种 JavaScript 执行环境,比如 Chrome 浏览器、Node.js、Electron 等。

处理流程

javascript是一个高级语言,执行它流程就是从人能看懂的代码转成机器能读懂的代码并执行的过程。
v8执行javascript代码的流程如下:
在这里插入图片描述

  1. 代码解析(parse)转成AST(抽象语法树)。
  2. v8的Ignotion(解释器)将AST解释成字节码,并一边解释一边执行,将多次执行的代码标记为热代码(hot code),并将运行信息反馈给TurboFan(编译器)。
  3. TurboFan(编译器)根据运行信息优化编译字节码,然后生成优化后的机器码,后面再次使用这些代码就会直接使用机器码执行,若机器码不符合将会逆向生成字节码。

这种在运行时编译代码的技术也被称为 JIT(即时编译),通过 JIT 可以极大提升 JavaScript 代码的执行性能

代码解析

v8通过parse模块和PreParse模块将代码转成AST(抽象语法树)。
转换过程有词法分析和语法分析。
一般可以直接执行的代码由parse模块解析,当代码中有很多不是可以立即执行的代码(例如函数)时,v8会进行PreParse(预解析),只验证代码是否合法和函数声明(确定有这个东西),不生成AST,只有在使用时才会进行解析,以优化解析性能,缩短解析运行时间。

词法分析

我们写的js文件其实是文本文件,保存的是字符串。扩展名为js代表它是保存符合js代码规则的文本文档,可以使用js的词法分析进行分析。
这一步将字符串(字符流)解析成tokens(js语法上最小单位,可以是单个字符,也可以是字符串),v8中的scanner是词法解析器。

语法分析

得到tokens后,下一步就是语法分析,语法分析是将tokens转换成AST(抽象语法树)。
ast是一个有层次的数据结构,它是承接源代码和解释器的中间性代码。

AST类似于这种:
js代码

let name = 'zsk6';

我是在这里ast转换通过acorn将js转换ast:

{
  "type": "Program",
  "start": 0,
  "end": 18,
  "body": [
    {
      "type": "VariableDeclaration",
      "start": 0,
      "end": 18,
      "declarations": [
        {
          "type": "VariableDeclarator",
          "start": 4,
          "end": 17,
          "id": {
            "type": "Identifier",
            "start": 4,
            "end": 8,
            "name": "name"
          },
          "init": {
            "type": "Literal",
            "start": 11,
            "end": 17,
            "value": "zsk6",
            "raw": "'zsk6'"
          }
        }
      ],
      "kind": "let"
    }
  ],
  "sourceType": "module"
}

在这一阶段可以进行以下操作:

  • 代码分析:编译器或解释器对AST进行语义分析,以检查源代码中的语义错误。这包括类型检查、符号解析、作用域分析等。
  • 代码优化: 可以对ast进行各种优化,例如删除无用代码、提前进行常量计算等。

Ignition解释器

Ignition是V8解释器,负责执行字节码,它的输入一个字节码列表(bytecode array),输出是程序的执行结果。
在解释字节码之前需要遍历ast树生成字节码。

ast生成字节码

字节码(bytecode)通常指的是已经经过编译,但与特定机器代码无关,需要解释器转译后才能成为机器代码的中间代码。
通过有限状态机遍历ast树和提前定义好的宏定义模板后生成字节码列表,供Ignition解释执行。

执行字节码

gnition是基于寄存器的解释器,这些寄存器(除累加寄存器外,它被很多字节码作为隐式的输入输出寄存器,它是物理寄存器)是V8维护的虚拟寄存器,用栈实现,不是物理寄存器。在执行之前需要做些准备,包括构建堆栈、参数入压等,然后逐个执行字节码。

TurboFan(编译器)

Turbofan 使 JavaScript 执行的更快,但也需要更多的编译时间,所以 V8 只对热点函数使用 Turbofan。
Turbofan 优化机制的核心思想是假定你后面再次使用代码时和前面的用法一致,这样就不需要各种判断以提升性能。
若后面调用和前面的用法不一致,将会逆向生成字节码,以便程序正确执行。

结语

结束了。

文章来源:https://blog.csdn.net/qq_43231248/article/details/135648469
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。