js(V8)引擎运行原理(下)

156 阅读3分钟

​持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第4天,点击查看活动详情

ignation模块(解释器/转化器)

作用:将ast抽象语法树转换成字节码(bytecode) 如果函数未调用,是不会转换成ast的

疑惑:为什么不直接转换成机器码呢?

因为当前程序运行环境可能不一样的,可能跑在mac本的Chrome浏览器上,也有可能跑在window本的Chrome浏览器上,也有可能跑在服务器linux的电脑的浏览器或node上,不同的环境有不同的cpu,不同的cpu可能又有不同的架构,不同的架构所执行的机器指令是不一样的(就不深入了,没实力)

解惑:由于存在环境可能不一样,所以很难知道到底转换成哪种机器指令(和java很像),所以这里将我们的代码转换成字节码(可以实现跨平台)

当要运行的时候,V8引擎会将字节码转换成对应的机器指令,字节码转换成机器码肯定比ast抽象语法树转换成字节码性能要好

字节码 ===> 汇编代码 ===> cpu要执行的机器指令

等等,还没完,还漏了一个TurboFan模块

TurboFan模块

觉不觉得字节码转换成cpu对应的机器指令也很费性能,比如一个函数,多次调用,我就要多次转换,一样的工作,重复执行,所以,TurboFan模块就来解决问题了

如何解决:

将我们多次调用的函数直接从字节码转换成对应的cpu机器指令并保存起来,等到被调用时直接执行指令,性能直接拉满(只执行少次的代码就不用进行转化了,浪费空间资源)

那么问题来了,它怎么知道这个函数被多次执行了?

是由ignation模块来进行收集信息,比如函数的执行信息,如果发现函数执行评频率非常高,就会把这个函数进行标记成hot(热函数),一旦是热函数就会由TurboFan模块进行转换成优化后机器指令(MachineCode)

不过这样还是有问题的

比如说这个函数是求和函数

function sum(num1, num2) {
    return num1 + num2
}

sum(20, 20)
sum(30, 30)
......
sum('20', 30)

本来是数字相加的,突然传来了一个字符串,字符串和数字相加是不同的指令的,又由于JavaScript是一门动态语言,不会对类型做检测,所以一开始是检测不到数据类型的变化的,导致最后那个字符串类型函数运行时机器指令不能用,就会通过Deoptimizayion(反向优化),把机器指令转换成字节码,在按照字节码的方式进行运行结果,

所以TypeScript代码比我们平时写的JavaScript代码性能稍微高一点