summaryrefslogtreecommitdiff
path: root/gc.c
diff options
context:
space:
mode:
authoralpaca-tc <[email protected]>2025-04-06 01:50:08 +0900
committerKoichi Sasada <[email protected]>2025-06-09 12:33:35 +0900
commitc8ddc0a843074811b200673a2019fbe4b50bb890 (patch)
treef3881cd1f408f10abfdd7a8258d88cf18a557717 /gc.c
parentd0b5f3155406e8243b78e4cedd3a38710c7c323c (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.c39
1 files changed, 39 insertions, 0 deletions
diff --git a/gc.c b/gc.c
index 3e7d88209f..5281e7fb49 100644
--- a/gc.c
+++ b/gc.c
@@ -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);
}
}