字节码与二进制的“样貌”

上节内容 从源码到抽象语法树可视化 我们演示了什么是抽象语法树,相信当别人再向你提到它的时候,脑海中一定能想到它的“面貌”。对于 JavaScript 引擎(文章提到的都是 V8)来说,把「JavaScript 代码」转换成抽象语法树来说是基本的操作,后面还有好多要做的事情。这就好比你做菜的时候,现在只是把菜洗好了,后面还需要经过很多道手续,你才能吃上可口的饭菜。我先丢两张图给大家,看不懂没关系,学习是一个循序渐进的过程。我们今天主要学懂 ByteCode(字节码) 和 Mechine Code(机器码)。

字节码与二进制的“样貌”_第1张图片

字节码与二进制的“样貌”_第2张图片

V8 是谷歌开源的 JavaScript 引擎,被用于 Chrome 和 Node.js ,主要由上图中的一些「零件」组成,不同「零件」的分工不同,犹如炒菜的时候盘子、锅、勺子、铲子的作用,分工明确。

程序最终会被 CPU 执行,不同架构 CPU 提供的指令是不同的,而我们写的一套代码需要跑到不同架构的 CPU 上,这就需要 JavaScript 引擎来做这件事情。最初的时候 V8 直接通过 AST 生成对应机器码,后来爆出一堆问题,比如内存占用大、启动时间长等。

为了解决直接生成机器码的缺点,引入了字节码(图中的 ByteCode)。当别人问你什么是字节码的时候,你脑海中需要捕捉到一个“面貌”。从图中可以看到 ByteCode 是通过 Ignition 生

那什么是字节码呢?能不能看到代码执行的字节码呢?

字节码是机器码的(二进制)一种抽象,你可以把它理解为一种到机器码的中间码。由字节码转换成机器码非常容易。我们看一段代码被转换成字节码的“面貌”(注:只有函数被调用时才会生成字节码,下面的代码如果不调用 lefex 函数,将不会生成字节码):

function lefex(name, age) {
    var lef_name = name;
    if (lef_name) {
        lef_name = 'suyan work again';
    }
    let lef_age = age;
}
lefex();

通过 node 添加参数 --print-bytecode 生成字节码:

node --print-bytecode bcode2.js > ./test.txt,生成的字节码如下,是不是有一种汇编的感觉:

字节码与二进制的“样貌”_第3张图片

V8 提供了下面这些字节码指令:

字节码与二进制的“样貌”_第4张图片

那机器码又长什么样子呢?通过 node 加参数 --print-code 运行 JavaScript 文件:

node --print-code bcode2.js > ./tcode.js

效果如下,我只截取了部分图:

字节码与二进制的“样貌”_第5张图片

关于 V8 的更多介绍,可以查看 V8 的官网,有很多内容。我把认为不错的资料下载下来了(需要梯子)。你可以在公众号对话框输入 v8 即可获取下面的学习资料。

字节码与二进制的“样貌”_第6张图片

字节码与二进制的“样貌”_第7张图片

这两节的内容主要让你在脑海中对抽象语法树、字节码、机器码有一个认识。大家加油。


推荐阅读:

https://blog.fundebug.com/2019/07/16/how-does-v8-work/

https://v8.dev/blog/launching-ignition-and-turbofan

https://v8.dev/docs/ignition

https://v8.dev/docs/turbofan

https://v8.dev/blog/turbofan-jit

https://link.medium.com/zbwcpgkyc3

你可能感兴趣的:(字节码与二进制的“样貌”)