Ruby JIT Hacking Guide / RubyKaigi 2023
by
Takashi Kokubun
Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
Ruby JIT Hacking Guide @k0kubun
Slide 2
Slide 2 text
@k0kubun
Slide 3
Slide 3 text
RJIT ERB Haml Slim I maintain
Slide 4
Slide 4 text
What's JIT?
Slide 5
Slide 5 text
Ruby JITs MJIT Ruby 2.6
Slide 6
Slide 6 text
Ruby JITs YJIT Ruby 3.1 MJIT Ruby 2.6
Slide 7
Slide 7 text
Ruby JITs YJIT Ruby 3.1 MJIT Ruby 2.6 RJIT Ruby 3.3
Slide 8
Slide 8 text
Railsbench Speedup relative to 2.5 No JIT (s/s) 0 0.5 1 1.5 2 Ruby 2.5 Ruby 2.6 Ruby 2.7 Ruby 3.0 Ruby 3.1 Ruby 3.2 Ruby 3.3 1.93 1.85 1.54 1.59 1.2 1.25 1.08 1.05 1.07 1.26 1.24 1.12 1.09 1.05 1.07 1 No JIT MJIT / RJIT YJIT
Slide 9
Slide 9 text
Ruby 3.2 YJIT
Slide 10
Slide 10 text
Ruby 3.3 YJIT
Slide 11
Slide 11 text
Using YJIT • Install Rust and then build Ruby • Use --yjit or export RUBY_YJIT_ENABLE=1
Slide 12
Slide 12 text
Ruby JIT Hacking Guide
Slide 13
Slide 13 text
Ruby Hacking Guide
Slide 14
Slide 14 text
Ruby JIT Hacking Guide JIT JIT
Slide 15
Slide 15 text
How Ruby JIT works Ruby
Slide 16
Slide 16 text
How Ruby JIT works 1 + 2 Ruby Abstract Syntax Tree
Slide 17
Slide 17 text
How Ruby JIT works 1 + 2 putobject 1 putobject 2 opt_plus leave Ruby Abstract Syntax Tree Instruction Sequence (Bytecode)
Slide 18
Slide 18 text
How Ruby JIT works 1 + 2 putobject 1 putobject 2 opt_plus leave Ruby Abstract Syntax Tree Instruction Sequence (Bytecode) Machine Code
Slide 19
Slide 19 text
x86_64 assembly
Slide 20
Slide 20 text
• Read asm comments •--yjit-dump-disasm •--rjit-dump-disasm x86_64 assembly
Slide 21
Slide 21 text
• mov: assignment instruction • esi: register for stack[0] x86_64 assembly stack[0] = 3
Slide 22
Slide 22 text
x86_64 assembly • mov: assignment instruction • edi: register for stack[1] stack[0] = 3 stack[1] = 5
Slide 23
Slide 23 text
x86_64 assembly • add,sub: arithmetic instruction • rax: temporary register stack[0] = 3 stack[1] = 5 temp = stack[0] temp -= 1 temp += stack[1]
Slide 24
Slide 24 text
x86_64 assembly • jo: jump if over fl ow • rsi: register for stack[0] stack[0] = 3 stack[1] = 5 temp = stack[0] temp -= 1 temp += stack[1] jump if overflow stack[0] = temp
Slide 25
Slide 25 text
x86_64 encoding
Slide 26
Slide 26 text
x86_64 encoding opv86: https://hikalium.github.io/opv86/
Slide 27
Slide 27 text
x86_64 encoding opv86: https://hikalium.github.io/opv86/
Slide 28
Slide 28 text
Calling a custom JIT Ruby 3.2 Ruby 3.3+ 1. Run Ruby with --mjit=pause --rjit=pause 2. Override RubyVM::MJIT.compile RubyVM::RJIT#compile 3. Call RubyVM::MJIT.resume RubyVM::RJIT.resume
Slide 29
Slide 29 text
Building JIT is fun
Slide 30
Slide 30 text
k0kubun/ruby-jit-challenge Ruby JIT Challenge
Slide 31
Slide 31 text
Ruby JIT Challenge Hashtag: #ruby-jit-challenge Speedup relative to No JIT (s/s) 0 3 6 9 12 No JIT RJIT YJIT Ruby JIT 11.08 6.31 3.75 1 Fibonatti benchmark
Slide 32
Slide 32 text
Optimizing Ruby JIT
Slide 33
Slide 33 text
Side exits side exit
Slide 34
Slide 34 text
Method rede fi nition Rede fi nition Hook Invalidate
Slide 35
Slide 35 text
Method rede fi nition Rede fi nition Hook Invalidate side exit
Slide 36
Slide 36 text
Constant rede fi nition
Slide 37
Slide 37 text
Register allocation: Stack 0: rsi 1: rdi 4: r10 2: r8 3: r9 VM stack
Slide 38
Slide 38 text
Register allocation: Stack 0: rsi 1: rdi 4: r10 2: r8 3: r9 VM stack
Slide 39
Slide 39 text
Register allocation: Local variables • Spill registers on C function calls • Binding • debug_inspector API
Slide 40
Slide 40 text
Polymorphic method cache
Slide 41
Slide 41 text
Splitting
Slide 42
Slide 42 text
Method inlining
Slide 43
Slide 43 text
Conclusion • Enjoy custom JIT development • Let's make YJIT the best Ruby JIT