diff options
author | Jemma Issroff <[email protected]> | 2022-11-22 15:28:14 -0500 |
---|---|---|
committer | GitHub <[email protected]> | 2022-11-22 15:28:14 -0500 |
commit | 9c5e3671ebd9c07c178ca5dac08ad15ad1eae411 (patch) | |
tree | 06f4f0560176011f14832d82f9e141ead7cac3f2 | |
parent | 20b9d7b9fde83c98046eacdfcb40e8cb6607963e (diff) |
Increment max_iv_count on class based on number of set_iv in initialize (#6788)
We can loosely predict the number of ivar sets on a class based on the
number of iv set instructions in the initialize method. This should give
us a more accurate estimate to use for initial size pool allocation,
which should in turn give us more cache hits.
Notes
Notes:
Merged-By: maximecb <[email protected]>
-rw-r--r-- | gc.c | 2 | ||||
-rw-r--r-- | iseq.c | 39 | ||||
-rw-r--r-- | vm_core.h | 1 | ||||
-rw-r--r-- | vm_insnhelper.c | 5 |
4 files changed, 46 insertions, 1 deletions
@@ -3089,7 +3089,7 @@ rb_imemo_new_debug(enum imemo_type type, VALUE v1, VALUE v2, VALUE v3, VALUE v0, } #endif -VALUE +MJIT_FUNC_EXPORTED VALUE rb_class_allocate_instance(VALUE klass) { return rb_class_instance_allocate_internal(klass, T_OBJECT | ROBJECT_EMBED, RGENGC_WB_PROTECTED_OBJECT); @@ -2491,6 +2491,45 @@ rb_iseq_disasm(const rb_iseq_t *iseq) } /* + * Estimates the number of instance variables that will be set on + * a given `class` with the initialize method defined in + * `initialize_iseq` + */ +attr_index_t +rb_estimate_iv_count(VALUE klass, const rb_iseq_t * initialize_iseq) +{ + bool calls_super = false; + + struct rb_id_table * iv_names = rb_id_table_create(0); + + VALUE * code = ISEQ_BODY(initialize_iseq)->iseq_encoded; + + for (unsigned int i = 0; i < ISEQ_BODY(initialize_iseq)->iseq_size; ) { + VALUE insn = code[i]; + int original_insn = rb_vm_insn_addr2insn((const void *)insn); + + if (BIN(setinstancevariable) == original_insn) { + ID name = (ID)code[i + 1]; + rb_id_table_insert(iv_names, name, Qtrue); + } + else if (BIN(invokesuper) == original_insn) { + calls_super = true; + } + + i += insn_len(original_insn); + } + + attr_index_t count = (attr_index_t)rb_id_table_size(iv_names); + + if (calls_super) { + VALUE superclass = rb_class_superclass(klass); + count += RCLASS_EXT(superclass)->max_iv_count; + } + + return count; +} + +/* * call-seq: * iseq.disasm -> str * iseq.disassemble -> str @@ -1158,6 +1158,7 @@ rb_iseq_t *rb_iseq_new_with_callback(const struct rb_iseq_new_with_callback_call VALUE rb_iseq_disasm(const rb_iseq_t *iseq); int rb_iseq_disasm_insn(VALUE str, const VALUE *iseqval, size_t pos, const rb_iseq_t *iseq, VALUE child); +attr_index_t rb_estimate_iv_count(VALUE klass, const rb_iseq_t * initialize_iseq); VALUE rb_iseq_coverage(const rb_iseq_t *iseq); diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 76bdbb86de..073c515d3c 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -4946,6 +4946,11 @@ vm_define_method(const rb_execution_context_t *ec, VALUE obj, ID id, VALUE iseqv } rb_add_method_iseq(klass, id, (const rb_iseq_t *)iseqval, cref, visi); + // Set max_iv_count on klasses based on number of ivar sets that are in the initialize method + if (id == rb_intern("initialize") && klass != rb_cObject && RB_TYPE_P(klass, T_CLASS) && (rb_get_alloc_func(klass) == rb_class_allocate_instance)) { + + RCLASS_EXT(klass)->max_iv_count = rb_estimate_iv_count(klass, (const rb_iseq_t *)iseqval); + } if (!is_singleton && vm_scope_module_func_check(ec)) { klass = rb_singleton_class(klass); |