Optionally traverse non-weak references in rb_gc_vm_weak_table_foreach

For moving garbage collectors, we may want to combine liveliness checking
with reference updating for performance. This commit allows for non-weak
references to be passed into the callback function when weak_only is false.
This commit is contained in:
Peter Zhu 2025-01-23 10:28:29 -05:00
parent c3c7300b89
commit 9e5ff79c5b
Notes: git 2025-01-27 15:28:55 +00:00
2 changed files with 124 additions and 24 deletions

146
gc.c
View File

@ -3346,22 +3346,39 @@ struct global_vm_table_foreach_data {
vm_table_foreach_callback_func callback; vm_table_foreach_callback_func callback;
vm_table_update_callback_func update_callback; vm_table_update_callback_func update_callback;
void *data; void *data;
bool weak_only;
}; };
static int static int
vm_weak_table_foreach_key(st_data_t key, st_data_t value, st_data_t data, int error) vm_weak_table_foreach_weak_key(st_data_t key, st_data_t value, st_data_t data, int error)
{ {
struct global_vm_table_foreach_data *iter_data = (struct global_vm_table_foreach_data *)data; struct global_vm_table_foreach_data *iter_data = (struct global_vm_table_foreach_data *)data;
return iter_data->callback((VALUE)key, iter_data->data); int ret = iter_data->callback((VALUE)key, iter_data->data);
if (!iter_data->weak_only) {
if (ret != ST_CONTINUE) return ret;
ret = iter_data->callback((VALUE)value, iter_data->data);
}
return ret;
} }
static int static int
vm_weak_table_foreach_update_key(st_data_t *key, st_data_t *value, st_data_t data, int existing) vm_weak_table_foreach_update_weak_key(st_data_t *key, st_data_t *value, st_data_t data, int existing)
{ {
struct global_vm_table_foreach_data *iter_data = (struct global_vm_table_foreach_data *)data; struct global_vm_table_foreach_data *iter_data = (struct global_vm_table_foreach_data *)data;
return iter_data->update_callback((VALUE *)key, iter_data->data); int ret = iter_data->update_callback((VALUE *)key, iter_data->data);
if (!iter_data->weak_only) {
if (ret != ST_CONTINUE) return ret;
ret = iter_data->update_callback((VALUE *)value, iter_data->data);
}
return ret;
} }
static int static int
@ -3369,6 +3386,11 @@ vm_weak_table_str_sym_foreach(st_data_t key, st_data_t value, st_data_t data, in
{ {
struct global_vm_table_foreach_data *iter_data = (struct global_vm_table_foreach_data *)data; struct global_vm_table_foreach_data *iter_data = (struct global_vm_table_foreach_data *)data;
if (!iter_data->weak_only) {
int ret = iter_data->callback((VALUE)key, iter_data->data);
if (ret != ST_CONTINUE) return ret;
}
if (STATIC_SYM_P(value)) { if (STATIC_SYM_P(value)) {
return ST_CONTINUE; return ST_CONTINUE;
} }
@ -3378,10 +3400,15 @@ vm_weak_table_str_sym_foreach(st_data_t key, st_data_t value, st_data_t data, in
} }
static int static int
vm_weak_table_foreach_update_value(st_data_t *key, st_data_t *value, st_data_t data, int existing) vm_weak_table_foreach_update_weak_value(st_data_t *key, st_data_t *value, st_data_t data, int existing)
{ {
struct global_vm_table_foreach_data *iter_data = (struct global_vm_table_foreach_data *)data; struct global_vm_table_foreach_data *iter_data = (struct global_vm_table_foreach_data *)data;
if (!iter_data->weak_only) {
int ret = iter_data->update_callback((VALUE *)key, iter_data->data);
if (ret != ST_CONTINUE) return ret;
}
return iter_data->update_callback((VALUE *)value, iter_data->data); return iter_data->update_callback((VALUE *)value, iter_data->data);
} }
@ -3396,35 +3423,108 @@ free_gen_ivtbl(VALUE obj, struct gen_ivtbl *ivtbl)
} }
static int static int
vm_weak_table_gen_ivar_foreach(st_data_t key, st_data_t value, st_data_t data, int error) vm_weak_table_gen_ivar_foreach_too_complex_i(st_data_t _key, st_data_t value, st_data_t data, int error)
{ {
int retval = vm_weak_table_foreach_key(key, value, data, error); struct global_vm_table_foreach_data *iter_data = (struct global_vm_table_foreach_data *)data;
if (retval == ST_DELETE) {
GC_ASSERT(!iter_data->weak_only);
return iter_data->callback((VALUE)value, iter_data->data);
}
static int
vm_weak_table_gen_ivar_foreach_too_complex_replace_i(st_data_t *_key, st_data_t *value, st_data_t data, int existing)
{
struct global_vm_table_foreach_data *iter_data = (struct global_vm_table_foreach_data *)data;
GC_ASSERT(!iter_data->weak_only);
return iter_data->update_callback((VALUE *)value, iter_data->data);
}
struct st_table *rb_generic_ivtbl_get(void);
static int
vm_weak_table_gen_ivar_foreach(st_data_t key, st_data_t value, st_data_t data)
{
struct global_vm_table_foreach_data *iter_data = (struct global_vm_table_foreach_data *)data;
int ret = iter_data->callback((VALUE)key, iter_data->data);
switch (ret) {
case ST_CONTINUE:
break;
case ST_DELETE:
free_gen_ivtbl((VALUE)key, (struct gen_ivtbl *)value); free_gen_ivtbl((VALUE)key, (struct gen_ivtbl *)value);
FL_UNSET((VALUE)key, FL_EXIVAR); FL_UNSET((VALUE)key, FL_EXIVAR);
return ST_DELETE;
case ST_REPLACE: {
VALUE new_key = (VALUE)key;
ret = iter_data->update_callback(&new_key, iter_data->data);
if (key != new_key) ret = ST_DELETE;
DURING_GC_COULD_MALLOC_REGION_START();
{
st_insert(rb_generic_ivtbl_get(), (st_data_t)new_key, value);
}
DURING_GC_COULD_MALLOC_REGION_END();
key = (st_data_t)new_key;
break;
}
default:
return ret;
} }
return retval;
if (!iter_data->weak_only) {
struct gen_ivtbl *ivtbl = (struct gen_ivtbl *)value;
if (rb_shape_obj_too_complex((VALUE)key)) {
st_foreach_with_replace(
ivtbl->as.complex.table,
vm_weak_table_gen_ivar_foreach_too_complex_i,
vm_weak_table_gen_ivar_foreach_too_complex_replace_i,
data
);
}
else {
for (uint32_t i = 0; i < ivtbl->as.shape.numiv; i++) {
if (SPECIAL_CONST_P(ivtbl->as.shape.ivptr[i])) continue;
int ivar_ret = iter_data->callback(ivtbl->as.shape.ivptr[i], iter_data->data);
switch (ivar_ret) {
case ST_CONTINUE:
break;
case ST_REPLACE:
iter_data->update_callback(&ivtbl->as.shape.ivptr[i], iter_data->data);
break;
default:
rb_bug("vm_weak_table_gen_ivar_foreach: return value %d not supported", ivar_ret);
}
}
}
}
return ret;
} }
static int static int
vm_weak_table_frozen_strings_foreach(st_data_t key, st_data_t value, st_data_t data, int error) vm_weak_table_frozen_strings_foreach(st_data_t key, st_data_t value, st_data_t data, int error)
{ {
GC_ASSERT(RB_TYPE_P((VALUE)key, T_STRING)); int retval = vm_weak_table_foreach_weak_key(key, value, data, error);
int retval = vm_weak_table_foreach_key(key, value, data, error);
if (retval == ST_DELETE) { if (retval == ST_DELETE) {
FL_UNSET((VALUE)key, RSTRING_FSTR); FL_UNSET((VALUE)key, RSTRING_FSTR);
} }
return retval; return retval;
} }
struct st_table *rb_generic_ivtbl_get(void);
void void
rb_gc_vm_weak_table_foreach(vm_table_foreach_callback_func callback, rb_gc_vm_weak_table_foreach(vm_table_foreach_callback_func callback,
vm_table_update_callback_func update_callback, vm_table_update_callback_func update_callback,
void *data, void *data,
bool weak_only,
enum rb_gc_vm_weak_tables table) enum rb_gc_vm_weak_tables table)
{ {
rb_vm_t *vm = GET_VM(); rb_vm_t *vm = GET_VM();
@ -3432,7 +3532,8 @@ rb_gc_vm_weak_table_foreach(vm_table_foreach_callback_func callback,
struct global_vm_table_foreach_data foreach_data = { struct global_vm_table_foreach_data foreach_data = {
.callback = callback, .callback = callback,
.update_callback = update_callback, .update_callback = update_callback,
.data = data .data = data,
.weak_only = weak_only,
}; };
switch (table) { switch (table) {
@ -3440,8 +3541,8 @@ rb_gc_vm_weak_table_foreach(vm_table_foreach_callback_func callback,
if (vm->ci_table) { if (vm->ci_table) {
st_foreach_with_replace( st_foreach_with_replace(
vm->ci_table, vm->ci_table,
vm_weak_table_foreach_key, vm_weak_table_foreach_weak_key,
vm_weak_table_foreach_update_key, vm_weak_table_foreach_update_weak_key,
(st_data_t)&foreach_data (st_data_t)&foreach_data
); );
} }
@ -3451,8 +3552,8 @@ rb_gc_vm_weak_table_foreach(vm_table_foreach_callback_func callback,
if (vm->overloaded_cme_table) { if (vm->overloaded_cme_table) {
st_foreach_with_replace( st_foreach_with_replace(
vm->overloaded_cme_table, vm->overloaded_cme_table,
vm_weak_table_foreach_key, vm_weak_table_foreach_weak_key,
vm_weak_table_foreach_update_key, vm_weak_table_foreach_update_weak_key,
(st_data_t)&foreach_data (st_data_t)&foreach_data
); );
} }
@ -3463,7 +3564,7 @@ rb_gc_vm_weak_table_foreach(vm_table_foreach_callback_func callback,
st_foreach_with_replace( st_foreach_with_replace(
global_symbols.str_sym, global_symbols.str_sym,
vm_weak_table_str_sym_foreach, vm_weak_table_str_sym_foreach,
vm_weak_table_foreach_update_value, vm_weak_table_foreach_update_weak_value,
(st_data_t)&foreach_data (st_data_t)&foreach_data
); );
} }
@ -3472,10 +3573,9 @@ rb_gc_vm_weak_table_foreach(vm_table_foreach_callback_func callback,
case RB_GC_VM_GENERIC_IV_TABLE: { case RB_GC_VM_GENERIC_IV_TABLE: {
st_table *generic_iv_tbl = rb_generic_ivtbl_get(); st_table *generic_iv_tbl = rb_generic_ivtbl_get();
if (generic_iv_tbl) { if (generic_iv_tbl) {
st_foreach_with_replace( st_foreach(
generic_iv_tbl, generic_iv_tbl,
vm_weak_table_gen_ivar_foreach, vm_weak_table_gen_ivar_foreach,
vm_weak_table_foreach_update_key,
(st_data_t)&foreach_data (st_data_t)&foreach_data
); );
} }
@ -3486,7 +3586,7 @@ rb_gc_vm_weak_table_foreach(vm_table_foreach_callback_func callback,
st_foreach_with_replace( st_foreach_with_replace(
vm->frozen_strings, vm->frozen_strings,
vm_weak_table_frozen_strings_foreach, vm_weak_table_frozen_strings_foreach,
vm_weak_table_foreach_update_key, vm_weak_table_foreach_update_weak_key,
(st_data_t)&foreach_data (st_data_t)&foreach_data
); );
} }

View File

@ -77,7 +77,7 @@ void *rb_gc_get_ractor_newobj_cache(void);
void rb_gc_initialize_vm_context(struct rb_gc_vm_context *context); void rb_gc_initialize_vm_context(struct rb_gc_vm_context *context);
void rb_gc_worker_thread_set_vm_context(struct rb_gc_vm_context *context); void rb_gc_worker_thread_set_vm_context(struct rb_gc_vm_context *context);
void rb_gc_worker_thread_unset_vm_context(struct rb_gc_vm_context *context); void rb_gc_worker_thread_unset_vm_context(struct rb_gc_vm_context *context);
void rb_gc_vm_weak_table_foreach(vm_table_foreach_callback_func callback, vm_table_update_callback_func update_callback, void *data, enum rb_gc_vm_weak_tables table); 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);
#endif #endif
RUBY_SYMBOL_EXPORT_END RUBY_SYMBOL_EXPORT_END