Skip to content

Commit 947a598

Browse files
committed
parallel sweep: fix for id2ref_tbl being managed table
1 parent 6f6a1d9 commit 947a598

File tree

1 file changed

+31
-39
lines changed

1 file changed

+31
-39
lines changed

gc.c

Lines changed: 31 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2141,13 +2141,9 @@ id2ref_tbl_unlock(void)
21412141
static void
21422142
id2ref_tbl_free(void *data)
21432143
{
2144-
id2ref_tbl_lock(true);
2145-
{
2146-
RUBY_ATOMIC_PTR_SET(id2ref_tbl, NULL); // clear global ref
2147-
st_table *table = (st_table *)data;
2148-
st_free_table(table);
2149-
}
2150-
id2ref_tbl_unlock();
2144+
st_table *table = (st_table *)data;
2145+
st_free_table(table);
2146+
RUBY_ATOMIC_PTR_SET(id2ref_tbl, NULL); // clear global ref
21512147
}
21522148

21532149
static const rb_data_type_t id2ref_tbl_type = {
@@ -2159,7 +2155,7 @@ static const rb_data_type_t id2ref_tbl_type = {
21592155
// dcompact function not required because the table is reference updated
21602156
// in rb_gc_vm_weak_table_foreach
21612157
},
2162-
.flags = RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_CONCURRENT_FREE_SAFE
2158+
.flags = RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
21632159
};
21642160

21652161
static VALUE
@@ -2270,36 +2266,26 @@ build_id2ref_i(VALUE obj, void *data)
22702266
{
22712267
st_table *id2ref_tbl = (st_table *)data;
22722268

2269+
if (rb_objspace_garbage_object_p(obj)) return;
2270+
22732271
switch (BUILTIN_TYPE(obj)) {
22742272
case T_CLASS:
22752273
case T_MODULE:
22762274
RUBY_ASSERT(!rb_objspace_garbage_object_p(obj));
22772275
if (RCLASS(obj)->object_id) {
2278-
id2ref_tbl_lock(false);
2279-
{
2280-
st_insert(id2ref_tbl, RCLASS(obj)->object_id, obj);
2281-
}
2282-
id2ref_tbl_unlock();
2276+
st_insert(id2ref_tbl, RCLASS(obj)->object_id, obj);
22832277
}
22842278
break;
22852279
case T_IMEMO:
22862280
RUBY_ASSERT(!rb_objspace_garbage_object_p(obj));
22872281
if (IMEMO_TYPE_P(obj, imemo_fields) && rb_shape_obj_has_id(obj)) {
2288-
id2ref_tbl_lock(false);
2289-
{
2290-
st_insert(id2ref_tbl, rb_obj_id(obj), rb_imemo_fields_owner(obj));
2291-
}
2292-
id2ref_tbl_unlock();
2282+
st_insert(id2ref_tbl, rb_obj_id(obj), rb_imemo_fields_owner(obj));
22932283
}
22942284
break;
22952285
case T_OBJECT:
22962286
RUBY_ASSERT(!rb_objspace_garbage_object_p(obj));
22972287
if (rb_shape_obj_has_id(obj)) {
2298-
id2ref_tbl_lock(false);
2299-
{
2300-
st_insert(id2ref_tbl, rb_obj_id(obj), obj);
2301-
}
2302-
id2ref_tbl_unlock();
2288+
st_insert(id2ref_tbl, rb_obj_id(obj), obj);
23032289
}
23042290
break;
23052291
default:
@@ -2317,24 +2303,30 @@ object_id_to_ref(void *objspace_ptr, VALUE object_id)
23172303

23182304
if (!RUBY_ATOMIC_PTR_LOAD(id2ref_tbl)) {
23192305
rb_gc_vm_barrier(); // stop other ractors, background sweeper could still be running
2306+
if (!RUBY_ATOMIC_PTR_LOAD(id2ref_tbl)) {
2307+
2308+
// GC Must not trigger while we build the table, otherwise if we end
2309+
// up freeing an object that had an ID, we might try to delete it from
2310+
// the table even though it wasn't inserted yet.
2311+
st_table *tmp_id2ref_tbl = st_init_table(&object_id_hash_type);
2312+
VALUE tmp_id2ref_value = TypedData_Wrap_Struct(0, &id2ref_tbl_type, tmp_id2ref_tbl);
2313+
2314+
// build_id2ref_i will most certainly malloc, which could trigger GC and sweep
2315+
// objects we just added to the table.
2316+
// By calling rb_gc_disable() we also save having to handle potentially garbage objects.
2317+
bool gc_disabled = RTEST(rb_gc_disable());
2318+
{
2319+
id2ref_value = tmp_id2ref_value;
23202320

2321-
// GC Must not trigger while we build the table, otherwise if we end
2322-
// up freeing an object that had an ID, we might try to delete it from
2323-
// the table even though it wasn't inserted yet.
2324-
st_table *tmp_id2ref_tbl = st_init_table(&object_id_hash_type);
2325-
VALUE tmp_id2ref_value = TypedData_Wrap_Struct(0, &id2ref_tbl_type, tmp_id2ref_tbl);
2326-
2327-
// build_id2ref_i will most certainly malloc, which could trigger GC and sweep
2328-
// objects we just added to the table.
2329-
// By calling rb_gc_disable() we also save having to handle potentially garbage objects.
2330-
bool gc_disabled = RTEST(rb_gc_disable());
2331-
{
2332-
id2ref_value = tmp_id2ref_value;
2333-
2334-
rb_gc_impl_each_object(objspace, build_id2ref_i, (void *)tmp_id2ref_tbl);
2335-
RUBY_ATOMIC_PTR_SET(id2ref_tbl, tmp_id2ref_tbl);
2321+
id2ref_tbl_lock(false);
2322+
{
2323+
rb_gc_impl_each_object(objspace, build_id2ref_i, (void *)tmp_id2ref_tbl);
2324+
}
2325+
id2ref_tbl_unlock();
2326+
RUBY_ATOMIC_PTR_SET(id2ref_tbl, tmp_id2ref_tbl);
2327+
}
2328+
if (!gc_disabled) rb_gc_enable();
23362329
}
2337-
if (!gc_disabled) rb_gc_enable();
23382330
}
23392331

23402332
VALUE obj;

0 commit comments

Comments
 (0)