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 + + * 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 * 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;