mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
add rb_funcallv_with_cc()
Why not cache the method entry at each caller site. The void** is in fact a method entry, but this struct is hidden from ruby.h so intentionally left opaque.
This commit is contained in:
parent
ccad34f453
commit
2a6457b5b7
Notes:
git
2019-09-04 14:09:03 +09:00
2 changed files with 64 additions and 1 deletions
|
@ -1892,6 +1892,10 @@ VALUE rb_funcallv_public(VALUE, ID, int, const VALUE*);
|
|||
#define rb_funcall3 rb_funcallv_public
|
||||
VALUE rb_funcall_passing_block(VALUE, ID, int, const VALUE*);
|
||||
VALUE rb_funcall_with_block(VALUE, ID, int, const VALUE*, VALUE);
|
||||
#if GCC_VERSION_SINCE(3, 3, 0)
|
||||
__attribute__((__nonnull__ (1))) /* TODO: should check using configure */
|
||||
#endif
|
||||
VALUE rb_funcallv_with_cc(void**, VALUE, ID, int, const VALUE*);
|
||||
int rb_scan_args(int, const VALUE*, const char*, ...);
|
||||
VALUE rb_call_super(int, const VALUE*);
|
||||
VALUE rb_current_receiver(void);
|
||||
|
@ -2607,10 +2611,19 @@ __extension__({ \
|
|||
const VALUE rb_funcall_args[] = {__VA_ARGS__}; \
|
||||
const int rb_funcall_nargs = \
|
||||
(int)(sizeof(rb_funcall_args) / sizeof(VALUE)); \
|
||||
rb_funcallv(recv, mid, \
|
||||
static void *rb_funcall_opaque_cc = NULL; \
|
||||
rb_funcallv_with_cc(&rb_funcall_opaque_cc, \
|
||||
recv, mid, \
|
||||
rb_varargs_argc_check(rb_funcall_argc, rb_funcall_nargs), \
|
||||
rb_funcall_nargs ? rb_funcall_args : NULL); \
|
||||
})
|
||||
|
||||
# define rb_funcallv(recv, mid, argc, argv) \
|
||||
__extension__({ \
|
||||
static void *rb_funcallv_opaque_cc = NULL; \
|
||||
rb_funcallv_with_cc(&rb_funcallv_opaque_cc, \
|
||||
recv, mid, argc,argv); \
|
||||
})
|
||||
#endif
|
||||
|
||||
#ifndef RUBY_DONT_SUBST
|
||||
|
|
50
vm_eval.c
50
vm_eval.c
|
@ -800,7 +800,9 @@ rb_apply(VALUE recv, ID mid, VALUE args)
|
|||
return rb_call(recv, mid, argc, argv, CALL_FCALL);
|
||||
}
|
||||
|
||||
#ifdef rb_funcall
|
||||
#undef rb_funcall
|
||||
#endif
|
||||
/*!
|
||||
* Calls a method
|
||||
* \param recv receiver of the method
|
||||
|
@ -834,6 +836,9 @@ rb_funcall(VALUE recv, ID mid, int n, ...)
|
|||
return rb_call(recv, mid, n, argv, CALL_FCALL);
|
||||
}
|
||||
|
||||
#ifdef rb_funcallv
|
||||
#undef rb_funcallv
|
||||
#endif
|
||||
/*!
|
||||
* Calls a method
|
||||
* \param recv receiver of the method
|
||||
|
@ -862,6 +867,51 @@ rb_funcallv_public(VALUE recv, ID mid, int argc, const VALUE *argv)
|
|||
return rb_call(recv, mid, argc, argv, CALL_PUBLIC);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Calls a method
|
||||
* \param ptr opaque call cache
|
||||
* \param recv receiver of the method
|
||||
* \param mid an ID that represents the name of the method
|
||||
* \param argc the number of arguments
|
||||
* \param argv pointer to an array of method arguments
|
||||
*/
|
||||
VALUE
|
||||
rb_funcallv_with_cc(void **ptr, VALUE recv, ID mid, int argc, const VALUE *argv)
|
||||
{
|
||||
VM_ASSERT(ptr);
|
||||
const VALUE klass = CLASS_OF(recv);
|
||||
VM_ASSERT(klass != Qfalse);
|
||||
VM_ASSERT(RBASIC_CLASS(klass) == 0 || rb_obj_is_kind_of(klass, rb_cClass));
|
||||
rb_serial_t now = GET_GLOBAL_METHOD_STATE();
|
||||
rb_serial_t serial = RCLASS_SERIAL(klass);
|
||||
struct opaque {
|
||||
const rb_callable_method_entry_t *me;
|
||||
rb_serial_t updated_at;
|
||||
rb_serial_t class_at;
|
||||
ID mid;
|
||||
} *cc;
|
||||
if (UNLIKELY(! *ptr)) {
|
||||
*ptr = ZALLOC(struct opaque);
|
||||
}
|
||||
cc = *ptr;
|
||||
|
||||
if (cc->updated_at != now ||
|
||||
cc->class_at != serial ||
|
||||
cc->mid != mid) {
|
||||
*cc = (struct opaque) {
|
||||
rb_callable_method_entry(klass, mid), now, serial, mid,
|
||||
};
|
||||
}
|
||||
|
||||
if (UNLIKELY(UNDEFINED_METHOD_ENTRY_P(cc->me))) {
|
||||
/* :FIXME: this path can be made faster */
|
||||
return rb_funcallv(recv, mid, argc, argv);
|
||||
}
|
||||
else {
|
||||
return rb_vm_call0(GET_EC(), recv, mid, argc, argv, cc->me);
|
||||
}
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_funcall_passing_block(VALUE recv, ID mid, int argc, const VALUE *argv)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue