Commit Graph
902 Commits
Author SHA1 Message Date
Hiroshi SHIBATA 13c99ffab9 Fix autoload's require dispatch under Ruby::Box
With RUBY_BOX=1, firing an autoload invoked Ruby::Box#require on the
registered box, bypassing any Kernel#require decoration (RubyGems,
Zeitwerk, ...) prepended in that box. Zeitwerk's implicit namespaces
rely on the decorated require, so a plain Rails app failed with
LoadError on the first request. Call require on the box's top self in
a frame running in that box instead, which dispatches the decorated
method and still loads the feature into the box that registered the
autoload.
2026-08-31 08:18:42 +09:00
Koichi SasadaandClaude Opus 5 9d3b43fda9 Ractor: do not leak generic_fields_lock when the insert raises
Adding a generic-fields entry takes the VM-wide generic_fields_lock and then
calls st_insert, which mallocs when the table grows.  With this Ractor's GC
disabled the allocation cannot fall back to a collection, so it can raise
NoMemoryError -- and the raise skipped both gf_unlock() and the matching
rb_gc_local_enable().  A leaked generic_fields_lock hangs every later access
to generic fields, including the marking of any Ractor's local GC, so an
otherwise recoverable NoMemoryError turned into a deadlock.  Unwind through
a tag instead.

While here, drop three things that no longer match the code: a basket
payload comment describing a generic-ivar map field that was removed, the
unused st_table placeholder left in ractor_basket_new, and two comments in
variable.c still describing the per-Ractor generic-fields tables that the
single global table replaced.

This commit also carries the mechanical translation of the Japanese comments
in these two files, which was in progress in the same working tree.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 16:27:53 +09:00
Koichi Sasada 84faabfd19 GC: per-Ractor local GC — generic fields (single global table)
Keep the generic-ivar host-to-fields_obj mapping in one global table,
serializing mutators with a dedicated lock.  A local GC marks only the
values living in its own objspace; the global GC marks the values of
live keys in the weak pass that runs after marking.  This removes the
table-ownership transitions that used to happen on shareable promotion,
on send, and on absorb.
2026-08-07 16:27:53 +09:00
Nobuyoshi Nakada 2d616a9bb0 Remove unused autoload table copier
Remove the copier left unused when class fields cloning replaced raw
table copying in commit 3abdd4241f.
2026-07-29 11:42:03 +09:00
Jean BoussierandJohn Hawthorn 40f105bd55 Change RStruct to match SHAPE_ID_LAYOUT_EXTENDED
THe downside is that we now always reserve one 8B reference for the
IMEMO/fields, even for structs that never have any ivars.

But it is an acceptable tradeoff given that ivars on structs aren't
rare.

Co-Authored-By: John Hawthorn <john@hawthorn.email>
2026-07-21 08:30:12 +02:00
Jean Boussier 74bd057f9c Get rid of ROBJECT_FIELDS_HASH 2026-07-15 20:52:47 +02:00
Jean Boussier efb3a73445 rb_imemo_fields_ptr: assume embedded 2026-07-15 20:52:47 +02:00
Jean Boussier 6cd755deab variable.c: generalize use of rb_obj_fields()
Numerous codepath have the same `switch/case` with very little
differing logic compared to `rb_obj_fields`, might as well
use it everywhere and share more code.
2026-07-15 19:09:20 +02:00
Jean Boussier 86951165b8 Get rid of ROBJECT_HEAP flag
This flag is now entirely redundant with the shape_id layout bits.
2026-07-15 15:43:28 +02:00
Jean Boussier 4bd94ccbbd variable.c: only filter out object_id, not all internal ivars 2026-07-14 23:50:17 +02:00
Jean Boussier 944d936d7c variable.c: Refactor too_complex evacuation paths
Now share more code between the various cases:

  - Whether to copy all fields or just ivars
  - Whether to add or remove some capacity.
2026-07-14 23:50:17 +02:00
Jean Boussier 24337e3cbe Refactor rb_obj_copy_ivar
Share more code with `rb_copy_generic_ivar`.
2026-07-14 23:50:17 +02:00
Jean Boussier 6c23075086 rb_copy_generic_ivar: cleanup goto statement
It used to be that multiple paths would need to clear
the generic ivar reference, but it's no longer the case.
2026-07-14 23:50:17 +02:00
Jean Boussier 6f0548a0bd Simplify rb_obj_copy_ivar and rb_copy_generic_ivar
By handling complex shapes in `rb_shape_rebuild` we can merge
the two complex cases (when `src` is complex and when `dest`
becomes complex).
2026-07-14 23:50:17 +02:00
Jean Boussier 71ee81f7d9 imemo.c: embed the st_table inside rb_fields
Followup: https://github.com/ruby/ruby/pull/17631

