Better handle running out of shapes in remove_shape_recursive

This commit is contained in:
Jean Boussier 2023-11-02 10:37:09 +01:00 committed by Jean Boussier
parent 42f368ead5
commit 33795931a0
2 changed files with 36 additions and 2 deletions

View File

@ -583,12 +583,16 @@ remove_shape_recursive(VALUE obj, ID id, rb_shape_t * shape, VALUE * removed)
// We found a new parent. Create a child of the new parent that
// has the same attributes as this shape.
if (new_parent) {
bool dont_care;
rb_shape_t * new_child = get_next_shape_internal(new_parent, shape->edge_name, shape->type, &dont_care, true);
if (UNLIKELY(new_parent->type == SHAPE_OBJ_TOO_COMPLEX)) {
return new_parent;
}
bool dont_care;
rb_shape_t * new_child = get_next_shape_internal(new_parent, shape->edge_name, shape->type, &dont_care, true);
if (UNLIKELY(new_child->type == SHAPE_OBJ_TOO_COMPLEX)) {
return new_child;
}
new_child->capacity = shape->capacity;
if (new_child->type == SHAPE_IVAR) {
move_iv(obj, id, shape->next_iv_index - 1, new_child->next_iv_index - 1);

View File

@ -577,6 +577,36 @@ class TestShapes < Test::Unit::TestCase
assert_equal [0, 1, nil, 3, 4], ivars
end
def test_remove_instance_variable_when_out_of_shapes
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
ivars_count = 5
object = Object.new
ivars_count.times do |i|
object.instance_variable_set("@ivar_#{i}", i)
end
ivars = ivars_count.times.map do |i|
object.instance_variable_get("@ivar_#{i}")
end
assert_equal [0, 1, 2, 3, 4], ivars
o = Object.new
i = 0
while RubyVM::Shape.shapes_available > 0
o.instance_variable_set(:"@i#{i}", 1)
i += 1
end
object.remove_instance_variable(:@ivar_2)
ivars = ivars_count.times.map do |i|
object.instance_variable_get("@ivar_#{i}")
end
assert_equal [0, 1, nil, 3, 4], ivars
end;
end
def test_freeze_after_complex
ensure_complex