diff --git a/gc.c b/gc.c index 788d0751b521af..6f4997314833ea 100644 --- a/gc.c +++ b/gc.c @@ -3755,7 +3755,7 @@ rb_gc_register_address(VALUE *addr) RB_VM_LOCKING() { if (vm->global_object_list_size == vm->global_object_list_capa) { size_t new_capa = vm->global_object_list_capa ? vm->global_object_list_capa * 2 : 64; - vm->global_object_list = SIZED_REALLOC_N(vm->global_object_list, VALUE *, new_capa, vm->global_object_list_capa); + SIZED_REALLOC_N(vm->global_object_list, VALUE *, new_capa, vm->global_object_list_capa); vm->global_object_list_capa = new_capa; } diff --git a/proc.c b/proc.c index c93ba2b636b55d..563f2393f3d2c9 100644 --- a/proc.c +++ b/proc.c @@ -385,19 +385,31 @@ rb_f_binding(VALUE self) } /* - * call-seq: - * binding.eval(string [, filename [,lineno]]) -> obj + * call-seq: + * binding.eval(string, filename = default_filename, lineno = 1) -> obj * - * Evaluates the Ruby expression(s) in string, in the - * binding's context. If the optional filename and - * lineno parameters are present, they will be used when - * reporting syntax errors. + * Evaluates the Ruby expression(s) in +string+ in the context of + * +self+. Returns the result of the last expression: * - * def get_binding(param) - * binding - * end + * def get_binding(param) = binding * b = get_binding("hello") * b.eval("param") #=> "hello" + * + * If the optional +filename+ is given, it will be used as the + * filename of the evaluation (for __FILE__ and errors). + * Otherwise, it will default to (eval at __FILE__:__LINE__) + * where __FILE__ and __LINE__ are the filename and + * line number of the caller, respectively: + * + * b.eval("puts __FILE__") # => "(eval at test.rb:4)" + * b.eval("puts __FILE__", "foobar.rb") # => "foobar.rb" + * + * If the optional +lineno+ is given, it will be used as the + * line number of the evaluation (for __LINE__ and errors). + * Otherwise, it will default to 1: + * + * b.eval("puts __LINE__") # => 1 + * b.eval("puts __LINE__", "foobar.rb", 10) # => 10 */ static VALUE @@ -1853,6 +1865,8 @@ mnew_missing_by_name(VALUE klass, VALUE obj, VALUE *name, int scope, VALUE mclas return mnew_missing(klass, obj, SYM2ID(vid), mclass); } +VALUE rb_zsuper_to_super(int argc, VALUE *argv, VALUE self); + static VALUE mnew_internal(const rb_method_entry_t *me, VALUE klass, VALUE iclass, VALUE obj, ID id, VALUE mclass, int scope, int error) @@ -1878,8 +1892,9 @@ mnew_internal(const rb_method_entry_t *me, VALUE klass, VALUE iclass, rb_print_inaccessible(klass, id, visi); } } - if (me->def->type == VM_METHOD_TYPE_ZSUPER) { - if (me->defined_class) { + if (me->def->type == VM_METHOD_TYPE_ZSUPER || + (me->def->type == VM_METHOD_TYPE_CFUNC && me->def->body.cfunc.func == (rb_cfunc_t)rb_zsuper_to_super)) { + if (me->def->type == VM_METHOD_TYPE_ZSUPER && me->defined_class) { VALUE klass = RCLASS_SUPER(RCLASS_ORIGIN(me->defined_class)); id = me->def->original_id; me = (rb_method_entry_t *)rb_callable_method_entry_with_refinements(klass, id, &iclass); @@ -3071,7 +3086,11 @@ original_method_entry(VALUE mod, ID id) while ((me = rb_method_entry(mod, id)) != 0) { const rb_method_definition_t *def = me->def; - if (def->type != VM_METHOD_TYPE_ZSUPER) break; + + if (def->type != VM_METHOD_TYPE_ZSUPER && + (def->type != VM_METHOD_TYPE_CFUNC || + def->body.cfunc.func != (rb_cfunc_t)rb_zsuper_to_super)) break; + mod = RCLASS_SUPER(me->owner); id = def->original_id; } diff --git a/test/ruby/test_refinement.rb b/test/ruby/test_refinement.rb index c3ded524fc891d..5089135043929e 100644 --- a/test/ruby/test_refinement.rb +++ b/test/ruby/test_refinement.rb @@ -1675,6 +1675,33 @@ def a = :b end end + def test_zsuper_refinement_method_arity_and_parameters + assert_separately([], <<-"end;") + class A + private def a(b) = b + end + + class B < A + public :a + end + + module R + refine A do + public :a + end + end + using R + + m = B.instance_method(:a) + assert_equal(1, m.arity) + assert_equal([[:req, :b]], m.parameters) + + m = A.instance_method(:a) + assert_equal(1, m.arity) + assert_equal([[:req, :b]], m.parameters) + end; + end + def test_instance_methods bug8881 = '[ruby-core:57080] [Bug #8881]' assert_not_include(Foo.instance_methods(false), :z, bug8881) diff --git a/vm_method.c b/vm_method.c index 244ebbb720b0e0..5ef47e97ac51e5 100644 --- a/vm_method.c +++ b/vm_method.c @@ -1370,8 +1370,8 @@ check_override_opt_method(VALUE klass, VALUE mid) } } -static VALUE -zsuper_to_super(int argc, VALUE *argv, VALUE self) +VALUE +rb_zsuper_to_super(int argc, VALUE *argv, VALUE self) { return rb_call_super_kw(argc, argv, RB_PASS_CALLED_KEYWORDS); } @@ -1486,7 +1486,7 @@ rb_method_entry_make(VALUE klass, ID mid, VALUE defined_class, rb_method_visibil def = rb_method_definition_create(type, original_id); if (turn_zsuper_to_super) { def->type = VM_METHOD_TYPE_CFUNC; - def->body.cfunc.func = (rb_cfunc_t)zsuper_to_super; + def->body.cfunc.func = (rb_cfunc_t)rb_zsuper_to_super; def->body.cfunc.invoker = ractor_safe_call_cfunc_m1; def->body.cfunc.argc = -1; } diff --git a/zjit.rb b/zjit.rb index 480ffa15441f64..cd4f9188b208cc 100644 --- a/zjit.rb +++ b/zjit.rb @@ -157,7 +157,7 @@ def stats_string :gc_time_ns, :invalidation_time_ns, - :vm_write_pc_count, + :vm_write_jit_frame_count, :vm_write_sp_count, :vm_write_locals_count, :vm_write_stack_count, diff --git a/zjit/src/codegen.rs b/zjit/src/codegen.rs index acc5002a2a267c..f4d62fc7bcef43 100644 --- a/zjit/src/codegen.rs +++ b/zjit/src/codegen.rs @@ -2708,8 +2708,8 @@ fn gen_save_pc_for_gc(asm: &mut Assembler, state: &FrameState) { let opcode: usize = state.get_opcode().try_into().unwrap(); let next_pc: *const VALUE = unsafe { state.pc.offset(insn_len(opcode) as isize) }; - gen_incr_counter(asm, Counter::vm_write_pc_count); - asm_comment!(asm, "save PC to CFP"); + gen_incr_counter(asm, Counter::vm_write_jit_frame_count); + asm_comment!(asm, "save JITFrame to CFP"); if let Some(pc) = PC_POISON { asm.mov(Opnd::mem(64, CFP, RUBY_OFFSET_CFP_PC), Opnd::const_ptr(pc)); } diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index e350387dc27999..e5976a4045d642 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -2998,8 +2998,8 @@ impl Function { Insn::GetEP { .. } => types::CPtr, Insn::LoadSelf => types::BasicObject, &Insn::LoadField { return_type, .. } => return_type, - Insn::GetSpecialSymbol { .. } => types::BasicObject, - Insn::GetSpecialNumber { .. } => types::BasicObject, + Insn::GetSpecialSymbol { .. } => types::StringExact.union(types::NilClass), + Insn::GetSpecialNumber { .. } => types::StringExact.union(types::NilClass), Insn::GetClassVar { .. } => types::BasicObject, Insn::ToNewArray { .. } => types::ArrayExact, Insn::ToArray { .. } => types::ArrayExact, diff --git a/zjit/src/hir/opt_tests.rs b/zjit/src/hir/opt_tests.rs index e8a0488023da88..3435347d338c21 100644 --- a/zjit/src/hir/opt_tests.rs +++ b/zjit/src/hir/opt_tests.rs @@ -11109,7 +11109,7 @@ mod hir_opt_tests { } #[test] - fn test_dont_inline_integer_xor_with_bignum_or_boolean() { + fn test_dont_inline_integer_xor_with_bignum_lhs() { eval(" def test(x, y) = x ^ y test(4 << 70, 1) @@ -11136,7 +11136,10 @@ mod hir_opt_tests { CheckInterrupts Return v28 "); + } + #[test] + fn test_dont_inline_integer_xor_with_bignum_rhs() { eval(" def test(x, y) = x ^ y test(1, 4 << 70) @@ -11163,7 +11166,10 @@ mod hir_opt_tests { CheckInterrupts Return v28 "); + } + #[test] + fn test_dont_inline_integer_xor_with_boolean() { eval(" def test(x, y) = x ^ y test(true, 0) diff --git a/zjit/src/hir/tests.rs b/zjit/src/hir/tests.rs index 7466d4bb1a071a..566cf7aeb7cf7a 100644 --- a/zjit/src/hir/tests.rs +++ b/zjit/src/hir/tests.rs @@ -5525,6 +5525,66 @@ pub(crate) mod hir_build_tests { assert!(hir.contains("BreakPoint")); assert!(hir.contains("Return v")); } + + #[test] + fn test_getspecialnumber() { + eval(" + def test(a) + a =~/(hello)/ + $1 + end + "); + assert_snapshot!(hir_string("test"), @" + fn test@:3: + bb1(): + EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:CPtr = LoadSP + v3:BasicObject = LoadField v2, :a@0x1000 + Jump bb3(v1, v3) + bb2(): + EntryPoint JIT(0) + v6:BasicObject = LoadArg :self@0 + v7:BasicObject = LoadArg :a@1 + Jump bb3(v6, v7) + bb3(v9:BasicObject, v10:BasicObject): + v15:RegexpExact[VALUE(0x1008)] = Const Value(VALUE(0x1008)) + v18:BasicObject = Send v10, :=~, v15 # SendFallbackReason: Uncategorized(opt_regexpmatch2) + v22:StringExact|NilClass = GetSpecialNumber 2 + CheckInterrupts + Return v22 + "); + } + + #[test] + fn test_getspecialsymbol() { + eval(" + def test(a) + a =~/(hello)/ + $& + end + "); + assert_snapshot!(hir_string("test"), @" + fn test@:3: + bb1(): + EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:CPtr = LoadSP + v3:BasicObject = LoadField v2, :a@0x1000 + Jump bb3(v1, v3) + bb2(): + EntryPoint JIT(0) + v6:BasicObject = LoadArg :self@0 + v7:BasicObject = LoadArg :a@1 + Jump bb3(v6, v7) + bb3(v9:BasicObject, v10:BasicObject): + v15:RegexpExact[VALUE(0x1008)] = Const Value(VALUE(0x1008)) + v18:BasicObject = Send v10, :=~, v15 # SendFallbackReason: Uncategorized(opt_regexpmatch2) + v22:StringExact|NilClass = GetSpecialSymbol LastMatch + CheckInterrupts + Return v22 + "); + } } /// Test successor and predecessor set computations. diff --git a/zjit/src/stats.rs b/zjit/src/stats.rs index 22fbb2b23fc20f..57320a02e750bd 100644 --- a/zjit/src/stats.rs +++ b/zjit/src/stats.rs @@ -440,7 +440,7 @@ make_counters! { complex_arg_pass_caller_forwarding, // Writes to the VM frame - vm_write_pc_count, + vm_write_jit_frame_count, vm_write_sp_count, vm_write_locals_count, vm_write_stack_count,