Ruby Matz 合并了我给 Spinel 的一个 PR,顺便介绍下这个 Ruby AOT 编译器

femto · 2026年09月24日 · 44 次阅读

给 matz/spinel 提了个 PR,Matz 合了 (#4899)。借这个机会介绍一下 Spinel —— 国内讨论得不多,但我觉得挺值得一看。

Spinel 是什么

Matz 在写的 Ruby AOT 编译器:把 Ruby 源码编译成独立的原生可执行文件,不需要 Ruby 运行时。

管线是这样的:

Ruby (.rb)
   │
   ├─ parse          libprism(Prism 以 C 库链入)
   ├─ analyze        全程序类型推断,走到不动点
   ├─ codegen        生成一个 C 文件
   └─ cc -O2         系统 C 编译器 + 运行时库
   │
   └─→ 原生二进制,无运行时依赖

几个我觉得有意思的点:

编译器本身是单个自包含的 C 二进制。 解析、推断、生成 C、调用 cc,全在一个进程里完成,中间没有序列化步骤 —— codegen 直接读 analyze 刚推断出的类型。

它自举过。 按 README 的 History:最早 C 写的,后来用 Ruby 重写,再后来用一个能编译自己的 Ruby 子集重写。现在 master 回到了 C 实现 (构建快得多,输出等价),自举的那版保留在 self-host 分支。

关键在"全程序"。 因为能看到整个程序,Integer 可以落成裸的 intptr_t 而不是装箱对象,方法调用能去虚化,死代码能整块删掉。这是 JIT 很难做到的 —— JIT 只能看到已经跑热的那部分。

性能

README 里的数字 (2026-09-17 测,28 个 benchmark,32 核 Linux,gcc 13.3,基线 CRuby 4.0.4):

  • 对 --yjit 几何平均 ~8.5x
  • 对解释器 ~15.2x

抽几行:

Benchmark Spinel Ruby 4.0.4 + YJIT
mandelbrot 18 ms 939 ms 938 ms
matmul 6.1 ms 200 ms 201 ms
ao_render(光追) 70 ms 1646 ms 611 ms
json_parse 28 ms 212 ms 133 ms
csv_process 95 ms 491 ms 396 ms

试一下

git clone https://github.com/matz/spinel && cd spinel
make deps && make

cat > hello.rb <<'RUBY'
def fib(n) = n < 2 ? n : fib(n - 1) + fib(n - 2)
puts fib(34)
RUBY

./spinel hello.rb && ./hello

还有个 cargo/mix 风格的项目工具 spin(spin new / spin add / spin test / spin build),依赖是被编译进二进制的源码树,没有运行时加载。

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请 注册新账号