148 Commits
Author SHA1 Message Date
Jeremy Evans 3a66844fa9 Allow super in module method called via refinement method super
This was previously prohibited as it wasn't handled correctly. The
reason it wasn't handled correctly is that at the point of the super
call, the refinement module didn't have the class super pointer
set correctly, so it couldn't determine the ancestor to start the
lookup for the super method to call.  Fix that by lazily creating a
refinement module iclass with the class super pointer set correctly.
This is cached in a hidden hash so it's only created the first time
it is needed (similar to how singleton classes are created).

Unfortunately, storing this hidden hash in an instance variable in
the iclass failed CI due to shape_id layout mismatch errors. Storing
the hidden hash in an instance variable of the class/module itself is
possible, but that doesn't work if the class/module is frozen. So the
only option is to store this in rb_classext_struct. I didn't want to
increase the size of rb_classext_struct, so this uses the classpath
member to store the hash. That member is currently only used for
classes/modules and not for iclasses, so it shouldn't cause any
problems. Ultimately, I think the classpath entry should be moved
into the as union as that would be easier to understand. However, I
did not do so in this commit in order to avoid unnecessary churn.

By lazily creating the iclass, we don't create unnecessary iclasses.
For example, if Enumerable is refined, this only generates refinement
module iclasses for the classes using Enumerable where the refinement
method is actually called.

While working on specs for this, I ran into an infinite loop because
current_method_entry didn't correctly handle bmethods.  So update
current_method_entry to handle that.

