图解 Google V8
李兵
前盛大创新院高级研究员
立即订阅
3131 人已学习
课程目录
已完结 24 讲
0/4登录后,你可以任选4讲全文学习。
宏观视角 (2讲)
开篇词 | 如何学习谷歌高性能 JavaScript 引擎V8?
免费
01 | V8是如何执行一段JavaScript代码的?
JavaScript设计思想篇 (7讲)
02 | 函数即对象:一篇文章彻底搞懂JavaScript的函数特点
03 | 快属性和慢属性:V8是怎样提升对象属性访问速度的?
04 | 函数表达式:涉及大量概念,函数表达式到底该怎么学?
05|原型链:V8是如何实现对象继承的?
06|作用域链:V8是如何查找变量的?
07|类型转换:V8是怎么实现1+“2”的?
08|答疑:如何构建和使用V8的调试工具d8?
V8编译流水线 (8讲)
09 | 运行时环境:运行JavaScript代码的基石
10 | 机器代码:二进制机器码究竟是如何被CPU执行的?
11 | 堆和栈:函数调用是如何影响到内存布局的?
12 | 延迟解析:V8是如何实现闭包的?
13 | 字节码(一):V8为什么又重新引入字节码?
14|字节码(二):解释器是如何解释执行字节码的?
15 | 隐藏类:如何在内存中快速查找对象属性?
16 | 答疑: V8是怎么通过内联缓存来提升函数执行效率的?
事件循环和垃圾回收 (6讲)
17 | 消息队列:V8是怎么实现回调函数的?
18 | 异步编程(一):V8是如何实现微任务的?
19|异步编程(二):V8是如何实现async/await的?
20 | 垃圾回收(一):V8的两个垃圾回收器是如何工作的?
21 | 垃圾回收(二):V8是如何优化垃圾回收器执行效率的?
22|答疑:几种常见内存问题的解决策略
结束语 (1讲)
结束语 | 我的前端学习踩坑史
图解 Google V8
15
15
1.0x
00:00/00:00
登录|注册

14|字节码(二):解释器是如何解释执行字节码的?

李兵 2020-04-16
你好,我是李兵。
在上节我们介绍了 V8 为什么要引入字节码,这节课我们来聊聊解释器是如何解释执行字节码的。学习字节码如何被执行,可以让我们理解解释器的工作机制,同时还能帮助我们搞懂 JavaScript 运行时的内存结构,特别是闭包的结构和非闭包数据的区别。
字节码的解释执行在编译流水线中的位置你可以参看下图:

如何生成字节码?

我们知道当 V8 执行一段 JavaScript 代码时,会先对 JavaScript 代码进行解析 (Parser),并生成为 AST 和作用域信息,之后 AST 和作用域信息被输入到一个称为 Ignition 的解释器中,并将其转化为字节码,之后字节码再由 Ignition 解释器来解释执行。
接下来,我们就结合一段代码来看看执行解释器是怎么解释执行字节码的。你可以参看下面这段代码:
function add(x, y) {
var z = x+y
return z
}
console.log(add(1, 2))
在控制台执行这段代码,会返回数字 3,V8 是如何得到这个结果的呢?
刚刚我们提到了,V8 首先会将函数的源码解析为 AST,这一步由解析器 (Parser) 完成,你可以在 d8 中通过–print-ast 命令来查看 V8 内部生成的 AST。
[generating bytecode for function: add]
--- AST ---
FUNC at 12
. KIND 0
. LITERAL ID 1
. SUSPEND COUNT 0
. NAME "add"
. PARAMS
. . VAR (0x7fa7bf8048e8) (mode = VAR, assigned = false) "x"
. . VAR (0x7fa7bf804990) (mode = VAR, assigned = false) "y"
. DECLS
. . VARIABLE (0x7fa7bf8048e8) (mode = VAR, assigned = false) "x"
. . VARIABLE (0x7fa7bf804990) (mode = VAR, assigned = false) "y"
. . VARIABLE (0x7fa7bf804a38) (mode = VAR, assigned = false) "z"
. BLOCK NOCOMPLETIONS at -1
. . EXPRESSION STATEMENT at 31
. . . INIT at 31
. . . . VAR PROXY local[0] (0x7fa7bf804a38) (mode = VAR, assigned = false) "z"
. . . . ADD at 32
. . . . . VAR PROXY parameter[0] (0x7fa7bf8048e8) (mode = VAR, assigned = false) "x"
. . . . . VAR PROXY parameter[1] (0x7fa7bf804990) (mode = VAR, assigned = false) "y"
. RETURN at 37
. . VAR PROXY local[0] (0x7fa7bf804a38) (mode = VAR, assigned = false) "z"
同样,我们将其图形化:
从图中可以看出,函数的字面量被解析为 AST 树的形态,这个函数主要拆分成四部分。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《图解 Google V8》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(10)

  • leaf
    另外请问老师对jvm的字节码熟悉吗,能否推荐一些jvm字节码与v8字节码的比较的资料。目前看到的差异是1)基于栈和基于寄存器,2)v8字节码带了feedback vector。不知还有什么其他的差异。两者之间能否相互表示。openjdk里面自带的nashorn就是一个用java实现的js引擎,它是把js翻译成java字节码吗?

    作者回复: 主要因为JavaScript是动态的,而Java是静态的,所以V8需要对动态语言的特性做大量的优化,隐藏类、IC、和IC所使用的Feedback vector都是将动态语言静态化的一种手段。

    至于你说的nashorn,我的确不熟悉,所以我也不知道它具体的执行流水线。



    2020-04-17
    1
    2
  • code-artist
    老师我有一个疑问:'Ldar a1表示将寄存器中的值加载到累加器中' a1的值不是在栈里面吗?不是直接从栈中加载到累加器吗?

    作者回复: 这个是参数,存放在栈中,a0代表第一个参数,a1参数代表第二参数,参数an代表第n个参数,你可以把存放参数的地方也看成是存放在栈中的一块寄存器,参数寄存器。

    2020-04-18
    1
  • 灰的更高
    老师,我在这次的课件中看到了,小整型smi。我之前在看书的时候看到了v8的数据表示,书上说smi直接使用前32位进行数值表示,后32位为句柄且最后一位标记位是1,除了smi其他的类型都是存放的指针句柄最后一位是0,但是我不清楚这个其他类型存档指针是什么格式,然后又怎么样和咱们课程里面的内容联系在一起呢,麻烦您能简单介绍一下吗
    2020-05-13
  • champ可口可乐了
    [generated bytecode for function: add (0x02160824fe59 <SharedFunctionInfo add>)]
    Parameter count 3
    Register count 1
    Frame size 8
             0x21608250026 @ 0 : 25 02 Ldar a1
             0x21608250028 @ 2 : 34 03 00 Add a0, [0]
             0x2160825002b @ 5 : 26 fb Star r0
             0x2160825002d @ 7 : aa Return
    Constant pool (size = 0)
    Handler Table (size = 0)
    Source Position Table (size = 0)

    这是我的Mac平台输出的字节码,好像那2条无用代码被优化掉了。
    但是,函数开头没有出现 StackCheck,不知道为什么
    2020-04-19
  • Longerian
    v8生成的字节码,为什么先把第二个参数load到累加器里,v8 处理参数的顺序是倒序的吗?
    2020-04-19
    1
  • 木山
    老师下午好, 我来这里催加餐了(笑),
    2020-04-17
  • 一步
    解释器 执行字节码 ,是在解释器内部执行吗? 底层还需要把指令在放到 CPU执行 吗? 这里的 寄存器 是解释器内部的? 还是指CPU的寄存器?
    2020-04-16
    1
  • 一步
    在生成 作用域 那个图里面, 参数 x ,y 在堆中进行声明吗? 这个不应该也是在栈中的?
    2020-04-16
  • 踢车牛
    Frame size 8
       13 E> 0x3506cbf1f8c6 @ 0 : a5 StackCheck
       32 S> 0x3506cbf1f8c7 @ 1 : 25 02 Ldar a1
       33 E> 0x3506cbf1f8c9 @ 3 : 34 03 00 Add a0, [0]
             0x3506cbf1f8cc @ 6 : 26 fb Star r0
       46 S> 0x3506cbf1f8ce @ 8 : a9 Return

    字节码生成 5行,和老师的显示略有差异
    2020-04-16
  • qinsi
    基于栈的虚拟机实现简单,可移植性好;基于寄存器的虚拟机指令表达能力强,性能高,生成的字节码更短
    2020-04-16
    1
收起评论
10
返回
顶部