Skip to content

Commit 1986bca

Browse files
committed
imemo_fields: store owner object in RBasic.klass
It is much more convenient than storing the klass, especially when dealing with `object_id` as it allows to update the id2ref table without having to dereference the owner, which may be garbage at that point.
1 parent d4f7435 commit 1986bca

7 files changed

Lines changed: 63 additions & 41 deletions

File tree

gc.c

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1921,7 +1921,7 @@ object_id(VALUE obj)
19211921
// in fields.
19221922
return class_object_id(obj);
19231923
case T_IMEMO:
1924-
rb_bug("T_IMEMO can't have an object_id");
1924+
RUBY_ASSERT(IMEMO_TYPE_P(obj, imemo_fields));
19251925
break;
19261926
default:
19271927
break;
@@ -1965,15 +1965,16 @@ build_id2ref_i(VALUE obj, void *data)
19651965
}
19661966
break;
19671967
case T_IMEMO:
1968-
if (IMEMO_TYPE_P(obj, imemo_fields) && rb_shape_obj_has_id(obj) && rb_gc_impl_garbage_object_p(objspace, obj)) {
1969-
rb_imemo_fields_clear(obj);
1968+
if (IMEMO_TYPE_P(obj, imemo_fields) && rb_shape_obj_has_id(obj)) {
1969+
if (rb_gc_impl_garbage_object_p(objspace, obj)) {
1970+
RBASIC_SET_SHAPE_ID(obj, ROOT_SHAPE_ID);
1971+
}
1972+
else {
1973+
st_insert(id2ref_tbl, rb_obj_id(obj), rb_imemo_fields_owner(obj));
1974+
}
19701975
}
1971-
19721976
break;
1973-
case T_NONE:
1974-
case T_ZOMBIE:
1975-
break;
1976-
default:
1977+
case T_OBJECT:
19771978
if (rb_shape_obj_has_id(obj)) {
19781979
if (rb_gc_impl_garbage_object_p(objspace, obj)) {
19791980
RBASIC_SET_SHAPE_ID(obj, ROOT_SHAPE_ID);
@@ -1983,6 +1984,9 @@ build_id2ref_i(VALUE obj, void *data)
19831984
}
19841985
}
19851986
break;
1987+
default:
1988+
// For generic_fields, the T_IMEMO/fields is responsible for populating the entry.
1989+
break;
19861990
}
19871991
}
19881992

imemo.c

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -109,40 +109,40 @@ rb_imemo_tmpbuf_parser_heap(void *buf, rb_imemo_tmpbuf_t *old_heap, size_t cnt)
109109
}
110110

111111
static VALUE
112-
imemo_fields_new(VALUE klass, size_t capa)
112+
imemo_fields_new(VALUE owner, size_t capa)
113113
{
114114
size_t embedded_size = offsetof(struct rb_fields, as.embed) + capa * sizeof(VALUE);
115115
if (rb_gc_size_allocatable_p(embedded_size)) {
116-
VALUE fields = rb_imemo_new(imemo_fields, klass, embedded_size);
116+
VALUE fields = rb_imemo_new(imemo_fields, owner, embedded_size);
117117
RUBY_ASSERT(IMEMO_TYPE_P(fields, imemo_fields));
118118
return fields;
119119
}
120120
else {
121-
VALUE fields = rb_imemo_new(imemo_fields, klass, sizeof(struct rb_fields));
121+
VALUE fields = rb_imemo_new(imemo_fields, owner, sizeof(struct rb_fields));
122122
FL_SET_RAW(fields, OBJ_FIELD_EXTERNAL);
123123
IMEMO_OBJ_FIELDS(fields)->as.external.ptr = ALLOC_N(VALUE, capa);
124124
return fields;
125125
}
126126
}
127127

128128
VALUE
129-
rb_imemo_fields_new(VALUE klass, size_t capa)
129+
rb_imemo_fields_new(VALUE owner, size_t capa)
130130
{
131-
return imemo_fields_new(klass, capa);
131+
return imemo_fields_new(owner, capa);
132132
}
133133

134134
static VALUE
135-
imemo_fields_new_complex(VALUE klass, size_t capa)
135+
imemo_fields_new_complex(VALUE owner, size_t capa)
136136
{
137-
VALUE fields = imemo_fields_new(klass, sizeof(struct rb_fields));
137+
VALUE fields = imemo_fields_new(owner, sizeof(struct rb_fields));
138138
IMEMO_OBJ_FIELDS(fields)->as.complex.table = st_init_numtable_with_size(capa);
139139
return fields;
140140
}
141141

