зеркало из https://github.com/github/ruby.git
rb_method_basic_definition_p with CC
Noticed that rb_method_basic_definition_p is frequently called. Its callers include vm_caller_setup_args_block(), rb_hash_default_value(), rb_num_neative_int_p(), and a lot more. It seems worth caching the method resolution part. Majority of rb_method_basic_definion_p() usages take fixed class and fixed method id combinations. Calculating ------------------------------------- ours trunk so_matrix 2.379 2.115 i/s - 1.000 times in 0.420409s 0.472879s Comparison: so_matrix ours: 2.4 i/s trunk: 2.1 i/s - 1.12x slower
This commit is contained in:
Родитель
1390d56ecf
Коммит
6ff1250739
|
@ -2389,6 +2389,8 @@ struct rb_call_data {
|
|||
};
|
||||
RUBY_FUNC_EXPORTED
|
||||
RUBY_FUNC_NONNULL(1, VALUE rb_funcallv_with_cc(struct rb_call_data*, VALUE, ID, int, const VALUE*));
|
||||
RUBY_FUNC_EXPORTED
|
||||
RUBY_FUNC_NONNULL(1, bool rb_method_basic_definition_p_with_cc(struct rb_call_data *, VALUE, ID));
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define rb_funcallv(recv, mid, argc, argv) \
|
||||
|
@ -2396,6 +2398,12 @@ RUBY_FUNC_NONNULL(1, VALUE rb_funcallv_with_cc(struct rb_call_data*, VALUE, ID,
|
|||
static struct rb_call_data rb_funcallv_data = { { 0, }, { 0, }, }; \
|
||||
rb_funcallv_with_cc(&rb_funcallv_data, recv, mid, argc, argv); \
|
||||
})
|
||||
# define rb_method_basic_definition_p(klass, mid) \
|
||||
__extension__({ \
|
||||
static struct rb_call_data rb_mbdp = { { 0, }, { 0, }, }; \
|
||||
(klass == Qfalse) ? /* hidden object cannot be overridden */ true : \
|
||||
rb_method_basic_definition_p_with_cc(&rb_mbdp, klass, mid); \
|
||||
})
|
||||
#endif
|
||||
|
||||
/* miniprelude.c, prelude.c */
|
||||
|
|
|
@ -1433,13 +1433,9 @@ rb_vm_search_method_slowpath(struct rb_call_data *cd, VALUE klass)
|
|||
}
|
||||
|
||||
static void
|
||||
vm_search_method(struct rb_call_data *cd, VALUE recv)
|
||||
vm_search_method_fastpath(struct rb_call_data *cd, VALUE klass)
|
||||
{
|
||||
struct rb_call_cache *cc = &cd->cc;
|
||||
VALUE klass = CLASS_OF(recv);
|
||||
|
||||
VM_ASSERT(klass != Qfalse);
|
||||
VM_ASSERT(RBASIC_CLASS(klass) == 0 || rb_obj_is_kind_of(klass, rb_cClass));
|
||||
|
||||
#if OPT_INLINE_METHOD_CACHE
|
||||
if (LIKELY(RB_DEBUG_COUNTER_INC_UNLESS(mc_global_state_miss,
|
||||
|
@ -1456,6 +1452,16 @@ vm_search_method(struct rb_call_data *cd, VALUE recv)
|
|||
rb_vm_search_method_slowpath(cd, klass);
|
||||
}
|
||||
|
||||
static void
|
||||
vm_search_method(struct rb_call_data *cd, VALUE recv)
|
||||
{
|
||||
VALUE klass = CLASS_OF(recv);
|
||||
|
||||
VM_ASSERT(klass != Qfalse);
|
||||
VM_ASSERT(RBASIC_CLASS(klass) == 0 || rb_obj_is_kind_of(klass, rb_cClass));
|
||||
vm_search_method_fastpath(cd, klass);
|
||||
}
|
||||
|
||||
static inline int
|
||||
check_cfunc(const rb_callable_method_entry_t *me, VALUE (*func)())
|
||||
{
|
||||
|
|
18
vm_method.c
18
vm_method.c
|
@ -2024,6 +2024,21 @@ rb_mod_modfunc(int argc, VALUE *argv, VALUE module)
|
|||
return module;
|
||||
}
|
||||
|
||||
bool
|
||||
rb_method_basic_definition_p_with_cc(struct rb_call_data *cd, VALUE klass, ID mid)
|
||||
{
|
||||
if (cd->ci.mid != mid) {
|
||||
*cd = (struct rb_call_data) /* reset */ { .ci = { .mid = mid, }, };
|
||||
}
|
||||
|
||||
vm_search_method_fastpath(cd, klass);
|
||||
return cd->cc.me && METHOD_ENTRY_BASIC(cd->cc.me);
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma push_macro("rb_method_basic_definition_p")
|
||||
#undef rb_method_basic_definition_p
|
||||
#endif
|
||||
int
|
||||
rb_method_basic_definition_p(VALUE klass, ID id)
|
||||
{
|
||||
|
@ -2032,6 +2047,9 @@ rb_method_basic_definition_p(VALUE klass, ID id)
|
|||
me = rb_method_entry(klass, id);
|
||||
return (me && METHOD_ENTRY_BASIC(me)) ? TRUE : FALSE;
|
||||
}
|
||||
#ifdef __GNUC__
|
||||
#pragma pop_macro("rb_method_basic_definition_p")
|
||||
#endif
|
||||
|
||||
static VALUE
|
||||
call_method_entry(rb_execution_context_t *ec, VALUE defined_class, VALUE obj, ID id,
|
||||
|
|
Загрузка…
Ссылка в новой задаче