<feed xmlns='http://www.w3.org/2005/Atom'>
<title>ruby.git/test/objspace/test_objspace.rb, branch v4.0.2</title>
<subtitle>The Ruby Programming Language</subtitle>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/'/>
<entry>
<title>ObjectSpace.{dump,dump_all,dump_shapes} needs vm barrier. (#15569)</title>
<updated>2025-12-17T17:17:30+00:00</updated>
<author>
<name>Luke Gruber</name>
<email>luke.gruber@shopify.com</email>
</author>
<published>2025-12-17T17:17:30+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=56b67f1684bf1955cf69fc06701e2a710898bd9b'/>
<id>56b67f1684bf1955cf69fc06701e2a710898bd9b</id>
<content type='text'>
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"</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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"</pre>
</div>
</content>
</entry>
<entry>
<title>Register internal tracepoints globally</title>
<updated>2025-12-09T00:38:45+00:00</updated>
<author>
<name>John Hawthorn</name>
<email>john@hawthorn.email</email>
</author>
<published>2025-12-03T08:06:03+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=de94f88c6820c94b69df3343c6050cdb8cc0610e'/>
<id>de94f88c6820c94b69df3343c6050cdb8cc0610e</id>
<content type='text'>
Internal tracepoints only make sense to run globally, and they already
took completely different paths.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Internal tracepoints only make sense to run globally, and they already
took completely different paths.
</pre>
</div>
</content>
</entry>
<entry>
<title>Increase timeout for a flaky test (#14233)</title>
<updated>2025-08-14T23:41:01+00:00</updated>
<author>
<name>Takashi Kokubun</name>
<email>takashi.kokubun@shopify.com</email>
</author>
<published>2025-08-14T23:41:01+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=5e8f9ea4953af1737a477613aa31e72ca81031c6'/>
<id>5e8f9ea4953af1737a477613aa31e72ca81031c6</id>
<content type='text'>
https://github.com/ruby/ruby/actions/runs/16977882022/job/48131284556</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
https://github.com/ruby/ruby/actions/runs/16977882022/job/48131284556</pre>
</div>
</content>
</entry>
<entry>
<title>Skip test affected by TracePoint-dependent allocation_class_path</title>
<updated>2025-05-01T08:21:36+00:00</updated>
<author>
<name>Yusuke Endoh</name>
<email>mame@ruby-lang.org</email>
</author>
<published>2025-05-01T07:50:46+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=5cee3329df2963667d958cc7bb091f77ae9172aa'/>
<id>5cee3329df2963667d958cc7bb091f77ae9172aa</id>
<content type='text'>
These assertions fail when TracePoint is enabled due to differing
allocation context. Commented out for now until behavior is fixed.

See [Bug #21298]
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
These assertions fail when TracePoint is enabled due to differing
allocation context. Commented out for now until behavior is fixed.

See [Bug #21298]
</pre>
</div>
</content>
</entry>
<entry>
<title>Inline Class#new.</title>
<updated>2025-04-25T20:46:05+00:00</updated>
<author>
<name>Aaron Patterson</name>
<email>tenderlove@ruby-lang.org</email>
</author>
<published>2025-03-17T23:59:19+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=8ac8225c504dee57454131e7cde2c47126596fdc'/>
<id>8ac8225c504dee57454131e7cde2c47126596fdc</id>
<content type='text'>
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:

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

New instructions:

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

```
&gt; hyperfine "ruby --disable-gems -e'i = 0; while i &lt; 10_000_000; Hash.new(capacity: 0); i += 1; end'" "./ruby --disable-gems -e'i = 0; while i &lt; 10_000_000; Hash.new(capacity: 0); i += 1; end'"
Benchmark 1: ruby --disable-gems -e'i = 0; while i &lt; 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 &lt; 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 &lt; 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 &lt; 10_000_000; Hash.new(capacity: 0); i += 1; end'
```

This commit changes the backtrace for `initialize`:

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

def hello
  Foo.new
end

hello
aaron@tc ~/g/ruby (inline-new)&gt; 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 '&lt;main&gt;'
aaron@tc ~/g/ruby (inline-new)&gt; ./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 '&lt;main&gt;'
```

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

```
aaron@tc ~/g/ruby (inline-new)&gt; 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)&gt; 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)&gt; 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 &lt;john@hawthorn.email&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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:

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

New instructions:

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

```
&gt; hyperfine "ruby --disable-gems -e'i = 0; while i &lt; 10_000_000; Hash.new(capacity: 0); i += 1; end'" "./ruby --disable-gems -e'i = 0; while i &lt; 10_000_000; Hash.new(capacity: 0); i += 1; end'"
Benchmark 1: ruby --disable-gems -e'i = 0; while i &lt; 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 &lt; 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 &lt; 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 &lt; 10_000_000; Hash.new(capacity: 0); i += 1; end'
```

This commit changes the backtrace for `initialize`:

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

def hello
  Foo.new
end

hello
aaron@tc ~/g/ruby (inline-new)&gt; 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 '&lt;main&gt;'
aaron@tc ~/g/ruby (inline-new)&gt; ./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 '&lt;main&gt;'
```

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

```
aaron@tc ~/g/ruby (inline-new)&gt; 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)&gt; 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)&gt; 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 &lt;john@hawthorn.email&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>objspace_dump: Include `shareable` flag</title>
<updated>2025-04-24T08:14:29+00:00</updated>
<author>
<name>Jean Boussier</name>
<email>jean.boussier@gmail.com</email>
</author>
<published>2025-04-21T01:21:55+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=cb1ea54bbf6cdf49c53f42720fec1a151069810c'/>
<id>cb1ea54bbf6cdf49c53f42720fec1a151069810c</id>
<content type='text'>
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.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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.
</pre>
</div>
</content>
</entry>
<entry>
<title>Harden `TestObjSpace#test_memsize_of_root_shared_string`</title>
<updated>2025-03-06T07:42:01+00:00</updated>
<author>
<name>Jean Boussier</name>
<email>jean.boussier@gmail.com</email>
</author>
<published>2025-03-06T07:09:57+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=ca4325f6c9710ae5dcda9f735b264ba92bffb68f'/>
<id>ca4325f6c9710ae5dcda9f735b264ba92bffb68f</id>
<content type='text'>
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 #&lt;String:0x00007f9b50e8c978&gt;
    /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'
