summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--test/ruby/test_shapes.rb19
-rw-r--r--vm_insnhelper.c22
2 files changed, 40 insertions, 1 deletions
diff --git a/test/ruby/test_shapes.rb b/test/ruby/test_shapes.rb
index 09a99c4855..4967b404e2 100644
--- a/test/ruby/test_shapes.rb
+++ b/test/ruby/test_shapes.rb
@@ -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;
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 6b354dd19a..e28323e588 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -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;
}
}