什么是V8

一个接受Javascript代码,编译代码然后执行的C++程序,编译后的代码可以在多种操作系统多种处理器上运行

主要工作

  • 编译js代码
  • 处理调用栈
  • 内存分配
  • 垃圾的回收

重要组件

大部分js引擎在编译和执行js代码,都会用到三个重要的组件

  • 解析器:负责将JS源代码解析成抽象语法树(AST)
  • 解释器: 负责将AST解释成字节码bytecode,同时解释器也有直接解释执行bytecode的能力
  • 编译器:负责编译出运行更加高效的机器代码

V8 5.8以前

v8 5.8之前没有解释器,有两个编译器。
JS有解析器解析后生成抽象语法树AST,然后有Full-codegen编译器直接使用AST来编译出机器代码,而不进行中间转换。
Full-codegen编译起也被称为基准编译器,因为它生成的是一个基准未被优化的机器代码。这样做的好处是,当我们第一次执行js的时候,就是直接使用的高效的机器代码。因为没有中间的字节码产生,就不需要解释器。
当代码运行一段时间后,V8引擎中的分析线程,收集了足够的数据,来帮助另一个编译器Crankshaft来做代码优化。
然后需要优化的源码重新解析生成AST,然后CrankShaft根据生成好的ASt再生成优化后的机器代码,来提升运行的一个效率。所以CankShaft又成为优化编译器。

javascript怎么编译 js文件用什么编译_编译javascript的工具

缺点

  1. 机器码占用大量内存
  2. 缺少中间层机器吗,无法实现一些优化策略
  3. 无法很好的支持和优化JS的新语法特性

优化后的V8

语法树的解析还是基本保持一致的,但在获得抽象语法树之后,v8引擎加入了解释器Ignition,语法树通过解释器Ignition生成了bytecode字节码,此时AST就被清除掉了,释放内存空间,生成bytecode直接被解释器执行,同时生成的bytecode将作为基准执行模型,字节码更加简洁。生成的bytecode大小相当于等效的基准机器代码的25到50%左右。

在代码不断运行过程中,解释器收集到了很多可以用来优化代码的信息,比如变量的类型、那些函数执行的频率较高,这些信息被发送给编译器TruboFan,编译起TruboFan会根据这些信息来编译出经过优化的机器代码。

优化的机器码也有可能被反向编译为字节码,这个过程叫deoptimization

javascript怎么编译 js文件用什么编译_开发语言_02

优化策略

  1. 函数只声明未被调用,不会被解析成AST
  2. 函数只被调用一次,bytecode直接被解释执行
  3. 如果函数被调用多次,可能会被标记为热点函数,可能会被编译成机器代码

优点

  1. 由于不需要直接编译成机器码,而是使用了中间层的字节码,字节码生成速度远远大于机器吗,所以网页初始化解析执行js的时间缩短了
  2. 在生成的优化机器代码时,不需要再从源码开始编译,而是直接使用字节码编译。而且需要deoptimization时,只需要回归到中间层字节码解释执行就可以了