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:
parent
c3c7300b89
commit
9e5ff79c5b
Notes:
git
2025-01-27 15:28:55 +00:00
146
gc.c
146
gc.c
@ -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
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
2
gc/gc.h
2
gc/gc.h
@ -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
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user