Skip to content

define_method conversion fails to yield after indy JIT #8946

@headius

Description

@headius

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions