summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-10-19 10:38:30 +0000
committerko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-10-19 10:38:30 +0000
commitf4dbc7a3849988ebe75d3e1031aa50441347c497 (patch)
tree9750044142c879b0abc569e92dedaeeee5158d12
parent0fc7f4bb304ad07e8172f868d885112a1dcceb0f (diff)
* method.h (rb_method_cfunc_t::invoker): add new field (func ptr)
`invoker'. `invoker' function invoke cfunc body (rb_method_cfunc_t::func). `invoker' is set at method definition timing. With this change, the big `switch' (branch) in `call_cfunc()' is no longer needed. However, the performance benefit is only a bit. * vm_core.h (rb_call_info_t::aux::func): add a new field to store cfunc body function pointer. * vm_method.c (call_cfunc_invoker_func): add a new function which returns a suitable invoke function. * vm_method.c (setup_method_cfunc_struct): added. * vm_method.c (rb_add_method): fix to set `invoker'. * vm_eval.c (vm_call0_body): catch up above changes. * vm_insnhelper.c (call_cfunc): removed. * vm_insnhelper.c (vm_call_cfunc): fix to call cfunc body with `invoker' function. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37268 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog27
-rw-r--r--method.h3
-rw-r--r--vm_core.h1
-rw-r--r--vm_eval.c13
-rw-r--r--vm_insnhelper.c197
-rw-r--r--vm_method.c43
6 files changed, 197 insertions, 87 deletions
diff --git a/ChangeLog b/ChangeLog
index 4333c4a7b3..32696cf9ed 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,30 @@
+Fri Oct 19 19:29:11 2012 Koichi Sasada <ko1@atdot.net>
+
+ * method.h (rb_method_cfunc_t::invoker): add new field (func ptr)
+ `invoker'. `invoker' function invoke cfunc body
+ (rb_method_cfunc_t::func).
+ `invoker' is set at method definition timing.
+ With this change, the big `switch' (branch) in `call_cfunc()'
+ is no longer needed.
+ However, the performance benefit is only a bit.
+
+ * vm_core.h (rb_call_info_t::aux::func): add a new field to store
+ cfunc body function pointer.
+
+ * vm_method.c (call_cfunc_invoker_func): add a new function which
+ returns a suitable invoke function.
+
+ * vm_method.c (setup_method_cfunc_struct): added.
+
+ * vm_method.c (rb_add_method): fix to set `invoker'.
+
+ * vm_eval.c (vm_call0_body): catch up above changes.
+
+ * vm_insnhelper.c (call_cfunc): removed.
+
+ * vm_insnhelper.c (vm_call_cfunc): fix to call cfunc body
+ with `invoker' function.
+
Fri Oct 19 16:55:58 2012 Koichi Sasada <ko1@atdot.net>
* eval.c, vm_eval.c: use TH_PUSH_TAG() instead of PUSH_TAG().
diff --git a/method.h b/method.h
index cc7b51dddb..ba5899ca93 100644
--- a/method.h
+++ b/method.h
@@ -45,8 +45,11 @@ typedef enum {
VM_METHOD_TYPE_CFUNC_FRAMELESS
} rb_method_type_t;
+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);
int argc;
} rb_method_cfunc_t;
diff --git a/vm_core.h b/vm_core.h
index 9f6f638c4d..548986dc56 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -166,6 +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 */
} aux;
VALUE (*call)(struct rb_thread_struct *th, struct rb_control_frame_struct *cfp, struct rb_call_info_struct *ci);
diff --git a/vm_eval.c b/vm_eval.c
index 4b1c95c0fd..2bc19c804a 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -93,8 +93,17 @@ vm_call0_body(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv)
0, reg_cfp->sp, 1, ci->me);
cfp->me = ci->me;
- val = call_cfunc(ci->me->def->body.cfunc.func, ci->recv,
- ci->me->def->body.cfunc.argc, ci->argc, argv);
+
+ {
+ 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");
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 09e5e6390b..ea5124c2bd 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -1293,88 +1293,119 @@ vm_call_iseq_setup_tailcall(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_in
return Qundef;
}
-static inline VALUE
-call_cfunc(VALUE (*func)(), VALUE recv,
- int len, int argc, const VALUE *argv)
+static VALUE
+call_cfunc_m2(const rb_call_info_t *ci, const VALUE *argv)
{
- /* printf("len: %d, argc: %d\n", len, argc); */
+ return (ci->aux.func)(ci->recv, rb_ary_new4(ci->argc, argv));
+}
- if (len >= 0) rb_check_arity(argc, len, len);
+static VALUE
+call_cfunc_m1(const rb_call_info_t *ci, const VALUE *argv)
+{
+ return (ci->aux.func)(ci->argc, argv, ci->recv);
+}
- switch (len) {
- case -2:
- return (*func) (recv, rb_ary_new4(argc, argv));
- break;
- case -1:
- return (*func) (argc, argv, recv);
- break;
- case 0:
- return (*func) (recv);
- break;
- case 1:
- return (*func) (recv, argv[0]);
- break;
- case 2:
- return (*func) (recv, argv[0], argv[1]);
- break;
- case 3:
- return (*func) (recv, argv[0], argv[1], argv[2]);
- break;
- case 4:
- return (*func) (recv, argv[0], argv[1], argv[2], argv[3]);
- break;
- case 5:
- return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4]);
- break;
- case 6:
- return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
- argv[5]);
- break;
- case 7:
- return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
- argv[5], argv[6]);
- break;
- case 8:
- return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
- argv[5], argv[6], argv[7]);
- break;
- case 9:
- return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
- argv[5], argv[6], argv[7], argv[8]);
- break;
- case 10:
- return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
- argv[5], argv[6], argv[7], argv[8], argv[9]);
- break;
- case 11:
- return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
- argv[5], argv[6], argv[7], argv[8], argv[9],
- argv[10]);
- break;
- case 12:
- return (*func) (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]);
- break;
- case 13:
- return (*func) (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]);
- break;
- case 14:
- return (*func) (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]);
- break;
- case 15:
- return (*func) (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]);
- break;
- default:
- rb_raise(rb_eArgError, "too many arguments(%d)", len);
- UNREACHABLE;
- }
+static VALUE
+call_cfunc_0(const rb_call_info_t *ci, const VALUE *argv)
+{
+ return (ci->aux.func)(ci->recv);
+}
+
+static VALUE
+call_cfunc_1(const rb_call_info_t *ci, const VALUE *argv)
+{
+ return (ci->aux.func)(ci->recv, argv[0]);
+}
+
+static VALUE
+call_cfunc_2(const rb_call_info_t *ci, const VALUE *argv)
+{
+ return (ci->aux.func)(ci->recv, argv[0], argv[1]);
+}
+
+static VALUE
+call_cfunc_3(const rb_call_info_t *ci, const VALUE *argv)
+{
+ return (ci->aux.func)(ci->recv, argv[0], argv[1], argv[2]);
+}
+
+static VALUE
+call_cfunc_4(const rb_call_info_t *ci, const VALUE *argv)
+{
+ return (ci->aux.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)
+{
+ return (ci->aux.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)
+{
+ return (ci->aux.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)
+{
+ return (ci->aux.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)
+{
+ return (ci->aux.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)
+{
+ return (ci->aux.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)
+{
+ 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]);
+}
+
+static VALUE
+call_cfunc_11(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]);
+}
+
+static VALUE
+call_cfunc_12(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]);
+}
+
+static VALUE
+call_cfunc_13(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]);
+}
+
+static VALUE
+call_cfunc_14(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]);
+}
+
+static VALUE
+call_cfunc_15(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]);
+}
+
+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);
}
static VALUE
@@ -1383,18 +1414,20 @@ vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
volatile VALUE val = 0;
const rb_method_entry_t *me = ci->me;
const rb_method_definition_t *def = me->def;
+ int len = def->body.cfunc.argc;
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, ci->recv, me->called_id, me->klass);
vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, ci->recv, ci->defined_class,
VM_ENVVAL_BLOCK_PTR(ci->blockptr), 0, th->cfp->sp, 1, me);
- reg_cfp->sp -= ci->argc + 1;
+ if (len >= 0) rb_check_arity(ci->argc, len, len);
- val = call_cfunc(def->body.cfunc.func, ci->recv, (int)def->body.cfunc.argc, ci->argc, reg_cfp->sp + 1);
+ ci->aux.func = def->body.cfunc.func;
+ val = vm_call_cfunc_call(th, reg_cfp, ci);
if (reg_cfp != th->cfp + 1) {
- rb_bug("cfp consistency error - send");
+ rb_bug("vm_call_cfunc - cfp consistency error");
}
vm_pop_frame(th);
diff --git a/vm_method.c b/vm_method.c
index 058b03dac6..6cec0ab1f8 100644
--- a/vm_method.c
+++ b/vm_method.c
@@ -303,6 +303,41 @@ method_added(VALUE klass, ID mid)
}
}
+static VALUE
+(*call_cfunc_invoker_func(int argc))(const rb_call_info_t *, const VALUE *)
+{
+ switch (argc) {
+ case -2: return call_cfunc_m2;
+ case -1: return call_cfunc_m1;
+ case 0: return call_cfunc_0;
+ case 1: return call_cfunc_1;
+ case 2: return call_cfunc_2;
+ case 3: return call_cfunc_3;
+ case 4: return call_cfunc_4;
+ case 5: return call_cfunc_5;
+ case 6: return call_cfunc_6;
+ case 7: return call_cfunc_7;
+ case 8: return call_cfunc_8;
+ case 9: return call_cfunc_9;
+ case 10: return call_cfunc_10;
+ case 11: return call_cfunc_11;
+ case 12: return call_cfunc_12;
+ case 13: return call_cfunc_13;
+ case 14: return call_cfunc_14;
+ case 15: return call_cfunc_15;
+ default:
+ rb_bug("call_cfunc_func: unsupported length: %d", argc);
+ }
+}
+
+static void
+setup_method_cfunc_struct(rb_method_cfunc_t *cfunc, VALUE (*func)(), int argc)
+{
+ cfunc->func = func;
+ cfunc->argc = argc;
+ cfunc->invoker = call_cfunc_invoker_func(argc);
+}
+
rb_method_entry_t *
rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *opts, rb_method_flag_t noex)
{
@@ -321,7 +356,10 @@ rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *opts, rb_method_
break;
case VM_METHOD_TYPE_CFUNC:
case VM_METHOD_TYPE_CFUNC_FRAMELESS:
- def->body.cfunc = *(rb_method_cfunc_t *)opts;
+ {
+ rb_method_cfunc_t *cfunc = (rb_method_cfunc_t *)opts;
+ setup_method_cfunc_struct(&def->body.cfunc, cfunc->func, cfunc->argc);
+ }
break;
case VM_METHOD_TYPE_ATTRSET:
case VM_METHOD_TYPE_IVAR:
@@ -338,8 +376,7 @@ rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *opts, rb_method_
def->body.proc = (VALUE)opts;
break;
case VM_METHOD_TYPE_NOTIMPLEMENTED:
- def->body.cfunc.func = rb_f_notimplement;
- def->body.cfunc.argc = -1;
+ setup_method_cfunc_struct(&def->body.cfunc, rb_f_notimplement, -1);
break;
case VM_METHOD_TYPE_OPTIMIZED:
def->body.optimize_type = (enum method_optimized_type)opts;