Batch cleanup geniv before sweep

Previously we needed to check every object to determine whether or not
it might have an entry in the geniv table.

This commit adds a function, rb_gc_vm_weak_table_essential_p, which
allows gc.c to decide which tables to always handle in batch.

MMTK will continue to call rb_gc_vm_weak_table_foreach on all tables.
This only changes the default GC to sweep the "essential" tables first,
but continue to call rb_gc_obj_free_vm_weak_references on other objects.

This makes the geniv table "essental", as it's usually small and needs
to be tested on every type of object. It leaves the fstring table,
symbol table, callinfo table, and overloaded CME table as-is because
those tables are (mostly) larger and are only needed by specific object
types.
This commit is contained in:
John Hawthorn committed 2026-07-15 13:54:14 -07:00
1 parent a758990d44
commit f7eca0d41e
3 files changed
+35 -9
Notes: git 2026-07-15 20:54:42 +00:00

No files matched your search

+14 -9
View File
@@ -1411,11 +1411,6 @@ rb_gc_obj_needs_cleanup_p(VALUE obj)
return rb_gc_imemo_needs_cleanup_p(obj);
}
shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
if (rb_shape_has_fields(shape_id) && rb_shape_layout(shape_id) == SHAPE_ID_LAYOUT_OTHER) {
return true;
}
switch (flags & RUBY_T_MASK) {
case T_FLOAT:
case T_RATIONAL:
@@ -2162,10 +2157,6 @@ rb_gc_obj_free_vm_weak_references(VALUE obj)
{
ASSUME(!RB_SPECIAL_CONST_P(obj));
if (rb_obj_gen_fields_p(obj)) {
rb_free_generic_ivar(obj);
}
switch (BUILTIN_TYPE(obj)) {
case T_STRING:
if (FL_TEST_RAW(obj, RSTRING_FSTR)) {
@@ -4048,6 +4039,20 @@ vm_weak_table_frozen_strings_foreach(VALUE *str, void *data)
}
void rb_fstring_foreach_with_replace(int (*callback)(VALUE *str, void *data), void *data);
// Whether this table must be cleaned every GC after marking.
// Other tables may be skipped cleaned up per-object via rb_gc_obj_free_vm_weak_references.
bool
rb_gc_vm_weak_table_essential_p(enum rb_gc_vm_weak_tables table)
{
switch (table) {
case RB_GC_VM_GENERIC_FIELDS_TABLE:
return true;
default:
return false;
}
}
void
rb_gc_vm_weak_table_foreach(vm_table_foreach_callback_func callback,
vm_table_update_callback_func update_callback,
+20
View File
@@ -4232,6 +4232,15 @@ gc_sweep_freeobj_hooks(rb_objspace_t *objspace)
}
}
static int
gc_sweep_weak_table_i(VALUE val, void *data)
{
rb_objspace_t *objspace = data;
if (RB_SPECIAL_CONST_P(val)) return ST_CONTINUE;
if (RVALUE_MARKED(objspace, val)) return ST_CONTINUE;
return ST_DELETE;
}
static void
gc_sweep_start(rb_objspace_t *objspace)
{
@@ -4242,6 +4251,17 @@ gc_sweep_start(rb_objspace_t *objspace)
gc_sweep_freeobj_hooks(objspace);
}
for (int table = 0; table < RB_GC_VM_WEAK_TABLE_COUNT; table++) {
if (!rb_gc_vm_weak_table_essential_p(table)) continue;
rb_gc_vm_weak_table_foreach(
gc_sweep_weak_table_i,
NULL,
objspace,
true,
table
);
}
#if GC_CAN_COMPILE_COMPACTION
if (objspace->flags.during_compacting) {
gc_sort_heap_by_compare_func(
+1
View File
@@ -92,6 +92,7 @@ MODULAR_GC_FN void rb_gc_vm_unlock_no_barrier(unsigned int lev, const char *file
MODULAR_GC_FN void rb_gc_vm_barrier(void);
MODULAR_GC_FN size_t rb_gc_obj_optimal_size(VALUE obj);
MODULAR_GC_FN void rb_gc_mark_children(void *objspace, VALUE obj);
MODULAR_GC_FN bool rb_gc_vm_weak_table_essential_p(enum rb_gc_vm_weak_tables table);
MODULAR_GC_FN void rb_gc_vm_weak_table_foreach(vm_table_foreach_callback_func callback, vm_table_update_callback_func update_callback, void *data, bool weak_only, enum rb_gc_vm_weak_tables table);
MODULAR_GC_FN void rb_gc_update_object_references(void *objspace, VALUE obj);
MODULAR_GC_FN void rb_gc_update_vm_references(void *objspace);