ruby-changes:25216
From: ko1 <ko1@a...>
Date: Fri, 19 Oct 2012 19:38:42 +0900 (JST)
Subject: [ruby-changes:25216] ko1:r37268 (trunk): * method.h (rb_method_cfunc_t::invoker): add new field (func ptr)
ko1 2012-10-19 19:38:30 +0900 (Fri, 19 Oct 2012) New Revision: 37268 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=37268 Log: * 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. Modified files: trunk/ChangeLog trunk/method.h trunk/vm_core.h trunk/vm_eval.c trunk/vm_insnhelper.c trunk/vm_method.c Index: method.h =================================================================== --- method.h (revision 37267) +++ method.h (revision 37268) @@ -45,8 +45,11 @@ 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; Index: ChangeLog =================================================================== --- ChangeLog (revision 37267) +++ ChangeLog (revision 37268) @@ -1,3 +1,30 @@ +Fri Oct 19 19:29:11 2012 Koichi Sasada <ko1@a...> + + * 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@a...> * eval.c, vm_eval.c: use TH_PUSH_TAG() instead of PUSH_TAG(). Index: vm_core.h =================================================================== --- vm_core.h (revision 37267) +++ vm_core.h (revision 37268) @@ -166,6 +166,7 @@ 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); Index: vm_eval.c =================================================================== --- vm_eval.c (revision 37267) +++ vm_eval.c (revision 37268) @@ -93,9 +93,18 @@ 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"); } Index: vm_method.c =================================================================== --- vm_method.c (revision 37267) +++ vm_method.c (revision 37268) @@ -303,6 +303,41 @@ } } +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 @@ 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 @@ 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; Index: vm_insnhelper.c =================================================================== --- vm_insnhelper.c (revision 37267) +++ vm_insnhelper.c (revision 37268) @@ -1293,108 +1293,141 @@ 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 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); -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/