173 Commits
Author SHA1 Message Date
Peter Zhu 8972135571 Include JIT call count in ObjectSpace dumps of iseq
This commit adds `jit_calls` and `jit_threshold_reached` to iseq dumps which
dumps the number of calls to the iseq and whether the iseq has been JIT
compiled or not, respectively.
2026-10-09 08:56:20 +09:00
Peter Zhu 5299d8d132 Dump Hash AR/ST status in ObjectSpace.dump 2026-09-26 09:54:59 +09:00
John Hawthorn e4120cace4 Add test for WB-protection in objspace 2026-09-09 22:33:16 -07:00
Luke Gruber 63a726f762 Fix ObjectSpace.shareable_objects_from: don't return foreign unshareables
After the rlgc merge, this method and also ObjectSpace.shareable_objects_from_roots could
return foreign unshareables which violates Ractor containment.
2026-08-10 09:57:05 -04:00
Luke Gruber a77781faf6 Ractor: heap dumps include zombie objspaces
Zombie objspaces are created a Ractor is joined but `#value` wasn't
called on it. They are also created when a Ractor is collected and
didn't have its objspace absorbed by another Ractor. If we do a heap
dump of all objects, we want to see the shareables in those objspaces.
2026-08-10 09:55:09 -04:00
Nobuyoshi Nakada 937f6c22b3 Use assert_include instead of assert_includes 2026-08-08 14:46:58 +09:00
Peter Zhu 66c8e49a18 Unify STR_DUPLICATE_MAX_EMBED_LEN and STR_SUBSEQ_MAX_EMBED_SIZE 2026-08-07 19:58:21 -04:00
Koichi SasadaandClaude 5f87918fb4 GC: per-Ractor local GC — tests
Adjust bootstraptest and test-all for the per-Ractor local GC, and add
regression tests for the Ractor lifecycle and cross-objspace cases.

Co-authored-by: Claude <noreply@anthropic.com>
2026-08-07 16:27:53 +09:00
Peter Zhu c2473016ed Set STR_DUPLICATE_MAX_EMBED_LEN to 256
I benchmarked various values of STR_DUPLICATE_MAX_EMBED_LEN and the
performance impacts. For String#dup, creating a view is faster until it
is below 256 bytes. Unsurprisingly, if we add modification to the string,
then it is faster to eagerly create a copy than use a view. Surprisingly,
if we append to the string, it's still faster to go from embedded -> extended
than shared -> extended. However, both of these cases will incur a memory
penalty as the remainder of the slot is wasted memory.

Benchmark:

    require "benchmark"

    TIMES = 10_000_000

    Benchmark.bm do |x|
      [64, 128, 256, 512, 1024].each do |len|
        len -= 25 # Subtract header length

        x.report("String#dup for #{len.to_s}") do
          pid = fork do
            str = ("a" * len).freeze

            i = 0
            while i < TIMES
              str.dup
              i += 1
            end
          end
          Process.wait(pid)
        end

        x.report("String#dup + String#[]= for #{len.to_s}") do
          pid = fork do
            str = ("a" * len).freeze

            i = 0
            while i < TIMES
              dup = str.dup
              dup[0] = "1"
              i += 1
            end
          end
          Process.wait(pid)
        end

        x.report("String#dup + String#<< for #{len.to_s}") do
          pid = fork do
            str = ("a" * len).freeze

            i = 0
            while i < TIMES
              dup = str.dup
              dup << "1"
              i += 1
            end
          end
          Process.wait(pid)
        end
      end
    end