Implements [Feature #22309]
2026-10-10 01:14:57 -07:00
Hiroshi SHIBATAandClaude Opus 5 44fff96b0b Attach a box classext to its class before filling it in
rb_class_duplicate_classext builds the whole copy first and the caller only
then puts it in the class's table, so a GC in the middle collects the tables
it has made and marking the class afterwards walks into a freed object.  Put
the classext in the table first instead.  Marking it while it is still half
built is fine, since ZALLOC leaves every field zero.

    $ RUBY_BOX=1 ruby --disable-gems -e 'GC.stress = true; module Enumerable; def m; end; end'
    -e:1: [BUG] try to mark T_NONE object (obj: out-of-heap:0x..., parent: ... T_MODULE/Module Enumerable)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 16:29:51 +09:00
Nobuyoshi Nakada 92cef2802c Mark rb_freeze_singleton_class as internal
`rb_freeze_singleton_class` is an implementation detail of
`RB_OBJ_FREEZE`, so deprecate direct calls from extension libraries
before removing its public declaration in Ruby 4.2.
2026-09-19 18:51:40 +09:00
Koichi SasadaandClaude Fable 5 f5a57659d6 Ractor: move a singleton class's ownership with its object
A singleton class belongs to the owner of the object it is attached to, and
Ractor#send(move: true) hands that object over.  Without this the receiver could
define singleton methods on a moved object only when its singleton class had not
been materialized before the move.  The eigenclass chain above it goes too: each
of those is attached to the class below it, so by the same rule they follow.

The move is refused when any of them holds unshareable constants or variables:
the receiver would become their owner, and so allowed to read them, while the
sender still holds the objects themselves.  The check runs in the preflight pass,
before anything is mutated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-10 16:02:03 +09:00
Koichi SasadaandClaude Fable 5 3f2e84dd36 Ractor: record the creator Ractor of classes/modules
Every class/module records the id of the Ractor that created it in
rb_classext_t::owner_ractor_id; only that Ractor may modify it.  0 means the
main Ractor, so a program that never leaves it stores nothing.

An id rather than the Ractor object: ids come from a monotonic counter and are
never reused, so the comparison can never meet a dangling or recycled identity,
there is nothing for the GC to trace or move, and a class does not keep its
creator alive.  It also gives the termination rule for free -- once the owner
is gone no live Ractor carries its id, so no comparison can succeed and the
class is read-only for everybody.

Singleton classes and metaclasses inherit the owner of the attached
class/module instead of the Ractor which happened to trigger their lazy
creation.

rb_class_owned_p() is inline: later commits put it on the class instance
variable and constant read paths, where it replaces what used to be a single
load of ruby_single_main_ractor.  Only the non-main-owner half is out of line.
That needs rb_ractor_main_p() in internal/class.h, hence the include guard
ractor_core.h was missing.

This commit only records the ownership and introduces the
rb_class_owned_p()/rb_class_owner_check() helpers; no behavior changes yet.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-10 16:02:03 +09:00
Takashi KokubunandNobuyoshi Nakada dcfba57257 Suppress -Warray-bounds false positive in RCLASS_WRITE_SUPER (#16990)
After 4bb1977b78 switched RCLASS_PRIME_CLASSEXT_WRITABLE_P to FL_TEST_RAW,
GCC lost the RB_FL_ABLE-derived hint that klass is not a special const,
and started warning that RCLASS_EXT_PRIME(klass) (used by the inlined
RCLASS_WRITE_SUPER in class_associate_super) could yield a near-zero
pointer. Make the existing VM_ASSERT(klass != 0) precondition visible
to the optimizer via RBIMPL_ASSUME so the warning goes away without
re-introducing the FL_TEST overhead.

Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
2026-05-26 14:50:45 -07:00
Jeremy Evans cb0cd76a08 Handle refinements correctly in {Method,UnboundMethod}#super_method
A `Method#super_method` chain should return the methods that `super`
would call if the method was called normally. Previously, there were
multiple problems:

* There was an infinite `super_method` loop for refined methods.

* Lookup considered the refinements activated at the call site of
  `super_method`, and not all the call site of `super` inside the
  method.

This tries to recreate the logic that `super` uses inside
`super_method`. It avoids the loop. It also considers the refinements
activated for the method itself, not for the caller of `super_method`,
correctly handling refinements in outer scopes of the method. This
requires avoiding the use of rb_callable_method_entry_with_refinements,
which implicitly will consider refinements activated in the caller of
`super_method`.

The added tests attempt to ensure that the `super_method` lookup chain
matches the methods that `super` calls if you call the method.

This adds an `RICLASS_FOR_REFINEMENT_P` helper method, for logic that
is used a couple times in the new code and once in
`vm_search_normal_superclass`.
2026-05-19 17:06:09 -07:00
Luke Gruber 4bb1977b78 Fix perf. of RCLASS_EXT_WRITABLE
FL_TEST -> FL_TEST_RAW
FL_SET  -> FL_SET_RAW

I was seeing bad performance on the ruby-bench getivar-module benchmark
when using yjit. This was with other changes in a branch, but changes
totally unrelated to accessing ivars on a class or using boxes. The
change to RCLASS_PRIME_CLASSEXT_WRITABLE_P was the one that made the
difference, but I changed a couple of other FL_SET uses as well. This
change reduced the benchmark runs from 60ms to 40ms.
2026-05-14 12:44:36 -04:00
John Hawthorn f71840a230 Replace subclasses linked list with weakref array 2026-05-13 18:36:51 -07:00
John Hawthorn 88095eb196 Remove CREF rewriting for cloned classes/modules
When a class or module was cloned, rb_vm_rewrite_cref would rewrite the
CREF chain of each cloned method to point at the new class. Remove this
special case so that clone behaves consistently with all other ways of
adopting a method.

This also removes the RCLASS_CLONED flag which was used to prevent
constant inline cache sharing between cloned classes [Bug #15877], and
the vm_cref_new_use_prev helper which only existed for CREF rewriting.

[Feature #21981]
2026-05-13 13:40:46 -07:00
Satoshi Tagomori 276f0d9b3e [Bug #21881] Separate the master and root box
This change separates the master box from the root box, as the single
master copy of boxes.
Before this change, the root box is the source of copies, and also
it runs builtin classes' code. Builtin code makes changes by
requiring files, thus the source of copies is mutable, be different
from the past one. This causes different internal states of boxes,
depending on when it is created.
After this change, all boxes are created from the master box, and
the master box never runs code, so it realizes the immutable source
of copies.

This also makes is possible to separate RubyGems (and other default
gems) from each boxes. All boxes will have their own copies of RubyGems.
RubyGems has its internal state, but it'll be separated between boxes
after this change.
2026-05-10 09:38:45 +09: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
Jean Boussier 73b5cbbfb3 class.h: store classpath earlier in the struct
It's probably the most helpful field while debugging, having
it toward the start of the struct ensure `rp` and other debugger
helpers will display it.
2026-05-03 23:40:36 +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
Jean Boussier 45d586ad60 Never increment max_iv_count on Object / BasicObject.
Otherwise some code defining ivars on a naked object early during
program boot can cause all objects to be larger than needed.

This seem like it was always the intention, but wasn't quite
properly prevented.

Also stop updating `max_iv_count` during GC marking as it is
redundant.
2026-05-02 08:46:36 +02: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
Matt Valentine-House c9b7088364 Introduce power-of-two size pools
Replace the RVALUE_SLOT_SIZE-multiplier based pool sizes with explicit
power-of-two (and near-power-of-two) slot sizes. On 64-bit this gives
12 heaps (32, 40, 64, 80, 96, 128, 160, 256, 512, 640, 768, 1024)
instead of 5, providing finer granularity and less internal
fragmentation. On 32-bit the layout is 5 heaps (32, 64, 128, 256, 512).
2026-04-09 13:24:09 +01:00
John Hawthorn 202114608b Use RB_BUILTIN_TYPE in RCLASS_SINGLETON_P
This should avoid us emitting the check for a special constant.
2026-04-06 15:36:54 -07:00
John Hawthorn 3c251f79a3 Don't add singleton classes to subclasses list
Singleton classes don't need to be iterated in the subclasses list, we
only need to know that a subclass exists so that we can use the "method
entry" path for invalidation.
2026-03-30 18:26:58 -07:00
John Hawthorn 111215de27 Copy allocator to subclasses at boot and on change
Copy the allocator from superclass to subclass at class creation time,
so rb_get_alloc_func no longer needs to walk the ancestor chain.

This expands on 68ffc8db08, which did this
copy, but only for classes defined in Ruby (ex. `class Foo`). And allows
us to simple read the allocator field for any class to get the correct
value.

To keep this correct when rb_define_alloc_func is called after
subclasses already exist, propagate the new allocator down to all
subclasses. An RCLASS_ALLOCATOR_DEFINED flag distinguishes classes with
an explicitly set allocator from those that inherited one, so
propagation stops at subclasses that define their own.
2026-03-25 12:51:46 -07:00
John Hawthorn a0583318d3 Don't allow RCLASS_ALLOCATOR on a singleton 2026-03-25 12:51:46 -07: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
John Hawthorn 32e6dc0f31 Speed up class allocator search
This rewrites the class allocator search to be faster. Instead of using
RCLASS_SUPER, which is now even slower due to Box, we can scan the
superclasses list to find a class where the allocator is defined.

This also disallows allocating from an ICLASS. Previously I believe that
was only done for FrozenCore, and that was changed in
e596cf6e93.
2025-12-11 09:53:10 -08:00
Satoshi Tagomori 9eafeaed67 Box: Free rb_classext_t struct for a box when the box is GCed 2025-12-02 23:49:49 +09:00
Luke Gruber 148fde2754 Revert "ns_subclasses refcount accesses need to be atomic (#15083)" (#15138)
This reverts commit 2998c8d6b9.

We need to find a better way to fix this bug. Even with this refcount
change, errors were still being seen in CI. For now we need to remove
this failing test.
2025-11-11 02:52:43 +00:00
John Hawthorn 6238b6f53e Remove unused subclass methods 2025-11-10 15:55:38 -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
Luke Gruber 2998c8d6b9 ns_subclasses refcount accesses need to be atomic (#15083)
We were seeing errors like:

```
* thread #8, stop reason = EXC_BAD_ACCESS (code=1, address=0x803)
  * frame #0: 0x00000001001fe944 ruby`rb_st_lookup(tab=0x00000000000007fb, key=1, value=0x00000001305b7490) at st.c:1066:22
    frame #1: 0x000000010002d658 ruby`remove_class_from_subclasses [inlined] class_get_subclasses_for_ns(tbl=0x00000000000007fb, ns_id=1) at class.c:604:9
    frame #2: 0x000000010002d650 ruby`remove_class_from_subclasses(tbl=0x00000000000007fb, ns_id=1, klass=4754039232) at class.c:620:34
    frame #3: 0x000000010002c8a8 ruby`rb_class_classext_free_subclasses(ext=0x000000011b5ce1d8, klass=4754039232, replacing=<unavailable>) at class.c:700:9
    frame #4: 0x000000010002c760 ruby`rb_class_classext_free(klass=4754039232, ext=0x000000011b5ce1d8, is_prime=true) at class.c:105:5
    frame #5: 0x00000001000e770c ruby`classext_free(ext=<unavailable>, is_prime=<unavailable>, namespace=<unavailable>, arg=<unavailable>) at gc.c:1231:5 [artificial]
    frame #6: 0x000000010002d178 ruby`rb_class_classext_foreach(klass=<unavailable>, func=(ruby`classext_free at gc.c:1228), arg=0x00000001305b75c0) at class.c:518:5
    frame #7: 0x00000001000e745c ruby`rb_gc_obj_free(objspace=0x000000012500c400, obj=4754039232) at gc.c:1282:9
    frame #8: 0x00000001000e70d4 ruby`gc_sweep_plane(objspace=0x000000012500c400, heap=<unavailable>, p=4754039232, bitset=4095, ctx=0x00000001305b76e8) at default.c:3482:21
    frame #9: 0x00000001000e6e9c ruby`gc_sweep_page(objspace=0x000000012500c400, heap=0x000000012500c540, ctx=0x00000001305b76e8) at default.c:3567:13
    frame #10: 0x00000001000e51d0 ruby`gc_sweep_step(objspace=0x000000012500c400, heap=0x000000012500c540) at default.c:3848:9
    frame #11: 0x00000001000e1880 ruby`gc_continue [inlined] gc_sweep_continue(objspace=0x000000012500c400, sweep_heap=0x000000012500c540) at default.c:3931:13
    frame #12: 0x00000001000e1754 ruby`gc_continue(objspace=0x000000012500c400, heap=0x000000012500c540) at default.c:2037:9
    frame #13: 0x00000001000e10bc ruby`newobj_cache_miss [inlined] heap_prepare(objspace=0x000000012500c400, heap=0x000000012500c540) at default.c:2056:5
    frame #14: 0x00000001000e1074 ruby`newobj_cache_miss [inlined] heap_next_free_page(objspace=0x000000012500c400, heap=0x000000012500c540) at default.c:2280:9
    frame #15: 0x00000001000e106c ruby`newobj_cache_miss(objspace=0x000000012500c400, cache=0x0000600001b00300, heap_idx=2, vm_locked=false) at default.c:2387:38
    frame #16: 0x00000001000e0d28 ruby`newobj_alloc(objspace=<unavailable>, cache=<unavailable>, heap_idx=<unavailable>, vm_locked=<unavailable>) at default.c:2411:15 [artificial]
    frame #17: 0x00000001000d7214 ruby`newobj_of [inlined] rb_gc_impl_new_obj(objspace_ptr=<unavailable>, cache_ptr=<unavailable>, klass=<unavailable>, flags=<unavailable>, wb_protected=<unavailable>, alloc_size=<unavailable>) at default.c:2490:15
    frame #18: 0x00000001000d719c ruby`newobj_of(cr=<unavailable>, klass=4313971728, flags=258, wb_protected=<unavailable>, size=<unavailable>) at gc.c:995:17
    frame #19: 0x00000001000d73ec ruby`rb_wb_protected_newobj_of(ec=<unavailable>, klass=<unavailable>, flags=<unavailable>, size=<unavailable>) at gc.c:1044:12 [artificial]
    frame #20: 0x0000000100032d34 ruby`class_alloc0(type=<unavailable>, klass=4313971728, namespaceable=<unavailable>) at class.c:803:5
```
2025-11-06 16:32:20 -05:00
Satoshi Tagomori f53b8194cd Stop deleting the reference from superclass when replacing classext.
Calling the usual rb_iclass_classext_free() causes SEGV because
duplicating a newer classext of iclass had set the reference from superclass
to the newer classext, but calling rb_iclass_classext_free() deletes it.
2025-10-26 17:49:39 +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
Peter Zhu 4a23b6a89f Fix memory leak in RCLASS_SET_NAMESPACE_CLASSEXT
The st_insert in RCLASS_SET_NAMESPACE_CLASSEXT may overwrite an existing
rb_classext_t, causing it to leak memory. This commit changes it to use
st_update to free the existing one before overwriting it.
2025-10-21 18:42:17 -04:00
Peter Zhu cd42096f5a Move rb_class_classext_free to class.c 2025-10-21 18:42:17 -04:00
Satoshi Tagomori 2548c476a3 Add namespace debug methods and assertions 2025-10-07 14:19:26 +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
John Hawthorn feb8331673 Atomic CC table set in cache_callable_method_entry 2025-08-21 09:17:31 +02:00
Jean Boussier 10aa4134d4 imemo_fields: store owner object in RBasic.klass
It is much more convenient than storing the klass, especially
when dealing with `object_id` as it allows to update the id2ref
table without having to dereference the owner, which may be
garbage at that point.
2025-08-13 19:53:18 +02:00
Jean Boussier f2a7e48dea Make RClass.cc_table a managed object
For now this doesn't change anything, but now that the table
is managed by GC, it opens the door to use RCU when in multi-ractor
mode, hence allow unsynchornized reads.
2025-08-01 10:42:04 +02:00
John Hawthorn 9256442615 Cleanup M_TBL workarounds and comments
Previously we had an assertion that the method table was only set on
young objects, and a comment stating that was how it needed to be used.
I think that confused the complexity of the write barriers that may be
needed here.

* Setting an empty M_TBL never needs a write barrier
* T_CLASS and T_MODULE should always fire a write barrier to newly added
  methods
* T_ICLASS only needs a write barrier to methods when
  RCLASSEXT_ICLASS_IS_ORIGIN(x) && !RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(x)

We shouldn't assume that the object being young is sufficient, because
we also need write barriers for incremental marking and it's unreliable.
2025-07-23 14:33:55 -07:00
Jean Boussier 517c106709 imemo_fields_set: save copying when reassigning a variable
If we still fit in the existing imemo/fields object we can
update it atomically, saving a reallocation.
2025-07-03 09:20:22 +02:00
Jean Boussier 32ee3fab0a Shink RClass when it is known they can't be namespaced
Even when namespaces are enabled, only a few core classes created
during init will eventually be namespaced.

For these it's OK to allocate a 320B slot to hold the extra namespace
stuff.

But for any class created post init, we know we'll never need the
namespace and we can fit in a 160B slot.
2025-06-23 10:04:58 +01:00
Jean Boussier ea4a53c595 Avoid creating namespace table for classes that can't be namespaced. 2025-06-23 10:04:58 +01:00
Jean Boussier 96a0c2065a Mark RClass instance that may be namespaced with RCLASS_NAMESPACEABLE 2025-06-23 10:04:58 +01:00
Jean Boussier 164486a954 Refactor rb_imemo_fields_new to not assume T_CLASS 2025-06-17 15:28:05 +02:00
Jean Boussier fb68721f63 Rename imemo_class_fields -> imemo_fields 2025-06-17 15:28:05 +02:00
Jean Boussier 9e839d3c0e Optimize benchmark/vm_ivar_of_class
```
compare-ruby: ruby 3.5.0dev (2025-06-17T08:45:40Z master e9d35671d2) +PRISM [arm64-darwin24]
last_commit=[ruby/json] Fix a typo
built-ruby: ruby 3.5.0dev (2025-06-17T09:27:05Z opt-getivar-for-cl.. ed1d7cd778) +PRISM [arm64-darwin24]

|                      |compare-ruby|built-ruby|
|:---------------------|-----------:|---------:|
|vm_ivar_of_class_set  |     12.306M|   13.957M|
|                      |           -|     1.13x|
|vm_ivar_of_class      |     16.167M|   24.029M|
|                      |           -|     1.49x|
```
2025-06-17 13:00:31 +02:00
Jean Boussier a74c385208 Make setting and accessing class ivars lock-free
Now that class fields have been deletated to a T_IMEMO/class_fields
when we're in multi-ractor mode, we can read and write class instance
variable in an atomic way using Read-Copy-Update (RCU).

Note when in multi-ractor mode, we always use RCU. In theory
we don't need to, instead if we ensured the field is written
before the shape is updated it would be safe.

Benchmark:

```ruby
Warning[:experimental] = false

class Foo
  @foo = 1
  @bar = 2
  @baz = 3
  @egg = 4
  @spam = 5

  class << self
    attr_reader :foo, :bar, :baz, :egg, :spam
  end
end

ractors = 8.times.map do
  Ractor.new do
    1_000_000.times do
      Foo.bar + Foo.baz * Foo.egg - Foo.spam
    end
  end
end

if Ractor.method_defined?(:value)
  ractors.each(&:value)
else
  ractors.each(&:take)
end
```

This branch vs Ruby 3.4:

```bash
$ hyperfine -w 1 'ruby --disable-all ../test.rb' './miniruby ../test.rb'

Benchmark 1: ruby --disable-all ../test.rb
  Time (mean ± σ):      3.162 s ±  0.071 s    [User: 2.783 s, System: 10.809 s]
  Range (min … max):    3.093 s …  3.337 s    10 runs

Benchmark 2: ./miniruby ../test.rb
  Time (mean ± σ):     208.7 ms ±   4.6 ms    [User: 889.7 ms, System: 6.9 ms]
  Range (min … max):   202.8 ms … 222.0 ms    14 runs

Summary
  ./miniruby ../test.rb ran
   15.15 ± 0.47 times faster than ruby --disable-all ../test.rb
```
2025-06-12 14:55:13 +02:00
Jean Boussier 8b5ac5abf2 Fix class instance variable inside namespaces
Now that classes fields are delegated to an object with its own
shape_id, we no longer need to mark all classes as TOO_COMPLEX.
2025-06-12 13:43:29 +02:00