diff options
-rw-r--r-- | benchmark/hash_key.yml | 5 | ||||
-rw-r--r-- | hash.c | 18 |
2 files changed, 22 insertions, 1 deletions
diff --git a/benchmark/hash_key.yml b/benchmark/hash_key.yml new file mode 100644 index 0000000000..cab4cf9ca4 --- /dev/null +++ b/benchmark/hash_key.yml @@ -0,0 +1,5 @@ +prelude: | + obj = Object.new + hash = { obj => true } +benchmark: hash.key?(obj) +loop_count: 30000000 @@ -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); |