V8 — JavaScript 引擎内核

Chrome 和 Node.js 的 JavaScript 引擎——Ignition 解释器 + TurboFan JIT + Orinoco GC + libuv 事件循环。

概念

V8 是 Google 开发的高性能 JavaScript 引擎,用 C++ 编写。它的”内核”从不直接执行 JS 源码——而是先编译为字节码 (Ignition),再将热点路径编译为机器码 (TurboFan)。V8 内核对”动态类型语言如何接近静态语言性能”这个问题给出了产业级答案。

核心组件

组件职责关键概念
Ignition字节码解释器, 生成并执行 V8 字节码accumulator register
TurboFan优化 JIT 编译器, 字节码 → 机器码sea-of-nodes IR
隐藏类 (Hidden Classes)对象形状的动态优化Map 对象, 转换链
Orinoco GC并行标记 + 增量清除 + 压缩分代 + 并发
IsolateV8 虚拟机实例 (独立堆)线程安全隔离
libuv 事件循环提供异步 I/O, 定时器, 信号epoll/kqueue/IOCP

Ignition 字节码解释器

// JS 源码
function add(a, b) {
 return a + b;
}
add(3, 4);
 
// 内部编译为 Ignition 字节码 (简化表示)
// function add:
// LdaUndefined // accumulator = undefined (预检查)
// Ldar a1 // accumulator = a1
// Add a2, [0] // accumulator += a2, 反馈槽 0
// Return // 返回 accumulator
//
// 调用:
// LdaSmi [3] // accumulator = 3
// Star r0 // r0 = accumulator
// LdaSmi [4] // accumulator = 4
// Star r1 // r1 = accumulator
// LdaGlobal [add] // accumulator = add
// Call1 r0, r1 // 调用 add(r0, r1)

隐藏类 (Hidden Classes)

// 与 C++ vtable 类似但动态创建
var o = {}; // o.Map = M0 (空对象形状)
o.x = 5; // o.Map = M1 (拥有 int x) [M0 --(.x)--> M1]
o.y = "hello"; // o.Map = M2 (拥有 x, y) [M1 --(.y)--> M2]

var p = {}; // p.Map = M0 (复用!)
p.x = 10; // p.Map = M1 (复用!)
p.y = "world"; // p.Map = M2 (复用!)

// 如果两个对象有相同的隐藏类 (Map), 说明它们属性名、顺序、类型一致
// TurboFan 就可以像访问 C 结构体一样在固定偏移量处读写属性
// 这就是 V8 为何快: 把动态对象当静态结构体优化

TurboFan JIT 编译

Ignition 收集类型反馈 (Type Feedback):
 add(3, 4) → 两个参数都是 Smi (小整数)
 add(3.2, 4.1) → 两个参数都是 Float64

当调用 add 足够多次 (热点):
 TurboFan 基于类型反馈生成优化后的机器码:
 IF 两个参数都是 Smi:
 result = a + b (整数加法, 一条 CPU 指令)
 CHECK overflow
 RETURN result
 ELSE:
 DEOPTIMIZE → 退回到 Ignition (去优化)

去优化 (Deoptimization):
 当假设被打破时 (例如 add 收到了字符串参数)
 TurboFan 生成的代码检测到类型不匹配
 丢弃编译的机器码, 从 Ignition 字节码重新继续执行

Orinoco GC

阶段算法是否并发
标记 (Mark)从 roots 出发追踪可达对象并发 + 并行
清除 (Sweep)释放不可达对象增量 (与 mutator 交替)
压缩 (Compact)移动存活对象消除碎片STW (极短)
新生代 (Young Gen)Scavenge (Cheney 算法)并行