1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Optimize calls to Kernel#hash (#3987)

This avoids recursive checks when the `hash` method of an object
isn't specialized.
This commit is contained in:
Marc-André Lafortune 2020-12-24 12:08:12 -05:00 committed by GitHub
parent 8981a63f12
commit db2ebbd71b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
Notes: git 2020-12-25 02:08:37 +09:00
Merged-By: nurse <naruse@airemix.jp>
3 changed files with 34 additions and 1 deletions

6
hash.c
View file

@ -142,7 +142,11 @@ hash_recursive(VALUE obj, VALUE arg, int recurse)
VALUE VALUE
rb_hash(VALUE obj) rb_hash(VALUE obj)
{ {
VALUE hval = rb_exec_recursive_outer(hash_recursive, obj, 0); VALUE hval = rb_check_funcall_basic_kw(obj, id_hash, rb_mKernel, 0, 0, 0);
if (hval == Qundef) {
hval = rb_exec_recursive_outer(hash_recursive, obj, 0);
}
while (!FIXNUM_P(hval)) { while (!FIXNUM_P(hval)) {
if (RB_TYPE_P(hval, T_BIGNUM)) { if (RB_TYPE_P(hval, T_BIGNUM)) {

View file

@ -74,6 +74,7 @@ VALUE rb_check_funcall_with_hook_kw(VALUE recv, ID mid, int argc, const VALUE *a
rb_check_funcall_hook *hook, VALUE arg, int kw_splat); rb_check_funcall_hook *hook, VALUE arg, int kw_splat);
const char *rb_type_str(enum ruby_value_type type); const char *rb_type_str(enum ruby_value_type type);
VALUE rb_check_funcall_default(VALUE, ID, int, const VALUE *, VALUE); VALUE rb_check_funcall_default(VALUE, ID, int, const VALUE *, VALUE);
VALUE rb_check_funcall_basic_kw(VALUE, ID, VALUE, int, const VALUE*, int);
VALUE rb_yield_1(VALUE val); VALUE rb_yield_1(VALUE val);
VALUE rb_yield_force_blockarg(VALUE values); VALUE rb_yield_force_blockarg(VALUE values);
VALUE rb_lambda_call(VALUE obj, ID mid, int argc, const VALUE *argv, VALUE rb_lambda_call(VALUE obj, ID mid, int argc, const VALUE *argv,

View file

@ -936,6 +936,34 @@ rb_funcallv_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int kw_splat)
return rb_call(recv, mid, argc, argv, kw_splat ? CALL_FCALL_KW : CALL_FCALL); return rb_call(recv, mid, argc, argv, kw_splat ? CALL_FCALL_KW : CALL_FCALL);
} }
/*!
* Calls a method only if it is the basic method of `ancestor`
* otherwise returns Qundef;
* \param recv receiver of the method
* \param mid an ID that represents the name of the method
* \param ancestor the Class that defined the basic method
* \param argc the number of arguments
* \param argv pointer to an array of method arguments
* \param kw_splat bool
*/
VALUE
rb_check_funcall_basic_kw(VALUE recv, ID mid, VALUE ancestor, int argc, const VALUE *argv, int kw_splat)
{
const rb_callable_method_entry_t *cme;
rb_execution_context_t *ec;
VALUE klass = CLASS_OF(recv);
if (!klass) return Qundef; /* hidden object */
cme = rb_callable_method_entry(klass, mid);
if (cme && METHOD_ENTRY_BASIC(cme) && RBASIC_CLASS(cme->defined_class) == ancestor) {
ec = GET_EC();
return rb_vm_call0(ec, recv, mid, argc, argv, cme, kw_splat);
}
return Qundef;
}
/*! /*!
* Calls a method. * Calls a method.
* *