summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog29
-rw-r--r--method.h2
-rw-r--r--vm.c1
-rw-r--r--vm_core.h24
-rw-r--r--vm_eval.c108
-rw-r--r--vm_insnhelper.c196
-rw-r--r--vm_method.c2
7 files changed, 278 insertions, 84 deletions
diff --git a/ChangeLog b/ChangeLog
index 2fa0142f87..8fc021deff 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,32 @@
+Tue Oct 23 12:57:29 2012 Koichi Sasada <ko1@atdot.net>
+
+ * vm_core.h, vm_insnhelper.c, vm_eval.c (OPT_CALL_CFUNC_WITHOUT_FRAME):
+ add a new otpimization and its macro `OPT_CALL_CFUNC_WITHOUT_FRAME'.
+ This optimization makes all cfunc method calls `frameless', which
+ is fster than ordinal cfunc method call.
+ If `frame' is needed (for example, it calls another method with
+ `rb_funcall()'), then build a frame. In other words, this
+ optimization delays frame building.
+ However, to delay the frame building, we need additional overheads:
+ (1) Store the last call information.
+ (2) Check the delayed frame buidling before the frame is needed.
+ (3) Overhead to build a delayed frame.
+ rb_thread_t::passed_ci is storage of delayed cfunc call information.
+ (1) is lightweight because it is only 1 assignment to `passed_ci'.
+ To achieve (2), we modify GET_THREAD() to check `passed_ci' every
+ time. It causes 10% overhead on my envrionment.
+ This optimization only works for cfunc methods which do not need
+ their `frame'.
+ After evaluation on my environment, this optimization does not
+ effective every time. Because of this evaluation results, this
+ optimization is disabled at default.
+
+ * vm_insnhelper.c, vm.c: add VM_PROFILE* macros to measure behaviour
+ of VM internals. I will extend this feature.
+
+ * vm_method.c, method.h: change parameters of the `invoker' function.
+ Receive `func' pointer as the first parameter.
+
Tue Oct 23 06:21:05 2012 Aaron Patterson <aaron@tenderlovemaking.com>
* ext/psych/parser.c: just get the constant defined in Ruby.
diff --git a/method.h b/method.h
index ba5899ca93..7f08ea261c 100644
--- a/method.h
+++ b/method.h
@@ -49,7 +49,7 @@ struct rb_call_info_struct;
typedef struct rb_method_cfunc_struct {
VALUE (*func)(ANYARGS);
- VALUE (*invoker)(const struct rb_call_info_struct *ci, const VALUE *argv);
+ VALUE (*invoker)(VALUE (*func)(ANYARGS), const struct rb_call_info_struct *ci, const VALUE *argv);
int argc;
} rb_method_cfunc_t;
diff --git a/vm.c b/vm.c
index f8d59ba563..c47b5924f8 100644
--- a/vm.c
+++ b/vm.c
@@ -2210,6 +2210,7 @@ Init_VM(void)
/* vm_backtrace.c */
Init_vm_backtrace();
+ VM_PROFILE_ATEXIT();
}
void
diff --git a/vm_core.h b/vm_core.h
index 5e68b8e9ab..e2d18c1aab 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -166,7 +166,7 @@ typedef struct rb_call_info_struct {
int opt_pc; /* used by iseq */
long index; /* used by ivar */
int missing_reason; /* used by method_missing */
- VALUE (*func)(ANYARGS); /* used by cfunc */
+ int inc_sp; /* used by cfunc */
} aux;
VALUE (*call)(struct rb_thread_struct *th, struct rb_control_frame_struct *cfp, struct rb_call_info_struct *ci);
@@ -478,6 +478,9 @@ typedef struct rb_thread_struct {
/* for bmethod */
const rb_method_entry_t *passed_me;
+ /* for cfunc */
+ rb_call_info_t *passed_ci;
+
/* for load(true) */
VALUE top_self;
VALUE top_wrapper;
@@ -816,7 +819,24 @@ extern rb_vm_t *ruby_current_vm;
extern rb_event_flag_t ruby_vm_event_flags;
#define GET_VM() ruby_current_vm
-#define GET_THREAD() ruby_current_thread
+
+#ifndef OPT_CALL_CFUNC_WITHOUT_FRAME
+#define OPT_CALL_CFUNC_WITHOUT_FRAME 0
+#endif
+
+static inline rb_thread_t *
+GET_THREAD(void)
+{
+ rb_thread_t *th = ruby_current_thread;
+#if OPT_CALL_CFUNC_WITHOUT_FRAME
+ if (UNLIKELY(th->passed_ci != 0)) {
+ void vm_call_cfunc_push_frame(rb_thread_t *th);
+ vm_call_cfunc_push_frame(th);
+ }
+#endif
+ return th;
+}
+
#define rb_thread_set_current_raw(th) (void)(ruby_current_thread = (th))
#define rb_thread_set_current(th) do { \
if ((th)->vm->running_thread != (th)) { \
diff --git a/vm_eval.c b/vm_eval.c
index 0cf82b2020..f4208dee38 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -49,6 +49,84 @@ vm_call0(rb_thread_t* th, VALUE recv, VALUE id, int argc, const VALUE *argv,
return vm_call0_body(th, ci, argv);
}
+#if OPT_CALL_CFUNC_WITHOUT_FRAME
+static VALUE
+vm_call0_cfunc(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv)
+{
+ VALUE val;
+
+ EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, ci->recv, ci->mid, ci->defined_class);
+ {
+ rb_control_frame_t *reg_cfp = th->cfp;
+ const rb_method_entry_t *me = ci->me;
+ const rb_method_cfunc_t *cfunc = &me->def->body.cfunc;
+ int len = cfunc->argc;
+
+ if (len >= 0) rb_check_arity(ci->argc, len, len);
+
+ th->passed_ci = ci;
+ ci->aux.inc_sp = 0;
+ VM_PROFILE_UP(2);
+ val = (*cfunc->invoker)(cfunc->func, ci, argv);
+
+ if (reg_cfp == th->cfp) {
+ if (UNLIKELY(th->passed_ci != ci)) {
+ rb_bug("vm_call0_cfunc: passed_ci error (ci: %p, passed_ci: %p)", ci, th->passed_ci);
+ }
+ th->passed_ci = 0;
+ }
+ else {
+ if (reg_cfp != th->cfp + 1) {
+ rb_bug("vm_call0_cfunc: cfp consistency error");
+ }
+ VM_PROFILE_UP(3);
+ vm_pop_frame(th);
+ }
+ }
+ EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, ci->recv, ci->mid, ci->defined_class);
+
+ return val;
+}
+#else
+static VALUE
+vm_call0_cfunc_with_frame(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv)
+{
+ VALUE val;
+
+ EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, ci->recv, ci->mid, ci->defined_class);
+ {
+ rb_control_frame_t *reg_cfp = th->cfp;
+ const rb_method_entry_t *me = ci->me;
+ const rb_method_cfunc_t *cfunc = &me->def->body.cfunc;
+ int len = cfunc->argc;
+
+ vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC,
+ ci->recv, ci->defined_class, VM_ENVVAL_BLOCK_PTR(ci->blockptr),
+ 0, reg_cfp->sp, 1, ci->me);
+
+ if (len >= 0) rb_check_arity(ci->argc, len, len);
+
+ VM_PROFILE_UP(2);
+ val = (*cfunc->invoker)(cfunc->func, ci, argv);
+
+ if (UNLIKELY(reg_cfp != th->cfp + 1)) {
+ rb_bug("vm_call0_cfunc_with_frame: cfp consistency error");
+ }
+ VM_PROFILE_UP(3);
+ vm_pop_frame(th);
+ }
+ EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, ci->recv, ci->mid, ci->defined_class);
+
+ return val;
+}
+
+static VALUE
+vm_call0_cfunc(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv)
+{
+ return vm_call0_cfunc_with_frame(th, ci, argv);
+}
+#endif
+
/* `ci' should point temporal value (on stack value) */
static VALUE
vm_call0_body(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv)
@@ -84,35 +162,9 @@ vm_call0_body(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv)
break;
}
case VM_METHOD_TYPE_NOTIMPLEMENTED:
- case VM_METHOD_TYPE_CFUNC: {
- EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, ci->recv, ci->mid, ci->defined_class);
- {
- rb_control_frame_t *reg_cfp = th->cfp;
- rb_control_frame_t *cfp = vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC,
- ci->recv, ci->defined_class, VM_ENVVAL_BLOCK_PTR(ci->blockptr),
- 0, reg_cfp->sp, 1, ci->me);
-
- cfp->me = ci->me;
-
- {
- const rb_method_entry_t *me = ci->me;
- const rb_method_definition_t *def = me->def;
- int len = def->body.cfunc.argc;
-
- if (len >= 0) rb_check_arity(ci->argc, len, len);
-
- ci->aux.func = def->body.cfunc.func;
- val = (*def->body.cfunc.invoker)(ci, argv);
- }
-
- if (reg_cfp != th->cfp + 1) {
- rb_bug("cfp consistency error - call0");
- }
- vm_pop_frame(th);
- }
- EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, ci->recv, ci->mid, ci->defined_class);
+ case VM_METHOD_TYPE_CFUNC:
+ val = vm_call0_cfunc(th, ci, argv);
break;
- }
case VM_METHOD_TYPE_ATTRSET: {
rb_check_arity(ci->argc, 1, 1);
val = rb_ivar_set(ci->recv, ci->me->def->body.attr.id, argv[0]);
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index ea5124c2bd..1ba1ce582b 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -1294,137 +1294,152 @@ vm_call_iseq_setup_tailcall(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_in
}
static VALUE
-call_cfunc_m2(const rb_call_info_t *ci, const VALUE *argv)
+call_cfunc_m2(VALUE (*func)(ANYARGS), const rb_call_info_t *ci, const VALUE *argv)
{
- return (ci->aux.func)(ci->recv, rb_ary_new4(ci->argc, argv));
+ return (*func)(ci->recv, rb_ary_new4(ci->argc, argv));
}
static VALUE
-call_cfunc_m1(const rb_call_info_t *ci, const VALUE *argv)
+call_cfunc_m1(VALUE (*func)(ANYARGS), const rb_call_info_t *ci, const VALUE *argv)
{
- return (ci->aux.func)(ci->argc, argv, ci->recv);
+ return (*func)(ci->argc, argv, ci->recv);
}
static VALUE
-call_cfunc_0(const rb_call_info_t *ci, const VALUE *argv)
+call_cfunc_0(VALUE (*func)(ANYARGS), const rb_call_info_t *ci, const VALUE *argv)
{
- return (ci->aux.func)(ci->recv);
+ return (*func)(ci->recv);
}
static VALUE
-call_cfunc_1(const rb_call_info_t *ci, const VALUE *argv)
+call_cfunc_1(VALUE (*func)(ANYARGS), const rb_call_info_t *ci, const VALUE *argv)
{
- return (ci->aux.func)(ci->recv, argv[0]);
+ return (*func)(ci->recv, argv[0]);
}
static VALUE
-call_cfunc_2(const rb_call_info_t *ci, const VALUE *argv)
+call_cfunc_2(VALUE (*func)(ANYARGS), const rb_call_info_t *ci, const VALUE *argv)
{
- return (ci->aux.func)(ci->recv, argv[0], argv[1]);
+ return (*func)(ci->recv, argv[0], argv[1]);
}
static VALUE
-call_cfunc_3(const rb_call_info_t *ci, const VALUE *argv)
+call_cfunc_3(VALUE (*func)(ANYARGS), const rb_call_info_t *ci, const VALUE *argv)
{
- return (ci->aux.func)(ci->recv, argv[0], argv[1], argv[2]);
+ return (*func)(ci->recv, argv[0], argv[1], argv[2]);
}
static VALUE
-call_cfunc_4(const rb_call_info_t *ci, const VALUE *argv)
+call_cfunc_4(VALUE (*func)(ANYARGS), const rb_call_info_t *ci, const VALUE *argv)
{
- return (ci->aux.func)(ci->recv, argv[0], argv[1], argv[2], argv[3]);
+ return (*func)(ci->recv, argv[0], argv[1], argv[2], argv[3]);
}
static VALUE
-call_cfunc_5(const rb_call_info_t *ci, const VALUE *argv)
+call_cfunc_5(VALUE (*func)(ANYARGS), const rb_call_info_t *ci, const VALUE *argv)
{
- return (ci->aux.func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4]);
+ return (*func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4]);
}
static VALUE
-call_cfunc_6(const rb_call_info_t *ci, const VALUE *argv)
+call_cfunc_6(VALUE (*func)(ANYARGS), const rb_call_info_t *ci, const VALUE *argv)
{
- return (ci->aux.func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
+ return (*func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
}
static VALUE
-call_cfunc_7(const rb_call_info_t *ci, const VALUE *argv)
+call_cfunc_7(VALUE (*func)(ANYARGS), const rb_call_info_t *ci, const VALUE *argv)
{
- return (ci->aux.func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
+ return (*func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
}
static VALUE
-call_cfunc_8(const rb_call_info_t *ci, const VALUE *argv)
+call_cfunc_8(VALUE (*func)(ANYARGS), const rb_call_info_t *ci, const VALUE *argv)
{
- return (ci->aux.func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);
+ return (*func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);
}
static VALUE
-call_cfunc_9(const rb_call_info_t *ci, const VALUE *argv)
+call_cfunc_9(VALUE (*func)(ANYARGS), const rb_call_info_t *ci, const VALUE *argv)
{
- return (ci->aux.func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]);
+ return (*func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]);
}
static VALUE
-call_cfunc_10(const rb_call_info_t *ci, const VALUE *argv)
+call_cfunc_10(VALUE (*func)(ANYARGS), const rb_call_info_t *ci, const VALUE *argv)
{
- return (ci->aux.func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9]);
+ return (*func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9]);
}
static VALUE
-call_cfunc_11(const rb_call_info_t *ci, const VALUE *argv)
+call_cfunc_11(VALUE (*func)(ANYARGS), const rb_call_info_t *ci, const VALUE *argv)
{
- return (ci->aux.func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10]);
+ return (*func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10]);
}
static VALUE
-call_cfunc_12(const rb_call_info_t *ci, const VALUE *argv)
+call_cfunc_12(VALUE (*func)(ANYARGS), const rb_call_info_t *ci, const VALUE *argv)
{
- return (ci->aux.func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11]);
+ return (*func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11]);
}
static VALUE
-call_cfunc_13(const rb_call_info_t *ci, const VALUE *argv)
+call_cfunc_13(VALUE (*func)(ANYARGS), const rb_call_info_t *ci, const VALUE *argv)
{
- return (ci->aux.func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12]);
+ return (*func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12]);
}
static VALUE
-call_cfunc_14(const rb_call_info_t *ci, const VALUE *argv)
+call_cfunc_14(VALUE (*func)(ANYARGS), const rb_call_info_t *ci, const VALUE *argv)
{
- return (ci->aux.func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13]);
+ return (*func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13]);
}
static VALUE
-call_cfunc_15(const rb_call_info_t *ci, const VALUE *argv)
+call_cfunc_15(VALUE (*func)(ANYARGS), const rb_call_info_t *ci, const VALUE *argv)
{
- return (ci->aux.func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14]);
+ return (*func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14]);
}
-static VALUE
-vm_call_cfunc_call(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
-{
- reg_cfp->sp -= ci->argc + 1;
- return (*ci->me->def->body.cfunc.invoker)(ci, reg_cfp->sp + 1);
+#ifndef VM_PROFILE
+#define VM_PROFILE 0
+#endif
+
+#if VM_PROFILE
+static int vm_profile_counter[4];
+#define VM_PROFILE_UP(x) (vm_profile_counter[x]++)
+#define VM_PROFILE_ATEXIT() atexit(vm_profile_show_result)
+static void vm_profile_show_result(void) {
+ fprintf(stderr, "VM Profile results: \n");
+ fprintf(stderr, "r->c call: %d\n", vm_profile_counter[0]);
+ fprintf(stderr, "r->c popf: %d\n", vm_profile_counter[1]);
+ fprintf(stderr, "c->c call: %d\n", vm_profile_counter[2]);
+ fprintf(stderr, "r->c popf: %d\n", vm_profile_counter[3]);
}
+#else
+#define VM_PROFILE_UP(x)
+#define VM_PROFILE_ATEXIT()
+#endif
static VALUE
-vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
+vm_call_cfunc_with_frame(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
{
- volatile VALUE val = 0;
+ VALUE val;
const rb_method_entry_t *me = ci->me;
- const rb_method_definition_t *def = me->def;
- int len = def->body.cfunc.argc;
+ const rb_method_cfunc_t *cfunc = &me->def->body.cfunc;
+ int len = cfunc->argc;
+ VALUE recv = ci->recv;
- EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, ci->recv, me->called_id, me->klass);
+ EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass);
- vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, ci->recv, ci->defined_class,
+ vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, recv, ci->defined_class,
VM_ENVVAL_BLOCK_PTR(ci->blockptr), 0, th->cfp->sp, 1, me);
if (len >= 0) rb_check_arity(ci->argc, len, len);
- ci->aux.func = def->body.cfunc.func;
- val = vm_call_cfunc_call(th, reg_cfp, ci);
+ reg_cfp->sp -= ci->argc + 1;
+ VM_PROFILE_UP(0);
+ val = (*cfunc->invoker)(cfunc->func, ci, reg_cfp->sp + 1);
if (reg_cfp != th->cfp + 1) {
rb_bug("vm_call_cfunc - cfp consistency error");
@@ -1432,11 +1447,89 @@ vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
vm_pop_frame(th);
- EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, ci->recv, me->called_id, me->klass);
+ EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->klass);
+
+ return val;
+}
+
+#if OPT_CALL_CFUNC_WITHOUT_FRAME
+static VALUE
+vm_call_cfunc_latter(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
+{
+ VALUE val;
+ int argc = ci->argc;
+ VALUE *argv = STACK_ADDR_FROM_TOP(argc);
+ const rb_method_cfunc_t *cfunc = &ci->me->def->body.cfunc;
+
+ th->passed_ci = ci;
+ reg_cfp->sp -= argc + 1;
+ ci->aux.inc_sp = argc + 1;
+ VM_PROFILE_UP(0);
+ val = (*cfunc->invoker)(cfunc->func, ci, argv);
+
+ /* check */
+ if (reg_cfp == th->cfp) { /* no frame push */
+ if (UNLIKELY(th->passed_ci != ci)) {
+ rb_bug("vm_call_cfunc_latter: passed_ci error (ci: %p, passed_ci: %p)", ci, th->passed_ci);
+ }
+ th->passed_ci = 0;
+ }
+ else {
+ if (UNLIKELY(reg_cfp != RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp))) {
+ rb_bug("vm_call_cfunc_latter: cfp consistency error (%p, %p)", reg_cfp, th->cfp+1);
+ }
+ vm_pop_frame(th);
+ VM_PROFILE_UP(1);
+ }
+
+ return val;
+}
+
+static VALUE
+vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
+{
+ VALUE val;
+ const rb_method_entry_t *me = ci->me;
+ int len = me->def->body.cfunc.argc;
+ VALUE recv = ci->recv;
+
+ if (len >= 0) rb_check_arity(ci->argc, len, len);
+
+ EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass);
+
+ if (!(ci->me->flag & NOEX_PROTECTED) &&
+ !(ci->flag & VM_CALL_ARGS_SPLAT)) {
+ CI_SET_FASTPATH(ci, vm_call_cfunc_latter, 1);
+ }
+ val = vm_call_cfunc_latter(th, reg_cfp, ci);
+
+ EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->klass);
return val;
}
+void
+vm_call_cfunc_push_frame(rb_thread_t *th)
+{
+ rb_call_info_t *ci = th->passed_ci;
+ const rb_method_entry_t *me = ci->me;
+ th->passed_ci = 0;
+
+ vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, ci->recv, ci->defined_class,
+ VM_ENVVAL_BLOCK_PTR(ci->blockptr), 0, th->cfp->sp + ci->aux.inc_sp, 1, me);
+
+ if (ci->call != vm_call_general) {
+ ci->call = vm_call_cfunc_with_frame;
+ }
+}
+#else /* OPT_CALL_CFUNC_WITHOUT_FRAME */
+static VALUE
+vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
+{
+ return vm_call_cfunc_with_frame(th, reg_cfp, ci);
+}
+#endif
+
static VALUE
vm_call_ivar(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
{
@@ -1591,10 +1684,9 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
return vm_call_iseq_setup(th, cfp, ci);
}
case VM_METHOD_TYPE_NOTIMPLEMENTED:
- case VM_METHOD_TYPE_CFUNC:{
+ case VM_METHOD_TYPE_CFUNC:
CI_SET_FASTPATH(ci, vm_call_cfunc, enable_fastpath);
return vm_call_cfunc(th, cfp, ci);
- }
case VM_METHOD_TYPE_ATTRSET:{
rb_check_arity(ci->argc, 0, 1);
ci->aux.index = 0;
diff --git a/vm_method.c b/vm_method.c
index 6cec0ab1f8..8994fa2c2e 100644
--- a/vm_method.c
+++ b/vm_method.c
@@ -304,7 +304,7 @@ method_added(VALUE klass, ID mid)
}
static VALUE
-(*call_cfunc_invoker_func(int argc))(const rb_call_info_t *, const VALUE *)
+(*call_cfunc_invoker_func(int argc))(VALUE (*func)(ANYARGS), const rb_call_info_t *, const VALUE *)
{
switch (argc) {
case -2: return call_cfunc_m2;