2779 Commits

Author SHA1 Message Date
Matt Valentine-House
3c634893e2 Remove the unnecesary integer comparison
Most compilers will optimise this anyway
2026-01-26 18:01:09 +00:00
Matt Valentine-House
d15117e293 BIGNUM can't have fields other than object_id 2026-01-26 18:01:09 +00:00
Matt Valentine-House
7444f415db rename rb_gc_obj_free_on_sweep -> rb_gc_obj_needs_cleanup_p 2026-01-26 18:01:09 +00:00
Matt Valentine-House
efde37b712 Move the gc fast path out of the default GC impl
It relies too much on VM level concerns, such that it can't be built
with modular GC enabled.

We'll move it into the VM, and then expose it to the GC
implementations so they can use it.
2026-01-26 18:01:09 +00:00
Matt Valentine-House
c21f3490d1 Implement a fast path for sweeping (gc_sweep_fast_path_p).
[Feature #21846]

There is a single path through our GC Sweeping code, and we always call
rb_gc_obj_free_vm_weak_references and rb_gc_obj_free before adding the
object back to the freelist.

We do this even when the object has no external resources that require
being free'd and has no weak references pointing to it.

This commit introduces a conservative fast path through gc_sweep_plane
that uses the object flags to identify certain cases where these calls
can be skipped - for these objects we just add them straight back on the
freelist. Any object for which gc_sweep_fast_path_p returns false will
use the current full sweep code (referred to here as the slow path).

Currently there are 2 checks that
will _always_ require an object to go down the slow path:

1. Has it's object_id been observed and stored in the id2ref_table
2. Has it got generic ivars in the gen_fields table

If neither of these are true, then we run some flag checks on the object
and send the following cases down the fast path:

- Objects that are not heap allocated
- Embedded strings that aren't in the fstring table
- Embedded Arrays
- Embedded Hashes
- Embedded Bignums
- Embedded Strings
- Floats, Rationals and Complex
- Various IMEMO subtypes that do no allocation

We've benchmarked this code using ruby-bench as well as the gcbench
benchmarks inside Ruby (benchmarks/gc) and this patch results in a
modest speed improvement on almost all of the headline benchmarks (2% in
railsbench with YJIT enabled), and an observable 30% improvement in time
spent sweeping during the GC benchmarks:

```
master: ruby 4.1.0dev (2026-01-19T12:03:33Z master 859920dfd2) +YJIT +PRISM [x86_64-linux]
experiment: ruby 4.1.0dev (2026-01-16T21:36:46Z mvh-sweep-fast-pat.. c3ffe377a1) +YJIT +PRISM [x86_64-linux]

--------------  -----------  ----------  ---------------  ----------  ------------------  -----------------
bench           master (ms)  stddev (%)  experiment (ms)  stddev (%)  experiment 1st itr  master/experiment
lobsters        N/A          N/A         N/A              N/A         N/A                 N/A
activerecord    132.5        0.9         132.5            1.0         1.056               1.001
chunky-png      577.2        0.4         580.1            0.4         0.994               0.995
erubi-rails     902.9        0.2         894.3            0.2         1.040               1.010
hexapdf         1763.9       3.3         1760.6           3.7         1.027               1.002
liquid-c        56.9         0.6         56.7             1.4         1.004               1.003
liquid-compile  46.3         2.1         46.1             2.1         1.005               1.004
liquid-render   77.8         0.8         75.1             0.9         1.023               1.036
mail            114.7        0.4         113.0            1.4         1.054               1.015
psych-load      1635.4       1.4         1625.9           0.5         0.988               1.006
railsbench      1685.4       2.4         1650.1           2.0         0.989               1.021
rubocop         133.5        8.1         130.3            7.8         1.002               1.024
ruby-lsp        140.3        1.9         137.5            1.8         1.007               1.020
sequel          64.6         0.7         63.9             0.7         1.003               1.011
shipit          1196.2       4.3         1181.5           4.2         1.003               1.012
--------------  -----------  ----------  ---------------  ----------  ------------------  -----------------

Legend:
- experiment 1st itr: ratio of master/experiment time for the first benchmarking iteration.
- master/experiment: ratio of master/experiment time. Higher is better for experiment. Above 1 represents a speedup.
```

```
Benchmark      │    Wall(B)   Sweep(B)  Mark(B) │    Wall(E)   Sweep(E)  Mark(E) │   Wall Δ  Sweep Δ
───────────────┼─────────────────────────────────┼─────────────────────────────────┼──────────────────
null           │     0.000s        1ms      4ms │     0.000s        1ms      4ms │       0%       0%
hash1          │     4.330s      875ms     46ms │     3.960s      531ms     44ms │ +8.6% +39.3%
hash2          │     6.356s      243ms    988ms │     6.298s      176ms    1.03s │ +0.9% +27.6%
rdoc           │    37.337s      2.42s    1.09s │    36.678s      2.11s    1.20s │ +1.8% +13.1%
binary_trees   │     3.366s      426ms    252ms │     3.082s      275ms    239ms │ +8.4% +35.4%
ring           │     5.252s       14ms    2.47s │     5.327s       12ms    2.43s │ -1.4% +14.3%
redblack       │     2.966s       28ms     41ms │     2.940s       21ms     38ms │ +0.9% +25.0%
───────────────┼─────────────────────────────────┼─────────────────────────────────┼──────────────────

Legend: (B) = Baseline, (E) = Experiment, Δ = improvement (positive = faster)
        Wall = total wallclock, Sweep = GC sweeping time, Mark = GC marking time
        Times are median of 3 runs
```

These results are also borne out when YJIT is disabled:

```
master: ruby 4.1.0dev (2026-01-19T12:03:33Z master 859920dfd2) +PRISM [x86_64-linux]
experiment: ruby 4.1.0dev (2026-01-16T21:36:46Z mvh-sweep-fast-pat.. c3ffe377a1) +PRISM [x86_64-linux]

--------------  -----------  ----------  ---------------  ----------  ------------------  -----------------
bench           master (ms)  stddev (%)  experiment (ms)  stddev (%)  experiment 1st itr  master/experiment
lobsters        N/A          N/A         N/A              N/A         N/A                 N/A
activerecord    389.6        0.3         377.5            0.3         1.032               1.032
chunky-png      1123.4       0.2         1109.2           0.2         1.013               1.013
erubi-rails     1754.3       0.1         1725.7           0.1         1.035               1.017
hexapdf         3346.5       0.9         3326.9           0.7         1.003               1.006
liquid-c        84.0         0.5         83.5             0.5         0.992               1.006
liquid-compile  74.0         1.5         73.5             1.4         1.011               1.008
liquid-render   199.9        0.4         199.6            0.4         1.000               1.002
mail            177.8        0.4         176.4            0.4         1.069               1.008
psych-load      2749.6       0.7         2777.0           0.0         0.980               0.990
railsbench      2983.0       1.0         2965.5           0.8         1.041               1.006
rubocop         228.8        1.0         227.5            1.2         1.015               1.005
ruby-lsp        221.8        0.9         216.1            0.8         1.011               1.026
sequel          89.1         0.5         89.1             1.8         1.005               1.000
shipit          2385.6       1.6         2371.8           1.0         1.002               1.006
--------------  -----------  ----------  ---------------  ----------  ------------------  -----------------

Legend:
- experiment 1st itr: ratio of master/experiment time for the first benchmarking iteration.
- master/experiment: ratio of master/experiment time. Higher is better for experiment. Above 1 represents a speedup.
```

```
Benchmark      │    Wall(B)   Sweep(B)  Mark(B) │    Wall(E)   Sweep(E)  Mark(E) │   Wall Δ  Sweep Δ
───────────────┼─────────────────────────────────┼─────────────────────────────────┼──────────────────
null           │     0.000s        1ms      4ms │     0.000s        1ms      3ms │       0%       0%
hash1          │     4.349s      877ms     45ms │     4.045s      532ms     44ms │ +7.0% +39.3%
hash2          │     6.575s      235ms    967ms │     6.540s      181ms    1.04s │ +0.5% +23.0%
rdoc           │    45.782s      2.23s    1.14s │    44.925s      1.90s    1.01s │ +1.9% +15.0%
binary_trees   │     6.433s      426ms    252ms │     6.268s      278ms    240ms │ +2.6% +34.7%
ring           │     6.584s       17ms    2.33s │     6.738s       13ms    2.33s │ -2.3% +30.8%
redblack       │    13.334s       31ms     42ms │    13.296s       24ms    107ms │ +0.3% +22.6%
───────────────┼─────────────────────────────────┼─────────────────────────────────┼──────────────────

Legend: (B) = Baseline, (E) = Experiment, Δ = improvement (positive = faster)
        Wall = total wallclock, Sweep = GC sweeping time, Mark = GC marking time
        Times are median of 3 runs
```
2026-01-26 18:01:09 +00:00
Peter Zhu
19450d85d6 [DOC] Improve docs for ObjectSpace.define_finalizer 2026-01-18 10:47:13 -05:00
Jean Boussier
73be9992e9 Disambiguate private and public RSTRUCT_ helpers
RSTRUCT_LEN / RSTRUCT_GET / RSTRUCT_SET all existing in two
versions, one public that does type and frozens checks
and one private that doesn't.

The problem is that this is error prone because the public version
is always accessible, but the private one require to include
`internal/struct.h`. So you may have some code that rely on the
public version, and later on the private header is included and
changes the behavior.

This already led to introducing a bug in YJIT & ZJIT:
https://github.com/ruby/ruby/pull/15835
2026-01-11 13:03:03 +01:00
Peter Zhu
7379b9ed78 Optimize rb_mark_generic_ivar for T_DATA and T_STRUCT
T_DATA and T_STRUCT could have ivars but might not use the generic_fields_tbl.
This commit skips lookup in the generic_fields_tbl for those cases.
2026-01-09 17:31:10 +01:00
Peter Zhu
7d5c0247eb Dump fstr and frozen status in rb_raw_obj_info_buitin_type 2026-01-04 12:26:06 -05:00
Peter Zhu
6939f03f4c Add field handle_weak_references to TypedData
This commit adds a field handle_weak_references to rb_data_type_struct for
the callback when handling weak references. This avoids TypedData objects
from needing to expose their rb_data_type_struct and weak references function.
2026-01-04 09:02:40 -05:00
Peter Zhu
5b87294d2f Add rb_gc_print_backtrace 2026-01-03 10:43:24 -05:00
Nobuyoshi Nakada
d95bebe06c
Make RTYPEDDATA_EMBEDDABLE_P internal-use only
It should not be exposed because it is so implementation specific that
it is only used in gc.c even within the entire Ruby source tree.
2025-12-31 11:29:29 +09:00
Nobuyoshi Nakada
c352808fa9
Introduce typed-data embeddable predicate macros
The combination of `&` and `&&` is confusing.
2025-12-31 11:27:46 +09:00
Peter Zhu
7902ae34d0 Add rb_gc_move_obj_during_marking 2025-12-29 09:03:31 -05:00
Peter Zhu
01cd9c9fad Add rb_gc_register_pinning_obj 2025-12-29 09:03:31 -05:00
Nobuyoshi Nakada
f84110e601
Remove old APIs to allocate a data object deprecated for 5 years 2025-12-26 17:02:41 +09:00
Peter Zhu
57637827e6 Implement cont using declare weak references 2025-12-25 09:18:17 -05:00
Peter Zhu
0c07a4246c Implement weak references on gen fields cache 2025-12-25 09:18:17 -05:00
Peter Zhu
ade779b1e1 Implement callcache using declare weak references 2025-12-25 09:18:17 -05:00
Peter Zhu
b2feb09efe Implement WeakMap and WeakKeyMap using declare weak references 2025-12-25 09:18:17 -05:00
Peter Zhu
10b97f52fd Implement declaring weak references
[Feature #21084]

 # Summary

The current way of marking weak references uses `rb_gc_mark_weak(VALUE *ptr)`.
This presents challenges because Ruby's GC is incremental, meaning that if the
`ptr` changes (e.g. realloc'd or free'd), then we could have an invalid memory
access. This also overwrites `*ptr = Qundef` if `*ptr` is dead, which prevents
any cleanup to be run (e.g. freeing memory or deleting entries from hash
tables). This ticket proposes `rb_gc_declare_weak_references` which declares
that an object has weak references and calls a cleanup function after marking,
allowing the object to clean up any memory for dead objects.

 # Introduction

In [[Feature #19783]](https://bugs.ruby-lang.org/issues/19783), I introduced an
API allowing objects to mark weak references, the function signature looks like
this:

```c
void rb_gc_mark_weak(VALUE *ptr);
```

`rb_gc_mark_weak` is called during the marking phase of the GC to specify that
the memory at `ptr` holds a pointer to a Ruby object that is weakly referenced.
`rb_gc_mark_weak` appends this pointer to a list that is processed after the
marking phase of the GC. If the object at `*ptr` is no longer alive, then it
overwrites the object reference with a special value (`*ptr = Qundef`).

However, this API resulted in two challenges:

1. Ruby's default GC is incremental, which means that the GC is not ran in one
   phase, but rather split into chunks of work that interleaves with Ruby
   execution. The `ptr` passed into `rb_gc_mark_weak` could be on the malloc
   heap, and that memory could be realloc'd or even free'd. We had to use
   workarounds such as `rb_gc_remove_weak` to ensure that there were no illegal
   memory accesses. This made `rb_gc_mark_weak` difficult to use, impacted
   runtime performance, and increased memory usage.
2. When an object dies, `rb_gc_mark_weak` only overwites the reference with
   `Qundef`. This means that if we want to do any cleanup (e.g. free a piece of
   memory or delete a hash table entry), we could not do that and had to defer
   this process elsewhere (e.g. during marking or runtime).

In this ticket, I'm proposing a new API for weak references. Instead of an
object marking its weak references during the marking phase, the object declares
that it has weak references using the `rb_gc_declare_weak_references` function.
This declaration occurs during runtime (e.g. after the object has been created)
rather than during GC.

After an object declares that it has weak references, it will have its callback
function called after marking as long as that object is alive. This callback
function can then call a special function `rb_gc_handle_weak_references_alive_p`
to determine whether its references are alive. This will allow the callback
function to do whatever it wants on the object, allowing it to perform any
cleanup work it needs.

This significantly simplifies the code for `ObjectSpace::WeakMap` and
`ObjectSpace::WeakKeyMap` because it no longer needs to have the workarounds for
the limitations of `rb_gc_mark_weak`.

 # Performance

The performance results below demonstrate that `ObjectSpace::WeakMap#[]=` is now
about 60% faster because the implementation has been simplified and the number
of allocations has been reduced. We can see that there is not a significant
impact on the performance of `ObjectSpace::WeakMap#[]`.

Base:

```
ObjectSpace::WeakMap#[]=
                          4.620M (± 6.4%) i/s  (216.44 ns/i) -     23.342M in   5.072149s
ObjectSpace::WeakMap#[]
                         30.967M (± 1.9%) i/s   (32.29 ns/i) -    154.998M in   5.007157s
```

Branch:

```
ObjectSpace::WeakMap#[]=
                          7.336M (± 2.8%) i/s  (136.31 ns/i) -     36.755M in   5.013983s
ObjectSpace::WeakMap#[]
                         30.902M (± 5.4%) i/s   (32.36 ns/i) -    155.901M in   5.064060s
```

Code:

```
require "bundler/inline"

gemfile do
  source "https://rubygems.org"
  gem "benchmark-ips"
end

wmap = ObjectSpace::WeakMap.new
key = Object.new
val = Object.new
wmap[key] = val

Benchmark.ips do |x|
  x.report("ObjectSpace::WeakMap#[]=") do |times|
    i = 0
    while i < times
      wmap[Object.new] = Object.new
      i += 1
    end
  end

  x.report("ObjectSpace::WeakMap#[]") do |times|
    i = 0
    while i < times
      wmap[key]
      wmap[val] # does not exist
      i += 1
    end
  end
end
```

 # Alternative designs

Currently, `rb_gc_declare_weak_references` is designed to be an internal-only
API. This allows us to assume the object types that call
`rb_gc_declare_weak_references`. In the future, if we want to open up this API
to third parties, we may want to change this function to something like:

```c
void rb_gc_add_cleaner(VALUE obj, void (*callback)(VALUE obj));
```

This will allow the third party to implement a custom `callback` that gets
called after the marking phase of GC to clean up any dead references. I chose
not to implement this design because it is less efficient as we would need to
store a mapping from `obj` to `callback`, which requires extra memory.
2025-12-25 09:18:17 -05:00
Peter Zhu
e2cf92eddc Move special const check to gc.c for rb_gc_impl_object_moved_p 2025-12-23 13:54:08 -05:00
Peter Zhu
fe9a7448b1 Check slot_size before zeroing memory for GC hook
If the slot_size < RVALUE_SIZE then we would underflow in the memset.
2025-12-20 11:27:34 -05:00
Luke Gruber
601ac78caf
[DOC] Small changes to docs for ObjectSpace#each_object (#15564)
Change example to use user-defined class instead of `Numeric`.
2025-12-17 14:00:58 -05:00
Nobuyoshi Nakada
61bab18890 Rename to struct rbimpl_size_overflow_tag
This struct is used for addition not only for multiplication, so
remove the word `mul`, and make the member names more descriptive.
2025-12-17 17:35:58 +09:00
John Hawthorn
89e09e4daf Add assumption to free_vm_weak_references
Help the compiler know that we always get a heap object here.
2025-12-11 09:53:18 -08:00
Nobuyoshi Nakada
3636277dc5
Add NUM2PTR and PTR2NUM macros
These macros have been defined here and there, so collect them.
2025-12-10 12:09:50 +09:00
hi
25f277abe4 Fix typos in gc.c and gc.rb 2025-12-09 16:45:38 +09:00
Peter Zhu
4f900c35bc Output ivar length for T_OBJECT in obj_info 2025-12-07 08:51:02 -08:00
Peter Zhu
588347a088 Fix id2ref for multi-Ractor
The id2ref table needs to be under a VM lock to ensure there are no race
conditions. The following script crashes:

    o = Object.new

    ObjectSpace._id2ref(o.object_id)

    10.times.map do
      Ractor.new do
        10_000.times do
          a = Object.new
          a.object_id
        end
      end
    end.map(&:value)

With:

    [BUG] Object ID seen, but not in _id2ref table: object_id=2800 object=T_OBJECT
    ruby 4.0.0dev (2025-12-06T15:15:43Z ractor-id2ref-fix e7f9abdc91) +PRISM [x86_64-linux]

    -- Control frame information -----------------------------------------------
    c:0001 p:---- s:0003 e:000002 l:y b:---- DUMMY  [FINISH]

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

    -- C level backtrace information -------------------------------------------
    miniruby(rb_print_backtrace+0x14) [0x6047d09b2dff] vm_dump.c:1105
    miniruby(rb_vm_bugreport) vm_dump.c:1450
    miniruby(rb_bug_without_die_internal+0x5f) [0x6047d066bf57] error.c:1098
    miniruby(rb_bug) error.c:1116
    miniruby(rb_gc_get_ractor_newobj_cache+0x0) [0x6047d066c8dd] gc.c:2052
    miniruby(gc_sweep_plane+0xad) [0x6047d079276d] gc/default/default.c:3513
    miniruby(gc_sweep_page) gc/default/default.c:3605
    miniruby(gc_sweep_step) gc/default/default.c:3886
    miniruby(gc_sweep+0x1ba) [0x6047d0794cfa] gc/default/default.c:4154
    miniruby(gc_start+0xbf2) [0x6047d0796742] gc/default/default.c:6519
    miniruby(heap_prepare+0xcc) [0x6047d079748c] gc/default/default.c:2090
    miniruby(heap_next_free_page) gc/default/default.c:2305
    miniruby(newobj_cache_miss) gc/default/default.c:2412
    miniruby(newobj_alloc+0xd) [0x6047d0798ff5] gc/default/default.c:2436
    miniruby(rb_gc_impl_new_obj) gc/default/default.c:2515
    miniruby(newobj_of) gc.c:996
    miniruby(rb_wb_protected_newobj_of) gc.c:1046
    miniruby(str_alloc_embed+0x28) [0x6047d08fda18] string.c:1019
    miniruby(str_enc_new) string.c:1069
    miniruby(prep_io+0x5) [0x6047d07cda14] io.c:9305
    miniruby(prep_stdio) io.c:9347
    miniruby(rb_io_prep_stdin) io.c:9365
    miniruby(thread_start_func_2+0x77c) [0x6047d093a55c] thread.c:679
    miniruby(thread_sched_lock_+0x0) [0x6047d093aacd] thread_pthread.c:2241
    miniruby(co_start) thread_pthread_mn.c:469
2025-12-06 10:08:24 -08:00
Peter Zhu
791acc5697 Revert "gc.c: Pass shape_id to newobj_init"
This reverts commit 228d13f6ed914d1e7f6bd2416e3f5be8283be865.

This commit makes default.c and mmtk.c depend on shape.h, which prevents
them from building independently.
2025-12-05 15:40:39 -08:00
Keenan Brock
2b05785941 Allow rb_thread_call_with_gvl() to work when thread already has GVL
[Feature #20750]

Co-authored-by: Benoit Daloze <eregontp@gmail.com>
2025-12-05 20:50:00 +01:00
Jean Boussier
8d1a6bc48b gc.c: check if the struct has fields before marking the fields_obj
If GC trigger in the middle of `struct_alloc`, and the struct has more
than 3 elements, then `fields_obj` reference is garbage.

We must first check the shape to know if it was actually initialized.
2025-12-03 21:15:10 +01:00
Jean Boussier
228d13f6ed gc.c: Pass shape_id to newobj_init
Attempt to fix the following SEGV:

```
ruby(gc_mark) ../src/gc/default/default.c:4429
ruby(gc_mark_children+0x45) [0x560b380bf8b5] ../src/gc/default/default.c:4625
ruby(gc_mark_stacked_objects) ../src/gc/default/default.c:4647
ruby(gc_mark_stacked_objects_all) ../src/gc/default/default.c:4685
ruby(gc_marks_rest) ../src/gc/default/default.c:5707
ruby(gc_marks+0x4e7) [0x560b380c41c1] ../src/gc/default/default.c:5821
ruby(gc_start) ../src/gc/default/default.c:6502
ruby(heap_prepare+0xa4) [0x560b380c4efc] ../src/gc/default/default.c:2074
ruby(heap_next_free_page) ../src/gc/default/default.c:2289
ruby(newobj_cache_miss) ../src/gc/default/default.c:2396
ruby(RB_SPECIAL_CONST_P+0x0) [0x560b380c5df4] ../src/gc/default/default.c:2420
ruby(RB_BUILTIN_TYPE) ../src/include/ruby/internal/value_type.h:184
ruby(newobj_init) ../src/gc/default/default.c:2136
ruby(rb_gc_impl_new_obj) ../src/gc/default/default.c:2500
ruby(newobj_of) ../src/gc.c:996
ruby(rb_imemo_new+0x37) [0x560b380d8bed] ../src/imemo.c:46
ruby(imemo_fields_new) ../src/imemo.c:105
ruby(rb_imemo_fields_new) ../src/imemo.c:120
```

I have no reproduction, but my understanding based on the backtrace
and error is that GC is triggered inside `newobj_init` causing the
new object to be marked while in a incomplete state.

I believe the fix is to pass the `shape_id` down to `newobj_init`
so it can be set before the GC has a chance to trigger.
2025-12-03 19:51:48 +01:00
Jean Boussier
5770c186d1 Rename rb_obj_exivar_p -> rb_obj_gen_fields_p
The "EXIVAR" terminology has been replaced by "gen fields"
AKA "generic fields".

Exivar implies variable, but generic fields include more than
just variables, e.g. `object_id`.
2025-12-03 15:57:26 +01:00
Jean Boussier
8c3909935e Handle NEWOBJ tracepoints settings fields
[Bug #21710]

- struct.c: `struct_alloc`

It is possible for a `NEWOBJ` tracepoint call back to write fields
into a newly allocated object before `struct_alloc` had the time
to set the `RSTRUCT_GEN_FIELDS` flags and such.

Hence we can't blindly initialize the `fields_obj` reference to `0`
we first need to check no fields were added yet.

- object.c: `rb_class_allocate_instance`

Similarly, if a `NEWOBJ` tracepoint tries to set fields on the object,
the `shape_id` must already be set, as it's required on T_OBJECT to
know where to write fields.

`NEWOBJ_OF` had to be refactored to accept a `shape_id`.
2025-12-03 08:14:56 +01:00
Satoshi Tagomori
84bc1f038a Box: Mark boxes when a class/module is originally defined in it.
When a class/module defined by extension libraries in a box, checking
types of instances of the class needs to access its data type (rb_data_type_t).
So if a class still exists (not GCed), the box must exist too (to be marked).
2025-12-02 23:49:49 +09:00
Luke Gruber
1660b8145c
Eliminate redundant work and branching when marking T_OBJECT (#15274) 2025-11-26 16:23:34 -05:00
John Hawthorn
9764306c48 Accurate GC.stat under multi-Ractor mode 2025-11-20 17:19:40 -08:00
John Hawthorn
1f299dd309 Fix crash in optimal size for large T_OBJECT
Previously any T_OBJECT with >= 94 IVARs would crash during compaction
attempting to make an object too large to embed.
2025-11-18 17:02:06 -08:00
Peter Zhu
a731080f46 Make rb_gc_obj_optimal_size always return allocatable size
It may return sizes that aren't allocatable for arrays and strings.
2025-11-09 11:14:54 -08:00
Peter Zhu
827f11fce3 Move rb_gc_verify_shareable to gc.c
rb_gc_verify_shareable is not GC implementation specific so it should live
in gc.c.
2025-11-08 17:58:25 -08:00
Satoshi Tagomori
d2a587c791 renaming internal data structures and functions from namespace to box 2025-11-07 13:14:54 +09:00
Luke Gruber
f1f2dfebe8
Release VM lock before running finalizers (#15050)
We shouldn't run any ruby code with the VM lock held.
2025-11-04 14:46:01 -05:00
John Hawthorn
14f6f7051b Fix rb_gc_impl_checking_shareable for modular GC
This implements it the same as the other modular GC functions
2025-11-04 09:28:53 -08:00
Koichi Sasada
a177799807 catch up modular-gc 2025-10-23 13:08:26 +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
cd42096f5a Move rb_class_classext_free to class.c 2025-10-21 18:42:17 -04:00
Stan Lo
2ed5a02fcc
ZJIT: Add NoSingletonClass patch point (#14680)
* ZJIT: Add NoSingletonClass patch point

This patch point makes sure that when the object has a singleton class,
the JIT code is invalidated. As of now, this is only needed for C call
optimization.

In YJIT, the singleton class guard only applies to Array, Hash, and String.
But in ZJIT, we may optimize C calls from gems (e.g. `sqlite3`). So the
patch point needs to be applied to a broader range of classes.

* ZJIT: Only generate NoSingletonClass guard when the type can have singleton class

* ZJIT: Update or forget NoSingletonClass patch point when needed
2025-10-02 09:03:25 -07:00
Aiden Fox Ivey
2f1c30cd50
ZJIT: Add --zjit-trace-exits (#14640)
Add side exit tracing functionality for ZJIT
2025-09-30 15:55:33 +00:00