Skip to content

Commit d0e8149

Browse files
committed
Fix object_id for classes in modules in namespace context
Given classes and modules have a different set of fields in every namespace, we can't store the object_id in fields for them. Given that some space was freed in `RClass` we can store it there instead.
1 parent a6435be commit d0e8149

2 files changed

Lines changed: 45 additions & 2 deletions

File tree

gc.c

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1861,9 +1861,40 @@ static const rb_data_type_t id_to_obj_tbl_type = {
18611861
.flags = RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
18621862
};
18631863

1864+
static VALUE
1865+
class_object_id(VALUE klass)
1866+
{
1867+
VALUE id = RCLASS(klass)->object_id;
1868+
if (!id) {
1869+
unsigned int lock_lev = rb_gc_vm_lock();
1870+
id = ULL2NUM(next_object_id);
1871+
next_object_id += OBJ_ID_INCREMENT;
1872+
VALUE existing_id = RUBY_ATOMIC_VALUE_CAS(RCLASS(klass)->object_id, 0, id);
1873+
if (existing_id) {
1874+
id = existing_id;
1875+
}
1876+
else if (RB_UNLIKELY(id_to_obj_tbl)) {
1877+
st_insert(id_to_obj_tbl, id, klass);
1878+
}
1879+
rb_gc_vm_unlock(lock_lev);
1880+
}
1881+
return id;
1882+
}
1883+
18641884
static VALUE
18651885
object_id(VALUE obj)
18661886
{
1887+
switch (BUILTIN_TYPE(obj)) {
1888+
case T_CLASS:
1889+
case T_MODULE:
1890+
// With namespaces, classes and modules have different fields
1891+
// in different namespaces, so we cannot store the object id
1892+
// in fields.
1893+
return class_object_id(obj);
1894+
default:
1895+
break;
1896+
}
1897+
18671898
VALUE id = Qfalse;
18681899
unsigned int lock_lev;
18691900

@@ -1896,8 +1927,19 @@ static void
18961927
build_id_to_obj_i(VALUE obj, void *data)
18971928
{
18981929
st_table *id_to_obj_tbl = (st_table *)data;
1899-
if (rb_shape_obj_has_id(obj)) {
1900-
st_insert(id_to_obj_tbl, rb_obj_id(obj), obj);
1930+
1931+
switch (BUILTIN_TYPE(obj)) {
1932+
case T_CLASS:
1933+
case T_MODULE:
1934+
if (RCLASS(obj)->object_id) {
1935+
st_insert(id_to_obj_tbl, RCLASS(obj)->object_id, obj);
1936+
}
1937+
break;
1938+
default:
1939+
if (rb_shape_obj_has_id(obj)) {
1940+
st_insert(id_to_obj_tbl, rb_obj_id(obj), obj);
1941+
}
1942+
break;
19011943
}
19021944
}
19031945

internal/class.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ STATIC_ASSERT(shape_max_variations, SHAPE_MAX_VARIATIONS < (1 << (sizeof(((rb_cl
136136
struct RClass {
137137
struct RBasic basic;
138138
st_table *ns_classext_tbl; // ns_object -> (rb_classext_t *)
139+
VALUE object_id;
139140
/*
140141
* If ns_classext_tbl is NULL, then the prime classext is readable (because no other classext exists).
141142
* For the check whether writable or not, check flag RCLASS_PRIME_CLASSEXT_WRITABLE

0 commit comments

Comments
 (0)