1296 Commits

Author SHA1 Message Date
Peter Zhu
e24b52885f Allow objects on Ruby stack to be GC movable
Objects on the Ruby stack can be GC movable and there is corresponding
code in rb_execution_context_update to update references for moved objects.
2026-01-20 18:01:22 -05:00
Peter Zhu
eaa83e505f Always allocate Fiber objects in Thread
Currently, root fibers of threads do not have a corresponding Ruby object
backing it by default (it does have one when an object is required, such
as when Fiber.current is called). This is a problem for the new GC weak
references design in #12606 since Thread is not declared as having weak
references but it does hold weak references (the generic ivar cache).

This commit changes it to always allocate a Fiber object for the root
fiber.
2025-12-28 08:55:38 -05:00
Peter Zhu
0c07a4246c Implement weak references on gen fields cache 2025-12-25 09:18:17 -05:00
John Hawthorn
63b082cf0e Store ractor_id directly on EC
This is easier to access as ec->ractor_id instead of pointer-chasing through
ec->thread->ractor->ractor_id

Co-authored-by: Luke Gruber <luke.gru@gmail.com>
2025-12-18 13:43:45 -08:00
John Hawthorn
28c2a5b2a4 Fix env debug assertion failure w/ Ractors+JITs
Previously when using a JIT and Ractors at the same time with debug
assertions turned on this could rarely fail with:

    vm_core.h:1448: Assertion Failed: VM_ENV_FLAGS:FIXNUM_P(flags)

When using Ractors, any time the VM lock is acquired, that may join a
barrier as another Ractor initiates GC. This could be made to happen
reliably by replacing the invalidation with a call to rb_gc().

This assertion failure happens because

    VM_STACK_ENV_WRITE(ep, 0, (VALUE)env);

Is setting VM_ENV_DATA_INDEX_FLAGS to the environment, which is not a
valid set of flags (it should be a fixnum). Although we update cfp->ep,
rb_execution_context_mark will also mark the PREV_EP, and until the
recursive calls to vm_make_env_each all finish the "next" ep may still
be pointing to the stack env we've just escaped.

