Project

General

Profile

Bug #22546 ยป yjit_repro.rb

jamescook83 (James Cook), 11/13/2026 06:19 PM

 
# YJIT on arm64 panics in yjit::asm::arm64::add while compiling a method with many locals.
#
# ruby yjit_repro.rb # finds the smallest number of locals that panics
# ruby --yjit yjit_repro.rb N # one try: defines a method of N locals and calls it 100 times
#
# Plain Ruby, no gems. Each try runs in a child Ruby with --yjit, so a panic only ends the child.

def define_and_call(count)
body = (1..count).map { |n| " v#{n} = a + #{n}" }.join("\n")
eval("def many_locals(a)\n#{body}\n v1\nend") # rubocop:disable Security/Eval
100.times { many_locals(1) } # past YJIT's call threshold, so the method is compiled
end

def panics?(count)
out = IO.popen([RbConfig.ruby, "--yjit", "-W0", __FILE__, count.to_s], err: %i[child out], &:read)
out.include?("YJIT has panicked")
end

if ARGV.first
define_and_call(Integer(ARGV.first))
puts "#{ARGV.first} locals: no panic"
exit
end

puts RUBY_DESCRIPTION
low = 1 # known not to panic
high = 2048 # known to panic
abort "#{high} locals does not panic here" unless panics?(high)
while high - low > 1
mid = (low + high) / 2
panics?(mid) ? high = mid : low = mid
end
puts "#{low} locals (#{low + 1} with the argument): compiles"
puts "#{high} locals (#{high + 1} with the argument): YJIT panics"
    (1-1/1)