|
| 1 | +diff --git a/gc.c b/gc.c |
| 2 | +index 68304d26c50e0d..ff99c52c8fa8fd 100644 |
| 3 | +--- a/gc.c |
| 4 | ++++ b/gc.c |
| 5 | +@@ -1246,6 +1246,15 @@ rb_gc_obj_free_vm_weak_references(VALUE obj) |
| 6 | + break; |
| 7 | + case T_IMEMO: |
| 8 | + switch (imemo_type(obj)) { |
| 9 | ++ case imemo_callcache: { |
| 10 | ++ const struct rb_callcache *cc = (const struct rb_callcache *)obj; |
| 11 | ++ |
| 12 | ++ if (vm_cc_refinement_p(cc)) { |
| 13 | ++ rb_vm_delete_cc_refinement(cc); |
| 14 | ++ } |
| 15 | ++ |
| 16 | ++ break; |
| 17 | ++ } |
| 18 | + case imemo_callinfo: |
| 19 | + rb_vm_ci_free((const struct rb_callinfo *)obj); |
| 20 | + break; |
| 21 | +@@ -3436,6 +3445,64 @@ vm_weak_table_frozen_strings_foreach(st_data_t key, st_data_t value, st_data_t d |
| 22 | + |
| 23 | + struct st_table *rb_generic_ivtbl_get(void); |
| 24 | + |
| 25 | ++struct global_vm_cc_refinement_foreach_data { |
| 26 | ++ struct global_vm_table_foreach_data *iter_data; |
| 27 | ++ st_table *new_tbl; |
| 28 | ++}; |
| 29 | ++ |
| 30 | ++static int |
| 31 | ++vm_weak_table_cc_refinement_foreach_i(st_data_t key, st_data_t value, st_data_t data) |
| 32 | ++{ |
| 33 | ++ struct global_vm_cc_refinement_foreach_data *cc_refinement_foreach_data = (struct global_vm_cc_refinement_foreach_data *)data; |
| 34 | ++ struct global_vm_table_foreach_data *iter_data = cc_refinement_foreach_data->iter_data; |
| 35 | ++ struct st_table *new_tbl = cc_refinement_foreach_data->new_tbl; |
| 36 | ++ |
| 37 | ++ int ret = iter_data->callback((VALUE)key, iter_data->data); |
| 38 | ++ |
| 39 | ++ const struct rb_callcache *cc = (struct rb_callcache *)key; |
| 40 | ++ switch (ret) { |
| 41 | ++ case ST_CONTINUE: |
| 42 | ++ break; |
| 43 | ++ case ST_DELETE: |
| 44 | ++ return ret; |
| 45 | ++ case ST_REPLACE: { |
| 46 | ++ VALUE new_key = (VALUE)key; |
| 47 | ++ iter_data->update_callback(&new_key, iter_data->data); |
| 48 | ++ cc = (struct rb_callcache *)new_key; |
| 49 | ++ break; |
| 50 | ++ } |
| 51 | ++ default: |
| 52 | ++ rb_bug("vm_weak_table_cc_refinement_foreach_i: return value %d not supported", ret); |
| 53 | ++ } |
| 54 | ++ |
| 55 | ++ DURING_GC_COULD_MALLOC_REGION_START(); |
| 56 | ++ { |
| 57 | ++ rb_vm_insert_cc_refinement(new_tbl, cc); |
| 58 | ++ } |
| 59 | ++ DURING_GC_COULD_MALLOC_REGION_END(); |
| 60 | ++ |
| 61 | ++ return ret; |
| 62 | ++} |
| 63 | ++ |
| 64 | ++static st_table * |
| 65 | ++vm_weak_table_cc_refinement_rebuild(st_table *cc_refinement_table, struct global_vm_table_foreach_data *iter_data) |
| 66 | ++{ |
| 67 | ++ st_table *new_tbl = NULL; |
| 68 | ++ DURING_GC_COULD_MALLOC_REGION_START(); |
| 69 | ++ { |
| 70 | ++ new_tbl = st_init_numtable_with_size(st_table_size(cc_refinement_table)); |
| 71 | ++ } |
| 72 | ++ DURING_GC_COULD_MALLOC_REGION_END(); |
| 73 | ++ |
| 74 | ++ struct global_vm_cc_refinement_foreach_data cc_refinement_foreach_data = { |
| 75 | ++ .iter_data = iter_data, |
| 76 | ++ .new_tbl = new_tbl, |
| 77 | ++ }; |
| 78 | ++ |
| 79 | ++ st_foreach(cc_refinement_table, vm_weak_table_cc_refinement_foreach_i, (st_data_t)&cc_refinement_foreach_data); |
| 80 | ++ return new_tbl; |
| 81 | ++} |
| 82 | ++ |
| 83 | + void |
| 84 | + rb_gc_vm_weak_table_foreach(vm_table_foreach_callback_func callback, |
| 85 | + vm_table_update_callback_func update_callback, |
| 86 | +@@ -3498,6 +3565,17 @@ rb_gc_vm_weak_table_foreach(vm_table_foreach_callback_func callback, |
| 87 | + ); |
| 88 | + break; |
| 89 | + } |
| 90 | ++ case RB_GC_VM_CC_REFINEMENT_TABLE: { |
| 91 | ++ st_table_size(vm->cc_refinement_table); |
| 92 | ++ if (vm->cc_refinement_table && st_table_size(vm->cc_refinement_table) > 0) { |
| 93 | ++ st_table *old_tbl = vm->cc_refinement_table; |
| 94 | ++ st_table *new_tbl = vm_weak_table_cc_refinement_rebuild(vm->cc_refinement_table, &foreach_data); |
| 95 | ++ |
| 96 | ++ vm->cc_refinement_table = new_tbl; |
| 97 | ++ st_free_table(old_tbl); |
| 98 | ++ } |
| 99 | ++ break; |
| 100 | ++ } |
| 101 | + default: |
| 102 | + rb_bug("rb_gc_vm_weak_table_foreach: unknown table %d", table); |
| 103 | + } |
| 104 | +diff --git a/gc/gc.h b/gc/gc.h |
| 105 | +index 5b380df1f45cc8..a096bb184a0d74 100644 |
| 106 | +--- a/gc/gc.h |
| 107 | ++++ b/gc/gc.h |
| 108 | +@@ -30,6 +30,7 @@ enum rb_gc_vm_weak_tables { |
| 109 | + RB_GC_VM_GLOBAL_SYMBOLS_TABLE, |
| 110 | + RB_GC_VM_GENERIC_IV_TABLE, |
| 111 | + RB_GC_VM_FROZEN_STRINGS_TABLE, |
| 112 | ++ RB_GC_VM_CC_REFINEMENT_TABLE, |
| 113 | + RB_GC_VM_WEAK_TABLE_COUNT |
| 114 | + }; |
| 115 | + #endif |
| 116 | +diff --git a/method.h b/method.h |
| 117 | +index 030c3cc3d18be9..5c5d19cabe6223 100644 |
| 118 | +--- a/method.h |
| 119 | ++++ b/method.h |
| 120 | +@@ -250,6 +250,9 @@ void rb_scope_visibility_set(rb_method_visibility_t); |
| 121 | + |
| 122 | + VALUE rb_unnamed_parameters(int arity); |
| 123 | + |
| 124 | ++void rb_vm_insert_cc_refinement(st_table *cc_refinement_table, const struct rb_callcache *cc); |
| 125 | ++void rb_vm_delete_cc_refinement(const struct rb_callcache *cc); |
| 126 | ++ |
| 127 | + void rb_clear_method_cache(VALUE klass_or_module, ID mid); |
| 128 | + void rb_clear_all_refinement_method_cache(void); |
| 129 | + |
| 130 | +diff --git a/vm.c b/vm.c |
| 131 | +index 9a0008ea070ccd..7aa9739fba67c6 100644 |
| 132 | +--- a/vm.c |
| 133 | ++++ b/vm.c |
| 134 | +@@ -3143,6 +3143,10 @@ ruby_vm_destruct(rb_vm_t *vm) |
| 135 | + st_free_table(vm->frozen_strings); |
| 136 | + vm->frozen_strings = 0; |
| 137 | + } |
| 138 | ++ if (vm->cc_refinement_table) { |
| 139 | ++ st_free_table(vm->cc_refinement_table); |
| 140 | ++ vm->cc_refinement_table = NULL; |
| 141 | ++ } |
| 142 | + RB_ALTSTACK_FREE(vm->main_altstack); |
| 143 | + |
| 144 | + struct global_object_list *next; |
| 145 | +@@ -3245,6 +3249,7 @@ vm_memsize(const void *ptr) |
| 146 | + vm_memsize_builtin_function_table(vm->builtin_function_table) + |
| 147 | + rb_id_table_memsize(vm->negative_cme_table) + |
| 148 | + rb_st_memsize(vm->overloaded_cme_table) + |
| 149 | ++ rb_st_memsize(vm->cc_refinement_table) + |
| 150 | + vm_memsize_constant_cache() + |
| 151 | + GET_SHAPE_TREE()->cache_size * sizeof(redblack_node_t) |
| 152 | + ); |
| 153 | +@@ -4447,6 +4452,7 @@ Init_vm_objects(void) |
| 154 | + vm->loading_table = st_init_strtable(); |
| 155 | + vm->ci_table = st_init_table(&vm_ci_hashtype); |
| 156 | + vm->frozen_strings = st_init_table_with_size(&rb_fstring_hash_type, 10000); |
| 157 | ++ vm->cc_refinement_table = st_init_numtable(); |
| 158 | + } |
| 159 | + |
| 160 | + // Stub for builtin function when not building YJIT units |
| 161 | +diff --git a/vm_callinfo.h b/vm_callinfo.h |
| 162 | +index d85261aaf900cd..5e0fcc5465cf8a 100644 |
| 163 | +--- a/vm_callinfo.h |
| 164 | ++++ b/vm_callinfo.h |
| 165 | +@@ -345,6 +345,7 @@ vm_cc_new(VALUE klass, |
| 166 | + break; |
| 167 | + case cc_type_refinement: |
| 168 | + *(VALUE *)&cc->flags |= VM_CALLCACHE_REFINEMENT; |
| 169 | ++ rb_vm_insert_cc_refinement(NULL, cc); |
| 170 | + break; |
| 171 | + } |
| 172 | + |
| 173 | +diff --git a/vm_core.h b/vm_core.h |
| 174 | +index 961cc3967c3a6d..ccca31a768c34c 100644 |
| 175 | +--- a/vm_core.h |
| 176 | ++++ b/vm_core.h |
| 177 | +@@ -799,6 +799,7 @@ typedef struct rb_vm_struct { |
| 178 | + struct rb_id_table *negative_cme_table; |
| 179 | + st_table *overloaded_cme_table; // cme -> overloaded_cme |
| 180 | + st_table *unused_block_warning_table; |
| 181 | ++ st_table *cc_refinement_table; |
| 182 | + |
| 183 | + // This id table contains a mapping from ID to ICs. It does this with ID |
| 184 | + // keys and nested st_tables as values. The nested tables have ICs as keys |
| 185 | +diff --git a/vm_method.c b/vm_method.c |
| 186 | +index e4f71648acb3aa..177723fd423d28 100644 |
| 187 | +--- a/vm_method.c |
| 188 | ++++ b/vm_method.c |
| 189 | +@@ -310,27 +310,29 @@ rb_clear_method_cache(VALUE klass_or_module, ID mid) |
| 190 | + } |
| 191 | + |
| 192 | + static int |
| 193 | +-invalidate_all_refinement_cc(void *vstart, void *vend, size_t stride, void *data) |
| 194 | +-{ |
| 195 | +- VALUE v = (VALUE)vstart; |
| 196 | +- for (; v != (VALUE)vend; v += stride) { |
| 197 | +- void *ptr = rb_asan_poisoned_object_p(v); |
| 198 | +- rb_asan_unpoison_object(v, false); |
| 199 | +- |
| 200 | +- if (RBASIC(v)->flags) { // liveness check |
| 201 | +- if (imemo_type_p(v, imemo_callcache)) { |
| 202 | +- const struct rb_callcache *cc = (const struct rb_callcache *)v; |
| 203 | +- if (vm_cc_refinement_p(cc) && cc->klass) { |
| 204 | +- vm_cc_invalidate(cc); |
| 205 | +- } |
| 206 | +- } |
| 207 | +- } |
| 208 | ++invalidate_cc_refinement(st_data_t key, st_data_t value, st_data_t data) |
| 209 | ++{ |
| 210 | ++ VALUE v = (VALUE)key; |
| 211 | ++ void *ptr = rb_asan_poisoned_object_p(v); |
| 212 | ++ rb_asan_unpoison_object(v, false); |
| 213 | ++ |
| 214 | ++ if (rb_gc_pointer_to_heap_p(v) && |
| 215 | ++ !rb_objspace_garbage_object_p(v) && |
| 216 | ++ RBASIC(v)->flags) { // liveness check |
| 217 | ++ const struct rb_callcache *cc = (const struct rb_callcache *)v; |
| 218 | + |
| 219 | +- if (ptr) { |
| 220 | +- rb_asan_poison_object(v); |
| 221 | ++ VM_ASSERT(vm_cc_refinement_p(cc)); |
| 222 | ++ |
| 223 | ++ if (cc->klass) { |
| 224 | ++ vm_cc_invalidate(cc); |
| 225 | + } |
| 226 | + } |
| 227 | +- return 0; // continue to iteration |
| 228 | ++ |
| 229 | ++ if (ptr) { |
| 230 | ++ rb_asan_poison_object(v); |
| 231 | ++ } |
| 232 | ++ |
| 233 | ++ return ST_CONTINUE; |
| 234 | + } |
| 235 | + |
| 236 | + static st_index_t |
| 237 | +@@ -442,10 +444,49 @@ rb_vm_ci_free(const struct rb_callinfo *ci) |
| 238 | + st_delete(vm->ci_table, &key, NULL); |
| 239 | + } |
| 240 | + |
| 241 | ++void |
| 242 | ++rb_vm_insert_cc_refinement(st_table *cc_refinement_table, const struct rb_callcache *cc) |
| 243 | ++{ |
| 244 | ++ st_data_t key = (st_data_t)cc; |
| 245 | ++ |
| 246 | ++ if (cc_refinement_table) { |
| 247 | ++ st_insert(cc_refinement_table, key, 1); |
| 248 | ++ } else { |
| 249 | ++ rb_vm_t *vm = GET_VM(); |
| 250 | ++ RB_VM_LOCK_ENTER(); |
| 251 | ++ { |
| 252 | ++ st_insert(vm->cc_refinement_table, key, 1); |
| 253 | ++ } |
| 254 | ++ RB_VM_LOCK_LEAVE(); |
| 255 | ++ } |
| 256 | ++} |
| 257 | ++ |
| 258 | ++void rb_st_compact_table(st_table *tab); |
| 259 | ++ |
| 260 | ++void |
| 261 | ++rb_vm_delete_cc_refinement(const struct rb_callcache *cc) |
| 262 | ++{ |
| 263 | ++ ASSERT_vm_locking(); |
| 264 | ++ |
| 265 | ++ rb_vm_t *vm = GET_VM(); |
| 266 | ++ st_data_t key = (st_data_t)cc; |
| 267 | ++ |
| 268 | ++ st_delete(vm->cc_refinement_table, &key, NULL); |
| 269 | ++} |
| 270 | ++ |
| 271 | + void |
| 272 | + rb_clear_all_refinement_method_cache(void) |
| 273 | + { |
| 274 | +- rb_objspace_each_objects(invalidate_all_refinement_cc, NULL); |
| 275 | ++ rb_vm_t *vm = GET_VM(); |
| 276 | ++ |
| 277 | ++ RB_VM_LOCK_ENTER(); |
| 278 | ++ { |
| 279 | ++ st_foreach(vm->cc_refinement_table, invalidate_cc_refinement, (st_data_t)NULL); |
| 280 | ++ st_clear(vm->cc_refinement_table); |
| 281 | ++ rb_st_compact_table(vm->cc_refinement_table); |
| 282 | ++ } |
| 283 | ++ RB_VM_LOCK_LEAVE(); |
| 284 | ++ |
| 285 | + rb_yjit_invalidate_all_method_lookup_assumptions(); |
| 286 | + } |
| 287 | + |
0 commit comments