Skip to content

Commit 184cfa8

Browse files
committed
Fix iterating of T_CLASS ivars (and remove lock too)
1 parent d218fb9 commit 184cfa8

4 files changed

Lines changed: 41 additions & 36 deletions

File tree

gc.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3166,12 +3166,8 @@ rb_gc_mark_children(void *objspace, VALUE obj)
31663166
foreach_args.objspace = objspace;
31673167
foreach_args.obj = obj;
31683168
rb_class_classext_foreach(obj, gc_mark_classext_module, (void *)&foreach_args);
3169-
3170-
if (!rb_shape_obj_too_complex_p(obj)) {
3171-
for (attr_index_t i = 0; i < RCLASS_FIELDS_COUNT(obj); i++) {
3172-
gc_mark_internal(RCLASS_PRIME_FIELDS(obj)[i]);
3173-
}
3174-
}
3169+
gc_mark_internal(RCLASS_EXT_READABLE(obj)->fields_obj);
3170+
// FIXME: other namespaces should be marked too
31753171
break;
31763172

31773173
case T_ICLASS:

imemo.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,16 @@ rb_imemo_mark_and_move(VALUE obj, bool reference_updating)
458458
break;
459459
}
460460
case imemo_class_fields: {
461-
// The object is responsible for marking
461+
if (rb_shape_obj_too_complex_p(obj)) {
462+
rb_mark_tbl_no_pin(rb_imemo_class_fields_complex_tbl(obj));
463+
}
464+
else {
465+
VALUE *fields = rb_imemo_class_fields_ptr(obj);
466+
uint32_t len = RSHAPE(rb_obj_shape_id(obj))->next_field_index;
467+
for (uint32_t i = 0; i < len; i++) {
468+
rb_gc_mark_and_move(&fields[i]);
469+
}
470+
}
462471
break;
463472
}
464473
default:

internal/class.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -571,9 +571,9 @@ RCLASS_SET_FIELDS_HASH(VALUE obj, st_table *tbl)
571571
RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
572572
RUBY_ASSERT(rb_shape_obj_too_complex_p(obj));
573573

574-
VALUE fields = rb_imemo_class_fields_new_complex(obj, tbl);
575-
rb_shape_set_shape_id(fields, RBASIC_SHAPE_ID(obj));
576-
RCLASSEXT_SET_FIELDS_OBJ(obj, RCLASS_EXT_PRIME(obj), fields);
574+
VALUE fields_obj = rb_imemo_class_fields_new_complex(obj, tbl);
575+
rb_shape_set_shape_id(fields_obj, RBASIC_SHAPE_ID(obj));
576+
RCLASSEXT_SET_FIELDS_OBJ(obj, RCLASS_EXT_PRIME(obj), fields_obj);
577577
}
578578

579579
static inline void

variable.c

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1596,9 +1596,8 @@ obj_transition_too_complex(VALUE obj, st_table *table)
15961596
break;
15971597
case T_CLASS:
15981598
case T_MODULE:
1599-
rb_shape_set_shape_id(obj, shape_id);
16001599
// FIXME: RCLASS_SET_FIELDS_HASH allocates, if GC trigger `table` might be corrupted.
1601-
RCLASS_SET_FIELDS_HASH(obj, table);
1600+
rb_bug("obj_transition_too_complex can't be used with T_CLASS/T_MODULE, see class_ivar_set_transition_too_complex");
16021601
break;
16031602
default:
16041603
RB_VM_LOCK_ENTER();
@@ -2214,6 +2213,7 @@ struct iv_itr_data {
22142213
st_data_t arg;
22152214
rb_ivar_foreach_callback_func *func;
22162215
bool ivar_only;
2216+
VALUE *fields;
22172217
};
22182218

