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
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Takashi Kokubun
December 20, 2025
Programming
560
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.8k
一度始めたらやめられない開発効率向上術 / Findy あなたのdotfilesを教えて!
k0kubun
4
3.2k
ZJIT: The Future of Ruby Performance / San Francisco Ruby Conference 2025
k0kubun
1
150
ZJIT: Building a New JIT Compiler for Ruby / REBASE 2025
k0kubun
0
160
Deoptimization: How YJIT Speeds Up Ruby by Slowing Down / RubyKaigi 2025
k0kubun
2
4.8k
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.4k
Towards Ruby 4 JIT / RubyKaigi 2022
k0kubun
3
12k
Other Decks in Programming
See All in Programming
DroidKaigi 2026 「個人開発という実験場: Android エンジニアが手にする4つの自由」
slashnephy
0
160
Jindong: Introducing Declarative Haptics in Compose Multiplatform
l2hyunwoo
0
140
片田舎のおっさん、 Swift Buildのダイアモンド問題解決の不具合修正PRを出すが、解決方法がキャッシュをしないようにすることであり、ビルド時間が伸びると言われてマージされないので高速化もする/swiftbuild
yimajo
0
340
自分的「カンファレンスの楽しみ方」
syumai
0
160
How I Won Prize Money at a Hackathon Using Codex and Symphony Alpha
yasei_no_otoko
0
130
夏だ!祭りだ!祭りとはドメインモデリングでは?
ryugen04
0
500
仕様駆動開発の消費期限
watany
20
9.2k
高専、大学編入、そして未踏へ〜プロダクト開発とキャリアの歩み - Technical College, University Transfer, and On to “Mitou” / My Journey in Product Development and Career
pkmiya
0
120
自動化したのに回らない テスト運用の壁―AI時代の品質責任と生産性
mfunaki
0
560
DynamoDBの基礎を振り返りながらベクトル検索機能を理解する
musan
3
260
思考垂れ流し開発 ~音声入力 × AIエージェント × 開発ハーネスによる試行錯誤~
npostring
0
610
PHPプロジェクトの結合バランスを可視化する #php_night
kajitack
0
180
Featured
See All Featured
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.8k
Building Experiences: Design Systems, User Experience, and Full Site Editing
marktimemedia
0
590
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
1
300
How to build a perfect <img>
jonoalderson
1
5.9k
A Modern Web Designer's Workflow
chriscoyier
698
190k
Writing Fast Ruby
sferik
630
63k
Fantastic passwords and where to find them - at NoRuKo
philnash
52
3.8k
Discover your Explorer Soul
emna__ayadi
2
1.3k
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
1
2.1k
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
480
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