✦ Ruby 3.3: Use the interpreter’s C function (like MJIT) for:
✦ Unsupported calls
✦ Megamorphic calls
✦ Fallbacks allow the subsequent code to be compiled
Method Call Fallbacks
Slide 29
Slide 29 text
✦ Ruby 3.3: Use the interpreter’s C function (like MJIT) for:
✦ Unsupported calls
✦ Megamorphic calls ← What’s this?
✦ Fallbacks allow the subsequent code to be compiled
Method Call Fallbacks
Slide 30
Slide 30 text
class X
def call
@x = x
end
end
class A < X
def x = :a
end
:a if self.class == A
Ruby
Code
Ruby 3.2 YJIT
Slide 31
Slide 31 text
class X
def call
@x = x
end
end
class A < X
def x = :a
end
class B < X
def x = :b
end
:a if self.class == A
Ruby
Code
Ruby 3.2 YJIT
:b if self.class == B
Slide 32
Slide 32 text
class X
def call
@x = x
end
end
class A < X
def x = :a
end
class B < X
def x = :b
end
class C < X
def x = :c
end
:a if self.class == A
Ruby
Code
Ruby 3.2 YJIT
:b if self.class == B
:c if self.class == C
Slide 33
Slide 33 text
class X
def call
@x = x
end
end
class A < X
def x = :a
end
class B < X
def x = :b
end
class C < X
def x = :c
end
class D < X
def x = :d
end
:a if self.class == A
Ruby
Code
Ruby 3.2 YJIT
:b if self.class == B
:c if self.class == C
side exit
Slide 34
Slide 34 text
class X
def call
@x = x
end
end
class A < X
def x = :a
end
class B < X
def x = :b
end
class C < X
def x = :c
end
class D < X
def x = :d
end
:a if self.class == A
Ruby
Code
Ruby 3.2 YJIT
:b if self.class == B
:c if self.class == C
side exit
:a if self.class == A
:b if self.class == B
:c if self.class == C
vm_send :x
Ruby 3.3 YJIT
setivar @x
Slide 35
Slide 35 text
May 15th - 17th, 2024
NAHA CULTURAL ARTS THEATER NAHArt, Okinawa, Japan
Exception Handlers
Slide 36
Slide 36 text
No content
Slide 37
Slide 37 text
✦ In CRuby, exception handlers are executed differently
from regular methods
✦ Ruby 3.3 YJIT added support for them in CRuby JITs for
the first time
✦ "Exceptions" are not necessarily Ruby exceptions, e.g.
break/return in blocks
Exception Handlers
Slide 38
Slide 38 text
def foo(arr)
@foo = arr.each do |a|
break a if a.odd?
end
end
Ruby 3.2
Slide 39
Slide 39 text
def foo(arr)
@foo = arr.each do |a|
break a if a.odd?
end
end
getlocal arr
send :each, block
dup
setivar @foo
leave
getlocal a
send :odd?
branchunless L0
getlocal a
throw TAG_BREAK
leave
L0: putnil
leave
Ruby 3.2
Call Stack
Slide 40
Slide 40 text
def foo(arr)
@foo = arr.each do |a|
break a if a.odd?
end
end
getlocal arr
send :each, block
dup
setivar @foo
leave
getlocal a
send :odd?
branchunless L0
getlocal a
throw TAG_BREAK
leave
L0: putnil
leave
Call Stack
Ruby 3.2
foo
Slide 41
Slide 41 text
def foo(arr)
@foo = arr.each do |a|
break a if a.odd?
end
end
getlocal arr
send :each, block
dup
setivar @foo
leave
getlocal a
send :odd?
branchunless L0
getlocal a
throw TAG_BREAK
leave
L0: putnil
leave
Call Stack
Ruby 3.2
foo
Array#each
Slide 42
Slide 42 text
def foo(arr)
@foo = arr.each do |a|
break a if a.odd?
end
end
getlocal arr
send :each, block
dup
setivar @foo
leave
getlocal a
send :odd?
branchunless L0
getlocal a
throw TAG_BREAK
leave
L0: putnil
leave
Call Stack
Ruby 3.2
foo
Array#each
block in foo
Slide 43
Slide 43 text
def foo(arr)
@foo = arr.each do |a|
break a if a.odd?
end
end
getlocal arr
send :each, block
dup
setivar @foo
leave
getlocal a
send :odd?
branchunless L0
getlocal a
throw TAG_BREAK
leave
L0: putnil
leave
Call Stack
Ruby 3.2
foo
Array#each
block in foo
Slide 44
Slide 44 text
def foo(arr)
@foo = arr.each do |a|
break a if a.odd?
end
end
getlocal arr
send :each, block
dup
setivar @foo
leave
getlocal a
send :odd?
branchunless L0
getlocal a
throw TAG_BREAK
leave
L0: putnil
leave
Call Stack
Ruby 3.2
foo
Slide 45
Slide 45 text
def foo(arr)
@foo = arr.each do |a|
break a if a.odd?
end
end
getlocal arr
send :each, block
dup
setivar @foo
leave
getlocal a
send :odd?
branchunless L0
getlocal a
throw TAG_BREAK
leave
L0: putnil
leave
Ruby 3.2
JIT: 60%
Interpreter: 40%
Slide 46
Slide 46 text
def foo(arr)
@foo = arr.each do |a|
break a if a.odd?
end
end
getlocal arr
send :each, block
dup
setivar @foo
leave
getlocal a
send :odd?
branchunless L0
getlocal a
throw TAG_BREAK
leave
L0: putnil
leave
Ruby 3.3
JIT: 100%
Slide 47
Slide 47 text
May 15th - 17th, 2024
NAHA CULTURAL ARTS THEATER NAHArt, Okinawa, Japan
Register Allocator
for Stack Values
Slide 48
Slide 48 text
No content
Slide 49
Slide 49 text
✦ Ruby 3.2 YJIT writes VM stack values onto memory
✦ Ruby 3.3 YJIT allocates registers for them
Register Allocator for Stack Values
Slide 50
Slide 50 text
def three
1 + 2
end
Ruby 3.2
Slide 51
Slide 51 text
def three
1 + 2
end
putobject 1
putobject 2
opt_plus
leave
Ruby 3.2
Memory
Register A Register B
Slide 52
Slide 52 text
def three
1 + 2
end
putobject 1
putobject 2
opt_plus
leave
Ruby 3.2
Memory
Register A Register B
1
Slide 53
Slide 53 text
def three
1 + 2
end
putobject 1
putobject 2
opt_plus
leave
Ruby 3.2
Memory
Register A Register B
1
2
Slide 54
Slide 54 text
def three
1 + 2
end
putobject 1
putobject 2
opt_plus
leave
Ruby 3.2
Memory
Register A Register B
3
Slide 55
Slide 55 text
def three
1 + 2
end
putobject 1
putobject 2
opt_plus
leave
Ruby 3.2
Memory
Register A Register B
Slide 56
Slide 56 text
def three
1 + 2
end
putobject 1
putobject 2
opt_plus
leave
Ruby 3.3
Memory
Register A Register B
Slide 57
Slide 57 text
def three
1 + 2
end
putobject 1
putobject 2
opt_plus
leave
Ruby 3.3
Memory
Register A Register B
1
Slide 58
Slide 58 text
def three
1 + 2
end
putobject 1
putobject 2
opt_plus
leave
Ruby 3.3
Memory
Register A Register B
1 2
Slide 59
Slide 59 text
def three
1 + 2
end
putobject 1
putobject 2
opt_plus
leave
Ruby 3.3
Memory
Register A Register B
3
Slide 60
Slide 60 text
def three
1 + 2
end
putobject 1
putobject 2
opt_plus
leave
Ruby 3.3
Memory
Register A Register B
Slide 61
Slide 61 text
✦ Ruby 3.4 YJIT: Optimize local variables like stack values,
speculating Kernel#binding is not called
✦ Ruby 3.4 will hopefully allocate registers for them too
(under development)
Register Allocator for Local Variables
Slide 62
Slide 62 text
May 15th - 17th, 2024
NAHA CULTURAL ARTS THEATER NAHArt, Okinawa, Japan
Method Inlining for Ruby
Slide 63
Slide 63 text
No content
Slide 64
Slide 64 text
✦ YJIT 3.3+ inlines single-line methods that return:
✦ Ruby 3.3: 1, 2, 3, …, true, false, nil, :symbol
✦ Ruby 3.4: self, local variables
Method Inlining for Ruby
Slide 65
Slide 65 text
Active
Support
Slide 66
Slide 66 text
Active
Support
Slide 67
Slide 67 text
Active
Support
Slide 68
Slide 68 text
Symbol#to_sym
Slide 69
Slide 69 text
Sorbet Helper Patches
Slide 70
Slide 70 text
May 15th - 17th, 2024
NAHA CULTURAL ARTS THEATER NAHArt, Okinawa, Japan
Method Inlining for C
Slide 71
Slide 71 text
No content
Slide 72
Slide 72 text
✦ Ruby 3.3 YJIT specializes many C methods, which leads
to a high C method inlining ratio
✦ Ruby 3.4 YJIT pushes "lazy frames"
Method Inlining for C
Slide 73
Slide 73 text
No content
Slide 74
Slide 74 text
No content
Slide 75
Slide 75 text
No content
Slide 76
Slide 76 text
✦ Enable YJIT in production now!
✦ YJIT speeds up production apps by 10-20%
✦ Upgrade Ruby to 3.3
✦ JIT more code, allocate registers, and inline method calls
Conclusion