Result:

    1024

                                            user     system      total        real
        String#dup for 39                0.000085   0.000646   0.207714 (  0.208041)
        String#dup + String#[]= for 39   0.000067   0.000379   0.499957 (  0.500514)
        String#dup + String#<< for 39    0.000069   0.000413   0.600205 (  0.600984)
        String#dup for 103               0.000068   0.000374   0.236938 (  0.237424)
        String#dup + String#[]= for 103  0.000063   0.000401   0.501791 (  0.502506)
        String#dup + String#<< for 103   0.000066   0.000395   0.600041 (  0.600870)
        String#dup for 231               0.000066   0.000370   0.281924 (  0.282409)
        String#dup + String#[]= for 231  0.000064   0.000355   0.574779 (  0.575599)
        String#dup + String#<< for 231   0.000070   0.000395   0.691011 (  0.691972)
        String#dup for 487               0.000070   0.000366   0.355631 (  0.356230)
        String#dup + String#[]= for 487  0.000067   0.000391   0.653774 (  0.654509)
        String#dup + String#<< for 487   0.000066   0.000359   0.891413 (  0.892607)
        String#dup for 999               0.000068   0.000394   0.527350 (  0.528033)
        String#dup + String#[]= for 999  0.000067   0.000378   0.786794 (  0.787682)
        String#dup + String#<< for 999   0.000063   0.000363   1.070604 (  1.071885)

    512

                                            user     system      total        real
        String#dup for 39                0.000083   0.000639   0.207305 (  0.207687)
        String#dup + String#[]= for 39   0.000067   0.000398   0.501968 (  0.502645)
        String#dup + String#<< for 39    0.000071   0.000414   0.586533 (  0.587365)
        String#dup for 103               0.000064   0.000397   0.222104 (  0.222600)
        String#dup + String#[]= for 103  0.000069   0.000389   0.483612 (  0.484240)
        String#dup + String#<< for 103   0.000069   0.000380   0.606659 (  0.607510)
        String#dup for 231               0.000067   0.000388   0.292563 (  0.293070)
        String#dup + String#[]= for 231  0.000064   0.000389   0.573774 (  0.574479)
        String#dup + String#<< for 231   0.000069   0.000413   0.739569 (  0.740614)
        String#dup for 487               0.000067   0.000419   0.370516 (  0.371072)
        String#dup + String#[]= for 487  0.000060   0.000337   0.676507 (  0.677282)
        String#dup + String#<< for 487   0.000074   0.000410   0.911670 (  0.916480)
        String#dup for 999               0.000069   0.000397   0.239633 (  0.240049)
        String#dup + String#[]= for 999  0.000066   0.000370   1.196397 (  1.198272)
        String#dup + String#<< for 999   0.000072   0.000396   1.683562 (  1.686244)

    256

                                            user     system      total        real
        String#dup for 39                0.000073   0.000588   0.198103 (  0.198485)
        String#dup + String#[]= for 39   0.000067   0.000397   0.475345 (  0.476011)
        String#dup + String#<< for 39    0.000074   0.000408   0.589001 (  0.589778)
        String#dup for 103               0.000073   0.000420   0.244381 (  0.244818)
        String#dup + String#[]= for 103  0.000065   0.000421   0.480720 (  0.481569)
        String#dup + String#<< for 103   0.000070   0.000414   0.589164 (  0.590123)
        String#dup for 231               0.000077   0.000447   0.272169 (  0.272640)
        String#dup + String#[]= for 231  0.000067   0.000425   0.517280 (  0.518037)
        String#dup + String#<< for 231   0.000064   0.000409   0.681593 (  0.682572)
        String#dup for 487               0.000065   0.000390   0.229708 (  0.230153)
        String#dup + String#[]= for 487  0.000067   0.000395   0.872966 (  0.874233)
        String#dup + String#<< for 487   0.000071   0.000411   1.317758 (  1.320085)
        String#dup for 999               0.000070   0.000397   0.255197 (  0.255609)
        String#dup + String#[]= for 999  0.000068   0.000380   1.174781 (  1.176700)
        String#dup + String#<< for 999   0.000067   0.000389   1.729608 (  1.738797)

    128

                                            user     system      total        real
        String#dup for 39                0.000105   0.000950   0.205384 (  0.206565)
        String#dup + String#[]= for 39   0.000066   0.000406   0.483924 (  0.485308)
        String#dup + String#<< for 39    0.000075   0.000433   0.590150 (  0.591641)
        String#dup for 103               0.000076   0.000414   0.225900 (  0.227975)
        String#dup + String#[]= for 103  0.000098   0.000604   0.499234 (  0.503926)
        String#dup + String#<< for 103   0.000070   0.000400   0.619562 (  0.627411)
        String#dup for 231               0.000073   0.000445   0.241433 (  0.243606)
        String#dup + String#[]= for 231  0.000067   0.000402   0.843665 (  0.853293)
        String#dup + String#<< for 231   0.000071   0.000392   0.990903 (  0.994555)
        String#dup for 487               0.000073   0.000403   0.234920 (  0.236132)
        String#dup + String#[]= for 487  0.000077   0.000445   0.944582 (  0.956001)
        String#dup + String#<< for 487   0.000069   0.000410   1.337099 (  1.341250)
        String#dup for 999               0.000072   0.000420   0.233520 (  0.234182)
        String#dup + String#[]= for 999  0.000072   0.000419   1.186288 (  1.188972)
        String#dup + String#<< for 999   0.000069   0.000436   1.685112 (  1.689536)
2026-07-28 10:57:57 -04:00
Peter Zhu eb9d72aea1 Max length for embedding duplicated strings
We should cap the max length for embedding duplicated strings because it
could be costly in performance and memory usage for very large embedded
strings. Instead, we can use a view into the parent string and perform
copy-on-write.
2026-07-26 14:55:18 -04: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
Peter Zhu c81174687a Change test_dump_includes_slot_size to work without GC.stat_heap 2026-07-08 03:38:35 -04:00
Hiroshi SHIBATAandClaude Opus 4.8 815692018c Remove obsolete Windows skip guards from core tests
These guards no longer match current mswin behavior. The affected tests
pass reliably on an x64-mswin64_140 build, repeatedly and under -j16 for
the flaky-history ones.

Only the mswin conditions are removed. test_ractor and test_transcode
keep their darwin and s390x guards. test_thread_queue keeps the MinGW
omit and drops only the retired AppVeyor branch. test_box re-enables
box_1 only, since box_2 still crashes at process exit under mswin and
stays pended.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 10:49:19 +09:00
Hiroshi SHIBATAandClaude Opus 4.8 a614959d42 Avoid timeout in test_dump_all_with_ractors
File.readlines slurps each Ractor's whole ~8MB dump into memory at once.
Because dump_all dumps the shared heap, the concurrent Ractors' readlines
buffers feed back into each other's dumps, so peak memory grows
superlinearly and the stop-the-world barrier thrashes past the 100s
timeout on macOS/M:N. File.foreach keeps peak memory flat (NR=16:
2.96GB -> 47MB) while still parsing every line.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 09:43:32 +09:00
John Hawthorn 45efffd756 Avoid timeout on object tracing test 2026-06-11 14:30:43 -07:00
John Hawthorn dd9213c41d Convert object_tracing to use weak references
Object tracing listens to the NEWOBJ hook to see all objects allocated
while it is active. Previously it also enabled a FREEOBJ tracepoint to
drop each object's record as the object was freed.

However the FREEOBJ tracepoint only fires while tracing is active. An
object recorded during tracing can be freed after tracing stops, and
that free was missed, leaving a stale record in object_table keyed by a
freed object. These dangling keys are unsafe during compaction, which
was previously mitigated with rb_gc_pointer_to_heap_p (which I'd like to
stop using). These dangling keys could also become incorrectly
associated with a new object allocated in its place.

Instead we can declare object_table's keys as weak references. The GC
then invokes our weak reference callback on every collection, whether or
not tracing is running, letting us reap the records of objects about to
be freed. This callback runs before the FREEOBJ hook, which makes the
FREEOBJ tracepoint unnecessary.
2026-06-05 10:56:16 -07: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
Matt Valentine-House aa5f1922cd Update tests for new pool layout 2026-04-09 13:24:09 +01:00
John Hawthorn 6721ec2612 Include free_immediately: false in heap dumps
This adds "free_immediately: false" to the heap dump for any T_DATA
which doesn't specify RUBY_TYPED_FREE_IMMEDIATELY. These are the objects
which end up as T_ZOMBIE and will have their dfree callback deferred to
later when the program is running holding the GVL.

This is useful to include because there is more overhead to freeing
these objects, and it's worth knowing how many there are.
2026-03-16 15:56:52 -07:00
Matt Valentine-House 208b173c25 Look up slot sizes for allocations in a table
Also remove BASE_SLOT_SIZE.
2026-03-09 15:09:53 +00:00
Hiroshi SHIBATA 3896dbc9ee Extend timeout for test_undefine_finalizer
https://ci.rvm.jp/results/trunk-yjit@ruby-sp2-noble-docker/6204308
2026-02-17 15:01:02 +09:00
Peter Zhu 40117ea04b Use Object for ObjectSpace.dump test
This test fails if BASE_SLOT_SIZE is 32 bytes because Strings occupy 40
bytes. Objects are smaller and would be 40 bytes.
2026-02-08 10:28:52 -05:00
Koichi Sasada 25422c0d07 use SIGSEGV on ractor timeout
to show C level backtrace for the following failure:

```
  1) Error:
TestObjSpaceRactor#test_undefine_finalizer:
Test::Unit::ProxyError: execution of Test::Unit::CoreAssertions#assert_separately expired timeout (10 sec)
pid 861177 killed by SIGTERM (signal 15)
|
    /tmp/ruby/src/trunk-yjit/test/objspace/test_ractor.rb:17:in 'TestObjSpaceRactor#test_undefine_finalizer'
```
2026-02-03 17:11:22 +09:00
Augustin Gottlieb 6ef0eb29c6 Add early type validation for ObjectSpace.memsize_of_all klass argument 2026-01-23 11:00:37 +09:00
Peter Zhu e8c61f5139 Remove ObjectSpace.count_nodes
ObjectSpace.count_nodes has been a no-op and returning an empty hash since
Ruby 2.5 because parser nodes are not GC managed.
2026-01-09 18:05:43 -05:00
Nobuyoshi Nakada e01e13c239 Use assert_ruby_status if no assertion 2026-01-09 17:16:22 +09:00
Luke Gruber 56b67f1684 ObjectSpace.{dump,dump_all,dump_shapes} needs vm barrier. (#15569)
This allows these methods to be called from ractors.

Add new exported function `rb_vm_lock_with_barrier()` that requires
users to include "vm_sync.h"
2025-12-17 12:17:30 -05:00
John Hawthorn de94f88c68 Register internal tracepoints globally
Internal tracepoints only make sense to run globally, and they already
took completely different paths.
2025-12-08 16:38:45 -08:00
Luke GruberandJohn Hawthorn 7ff036d59b Prevent GC from running during newobj_of for internal_event_newobj.
If another ractor is calling for GC, we need to prevent the current one
from joining the barrier. Otherwise, our half-built object will be marked.

The repro script was:

test.rb:
```ruby
require "objspace"
1000.times do
  ObjectSpace.trace_object_allocations do
    r = Ractor.new do
      _obj = 'a' * 1024
    end

    r.join
  end
end
```

$ untilfail lldb -b ./exe/ruby -o "target create ./exe/ruby" -o "run test.rb" -o continue

It would fail at `ractor_port_mark`, rp->r was a garbage value. Credit to John for finding the
solution.

Co-authored-by: John Hawthorn <john.hawthorn@shopify.com>
2025-09-18 13:52:37 -07:00
Peter Zhu df2f462acc Skip TestObjSpaceRactor#test_tracing_does_not_crash
It crashes frequently on CI but I am not able to reproduce locally:

https://ci.rvm.jp/results/trunk-random1@ruby-sp2-noble-docker/5954509
https://ci.rvm.jp/results/trunk-random0@ruby-sp2-noble-docker/5954501
2025-09-17 11:50:46 -04:00
Takashi Kokubun 5e8f9ea495 Increase timeout for a flaky test (#14233)
https://github.com/ruby/ruby/actions/runs/16977882022/job/48131284556
2025-08-14 23:41:01 +00: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
Jean Boussier a294427017 Add missing lock to rb_gc_impl_copy_finalizer 2025-05-16 20:16:52 +02:00
Jean Boussier ed632cd0ba Add missing lock in rb_gc_impl_undefine_finalizer
The table is global so accesses must be synchronized.
2025-05-15 13:32:08 +02:00
Yusuke Endoh 5cee3329df Skip test affected by TracePoint-dependent allocation_class_path
These assertions fail when TracePoint is enabled due to differing
allocation context. Commented out for now until behavior is fixed.

See [Bug #21298]
2025-05-01 17:21:36 +09:00
Aaron PattersonandJohn Hawthorn 8ac8225c50 Inline Class#new.
This commit inlines instructions for Class#new.  To make this work, we
added a new YARV instructions, `opt_new`.  `opt_new` checks whether or
not the `new` method is the default allocator method.  If it is, it
allocates the object, and pushes the instance on the stack.  If not, the
instruction jumps to the "slow path" method call instructions.

Old instructions:

```
> ruby --dump=insns -e'Object.new'
== disasm: #<ISeq:<main>@-e:1 (1,0)-(1,10)>
0000 opt_getconstant_path                   <ic:0 Object>             (   1)[Li]
0002 opt_send_without_block                 <calldata!mid:new, argc:0, ARGS_SIMPLE>
0004 leave
```

New instructions:

```
> ./miniruby --dump=insns -e'Object.new'
== disasm: #<ISeq:<main>@-e:1 (1,0)-(1,10)>
0000 opt_getconstant_path                   <ic:0 Object>             (   1)[Li]
0002 putnil
0003 swap
0004 opt_new                                <calldata!mid:new, argc:0, ARGS_SIMPLE>, 11
0007 opt_send_without_block                 <calldata!mid:initialize, argc:0, FCALL|ARGS_SIMPLE>
0009 jump                                   14
0011 opt_send_without_block                 <calldata!mid:new, argc:0, ARGS_SIMPLE>
0013 swap
0014 pop
0015 leave
```

This commit speeds up basic object allocation (`Foo.new`) by 60%, but
classes that take keyword parameters see an even bigger benefit because
no hash is allocated when instantiating the object (3x to 6x faster).

Here is an example that uses `Hash.new(capacity: 0)`:

```
> hyperfine "ruby --disable-gems -e'i = 0; while i < 10_000_000; Hash.new(capacity: 0); i += 1; end'" "./ruby --disable-gems -e'i = 0; while i < 10_000_000; Hash.new(capacity: 0); i += 1; end'"
Benchmark 1: ruby --disable-gems -e'i = 0; while i < 10_000_000; Hash.new(capacity: 0); i += 1; end'
  Time (mean ± σ):      1.082 s ±  0.004 s    [User: 1.074 s, System: 0.008 s]
  Range (min … max):    1.076 s …  1.088 s    10 runs

Benchmark 2: ./ruby --disable-gems -e'i = 0; while i < 10_000_000; Hash.new(capacity: 0); i += 1; end'
  Time (mean ± σ):     627.9 ms ±   3.5 ms    [User: 622.7 ms, System: 4.8 ms]
  Range (min … max):   622.7 ms … 633.2 ms    10 runs

Summary
  ./ruby --disable-gems -e'i = 0; while i < 10_000_000; Hash.new(capacity: 0); i += 1; end' ran
    1.72 ± 0.01 times faster than ruby --disable-gems -e'i = 0; while i < 10_000_000; Hash.new(capacity: 0); i += 1; end'
```

This commit changes the backtrace for `initialize`:

```
aaron@tc ~/g/ruby (inline-new)> cat test.rb
class Foo
  def initialize
    puts caller
  end
end

def hello
  Foo.new
end

hello
aaron@tc ~/g/ruby (inline-new)> ruby -v test.rb
ruby 3.4.2 (2025-02-15 revision d2930f8e7a) +PRISM [arm64-darwin24]
test.rb:8:in 'Class#new'
test.rb:8:in 'Object#hello'
test.rb:11:in '<main>'
aaron@tc ~/g/ruby (inline-new)> ./miniruby -v test.rb
ruby 3.5.0dev (2025-03-28T23:59:40Z inline-new c4157884e4) +PRISM [arm64-darwin24]
test.rb:8:in 'Object#hello'
test.rb:11:in '<main>'
```

It also increases memory usage for calls to `new` by 122 bytes:

```
aaron@tc ~/g/ruby (inline-new)> cat test.rb
require "objspace"

class Foo
  def initialize
    puts caller
  end
end

def hello
  Foo.new
end

puts ObjectSpace.memsize_of(RubyVM::InstructionSequence.of(method(:hello)))
aaron@tc ~/g/ruby (inline-new)> make runruby
RUBY_ON_BUG='gdb -x ./.gdbinit -p' ./miniruby -I./lib -I. -I.ext/common  ./tool/runruby.rb --extout=.ext  -- --disable-gems  ./test.rb
656
aaron@tc ~/g/ruby (inline-new)> ruby -v test.rb
ruby 3.4.2 (2025-02-15 revision d2930f8e7a) +PRISM [arm64-darwin24]
544
```

Thanks to @ko1 for coming up with this idea!

Co-Authored-By: John Hawthorn <john@hawthorn.email>
2025-04-25 13:46:05 -07:00
Jean Boussier cb1ea54bbf objspace_dump: Include shareable flag
Given that the currently planned ractor local GC implementation
performance will heavilly be influenced by the number of shareable
objects it would be valuable to be able to know how many of them
are in the heap.
2025-04-24 10:14:29 +02:00
Jean Boussier ca4325f6c9 Harden TestObjSpace#test_memsize_of_root_shared_string
This test occasionally fail because it runs into a String instance
that had its `==` method removed.

I couldn't identify where this String comes from, but in general
when using `each_object` it's best to not assume returned objectd
are functional.

By just inverting the operands of `==` we ensure it's always
`String#==` that is called.

```
  1) Error:
TestObjSpace#test_memsize_of_root_shared_string:
NoMethodError: undefined method '==' for #<String:0x00007f9b50e8c978>
    /tmp/ruby/src/trunk-random1/test/objspace/test_objspace.rb:35:in 'block in TestObjSpace#test_memsize_of_root_shared_string'
    /tmp/ruby/src/trunk-random1/test/objspace/test_objspace.rb:35:in 'ObjectSpace.each_object'
    /tmp/ruby/src/trunk-random1/test/objspace/test_objspace.rb:35:in 'TestObjSpace#test_memsize_of_root_shared_string'
```
2025-03-06 08:42:01 +01:00
Peter Zhu 5e45f2a0bc Add age to rb_gc_object_metadata
This will allow ObjectSpace.dump to output the age of the object.
2025-02-19 09:47:28 -05:00
Peter Zhu d729c1575e Output object_id in ObjectSpace.dump
Outputs the object ID in the dump for objects that have it seen.
2025-01-30 11:48:14 -05:00
Peter Zhu 516a6cd1ad Check whether object is valid in allocation_info_tracer_compact
When reference updating ObjectSpace.trace_object_allocations, we need to
check whether the object is valid or not because it does not mark the
object so the object may be dead. This can cause a segmentation fault
if the object is on a free heap page.

For example, the following script crashes:

    require "objspace"

    objs = []
    ObjectSpace.trace_object_allocations do
      1_000_000.times do
        objs << Object.new
      end
    end

    objs = nil

    # Free pages that the objs were on
    GC.start

    # Run compaction and check that it doesn't crash
    GC.compact
2024-12-16 12:24:24 -05:00
Peter Zhu 15765eac0a Fix ObjectSpace.trace_object_allocations for compaction
We need to reinsert into the ST table when an object moves because it is
a numtable that hashes on the object address, so when an object moves we
need to reinsert it rather than just updating the key.
2024-12-16 10:12:54 -05:00
Jean Boussier ee1cd1656f ObjectSpace.dump: handle Module#set_temporary_name
[Bug #20892]

Until the introduction of that method, it was impossible for a
Module name not to be valid JSON, hence it wasn't going through
the slower escaping function.

This assumption no longer hold.
2024-11-12 20:21:27 +01:00
Peter Zhu 0160dafc4c Replace all GC.disable with EnvUtil.without_gc 2024-09-17 10:34:26 -04:00
Peter Zhu 51bd816517 [Feature #20470] Split GC into gc_impl.c
This commit splits gc.c into two files:

- gc.c now only contains code not specific to Ruby GC. This includes
  code to mark objects (which the GC implementation may choose not to
  use) and wrappers for internal APIs that the implementation may need
  to use (e.g. locking the VM).

- gc_impl.c now contains the implementation of Ruby's GC. This includes
  marking, sweeping, compaction, and statistics. Most importantly,
  gc_impl.c only uses public APIs in Ruby and a limited set of functions
  exposed in gc.c. This allows us to build gc_impl.c independently of
  Ruby and plug Ruby's GC into itself.
2024-07-03 09:03:40 -04:00
Jean Boussier e82138e48a Stabilize TestObjSpace#test_dump_special_consts
The test assumes `:foo` is a static symbol, but that is only true
if a literal `:foo` was parsed before `"foo".to_sym` was evaled:

```ruby
require 'objspace'
foo_sym = "foo".to_sym
puts ObjectSpace.dump(eval(":foo"))
```

```
{"address":"0x100fb46d0", "type":"SYMBOL", "shape_id":10, "slot_size":40, "class":"0x100d3e9c8", "frozen":true, "bytesize":3, "value":"foo", "memsize":40, "flags":{"wb_protected":true, "marking":true, "marked":true}}
```
2024-05-09 12:23:34 +02:00
Nobuyoshi Nakada 91485d7dc6 Adjust indent [ci skip] 2024-05-04 01:15:09 +09:00
Jean Boussier 09d8c99cdc Ensure test suite is compatible with --frozen-string-literal
As preparation for https://bugs.ruby-lang.org/issues/20205
making sure the test suite is compatible with frozen string
literals is making things easier.
2024-03-14 17:56:15 +01:00
Takashi Kokubun 1721bb9dc6 Skip a flaky objspace test on Visual Studio
This seems to happen only on VisualStudio:
https://github.com/ruby/ruby/actions/runs/7130917319/job/19418375386

It fails relatively frequently. Nobody seems actively working on it, so
let's skip it until somebody starts working on it.
2023-12-07 09:42:56 -08:00
Jean Boussier 6391ae9ebc objspace_dump.c: dump call cache ids with dump_append_id
Not all `ID` have an associated string.

Fixes a SEGFAULT in ObjectSpace.dump_all spec.
2023-11-22 10:24:35 +01:00