define_method conversion fails to yield after indy JIT
Under certain circumstances, a define_method method will fail to yield to the surrounding scope's block:
- define_method with yield
- inside another method
- closure-based define_method has been converted to a normal method
- converted method has JIT compiled
- indy is enabled and has optimized
This reproduces on both 10 and 9.4 when indy is enabled.
class Foo
class << self
def go(&xxx)
define_method(:foo) { yield }
end
end
end
f = Foo.new
Foo.go {puts 1}
4.times { f.foo }
When run with jit.threshold=0 it iterates twice and then fails to yield on the third iteration:
$ jruby -Xjit.threshold=0 -Xjit.logging blah.rb
2025-08-07T12:06:42.080+03:00 [main] INFO Ruby : done compiling target script: blah.rb
2025-08-07T12:06:42.135+03:00 [main] INFO JITCompiler : method done jitting: Foo foo at blah.rb:3
1
1
LocalJumpError: no block given
foo at blah.rb:4
<main> at blah.rb:10
times at org/jruby/RubyFixnum.java:338
<main> at blah.rb:10
Something about the indy logic for this define_method body causes it to lose context for the surrounding go method's block.
For JRuby 10.0.2.0 we have disabled define_method conversion when it is called within another method, but since that is a fairly common pattern we would like to figure out the problem and re-enable conversion in a future release.
See #8943 for the temporary workaround. The issue was discovered in #8930 by forcing language specs to run repeatedly.