mirror of
https://github.com/ruby/ruby.git
synced 2025-09-15 08:33:58 +02:00
* 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
This commit is contained in:
parent
3c73f44c7f
commit
9eba45a72a
7 changed files with 278 additions and 84 deletions
108
vm_eval.c
108
vm_eval.c
|
@ -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]);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue