diff options
author | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-10-23 04:22:31 +0000 |
---|---|---|
committer | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-10-23 04:22:31 +0000 |
commit | 9eba45a72a63674e35d0e9dec6ddf73088ed39e8 (patch) | |
tree | 4d7ee4eb683d9f88c9a7c490cad5f66bea96d801 /vm_eval.c | |
parent | 3c73f44c7f779fe9eea823457c4f288aa21d3c32 (diff) |
* 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.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37293 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'vm_eval.c')
-rw-r--r-- | vm_eval.c | 108 |
1 files changed, 80 insertions, 28 deletions
@@ -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]); |