Turn rb_classext_t.fields into a T_IMEMO/class_fields

This behave almost exactly as a T_OBJECT, the layout is entirely
compatible.

This aims to solve two problems.

First, it solves the problem of namspaced classes having
a single `shape_id`. Now each namespaced classext
has an object that can hold the namespace specific
shape.

Second, it open the door to later make class instance variable
writes atomics, hence be able to read class variables
without locking the VM.
In the future, in multi-ractor mode, we can do the write
on a copy of the `fields_obj` and then atomically swap it.

Considerations:

  - Right now the `RClass` shape_id is always synchronized,
    but with namespace we should likely mark classes that have
    multiple namespace with a specific shape flag.
This commit is contained in:
Jean Boussier 2025-05-22 14:01:46 +02:00
parent 166ff187bd
commit 3abdd4241f
Notes: git 2025-06-12 05:58:29 +00:00
14 changed files with 435 additions and 218 deletions

18
shape.c
View file

@ -396,6 +396,13 @@ rb_obj_shape_id(VALUE obj)
return SPECIAL_CONST_SHAPE_ID;
}
if (BUILTIN_TYPE(obj) == T_CLASS || BUILTIN_TYPE(obj) == T_MODULE) {
VALUE fields_obj = RCLASS_FIELDS_OBJ(obj);
if (fields_obj) {
return RBASIC_SHAPE_ID(fields_obj);
}
return ROOT_SHAPE_ID;
}
return RBASIC_SHAPE_ID(obj);
}
@ -881,14 +888,11 @@ shape_get_next(rb_shape_t *shape, VALUE obj, ID id, bool emit_warnings)
#endif
VALUE klass;
switch (BUILTIN_TYPE(obj)) {
case T_CLASS:
case T_MODULE:
klass = rb_singleton_class(obj);
break;
default:
if (IMEMO_TYPE_P(obj, imemo_class_fields)) { // HACK
klass = CLASS_OF(obj);
}
else {
klass = rb_obj_class(obj);
break;
}
bool allow_new_shape = RCLASS_VARIATION_COUNT(klass) < SHAPE_MAX_VARIATIONS;