Faster rb_gc_handle_weak_references

Pass objspace throughout the call chain.

For a script with 100k callcaches, major GC time improved for bothh
single-ractor and multi-ractor.

| Configuration | Baseline | Patched | Δ |
|---|---|---|---|
| single-ractor | 14.04 ms/major GC | 13.60 ms/major GC | **-3.1%** |
| multi-ractor | 18.55 ms/major GC | 17.25 ms/major GC | **-7.0%** |
This commit is contained in:
Luke Gruber 2026-10-23 12:52:28 -04:00 committed by Luke Gruber
parent eb1a765b9a
commit b62abdae8b
Notes: git 2026-10-28 22:46:35 +00:00
11 changed files with 48 additions and 33 deletions

12
cont.c
View File

@ -1506,14 +1506,14 @@ cont_save_machine_stack(rb_thread_t *th, rb_context_t *cont)
}
static void
cont_handle_weak_references(void *ptr)
cont_handle_weak_references(void *ptr, void *objspace)
{
rb_context_t *cont = ptr;
if (!cont) return;
if (!rb_gc_handle_weak_references_alive_p(cont->saved_ec.gen_fields_cache.obj) ||
!rb_gc_handle_weak_references_alive_p(cont->saved_ec.gen_fields_cache.fields_obj)) {
if (!rb_gc_handle_weak_references_alive_p(objspace, cont->saved_ec.gen_fields_cache.obj) ||
!rb_gc_handle_weak_references_alive_p(objspace, cont->saved_ec.gen_fields_cache.fields_obj)) {
cont->saved_ec.gen_fields_cache.obj = Qundef;
cont->saved_ec.gen_fields_cache.fields_obj = Qundef;
}
@ -2267,14 +2267,14 @@ rb_cont_call(int argc, VALUE *argv, VALUE contval)
*/
static void
fiber_handle_weak_references(void *ptr)
fiber_handle_weak_references(void *ptr, void *objspace)
{
rb_fiber_t *fiber = ptr;
if (!fiber) return;
if (!rb_gc_handle_weak_references_alive_p(fiber->cont.saved_ec.gen_fields_cache.obj) ||
!rb_gc_handle_weak_references_alive_p(fiber->cont.saved_ec.gen_fields_cache.fields_obj)) {
if (!rb_gc_handle_weak_references_alive_p(objspace, fiber->cont.saved_ec.gen_fields_cache.obj) ||
!rb_gc_handle_weak_references_alive_p(objspace, fiber->cont.saved_ec.gen_fields_cache.fields_obj)) {
fiber->cont.saved_ec.gen_fields_cache.obj = Qundef;
fiber->cont.saved_ec.gen_fields_cache.fields_obj = Qundef;
}

View File

@ -160,13 +160,19 @@ allocation_info_tracer_memsize(const void *ptr)
return size;
}
struct allocation_info_weak_reference_arg {
struct traceobj_arg *arg;
void *objspace;
};
static int
allocation_info_tracer_weak_reference_i(st_data_t key, st_data_t value, st_data_t data)
{
struct traceobj_arg *arg = (struct traceobj_arg *)data;
struct allocation_info_weak_reference_arg *wrarg = (struct allocation_info_weak_reference_arg *)data;
struct traceobj_arg *arg = wrarg->arg;
struct allocation_info *info = (struct allocation_info *)value;
if (rb_gc_handle_weak_references_alive_p((VALUE)key)) {
if (rb_gc_handle_weak_references_alive_p(wrarg->objspace, (VALUE)key)) {
return ST_CONTINUE;
}
@ -184,11 +190,12 @@ allocation_info_tracer_weak_reference_i(st_data_t key, st_data_t value, st_data_
}
static void
allocation_info_tracer_weak_reference(void *ptr)
allocation_info_tracer_weak_reference(void *ptr, void *objspace)
{
struct traceobj_arg *arg = (struct traceobj_arg *)ptr;
struct allocation_info_weak_reference_arg wrarg = {arg, objspace};
st_foreach(arg->object_table, allocation_info_tracer_weak_reference_i, (st_data_t)arg);
st_foreach(arg->object_table, allocation_info_tracer_weak_reference_i, (st_data_t)&wrarg);
}
static int

22
gc.c
View File

@ -1501,16 +1501,22 @@ rb_gc_declare_weak_references(VALUE obj)
rb_gc_impl_declare_weak_references(rb_gc_get_objspace(), obj);
}
bool
rb_gc_handle_weak_references_alive_p(VALUE obj)
static inline bool
gc_weak_reference_alive_p(void *objspace, VALUE obj)
{
if (SPECIAL_CONST_P(obj)) return true;
return rb_gc_impl_handle_weak_references_alive_p(rb_gc_get_objspace(), obj);
return rb_gc_impl_handle_weak_references_alive_p(objspace, obj);
}
bool
rb_gc_handle_weak_references_alive_p(void *objspace, VALUE obj)
{
return gc_weak_reference_alive_p(objspace, obj);
}
void
rb_gc_handle_weak_references(VALUE obj)
rb_gc_handle_weak_references(void *objspace, VALUE obj)
{
switch (BUILTIN_TYPE(obj)) {
case T_DATA:
@ -1518,7 +1524,7 @@ rb_gc_handle_weak_references(VALUE obj)
const rb_data_type_t *type = RTYPEDDATA_TYPE(obj);
if (type->function.handle_weak_references) {
(type->function.handle_weak_references)(RTYPEDDATA_GET_DATA(obj));
(type->function.handle_weak_references)(RTYPEDDATA_GET_DATA(obj), objspace);
}
else {
rb_bug(
@ -1534,8 +1540,8 @@ rb_gc_handle_weak_references(VALUE obj)
case imemo_callcache: {
struct rb_callcache *cc = (struct rb_callcache *)obj;
if (cc->klass != Qundef &&
(!rb_gc_handle_weak_references_alive_p(cc->klass) ||
!rb_gc_handle_weak_references_alive_p((VALUE)cc->cme_))) {
(!gc_weak_reference_alive_p(objspace, cc->klass) ||
!gc_weak_reference_alive_p(objspace, (VALUE)cc->cme_))) {
vm_cc_invalidate(cc);
}
break;
@ -1544,7 +1550,7 @@ rb_gc_handle_weak_references(VALUE obj)
struct rb_subclasses *subs = (struct rb_subclasses *)obj;
VALUE *entries = rb_imemo_subclasses_entries(obj);
for (uint32_t i = 0; i < subs->count; i++) {
if (entries[i] && !rb_gc_handle_weak_references_alive_p(entries[i])) {
if (entries[i] && !gc_weak_reference_alive_p(objspace, entries[i])) {
entries[i] = 0;
}
}

View File

@ -7665,7 +7665,7 @@ gc_update_weak_references(rb_objspace_t *objspace)
VALUE *obj_ptr;
rb_darray_foreach(objspace->weak_references, i, obj_ptr) {
gc_mark_set_parent(objspace, *obj_ptr);
rb_gc_handle_weak_references(*obj_ptr);
rb_gc_handle_weak_references(objspace, *obj_ptr);
gc_mark_set_parent_invalid(objspace);
}

View File

@ -122,7 +122,7 @@ MODULAR_GC_FN void rb_gc_before_updating_jit_code(void);
MODULAR_GC_FN void rb_gc_after_updating_jit_code(void);
MODULAR_GC_FN bool rb_gc_obj_shareable_p(VALUE);
MODULAR_GC_FN void rb_gc_rp(VALUE);
MODULAR_GC_FN void rb_gc_handle_weak_references(VALUE obj);
MODULAR_GC_FN void rb_gc_handle_weak_references(void *objspace, VALUE obj);
MODULAR_GC_FN bool rb_gc_obj_needs_cleanup_p(VALUE obj);
/* True when a dead T_DATA of this type cannot have its dfree run during a parallel

View File

@ -363,7 +363,7 @@ rb_mmtk_handle_weak_references(MMTk_ObjectReference mmtk_object, bool moving)
marking_parent_object = object;
rb_gc_handle_weak_references(object);
rb_gc_handle_weak_references(rb_gc_get_objspace(), object);
if (moving) {
rb_gc_update_object_references(rb_gc_get_objspace(), object);

View File

@ -981,7 +981,7 @@ wbcheck_process_weak_references(rb_wbcheck_objspace_t *objspace)
for (size_t i = 0; i < objspace->weak_references->count; i++) {
VALUE obj = objspace->weak_references->items[i];
rb_gc_handle_weak_references(obj);
rb_gc_handle_weak_references(objspace, obj);
}
objspace->weak_references->count = 0;

View File

@ -295,7 +295,7 @@ struct rb_data_type_struct {
/**
* @internal
*/
void (*handle_weak_references)(void *);
void (*handle_weak_references)(void *, void *objspace);
/**
* This field is reserved for future extension. For now, it must be

View File

@ -306,7 +306,7 @@ int rb_objspace_garbage_object_p(VALUE obj);
int rb_objspace_foreign_object_p(VALUE obj);
int rb_objspace_live_object_p(VALUE obj);
void rb_gc_declare_weak_references(VALUE obj);
bool rb_gc_handle_weak_references_alive_p(VALUE obj);
bool rb_gc_handle_weak_references_alive_p(void *objspace, VALUE obj);
void rb_objspace_each_objects(
int (*callback)(void *start, void *end, size_t stride, void *data),

View File

@ -781,12 +781,12 @@ cc_refinement_set_compact(void *ptr)
}
static void
cc_refinement_set_handle_weak_references(void *ptr)
cc_refinement_set_handle_weak_references(void *ptr, void *objspace)
{
struct cc_refinement_entries *e = ptr;
size_t write = 0;
for (size_t read = 0; read < e->len; read++) {
if (rb_gc_handle_weak_references_alive_p(e->entries[read])) {
if (rb_gc_handle_weak_references_alive_p(objspace, e->entries[read])) {
e->entries[write++] = e->entries[read];
}
}

View File

@ -113,8 +113,10 @@ wmap_compact(void *ptr)
static int
rb_wmap_handle_weak_references_i(st_data_t key, st_data_t val, st_data_t arg)
{
if (rb_gc_handle_weak_references_alive_p(key) &&
rb_gc_handle_weak_references_alive_p(val)) {
void *objspace = (void *)arg;
if (rb_gc_handle_weak_references_alive_p(objspace, key) &&
rb_gc_handle_weak_references_alive_p(objspace, val)) {
return ST_CONTINUE;
}
else {
@ -123,11 +125,11 @@ rb_wmap_handle_weak_references_i(st_data_t key, st_data_t val, st_data_t arg)
}
static void
wmap_handle_weak_references(void *ptr)
wmap_handle_weak_references(void *ptr, void *objspace)
{
struct weakmap *w = ptr;
st_foreach(w->table, rb_wmap_handle_weak_references_i, (st_data_t)0);
st_foreach(w->table, rb_wmap_handle_weak_references_i, (st_data_t)objspace);
}
static const rb_data_type_t rb_weakmap_type = {
@ -616,7 +618,7 @@ wkmap_compact(void *ptr)
static int
rb_wkmap_handle_weak_references_i(st_data_t key, st_data_t val, st_data_t arg)
{
if (rb_gc_handle_weak_references_alive_p(key)) {
if (rb_gc_handle_weak_references_alive_p((void *)arg, key)) {
return ST_CONTINUE;
}
else {
@ -625,11 +627,11 @@ rb_wkmap_handle_weak_references_i(st_data_t key, st_data_t val, st_data_t arg)
}
static void
wkmap_handle_weak_references(void *ptr)
wkmap_handle_weak_references(void *ptr, void *objspace)
{
struct weakkeymap *w = ptr;
st_foreach(w->table, rb_wkmap_handle_weak_references_i, (st_data_t)0);
st_foreach(w->table, rb_wkmap_handle_weak_references_i, (st_data_t)objspace);
}
static const rb_data_type_t rb_weakkeymap_type = {