Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
ZJIT: The Ruby 4 JIT Compiler / Ruby Release 30...
Search
Takashi Kokubun
December 20, 2025
Programming
520
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
ZJIT: The Ruby 4 JIT Compiler / Ruby Release 30th Anniversary Party
https://rubyassociation.doorkeeper.jp/events/190436
Takashi Kokubun
December 20, 2025
More Decks by Takashi Kokubun
See All by Takashi Kokubun
Lightning-Fast Method Calls with Ruby 4.1 ZJIT / RubyKaigi 2026
k0kubun
3
3.4k
一度始めたらやめられない開発効率向上術 / Findy あなたのdotfilesを教えて!
k0kubun
4
3.1k
ZJIT: The Future of Ruby Performance / San Francisco Ruby Conference 2025
k0kubun
1
120
ZJIT: Building a New JIT Compiler for Ruby / REBASE 2025
k0kubun
0
130
Deoptimization: How YJIT Speeds Up Ruby by Slowing Down / RubyKaigi 2025
k0kubun
2
4.2k
YJIT Makes Rails 1.7x faster / RubyKaigi 2024
k0kubun
7
16k
Ruby JIT Hacking Guide / RubyKaigi 2023
k0kubun
2
11k
YJIT: Dive into Ruby's JIT compiler written in Rust / Rust.Tokyo 2022
k0kubun
2
2.3k
Towards Ruby 4 JIT / RubyKaigi 2022
k0kubun
3
12k
Other Decks in Programming
See All in Programming
フロントエンドとバックエンドで「1文字」を揃えよう
youkidearitai
PRO
0
210
DynamoDBには集計系のクエリがないけどなんとかしたい
musan
1
130
Datadog × OpenTelemetry 入門と実践のあいだ
kn_to_maxpno
1
150
キャリア迷子上等 ─ "ない道"は自分で作ればいい
16bitidol
3
1.4k
ローカルLLMを使ってB2Bサービスを作っていての学び
yaotti
0
140
Inside Stream API
skrb
1
640
The Arts and Crafts of Work in the AI Era — Toward Mastery in Software Development
kuranuki
1
720
Modding RubyKaigi for Myself
yui_knk
0
890
Lessons from Spec-Driven Development
simas
PRO
0
140
AIエージェントの隔離技術の徹底比較
kawayu
0
460
Javaの型とAI時代に型が大事な理由 / java types and type in AI era
kishida
2
110
密結合なバックエンドから TypeScript のコードを生成する
kemuridama
1
740
Featured
See All Featured
Deep Space Network (abreviated)
tonyrice
0
160
The untapped power of vector embeddings
frankvandijk
2
1.7k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.5k
Reflections from 52 weeks, 52 projects
jeffersonlam
356
21k
A brief & incomplete history of UX Design for the World Wide Web: 1989–2019
jct
2
390
Hiding What from Whom? A Critical Review of the History of Programming languages for Music
tomoyanonymous
2
840
Are puppies a ranking factor?
jonoalderson
1
3.5k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
34
2.8k
We Analyzed 250 Million AI Search Results: Here's What I Found
joshbly
1
1.3k
What's in a price? How to price your products and services
michaelherold
247
13k
The Illustrated Children's Guide to Kubernetes
chrisshort
51
52k
The Cost Of JavaScript in 2023
addyosmani
55
10k
Transcript
Ruby Release 30th Anniversary Party 2025 ZJIT: The Ruby 4
JIT Compiler Takashi Kokubun / @k0kubun
self • Takashi Kokubun (@k0kubun) • Shopify: Ruby JIT team
• Ruby committer: MJIT, RJIT, YJIT, ZJIT
YJIT
YJIT • Ruby 3.1+: ruby --yjit • Rust 1.58.0+ •
Production-ready JIT compiler • Enabled by default on Rails 7.2+
https://speed.ruby-lang.org/
https://railsatscale.com/2025-01-10-yjit-3-4-even-faster-and-more-memory-e ff i cient/
ZJIT
ZJIT • Ruby 4.0+: ruby --zjit • Rust 1.85.0+ (2024
Edition) • Experimental JIT compiler • To be productionized at Ruby 4.1
None
None
None
None
Why ZJIT? • Unblock cross-instruction optimizations • Less incremental, larger
comiplation units • No memory overhead for adding optimizations
How YJIT works
How YJIT works putobject 1 getconst TWO send + leave
Bytecode
How YJIT works putobject 1 getconst TWO send + leave
Bytecode YJIT block1 Mov Reg(0), 1
How YJIT works putobject 1 getconst TWO send + leave
Bytecode YJIT block1 Mov Reg(0), 1 Context Reg(0): Integer YJIT block2 Mov Reg(1), 2 PatchPoint Constant TWO
How YJIT works putobject 1 getconst TWO send + leave
Bytecode YJIT block1 Mov Reg(0), 1 Context Reg(0): Integer YJIT block2 YJIT block3 Mov Reg(1), 2 PatchPoint Constant TWO Context Reg(0): Integer Reg(1): Integer PatchPoint Integer#+ Add Reg(0), Reg(1) Ret Reg(0)
How ZJIT works putobject 1 getconst TWO send + leave
Bytecode
How ZJIT works putobject 1 getconst TWO zjit_send + leave
Bytecode
How ZJIT works putobject 1 getconst TWO zjit_send + leave
Bytecode ZJIT HIR v1 = 1 PatchPoint TWO v2 = 2 PatchPoint Integer#+ v3 = 3 Return v3
How ZJIT works putobject 1 getconst TWO zjit_send + leave
Bytecode ZJIT HIR v1 = 1 PatchPoint TWO v2 = 2 PatchPoint Integer#+ v3 = 3 Return v3 ZJIT LIR Ret 3 PatchPoint Const TWO PatchPoint Integer#+
ZJIT IR
ZJIT IR • ZJIT IR (Intermediate Representation): • HIR: High-level
IR, new in ZJIT • LIR: Ligh-level IR, same as YJIT
HIR
HIR Optimization Passes
LIR
LIR Lowering Passes
How ZJIT compiles Ruby code
How ZJIT compiles Ruby code one: putobject 1 leave two:
putobject 2 leave three: putself send :one putself send :two send :+ leave Parse & Compile
How ZJIT compiles Ruby code one: putobject 1 leave two:
putobject 2 leave three: putself send :one putself send :two send :+ leave one: putobject 1 leave two: putobject 2 leave three: putself zjit_send :one putself zjit_send :two zjit_send :+ leave Parse & Compile Pro fi le
How ZJIT compiles Ruby code Initial HIR: fn three@/Users/k0kubun/tmp/a.rb:11: bb0():
EntryPoint interpreter v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v11:BasicObject = SendWithoutBlock v6, :one v14:BasicObject = SendWithoutBlock v6, :two v17:BasicObject = SendWithoutBlock v11, :+, v14 CheckInterrupts Return v17 one: putobject 1 leave two: putobject 2 leave three: putself send :one putself send :two send :+ leave Compile
How ZJIT compiles Ruby code Optimized HIR: fn three@/Users/k0kubun/tmp/a.rb:11: bb0():
… bb2(v6:BasicObject): PatchPoint MethodRede fi ned(one) PatchPoint NoSingletonClass(Object) v24:HeapObject[Object] = GuardType v6, HeapObject[Object] v31:Fixnum[1] = Const Value(1) PatchPoint MethodRede fi ned(two) PatchPoint NoSingletonClass(Object) v28:HeapObject[Object] = GuardType v6, HeapObject[Object] v33:Fixnum[2] = Const Value(2) PatchPoint MethodRede fi ned(Integer, +) v38:Fixnum[3] = Const Value(3) CheckInterrupts Return v38 one: putobject 1 leave two: putobject 2 leave three: putself send :one putself send :two send :+ leave Inline
How ZJIT compiles Ruby code Optimized HIR: fn three@/Users/k0kubun/tmp/a.rb:11: bb0():
… bb2(v6:BasicObject): PatchPoint MethodRede fi ned(one) PatchPoint NoSingletonClass(Object) v24:HeapObject[Object] = GuardType v6, HeapObject[Object] v31:Fixnum[1] = Const Value(1) PatchPoint MethodRede fi ned(two) PatchPoint NoSingletonClass(Object) v28:HeapObject[Object] = GuardType v6, HeapObject[Object] v33:Fixnum[2] = Const Value(2) PatchPoint MethodRede fi ned(Integer, +) v38:Fixnum[3] = Const Value(3) CheckInterrupts Return v38 one: putobject 1 leave two: putobject 2 leave three: putself send :one putself send :two send :+ leave
Hacking on ZJIT HIR
How to dump ZJIT IR • HIR: ruby --zjit-dump-hir •
LIR: ruby --zjit-dump-lir
None
tryzjit. fl y.dev
tryzjit. fl y.dev
tryzjit. fl y.dev
tryzjit. fl y.dev
tryzjit. fl y.dev
None
None
None
Future of Ruby Performance
Future of Ruby Performance • We want less C extensions
• In particular, less C → Ruby callbacks
C functions dominate execution time Only 10% of execution time
is spent in JIT code https://gist.github.com/k0kubun/5e0b3bb894e9fed9b01e25fd25e8bea5
C functions dominate execution time Some interpreter implementations are used
for reasons https://gist.github.com/k0kubun/5e0b3bb894e9fed9b01e25fd25e8bea5 Complicated argument setup, C → Ruby calls, megamorphic callsite Instance variables: megamorphic callsite
C functions dominate execution time 15% is spent on DB
queries https://gist.github.com/k0kubun/5e0b3bb894e9fed9b01e25fd25e8bea5
C functions dominate execution time 15% is spent on allocation
and garbage collection https://gist.github.com/k0kubun/5e0b3bb894e9fed9b01e25fd25e8bea5
C functions dominate execution time Many methods are implemented in
C https://gist.github.com/k0kubun/5e0b3bb894e9fed9b01e25fd25e8bea5
C functions dominate execution time • Methods written in C
• C → Ruby calls • Megamorphic callsites Reasons why that happens
https://github.com/ruby/ruby/pull/3281
Conclusion • ZJIR unblocks cross-instructions optimizations • Enjoy hacking on
ZJIT HIR • Stay tuned for Ruby 4.1 ZJIT