Fix vm_getivar to handle module with TOO_COMPLEX shape

This commit is contained in:
Jean Boussier 2023-11-02 17:38:24 +01:00 коммит произвёл Jean Boussier
Родитель 4c3cc25ea2
Коммит 0cb1fc3850
2 изменённых файлов: 40 добавлений и 1 удалений

Просмотреть файл

@ -275,6 +275,25 @@ class TestShapes < Test::Unit::TestCase
end;
end
def test_run_out_of_shape_for_module_ivar
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
o = Object.new
i = 0
while RubyVM::Shape.shapes_available > 0
o.instance_variable_set(:"@i#{i}", 1)
i += 1
end
module Foo
@a = 1
@b = 2
assert_equal 1, @a
assert_equal 2, @b
end
end;
end
def test_run_out_of_shape_for_class_cvar
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;

Просмотреть файл

@ -1289,7 +1289,27 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call
rb_shape_t *shape = rb_shape_get_shape_by_id(shape_id);
if (shape_id == OBJ_TOO_COMPLEX_SHAPE_ID) {
if (!st_lookup(ROBJECT_IV_HASH(obj), id, &val)) {
st_table *table = NULL;
switch (BUILTIN_TYPE(obj)) {
case T_CLASS:
case T_MODULE:
table = (st_table *)RCLASS_IVPTR(obj);
break;
case T_OBJECT:
table = ROBJECT_IV_HASH(obj);
break;
default: {
struct gen_ivtbl *ivtbl;
if (rb_gen_ivtbl_get(obj, 0, &ivtbl)) {
table = ivtbl->as.complex.table;
}
break;
}
}
if (!table || !st_lookup(table, id, &val)) {
val = default_value;
}
}