From 8a579ae1cd5f7436a09d9f3e0c9c707c2f5b7e48 Mon Sep 17 00:00:00 2001 From: Max Bernstein Date: Thu, 19 Mar 2026 14:50:38 -0400 Subject: [PATCH 01/10] ZJIT: Clean up run_pass with macro identifier matching (#16459) Thanks, Alan. --- zjit/src/hir.rs | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index 72086cdf964ed6..e87f1ee006d924 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -5620,33 +5620,25 @@ impl Function { let mut passes: Vec = Vec::new(); let should_dump = get_option!(dump_hir_iongraph); - macro_rules! ident_equal { - ($a:ident, $b:ident) => { stringify!($a) == stringify!($b) }; + macro_rules! counter_for { + // Bucket all strength reduction together + (type_specialize) => { Counter::compile_hir_strength_reduce_time_ns }; + (inline) => { Counter::compile_hir_strength_reduce_time_ns }; + (optimize_getivar) => { Counter::compile_hir_strength_reduce_time_ns }; + (optimize_c_calls) => { Counter::compile_hir_strength_reduce_time_ns }; + // End strength reduction bucket + (optimize_load_store) => { Counter::compile_hir_optimize_load_store_time_ns }; + (fold_constants) => { Counter::compile_hir_fold_constants_time_ns }; + (clean_cfg) => { Counter::compile_hir_clean_cfg_time_ns }; + (remove_redundant_patch_points) => { Counter::compile_hir_remove_redundant_patch_points_time_ns }; + (remove_duplicate_check_interrupts) => { Counter::compile_hir_remove_duplicate_check_interrupts_time_ns }; + (eliminate_dead_code) => { Counter::compile_hir_eliminate_dead_code_time_ns }; + ($name:ident) => { unimplemented!("Counter for pass {}", stringify!($name)) }; } macro_rules! run_pass { ($name:ident) => { - // Bucket all strength reduction together - let counter = if ident_equal!($name, type_specialize) - || ident_equal!($name, inline) - || ident_equal!($name, optimize_getivar) - || ident_equal!($name, optimize_c_calls) { - Counter::compile_hir_strength_reduce_time_ns - } else if ident_equal!($name, optimize_load_store) { - Counter::compile_hir_optimize_load_store_time_ns - } else if ident_equal!($name, fold_constants) { - Counter::compile_hir_fold_constants_time_ns - } else if ident_equal!($name, clean_cfg) { - Counter::compile_hir_clean_cfg_time_ns - } else if ident_equal!($name, remove_redundant_patch_points) { - Counter::compile_hir_remove_redundant_patch_points_time_ns - } else if ident_equal!($name, remove_duplicate_check_interrupts) { - Counter::compile_hir_remove_duplicate_check_interrupts_time_ns - } else if ident_equal!($name, eliminate_dead_code) { - Counter::compile_hir_eliminate_dead_code_time_ns - } else { - unimplemented!("Counter for pass {}", stringify!($name)); - }; + let counter = counter_for!($name); crate::stats::with_time_stat(counter, || self.$name()); #[cfg(debug_assertions)] self.assert_validates(); if should_dump { From aecc11af38e00788942c8e923cd5d886c24eca0e Mon Sep 17 00:00:00 2001 From: Gareth Jones <3151613+G-Rath@users.noreply.github.com> Date: Fri, 20 Mar 2026 08:00:47 +1300 Subject: [PATCH 02/10] [ruby/erb] fix: exclude some files from published gem (https://github.com/ruby/erb/pull/108) https://github.com/ruby/erb/commit/2fd0a6b71c Co-authored-by: Takashi Kokubun --- lib/erb/erb.gemspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/erb/erb.gemspec b/lib/erb/erb.gemspec index 3793e5d70fac87..70113a2a04115e 100644 --- a/lib/erb/erb.gemspec +++ b/lib/erb/erb.gemspec @@ -20,8 +20,8 @@ Gem::Specification.new do |spec| spec.metadata['source_code_uri'] = spec.homepage spec.metadata['changelog_uri'] = "https://github.com/ruby/erb/blob/v#{spec.version}/NEWS.md" - spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do - `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } + spec.files = Dir.chdir(__dir__) do + `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|\.git|\.github)/}) } end spec.bindir = 'libexec' spec.executables = ['erb'] From c1745f40ac5ebafd495ffb42dd0416a6ec5de932 Mon Sep 17 00:00:00 2001 From: Burdette Lamar Date: Thu, 19 Mar 2026 18:28:58 -0500 Subject: [PATCH 03/10] Fix links (#16458) * [DOC] Fix links * [DOC] Fix links --- file.c | 2 +- io.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/file.c b/file.c index e503de9d932c3d..e40f67ec73817a 100644 --- a/file.c +++ b/file.c @@ -3425,7 +3425,7 @@ unlink_internal(const char *path, void *arg) * Since the underlying implementation relies on the * unlink(2) system call, the type of * exception raised depends on its error type (see - * https://linux.die.net/man/2/unlink) and has the form of + * https://man7.org/linux/man-pages/man2/unlink.2.html) and has the form of * e.g. Errno::ENOENT. * * See also Dir::rmdir. diff --git a/io.c b/io.c index 0ac78e96cca28d..ab04d8df22864c 100644 --- a/io.c +++ b/io.c @@ -10948,7 +10948,7 @@ advice_arg_check(VALUE advice) * advise(advice, offset = 0, len = 0) -> nil * * Invokes Posix system call - * {posix_fadvise(2)}[https://linux.die.net/man/2/posix_fadvise], + * {posix_fadvise(2)}[https://man7.org/linux/man-pages/man2/posix_fadvise.2.html], * which announces an intention to access data from the current file * in a particular manner. * @@ -11014,7 +11014,7 @@ is_pos_inf(VALUE x) * call-seq: * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil * - * Invokes system call {select(2)}[https://linux.die.net/man/2/select], + * Invokes system call {select(2)}[https://man7.org/linux/man-pages/man2/select.2.html], * which monitors multiple file descriptors, * waiting until one or more of the file descriptors * becomes ready for some class of I/O operation. @@ -11101,7 +11101,7 @@ is_pos_inf(VALUE x) * Finally, Linux kernel developers don't guarantee that * readability of select(2) means readability of following read(2) even * for a single process; - * see {select(2)}[https://linux.die.net/man/2/select] + * see {select(2)}[https://man7.org/linux/man-pages/man2/select.2.html] * * Invoking \IO.select before IO#readpartial works well as usual. * However it is not the best way to use \IO.select. @@ -11495,7 +11495,7 @@ rb_ioctl(VALUE io, VALUE req, VALUE arg) * call-seq: * ioctl(integer_cmd, argument) -> integer * - * Invokes Posix system call {ioctl(2)}[https://linux.die.net/man/2/ioctl], + * Invokes Posix system call {ioctl(2)}[https://man7.org/linux/man-pages/man2/ioctl.2.html], * which issues a low-level command to an I/O device. * * Issues a low-level command to an I/O device. @@ -11584,7 +11584,7 @@ rb_fcntl(VALUE io, VALUE req, VALUE arg) * call-seq: * fcntl(integer_cmd, argument) -> integer * - * Invokes Posix system call {fcntl(2)}[https://linux.die.net/man/2/fcntl], + * Invokes Posix system call {fcntl(2)}[https://man7.org/linux/man-pages/man2/fcntl.2.html], * which provides a mechanism for issuing low-level commands to control or query * a file-oriented I/O stream. Arguments and results are platform * dependent. @@ -11614,7 +11614,7 @@ rb_io_fcntl(int argc, VALUE *argv, VALUE io) * call-seq: * syscall(integer_callno, *arguments) -> integer * - * Invokes Posix system call {syscall(2)}[https://linux.die.net/man/2/syscall], + * Invokes Posix system call {syscall(2)}[https://man7.org/linux/man-pages/man2/syscall.2.html], * which calls a specified function. * * Calls the operating system function identified by +integer_callno+; From e9c482582872f33f03ab972be78e47c806c0971a Mon Sep 17 00:00:00 2001 From: Burdette Lamar Date: Thu, 19 Mar 2026 18:30:50 -0500 Subject: [PATCH 04/10] [ruby/date] [DOC] Fix link (https://github.com/ruby/date/pull/160) https://github.com/ruby/date/commit/54974fe8e5 --- ext/date/date_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/date/date_core.c b/ext/date/date_core.c index 9755fb819eaaa9..f37c1a54e5f53e 100644 --- a/ext/date/date_core.c +++ b/ext/date/date_core.c @@ -7478,7 +7478,7 @@ strftimev(const char *fmt, VALUE self, * * Date.new(2001, 2, 3).asctime # => "Sat Feb 3 00:00:00 2001" * - * See {asctime}[https://linux.die.net/man/3/asctime]. + * See {asctime}[https://man7.org/linux/man-pages/man3/asctime.3p.html]. * */ static VALUE From 1a2d8c7860de4d2749f014acdad10d2daaab1387 Mon Sep 17 00:00:00 2001 From: Jacob Denbeaux Date: Thu, 19 Mar 2026 17:01:50 -0400 Subject: [PATCH 05/10] Move compile_time_heap into block for load-store optimization --- zjit/src/hir.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index e87f1ee006d924..10c420336bc7ad 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -4949,8 +4949,8 @@ impl Function { } fn optimize_load_store(&mut self) { - let mut compile_time_heap: HashMap<(InsnId, i32), InsnId> = HashMap::new(); for block in self.rpo() { + let mut compile_time_heap: HashMap<(InsnId, i32), InsnId> = HashMap::new(); let old_insns = std::mem::take(&mut self.blocks[block.0].insns); let mut new_insns = vec![]; for insn_id in old_insns { From e7fa7293fd227879298861642fb0aa76950b0d86 Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Tue, 17 Mar 2026 21:05:10 -0700 Subject: [PATCH 06/10] ZJIT: Fix TracePoint return value for methods with rescue When ZJIT's send fallback (gen_send_without_block) cannot optimize a Send instruction, it calls rb_vm_opt_send_without_block, which uses VM_EXEC to execute the callee. VM_EXEC sets VM_FRAME_FLAG_FINISH on the callee's frame. In the interpreter, the same send is dispatched inline by vm_exec_core without setting FLAG_FINISH. This flag difference changes how `throw TAG_RETURN` (used by `return` inside `rescue`) is processed in vm_exec_handle_exception: - Without FLAG_FINISH: TAG_RETURN is converted to TAG_BREAK, and frame_return_value() returns the actual value (e.g. :f_raise_return) - With FLAG_FINISH: TAG_RETURN stays as-is, and frame_return_value() returns Qnil This caused TracePoint to report nil instead of the actual return value for methods like: def f_raise raise rescue return :f_raise_return end Fix by skipping ZJIT compilation while ISEQ trace events are active, so methods fall back to the interpreter which handles sends inline. --- vm.c | 11 +++++++++++ zjit.c | 19 +++++++++++++++++++ zjit/src/codegen_tests.rs | 24 ++++++++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/vm.c b/vm.c index 916e379d671a1e..0fa87a63efe59a 100644 --- a/vm.c +++ b/vm.c @@ -533,12 +533,23 @@ yjit_compile(rb_execution_context_t *ec) #endif #if USE_ZJIT +bool rb_zjit_iseq_tracing_currently_enabled(void); + static inline rb_jit_func_t zjit_compile(rb_execution_context_t *ec) { const rb_iseq_t *iseq = ec->cfp->iseq; struct rb_iseq_constant_body *body = ISEQ_BODY(iseq); + // Don't compile while tracing is active. ZJIT's send fallback uses + // rb_vm_opt_send_without_block which calls VM_EXEC, setting FLAG_FINISH + // on the callee frame. This changes exception handling semantics for + // throw TAG_RETURN (e.g. return from rescue), causing TracePoint to + // report nil instead of the actual return value. [Bug #21389] + if (rb_zjit_iseq_tracing_currently_enabled()) { + return NULL; + } + if (body->jit_entry == NULL) { body->jit_entry_calls++; diff --git a/zjit.c b/zjit.c index 1fdccbff64fab0..7704f4975e0cbb 100644 --- a/zjit.c +++ b/zjit.c @@ -264,6 +264,25 @@ rb_zjit_method_tracing_currently_enabled(void) return tracing_events & (RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN); } +// Check if any ISEQ trace events are currently enabled. +// Used to prevent ZJIT from compiling while tracing is active, since ZJIT's +// send fallback (rb_vm_opt_send_without_block) uses VM_EXEC which sets +// VM_FRAME_FLAG_FINISH on the callee frame, changing exception handling +// semantics for throw TAG_RETURN (e.g. return from rescue). +bool +rb_zjit_iseq_tracing_currently_enabled(void) +{ + rb_event_flag_t tracing_events; + if (rb_multi_ractor_p()) { + tracing_events = ruby_vm_event_enabled_global_flags; + } + else { + tracing_events = rb_ec_ractor_hooks(GET_EC())->events; + } + + return tracing_events & ISEQ_TRACE_EVENTS; +} + bool rb_zjit_insn_leaf(int insn, const VALUE *opes) { diff --git a/zjit/src/codegen_tests.rs b/zjit/src/codegen_tests.rs index c3b67b9ff89865..143200c2bc72cf 100644 --- a/zjit/src/codegen_tests.rs +++ b/zjit/src/codegen_tests.rs @@ -5156,3 +5156,27 @@ fn test_local_tracepoint() { called "), @"true"); } + +// Regression test: TracePoint return value for methods with rescue that use `return`. +// ZJIT's send fallback uses rb_vm_opt_send_without_block which calls VM_EXEC, +// setting FLAG_FINISH on the callee frame. This changes how throw TAG_RETURN is +// handled, causing the return value to be nil instead of the actual value. +#[test] +fn test_tracepoint_return_value_with_rescue() { + assert_snapshot!(inspect(" + def f_raise + raise + rescue + return :f_raise_return + end + + ary = [] + TracePoint.new(:return, :b_return){|tp| + ary << [tp.event, tp.method_id, tp.return_value] + }.enable{ + send :f_raise + } + ary.pop # last b_return event is not required + ary + "), @"[[:return, :f_raise, :f_raise_return]]"); +} From af459daea4afd67ada06c5fbde11501cd96db96e Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Thu, 19 Mar 2026 09:51:06 -0700 Subject: [PATCH 07/10] ZJIT: Use counted side exits for send fallbacks while tracing Instead of blocking compilation entirely when tracing is active, emit counted side exits in HIR before send fallback instructions that use VM_EXEC (which sets FLAG_FINISH on the callee frame, breaking throw TAG_RETURN semantics). This gives us runtime stats on how often tracing causes side exits while still allowing compilation. The tracing check is done at HIR construction time so that Send fallback instructions are never emitted into the IR when tracing is active, replaced by SideExit instructions instead. Affected YARV instructions: opt_neq, opt_send_without_block (and all opt_* variants), send, sendforward, invokesuper, invokesuperforward, invokeblock. --- vm.c | 11 ---------- zjit/bindgen/src/main.rs | 1 + zjit/src/cruby_bindings.inc.rs | 1 + zjit/src/hir.rs | 37 ++++++++++++++++++++++++++++++++++ zjit/src/stats.rs | 2 ++ 5 files changed, 41 insertions(+), 11 deletions(-) diff --git a/vm.c b/vm.c index 0fa87a63efe59a..916e379d671a1e 100644 --- a/vm.c +++ b/vm.c @@ -533,23 +533,12 @@ yjit_compile(rb_execution_context_t *ec) #endif #if USE_ZJIT -bool rb_zjit_iseq_tracing_currently_enabled(void); - static inline rb_jit_func_t zjit_compile(rb_execution_context_t *ec) { const rb_iseq_t *iseq = ec->cfp->iseq; struct rb_iseq_constant_body *body = ISEQ_BODY(iseq); - // Don't compile while tracing is active. ZJIT's send fallback uses - // rb_vm_opt_send_without_block which calls VM_EXEC, setting FLAG_FINISH - // on the callee frame. This changes exception handling semantics for - // throw TAG_RETURN (e.g. return from rescue), causing TracePoint to - // report nil instead of the actual return value. [Bug #21389] - if (rb_zjit_iseq_tracing_currently_enabled()) { - return NULL; - } - if (body->jit_entry == NULL) { body->jit_entry_calls++; diff --git a/zjit/bindgen/src/main.rs b/zjit/bindgen/src/main.rs index fa61f61481fd95..3e82efd8f623bc 100644 --- a/zjit/bindgen/src/main.rs +++ b/zjit/bindgen/src/main.rs @@ -292,6 +292,7 @@ fn main() { .allowlist_function("rb_set_cfp_(pc|sp)") .allowlist_function("rb_c_method_tracing_currently_enabled") .allowlist_function("rb_zjit_method_tracing_currently_enabled") + .allowlist_function("rb_zjit_iseq_tracing_currently_enabled") .allowlist_function("rb_full_cfunc_return") .allowlist_function("rb_assert_(iseq|cme)_handle") .allowlist_function("rb_IMEMO_TYPE_P") diff --git a/zjit/src/cruby_bindings.inc.rs b/zjit/src/cruby_bindings.inc.rs index 2b643d22ddd471..41ebdb0f55b512 100644 --- a/zjit/src/cruby_bindings.inc.rs +++ b/zjit/src/cruby_bindings.inc.rs @@ -2151,6 +2151,7 @@ unsafe extern "C" { pub fn rb_zjit_singleton_class_p(klass: VALUE) -> bool; pub fn rb_zjit_defined_ivar(obj: VALUE, id: ID, pushval: VALUE) -> VALUE; pub fn rb_zjit_method_tracing_currently_enabled() -> bool; + pub fn rb_zjit_iseq_tracing_currently_enabled() -> bool; pub fn rb_zjit_insn_leaf(insn: ::std::os::raw::c_int, opes: *const VALUE) -> bool; pub fn rb_zjit_local_id(iseq: *const rb_iseq_t, idx: ::std::os::raw::c_uint) -> ID; pub fn rb_zjit_cme_is_cfunc( diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index 10c420336bc7ad..4471827986ce65 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -532,6 +532,7 @@ pub enum SideExitReason { SplatKwPolymorphic, SplatKwNotProfiled, DirectiveInduced, + SendWhileTracing, } #[derive(Debug, Clone, Copy)] @@ -7509,6 +7510,11 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result { } let argc = unsafe { vm_ci_argc((*cd).ci) }; + // Side-exit send fallbacks while tracing to avoid FLAG_FINISH breaking throw TAG_RETURN semantics + if unsafe { rb_zjit_iseq_tracing_currently_enabled() } { + fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::SendWhileTracing }); + break; + } let args = state.stack_pop_n(argc as usize)?; let recv = state.stack_pop()?; let send = fun.push_insn(block, Insn::Send { recv, cd, blockiseq: None, args, state: exit_id, reason: Uncategorized(opcode) }); @@ -7638,6 +7644,12 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result { } } + // Side-exit send fallbacks while tracing to avoid FLAG_FINISH breaking throw TAG_RETURN semantics + if unsafe { rb_zjit_iseq_tracing_currently_enabled() } { + fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::SendWhileTracing }); + break; + } + { fn new_branch_block( fun: &mut Function, @@ -7724,6 +7736,11 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result { fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnhandledCallType(call_type) }); break; // End the block } + // Side-exit send fallbacks while tracing to avoid FLAG_FINISH breaking throw TAG_RETURN semantics + if unsafe { rb_zjit_iseq_tracing_currently_enabled() } { + fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::SendWhileTracing }); + break; + } let argc = unsafe { vm_ci_argc((*cd).ci) }; let block_arg = (flags & VM_CALL_ARGS_BLOCKARG) != 0; @@ -7758,6 +7775,11 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result { fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnhandledCallType(call_type) }); break; // End the block } + // Side-exit send fallbacks while tracing to avoid FLAG_FINISH breaking throw TAG_RETURN semantics + if unsafe { rb_zjit_iseq_tracing_currently_enabled() } { + fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::SendWhileTracing }); + break; + } let argc = unsafe { vm_ci_argc((*cd).ci) }; let args = state.stack_pop_n(argc as usize + usize::from(forwarding))?; @@ -7787,6 +7809,11 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result { fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnhandledCallType(call_type) }); break; // End the block } + // Side-exit send fallbacks while tracing to avoid FLAG_FINISH breaking throw TAG_RETURN semantics + if unsafe { rb_zjit_iseq_tracing_currently_enabled() } { + fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::SendWhileTracing }); + break; + } let argc = unsafe { vm_ci_argc((*cd).ci) }; let block_arg = (flags & VM_CALL_ARGS_BLOCKARG) != 0; let args = state.stack_pop_n(argc as usize + usize::from(block_arg))?; @@ -7821,6 +7848,11 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result { fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnhandledCallType(call_type) }); break; // End the block } + // Side-exit send fallbacks while tracing to avoid FLAG_FINISH breaking throw TAG_RETURN semantics + if unsafe { rb_zjit_iseq_tracing_currently_enabled() } { + fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::SendWhileTracing }); + break; + } let argc = unsafe { vm_ci_argc((*cd).ci) }; let args = state.stack_pop_n(argc as usize + usize::from(forwarding))?; let recv = state.stack_pop()?; @@ -7851,6 +7883,11 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result { fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnhandledCallType(call_type) }); break; // End the block } + // Side-exit send fallbacks while tracing to avoid FLAG_FINISH breaking throw TAG_RETURN semantics + if unsafe { rb_zjit_iseq_tracing_currently_enabled() } { + fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::SendWhileTracing }); + break; + } let argc = unsafe { vm_ci_argc((*cd).ci) }; let block_arg = (flags & VM_CALL_ARGS_BLOCKARG) != 0; let args = state.stack_pop_n(argc as usize + usize::from(block_arg))?; diff --git a/zjit/src/stats.rs b/zjit/src/stats.rs index 47a434360da5ff..66f418067cfcc9 100644 --- a/zjit/src/stats.rs +++ b/zjit/src/stats.rs @@ -232,6 +232,7 @@ make_counters! { exit_splatkw_polymorphic, exit_splatkw_not_profiled, exit_directive_induced, + exit_send_while_tracing, } // Send fallback counters that are summed as dynamic_send_count @@ -616,6 +617,7 @@ pub fn side_exit_counter(reason: crate::hir::SideExitReason) -> Counter { => exit_patchpoint_no_singleton_class, PatchPoint(Invariant::RootBoxOnly) => exit_patchpoint_root_box_only, + SendWhileTracing => exit_send_while_tracing, } } From 7383c92c2abdc024af7160e6c57e08fc527506c6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Mar 2026 02:09:07 +0000 Subject: [PATCH 08/10] Bump taiki-e/install-action Bumps the github-actions group with 1 update in the / directory: [taiki-e/install-action](https://github.com/taiki-e/install-action). Updates `taiki-e/install-action` from 2.68.36 to 2.69.2 - [Release notes](https://github.com/taiki-e/install-action/releases) - [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/taiki-e/install-action/compare/3a911424851a96b72dc168c8dd71fd98ed215d66...42721ded7ddc3cd90f687527e8602066e4e1ff3a) --- updated-dependencies: - dependency-name: taiki-e/install-action dependency-version: 2.69.2 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/zjit-macos.yml | 2 +- .github/workflows/zjit-ubuntu.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/zjit-macos.yml b/.github/workflows/zjit-macos.yml index 2db82efd2fc265..d43de41125df47 100644 --- a/.github/workflows/zjit-macos.yml +++ b/.github/workflows/zjit-macos.yml @@ -92,7 +92,7 @@ jobs: rustup install ${{ matrix.rust_version }} --profile minimal rustup default ${{ matrix.rust_version }} - - uses: taiki-e/install-action@3a911424851a96b72dc168c8dd71fd98ed215d66 # v2.68.36 + - uses: taiki-e/install-action@42721ded7ddc3cd90f687527e8602066e4e1ff3a # v2.69.2 with: tool: nextest@0.9 if: ${{ matrix.test_task == 'zjit-check' }} diff --git a/.github/workflows/zjit-ubuntu.yml b/.github/workflows/zjit-ubuntu.yml index e4a9842c5ad3c6..4f226da9fb8d6f 100644 --- a/.github/workflows/zjit-ubuntu.yml +++ b/.github/workflows/zjit-ubuntu.yml @@ -119,7 +119,7 @@ jobs: ruby-version: '3.1' bundler: none - - uses: taiki-e/install-action@3a911424851a96b72dc168c8dd71fd98ed215d66 # v2.68.36 + - uses: taiki-e/install-action@42721ded7ddc3cd90f687527e8602066e4e1ff3a # v2.69.2 with: tool: nextest@0.9 if: ${{ matrix.test_task == 'zjit-check' }} From 8b9635e14102d845362bec8e2ca0c79daa35b383 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Mar 2026 20:10:19 -0700 Subject: [PATCH 09/10] Bump github.com/microsoft/vcpkg from master to 2026.03.18 (#16472) --- vcpkg.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vcpkg.json b/vcpkg.json index 0bb6deaa118bcb..2652e626e55a83 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -7,5 +7,5 @@ "openssl", "zlib" ], - "builtin-baseline": "66c0373dc7fca549e5803087b9487edfe3aca0a1" + "builtin-baseline": "c3867e714dd3a51c272826eea77267876517ed99" } \ No newline at end of file From a5e2cbce97506d13f793667a967605dbe7c9e5f4 Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Thu, 19 Mar 2026 17:41:18 -0700 Subject: [PATCH 10/10] ZJIT: Prepare frame state before getivar calls rb_ivar_get can raise Ractor::IsolationError for class/module ivars from non-main Ractors. Without gen_prepare_non_leaf_call, the frame state is not properly set up when the exception is raised, which can lead to crashes or incorrect behavior during exception handling. --- zjit/src/codegen.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/zjit/src/codegen.rs b/zjit/src/codegen.rs index 0dd35bdf7eaaac..e51ddafe33798e 100644 --- a/zjit/src/codegen.rs +++ b/zjit/src/codegen.rs @@ -630,7 +630,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio Insn::CCallVariadic { cfunc, recv, name, args, cme, state, blockiseq, return_type: _, elidable: _ } => { gen_ccall_variadic(jit, asm, *cfunc, *name, opnd!(recv), opnds!(args), *cme, *blockiseq, &function.frame_state(*state)) } - Insn::GetIvar { self_val, id, ic, state: _ } => gen_getivar(jit, asm, opnd!(self_val), *id, *ic), + Insn::GetIvar { self_val, id, ic, state } => gen_getivar(jit, asm, opnd!(self_val), *id, *ic, &function.frame_state(*state)), Insn::SetGlobal { id, val, state } => no_output!(gen_setglobal(jit, asm, *id, opnd!(val), &function.frame_state(*state))), Insn::GetGlobal { id, state } => gen_getglobal(jit, asm, *id, &function.frame_state(*state)), &Insn::IsBlockParamModified { ep } => gen_is_block_param_modified(asm, opnd!(ep)), @@ -1107,7 +1107,9 @@ fn gen_ccall_variadic( } /// Emit an uncached instance variable lookup -fn gen_getivar(jit: &mut JITState, asm: &mut Assembler, recv: Opnd, id: ID, ic: *const iseq_inline_iv_cache_entry) -> Opnd { +fn gen_getivar(jit: &mut JITState, asm: &mut Assembler, recv: Opnd, id: ID, ic: *const iseq_inline_iv_cache_entry, state: &FrameState) -> Opnd { + // rb_ivar_get can raise Ractor::IsolationError for class/module ivars from non-main Ractors + gen_prepare_non_leaf_call(jit, asm, state); if ic.is_null() { asm_ccall!(asm, rb_ivar_get, recv, id.0.into()) } else {