Optimize Hash methods with Kernel#hash (#10160)

This commit is contained in:
Takashi Kokubun 2024-03-01 11:16:31 -08:00 committed by GitHub
parent 6f31dd495c
commit 70de3b170b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 22 additions and 1 deletions

5
benchmark/hash_key.yml Normal file
View File

@ -0,0 +1,5 @@
prelude: |
obj = Object.new
hash = { obj => true }
benchmark: hash.key?(obj)
loop_count: 30000000

18
hash.c
View File

@ -210,10 +210,26 @@ any_hash(VALUE a, st_index_t (*other_func)(VALUE))
return (long)hnum;
}
VALUE rb_obj_hash(VALUE obj);
VALUE rb_vm_call0(rb_execution_context_t *ec, VALUE recv, ID id, int argc, const VALUE *argv, const rb_callable_method_entry_t *cme, int kw_splat);
static st_index_t
obj_any_hash(VALUE obj)
{
VALUE hval = rb_check_funcall_basic_kw(obj, id_hash, rb_mKernel, 0, 0, 0);
VALUE hval = Qundef;
VALUE klass = CLASS_OF(obj);
if (klass) {
const rb_callable_method_entry_t *cme = rb_callable_method_entry(klass, id_hash);
if (cme && METHOD_ENTRY_BASIC(cme) && RBASIC_CLASS(cme->defined_class) == rb_mKernel) {
// Optimize away the frame push overhead if it's the default Kernel#hash
if (cme->def->type == VM_METHOD_TYPE_CFUNC && cme->def->body.cfunc.func == (VALUE (*)(ANYARGS))rb_obj_hash) {
hval = rb_obj_hash(obj);
}
else {
hval = rb_vm_call0(GET_EC(), obj, id_hash, 0, 0, cme, 0);
}
}
}
if (UNDEF_P(hval)) {
hval = rb_exec_recursive_outer_mid(hash_recursive, obj, 0, id_hash);