YJIT: Abort expandarray optimization if method_missing is defined

Fixes: [Bug #21707]
[AW: rewrote comments]
Co-authored-by: Alan Wu <alanwu@ruby-lang.org>
This commit is contained in:
Randy Stauner 2025-11-25 19:29:02 -07:00 committed by Alan Wu
parent c42c6c27c3
commit 5f55c9c8fb
Notes: git 2025-11-26 20:56:55 +00:00
4 changed files with 27 additions and 1 deletions

View File

@ -2680,6 +2680,22 @@ assert_equal '[1, 2]', %q{
expandarray_redefined_nilclass
}
assert_equal 'not_array', %q{
def expandarray_not_array(obj)
a, = obj
a
end
obj = Object.new
def obj.method_missing(m, *args, &block)
return [:not_array] if m == :to_ary
super
end
expandarray_not_array(obj)
expandarray_not_array(obj)
}
assert_equal '[1, 2, nil]', %q{
def expandarray_rhs_too_small
a, b, c = [1, 2]

View File

@ -2258,7 +2258,8 @@ fn gen_expandarray(
let comptime_recv = jit.peek_at_stack(&asm.ctx, 0);
// If the comptime receiver is not an array
// If the comptime receiver is not an array, speculate for when the `rb_check_array_type()`
// conversion returns nil and without side-effects (e.g. arbitrary method calls).
if !unsafe { RB_TYPE_P(comptime_recv, RUBY_T_ARRAY) } {
// at compile time, ensure to_ary is not defined
let target_cme = unsafe { rb_callable_method_entry_or_negative(comptime_recv.class_of(), ID!(to_ary)) };
@ -2270,6 +2271,13 @@ fn gen_expandarray(
return None;
}
// Bail when method_missing is defined to avoid generating code to call it.
// Also, for simplicity, bail when BasicObject#method_missing has been removed.
if !assume_method_basic_definition(jit, asm, comptime_recv.class_of(), ID!(method_missing)) {
gen_counter_incr(jit, asm, Counter::expandarray_method_missing);
return None;
}
// invalidate compile block if to_ary is later defined
jit.assume_method_lookup_stable(asm, target_cme);

View File

@ -816,6 +816,7 @@ pub(crate) mod ids {
def_ids! {
name: NULL content: b""
name: respond_to_missing content: b"respond_to_missing?"
name: method_missing content: b"method_missing"
name: to_ary content: b"to_ary"
name: to_s content: b"to_s"
name: eq content: b"=="

View File

@ -496,6 +496,7 @@ make_counters! {
expandarray_postarg,
expandarray_not_array,
expandarray_to_ary,
expandarray_method_missing,
expandarray_chain_max_depth,
// getblockparam