summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hawthorn <[email protected]>2024-02-11 21:43:38 -0800
committerJohn Hawthorn <[email protected]>2024-02-20 18:55:00 -0800
commit1c97abaabae6844c861705fd07f532292dcffa74 ()
treea1d5dbac7eab32f6ffc168f1e556dfac085bc89a
parent2a6917b463fa4065f26aea44802e2e24cc494e4c (diff)
De-dup identical callinfo objects
Previously every call to vm_ci_new (when the CI was not packable) would result in a different callinfo being returned this meant that every kwarg callsite had its own CI. When calling, different CIs result in different CCs. These CIs and CCs both end up persisted on the T_CLASS inside cc_tbl. So in an eval loop this resulted in a memory of both types of object. This also likely resulted in extra memory used, and extra time searching, in non-eval cases. For simplicity in this commit I always allocate a CI object inside rb_vm_ci_lookup, but ideally we would lazily allocate it only when needed. I hope to do that as a follow up in the future.
-rw-r--r--gc.c1
-rw-r--r--internal/class.h2
-rw-r--r--vm.c7
-rw-r--r--vm_callinfo.h15
-rw-r--r--vm_core.h1
-rw-r--r--vm_method.c114
6 files changed, 129 insertions, 11 deletions
@@ -3745,6 +3745,7 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
case imemo_callinfo:
{
const struct rb_callinfo * ci = ((const struct rb_callinfo *)obj);
if (ci->kwarg) {
((struct rb_callinfo_kwarg *)ci->kwarg)->references--;
if (ci->kwarg->references == 0) xfree((void *)ci->kwarg);
@@ -44,7 +44,7 @@ struct rb_classext_struct {
VALUE *iv_ptr;
struct rb_id_table *const_tbl;
struct rb_id_table *callable_m_tbl;
- struct rb_id_table *cc_tbl; /* ID -> [[ci, cc1], cc2, ...] */
struct rb_id_table *cvc_tbl;
size_t superclass_depth;
VALUE *superclasses;
@@ -2873,6 +2873,7 @@ rb_vm_update_references(void *ptr)
if (ptr) {
rb_vm_t *vm = ptr;
rb_gc_update_tbl_refs(vm->frozen_strings);
vm->mark_object_ary = rb_gc_location(vm->mark_object_ary);
vm->load_path = rb_gc_location(vm->load_path);
@@ -3119,6 +3120,10 @@ ruby_vm_destruct(rb_vm_t *vm)
st_free_table(vm->loading_table);
vm->loading_table = 0;
}
if (vm->frozen_strings) {
st_free_table(vm->frozen_strings);
vm->frozen_strings = 0;
@@ -3209,6 +3214,7 @@ vm_memsize(const void *ptr)
rb_vm_memsize_workqueue(&vm->workqueue) +
rb_st_memsize(vm->defined_module_hash) +
vm_memsize_at_exit_list(vm->at_exit) +
rb_st_memsize(vm->frozen_strings) +
vm_memsize_builtin_function_table(vm->builtin_function_table) +
rb_id_table_memsize(vm->negative_cme_table) +
@@ -4303,6 +4309,7 @@ Init_vm_objects(void)
/* initialize mark object array, hash */
vm->mark_object_ary = rb_ary_hidden_new(128);
vm->loading_table = st_init_strtable();
vm->frozen_strings = st_init_table_with_size(&rb_fstring_hash_type, 10000);
}
@@ -199,12 +199,13 @@ vm_ci_dump(const struct rb_callinfo *ci)
(((VALUE)(argc)) << CI_EMBED_ARGC_SHFT) | \
RUBY_FIXNUM_FLAG))
static inline const struct rb_callinfo *
vm_ci_new_(ID mid, unsigned int flag, unsigned int argc, const struct rb_callinfo_kwarg *kwarg, const char *file, int line)
{
- if (kwarg) {
- ((struct rb_callinfo_kwarg *)kwarg)->references++;
- }
if (USE_EMBED_CI && VM_CI_EMBEDDABLE_P(mid, flag, argc, kwarg)) {
RB_DEBUG_COUNTER_INC(ci_packed);
return vm_ci_new_id(mid, flag, argc, kwarg);
@@ -213,13 +214,7 @@ vm_ci_new_(ID mid, unsigned int flag, unsigned int argc, const struct rb_callinf
const bool debug = 0;
if (debug) ruby_debug_printf("%s:%d ", file, line);
- // TODO: dedup
- const struct rb_callinfo *ci = (const struct rb_callinfo *)
- rb_imemo_new(imemo_callinfo,
- (VALUE)mid,
- (VALUE)flag,
- (VALUE)argc,
- (VALUE)kwarg);
if (debug) rp(ci);
if (kwarg) {
RB_DEBUG_COUNTER_INC(ci_kw);
@@ -752,6 +752,7 @@ typedef struct rb_vm_struct {
const struct rb_builtin_function *builtin_function_table;
struct rb_id_table *negative_cme_table;
st_table *overloaded_cme_table; // cme -> overloaded_cme
@@ -333,6 +333,120 @@ invalidate_all_refinement_cc(void *vstart, void *vend, size_t stride, void *data
return 0; // continue to iteration
}
void
rb_clear_all_refinement_method_cache(void)
{