Open-Source Wikis

/

Ruby

/

JIT compilers

ruby/ruby

JIT compilers

Ruby ships two just-in-time compilers, both written in Rust and both linked statically into the interpreter at build time:

  • YJIT (yjit/) — Yet-Another-JIT. A method-based JIT that uses Lazy Basic Block Versioning. Production-grade since Ruby 3.2 (when it was rewritten from C to Rust). Targets x86_64 and arm64.
  • ZJIT (zjit/) — A newer JIT with a higher-level IR (HIR/LIR) and an offline-style optimizer. Under heavy active development as of this snapshot.

Both JITs are optional — pick at configure time:

./configure --enable-yjit --enable-zjit

At runtime, pick at most one with --yjit or --zjit. They observe iseqs running in the VM and, when one becomes hot, generate native machine code that the VM jumps into instead of interpreting.

graph LR
    iseq[Compiled iseq] -->|interpret| vm[VM dispatch loop]
    vm -->|hot threshold| trigger[JIT trigger]
    trigger -->|--yjit| yjit[YJIT codegen]
    trigger -->|--zjit| zjit[ZJIT codegen]
    yjit -->|machine code| jit_call[JIT entry]
    zjit -->|machine code| jit_call
    jit_call -->|on side exit| vm

The shared host code:

  • The build orchestrates Rust via yjit/yjit.mk and zjit/zjit.mk, called from the main Makefile.
  • Cargo.toml at the repo root is a workspace containing yjit, zjit, and a tiny jit crate.
  • yjit.c / zjit.c are the C entry points; everything beyond them is Rust.
  • yjit.h / zjit.h declare the C-callable interface.
  • yjit.rb / zjit.rb provide Ruby-level introspection (RubyVM::YJIT.runtime_stats, RubyVM::ZJIT.dump_*).

Pages in this section

Page Topic
yjit.md Lazy basic-block versioning JIT
zjit.md IR-driven JIT

History

The journey to Ruby's current JIT story:

  • 2.6 (Dec 2018): MJIT — a process-based JIT that wrote C and shelled out to GCC/Clang. Modest speedups; high startup cost.
  • 3.1 (Dec 2021): YJIT merged, originally written in C, by Maxime Chevalier-Boisvert at Shopify.
  • 3.2 (Dec 2022): YJIT rewritten in Rust. First Rust code in CRuby. MJIT begins deprecation.
  • 3.3 (Dec 2023): MJIT replaced by RJIT (a Ruby-implemented JIT, also experimental). RJIT later removed.
  • 3.4 / 4.0 (Dec 2024 / 2025): ZJIT lands.

This is the first time CRuby has shipped two JITs in parallel.

Choosing a JIT

Use YJIT if Use ZJIT if
You want a stable, mature JIT with years of production use You're testing the bleeding edge
Your workload is method-call-heavy with relatively stable types Your workload benefits from cross-method optimization
You're on a release before ZJIT is GA You want to give feedback on the next-gen design

Most users today should reach for --yjit.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

JIT compilers – Ruby wiki | Factory