make `overloaded_cme_table` truly weak key map

`overloaded_cme_table` keeps cme -> monly_cme pairs to manage
corresponding `monly_cme` for `cme`. The lifetime of the `monly_cme`
should be longer than `monly_cme`, but the previous patch losts the
reference to the living `monly_cme`.

Now `overloaded_cme_table` values are always root (keys are only weak
reference), it means `monly_cme` does not freed until corresponding
`cme` is invalidated.

To make managing easy, move `overloaded_cme_table` to `rb_vm_t`.
This commit is contained in:
Koichi Sasada 2021-12-21 14:06:02 +09:00
Родитель 3c7e95966d
Коммит ad450c9fe5
4 изменённых файлов: 22 добавлений и 31 удалений

8
gc.c
Просмотреть файл

@ -6379,9 +6379,7 @@ mark_method_entry(rb_objspace_t *objspace, const rb_method_entry_t *me)
if (def->body.iseq.iseqptr) gc_mark(objspace, (VALUE)def->body.iseq.iseqptr);
gc_mark(objspace, (VALUE)def->body.iseq.cref);
if (def->iseq_overload && me->defined_class) { // cme
const rb_callable_method_entry_t *monly_cme = rb_vm_lookup_overloaded_cme((const rb_callable_method_entry_t *)me);
if (monly_cme) {
gc_mark(objspace, (VALUE)monly_cme);
if (rb_vm_lookup_overloaded_cme((const rb_callable_method_entry_t *)me)) {
gc_mark_and_pin(objspace, (VALUE)me);
}
}
@ -10113,9 +10111,6 @@ gc_ref_update(void *vstart, void *vend, size_t stride, rb_objspace_t * objspace,
extern rb_symbols_t ruby_global_symbols;
#define global_symbols ruby_global_symbols
st_table *rb_vm_overloaded_cme_table(void);
static void
gc_update_references(rb_objspace_t *objspace)
{
@ -10151,7 +10146,6 @@ gc_update_references(rb_objspace_t *objspace)
gc_update_table_refs(objspace, objspace->id_to_obj_tbl);
gc_update_table_refs(objspace, global_symbols.str_sym);
gc_update_table_refs(objspace, finalizer_table);
gc_update_table_refs(objspace, rb_vm_overloaded_cme_table());
}
static VALUE

6
vm.c
Просмотреть файл

@ -2540,6 +2540,8 @@ rb_vm_update_references(void *ptr)
vm->top_self = rb_gc_location(vm->top_self);
vm->orig_progname = rb_gc_location(vm->orig_progname);
rb_gc_update_tbl_refs(vm->overloaded_cme_table);
if (vm->coverages) {
vm->coverages = rb_gc_location(vm->coverages);
vm->me2counter = rb_gc_location(vm->me2counter);
@ -2637,9 +2639,10 @@ rb_vm_mark(void *ptr)
rb_mark_tbl(vm->loading_table);
}
rb_gc_mark_values(RUBY_NSIG, vm->trap_list.cmd);
rb_gc_mark_values(RUBY_NSIG, vm->trap_list.cmd);
rb_id_table_foreach_values(vm->negative_cme_table, vm_mark_negative_cme, NULL);
rb_mark_tbl_no_pin(vm->overloaded_cme_table);
for (i=0; i<VM_GLOBAL_CC_CACHE_TABLE_SIZE; i++) {
const struct rb_callcache *cc = vm->global_cc_cache_table[i];
@ -3801,6 +3804,7 @@ Init_BareVM(void)
vm->objspace = rb_objspace_alloc();
ruby_current_vm_ptr = vm;
vm->negative_cme_table = rb_id_table_create(16);
vm->overloaded_cme_table = st_init_numtable();
Init_native_thread(th);
th->vm = vm;

Просмотреть файл

@ -714,6 +714,7 @@ typedef struct rb_vm_struct {
int builtin_inline_index;
struct rb_id_table *negative_cme_table;
st_table *overloaded_cme_table; // cme -> overloaded_cme
#ifndef VM_GLOBAL_CC_CACHE_TABLE_SIZE
#define VM_GLOBAL_CC_CACHE_TABLE_SIZE 1023

Просмотреть файл

@ -150,7 +150,7 @@ static rb_method_entry_t *rb_method_entry_alloc(ID called_id, VALUE owner, VALUE
const rb_method_entry_t * rb_method_entry_clone(const rb_method_entry_t *src_me);
static const rb_callable_method_entry_t *complemented_callable_method_entry(VALUE klass, ID id);
static const rb_callable_method_entry_t *lookup_overloaded_cme(const rb_callable_method_entry_t *cme);
static void delete_overloaded_cme(const rb_callable_method_entry_t *cme);
static void
clear_method_cache_by_id_in_class(VALUE klass, ID mid)
@ -216,7 +216,6 @@ clear_method_cache_by_id_in_class(VALUE klass, ID mid)
rb_callable_method_entry_t *monly_cme = (rb_callable_method_entry_t *)lookup_overloaded_cme(cme);
if (monly_cme) {
vm_cme_invalidate(monly_cme);
delete_overloaded_cme(monly_cme);
}
}
}
@ -393,6 +392,8 @@ rb_method_definition_release(rb_method_definition_t *def, int complemented)
}
}
static void delete_overloaded_cme(const rb_callable_method_entry_t *cme);
void
rb_free_method_entry(const rb_method_entry_t *me)
{
@ -922,12 +923,12 @@ rb_method_entry_make(VALUE klass, ID mid, VALUE defined_class, rb_method_visibil
}
static rb_method_entry_t *rb_method_entry_alloc(ID called_id, VALUE owner, VALUE defined_class, const rb_method_definition_t *def);
static st_table *overloaded_cme_table;
st_table *
rb_vm_overloaded_cme_table(void)
static st_table *
overloaded_cme_table(void)
{
return overloaded_cme_table;
VM_ASSERT(GET_VM()->overloaded_cme_table != NULL);
return GET_VM()->overloaded_cme_table;
}
#if VM_CHECK_MODE > 0
@ -943,7 +944,7 @@ void
rb_vm_dump_overloaded_cme_table(void)
{
fprintf(stderr, "== rb_vm_dump_overloaded_cme_table\n");
st_foreach(overloaded_cme_table, vm_dump_overloaded_cme_table, 0);
st_foreach(overloaded_cme_table(), vm_dump_overloaded_cme_table, 0);
}
#endif
@ -956,10 +957,7 @@ lookup_overloaded_cme_i(st_data_t *key, st_data_t *value, st_data_t data, int ex
const rb_callable_method_entry_t **ptr = (const rb_callable_method_entry_t **)data;
if (rb_objspace_garbage_object_p((VALUE)cme) ||
rb_objspace_garbage_object_p((VALUE)monly_cme) ||
METHOD_ENTRY_INVALIDATED(cme) ||
METHOD_ENTRY_INVALIDATED(monly_cme)) {
rb_objspace_garbage_object_p((VALUE)monly_cme)) {
*ptr = NULL;
return ST_DELETE;
}
@ -977,14 +975,8 @@ lookup_overloaded_cme(const rb_callable_method_entry_t *cme)
ASSERT_vm_locking();
const rb_callable_method_entry_t *monly_cme = NULL;
st_update(overloaded_cme_table, (st_data_t)cme, lookup_overloaded_cme_i, (st_data_t)&monly_cme);
if (monly_cme) {
return monly_cme;
}
else {
return NULL;
}
st_update(overloaded_cme_table(), (st_data_t)cme, lookup_overloaded_cme_i, (st_data_t)&monly_cme);
return monly_cme;
}
// used by gc.c
@ -998,7 +990,7 @@ static void
delete_overloaded_cme(const rb_callable_method_entry_t *cme)
{
ASSERT_vm_locking();
st_delete(overloaded_cme_table, (st_data_t *)&cme, NULL);
st_delete(overloaded_cme_table(), (st_data_t *)&cme, NULL);
}
static const rb_callable_method_entry_t *
@ -1006,7 +998,7 @@ get_overloaded_cme(const rb_callable_method_entry_t *cme)
{
const rb_callable_method_entry_t *monly_cme = lookup_overloaded_cme(cme);
if (monly_cme) {
if (monly_cme && !METHOD_ENTRY_INVALIDATED(monly_cme)) {
return monly_cme;
}
else {
@ -1021,7 +1013,7 @@ get_overloaded_cme(const rb_callable_method_entry_t *cme)
def);
ASSERT_vm_locking();
st_insert(overloaded_cme_table, (st_data_t)cme, (st_data_t)me);
st_insert(overloaded_cme_table(), (st_data_t)cme, (st_data_t)me);
METHOD_ENTRY_VISI_SET(me, METHOD_ENTRY_VISI(cme));
return (rb_callable_method_entry_t *)me;
@ -2828,7 +2820,7 @@ obj_respond_to_missing(VALUE obj, VALUE mid, VALUE priv)
void
Init_Method(void)
{
overloaded_cme_table = st_init_numtable();
//
}
void