Skip to content

Commit

Permalink
* method.h (rb_method_cfunc_t::invoker): add new field (func ptr)
Browse files Browse the repository at this point in the history
  `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
  • Loading branch information
ko1 committed Oct 19, 2012
1 parent 0fc7f4b commit f4dbc7a
Show file tree
Hide file tree
Showing 6 changed files with 197 additions and 87 deletions.
27 changes: 27 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,30 @@
Fri Oct 19 19:29:11 2012 Koichi Sasada <[email protected]>

* 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 <[email protected]>

* eval.c, vm_eval.c: use TH_PUSH_TAG() instead of PUSH_TAG().
Expand Down
3 changes: 3 additions & 0 deletions method.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
1 change: 1 addition & 0 deletions vm_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
13 changes: 11 additions & 2 deletions vm_eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
197 changes: 115 additions & 82 deletions vm_insnhelper.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
Expand Down
43 changes: 40 additions & 3 deletions vm_method.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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:
Expand All @@ -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;
Expand Down

0 comments on commit f4dbc7a

Please sign in to comment.