I'm not completely sure why we need to store this on the stack - why is
setting cfp->ep not enough? I'm also not sure why
rb_execution_context_mark needs to mark the prev_ep.
2025-12-18 11:03:23 -08:00
Luke Gruber
4fb537b1ee
Make tracepoints with set_trace_func or TracePoint.new ractor local (#15468)
Before this change, GC'ing any Ractor object caused you to lose all
enabled tracepoints across all ractors (even main). Now tracepoints are
ractor-local and this doesn't happen. Internal events are still global.

Fixes [Bug #19112]
2025-12-16 14:06:55 -05:00
Étienne Barrié
5903ed7ba9 Prevent ifunc procs from being made shareable
[Bug #21775]
2025-12-12 20:27:37 +01:00
John Hawthorn
de94f88c68 Register internal tracepoints globally
Internal tracepoints only make sense to run globally, and they already
took completely different paths.
2025-12-08 16:38:45 -08:00
Max Bernstein
a25196395e Add BOP_GTGT
This will help JITs (and maybe later the interpreter) optimize
Integer#>>.
2025-12-01 15:19:26 -08:00
Samuel Williams
bc9ea585be
Add rb_ec_close function to manage execution context cleanup. (#15253) 2025-12-01 04:49:31 +00:00
Nobuyoshi Nakada
2f53985da9
Revert miscommit at "Reset the cache variable before retrying"
This reverts commit 26a9e0b4e31f7b5a9cbd755e0a15823a8fa51bae partially.
2025-11-26 11:35:15 +09:00
Nobuyoshi Nakada
26a9e0b4e3
Reset the cache variable before retrying 2025-11-26 10:47:17 +09:00
Satoshi Tagomori
e84b91a292 Box: mark/move Box object referred via ENV/rb_env_t 2025-11-26 10:10:47 +09:00
Nobuyoshi Nakada
a24922a680
Remove stale declaration
`rb_zjit_option_enabled_p` seems no longer used/defined since
ruby/ruby#f84bbb423836d9d0d018b8ab71ecceb5868fd5be.
2025-11-20 17:56:51 +09:00
Randy Stauner
7b1e0a6096 ZJIT: Define jit_compile_exception for ZJIT even without YJIT
Seems like an oversight
2025-11-10 13:14:13 -08:00
Satoshi Tagomori
d2a587c791 renaming internal data structures and functions from namespace to box 2025-11-07 13:14:54 +09:00
Satoshi Tagomori
aaa1234702 update referenced filenames from namespace to box 2025-11-07 13:14:54 +09:00
John Hawthorn
cf4a034d59 Use rb_set_memsize for constant cache tables
These were converted to a set in
c0417bd094abcc68be913ce49a430df7cefbcd44
2025-11-06 15:46:06 -08:00
Takashi Kokubun
bd3b44cb0a
ZJIT: Use a shared trampoline across all ISEQs (#15042) 2025-11-04 16:09:13 -08:00
Satoshi Tagomori
fa4c04a7f7 Use CFUNC namespace only for IFUNC frames, its behavior should be unchanged 2025-11-03 02:06:11 +09:00
Koichi Sasada
bc00c4468e use SET_SHAREABLE
to adopt strict shareable rule.

* (basically) shareable objects only refer shareable objects
* (exception) shareable objects can refere unshareable objects
  but should not leak reference to unshareable objects to Ruby world
2025-10-23 13:08:26 +09:00
Luke Gruber
27ff586152 We can't grab the VM Lock in free functions
This is due to the way MMTK frees objects, which is on another native thread.
Due to this, there's no `ec` so we can't grab the VM Lock.

This was causing issues in release builds of MMTK on CI like:

```
  /home/runner/work/ruby/ruby/build/ruby(sigsegv+0x46) [0x557905117ef6] ../src/signal.c:948
  /lib/x86_64-linux-gnu/libc.so.6(0x7f555f845330) [0x7f555f845330]
  /home/runner/work/ruby/ruby/build/ruby(rb_ec_thread_ptr+0x0) [0x5579051d59d5] ../src/vm_core.h:2087
  /home/runner/work/ruby/ruby/build/ruby(rb_ec_ractor_ptr) ../src/vm_core.h:2036
  /home/runner/work/ruby/ruby/build/ruby(rb_current_execution_context) ../src/vm_core.h:2105
  /home/runner/work/ruby/ruby/build/ruby(rb_current_ractor_raw) ../src/vm_core.h:2104
  /home/runner/work/ruby/ruby/build/ruby(rb_current_ractor) ../src/vm_core.h:2112
  /home/runner/work/ruby/ruby/build/ruby(rb_current_ractor) ../src/vm_core.h:2110
  /home/runner/work/ruby/ruby/build/ruby(vm_locked) ../src/vm_sync.c:15
  /home/runner/work/ruby/ruby/build/ruby(rb_vm_lock_enter_body) ../src/vm_sync.c:141
  /home/runner/work/ruby/ruby/build/ruby(rb_vm_lock_enter+0xa) [0x557905390a5a] ../src/vm_sync.h:76
  /home/runner/work/ruby/ruby/build/ruby(fiber_pool_stack_release) ../src/cont.c:777
  /home/runner/work/ruby/ruby/build/ruby(fiber_stack_release+0xe) [0x557905392075] ../src/cont.c:919
  /home/runner/work/ruby/ruby/build/ruby(cont_free) ../src/cont.c:1087
  /home/runner/work/ruby/ruby/build/ruby(fiber_free) ../src/cont.c:1180
```

This would have ran into an assertion error in a debug build but we don't run debug builds of MMTK on Github's CI.

Co-authored-by: john.hawthorn@shopify.com
2025-10-15 10:49:37 -07:00
Satoshi Tagomori
c78895b1d6 Add "Namespace detection information" section in bug reports
* To show environments stack when the current namespace is unexpected or
  namespace detection is broken
* It is displayed only when RUBY_BUGREPORT_NAMESPACE_ENV=1 is specified
2025-10-13 17:41:36 +09:00
Satoshi Tagomori
25c893af6d Add a control frame column "n:xxxx" as namespace id in crash reports 2025-10-07 22:18:29 +09:00
Satoshi Tagomori
9a0e857c35 Stop displaying current namespace when it crashed
To avoid crashes during displaying crash reports.
2025-10-07 22:18:29 +09:00
Peter Zhu
1858233ffa Free the native thread of the main thread on FREE_AT_EXIT 2025-10-04 18:21:13 -04:00
Peter Zhu
c36c80bc25 Always free the main thread in RUBY_FREE_AT_EXIT 2025-10-02 17:09:38 -04:00
Peter Zhu
d8c8623f50 Set context_stack on main thread
We allocate the stack of the main thread using malloc, but we never set
malloc_stack to true and context_stack. If we fork, the main thread may
no longer be the main thread anymore so it reports memory being leaked
in RUBY_FREE_AT_EXIT.

This commit allows the main thread to free its own VM stack at shutdown.
2025-09-30 09:47:29 -04:00
Satoshi Tagomori
ccbf0662f8 No need to set namespace to the frame start evaluating main
* rb_vm_current_namespace() returns main_namespace if it's ready,
  root_namespace otherwise on the top of main_stack.
2025-09-29 01:15:38 +09:00
Satoshi Tagomori
f58f7f25a3 Fix bug of uninitialized variable, missed EoCFP, return values 2025-09-29 01:15:38 +09:00
Satoshi Tagomori
bff625d2a6 add VM_ENV_NAMESPACED_P to unify/simplify/correct when SPECVAL has a namespace 2025-09-29 01:15:38 +09:00
Satoshi Tagomori
20c73b1723 Skip CFUNC frames in the current namespace detection
* The current namespace should be based on the Ruby-level location (file, line no in .rb)
  and we can get it by LEP(ep) basically (VM_ENV_FLAG_LOCAL flag is set)
* But the control frame with VM_FRAME_MAGIC_CFUNC is also a LOCAL frame because
  it's a visible Ruby-level frame without block handlers
* So, for the namespace detection, LEP(ep) is not enough and we need to skip CFUNC
  frames to fetch the caller of such frames
2025-09-29 01:15:38 +09:00
Satoshi Tagomori
bb21b619f0 Detect the correct loading namespace from control frames
* checking all control frames (instead of filtering by VM_FRAME_RUBYFRAME_P)
  because VM_FRAME_FLAG_NS_REQUIRE is set on non-rubyframe
* skip frames of CFUNC in the root namespace for Kernel#require (etc) to avoid
  detecting the root namespace of those frames wrongly
2025-09-29 01:15:38 +09:00
Satoshi Tagomori
c755f35f0e Stop using ns->top_self here because it's set to th->top_self beforehand if needed 2025-09-29 01:15:38 +09:00
Satoshi Tagomori
76c4663a77 Fix Namespace.current to show its caller's namespace
Calling rb_current_namespace() in rb_namespace_current() means to show
the definition namespace of Namespace.current itself (it's the root always)
but the users' expectation is to show the namespace of the place where
the Namespace.current is called.
2025-09-29 01:15:38 +09:00
Satoshi Tagomori
4f47327287 Update current namespace management by using control frames and lexical contexts
to fix inconsistent and wrong current namespace detections.

This includes:
* Moving load_path and related things from rb_vm_t to rb_namespace_t to simplify
  accessing those values via namespace (instead of accessing either vm or ns)
* Initializing root_namespace earlier and consolidate builtin_namespace into root_namespace
* Adding VM_FRAME_FLAG_NS_REQUIRE for checkpoints to detect a namespace to load/require files
* Removing implicit refinements in the root namespace which was used to determine
  the namespace to be loaded (replaced by VM_FRAME_FLAG_NS_REQUIRE)
* Removing namespaces from rb_proc_t because its namespace can be identified by lexical context
* Starting to use ep[VM_ENV_DATA_INDEX_SPECVAL] to store the current namespace when
  the frame type is MAGIC_TOP or MAGIC_CLASS (block handlers don't exist in this case)
2025-09-29 01:15:38 +09:00
Koichi Sasada
55b1ba3bf2 Ractor.shareable_proc
call-seq:
  Ractor.sharable_proc(self: nil){} -> sharable proc

It returns shareable Proc object. The Proc object is
shareable and the self in a block will be replaced with
the value passed via `self:` keyword.

In a shareable Proc, the outer variables should
* (1) refer shareable objects
* (2) be not be overwritten

```ruby
  a = 42
  Ractor.shareable_proc{ p a }
  #=> OK

  b = 43
  Ractor.shareable_proc{ p b; b = 44 }
  #=> Ractor::IsolationError because 'b' is reassigned in the block.

  c = 44
  Ractor.shareable_proc{ p c }
  #=> Ractor::IsolationError because 'c' will be reassigned outside of the block.
  c = 45

  d = 45
  d = 46 if cond
  Ractor.shareable_proc{ p d }
  #=> Ractor::IsolationError because 'd' was reassigned outside of the block.
```

The last `d`'s case can be relaxed in a future version.

The above check will be done in a static analysis at compile time,
so the reflection feature such as `Binding#local_varaible_set`
can not be detected.

```ruby
  e = 42
  shpr = Ractor.shareable_proc{ p e } #=> OK
  binding.local_variable_set(:e, 43)
  shpr.call #=> 42 (returns captured timing value)
```

Ractor.sharaeble_lambda is also introduced.
[Feature #21550]
[Feature #21557]
2025-09-24 03:59:03 +09:00
Jun Aruga
971174054a Add a macro to manage the condition of no-inline version rb_current_ec
Add the macro `RB_THREAD_CURRENT_EC_NOINLINE` to manage the condition to use
no-inline version rb_current_ec for a better maintainability.

Note that the `vm_core.h` includes the `THREAD_IMPL_H` by the
`#include THREAD_IMPL_H`. The `THREAD_IMPL_H` can be `thread_none.h`,
`thread_pthread.h` or `thread_win32.h` according to the
`tool/m4/ruby_thread.m4` creating the `THREAD_IMPL_H`.

The change in this commit only defining the `RB_THREAD_CURRENT_EC_NOINLINE` in
the `thread_pthread.h` is okay in this situation. Because in the
`thread_none.h` case, the thread feature is not used at all, including
Thread-Local Storage (TLS), and in the `thread_win32.h` case, the
`RB_THREAD_LOCAL_SPECIFIER` is not defined. In the `thread_pthread.h` case, the
`RB_THREAD_LOCAL_SPECIFIER` is defined in the `configure.ac`. In the
`thread_none.h` case, the `RB_THREAD_LOCAL_SPECIFIER` is defined in the
`thread_none.h`.
2025-09-16 11:37:26 +01:00
Takashi Kokubun
4f030951f2
ZJIT: Invalidate local variables on EP escape (#14448) 2025-09-05 11:26:01 -07:00
Jun Aruga
73854a4b65 Use no-inline version rb_current_ec on ppc64le
This commit fixes the failures in bootstraptest/test_ractor.rb reported on
the issue ticket <https://bugs.ruby-lang.org/issues/21534>.

TLS (Thread-Local Storage) may not be accessed across .so on ppc64le too.
I am not sure about that.  The comment "// TLS can not be accessed across
.so on ..." in this commit comes from the following commit.

319afed20f (diff-408391c43b2372cfe1fefb3e1c2531df0184ed711f46d229b08964ec9e8fa8c7R118)
> // on Darwin, TLS can not be accessed across .so`

This failures only happened when configuring with cppflags=-DRUBY_DEBUG and -O3
on ppc64le.

The reproducing steps were below.

```
$ ./autogen.sh

$ ./configure -C --disable-install-doc cppflags=-DRUBY_DEBUG

$ make -j4

$ make btest BTESTS=bootstraptest/test_ractor.rb
...
FAIL 2/147 tests failed
make: *** [uncommon.mk:913: yes-btest] Error 1
```

The steps with a reproducing script based on the `bootstraptest/test_ractor.rb`
were below.

```
$ cat test_ractor_1.rb
counts = []
counts << Ractor.count
p counts.inspect

ractors = (1..2).map { Ractor.new { Ractor.receive } }
counts << Ractor.count
p counts.inspect

ractors[0].send('End 0').join
sleep 0.1 until ractors[0].inspect =~ /terminated/
counts << Ractor.count
p counts.inspect

ractors[1].send('End 1').join
sleep 0.1 until ractors[1].inspect =~ /terminated/
counts << Ractor.count
p counts.inspect

$ make run TESTRUN_SCRIPT=test_ractor_1.rb
...
vm_core.h:2017: Assertion Failed: rb_current_execution_context:ec == rb_current_ec_noinline()
...
```

The assertion failure happened at the following line.

f3206cc79b/vm_core.h (L2017)

This fix is similar with the following commit for the arm64.

f7059af50a

Fixes [Bug #21534]
2025-09-04 15:55:27 +01:00
Takashi Kokubun
809a9a9f29
ZJIT: Count exits coming from jit_exception (#14428) 2025-09-03 13:14:28 -07:00
Yusuke Endoh
2ccb2de677 Make RubyVM::AST.of return a parent node of NODE_SCOPE
This change makes `RubyVM::AST.of` and `.node_id_for_backtrace_location`
return a parent node of NODE_SCOPE (such as NODE_DEFN) instead of the
NODE_SCOPE node itself.
(In future, we may remove NODE_SCOPE, which is a bit hacky AST node.)

This is preparation for [Feature #21543].
2025-08-28 12:44:04 +09:00
Jean Boussier
2083fa89fc Implement gen_fields_tbl cache
There is a high likelyhood that `rb_obj_fields` is called
consecutively for the same object.

If we keep a cache of the last IMEMO/fields we interacted with,
we can save having to lookup the `gen_fields_tbl`, synchronize
the VM lock, etc.

On yjit-bench's, I instrumented the hit rate of this cache at:

  - `shipit`: 38%, with 111k hits.
  - `lobsters`: 59%, with 367k hits.
  - `rubocop`: 100% with only 300 hits.

I also ran a micro-benchmark which shows that ivar access is:

  - 1.25x faster when the cache is hit in single ractor mode.
  - 2x faster when the cache is hit in multi ractor mode.
  - 1.06x slower when the cache miss in single ractor mode.
  - 1.01x slower when the cache miss in multi ractor mode.

```yml
prelude: |
  class GenIvar < Array
    def initialize(...)
      super
      @iv = 1
    end

    attr_reader :iv
  end

  a = GenIvar.new
  b = GenIvar.new
benchmark:
  hit: a.iv; a.iv; a.iv; a.iv; a.iv; a.iv; a.iv; a.iv; a.iv; a.iv; a.iv; a.iv; a.iv; a.iv; a.iv; a.iv; a.iv; a.iv; a.iv; a.iv;
  miss: a.iv; b.iv; a.iv; b.iv; a.iv; b.iv; a.iv; b.iv; a.iv; b.iv; a.iv; b.iv; a.iv; b.iv; a.iv; b.iv; a.iv; b.iv; a.iv; b.iv;
```

Single ractor:
```
compare-ruby: ruby 3.5.0dev (2025-08-12T02:14:57Z master 428937a536) +YJIT +PRISM [arm64-darwin24]
built-ruby: ruby 3.5.0dev (2025-08-12T09:25:35Z gen-fields-cache 9456c35893) +YJIT +PRISM [arm64-darwin24]
warming up..

|      |compare-ruby|built-ruby|
|:-----|-----------:|---------:|
|hit   |      4.090M|    5.121M|
|      |           -|     1.25x|
|miss  |      3.756M|    3.534M|
|      |       1.06x|         -|
```

Multi-ractor:
```
compare-ruby: ruby 3.5.0dev (2025-08-12T02:14:57Z master 428937a536) +YJIT +PRISM [arm64-darwin24]
built-ruby: ruby 3.5.0dev (2025-08-12T09:25:35Z gen-fields-cache 9456c35893) +YJIT +PRISM [arm64-darwin24]
warming up..

|      |compare-ruby|built-ruby|
|:-----|-----------:|---------:|
|hit   |      2.205M|    4.460M|
|      |           -|     2.02x|
|miss  |      2.117M|    2.094M|
|      |       1.01x|         -|
```
2025-08-13 19:54:56 +02:00
Peter Zhu
95320f1ddf Fix RUBY_FREE_AT_EXIT for static symbols
Since static symbols allocate memory, we should deallocate them at shutdown
to prevent memory leaks from being reported with RUBY_FREE_AT_EXIT.
2025-08-05 12:04:27 -04:00
Jean Boussier
fc5e1541e4 Use rb_gc_mark_weak for cc->klass.
One of the biggest remaining contention point is `RClass.cc_table`.
The logical solution would be to turn it into a managed object, so
we can use an RCU strategy, given it's read heavy.

However, that's not currently possible because the table can't
be freed before the owning class, given the class free function
MUST go over all the CC entries to invalidate them.

However if the `CC->klass` reference is weak marked, then the
GC will take care of setting the reference to `Qundef`.
2025-08-01 10:42:04 +02:00
Takashi Kokubun
2cd10de330
ZJIT: Prepare for sharing JIT hooks with ZJIT (#14044) 2025-07-30 10:11:10 -07:00
Takashi Kokubun
b22eb0e468
ZJIT: Add --zjit-stats (#14034) 2025-07-29 10:00:15 -07:00
Peter Zhu
2bcb155b49 Convert global symbol table to concurrent set 2025-07-21 10:58:30 -04:00
John Hawthorn
cfc006d410 Always use atomics to get the shape count
When sharing between threads we need both atomic reads and writes. We
probably didn't need to use this in some cases (where we weren't running
in multi-ractor mode) but I think it's best to be consistent.
2025-07-09 10:38:04 -07:00
John Hawthorn
2ed4862690 Remove unnecessary union 2025-06-24 20:02:30 -07:00