diff options
author | Urabe, Shyouhei <shyouhei@ruby-lang.org> | 2018-10-11 11:47:49 +0900 |
---|---|---|
committer | 卜部昌平 <shyouhei@ruby-lang.org> | 2019-09-04 14:08:40 +0900 |
commit | 2a6457b5b7d67378528235cee7b9cb93fed00204 (patch) | |
tree | 259635fccbca1b111074c5c0f3f2e81f235fec6f /vm_eval.c | |
parent | ccad34f4533ffe532fea796def06808dc5a85877 (diff) | |
download | ruby-2a6457b5b7d67378528235cee7b9cb93fed00204.tar.gz |
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.
Diffstat (limited to 'vm_eval.c')
-rw-r--r-- | vm_eval.c | 50 |
1 files changed, 50 insertions, 0 deletions
@@ -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) { |