22192219
/*
@@ -2237,22 +2237,7 @@ iterate_over_shapes_with_callback(rb_shape_t *shape, rb_ivar_foreach_callback_fu
22372237
return true;
22382238
}
22392239

2240-
VALUE * iv_list;
2241-
switch (BUILTIN_TYPE(itr_data->obj)) {
2242-
case T_OBJECT:
2243-
RUBY_ASSERT(!rb_shape_obj_too_complex_p(itr_data->obj));
2244-
iv_list = ROBJECT_FIELDS(itr_data->obj);
2245-
break;
2246-
case T_CLASS:
2247-
case T_MODULE:
2248-
RUBY_ASSERT(!rb_shape_obj_too_complex_p(itr_data->obj));
2249-
iv_list = RCLASS_PRIME_FIELDS(itr_data->obj);
2250-
break;
2251-
default:
2252-
iv_list = itr_data->fields_tbl->as.shape.fields;
2253-
break;
2254-
}
2255-
VALUE val = iv_list[shape->next_field_index - 1];
2240+
VALUE val = itr_data->fields[shape->next_field_index - 1];
22562241
if (!UNDEF_P(val)) {
22572242
switch (callback(shape->edge_name, val, itr_data->arg)) {
22582243
case ST_CHECK:
@@ -2297,6 +2282,7 @@ obj_fields_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg, b
22972282
rb_st_foreach(ROBJECT_FIELDS_HASH(obj), each_hash_iv, (st_data_t)&itr_data);
22982283
}
22992284
else {
2285+
itr_data.fields = ROBJECT_FIELDS(obj);
23002286
iterate_over_shapes_with_callback(shape, func, &itr_data);
23012287
}
23022288
}
@@ -2320,6 +2306,7 @@ gen_fields_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg, b
23202306
rb_st_foreach(fields_tbl->as.complex.table, each_hash_iv, (st_data_t)&itr_data);
23212307
}
23222308
else {
2309+
itr_data.fields = fields_tbl->as.shape.fields;
23232310
iterate_over_shapes_with_callback(shape, func, &itr_data);
23242311
}
23252312
}
@@ -2330,6 +2317,8 @@ class_fields_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg,
23302317
RUBY_ASSERT(RB_TYPE_P(obj, T_CLASS) || RB_TYPE_P(obj, T_MODULE));
23312318

23322319
rb_shape_t *shape = rb_obj_shape(obj);
2320+
VALUE fields_obj = RCLASS_EXT_WRITABLE(obj)->fields_obj;
2321+
23332322
struct iv_itr_data itr_data = {
23342323
.obj = obj,
23352324
.arg = arg,
@@ -2338,11 +2327,13 @@ class_fields_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg,
23382327
};
23392328

23402329
if (rb_shape_obj_too_complex_p(obj)) {
2341-
rb_st_foreach(RCLASS_WRITABLE_FIELDS_HASH(obj), each_hash_iv, (st_data_t)&itr_data);
2330+
rb_st_foreach(rb_imemo_class_fields_complex_tbl(fields_obj), each_hash_iv, (st_data_t)&itr_data);
23422331
}
23432332
else {
2333+
itr_data.fields = rb_imemo_class_fields_ptr(fields_obj);
23442334
iterate_over_shapes_with_callback(shape, func, &itr_data);
23452335
}
2336+
RB_GC_GUARD(fields_obj);
23462337
}
23472338

23482339
void
@@ -2488,12 +2479,7 @@ rb_field_foreach(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg,
24882479
break;
24892480
case T_CLASS:
24902481
case T_MODULE:
2491-
IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(0);
2492-
RB_VM_LOCK_ENTER();
2493-
{
2494-
class_fields_each(obj, func, arg, ivar_only);
2495-
}
2496-
RB_VM_LOCK_LEAVE();
2482+
class_fields_each(obj, func, arg, ivar_only);
24972483
break;
24982484
default:
24992485
if (FL_TEST(obj, FL_EXIVAR)) {
@@ -4765,7 +4751,21 @@ class_ivar_set_set_shape_id(VALUE obj, shape_id_t shape_id, void *_data)
47654751
static void
47664752
class_ivar_set_transition_too_complex(VALUE obj, void *_data)
47674753
{
4768-
rb_evict_fields_to_hash(obj);
4754+
void rb_obj_copy_fields_to_hash_table(VALUE obj, st_table *table);
4755+
4756+
RUBY_ASSERT(!rb_shape_obj_too_complex_p(obj));
4757+
4758+
rb_shape_t *shape = rb_obj_shape(obj);
4759+
st_table *table = st_init_numtable_with_size(shape->next_field_index);
4760+
VALUE fields_obj = rb_imemo_class_fields_new_complex(obj, table);
4761+
rb_obj_copy_fields_to_hash_table(obj, table);
4762+
4763+
shape_id_t shape_id = rb_shape_transition_complex(obj);
4764+
rb_shape_set_shape_id(obj, shape_id);
4765+
rb_shape_set_shape_id(fields_obj, RBASIC_SHAPE_ID(obj));
4766+
RCLASSEXT_SET_FIELDS_OBJ(obj, RCLASS_EXT_PRIME(obj), fields_obj);
4767+
4768+
RUBY_ASSERT(rb_shape_obj_too_complex_p(obj));
47694769
}
47704770

47714771
static st_table *

0 commit comments

Comments
 (0)