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
550
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.7k
一度始めたらやめられない開発効率向上術 / Findy あなたのdotfilesを教えて!
k0kubun
4
3.2k
ZJIT: The Future of Ruby Performance / San Francisco Ruby Conference 2025
k0kubun
1
140
ZJIT: Building a New JIT Compiler for Ruby / REBASE 2025
k0kubun
0
150
Deoptimization: How YJIT Speeds Up Ruby by Slowing Down / RubyKaigi 2025
k0kubun
2
4.6k
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
freeeにおけるEvalsの実践例の紹介
freee
PRO
0
110
人間の目はかわらない、だからJPEGは30年もつ
yuzneri
12
18k
Detecting Compromised CI with eBPF and Cilium Tetragon
lizrice
0
180
「人を評価する AI」の設計と実装
ryoyanara
0
200
Cloudflare is Agents
chimame
0
160
これって Effect でできたのでは? / TSKaigi Mashup Kansai #2
susisu
0
230
進化を続けるGo toolsの現在地 / The Current State of Ever-Evolving Go Tools
hond0413
0
210
今さら聞けない .NET CLI
htkym
0
190
S3 を使うアプリケーションをローカル完結で動かすことに全力を注いでみた / Running S3 Apps Offline
contour_gara
0
460
生成AI導入の「期待外れ」を乗り越える ー 開発フロー改革が目指す、真の組織変革
starfish719
0
4.3k
型も通る、synthも通る、それでも危ない 〜AIのCDKの権限とコストを機械で検証する〜 / It Passes Type Checks, It Passes Synth Checks, but It’s Still Risky — Automatically Verifying Permissions and Costs in AI’s CDK —
seike460
PRO
1
550
ドリフトを絶対に許さない(?)CDK運用 / CDK Ops with Zero Tolerance for Drifts (?)
akihisaikeda
1
180
Featured
See All Featured
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
Making the Leap to Tech Lead
cromwellryan
135
10k
Amusing Abliteration
ianozsvald
1
240
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
<Decoding/> the Language of Devs - We Love SEO 2024
nikkihalliwell
1
280
A designer walks into a library…
pauljervisheath
211
24k
How STYLIGHT went responsive
nonsquared
100
6.2k
Google's AI Overviews - The New Search
badams
0
1.1k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.5k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
38
2.9k
Color Theory Basics | Prateek | Gurzu
gurzu
0
410
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
230
23k
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