|
# frozen_string_literal: true
|
|
|
|
# Minimal generated-code repro for the YJIT local-register mapping bug.
|
|
#
|
|
# Run with:
|
|
#
|
|
# ruby --yjit /workspace/yjit_many_locals_simple_repro.rb
|
|
#
|
|
# The method generated below has 257 locals:
|
|
#
|
|
# total
|
|
# y0, x0, y1, x1, ... y127, x127
|
|
#
|
|
# On buggy YJIT builds, x127's local index wraps onto total's register mapping.
|
|
# The final `total += 1` then reads an Object instead of 0 and fails.
|
|
|
|
source = +"def many_locals\n"
|
|
source << " total = 0\n"
|
|
|
|
128.times do |i|
|
|
source << " y#{i} = 1\n"
|
|
source << " x#{i} = Object.new\n"
|
|
end
|
|
|
|
source << " total += 1\n"
|
|
source << " total\n"
|
|
source << "end\n"
|
|
|
|
eval(source, TOPLEVEL_BINDING, __FILE__, 1)
|
|
|
|
iterations = Integer(ENV.fetch("ITERATIONS", "100000"))
|
|
|
|
puts "ruby=#{RUBY_DESCRIPTION}"
|
|
puts "yjit=#{RubyVM::YJIT.enabled? if defined?(RubyVM::YJIT)}"
|
|
puts "iterations=#{iterations}"
|
|
|
|
unless defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled?
|
|
warn "YJIT is not enabled. Re-run with: ruby --yjit #{__FILE__}"
|
|
end
|
|
|
|
iterations.times do |i|
|
|
result = many_locals
|
|
raise "wrong result: #{result.inspect}" unless result == 1
|
|
puts "iteration=#{i + 1}" if ((i + 1) % 10_000).zero?
|
|
rescue Exception => e # rubocop:disable Lint/RescueException
|
|
warn "failed_at=#{i + 1}"
|
|
warn e.full_message(highlight: false, order: :top)
|
|
raise
|
|
end
|
|
|
|
puts "ok iterations=#{iterations}"
|