Now that complex `RObject` always have an IMEMO/fields, we no
longer need to have an external `st_table` to replicate the
memory layout of `RObject`.
2026-07-14 23:50:17 +02:00
e0083cffa3 Refactor RObject to use T_IMEMO/fields_obj on overflow
Instead of spilling into a raw buffer, `RObject` now spills
into an `IMEMO/fields` object like other types.

From an instance variable layout standpoint, an extended `RObject`
is now identical to a `RTypedData`, as in they both store the
reference to their `IMEMO/fields` at the same offset (`VALUE * 2`).

One positive consequence of this is that the only case where a `T_OBJECT`
needs sweeping is if a finalizer was registered.

YJIT now side exit when it need to write a new ivar into a `RObject`
that is out of space. This is unlikely to cause a performance regression
as this codepath isn't supposed to happen after warmup given `max_iv_count`
is recorded on classes, so future objects should be large enough.
Hence it's best not to waste executable memory for such codepath.

ZJIT lost support for writting into extended `RObject`.
Most of the code to support it is there it's just missing an
implementation of `RBASIC_SET_SHAPE_ID`, which recently changed
to strip some bits out of the shape (see comments).
I will leave it to the ZJIT team to implement it (sorry).

There are a few future cleanups planned that I keep for followups:

  - We can now get rid of the `ROBJECT_HEAP` flag, it's redundant with
    the shape layout bits.
  - `imemo_fields` can now embed the `st_table` when complex.

