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,