2684 Commits

Author SHA1 Message Date
Jean Boussier
3abdd4241f Turn rb_classext_t.fields into a T_IMEMO/class_fields
This behave almost exactly as a T_OBJECT, the layout is entirely
compatible.

This aims to solve two problems.

First, it solves the problem of namspaced classes having
a single `shape_id`. Now each namespaced classext
has an object that can hold the namespace specific
shape.

Second, it open the door to later make class instance variable
writes atomics, hence be able to read class variables
without locking the VM.
In the future, in multi-ractor mode, we can do the write
on a copy of the `fields_obj` and then atomically swap it.

Considerations:

  - Right now the `RClass` shape_id is always synchronized,
    but with namespace we should likely mark classes that have
    multiple namespace with a specific shape flag.
2025-06-12 07:58:16 +02:00
Peter Zhu
837699e160 Take file and line in GC VM locks
This commit adds file and line to GC VM locking functions for debugging
purposes and adds upper case macros to pass __FILE__ and __LINE__.
2025-06-09 13:57:18 -04:00
Jean Boussier
f9966b9b76 Get rid of gen_fields_tbl.fields_count
This data is redundant because the shape already contains both the
length and capacity of the object's fields.

So it both waste space and create the possibility of a desync between
the two.

We also do not need to initialize everything to Qundef, this seem
to be a left-over from pre-shape instance variables.
2025-06-09 16:38:29 +02:00
alpaca-tc
c8ddc0a843 Optimize callcache invalidation for refinements
Fixes [Bug #21201]

This change addresses a performance regression where defining methods
inside `refine` blocks caused severe slowdowns. The issue was due to
`rb_clear_all_refinement_method_cache()` triggering a full object
space scan via `rb_objspace_each_objects` to find and invalidate
affected callcaches, which is very inefficient.

To fix this, I introduce `vm->cc_refinement_table` to track
callcaches related to refinements. This allows us to invalidate
only the necessary callcaches without scanning the entire heap,
resulting in significant performance improvement.
2025-06-09 12:33:35 +09:00
Jean Boussier
a640723d31 Simplify rb_gc_rebuild_shape
Now that there no longer multiple shape roots, all we need to do
when moving an object from one slot to the other is to update the
`heap_index` part of the shape_id.

Since this never need to create a shape transition, it will always
work and never result in a complex shape.
2025-06-07 18:30:44 +02:00
Koichi Sasada
1605704117 ignore confirming belonging while finrializer
A finalizer registerred in Ractor A can be invoked in B.

```ruby
require "tempfile"
r = Ractor.new{
  10_000.times{|i|
    Tempfile.new(["file_to_require_from_ractor#{i}", ".rb"])
  }
}
sleep 0.1
```

For example, above script makes tempfiles which have finalizers
on Ractor r, but at the end of the process, main Ractor will invoke
finalizers and it violates belonging check. This patch just ignore
the belonging check to avoid CI failure.

Of course it violates Ractor's isolation and wrong workaround.
This issue will be solved with Ractor local GC.
2025-06-07 09:52:03 +09:00
Koichi Sasada
1baa396e21 fix rp(obj) for any object
Now `rp(obj)` doesn't work if the `obj` is out-of-heap because
of `asan_unpoisoning_object()`, so this patch solves it.

Also add pointer information and type information to show.
2025-06-06 13:44:15 +09:00
Jean Boussier
772fc1f187 Get rid of rb_shape_t.flags
Now all flags are only in the `shape_id_t`, and can all be checked
without needing to dereference a pointer.
2025-06-05 07:44:44 +02:00
Peter Zhu
99cc100cdf Remove dead rb_malloc_info_show_results 2025-06-04 14:07:19 -04:00
John Hawthorn
e596cf6e93 Make FrozenCore a plain T_CLASS 2025-06-02 14:57:48 -04:00
Koichi Sasada
ef2bb61018 Ractor::Port
* Added `Ractor::Port`
  * `Ractor::Port#receive` (support multi-threads)
  * `Rcator::Port#close`
  * `Ractor::Port#closed?`
* Added some methods
  * `Ractor#join`
  * `Ractor#value`
  * `Ractor#monitor`
  * `Ractor#unmonitor`
* Removed some methods
  * `Ractor#take`
  * `Ractor.yield`
* Change the spec
  * `Racotr.select`

You can wait for multiple sequences of messages with `Ractor::Port`.

```ruby
ports = 3.times.map{ Ractor::Port.new }
ports.map.with_index do |port, ri|
  Ractor.new port,ri do |port, ri|
    3.times{|i| port << "r#{ri}-#{i}"}
  end
end

p ports.each{|port| pp 3.times.map{port.receive}}

```

In this example, we use 3 ports, and 3 Ractors send messages to them respectively.
We can receive a series of messages from each port.

You can use `Ractor#value` to get the last value of a Ractor's block:

```ruby
result = Ractor.new do
  heavy_task()
end.value
```

You can wait for the termination of a Ractor with `Ractor#join` like this:

```ruby
Ractor.new do
  some_task()
end.join
```

`#value` and `#join` are similar to `Thread#value` and `Thread#join`.

To implement `#join`, `Ractor#monitor` (and `Ractor#unmonitor`) is introduced.

This commit changes `Ractor.select()` method.
It now only accepts ports or Ractors, and returns when a port receives a message or a Ractor terminates.

We removes `Ractor.yield` and `Ractor#take` because:
* `Ractor::Port` supports most of similar use cases in a simpler manner.
* Removing them significantly simplifies the code.

We also change the internal thread scheduler code (thread_pthread.c):
* During barrier synchronization, we keep the `ractor_sched` lock to avoid deadlocks.
  This lock is released by `rb_ractor_sched_barrier_end()`
  which is called at the end of operations that require the barrier.
* fix potential deadlock issues by checking interrupts just before setting UBF.

https://bugs.ruby-lang.org/issues/21262
2025-05-31 04:01:33 +09:00
John Hawthorn
6a62a46c3c Read {max_iv,variation}_count from prime classext
MAX_IV_COUNT is a hint which determines the size of variable width
allocation we should use for a given class. We don't need to scope this
by namespace, if we end up with larger builtin objects on some
namespaces that isn't a user-visible problem, just extra memory use.

Similarly variation_count is used to track if a given object has had too
many branches in shapes it has used, and to use too_complex when that
happens. That's also just a hint, so we can use the same value across
namespaces without it being visible to users.

Previously variation_count was being incremented (written to) on the
RCLASS_EXT_READABLE ext, which seems incorrect if we wanted it to be
different across namespaces
2025-05-29 16:02:07 -04:00
Jean Boussier
925dec8d70 Rename rb_shape_set_shape_id in rb_obj_set_shape_id 2025-05-27 15:34:02 +02:00
Jean Boussier
ccf2b7c5b8 Refactor rb_shape_too_complex_p to take a shape_id_t. 2025-05-27 15:34:02 +02:00
Jean Boussier
a1f72d23a9 Refactor rb_shape_has_object_id
Now takes a `shape_id_t` and the version that takes a `rb_shape_t *`
is private.
2025-05-27 15:34:02 +02:00
Jean Boussier
a80a5000ab Refactor rb_obj_shape out.
It still exists but only in `shape.c`.
2025-05-27 15:34:02 +02:00
Peter Zhu
be5450467b Fix reference updating for id2ref table
The id2ref table could contain dead entries which should not be passed
into rb_gc_location. Also, we already update references in gc_update_references
using rb_gc_vm_weak_table_foreach so we do not need to update it again.
2025-05-27 08:22:26 +02:00
John Hawthorn
f483befd90 Add shape_id to RBasic under 32 bit
This makes `RBobject` `4B` larger on 32 bit systems
but simplifies the implementation a lot.

[Feature #21353]

Co-authored-by: Jean Boussier <byroot@ruby-lang.org>
2025-05-26 10:31:54 +02:00
Nobuyoshi Nakada
aad9fa2853
Use RB_VM_LOCKING 2025-05-25 15:22:43 +09:00
John Hawthorn
11ad7f5f47 Don't use namespaced classext for superclasses
Superclasses can't be modified by user code, so do not need namespace
indirection. For example Object.superclass is always BasicObject, no
matter what modules are included onto it.
2025-05-23 10:22:24 -07:00
Nobuyoshi Nakada
7154b4208b
Fix a -Wmaybe-uninitialized
lev in rb_gc_vm_lock() is uninitialized in single ractor mode.
2025-05-22 10:55:19 +09:00
John Hawthorn
6a16c3e26d Remove too_complex GC assertion
Classes from the default namespace are not writable, however they do not
transition to too_complex until they have been written to inside a user
namespace. So this assertion is invalid (as is the previous location it
was) but it doesn't seem to provide us much value.

Co-authored-by: Aaron Patterson <tenderlove@ruby-lang.org>
2025-05-21 17:23:18 -07:00
Aaron Patterson
6ea893f376 Add assertion for RCLASS_SET_PRIME_CLASSEXT_WRITABLE
When classes are booted, they should all be writeable unless namespaces
are enabled.  This commit adds an assertion to ensure that classes are
writable.
2025-05-21 09:51:32 -07:00
Peter Zhu
ac23fa0902 Use rb_id_table_foreach_values for mark_cc_tbl
We don't need the key, so we can improve performance by only iterating
on the value.

This will also fix the MMTk build because looking up the key in
rb_id_table_foreach requires locking the VM, which is not supported in
the MMTk worker threads.
2025-05-21 11:27:02 -04:00
Jean Boussier
31ba881684 Disable GC when building id2ref table
Building that table will likely malloc several time which
can trigger GC and cause race condition by freeing objects
that were just added to the table.

Disabling GC to prevent the race condition isn't elegant,
but iven this is a deprecated callpath that is executed at
most once per process, it seems acceptable.
2025-05-15 16:29:45 +02:00
Jean Boussier
60ffb714d2 Ensure shape_id is never used on T_IMEMO
It doesn't make sense to set ivars or anything shape
related on a T_IMEMO.

Co-Authored-By: John Hawthorn <john@hawthorn.email>
2025-05-15 16:06:52 +02:00
Jean Boussier
b5575a80bc Reduce Object#object_id contention.
If the object isn't shareable and already has a object_id
we can access it without a lock.

If we need to generate an ID, we may need to lock to find
the child shape.

We also generate the next `object_id` using atomics.
2025-05-14 14:41:46 +02:00
Jean Boussier
f9c3feccf4 Rename id_to_obj_tbl -> id2ref_tbl
As well as associated functions, this should make it more obvious
what the purpose is.
2025-05-14 11:41:14 +02:00
Jean Boussier
9400119702 Fix object_id for classes and modules in namespace context
Given classes and modules have a different set of fields in every
namespace, we can't store the object_id in fields for them.

Given that some space was freed in `RClass` we can store it there
instead.
2025-05-14 10:26:48 +02:00
Jean Boussier
2ca8769443 Reclaim one VALUE from rb_classext_t
The `includer` field is only used for `T_ICLASS`, so by moving
it into the existing union we can save one `VALUE` per class
and module.
2025-05-13 14:55:39 +02:00
Samuel Williams
425fa0aeb5
Make waiting_fd behaviour per-IO. (#13127)
- `rb_thread_fd_close` is deprecated and now a no-op.
- IO operations (including close) no longer take a vm-wide lock.
2025-05-13 19:02:03 +09:00
Jean Boussier
a6435befa7 variable.c: Refactor rb_obj_field_* to take shape_id_t 2025-05-13 10:35:34 +02:00
Peter Zhu
85d9ebc995 Remove duplicate asan_unpoisoning_object
It's already defined in internal/sanitizers.h.
2025-05-12 10:51:17 -04:00
Jean Boussier
8b7a4d167a Handle GC triggering while building the initial id_to_obj_tbl
GC can trigger while we build the table, and if it sweeps an object
with an ID, it may not find it in the `id_to_obj` table.
2025-05-11 22:05:06 +02:00
Jean Boussier
f2e5f6dbb6 Allow T_CLASS and generic types to be too_complex
The intial complex shape implementation never allowed objects
other than T_OBJECT to become too complex, unless we run out of
shapes.

I don't see any reason to prevent that.

Ref: https://github.com/ruby/ruby/pull/6931
2025-05-11 19:35:58 +02:00
Satoshi Tagomori
ae2d5378e8 Suppress warning about unused variable without VM_CHECK_MODE 2025-05-11 23:32:50 +09:00
Satoshi Tagomori
bbcc3782b1 Skip updating max_iv_count when the namespace cannot be determined 2025-05-11 23:32:50 +09:00
Satoshi Tagomori
294b52fb9b Follow the code style about else 2025-05-11 23:32:50 +09:00
Satoshi Tagomori
90e5ce6132 Rename RCLASS_EXT() macro to RCLASS_EXT_PRIME() to prevent using it wrongly
The macro RCLASS_EXT() accesses the prime classext directly, but it can be
valid only in a limited situation when namespace is enabled.
So, to prevent using RCLASS_EXT() in the wrong way, rename the macro and
let the developer check it is ok to access the prime classext or not.
2025-05-11 23:32:50 +09:00
Satoshi Tagomori
382645d440 namespace on read 2025-05-11 23:32:50 +09:00
Daisuke Aritomo
98667f82d2 [DOC] Update documentation for ObjectSpace#each_object
Co-authored-by: Benoit Daloze <eregontp@gmail.com>
2025-05-10 19:32:21 +02:00
Daisuke Aritomo
29b3d683fb [DOC] Make clear that current behavior is not ideal 2025-05-10 19:32:21 +02:00
Daisuke Aritomo
a51b4a86fc [DOC] ObjectSpace#each_object behavior in multi-Ractor mode
This behavior of ObjectSpace#each_object has been around since Ruby 3.0
when Ractors were first introduced, but was never documented and has
caused some amount of confusion:

https://bugs.ruby-lang.org/issues/17360
https://bugs.ruby-lang.org/issues/19387
https://bugs.ruby-lang.org/issues/21149
2025-05-10 19:32:21 +02:00
Jean Boussier
d9502a8386 Rename rb_field_get -> rb_obj_field_get
To be consistent with `rb_obj_field_set`.
2025-05-10 15:39:33 +02:00
Jean Boussier
3135eddb4e Refactor FIRST_T_OBJECT_SHAPE_ID to not be used outside shape.c 2025-05-09 20:45:48 +02:00
Jean Boussier
ea77250847 Rename RB_OBJ_SHAPE -> rb_obj_shape
As well as `RB_OBJ_SHAPE_ID` -> `rb_obj_shape_id`
and `RSHAPE` is now a simple alias for `rb_shape_lookup`.

I tried to turn all these into `static inline` but I'm having
trouble with `RUBY_EXTERN rb_shape_tree_t *rb_shape_tree_ptr;`
not being exposed as I'd expect.
2025-05-09 10:22:51 +02:00
Jean Boussier
becc45ff4e Eliminate some rb_shape_t * usages outside of shape.c. 2025-05-09 10:22:51 +02:00
Jean Boussier
5782561fc1 Rename rb_shape_get_shape_id -> RB_OBJ_SHAPE_ID
And `rb_shape_get_shape` -> `RB_OBJ_SHAPE`.
2025-05-09 10:22:51 +02:00
Jean Boussier
3f7c0af051 Rename rb_shape_obj_too_complex -> rb_shape_obj_too_complex_p 2025-05-09 10:22:51 +02:00
Jean Boussier
334ebba221 Rename rb_shape_get_shape_by_id -> RSHAPE 2025-05-09 10:22:51 +02:00