Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 054dba1

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 bb180b8 commit 054dba1

File tree

2 files changed

+67
-10
lines changed

2 files changed

+67
-10
lines changed

gc.c

Lines changed: 66 additions & 10 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

@@ -1940,16 +1982,30 @@ object_id_to_ref(void *objspace_ptr, VALUE object_id)
19401982
static inline void
19411983
obj_free_object_id(VALUE obj)
19421984
{
1985+
VALUE obj_id = 0;
19431986
if (RB_UNLIKELY(id_to_obj_tbl)) {
1944-
if (rb_shape_obj_has_id(obj)) {
1945-
VALUE obj_id = object_id(obj);
1946-
RUBY_ASSERT(FIXNUM_P(obj_id) || RB_TYPE_P(obj, T_BIGNUM));
1987+
switch (BUILTIN_TYPE(obj)) {
1988+
case T_CLASS:
1989+
case T_MODULE:
1990+
if (RCLASS(obj)->object_id) {
1991+
obj_id = RCLASS(obj)->object_id;
1992+
}
1993+
break;
1994+
default:
1995+
if (rb_shape_obj_has_id(obj)) {
1996+
obj_id = object_id(obj);
1997+
}
1998+
break;
1999+
}
2000+
}
19472001

1948-
if (!st_delete(id_to_obj_tbl, (st_data_t *)&obj_id, NULL)) {
1949-
// If we're currently building the table then it's not a bug
1950-
if (id_to_obj_tbl_built) {
1951-
rb_bug("Object ID seen, but not in id_to_obj table: object_id=%llu object=%s", NUM2ULL(obj_id), rb_obj_info(obj));
1952-
}
2002+
if (RB_UNLIKELY(obj_id)) {
2003+
RUBY_ASSERT(FIXNUM_P(obj_id) || RB_TYPE_P(obj, T_BIGNUM));
2004+
2005+
if (!st_delete(id_to_obj_tbl, (st_data_t *)&obj_id, NULL)) {
2006+
// If we're currently building the table then it's not a bug
2007+
if (id_to_obj_tbl_built) {
2008+
rb_bug("Object ID seen, but not in id_to_obj table: object_id=%llu object=%s", NUM2ULL(obj_id), rb_obj_info(obj));
19532009
}
19542010
}
19552011
}

internal/class.h

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

0 commit comments

Comments
 (0)