summaryrefslogtreecommitdiff
path: root/vm_eval.c
diff options
context:
space:
mode:
authorUrabe, Shyouhei <shyouhei@ruby-lang.org>2018-10-11 11:47:49 +0900
committer卜部昌平 <shyouhei@ruby-lang.org>2019-09-04 14:08:40 +0900
commit2a6457b5b7d67378528235cee7b9cb93fed00204 (patch)
tree259635fccbca1b111074c5c0f3f2e81f235fec6f /vm_eval.c
parentccad34f4533ffe532fea796def06808dc5a85877 (diff)
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.
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/1981
Diffstat (limited to 'vm_eval.c')
-rw-r--r--vm_eval.c50
1 files changed, 50 insertions, 0 deletions
diff --git a/vm_eval.c b/vm_eval.c
index e0c308ab76..437e984596 100644
--- a/vm_eval.c
+++ b/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)
{