diff --git a/test/ruby/test_yjit.rb b/test/ruby/test_yjit.rb index 2ea915bc0d..e4080595b0 100644 --- a/test/ruby/test_yjit.rb +++ b/test/ruby/test_yjit.rb @@ -1121,6 +1121,26 @@ class TestYJIT < Test::Unit::TestCase RUBY end + def test_nested_send + #[Bug #19464] + assert_compiles(<<~RUBY, result: [:ok, :ok]) + klass = Class.new do + class << self + alias_method :my_send, :send + + def bar = :ok + + def foo = bar + end + end + + with_break = -> { break klass.send(:my_send, :foo) } + wo_break = -> { klass.send(:my_send, :foo) } + + [with_break[], wo_break[]] + RUBY + end + private def code_gc_helpers diff --git a/version.h b/version.h index 75e081cf3c..5eb9d00160 100644 --- a/version.h +++ b/version.h @@ -11,7 +11,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 1 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 39 +#define RUBY_PATCHLEVEL 40 #include "ruby/version.h" #include "ruby/internal/abi.h" diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index 8c5b413286..687205e10f 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -5822,7 +5822,6 @@ fn gen_send_general( let opt_type = unsafe { get_cme_def_body_optimized_type(cme) }; match opt_type { OPTIMIZED_METHOD_TYPE_SEND => { - // This is for method calls like `foo.send(:bar)` // The `send` method does not get its own stack frame. // instead we look up the method and call it, @@ -5830,6 +5829,16 @@ fn gen_send_general( let starting_context = ctx.clone(); + // Reject nested cases such as `send(:send, :alias_for_send, :foo))`. + // We would need to do some stack manipulation here or keep track of how + // many levels deep we need to stack manipulate. Because of how exits + // currently work, we can't do stack manipulation until we will no longer + // side exit. + if flags & VM_CALL_OPT_SEND != 0 { + gen_counter_incr!(asm, send_send_nested); + return CantCompile; + } + if argc == 0 { gen_counter_incr!(asm, send_send_wrong_args); return CantCompile; @@ -5856,20 +5865,6 @@ fn gen_send_general( return CantCompile; } - // We aren't going to handle `send(send(:foo))`. We would need to - // do some stack manipulation here or keep track of how many levels - // deep we need to stack manipulate - // Because of how exits currently work, we can't do stack manipulation - // until we will no longer side exit. - let def_type = unsafe { get_cme_def_type(cme) }; - if let VM_METHOD_TYPE_OPTIMIZED = def_type { - let opt_type = unsafe { get_cme_def_body_optimized_type(cme) }; - if let OPTIMIZED_METHOD_TYPE_SEND = opt_type { - gen_counter_incr!(asm, send_send_nested); - return CantCompile; - } - } - flags |= VM_CALL_FCALL | VM_CALL_OPT_SEND; assume_method_lookup_stable(jit, ocb, cme);