<feed xmlns='http://www.w3.org/2005/Atom'>
<title>ruby.git/test/ruby/test_shapes.rb, branch v3_2_11</title>
<subtitle>The Ruby Programming Language</subtitle>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/'/>
<entry>
<title>merge revision(s) 82b57d7bfeefd717c10f7a5a3484aca6b3e708a3: [Backport #20162]</title>
<updated>2024-07-07T07:46:02+00:00</updated>
<author>
<name>nagachika</name>
<email>nagachika@ruby-lang.org</email>
</author>
<published>2024-07-07T05:42:08+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=c97a632363a170879b9755c5a123e92533908039'/>
<id>c97a632363a170879b9755c5a123e92533908039</id>
<content type='text'>
	Fix memory leak when duplicating too complex object

	[Bug #20162]

	Creating a ST table then calling st_replace leaks memory because the
	st_replace overwrites the ST table without freeing any of the existing
	memory. This commit changes it to use st_copy instead.

	For example:

	    RubyVM::Shape.exhaust_shapes

	    o = Object.new
	    o.instance_variable_set(:@a, 0)

	    10.times do
	      100_000.times { o.dup }

	      puts `ps -o rss= -p #{$$}`
	    end

	Before:

	    23264
	    33600
	    42672
	    52160
	    61600
	    71728
	    81056
	    90528
	    100560
	    109840

	After:

	    14752
	    14816
	    15584
	    15584
	    15664
	    15664
	    15664
	    15664
	    15664
	    15664
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
	Fix memory leak when duplicating too complex object

	[Bug #20162]

	Creating a ST table then calling st_replace leaks memory because the
	st_replace overwrites the ST table without freeing any of the existing
	memory. This commit changes it to use st_copy instead.

	For example:

	    RubyVM::Shape.exhaust_shapes

	    o = Object.new
	    o.instance_variable_set(:@a, 0)

	    10.times do
	      100_000.times { o.dup }

	      puts `ps -o rss= -p #{$$}`
	    end

	Before:

	    23264
	    33600
	    42672
	    52160
	    61600
	    71728
	    81056
	    90528
	    100560
	    109840

	After:

	    14752
	    14816
	    15584
	    15584
	    15664
	    15664
	    15664
	    15664
	    15664
	    15664
</pre>
</div>
</content>
</entry>
<entry>
<title>merge revision(s) 54dbd8bea8a79bfcdefa471c1717c6cd28022f33: [Backport #19535]</title>
<updated>2023-07-22T04:24:55+00:00</updated>
<author>
<name>nagachika</name>
<email>nagachika@ruby-lang.org</email>
</author>
<published>2023-07-22T04:24:55+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=fa72ba72f8c64fd0fa87c8f68cbc31f2e7b94b00'/>
<id>fa72ba72f8c64fd0fa87c8f68cbc31f2e7b94b00</id>
<content type='text'>
	Use an st table for "too complex" objects

	st tables will maintain insertion order so we can marshal dump / load
	objects with instance variables in the same order they were set on that
	particular instance

	[ruby-core:112926] [Bug #19535]

	Co-Authored-By: Jemma Issroff &lt;jemmaissroff@gmail.com&gt;
	---
	 gc.c                     | 10 ++++------
	 include/ruby/st.h        |  2 ++
	 object.c                 |  2 +-
	 ractor.c                 | 43 ++++++++++++++++++++++---------------------
	 shape.h                  |  6 +++---
	 st.c                     |  6 ++++++
	 test/ruby/test_shapes.rb | 21 +++++++++++++++++++++
	 variable.c               | 28 ++++++++++++++--------------
	 vm_insnhelper.c          |  2 +-
	 9 files changed, 74 insertions(+), 46 deletions(-)
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
	Use an st table for "too complex" objects

	st tables will maintain insertion order so we can marshal dump / load
	objects with instance variables in the same order they were set on that
	particular instance

	[ruby-core:112926] [Bug #19535]

	Co-Authored-By: Jemma Issroff &lt;jemmaissroff@gmail.com&gt;
	---
	 gc.c                     | 10 ++++------
	 include/ruby/st.h        |  2 ++
	 object.c                 |  2 +-
	 ractor.c                 | 43 ++++++++++++++++++++++---------------------
	 shape.h                  |  6 +++---
	 st.c                     |  6 ++++++
	 test/ruby/test_shapes.rb | 21 +++++++++++++++++++++
	 variable.c               | 28 ++++++++++++++--------------
	 vm_insnhelper.c          |  2 +-
	 9 files changed, 74 insertions(+), 46 deletions(-)
</pre>
</div>
</content>
</entry>
<entry>
<title>Prevent warning "assigned but unused variable - initial_shape"</title>
<updated>2022-12-16T23:40:36+00:00</updated>
<author>
<name>Yusuke Endoh</name>
<email>mame@ruby-lang.org</email>
</author>
<published>2022-12-16T23:40:36+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=2013dd465811b6d01129f25af4fbe84002a2273f'/>
<id>2013dd465811b6d01129f25af4fbe84002a2273f</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>Clean up Ruby Shape API</title>
<updated>2022-12-16T18:27:45+00:00</updated>
<author>
<name>Jemma Issroff</name>
<email>jemmaissroff@gmail.com</email>
</author>
<published>2022-12-15T21:38:53+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=297df9240772a14141988aef63400e3988584ced'/>
<id>297df9240772a14141988aef63400e3988584ced</id>
<content type='text'>
Make printing shapes better, use a struct instead of specific methods
for each field on a shape.

Co-Authored-By: Aaron Patterson &lt;tenderlove@ruby-lang.org&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Make printing shapes better, use a struct instead of specific methods
for each field on a shape.

Co-Authored-By: Aaron Patterson &lt;tenderlove@ruby-lang.org&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Transition complex objects to "too complex" shape</title>
<updated>2022-12-15T18:06:04+00:00</updated>
<author>
<name>Jemma Issroff</name>
<email>jemmaissroff@gmail.com</email>
</author>
<published>2022-12-08T22:16:52+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=c1ab6ddc9a6fa228caa5d26b118b54855051279c'/>
<id>c1ab6ddc9a6fa228caa5d26b118b54855051279c</id>
<content type='text'>
When an object becomes "too complex" (in other words it has too many
variations in the shape tree), we transition it to use a "too complex"
shape and use a hash for storing instance variables.

Without this patch, there were rare cases where shape tree growth could
"explode" and cause performance degradation on what would otherwise have
been cached fast paths.

This patch puts a limit on shape tree growth, and gracefully degrades in
the rare case where there could be a factorial growth in the shape tree.

For example:

```ruby
class NG; end

HUGE_NUMBER.times do
  NG.new.instance_variable_set(:"@unique_ivar_#{_1}", 1)
end
```

We consider objects to be "too complex" when the object's class has more
than SHAPE_MAX_VARIATIONS (currently 8) leaf nodes in the shape tree and
the object introduces a new variation (a new leaf node) associated with
that class.

For example, new variations on instances of the following class would be
considered "too complex" because those instances create more than 8
leaves in the shape tree:

```ruby
class Foo; end
9.times { Foo.new.instance_variable_set(":@uniq_#{_1}", 1) }
```

However, the following class is *not* too complex because it only has
one leaf in the shape tree:

```ruby
class Foo
  def initialize
    @a = @b = @c = @d = @e = @f = @g = @h = @i = nil
  end
end
9.times { Foo.new }
``

This case is rare, so we don't expect this change to impact performance
of most applications, but it needs to be handled.

Co-Authored-By: Aaron Patterson &lt;tenderlove@ruby-lang.org&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
When an object becomes "too complex" (in other words it has too many
variations in the shape tree), we transition it to use a "too complex"
shape and use a hash for storing instance variables.

Without this patch, there were rare cases where shape tree growth could
"explode" and cause performance degradation on what would otherwise have
been cached fast paths.

This patch puts a limit on shape tree growth, and gracefully degrades in
the rare case where there could be a factorial growth in the shape tree.

For example:

```ruby
class NG; end

HUGE_NUMBER.times do
  NG.new.instance_variable_set(:"@unique_ivar_#{_1}", 1)
end
```

We consider objects to be "too complex" when the object's class has more
than SHAPE_MAX_VARIATIONS (currently 8) leaf nodes in the shape tree and
the object introduces a new variation (a new leaf node) associated with
that class.

For example, new variations on instances of the following class would be
considered "too complex" because those instances create more than 8
leaves in the shape tree:

```ruby
class Foo; end
9.times { Foo.new.instance_variable_set(":@uniq_#{_1}", 1) }
```

However, the following class is *not* too complex because it only has
one leaf in the shape tree:

```ruby
class Foo
  def initialize
    @a = @b = @c = @d = @e = @f = @g = @h = @i = nil
  end
end
9.times { Foo.new }
``

This case is rare, so we don't expect this change to impact performance
of most applications, but it needs to be handled.

Co-Authored-By: Aaron Patterson &lt;tenderlove@ruby-lang.org&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Stop transitioning to UNDEF when undefining an instance variable</title>
<updated>2022-12-07T17:57:11+00:00</updated>
<author>
<name>Aaron Patterson</name>
<email>tenderlove@ruby-lang.org</email>
</author>
<published>2022-12-06T00:48:47+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=edc7af48acd12666a2945f30901d16b62a39f474'/>
<id>edc7af48acd12666a2945f30901d16b62a39f474</id>
<content type='text'>
Cases like this:

```ruby
obj = Object.new
loop do
  obj.instance_variable_set(:@foo, 1)
  obj.remove_instance_variable(:@foo)
end
```

can cause us to use many more shapes than we want (and even run out).
This commit changes the code such that when an instance variable is
removed, we'll walk up the shape tree, find the shape, then rebuild any
child nodes that happened to be below the "targetted for removal" IV.

This also requires moving any instance variables so that indexes derived
from the shape tree will work correctly.

Co-Authored-By: Jemma Issroff &lt;jemmaissroff@gmail.com&gt;
Co-authored-by: John Hawthorn &lt;jhawthorn@github.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Cases like this:

```ruby
obj = Object.new
loop do
  obj.instance_variable_set(:@foo, 1)
  obj.remove_instance_variable(:@foo)
end
```

can cause us to use many more shapes than we want (and even run out).
This commit changes the code such that when an instance variable is
removed, we'll walk up the shape tree, find the shape, then rebuild any
child nodes that happened to be below the "targetted for removal" IV.

This also requires moving any instance variables so that indexes derived
from the shape tree will work correctly.

Co-Authored-By: Jemma Issroff &lt;jemmaissroff@gmail.com&gt;
Co-authored-by: John Hawthorn &lt;jhawthorn@github.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Differentiate T_OBJECT shapes from other objects</title>
<updated>2022-11-18T16:31:56+00:00</updated>
<author>
<name>Aaron Patterson</name>
<email>tenderlove@ruby-lang.org</email>
</author>
<published>2022-11-17T23:57:11+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=10788166e7e568fdcd0b748e8d5dab442dcdc7ef'/>
<id>10788166e7e568fdcd0b748e8d5dab442dcdc7ef</id>
<content type='text'>
We would like to differentiate types of objects via their shape.  This
commit adds a special T_OBJECT shape when we allocate an instance of
T_OBJECT.  This allows us to avoid testing whether an object is an
instance of a T_OBJECT or not, we can just check the shape.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
We would like to differentiate types of objects via their shape.  This
commit adds a special T_OBJECT shape when we allocate an instance of
T_OBJECT.  This allows us to avoid testing whether an object is an
instance of a T_OBJECT or not, we can just check the shape.
</pre>
</div>
</content>
</entry>
<entry>
<title>Transition shape when object's capacity changes</title>
<updated>2022-11-10T15:11:34+00:00</updated>
<author>
<name>Jemma Issroff</name>
<email>jemmaissroff@gmail.com</email>
</author>
<published>2022-11-08T20:35:31+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=5246f4027ec574e77809845e1b1f7822cc2a5cef'/>
<id>5246f4027ec574e77809845e1b1f7822cc2a5cef</id>
<content type='text'>
This commit adds a `capacity` field to shapes, and adds shape
transitions whenever an object's capacity changes. Objects which are
allocated out of a bigger size pool will also make a transition from the
root shape to the shape with the correct capacity for their size pool
when they are allocated.

This commit will allow us to remove numiv from objects completely, and
will also mean we can guarantee that if two objects share shapes, their
IVs are in the same positions (an embedded and extended object cannot
share shapes). This will enable us to implement ivar sets in YJIT using
object shapes.

Co-Authored-By: Aaron Patterson &lt;tenderlove@ruby-lang.org&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
This commit adds a `capacity` field to shapes, and adds shape
transitions whenever an object's capacity changes. Objects which are
allocated out of a bigger size pool will also make a transition from the
root shape to the shape with the correct capacity for their size pool
when they are allocated.

This commit will allow us to remove numiv from objects completely, and
will also mean we can guarantee that if two objects share shapes, their
IVs are in the same positions (an embedded and extended object cannot
share shapes). This will enable us to implement ivar sets in YJIT using
object shapes.

Co-Authored-By: Aaron Patterson &lt;tenderlove@ruby-lang.org&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Rename `iv_count` on shapes to `next_iv_index`</title>
<updated>2022-10-21T21:57:34+00:00</updated>
<author>
<name>Jemma Issroff</name>
<email>jemmaissroff@gmail.com</email>
</author>
<published>2022-10-21T20:24:29+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=a11952dac1a5b0776a493968eeffbd4be4403b76'/>
<id>a11952dac1a5b0776a493968eeffbd4be4403b76</id>
<content type='text'>
`iv_count` is a misleading name because when IVs are unset, the new
shape doesn't decrement this value. `next_iv_count` is an accurate, and
more descriptive name.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
`iv_count` is a misleading name because when IVs are unset, the new
shape doesn't decrement this value. `next_iv_count` is an accurate, and
more descriptive name.
</pre>
</div>
</content>
</entry>
<entry>
<title>Add a test for transition order</title>
<updated>2022-10-14T19:01:42+00:00</updated>
<author>
<name>Aaron Patterson</name>
<email>tenderlove@ruby-lang.org</email>
</author>
<published>2022-10-14T18:59:31+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=cbd3d655745564e3c33a29a5625ac30b4d69fb29'/>
<id>cbd3d655745564e3c33a29a5625ac30b4d69fb29</id>
<content type='text'>
We only cache the destination shape id, but that can lead to false cache
hits.  This patch tests that we correctly handle false cache hits
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
We only cache the destination shape id, but that can lead to false cache
hits.  This patch tests that we correctly handle false cache hits
</pre>
</div>
</content>
</entry>
</feed>
