Skip to content

[pull] master from ruby:master#892

Merged
pull[bot] merged 23 commits intoturkdevops:masterfrom
ruby:master
Mar 28, 2026
Merged

[pull] master from ruby:master#892
pull[bot] merged 23 commits intoturkdevops:masterfrom
ruby:master

Conversation

@pull
Copy link
Copy Markdown

@pull pull bot commented Mar 28, 2026

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

k0kubun and others added 23 commits March 27, 2026 13:05
When JIT-to-JIT calls hit a function stub for lazy compilation, check
if the native stack is nearly exhausted before proceeding. If so, bail
out to the interpreter instead of compiling and entering more JIT code.

This complements the check in rb_zjit_iseq_gen_entry_point (which
guards interpreter-to-JIT entry) by also guarding JIT-to-JIT entry
via function stubs, matching what YJIT does in branch_stub_hit.
Add specific SendFallbackReason variants for InvokeBlock,
SendForward, and InvokeSuperForward instructions that previously
stayed as Uncategorized in type_specialize. Also add
SingleRactorModeRequired for paths in Send handling that failed
due to multi-ractor mode without setting a reason.

This reduces the "uncategorized" percentage from 53.6% to 0.2%
on the lobsters benchmark, making the stats output actionable.
…lize

Move the InvokeBlockNotSpecialized, SendForwardNotSpecialized, and
InvokeSuperForwardNotSpecialized reasons from type_specialize match
arms to HIR construction, since type_specialize doesn't attempt to
specialize these instructions anyway.
It appears in documentation on https://docs.ruby-lang.org/ under `Object::Ripper`

ruby/prism@6c1000661c
When profiling shows a monomorphic IFUNC block handler, emit
InvokeBlockIfunc which calls rb_vm_yield_with_cfunc directly
instead of falling back to rb_vm_invokeblock. This avoids the
interpreter dispatch overhead for the most common invokeblock
case on lobsters (77% of all invokeblock calls).

The implementation:
- Loads the block handler from the local EP
- Guards tag bits (& 0x3 == 0x3) to confirm IFUNC
- Untags the pointer to get the captured block
- Calls rb_vm_yield_with_cfunc(ec, captured, argc, argv)
Test Enumerable#map on a class with a Ruby `each` that uses `yield`.
This exercises the IFUNC block handler path in invokeblock, where
Enumerable C code creates an IFUNC wrapping the user's block.
Use IntAnd + GuardBitEquals to check (block_handler & 0x3) == 0x3,
matching VM_BH_IFUNC_P() in the interpreter. Add the IntAnd HIR
instruction (placed next to IntOr) for bitwise AND on raw C integers.
SYMBOL_GC removed in 2bcb155
THREAD_CACHE removed in be1bbd5
BIGNUM_DEBUG removed in e60cd14
When rb_bug() is called (e.g. from a ZJIT Rust panic), the crash report
file could be truncated and left nearly empty due to two issues:

1. The crash report file was opened with default (buffered) I/O. If
   rb_vm_bugreport() triggered a secondary crash, buffered output was
   lost. Fix by setting the file to unbuffered with setvbuf().

2. After rb_bug() wrote the crash report, die() called abort() which
   triggered our custom SIGABRT handler. The handler re-opened the same
   crash report file with "w" mode, truncating the report that was
   already written. Fix by resetting SIGABRT to SIG_DFL before abort().
Co-authored-by: Alan Wu <alanwu@ruby-lang.org>
Remove redundant rb_zjit_enabled_p checks from rb_zjit_cfp_pc and
rb_zjit_cfp_iseq since CFP_HAS_JIT_RETURN already checks it. Rewrite
rb_zjit_cfp_has_iseq and rb_zjit_cfp_has_pc as thin wrappers around
rb_zjit_cfp_iseq and rb_zjit_cfp_pc.
Add documentation to JITFrame fields explaining their purpose and
nullability. Split JITFrame::new into new_iseq and new_cfunc
constructors to make the two distinct use cases explicit.
Add mark() and update_references() methods to JITFrame so GC logic
is encapsulated. Store *mut JITFrame in ZJITState to avoid unsafe
const-to-mut casts in gc.rs.
Add rb_iseq_bare_opcode_at_pc which uses rb_vm_insn_addr2insn to
return the base instruction, stripping trace/zjit variants. Use it
in iseq_may_write_block_code to simplify the match arms.
The jit_return = 0 write in rb_set_cfp_pc was only needed by ZJIT.
Move it to the codegen call site next to where iseq is also set,
making the intent clearer.
Make zjit.h the single source of truth for the JITFrame struct layout.
Remove the manual #[repr(C)] definition from jit_frame.rs and replace
it with a type alias to the bindgen-generated zjit_jit_frame.
Expose rb_zjit_jit_frame_update_references so vm.c can call into Rust
to relocate the iseq pointer during GC compaction, instead of manually
manipulating JITFrame fields in C. This keeps JITFrame field access
consolidated in Rust.
Per tenderlove's review, every cfp->iseq read should go through an
accessor that accounts for JITFrame. Rename the field to _iseq so
direct access causes a compile error, and rename the accessors to
drop the zjit prefix (rb_cfp_iseq, rb_cfp_has_iseq, rb_cfp_pc,
rb_cfp_has_pc).
The interpreter always has a valid _iseq field (it's written on exit
from JIT code), so GET_ISEQ() doesn't need to go through rb_cfp_iseq().
Code in vm_insnhelper.c that may be called as a ZJIT fallback should
use rb_cfp_iseq() instead.
Rename for consistency with ISEQ_BODY naming convention. Remove the
separate rb_cfp_has_iseq/rb_cfp_has_pc wrappers — CFP_ISEQ and CFP_PC
return NULL for missing values, which works directly in if conditions.
Return the pointer directly instead of a bool, for consistency with
CFP_ISEQ and CFP_PC. The pointer is truthy in if conditions so all
callers work unchanged.
@pull pull bot locked and limited conversation to collaborators Mar 28, 2026
@pull pull bot added the ⤵️ pull label Mar 28, 2026
@pull pull bot merged commit 634707a into turkdevops:master Mar 28, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants