diff options
author | alpaca-tc <[email protected]> | 2025-04-06 01:50:08 +0900 |
---|---|---|
committer | Koichi Sasada <[email protected]> | 2025-06-09 12:33:35 +0900 |
commit | c8ddc0a843074811b200673a2019fbe4b50bb890 (patch) | |
tree | f3881cd1f408f10abfdd7a8258d88cf18a557717 /gc.c | |
parent | d0b5f3155406e8243b78e4cedd3a38710c7c323c (diff) |
Optimize callcache invalidation for refinements
Fixes [Bug #21201]
This change addresses a performance regression where defining methods
inside `refine` blocks caused severe slowdowns. The issue was due to
`rb_clear_all_refinement_method_cache()` triggering a full object
space scan via `rb_objspace_each_objects` to find and invalidate
affected callcaches, which is very inefficient.
To fix this, I introduce `vm->cc_refinement_table` to track
callcaches related to refinements. This allows us to invalidate
only the necessary callcaches without scanning the entire heap,
resulting in significant performance improvement.
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/13077
Diffstat (limited to 'gc.c')
-rw-r--r-- | gc.c | 39 |
1 files changed, 39 insertions, 0 deletions
@@ -2095,6 +2095,15 @@ rb_gc_obj_free_vm_weak_references(VALUE obj) break; case T_IMEMO: switch (imemo_type(obj)) { + case imemo_callcache: { + const struct rb_callcache *cc = (const struct rb_callcache *)obj; + + if (vm_cc_refinement_p(cc)) { + rb_vm_delete_cc_refinement(cc); + } + + break; + } case imemo_callinfo: rb_vm_ci_free((const struct rb_callinfo *)obj); break; @@ -3930,6 +3939,23 @@ vm_weak_table_foreach_update_weak_key(st_data_t *key, st_data_t *value, st_data_ } static int +vm_weak_table_cc_refinement_foreach(st_data_t key, st_data_t data, int error) +{ + struct global_vm_table_foreach_data *iter_data = (struct global_vm_table_foreach_data *)data; + + return iter_data->callback((VALUE)key, iter_data->data); +} + +static int +vm_weak_table_cc_refinement_foreach_update_update(st_data_t *key, st_data_t data, int existing) +{ + 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); +} + + +static int vm_weak_table_str_sym_foreach(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; @@ -4178,8 +4204,21 @@ rb_gc_vm_weak_table_foreach(vm_table_foreach_callback_func callback, ); break; } + case RB_GC_VM_CC_REFINEMENT_TABLE: { + if (vm->cc_refinement_table) { + set_foreach_with_replace( + vm->cc_refinement_table, + vm_weak_table_cc_refinement_foreach, + vm_weak_table_cc_refinement_foreach_update_update, + (st_data_t)&foreach_data + ); + } + break; + } case RB_GC_VM_WEAK_TABLE_COUNT: rb_bug("Unreacheable"); + default: + rb_bug("rb_gc_vm_weak_table_foreach: unknown table %d", table); } } |