summaryrefslogtreecommitdiff
path: root/gc.c
diff options
context:
space:
mode:
authorJean Boussier <jean.boussier@gmail.com>2025-05-22 14:01:46 +0200
committerJean Boussier <jean.boussier@gmail.com>2025-06-12 07:58:16 +0200
commit3abdd4241fd5231a5711ce1b087d660c667ef30d (patch)
treeddcdd184ca6720bac671cf296a5b7474a22477f5 /gc.c
parent166ff187bd2a84fddd7a633bdbdbcd4ae393c91e (diff)
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.
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/13411
Diffstat (limited to 'gc.c')
-rw-r--r--gc.c54
1 files changed, 2 insertions, 52 deletions
diff --git a/gc.c b/gc.c
index 05cefc739b..aefe8a116b 100644
--- a/gc.c
+++ b/gc.c
@@ -1201,7 +1201,6 @@ rb_data_free(void *objspace, VALUE obj)
struct classext_foreach_args {
VALUE klass;
- bool obj_too_complex;
rb_objspace_t *objspace; // used for update_*
};
@@ -1213,12 +1212,6 @@ classext_free(rb_classext_t *ext, bool is_prime, VALUE namespace, void *arg)
rb_id_table_free(RCLASSEXT_M_TBL(ext));
rb_cc_tbl_free(RCLASSEXT_CC_TBL(ext), args->klass);
- if (args->obj_too_complex) {
- st_free_table((st_table *)RCLASSEXT_FIELDS(ext));
- }
- else {
- xfree(RCLASSEXT_FIELDS(ext));
- }
if (!RCLASSEXT_SHARED_CONST_TBL(ext) && (tbl = RCLASSEXT_CONST_TBL(ext)) != NULL) {
rb_free_const_table(tbl);
}
@@ -1292,8 +1285,6 @@ rb_gc_obj_free(void *objspace, VALUE obj)
case T_MODULE:
case T_CLASS:
args.klass = obj;
- args.obj_too_complex = rb_shape_obj_too_complex_p(obj) ? true : false;
-
rb_class_classext_foreach(obj, classext_free, (void *)&args);
if (RCLASS(obj)->ns_classext_tbl) {
st_free_table(RCLASS(obj)->ns_classext_tbl);
@@ -2306,18 +2297,6 @@ classext_memsize(rb_classext_t *ext, bool prime, VALUE namespace, void *arg)
}
static void
-classext_fields_hash_memsize(rb_classext_t *ext, bool prime, VALUE namespace, void *arg)
-{
- size_t *size = (size_t *)arg;
- size_t count;
- RB_VM_LOCKING() {
- count = rb_st_table_size((st_table *)RCLASSEXT_FIELDS(ext));
- }
- // class IV sizes are allocated as powers of two
- *size += SIZEOF_VALUE << bit_length(count);
-}
-
-static void
classext_superclasses_memsize(rb_classext_t *ext, bool prime, VALUE namespace, void *arg)
{
size_t *size = (size_t *)arg;
@@ -2354,15 +2333,6 @@ rb_obj_memsize_of(VALUE obj)
case T_MODULE:
case T_CLASS:
rb_class_classext_foreach(obj, classext_memsize, (void *)&size);
-
- if (rb_shape_obj_too_complex_p(obj)) {
- rb_class_classext_foreach(obj, classext_fields_hash_memsize, (void *)&size);
- }
- else {
- // class IV sizes are allocated as powers of two
- size += SIZEOF_VALUE << bit_length(RCLASS_FIELDS_COUNT(obj));
- }
-
rb_class_classext_foreach(obj, classext_superclasses_memsize, (void *)&size);
break;
case T_ICLASS:
@@ -3135,10 +3105,7 @@ gc_mark_classext_module(rb_classext_t *ext, bool prime, VALUE namespace, void *a
gc_mark_internal(RCLASSEXT_SUPER(ext));
}
mark_m_tbl(objspace, RCLASSEXT_M_TBL(ext));
- if (rb_shape_obj_too_complex_p(obj)) {
- gc_mark_tbl_no_pin((st_table *)RCLASSEXT_FIELDS(ext));
- // for the case ELSE is written in rb_gc_mark_children() because it's per RClass, not classext
- }
+ gc_mark_internal(RCLASSEXT_FIELDS_OBJ(ext));
if (!RCLASSEXT_SHARED_CONST_TBL(ext) && RCLASSEXT_CONST_TBL(ext)) {
mark_const_tbl(objspace, RCLASSEXT_CONST_TBL(ext));
}
@@ -3218,12 +3185,6 @@ rb_gc_mark_children(void *objspace, VALUE obj)
foreach_args.objspace = objspace;
foreach_args.obj = obj;
rb_class_classext_foreach(obj, gc_mark_classext_module, (void *)&foreach_args);
-
- if (!rb_shape_obj_too_complex_p(obj)) {
- for (attr_index_t i = 0; i < RCLASS_FIELDS_COUNT(obj); i++) {
- gc_mark_internal(RCLASS_PRIME_FIELDS(obj)[i]);
- }
- }
break;
case T_ICLASS:
@@ -3849,7 +3810,6 @@ static void
update_classext(rb_classext_t *ext, bool is_prime, VALUE namespace, void *arg)
{
struct classext_foreach_args *args = (struct classext_foreach_args *)arg;
- VALUE klass = args->klass;
rb_objspace_t *objspace = args->objspace;
if (RCLASSEXT_SUPER(ext)) {
@@ -3858,16 +3818,7 @@ update_classext(rb_classext_t *ext, bool is_prime, VALUE namespace, void *arg)
update_m_tbl(objspace, RCLASSEXT_M_TBL(ext));
- if (args->obj_too_complex) {
- gc_ref_update_table_values_only((st_table *)RCLASSEXT_FIELDS(ext));
- }
- else {
- // Classext is not copied in this case
- for (attr_index_t i = 0; i < RCLASS_FIELDS_COUNT(klass); i++) {
- UPDATE_IF_MOVED(objspace, RCLASSEXT_FIELDS(RCLASS_EXT_PRIME(klass))[i]);
- }
- }
-
+ UPDATE_IF_MOVED(objspace, ext->fields_obj);
if (!RCLASSEXT_SHARED_CONST_TBL(ext)) {
update_const_tbl(objspace, RCLASSEXT_CONST_TBL(ext));
}
@@ -4255,7 +4206,6 @@ rb_gc_update_object_references(void *objspace, VALUE obj)
// Continue to the shared T_CLASS/T_MODULE
case T_MODULE:
args.klass = obj;
- args.obj_too_complex = rb_shape_obj_too_complex_p(obj);
args.objspace = objspace;
rb_class_classext_foreach(obj, update_classext, (void *)&args);
break;