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 算法)并行