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 Future of Ruby Performance / San Fran...
Search
Takashi Kokubun
November 19, 2025
Programming
120
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
ZJIT: The Future of Ruby Performance / San Francisco Ruby Conference 2025
https://sfruby.com/
Takashi Kokubun
November 19, 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.5k
一度始めたらやめられない開発効率向上術 / Findy あなたのdotfilesを教えて!
k0kubun
4
3.1k
ZJIT: The Ruby 4 JIT Compiler / Ruby Release 30th Anniversary Party
k0kubun
1
520
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
セキュリティの専門家じゃなくてもできる。「セキュリティ意識」をアップデートして サプライチェーン攻撃への耐性を高めよう。
tk3fftk
5
680
Oxcを導入して開発体験が向上した話
yug1224
4
290
AIチームを指揮するOSS「TAKT」活用術 / How to Use “TAKT,” an OSS Tool for Orchestrating AI Teams
nrslib
6
850
タクシーアプリ『GO』の バックエンド開発のおける AI利活用と若者のすべて
pyama86
3
1.9k
AI時代の仕事技芸論 — ソフトウェア開発で「遊ぶように働く」職人的熟達のすすめ
kuranuki
1
630
JJUG CCC 2026 Spring: JSpecify で実現する Kotlin フレンドリーな Java API 設計
ternbusty
1
150
Oxlintのカスタムルールの現況
syumai
6
1k
生成AI時代にこそ効くGo | Why Go Works in the Age of Generative AI
mom0tomo
8
3.2k
Spec Driven Development | AI Summit Lisbon
danielsogl
PRO
0
170
TypeScript+Orvalで実現する型安全かつ堅牢でスケーラブルなマルチチャネル通知基盤 / TSKaigi Night talks ~after conference~
d0riven
0
320
エージェンティックRAGにAWSで入門しよう!
har1101
8
1.3k
気づいたらRubyで100作品 ー クリエイティブコーディングが生活の一部になるまで / 100 Ruby Sketches Later: How Creative Coding Became Part of My Life
chobishiba
3
550
Featured
See All Featured
Are puppies a ranking factor?
jonoalderson
1
3.5k
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.6k
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
1
3.6k
Balancing Empowerment & Direction
lara
6
1.1k
Rails Girls Zürich Keynote
gr2m
96
14k
What does AI have to do with Human Rights?
axbom
PRO
1
2.2k
How to audit for AI Accessibility on your Front & Back End
davetheseo
0
410
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
Side Projects
sachag
455
43k
Test your architecture with Archunit
thirion
1
2.3k
Groundhog Day: Seeking Process in Gaming for Health
codingconduct
0
200
Jamie Indigo - Trashchat’s Guide to Black Boxes: Technical SEO Tactics for LLMs
techseoconnect
PRO
0
160
Transcript
San Francisco Ruby Conference 2025 ZJIT: The Future of Ruby
Performance Takashi Kokubun / @k0kubun
self • Takashi Kokubun (@k0kubun) • Shopify: Ruby JIT team
• Ruby committer: MJIT, RJIT, YJIT, ZJIT
YJIT
YJIT • Ruby 3.1+: ruby --yjit • 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 • Experimental JIT compiler
• To be productionized at Ruby 4.1
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
Playing with ZJIT IR • Build: con fi gure --enable-zjit
• HIR: ruby --zjit-dump-hir • LIR: ruby --zjit-dump-lir
https://tryzjit. fl y.dev/
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
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 • We're building ZJIT to unblock cross-instruction optimizations •
We want more code to be written in Ruby for performance