<feed xmlns='http://www.w3.org/2005/Atom'>
<title>ruby.git/shape.c, 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) cb22d78354e201ca74eba68a8b4edefb593e6754: [Backport #19536]</title>
<updated>2023-03-22T23:11:23+00:00</updated>
<author>
<name>NARUSE, Yui</name>
<email>naruse@airemix.jp</email>
</author>
<published>2023-03-22T23:11:23+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=400ccb16eefe4e21c4e3eacab4fd0f208fc5e151'/>
<id>400ccb16eefe4e21c4e3eacab4fd0f208fc5e151</id>
<content type='text'>
	Fix frozen status loss when moving objects

	[Bug #19536]

	When objects are moved between size pools, their frozen status is lost
	in the shape. This will cause the frozen check to be bypassed when there
	is an inline cache. For example, the following script should raise a
	FrozenError, but doesn't on Ruby 3.2 and master.

	    class A
	      def add_ivars
	        @a = @b = @c = @d = 1
	      end

	      def set_a
	        @a = 10
	      end
	    end

	    a = A.new
	    a.add_ivars
	    a.freeze

	    b = A.new
	    b.add_ivars
	    b.set_a # Set the inline cache in set_a

	    GC.verify_compaction_references(expand_heap: true, toward: :empty)

	    a.set_a
	---
	 shape.c                      |  2 +-
	 test/ruby/test_gc_compact.rb | 28 ++++++++++++++++++++++++++++
	 2 files changed, 29 insertions(+), 1 deletion(-)
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
	Fix frozen status loss when moving objects

	[Bug #19536]

	When objects are moved between size pools, their frozen status is lost
	in the shape. This will cause the frozen check to be bypassed when there
	is an inline cache. For example, the following script should raise a
	FrozenError, but doesn't on Ruby 3.2 and master.

	    class A
	      def add_ivars
	        @a = @b = @c = @d = 1
	      end

	      def set_a
	        @a = 10
	      end
	    end

	    a = A.new
	    a.add_ivars
	    a.freeze

	    b = A.new
	    b.add_ivars
	    b.set_a # Set the inline cache in set_a

	    GC.verify_compaction_references(expand_heap: true, toward: :empty)

	    a.set_a
	---
	 shape.c                      |  2 +-
	 test/ruby/test_gc_compact.rb | 28 ++++++++++++++++++++++++++++
	 2 files changed, 29 insertions(+), 1 deletion(-)
</pre>
</div>
</content>
</entry>
<entry>
<title>merge revision(s) 273dca3aed7989120d57f80c789733d4bc870ffe: [Backport #19248]</title>
<updated>2023-01-19T00:31:47+00:00</updated>
<author>
<name>NARUSE, Yui</name>
<email>naruse@airemix.jp</email>
</author>
<published>2023-01-19T00:31:47+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=08ae7f64dc52c2b61e451d6e79ebdae73d482677'/>
<id>08ae7f64dc52c2b61e451d6e79ebdae73d482677</id>
<content type='text'>
	Fix undefined behavior in shape.c

	Under strict aliasing, writing to the memory location of a different
	type is not allowed and will result in undefined behavior. This was
	happening in shape.c due to `rb_id_table_lookup` writing to the memory
	location of `VALUE *` that was casted from a `rb_shape_t **`.

	This was causing test failures when compiled with LTO.

	Fixes [Bug #19248]

	Co-Authored-By: Alan Wu &lt;alanwu@ruby-lang.org&gt;
	---
	 shape.c | 13 +++++++++++--
	 1 file changed, 11 insertions(+), 2 deletions(-)
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
	Fix undefined behavior in shape.c

	Under strict aliasing, writing to the memory location of a different
	type is not allowed and will result in undefined behavior. This was
	happening in shape.c due to `rb_id_table_lookup` writing to the memory
	location of `VALUE *` that was casted from a `rb_shape_t **`.

	This was causing test failures when compiled with LTO.

	Fixes [Bug #19248]

	Co-Authored-By: Alan Wu &lt;alanwu@ruby-lang.org&gt;
	---
	 shape.c | 13 +++++++++++--
	 1 file changed, 11 insertions(+), 2 deletions(-)
</pre>
</div>
</content>
</entry>
<entry>
<title>Hide RubyVM::Shape's interface as much as possible [ci skip]</title>
<updated>2022-12-22T23:06:37+00:00</updated>
<author>
<name>Takashi Kokubun</name>
<email>takashikkbn@gmail.com</email>
</author>
<published>2022-12-22T23:03:40+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=c566c968f96ba02e7e775c88b5cbb150fb3839e9'/>
<id>c566c968f96ba02e7e775c88b5cbb150fb3839e9</id>
<content type='text'>
RubyVM::Shape is usually not available (you need SHAPE_DEBUG macro,
which is not defined by default). So it seems confusing to leave
RubyVM::Shape in the document.

This hides only method definitions because, well, I can't find a way to
hide things defined by rb_define_const or rb_struct_define_under. I gave
up making the C-based documentation right. You should define things in
Ruby instead.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
RubyVM::Shape is usually not available (you need SHAPE_DEBUG macro,
which is not defined by default). So it seems confusing to leave
RubyVM::Shape in the document.

This hides only method definitions because, well, I can't find a way to
hide things defined by rb_define_const or rb_struct_define_under. I gave
up making the C-based documentation right. You should define things in
Ruby instead.
</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>Fix Object Movement allocation in GC</title>
<updated>2022-12-15T20:27:38+00:00</updated>
<author>
<name>Matt Valentine-House</name>
<email>matt@eightbitraptor.com</email>
</author>
<published>2022-12-13T15:11:57+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=bfc66e07b7e0134dfa2041c311dc56941fe1caf0'/>
<id>bfc66e07b7e0134dfa2041c311dc56941fe1caf0</id>
<content type='text'>
When moving Objects between size pools we have to assign a new shape.

This happened during updating references - we tried to create a new shape
tree that mirrored the existing tree, but based on the root shape of the
new size pool.

This causes allocations to happen if the new tree doesn't already exist,
potentially triggering a GC, during GC.

This commit changes object movement to look for a pre-existing new tree
during object movement, and if that tree does not exist, we don't move
the object to the new pool.

This allows us to remove the shape allocation from update references.

Co-Authored-By: Peter Zhu &lt;peter@peterzhu.ca&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
When moving Objects between size pools we have to assign a new shape.

This happened during updating references - we tried to create a new shape
tree that mirrored the existing tree, but based on the root shape of the
new size pool.

This causes allocations to happen if the new tree doesn't already exist,
potentially triggering a GC, during GC.

This commit changes object movement to look for a pre-existing new tree
during object movement, and if that tree does not exist, we don't move
the object to the new pool.

This allows us to remove the shape allocation from update references.

Co-Authored-By: Peter Zhu &lt;peter@peterzhu.ca&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>Add variation_count on classes</title>
<updated>2022-12-15T18:06:04+00:00</updated>
<author>
<name>Jemma Issroff</name>
<email>jemmaissroff@gmail.com</email>
</author>
<published>2022-12-08T21:48:48+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=a3d552aedd190b0f21a4f6479f0ef1d2ce90189b'/>
<id>a3d552aedd190b0f21a4f6479f0ef1d2ce90189b</id>
<content type='text'>
Count how many "variations" each class creates. A "variation" is a a
unique ordering of instance variables on a particular class. This can
also be thought of as a branch in the shape tree.

For example, the following Foo class will have 2 variations:

```ruby
class Foo ; end

Foo.new.instance_variable_set(:@a, 1) # case 1: creates one variation
Foo.new.instance_variable_set(:@b, 1) # case 2: creates another variation

foo = Foo.new
foo.instance_variable_set(:@a, 1) # does not create a new variation
foo.instance_variable_set(:@b, 1) # does not create a new variation (a continuation of the variation in case 1)
```

We will use this number to limit the amount of shapes that a class can
create and fallback to using a hash iv lookup.

Co-Authored-By: Aaron Patterson &lt;tenderlove@ruby-lang.org&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Count how many "variations" each class creates. A "variation" is a a
unique ordering of instance variables on a particular class. This can
also be thought of as a branch in the shape tree.

For example, the following Foo class will have 2 variations:

```ruby
class Foo ; end

Foo.new.instance_variable_set(:@a, 1) # case 1: creates one variation
Foo.new.instance_variable_set(:@b, 1) # case 2: creates another variation

foo = Foo.new
foo.instance_variable_set(:@a, 1) # does not create a new variation
foo.instance_variable_set(:@b, 1) # does not create a new variation (a continuation of the variation in case 1)
```

We will use this number to limit the amount of shapes that a class can
create and fallback to using a hash iv lookup.

Co-Authored-By: Aaron Patterson &lt;tenderlove@ruby-lang.org&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Revert "Fix Object Movement allocation in GC"</title>
<updated>2022-12-15T17:00:30+00:00</updated>
<author>
<name>Peter Zhu</name>
<email>peter@peterzhu.ca</email>
</author>
<published>2022-12-15T17:00:30+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=f50aa19da63067c4b0de5964b6632df20202e71c'/>
<id>f50aa19da63067c4b0de5964b6632df20202e71c</id>
<content type='text'>
This reverts commit 9c54466e299aa91af225bc2d92a3d7755730948f.

We're seeing crashes in Shopify CI after this commit.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
This reverts commit 9c54466e299aa91af225bc2d92a3d7755730948f.

We're seeing crashes in Shopify CI after this commit.
</pre>
</div>
</content>
</entry>
<entry>
<title>Fix Object Movement allocation in GC</title>
<updated>2022-12-15T14:04:30+00:00</updated>
<author>
<name>Matt Valentine-House</name>
<email>matt@eightbitraptor.com</email>
</author>
<published>2022-12-13T15:11:57+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=9c54466e299aa91af225bc2d92a3d7755730948f'/>
<id>9c54466e299aa91af225bc2d92a3d7755730948f</id>
<content type='text'>
When moving Objects between size pools we have to assign a new shape.

This happened during updating references - we tried to create a new shape
tree that mirrored the existing tree, but based on the root shape of the
new size pool.

This causes allocations to happen if the new tree doesn't already exist,
potentially triggering a GC, during GC.

This commit changes object movement to look for a pre-existing new tree
during object movement, and if that tree does not exist, we don't move
the object to the new pool.

This allows us to remove the shape allocation from update references.

Co-Authored-By: Peter Zhu &lt;peter@peterzhu.ca&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
When moving Objects between size pools we have to assign a new shape.

This happened during updating references - we tried to create a new shape
tree that mirrored the existing tree, but based on the root shape of the
new size pool.

This causes allocations to happen if the new tree doesn't already exist,
potentially triggering a GC, during GC.

This commit changes object movement to look for a pre-existing new tree
during object movement, and if that tree does not exist, we don't move
the object to the new pool.

This allows us to remove the shape allocation from update references.

Co-Authored-By: Peter Zhu &lt;peter@peterzhu.ca&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Remove dead code in get_next_shape_internal</title>
<updated>2022-12-14T18:21:46+00:00</updated>
<author>
<name>Peter Zhu</name>
<email>peter@peterzhu.ca</email>
</author>
<published>2022-12-14T15:57:44+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=7a63114f8eaba7a1fe8a56a2e665703d9f9cfa8a'/>
<id>7a63114f8eaba7a1fe8a56a2e665703d9f9cfa8a</id>
<content type='text'>
If the rb_id_table_lookup fails, then res is not updated so it cannot be
any value other than null.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
If the rb_id_table_lookup fails, then res is not updated so it cannot be
any value other than null.
</pre>
</div>
</content>
</entry>
</feed>