Co-Authored-By: John Hawthorn <john@hawthorn.email>
Co-authored-by: Randy Stauner <randy@r4s6.net>
2026-07-14 10:44:39 +02:00
Jean Boussier 2c574ca7e2 Symbol#to_s now returns a frozen string.
[Feature #22137]

It has returned a chilled string, hence emitting deprecation
warnings for two versions.
2026-07-10 10:02:00 +02:00
Jean Boussier c966f3abd7 imemo.c: refactor imemo_fields_new
Lean on `rb_newobj` to get the shape embedded capacity properly
set.
2026-07-07 13:12:35 +02:00
Jean Boussier 263f06ad49 RBASIC_SET_SHAPE_ID: also strip the layout bits
Like the capacity part, the layout part of an object shape
almost never changes. The few exceptions are:

  - On allocation.
  - On being compacted by GC.
  - When RObject oberflows.

As such it simplifies a lot of code if `RBASIC_SET_SHAPE_ID` strips
the layout bits, as we often copy the shape from IMEMO/fields to
the owner object and vice-versa.

Also change `RBASIC_SET_SHAPE_ID_WITH_CAPACITY` into
`RBASIC_SET_FULL_SHAPE_ID` so it can be used for assigning both
capacity and layout.
2026-07-07 13:12:35 +02:00
John HawthornandLuke Gruber daffaaee73 Mark most TypedData types as THREAD_SAFE_FREE
Set RUBY_TYPED_THREAD_SAFE_FREE on TypedData types whose dfree function
is trivially safe, and only frees its own memory

Types not yet marked as THREAD_SAFE_FREE:
- id2ref_tbl_type: sets the process-global id2ref_tbl to NULL.
- mutex_data_type: unlinks itself from another thread's keeping_mutexes list.
- autoload_data_type: deletes nodes from a shared intrusive list.
- autoload_const_type: deletes itself from a shared list.
- rb_cont_data_type: mutates the shared fiber pool and the global first_jit_cont list.
- rb_fiber_data_type: delegates to cont_free.
- FiberPoolDataType: mutates shared fiber pool free-lists.
- ractor_data_type: reconfigures global VM event-hook flags and call caches.
- exported_object_registry: frees a global table under the VM lock.
- rb_box_data_type (Box::Entry): unlinks classext from other live class and module objects.
- box_ext_cleanup_type: dereferences another String object and calls unlink.
- monitor_data_type: uses the default free, so the flag has no effect.

Co-authored-by: Luke Gruber <luke.gruber@shopify.com>
2026-06-23 13:30:26 -07:00
Aaron Patterson c4d09f416c Reapply "Reserve 2 bits for expressing object layout (#17139)" (#17158)
This reverts commit ddb5055d96.
2026-06-01 19:30:58 +00:00
Aaron Patterson ddb5055d96 Revert "Reserve 2 bits for expressing object layout (#17139)"
This reverts commit 63d9f090b5.
2026-05-29 16:41:31 -07:00
63d9f090b5 Reserve 2 bits for expressing object layout (#17139)
* Reserve 2 bits for expressing object layout

We would like to make instance variable reads in the JIT compiler faster
(as well as simplify the JIT implementation).  Currently, in order to
read an instance variable, we have to:

1. Test for heap object
2. Load object to a 64 bit register
3. Mask the object header
4. Bit test against the masked header
5. JNE
6. Load field

We would like to:

1. Test for heap object
2. Load object shape to a 32 bit register
3. Bit test against the shape
4. JNE
5. Load field

The way we fetch instance variables is not consistent across objects.
In order to realize our goal, we need to encode object layout inside the
shape.  If we encode object layout inside the shape, then the shape
itself will guarantee that the access pattern generated by the JIT
compiler is correct.

We should encode the following load patterns into the shape tag bits.
This way we can share shapes on transitions, but be able to
differentiate the access patterns for the JIT compiler.  In other words,
two objects can have an `@a -> @b -> @c` transition and share the same
shape, but the tag bits can differentiate the access pattern so that the
JIT compiler can be confident that the machine code is correct.

Here are the patterns:

1. Embedded/Extended T_OBJECT Instance Variables

Objects with direct references to instance variables or via malloc
buffer

2. Objects with fields_objects fields

These are Data and TypedData objects.  They have an associated axillary
imemo/fields object that stores the instance variables.  The access
pattern is `object[2] + 2`.  The fields object is the 3rd field, and the
instance variables start at +2 inside the fields object.  The fields
object itself is a Ruby object, so it contains the usual header bits +
class headers.

3. Non Boxable Classes / Modules

This is similar to Objects with fields_objects, but the fields object is
stored at a different offset.  We’re differentiating this from boxable
classes and modules because those are harder to support.

4. Other

"Other" pattern is for objects that are rare, or have
difficult-to-implement access patterns.  This includes:

* Boxable classes and modules
* Structs (for now)
* Objects that use the geniv table

Proposed shape bit layout:

```
  Current shape_id_t is 32 bits:
  31        28 27 26 25 24 23 22        19 18                         0
  +-----------+--+--+--+--+--+------------+----------------------------+
  | unused    |L1|L0|OI|FR|CX| heap index | shape tree offset          |
  +-----------+--+--+--+--+--+------------+----------------------------+
               |  |  |  |  |  |            |
               |  |  |  |  |  |            +-- bits 0-18: SHAPE_ID_OFFSET_MASK
               |  |  |  |  |  +--------------- bits 19-22: SHAPE_ID_HEAP_INDEX_MASK
               |  |  |  |  +------------------ bit 23: SHAPE_ID_FL_COMPLEX
               |  |  |  +--------------------- bit 24: SHAPE_ID_FL_FROZEN
               |  |  +------------------------ bit 25: SHAPE_ID_FL_HAS_OBJECT_ID
               +--+--------------------------- bits 26-27: SHAPE_ID_LAYOUT_MASK
```

The important part about these layout patterns is that they do not
reflect the _type_ of object, only how the object is laid out in memory.
For example, we currently treat structs as "other", but we can refactor
them to have the same layout as "Objects with fields_objects", and when
we do that they should get a different bit in the shape header.

This commit only reserves the two bits, it doesn't use them in the JIT
compiler yet.

Co-Authored-By: John Hawthorn <john@hawthorn.email>
Co-Authored-By: Max Bernstein <tekknolagi@gmail.com>

* Update gc.c

Co-authored-by: Nobuyoshi Nakada <nobu.nakada@gmail.com>

* Update shape.h

Co-authored-by: Jean Boussier <jean.boussier@gmail.com>

* fix function name

* Update shape.c

Co-authored-by: Jean Boussier <jean.boussier@gmail.com>

* fix function name

* Revert "Update shape.c"

This reverts commit 900711defc6c541a93f3393a350819ae88cf87f1.

* add comment

---------

Co-authored-by: John Hawthorn <john@hawthorn.email>
Co-authored-by: Max Bernstein <tekknolagi@gmail.com>
Co-authored-by: Nobuyoshi Nakada <nobu.nakada@gmail.com>
Co-authored-by: Jean Boussier <jean.boussier@gmail.com>
2026-05-29 15:09:34 -07:00
John Hawthorn 594ae9f073 Give legacy T_DATA the same layout as TypedData
This allows us to treat the two types of T_DATA the same way when
reading instance variables.

Non-TypedData T_DATA are deprecated, so making them faster isn't
particularly important, but it is helpful to avoid needing to test for
TypedData and adding another special case.
2026-05-27 16:18:43 -07:00
Peter Zhu 6bc1aa31cc [Bug #22072] Fix rb_cvar_set for multi-Ractor
rb_cvar_set breaks the RCLASS_CVC_TBL because it creates a new cvc_tbl but
forgets to copy the contents over. This causes the following script to
crash:

    r = Ractor.new {}

    module Foo
      def self.foo = @@foo
    end

    Foo.class_variable_set(:@@foo, nil)
    Foo.class_variable_set(:@@bar, nil)

    puts Foo.foo

Crashes with:

    test.rb:4: [BUG] should have cvar cache entry
    ruby 4.1.0dev (2026-05-16T21:11:21Z define-obj-has-suf.. 642cfc59a7) +PRISM [x86_64-linux]

    -- Control frame information -----------------------------------------------
    c:0003 p:0003 s:0012 e:000011 l:y b:0001 r:(nil) METHOD test.rb:4
    c:0002 p:0036 s:0008 E:001118 l:n b:---- r:(nil) EVAL   test.rb:10 [FINISH]
    c:0001 p:0000 s:0003 E:0013c0 l:y b:---- r:(nil) DUMMY  [FINISH]

    -- Ruby level backtrace information ----------------------------------------
    test.rb:10:in '<main>'
    test.rb:4:in 'foo'

    -- Threading information ---------------------------------------------------
    Total ractor count: 1
    Ruby thread count for this ractor: 1

    -- C level backtrace information -------------------------------------------
    miniruby(rb_print_backtrace+0x24) [0x5701425120eb] vm_dump.c:1108
    miniruby(rb_vm_bugreport+0x374) [0x5701425128f2] vm_dump.c:1456
    miniruby(rb_bug_without_die_internal+0xa0) [0x5701422ad332] error.c:1107
    miniruby(rb_bug+0xb5) [0x5701422ad4de] error.c:1125
    miniruby(update_classvariable_cache+0xd1) [0x5701424d159c] vm_insnhelper.c:1501
    miniruby(vm_getclassvariable+0xd1) [0x5701424d16e4] vm_insnhelper.c:1532
    miniruby(vm_exec_core+0xfa6) [0x5701424e6fa9] insns.def:243
    miniruby(rb_vm_exec+0x140) [0x570142504532] vm.c:2805
    miniruby(rb_iseq_eval_main+0x3d) [0x5701425054c8] vm.c:3101
    miniruby(rb_ec_exec_node+0x128) [0x5701422b914a] eval.c:284
    miniruby(ruby_run_node+0x8d) [0x5701422b92be] eval.c:322
    miniruby(rb_main+0x4c) [0x5701421ccd8e] main.c:42
    miniruby(main+0x4b) [0x5701421ccdef] main.c:62
2026-05-17 09:09:53 -04:00
Jean Boussier deceb9f62e Rename rb_shape_obj_* into rb_obj_shape_*
For consistency.
2026-05-06 10:10:16 +02:00
Jean Boussier 4eeec614bb shapes: Rename TOO_COMPLEX in just COMPLEX
The `too_` prefix wasn't consistently used and just make the
thing longer for no benefit.
2026-05-06 10:10:16 +02:00
Jean Boussier 678d86f5e4 shape.c: transition to complex when max_capacity is reached
Now that we have 1024B slots, we can store up to 126 fields inline.

Objects larger than this are rare if not non-existent, hence we can
get rid of the `malloc` path for imemo/fields and simply transition
to `TOO_COMPLEX`.

This additionally allows to shrink `attr_index_t` from 16 to 8B.

Note: the ZJIT "ivar on extended" tests are renamed as "complex" because
"extended" AKA malloc allocated imemo/fields no longer exists.
They're now complex fields, AKA st tables.

rb_class_allocate_instance: start as complex when over max_fields

If `RCLASS_MAX_IV_COUNT` is over `max_fields`, allocating a large
slot to end up transitioning to `TOO_COMPLEX` is wasteful.

We might as well start as complex directly.
2026-05-06 09:02:02 +02:00
Nobuyoshi Nakada 31cdf7a9f8 Adjust style 2026-05-04 09:46:54 +09:00
Jean Boussier c9b53473e3 Refactor shape transition functions
Expose both `rb_obj_shape_` functions that take a `VALUE`
and `rb_shape_` functions that take a `shape_id`.

Make common transition functions such as `complex` and `frozen`
inlineable.

Also get rid of RB_SET_SHAPE_ID and rb_set_boxed_class_shape_id.
2026-05-03 11:36:26 +02:00
Jean Boussier 289343cf0f Create imemo/fields with shape_id
Simplify the API by taking a shape_id upon creation.
2026-05-02 10:33:48 +02:00
John Hawthorn f2d0ef269b Add and use rb_ivar_foreach_buffered
Previously, rb_ivar_foreach would walk up the shape tree, but yield
instance variables to the callback as it went. If the object shape was
modified during this callback, particularly with removing an instance
variable, it could result in reading free'd memory.

This commit solves this by adding a version which buffering all instance
variable names and values before calling the callback, giving a snapshot
of the object at the time rb_ivar_foreach_buffered is called.

The buffer is made with ALLOCV_N, so the performance difference should
be minimal, and I don't think this method is particuarly heavily used.

[Bug #21996]
2026-04-26 17:14:39 +09:00
John Hawthorn 96cd1bc765 Fix iv_count for too_complex generic ivar
Previously this branch forgot to assign iv_count when used with a
generic ivar which is too_complex, which could result in it incorrectly
returning 0.
2026-04-26 17:14:39 +09:00
Jean Boussier 47e061277a class.c: Make cvc_tbl a managed object
[Bug #21952]

Solves the double-free or use after-free concern with boxes.
Now entries can safely be used for copy-on-write.

Also is likely necessary to make it save to read cvar from
secondary ractors, as allowed since: ab32c0e690
2026-04-21 16:30:14 +09:00
John Hawthorn ab324956d7 Avoid array resize in rb_obj_instance_variables
We know (an estimate of) the ivar count upfront (+/- hidden internal
fields), from the shape, so we should reserve the expected length
upfront.
2026-04-13 08:46:15 -07:00
Andrii Furmanets 526344b56e Fix Box regexp match vars after non-match 2026-04-12 02:47:11 +09:00
Jean Boussier 7f4db64f28 Emit already initialzed constant warnings in a single call
When decorating `Warning.warn`, it's much more convenient to get
the whole warning in a single string.
2026-04-10 15:06:19 +02:00
John Hawthorn dd3542a0cd Fix class variable cache not invalidated by class_variable_set
The previous invalidation walked subclasses but missed cvars from
included modules, and skipped invalidation when creating a new cvar on
modules entirely. Always invalidate when a new class variable is
created, since this should be relatively rare.

We previously bumped the global state on any module inclusion, which
should be far more common than this.

[Bug #21978]
2026-04-01 19:21:18 -07:00
Jean Boussier 53099633e2 Make ruby_xfree_sized and ruby_xrealloc_sized public
[Feature #21861]
2026-04-01 08:10:07 +01:00
Takashi Kokubun 6a5a2612fd variable.c: Fix -Wmaybe-uninitialized warnings in rb_gvar_set/rb_gvar_get
Initialize `entry` and `var` to NULL. They are assigned inside
RB_VM_LOCKING() but used after it, and the compiler cannot prove the
locked block always executes.
2026-03-31 17:24:01 -07:00
Aaron Patterson ab32c0e690 Allow reading cvars from non-main Ractors (#16308)
Today you can read instance variables from non-main Ractors, but many
Rails applications use cvars, and we cannot read them.

For example:

```ruby
class Foo
  # This is NOT allowed to be read in non-main Ractors
  @@bar = 123
  def self.bar; @@bar; end

  # This is allowed to be read in non-main Ractors
  @baz = 123
  def self.baz; @baz; end
end

  # This is OK
Ractor.new {
  p Foo.baz
}.value

  # Exception here
Ractor.new {
  p Foo.bar
}.value
```

This commit changes the semantics of cvars to be the same as instance
variables:

* It's ok to read Ractor shareable objects from the non-main Ractor
* It's NOT ok to write from the non-main Ractor

[Feature #21942]
2026-03-19 00:41:25 +00:00
John Hawthorn a2531ba293 Simplify subclasses list, remove from Box
Currently we maintain the subclasses list for two separate purposes (we essentially have to different relationships we're putting into the same list):

1. On a T_MODULE, we track the T_ICLASSes created to include it into
   other classes. Used for method invalidation and propagating includes
   on the module that happen after it's been used
2. On a T_CLASS/T_ICLASS, we track the T_CLASS/T_ICLASS which are the
   immediate children of the class. We use this for method invalidation,
   some cvar things, and to iterate through subclasses.

Purpose 1 does not have any issues with box, the T_ICLASS always belongs
to one specific module and that's immutable. This list can be box-global
(always use the prime classext or hoist it out) and only needs to be
pruned during free. If we care about behaviour under a particular box
(ie. the propagating includes), we should look up the current box being
modified on the ICLASS itself.

Purpose 2 is more complicated. It currently tracks the immediate
children, the T_CLASS or T_ICLASS whose super points back. Because super
is per-box and is mutable (include/prepend insert ICLASSes into the
chain) we need to update the list on include/prepend, entries must be
per-box, and we can have multiple entries per-box. *I propose we
simplify this by no longer tracking the immediate subclass*, but instead
tracking the T_CLASS -> ... -> T_CLASS relationship, ie. the inverse of
rb_class_superclass. That relationship is the same across all boxes and
immutable after Class creation.

As a special case the ICLASS for refinements are also added to the
purpose 2 list (on T_CLASS). As those ICLASS do not chain to an eventual
leaf T_CLASS.

When we need to find the classes which have included a module, we can
use the module subclasses list to find the ICLASS and then use
RCLASS_INCLUDER. If we needed to iterate all T_ICLASS, we could then
walk up the CLASS_SUPER chain, but I didn't find anywhere we needed to
do that.
2026-03-17 14:42:07 -07:00
Jean Boussier 14eb083152 Speedup repeated calls to rb_gccct_clear_table
Profiling of `ruby --disable-all -e 1` shows between 5 and 10%
of the time is spent in `_platform_memset`, called from `rb_gccct_clear_table()`,
itself called from `clear_method_cache_by_id_in_class()`.

Which makes sense, during boot we define numerous methods, and after
each we have to invalidate the `gccct`, which is done by zeroing
1023 pointers, so roughtly 8kiB of memory.

By keeping track of whether the table was used since the last clear,
we can save a lot of useless memory writes.

This may also be beneficial when loading user defined code, as it's unlikely
the `gccct` would be dirtied between two `def`.

NB: profiling such a short lived process gives a lot of variance, but
with a very high sampling rate and multiple attempts, `clear_method_cache_by_id_in_class`
is always in the top 2 hotspots.
2026-03-16 20:53:49 +01:00
Jean Boussier 4e196af17c Use ruby_sized_xfree 2026-02-01 21:57:59 +01:00
Jean Boussier 050c00141c variable.c: Replace ruby_xfree by ruby_sized_xfree when applicable 2026-01-31 10:35:48 +01:00
aguspe 6e2bf5df4e [Tests] Assert Module#set_temporary_name returns self
The return value of Module#set_temporary_name was changed
to return `self`, but the existing tests
did not verify this.
2025-12-24 11:03:20 +09:00
Daisuke Aritomo 0fe111caa6 Respect encoding of ID in exception messages 2025-12-16 17:15:59 -08:00
Daisuke Aritomo cbcbbb2fbe Let Ractor::IsolationError report correct constant path
Before this patch, Ractor::IsolationError reported an incorrect constant
path when constant was found through `rb_const_get_0()`.

In this code, Ractor::IsolationError reported illegal access against
`M::TOPLEVEL`, where it should be `Object::TOPLEVEL`.

```ruby
TOPLEVEL = [1]

module M
  def self.f
    TOPLEVEL
  end
end

Ractor.new { M.f }.value
```

This was because `rb_const_get_0()` built the "path" part referring to
the module/class passed to it in the first place. When a constant was
found through recursive search upwards, the module/class which the
constant was found should be reported.

This patch fixes this issue by modifying rb_const_search() to take a
VALUE pointer to be filled with the module/class where the constant was
found.

[Bug #21782]
2025-12-16 17:15:59 -08:00
Étienne Barrié aab4f6287d Add the instance variable name and the module in Ractor::IsolationError (#15563) 2025-12-16 11:47:13 -05:00
Étienne Barrié 09a29e1312 Add the class variable and the class itself in Ractor::IsolationError (#15562) 2025-12-16 11:06:33 -05:00