Skip to content

[pull] master from ruby:master#887

Merged
pull[bot] merged 8 commits intoturkdevops:masterfrom
ruby:master
Mar 26, 2026
Merged

[pull] master from ruby:master#887
pull[bot] merged 8 commits intoturkdevops:masterfrom
ruby:master

Conversation

@pull
Copy link
Copy Markdown

@pull pull bot commented Mar 26, 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 8 commits March 25, 2026 23:57
ZJIT: Invalidate ISEQ version on EP escape

NoEPEscape PatchPoint side exits use without_locals() to avoid
overwriting locals that may have been modified externally (e.g., by
eval or instance_eval). This is correct when the PatchPoint fires
during a call where EP has actually escaped — the interpreter reads
locals from the heap EP, not the stack.

However, PatchPoints are globally patched: once EP escapes in any
call, the PatchPoint fires on ALL subsequent calls, including ones
where EP hasn't escaped. On those calls, the interpreter reads from
the stack, where the JIT may have only computed locals in registers
(e.g., [] for keyword argument defaults from checkkeyword) without
writing them to the frame. The without_locals() side exit doesn't
save these register values, so the interpreter sees stale values.

This was exposed by the no-profile-send recompilation path, which
creates partially-optimized methods where a previously-spilling Send
is inlined away, leaving no gen_spill_locals before the PatchPoint.

Fix by invalidating the ISEQ version when EP escapes. This resets
jit_func so subsequent calls go through the interpreter, which
correctly handles all locals from the start. This avoids the stale
locals problem without changing the without_locals() optimization.
In mmtk, finalizers are registered as postponed jobs
(rb_postponed_job_preregister) rather than running inline during GC
as with the default GC. Postponed jobs can execute on any Ruby thread
that checks for pending jobs, not just the thread that triggered GC.

This means a popen3 wait_thread can end up running a finalizer for
its own ProcessWrapper, causing wait_thread.value to attempt joining
the current thread, which raises ThreadError ("Target thread must not
be current thread").

Guard against this by skipping the join when the finalizer happens to
run on the wait_thread itself.
Default gem gemspecs list native extension files (e.g. date_core.bundle)
without the require path prefix (lib/). In new_format mode,
register_default_spec skipped these files because they didn't match the
prefix pattern, causing find_default_spec to return nil for them.

This led to activation conflicts when a regular gem version of the same
gem was also installed: the require fallback path
(find_in_unresolved_tree) would find the native extension in the regular
gem and try to activate it, conflicting with the already-activated
default gem.

Fix by also registering non-prefixed files that have a native extension
suffix (e.g. .bundle, .so), while still skipping non-requirable files
(README, ext/ sources, etc.).

ruby/rubygems@023fcae74f

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…fleRuby in TestGemCommandsOwnerCommand

ruby/rubygems@924cf41d11

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ordering

SimpleCov and test-unit both use at_exit hooks, which Ruby executes
in LIFO order. When SimpleCov was loaded after test-unit, its at_exit
hook fired first — before tests had run — producing a spurious
"Coverage report generated" message from stale results.

Moving SimpleCov setup before test-unit ensures its at_exit hook is
registered first and therefore runs last, after tests have completed.

ruby/rubygems@47e1c347e8

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Run gem tests concurrently using a thread pool instead of
sequentially. Each gem test runs in its own process group with
output captured via pipes and printed in original order after
all tests complete.

Concurrency is controlled by `TEST_BUNDLED_GEMS_NPROCS` env var,
defaulting to `[Etc.nprocessors, 8].min`. Per-process `RUBYLIB`
is passed via `Process.spawn` env hash to avoid shared `ENV`
mutation across threads.

Full suite on 10-core machine: 268s → ~107s (2.5x speedup).
@pull pull bot locked and limited conversation to collaborators Mar 26, 2026
@pull pull bot added the ⤵️ pull label Mar 26, 2026
@pull pull bot merged commit 788cb32 into turkdevops:master Mar 26, 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.

4 participants