```
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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 #&lt;String:0x00007f9b50e8c978&gt;
    /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'
```
</pre>
</div>
</content>
</entry>
<entry>
<title>Add age to rb_gc_object_metadata</title>
<updated>2025-02-19T14:47:28+00:00</updated>
<author>
<name>Peter Zhu</name>
<email>peter@peterzhu.ca</email>
</author>
<published>2025-02-18T18:45:27+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=5e45f2a0bce9a94b1b5f9eda615344e74a39e597'/>
<id>5e45f2a0bce9a94b1b5f9eda615344e74a39e597</id>
<content type='text'>
This will allow ObjectSpace.dump to output the age of the object.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
This will allow ObjectSpace.dump to output the age of the object.
</pre>
</div>
</content>
</entry>
<entry>
<title>Output object_id in ObjectSpace.dump</title>
<updated>2025-01-30T16:48:14+00:00</updated>
<author>
<name>Peter Zhu</name>
<email>peter@peterzhu.ca</email>
</author>
<published>2025-01-28T15:15:27+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=d729c1575e794bb9dafd1f7fcb0740735537504a'/>
<id>d729c1575e794bb9dafd1f7fcb0740735537504a</id>
<content type='text'>
Outputs the object ID in the dump for objects that have it seen.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Outputs the object ID in the dump for objects that have it seen.
</pre>
</div>
</content>
</entry>
<entry>
<title>Check whether object is valid in allocation_info_tracer_compact</title>
<updated>2024-12-16T17:24:24+00:00</updated>
<author>
<name>Peter Zhu</name>
<email>peter@peterzhu.ca</email>
</author>
<published>2024-12-16T16:41:41+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=516a6cd1ad620b880651c1333bd856a9d7dec3c4'/>
<id>516a6cd1ad620b880651c1333bd856a9d7dec3c4</id>
<content type='text'>
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 &lt;&lt; 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
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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 &lt;&lt; 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
</pre>
</div>
</content>
</entry>
</feed>
