Fix "too complex" iv sets on generic ivar objects

We weren't taking in to account that objects with generic IV tables
could go "too complex" in the IV set code.  This commit takes that in to
account and also ensures FL_EXIVAR is set when a geniv object
transitions to "too complex"

Co-Authored-By: Jean Boussier <byroot@ruby-lang.org>
This commit is contained in:
Aaron Patterson 2023-10-30 09:50:56 -07:00 committed by Peter Zhu
parent ac7f913ca3
commit 6f5e378057
2 changed files with 32 additions and 0 deletions

View File

@ -184,6 +184,32 @@ class TestShapes < Test::Unit::TestCase
assert_empty obj.instance_variables assert_empty obj.instance_variables
end end
def test_too_complex_geniv
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
class TooComplex < Hash
attr_reader :very_unique
end
obj = Object.new
i = 0
while RubyVM::Shape.shapes_available > 0
obj.instance_variable_set(:"@a#{i}", 1)
i += 1
end
(RubyVM::Shape::SHAPE_MAX_VARIATIONS * 2).times do
TooComplex.new.instance_variable_set(:"@unique_#{_1}", 1)
end
tc = TooComplex.new
tc.instance_variable_set(:@very_unique, 3)
tc.instance_variable_set(:@very_unique2, 4)
assert_equal 3, tc.instance_variable_get(:@very_unique)
assert_equal 4, tc.instance_variable_get(:@very_unique2)
end;
end
def test_use_all_shapes_then_freeze def test_use_all_shapes_then_freeze
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin; begin;

View File

@ -1483,6 +1483,11 @@ generic_ivar_set(VALUE obj, ID id, VALUE val)
attr_index_t index; attr_index_t index;
// The returned shape will have `id` in its iv_table // The returned shape will have `id` in its iv_table
if (rb_shape_obj_too_complex(obj)) {
rb_complex_ivar_set(obj, id, val);
return;
}
rb_shape_t *shape = rb_shape_get_shape(obj); rb_shape_t *shape = rb_shape_get_shape(obj);
if (UNLIKELY(shape->type == SHAPE_OBJ_TOO_COMPLEX)) { if (UNLIKELY(shape->type == SHAPE_OBJ_TOO_COMPLEX)) {
rb_complex_ivar_set(obj, id, val); rb_complex_ivar_set(obj, id, val);
@ -1498,6 +1503,7 @@ generic_ivar_set(VALUE obj, ID id, VALUE val)
rb_evict_ivars_to_hash(obj, shape); rb_evict_ivars_to_hash(obj, shape);
rb_complex_ivar_set(obj, id, val); rb_complex_ivar_set(obj, id, val);
rb_shape_set_shape(obj, next_shape); rb_shape_set_shape(obj, next_shape);
FL_SET_RAW(obj, FL_EXIVAR);
return; return;
} }
shape = next_shape; shape = next_shape;