diff --git a/array.c b/array.c index 5af5c856a8dc21..4b1343b6fa51bc 100644 --- a/array.c +++ b/array.c @@ -2167,12 +2167,12 @@ rb_ary_rfind(int argc, VALUE *argv, VALUE ary) /* * call-seq: - * find_index(object, offset: 0) -> integer or nil + * find_index(object) -> integer or nil * find_index {|element| ... } -> integer or nil - * find_index(offset: 0) -> new_enumerator - * index(object, offset: 0) -> integer or nil + * find_index -> new_enumerator + * index(object) -> integer or nil * index {|element| ... } -> integer or nil - * index(offset: 0) -> new_enumerator + * index -> new_enumerator * * Returns the zero-based integer index of a specified element, or +nil+. * @@ -2194,20 +2194,6 @@ rb_ary_rfind(int argc, VALUE *argv, VALUE ary) * * Returns +nil+ if the block never returns a truthy value. * - * When +offset+ is non-negative, begins the search at position +offset+; - * the returned index is relative to the beginning of +self+: - * - * a = [:foo, 'bar', 2, 'bar'] - * a.index('bar', offset: 1) # => 1 - * a.index('bar', offset: 2) # => 3 - * a.index('bar', offset: 4) # => nil - * - * With negative integer argument +offset+, selects the search position by counting backward - * from the end of +self+: - * - * a = [:foo, 'bar', 2, 'bar'] - * a.index('bar', offset: -2) # => 3 - * * With neither an argument nor a block given, returns a new Enumerator. * * Related: see {Methods for Querying}[rdoc-ref:Array@Methods+for+Querying]. @@ -2216,8 +2202,7 @@ rb_ary_rfind(int argc, VALUE *argv, VALUE ary) static VALUE rb_ary_index(int argc, VALUE *argv, VALUE ary) { - VALUE val, opts = Qnil, initpos = Qnil; - long pos = 0; + VALUE val; long i; if (argc == 0) { @@ -2229,24 +2214,11 @@ rb_ary_index(int argc, VALUE *argv, VALUE ary) } return Qnil; } - rb_check_arity(argc, 0, 2); - rb_scan_args(argc, argv, "1:", &val, &opts); - if (!NIL_P(opts)) { - static ID keywords[1]; - if (!keywords[0]) { - keywords[0] = rb_intern_const("offset"); - } - rb_get_kwargs(opts, keywords, 0, 1, &initpos); - if (!UNDEF_P(initpos)) - pos = NUM2LONG(initpos); - } + rb_check_arity(argc, 0, 1); + val = argv[0]; if (rb_block_given_p()) rb_warn("given block not used"); - if (pos < 0) - pos += RARRAY_LEN(ary); - if (pos < 0) - return Qnil; - for (i=pos; i integer or nil + * rindex(object) -> integer or nil * rindex {|element| ... } -> integer or nil - * rindex(offset: nil) -> new_enumerator + * rindex -> new_enumerator * * Returns the index of the last element for which object == element. * @@ -2278,23 +2250,6 @@ rb_ary_index(int argc, VALUE *argv, VALUE ary) * * Returns +nil+ if the block never returns a truthy value. * - * When +offset+ is non-negative, it specifies the maximum starting position in the - * array to end the search: - * - * a = [:foo, 'bar', 2, 'bar'] - * a.rindex('bar', offset: 0) # => 3 - * a.rindex(2, offset: 1) # => 2 - * a.rindex(2, offset: 3) # => nil - * - * With negative integer argument +offset+, - * selects the search position by counting backward from the end of +self+: - * - * a = [:foo, 'bar', 2, 'bar'] - * a.rindex('bar', -1) # => 3 - * a.rindex('bar', -2) # => 1 - * a.rindex('bar', -3) # => 1 - * a.rindex('bar', -4) # => nil - * * When neither an argument nor a block is given, returns a new Enumerator. * * Related: see {Methods for Querying}[rdoc-ref:Array@Methods+for+Querying]. @@ -2303,44 +2258,25 @@ rb_ary_index(int argc, VALUE *argv, VALUE ary) static VALUE rb_ary_rindex(int argc, VALUE *argv, VALUE ary) { - VALUE val, opts = Qnil, offset_arg = Qnil; - long i = RARRAY_LEN(ary) - 1, len, end_pos = 0, offset; + VALUE val; + long i = RARRAY_LEN(ary), len; if (argc == 0) { RETURN_ENUMERATOR(ary, 0, 0); - while (i >= 0) { + while (i--) { if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) return LONG2NUM(i); if (i > (len = RARRAY_LEN(ary))) { i = len; } - i--; } return Qnil; } - rb_check_arity(argc, 0, 2); - rb_scan_args(argc, argv, "1:", &val, &opts); - if (!NIL_P(opts)) { - static ID keywords[1]; - if (!keywords[0]) { - keywords[0] = rb_intern_const("offset"); - } - rb_get_kwargs(opts, keywords, 0, 1, &offset_arg); - if (!UNDEF_P(offset_arg)){ - offset = NUM2LONG(offset_arg); - if (offset < 0) { - i += offset + 1; - } - else { - end_pos = offset; - } - } - } + rb_check_arity(argc, 0, 1); + val = argv[0]; if (rb_block_given_p()) rb_warn("given block not used"); - if (i < 0 || end_pos >= RARRAY_LEN(ary)) - return Qnil; - for (; i >= end_pos; i--) { + while (i--) { VALUE e = RARRAY_AREF(ary, i); if (rb_equal(e, val)) { return LONG2NUM(i); diff --git a/internal.h b/internal.h index 002044cfa1a590..a08fab10dc2355 100644 --- a/internal.h +++ b/internal.h @@ -64,10 +64,6 @@ /* internal/symbol.h */ #define rb_sym_intern_ascii_cstr(...) rb_nonexistent_symbol(__VA_ARGS__) -/* internal/vm.h */ -#define rb_funcallv(...) rb_nonexistent_symbol(__VA_ARGS__) -#define rb_method_basic_definition_p(...) rb_nonexistent_symbol(__VA_ARGS__) - /* MRI debug support */ diff --git a/io_buffer.c b/io_buffer.c index 98c82bd6c7821d..a64fa506ec04c8 100644 --- a/io_buffer.c +++ b/io_buffer.c @@ -1490,7 +1490,8 @@ rb_io_buffer_readonly_p(VALUE self) * If the buffer is read only, meaning the buffer cannot be modified using * #set_value, #set_string or #copy and similar. * - * Frozen strings and read-only files create read-only buffers. + * A buffer created by IO::Buffer.for without a block is read-only, as is one + * backed by a frozen string or a read-only file. */ static VALUE io_buffer_readonly_p(VALUE self) diff --git a/test/ruby/test_array.rb b/test/ruby/test_array.rb index 5f47b652f5754f..36f88016149e2a 100644 --- a/test/ruby/test_array.rb +++ b/test/ruby/test_array.rb @@ -1162,14 +1162,7 @@ def test_index assert_nil(a.index('ca')) assert_nil(a.index([1,2])) - assert_equal(1, a.index(99, offset: 0)) - assert_equal(3, a.index(99, offset: 2)) - assert_equal(2, a.index(/a/, offset: -4)) - assert_nil(a.index(99, offset: a.size)) - assert_nil(a.index(99, offset: -a.size - 1)) - assert_equal(1, assert_warn(/given block not used/) {a.index(99) {|x| x == 'cat' }}) - assert_equal(3, assert_warn(/given block not used/) {a.index(99, offset: 2) {|x| x == 'cat' }}) end def test_values_at @@ -1544,15 +1537,7 @@ def test_rindex assert_nil(a.rindex('ca')) assert_nil(a.rindex([1,2])) - assert_equal(3, a.rindex(99, offset: 0)) - assert_equal(3, a.rindex(99, offset: 2)) - assert_equal(1, a.rindex(99, offset: -3)) - assert_nil(a.rindex(/a/, offset: -4)) - assert_nil(a.index(99, offset: a.size)) - assert_nil(a.index(99, offset: -a.size - 1)) - assert_equal(3, assert_warning(/given block not used/) {a.rindex(99) {|x| x == [1,2,3] }}) - assert_equal(3, assert_warning(/given block not used/) {a.rindex(99, offset: 2) {|x| x == [1,2,3] }}) bug15951 = "[Bug #15951]" o2 = Object.new diff --git a/test/ruby/test_yjit.rb b/test/ruby/test_yjit.rb index 97bf24bcb8a685..9b9a59c397f8e5 100644 --- a/test/ruby/test_yjit.rb +++ b/test/ruby/test_yjit.rb @@ -853,6 +853,27 @@ def jit_method RUBY end + def test_forwarding_callee_does_not_map_arguments_to_locals + assert_compiles( + <<~'RUBY', call_threshold: 1, code_gc: true, result: [:ok, :ok], verify_ctx: true + class ForwardingReceiver + def foo(...) = :ok + end + + def delegate(...) + receiver = ForwardingReceiver.new + if defined?(receiver.foo) + receiver.foo(...) + else + receiver.__send__(:foo, ...) + end + end + + 2.times.map { delegate(nil, "string") } + RUBY + ) + end + def test_send_block # Setlocal_wc_0 sometimes side-exits on write barrier assert_compiles(<<~'RUBY', result: "b:n/b:y/b:y/b:n") @@ -1996,7 +2017,8 @@ def assert_compiles( frozen_string_literal: nil, mem_size: nil, code_gc: false, - no_send_fallbacks: false + no_send_fallbacks: false, + verify_ctx: false ) reset_stats = <<~RUBY RubyVM::YJIT.runtime_stats @@ -2031,7 +2053,7 @@ def collect_insns(iseq) #{write_results} RUBY - status, out, err, stats = eval_with_jit(script, call_threshold:, mem_size:, code_gc:) + status, out, err, stats = eval_with_jit(script, call_threshold:, mem_size:, code_gc:, verify_ctx:) assert status.success?, "exited with status #{status.to_i}, stderr:\n#{err}" @@ -2096,7 +2118,9 @@ def script_shell_encode(s) s.chars.map { |c| c.ascii_only? ? c : "\\u%x" % c.codepoints[0] }.join end - def eval_with_jit(script, call_threshold: 1, timeout: 1000, mem_size: nil, code_gc: false) + def eval_with_jit( + script, call_threshold: 1, timeout: 1000, mem_size: nil, code_gc: false, verify_ctx: false + ) args = [ "--disable-gems", "--yjit-call-threshold=#{call_threshold}", @@ -2104,6 +2128,7 @@ def eval_with_jit(script, call_threshold: 1, timeout: 1000, mem_size: nil, code_ ] args << "--yjit-exec-mem-size=#{mem_size}" if mem_size args << "--yjit-code-gc" if code_gc + args << "--yjit-verify-ctx" if verify_ctx args << "-e" << script_shell_encode(script) stats_r, stats_w = IO.pipe # Separate thread so we don't deadlock when diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index 0a9a0a796eb7a5..c8178e12842cbb 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -8290,17 +8290,14 @@ fn gen_send_iseq( callee_ctx.set_inline_block(iseq); } - // Set the argument types in the callee's context - for arg_idx in 0..argc { - let stack_offs: u8 = (argc - arg_idx - 1).try_into().unwrap(); - let arg_type = asm.ctx.get_opnd_type(StackOpnd(stack_offs)); - callee_ctx.set_local_type(arg_idx.try_into().unwrap(), arg_type); - } - - // If we're in a forwarding callee, there will be one unknown type - // written in to the local table (the caller's CI object) - if forwarding { - callee_ctx.set_local_type(0, Type::Unknown) + // Forwarding callees store a callinfo object rather than arguments in + // their local table, so their argument types do not map to local types. + if !forwarding { + for arg_idx in 0..argc { + let stack_offs: u8 = (argc - arg_idx - 1).try_into().unwrap(); + let arg_type = asm.ctx.get_opnd_type(StackOpnd(stack_offs)); + callee_ctx.set_local_type(arg_idx.try_into().unwrap(), arg_type); + } } // Set the receiver type in the callee's context