Fix object_id
for classes and 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.
This commit is contained in:
parent
130d6aaef2
commit
9400119702
Notes:
git
2025-05-14 08:27:01 +00:00
62
gc.c
62
gc.c
@ -1861,9 +1861,42 @@ static const rb_data_type_t id_to_obj_tbl_type = {
|
|||||||
.flags = RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
|
.flags = RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define RUBY_ATOMIC_VALUE_LOAD(x) (VALUE)(RUBY_ATOMIC_PTR_LOAD(x))
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
class_object_id(VALUE klass)
|
||||||
|
{
|
||||||
|
VALUE id = RUBY_ATOMIC_VALUE_LOAD(RCLASS(klass)->object_id);
|
||||||
|
if (!id) {
|
||||||
|
unsigned int lock_lev = rb_gc_vm_lock();
|
||||||
|
id = ULL2NUM(next_object_id);
|
||||||
|
next_object_id += OBJ_ID_INCREMENT;
|
||||||
|
VALUE existing_id = RUBY_ATOMIC_VALUE_CAS(RCLASS(klass)->object_id, 0, id);
|
||||||
|
if (existing_id) {
|
||||||
|
id = existing_id;
|
||||||
|
}
|
||||||
|
else if (RB_UNLIKELY(id_to_obj_tbl)) {
|
||||||
|
st_insert(id_to_obj_tbl, id, klass);
|
||||||
|
}
|
||||||
|
rb_gc_vm_unlock(lock_lev);
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
object_id(VALUE obj)
|
object_id(VALUE obj)
|
||||||
{
|
{
|
||||||
|
switch (BUILTIN_TYPE(obj)) {
|
||||||
|
case T_CLASS:
|
||||||
|
case T_MODULE:
|
||||||
|
// With namespaces, classes and modules have different fields
|
||||||
|
// in different namespaces, so we cannot store the object id
|
||||||
|
// in fields.
|
||||||
|
return class_object_id(obj);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
VALUE id = Qfalse;
|
VALUE id = Qfalse;
|
||||||
unsigned int lock_lev;
|
unsigned int lock_lev;
|
||||||
|
|
||||||
@ -1896,9 +1929,20 @@ static void
|
|||||||
build_id_to_obj_i(VALUE obj, void *data)
|
build_id_to_obj_i(VALUE obj, void *data)
|
||||||
{
|
{
|
||||||
st_table *id_to_obj_tbl = (st_table *)data;
|
st_table *id_to_obj_tbl = (st_table *)data;
|
||||||
|
|
||||||
|
switch (BUILTIN_TYPE(obj)) {
|
||||||
|
case T_CLASS:
|
||||||
|
case T_MODULE:
|
||||||
|
if (RCLASS(obj)->object_id) {
|
||||||
|
st_insert(id_to_obj_tbl, RCLASS(obj)->object_id, obj);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
if (rb_shape_obj_has_id(obj)) {
|
if (rb_shape_obj_has_id(obj)) {
|
||||||
st_insert(id_to_obj_tbl, rb_obj_id(obj), obj);
|
st_insert(id_to_obj_tbl, rb_obj_id(obj), obj);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
@ -1940,9 +1984,24 @@ object_id_to_ref(void *objspace_ptr, VALUE object_id)
|
|||||||
static inline void
|
static inline void
|
||||||
obj_free_object_id(VALUE obj)
|
obj_free_object_id(VALUE obj)
|
||||||
{
|
{
|
||||||
|
VALUE obj_id = 0;
|
||||||
if (RB_UNLIKELY(id_to_obj_tbl)) {
|
if (RB_UNLIKELY(id_to_obj_tbl)) {
|
||||||
|
switch (BUILTIN_TYPE(obj)) {
|
||||||
|
case T_CLASS:
|
||||||
|
case T_MODULE:
|
||||||
|
if (RCLASS(obj)->object_id) {
|
||||||
|
obj_id = RCLASS(obj)->object_id;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
if (rb_shape_obj_has_id(obj)) {
|
if (rb_shape_obj_has_id(obj)) {
|
||||||
VALUE obj_id = object_id(obj);
|
obj_id = object_id(obj);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RB_UNLIKELY(obj_id)) {
|
||||||
RUBY_ASSERT(FIXNUM_P(obj_id) || RB_TYPE_P(obj, T_BIGNUM));
|
RUBY_ASSERT(FIXNUM_P(obj_id) || RB_TYPE_P(obj, T_BIGNUM));
|
||||||
|
|
||||||
if (!st_delete(id_to_obj_tbl, (st_data_t *)&obj_id, NULL)) {
|
if (!st_delete(id_to_obj_tbl, (st_data_t *)&obj_id, NULL)) {
|
||||||
@ -1952,7 +2011,6 @@ obj_free_object_id(VALUE obj)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -138,6 +138,7 @@ STATIC_ASSERT(shape_max_variations, SHAPE_MAX_VARIATIONS < (1 << (sizeof(((rb_cl
|
|||||||
struct RClass {
|
struct RClass {
|
||||||
struct RBasic basic;
|
struct RBasic basic;
|
||||||
st_table *ns_classext_tbl; // ns_object -> (rb_classext_t *)
|
st_table *ns_classext_tbl; // ns_object -> (rb_classext_t *)
|
||||||
|
VALUE object_id;
|
||||||
/*
|
/*
|
||||||
* If ns_classext_tbl is NULL, then the prime classext is readable (because no other classext exists).
|
* If ns_classext_tbl is NULL, then the prime classext is readable (because no other classext exists).
|
||||||
* For the check whether writable or not, check flag RCLASS_PRIME_CLASSEXT_WRITABLE
|
* For the check whether writable or not, check flag RCLASS_PRIME_CLASSEXT_WRITABLE
|
||||||
|
Loading…
x
Reference in New Issue
Block a user