From 961683bcb10ad7e470c7956104f34ef9220b6de4 Mon Sep 17 00:00:00 2001 From: Satoshi Tagomori Date: Fri, 31 Oct 2025 20:06:33 +0900 Subject: [PATCH 1/5] Run .so init functions in namespaces to be loaded --- load.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/load.c b/load.c index 9a1ff53f5415da..d1d6969039b849 100644 --- a/load.c +++ b/load.c @@ -1212,17 +1212,19 @@ load_ext(VALUE path, VALUE fname) return (VALUE)dln_load_feature(RSTRING_PTR(loaded), RSTRING_PTR(fname)); } -static bool -run_static_ext_init(rb_vm_t *vm, const char *feature) +static VALUE +run_static_ext_init(VALUE vm_ptr, VALUE feature_value) { + rb_vm_t *vm = (rb_vm_t *)vm_ptr; + const char *feature = RSTRING_PTR(feature_value); st_data_t key = (st_data_t)feature; st_data_t init_func; if (vm->static_ext_inits && st_delete(vm->static_ext_inits, &key, &init_func)) { ((void (*)(void))init_func)(); - return true; + return Qtrue; } - return false; + return Qfalse; } static int @@ -1331,7 +1333,7 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa else if (!*ftptr) { result = TAG_RETURN; } - else if (found == 's' && run_static_ext_init(th->vm, RSTRING_PTR(path))) { + else if (found == 's' && RTEST(rb_vm_call_cfunc_in_namespace(Qnil, run_static_ext_init, (VALUE)th->vm, path, path, ns))) { result = TAG_RETURN; } else if (RTEST(rb_hash_aref(realpaths, From 65168b7eafd30fd3958d71761fa155bba00cdec5 Mon Sep 17 00:00:00 2001 From: Satoshi Tagomori Date: Fri, 31 Oct 2025 20:07:28 +0900 Subject: [PATCH 2/5] Specify RUBY_DEBUG flag in the right way --- namespace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/namespace.c b/namespace.c index 4e5a4e9bc42491..847aff9f872965 100644 --- a/namespace.c +++ b/namespace.c @@ -1084,7 +1084,7 @@ Init_Namespace(void) if (rb_namespace_available()) { rb_include_module(rb_cObject, rb_mNamespaceLoader); -#ifdef RUBY_DEBUG +#if RUBY_DEBUG > 0 rb_define_singleton_method(rb_cNamespace, "root", rb_namespace_s_root, 0); rb_define_singleton_method(rb_cNamespace, "main", rb_namespace_s_main, 0); rb_define_global_function("dump_classext", rb_f_dump_classext, 1); From 6bdb2027f64df8e6f59273488ea01ed1614bcf76 Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Fri, 31 Oct 2025 23:52:23 +0900 Subject: [PATCH 3/5] [ruby/json] Fix memory leak when exception is raised during JSON generation part 2 Commit https://github.com/ruby/json/commit/44df509dc2de fixed it for StandardError, but other exceptions and jumps are also possible. Use rb_ensure() to release FBuffer instead of rb_rescue(). A reproducer: o = Object.new def o.to_json(a) = throw :a a = ["make heap allocation"*100, o] 10.times do 100_000.times do catch(:a) { JSON(a) } end puts `ps -o rss= -p #{$$}` end https://github.com/ruby/json/commit/9b7b648ecd --- ext/json/fbuffer/fbuffer.h | 5 +---- ext/json/generator/generator.c | 18 +++++------------- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/ext/json/fbuffer/fbuffer.h b/ext/json/fbuffer/fbuffer.h index d5fd8ac6d71f78..7d57a87b14ff5e 100644 --- a/ext/json/fbuffer/fbuffer.h +++ b/ext/json/fbuffer/fbuffer.h @@ -283,13 +283,10 @@ static VALUE fbuffer_finalize(FBuffer *fb) { if (fb->io) { fbuffer_flush(fb); - fbuffer_free(fb); rb_io_flush(fb->io); return fb->io; } else { - VALUE result = rb_utf8_str_new(FBUFFER_PTR(fb), FBUFFER_LEN(fb)); - fbuffer_free(fb); - return result; + return rb_utf8_str_new(FBUFFER_PTR(fb), FBUFFER_LEN(fb)); } } diff --git a/ext/json/generator/generator.c b/ext/json/generator/generator.c index d04c8a90797b7d..72155abe523358 100644 --- a/ext/json/generator/generator.c +++ b/ext/json/generator/generator.c @@ -1444,16 +1444,14 @@ static VALUE generate_json_try(VALUE d) data->func(data->buffer, data, data->obj); - return Qnil; + return fbuffer_finalize(data->buffer); } -static VALUE generate_json_rescue(VALUE d, VALUE exc) +static VALUE generate_json_ensure(VALUE d) { struct generate_json_data *data = (struct generate_json_data *)d; fbuffer_free(data->buffer); - rb_exc_raise(exc); - return Qundef; } @@ -1474,9 +1472,7 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func, .obj = obj, .func = func }; - rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data); - - return fbuffer_finalize(&buffer); + return rb_ensure(generate_json_try, (VALUE)&data, generate_json_ensure, (VALUE)&data); } /* call-seq: @@ -1522,9 +1518,7 @@ static VALUE cState_generate_new(int argc, VALUE *argv, VALUE self) .obj = obj, .func = generate_json }; - rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data); - - return fbuffer_finalize(&buffer); + return rb_ensure(generate_json_try, (VALUE)&data, generate_json_ensure, (VALUE)&data); } static VALUE cState_initialize(int argc, VALUE *argv, VALUE self) @@ -2030,9 +2024,7 @@ static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io) .obj = obj, .func = generate_json, }; - rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data); - - return fbuffer_finalize(&buffer); + return rb_ensure(generate_json_try, (VALUE)&data, generate_json_ensure, (VALUE)&data); } /* From 2c88500c0825c6f3f0671d1718e660c85eff691d Mon Sep 17 00:00:00 2001 From: Max Bernstein Date: Fri, 31 Oct 2025 13:54:02 -0400 Subject: [PATCH 4/5] ZJIT: Simplify some profiling APIs (#15017) --- zjit/src/hir.rs | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index 94becee9c8796a..5a609670f4b9ba 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -2126,23 +2126,6 @@ impl Function { self.push_insn(block, Insn::GuardType { val, guard_type, state }) } - fn likely_is_fixnum(&self, val: InsnId, profiled_type: ProfiledType) -> bool { - self.is_a(val, types::Fixnum) || profiled_type.is_fixnum() - } - - fn coerce_to_fixnum(&mut self, block: BlockId, val: InsnId, state: InsnId) -> InsnId { - if self.is_a(val, types::Fixnum) { return val; } - self.push_insn(block, Insn::GuardType { val, guard_type: types::Fixnum, state }) - } - - fn arguments_likely_fixnums(&mut self, left: InsnId, right: InsnId, state: InsnId) -> bool { - let frame_state = self.frame_state(state); - let iseq_insn_idx = frame_state.insn_idx; - let left_profiled_type = self.profiled_type_of_at(left, iseq_insn_idx).unwrap_or_default(); - let right_profiled_type = self.profiled_type_of_at(right, iseq_insn_idx).unwrap_or_default(); - self.likely_is_fixnum(left, left_profiled_type) && self.likely_is_fixnum(right, right_profiled_type) - } - fn count_fancy_call_features(&mut self, block: BlockId, ci_flags: c_uint) { use Counter::*; if 0 != ci_flags & VM_CALL_ARGS_SPLAT { self.push_insn(block, Insn::IncrCounter(fancy_arg_pass_caller_splat)); } @@ -2161,14 +2144,14 @@ impl Function { self.push_insn_id(block, orig_insn_id); return; } - if self.arguments_likely_fixnums(left, right, state) { + if self.likely_a(left, types::Fixnum, state) && self.likely_a(right, types::Fixnum, state) { if bop == BOP_NEQ { // For opt_neq, the interpreter checks that both neq and eq are unchanged. self.push_insn(block, Insn::PatchPoint { invariant: Invariant::BOPRedefined { klass: INTEGER_REDEFINED_OP_FLAG, bop: BOP_EQ }, state }); } self.push_insn(block, Insn::PatchPoint { invariant: Invariant::BOPRedefined { klass: INTEGER_REDEFINED_OP_FLAG, bop }, state }); - let left = self.coerce_to_fixnum(block, left, state); - let right = self.coerce_to_fixnum(block, right, state); + let left = self.coerce_to(block, left, types::Fixnum, state); + let right = self.coerce_to(block, right, types::Fixnum, state); let result = self.push_insn(block, f(left, right)); self.make_equal_to(orig_insn_id, result); self.insn_types[result.0] = self.infer_type(result); @@ -2567,8 +2550,8 @@ impl Function { let high_is_fix = self.is_a(high, types::Fixnum); if low_is_fix || high_is_fix { - let low_fix = self.coerce_to_fixnum(block, low, state); - let high_fix = self.coerce_to_fixnum(block, high, state); + let low_fix = self.coerce_to(block, low, types::Fixnum, state); + let high_fix = self.coerce_to(block, high, types::Fixnum, state); let replacement = self.push_insn(block, Insn::NewRangeFixnum { low: low_fix, high: high_fix, flag, state }); self.make_equal_to(insn_id, replacement); self.insn_types[replacement.0] = self.infer_type(replacement); From 980e18496e1aafc642b199d24c81ab4a8afb3abb Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Fri, 31 Oct 2025 11:08:13 -0700 Subject: [PATCH 5/5] namespace.c: Fix -Wunused-function warnings --- namespace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/namespace.c b/namespace.c index 847aff9f872965..0f0230b5fdbd9a 100644 --- a/namespace.c +++ b/namespace.c @@ -876,7 +876,7 @@ Init_enable_namespace(void) } } -#ifdef RUBY_DEBUG +#if RUBY_DEBUG > 0 /* :nodoc: */ static VALUE