142142
VALUE
143-
rb_imemo_fields_new_complex(VALUE klass, size_t capa)
143+
rb_imemo_fields_new_complex(VALUE owner, size_t capa)
144144
{
145-
return imemo_fields_new_complex(klass, capa);
145+
return imemo_fields_new_complex(owner, capa);
146146
}
147147

148148
static int
@@ -161,9 +161,9 @@ imemo_fields_complex_wb_i(st_data_t key, st_data_t value, st_data_t arg)
161161
}
162162

163163
VALUE
164-
rb_imemo_fields_new_complex_tbl(VALUE klass, st_table *tbl)
164+
rb_imemo_fields_new_complex_tbl(VALUE owner, st_table *tbl)
165165
{
166-
VALUE fields = imemo_fields_new(klass, sizeof(struct rb_fields));
166+
VALUE fields = imemo_fields_new(owner, sizeof(struct rb_fields));
167167
IMEMO_OBJ_FIELDS(fields)->as.complex.table = tbl;
168168
st_foreach(tbl, imemo_fields_trigger_wb_i, (st_data_t)fields);
169169
return fields;
@@ -176,15 +176,15 @@ rb_imemo_fields_clone(VALUE fields_obj)
176176
VALUE clone;
177177

178178
if (rb_shape_too_complex_p(shape_id)) {
179-
clone = rb_imemo_fields_new_complex(CLASS_OF(fields_obj), 0);
179+
clone = rb_imemo_fields_new_complex(rb_imemo_fields_owner(fields_obj), 0);
180180
RBASIC_SET_SHAPE_ID(clone, shape_id);
181181
st_table *src_table = rb_imemo_fields_complex_tbl(fields_obj);
182182
st_table *dest_table = rb_imemo_fields_complex_tbl(clone);
183183
st_replace(dest_table, src_table);
184184
st_foreach(dest_table, imemo_fields_complex_wb_i, (st_data_t)clone);
185185
}
186186
else {
187-
clone = imemo_fields_new(CLASS_OF(fields_obj), RSHAPE_CAPACITY(shape_id));
187+
clone = imemo_fields_new(rb_imemo_fields_owner(fields_obj), RSHAPE_CAPACITY(shape_id));
188188
RBASIC_SET_SHAPE_ID(clone, shape_id);
189189
VALUE *fields = rb_imemo_fields_ptr(clone);
190190
attr_index_t fields_count = RSHAPE_LEN(shape_id);

internal/class.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ RCLASS_WRITABLE_ENSURE_FIELDS_OBJ(VALUE obj)
546546
RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
547547
rb_classext_t *ext = RCLASS_EXT_WRITABLE(obj);
548548
if (!ext->fields_obj) {
549-
RB_OBJ_WRITE(obj, &ext->fields_obj, rb_imemo_fields_new(rb_singleton_class(obj), 1));
549+
RB_OBJ_WRITE(obj, &ext->fields_obj, rb_imemo_fields_new(obj, 1));
550550
}
551551
return ext->fields_obj;
552552
}

internal/imemo.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -273,12 +273,18 @@ struct rb_fields {
273273
#define OBJ_FIELD_EXTERNAL IMEMO_FL_USER0
274274
#define IMEMO_OBJ_FIELDS(fields) ((struct rb_fields *)fields)
275275

276-
VALUE rb_imemo_fields_new(VALUE klass, size_t capa);
277-
VALUE rb_imemo_fields_new_complex(VALUE klass, size_t capa);
278-
VALUE rb_imemo_fields_new_complex_tbl(VALUE klass, st_table *tbl);
276+
VALUE rb_imemo_fields_new(VALUE owner, size_t capa);
277+
VALUE rb_imemo_fields_new_complex(VALUE owner, size_t capa);
278+
VALUE rb_imemo_fields_new_complex_tbl(VALUE owner, st_table *tbl);
279279
VALUE rb_imemo_fields_clone(VALUE fields_obj);
280280
void rb_imemo_fields_clear(VALUE fields_obj);
281281

282+
static inline VALUE
283+
rb_imemo_fields_owner(VALUE fields_obj)
284+
{
285+
return CLASS_OF(fields_obj);
286+
}
287+
282288
static inline VALUE *
283289
rb_imemo_fields_ptr(VALUE obj_fields)
284290
{

shape.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -877,8 +877,17 @@ shape_get_next(rb_shape_t *shape, VALUE obj, ID id, bool emit_warnings)
877877
#endif
878878

879879
VALUE klass;
880-
if (IMEMO_TYPE_P(obj, imemo_fields)) { // HACK
881-
klass = CLASS_OF(obj);
880+
if (IMEMO_TYPE_P(obj, imemo_fields)) {
881+
VALUE owner = rb_imemo_fields_owner(obj);
882+
switch (BUILTIN_TYPE(owner)) {
883+
case T_CLASS:
884+
case T_MODULE:
885+
klass = rb_singleton_class(owner);
886+
break;
887+
default:
888+
klass = rb_obj_class(owner);
889+
break;
890+
}
882891
}
883892
else {
884893
klass = rb_obj_class(obj);

test/ruby/test_shapes.rb

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,14 @@ class Hi; end
149149
def test_too_many_ivs_on_class
150150
obj = Class.new
151151

152-
(MANY_IVS + 1).times do
152+
obj.instance_variable_set(:@test_too_many_ivs_on_class, 1)
153+
refute_predicate RubyVM::Shape.of(obj), :too_complex?
154+
155+
MANY_IVS.times do
153156
obj.instance_variable_set(:"@a#{_1}", 1)
154157
end
155158

156-
assert_false RubyVM::Shape.of(obj).too_complex?
159+
refute_predicate RubyVM::Shape.of(obj), :too_complex?
157160
end
158161

159162
def test_removing_when_too_many_ivs_on_class

variable.c

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1666,10 +1666,10 @@ imemo_fields_complex_from_obj_i(ID key, VALUE val, st_data_t arg)
16661666
}
16671667

16681668
static VALUE
1669-
imemo_fields_complex_from_obj(VALUE klass, VALUE source_fields_obj, shape_id_t shape_id)
1669+
imemo_fields_complex_from_obj(VALUE owner, VALUE source_fields_obj, shape_id_t shape_id)
16701670
{
16711671
attr_index_t len = source_fields_obj ? RSHAPE_LEN(RBASIC_SHAPE_ID(source_fields_obj)) : 0;
1672-
VALUE fields_obj = rb_imemo_fields_new_complex(klass, len + 1);
1672+
VALUE fields_obj = rb_imemo_fields_new_complex(owner, len + 1);
16731673

16741674
rb_field_foreach(source_fields_obj, imemo_fields_complex_from_obj_i, (st_data_t)fields_obj, false);
16751675
RBASIC_SET_SHAPE_ID(fields_obj, shape_id);
@@ -1678,9 +1678,9 @@ imemo_fields_complex_from_obj(VALUE klass, VALUE source_fields_obj, shape_id_t s
16781678
}
16791679

16801680
static VALUE
1681-
imemo_fields_copy_capa(VALUE klass, VALUE source_fields_obj, attr_index_t new_size)
1681+
imemo_fields_copy_capa(VALUE owner, VALUE source_fields_obj, attr_index_t new_size)
16821682
{
1683-
VALUE fields_obj = rb_imemo_fields_new(klass, new_size);
1683+
VALUE fields_obj = rb_imemo_fields_new(owner, new_size);
16841684
if (source_fields_obj) {
16851685
attr_index_t fields_count = RSHAPE_LEN(RBASIC_SHAPE_ID(source_fields_obj));
16861686
VALUE *fields = rb_imemo_fields_ptr(fields_obj);
@@ -1832,7 +1832,7 @@ general_field_set(VALUE obj, shape_id_t target_shape_id, VALUE val, void *data,
18321832
}
18331833

18341834
static VALUE
1835-
imemo_fields_set(VALUE klass, VALUE fields_obj, shape_id_t target_shape_id, ID field_name, VALUE val, bool concurrent)
1835+
imemo_fields_set(VALUE owner, VALUE fields_obj, shape_id_t target_shape_id, ID field_name, VALUE val, bool concurrent)
18361836
{
18371837
const VALUE original_fields_obj = fields_obj;
18381838
shape_id_t current_shape_id = fields_obj ? RBASIC_SHAPE_ID(fields_obj) : ROOT_SHAPE_ID;
@@ -1847,7 +1847,7 @@ imemo_fields_set(VALUE klass, VALUE fields_obj, shape_id_t target_shape_id, ID f
18471847
}
18481848
}
18491849
else {
1850-
fields_obj = imemo_fields_complex_from_obj(klass, original_fields_obj, target_shape_id);
1850+
fields_obj = imemo_fields_complex_from_obj(owner, original_fields_obj, target_shape_id);
18511851
current_shape_id = target_shape_id;
18521852
}
18531853

@@ -1861,7 +1861,7 @@ imemo_fields_set(VALUE klass, VALUE fields_obj, shape_id_t target_shape_id, ID f
18611861
else {
18621862
attr_index_t index = RSHAPE_INDEX(target_shape_id);
18631863
if (concurrent || index >= RSHAPE_CAPACITY(current_shape_id)) {
1864-
fields_obj = imemo_fields_copy_capa(klass, original_fields_obj, RSHAPE_CAPACITY(target_shape_id));
1864+
fields_obj = imemo_fields_copy_capa(owner, original_fields_obj, RSHAPE_CAPACITY(target_shape_id));
18651865
}
18661866

18671867
VALUE *table = rb_imemo_fields_ptr(fields_obj);
@@ -1884,7 +1884,7 @@ generic_field_set(VALUE obj, shape_id_t target_shape_id, ID field_name, VALUE va
18841884
}
18851885

18861886
const VALUE original_fields_obj = rb_obj_fields(obj, field_name);
1887-
VALUE fields_obj = imemo_fields_set(rb_obj_class(obj), original_fields_obj, target_shape_id, field_name, val, false);
1887+
VALUE fields_obj = imemo_fields_set(obj, original_fields_obj, target_shape_id, field_name, val, false);
18881888

18891889
rb_obj_set_fields(obj, fields_obj, field_name, original_fields_obj);
18901890
}
@@ -2319,7 +2319,7 @@ rb_copy_generic_ivar(VALUE dest, VALUE obj)
23192319
return;
23202320
}
23212321

2322-
new_fields_obj = rb_imemo_fields_new(rb_obj_class(dest), RSHAPE_CAPACITY(dest_shape_id));
2322+
new_fields_obj = rb_imemo_fields_new(dest, RSHAPE_CAPACITY(dest_shape_id));
23232323
VALUE *src_buf = rb_imemo_fields_ptr(fields_obj);
23242324
VALUE *dest_buf = rb_imemo_fields_ptr(new_fields_obj);
23252325
rb_shape_copy_fields(new_fields_obj, dest_buf, dest_shape_id, src_buf, src_shape_id);
@@ -4640,7 +4640,7 @@ class_fields_ivar_set(VALUE klass, VALUE fields_obj, ID id, VALUE val, bool conc
46404640
{
46414641
bool existing = true;
46424642
const VALUE original_fields_obj = fields_obj;
4643-
fields_obj = original_fields_obj ? original_fields_obj : rb_imemo_fields_new(rb_singleton_class(klass), 1);
4643+
fields_obj = original_fields_obj ? original_fields_obj : rb_imemo_fields_new(klass, 1);
46444644

46454645
shape_id_t current_shape_id = RBASIC_SHAPE_ID(fields_obj);
46464646
shape_id_t next_shape_id = current_shape_id;
@@ -4660,7 +4660,7 @@ class_fields_ivar_set(VALUE klass, VALUE fields_obj, ID id, VALUE val, bool conc
46604660

46614661
next_shape_id = rb_shape_transition_add_ivar(fields_obj, id);
46624662
if (UNLIKELY(rb_shape_too_complex_p(next_shape_id))) {
4663-
fields_obj = imemo_fields_complex_from_obj(rb_singleton_class(klass), fields_obj, next_shape_id);
4663+
fields_obj = imemo_fields_complex_from_obj(klass, fields_obj, next_shape_id);
46644664
goto too_complex;
46654665
}
46664666

@@ -4670,7 +4670,7 @@ class_fields_ivar_set(VALUE klass, VALUE fields_obj, ID id, VALUE val, bool conc
46704670
if (next_capacity > current_capacity) {
46714671
// We allocate a new fields_obj even when concurrency isn't a concern
46724672
// so that we're embedded as long as possible.
4673-
fields_obj = imemo_fields_copy_capa(rb_singleton_class(klass), fields_obj, next_capacity);
4673+
fields_obj = imemo_fields_copy_capa(klass, fields_obj, next_capacity);
46744674
}
46754675

46764676
RUBY_ASSERT(RSHAPE(next_shape_id)->type == SHAPE_IVAR);

0 commit comments

Comments
 (0)