зеркало из https://github.com/github/ruby.git
* 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:
Родитель
3c73f44c7f
Коммит
9eba45a72a
29
ChangeLog
29
ChangeLog
|
@ -1,3 +1,32 @@
|
|||
Tue Oct 23 12:57:29 2012 Koichi Sasada <ko1@atdot.net>
|
||||
|
||||
* 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.
|
||||
|
||||
Tue Oct 23 06:21:05 2012 Aaron Patterson <aaron@tenderlovemaking.com>
|
||||
|
||||
* ext/psych/parser.c: just get the constant defined in Ruby.
|
||||
|
|
2
method.h
2
method.h
|
@ -49,7 +49,7 @@ 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);
|
||||
VALUE (*invoker)(VALUE (*func)(ANYARGS), const struct rb_call_info_struct *ci, const VALUE *argv);
|
||||
int argc;
|
||||
} rb_method_cfunc_t;
|
||||
|
||||
|
|
1
vm.c
1
vm.c
|
@ -2210,6 +2210,7 @@ Init_VM(void)
|
|||
|
||||
/* vm_backtrace.c */
|
||||
Init_vm_backtrace();
|
||||
VM_PROFILE_ATEXIT();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
24
vm_core.h
24
vm_core.h
|
@ -166,7 +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 */
|
||||
int inc_sp; /* used by cfunc */
|
||||
} aux;
|
||||
|
||||
VALUE (*call)(struct rb_thread_struct *th, struct rb_control_frame_struct *cfp, struct rb_call_info_struct *ci);
|
||||
|
@ -478,6 +478,9 @@ typedef struct rb_thread_struct {
|
|||
/* for bmethod */
|
||||
const rb_method_entry_t *passed_me;
|
||||
|
||||
/* for cfunc */
|
||||
rb_call_info_t *passed_ci;
|
||||
|
||||
/* for load(true) */
|
||||
VALUE top_self;
|
||||
VALUE top_wrapper;
|
||||
|
@ -816,7 +819,24 @@ extern rb_vm_t *ruby_current_vm;
|
|||
extern rb_event_flag_t ruby_vm_event_flags;
|
||||
|
||||
#define GET_VM() ruby_current_vm
|
||||
#define GET_THREAD() ruby_current_thread
|
||||
|
||||
#ifndef OPT_CALL_CFUNC_WITHOUT_FRAME
|
||||
#define OPT_CALL_CFUNC_WITHOUT_FRAME 0
|
||||
#endif
|
||||
|
||||
static inline rb_thread_t *
|
||||
GET_THREAD(void)
|
||||
{
|
||||
rb_thread_t *th = ruby_current_thread;
|
||||
#if OPT_CALL_CFUNC_WITHOUT_FRAME
|
||||
if (UNLIKELY(th->passed_ci != 0)) {
|
||||
void vm_call_cfunc_push_frame(rb_thread_t *th);
|
||||
vm_call_cfunc_push_frame(th);
|
||||
}
|
||||
#endif
|
||||
return th;
|
||||
}
|
||||
|
||||
#define rb_thread_set_current_raw(th) (void)(ruby_current_thread = (th))
|
||||
#define rb_thread_set_current(th) do { \
|
||||
if ((th)->vm->running_thread != (th)) { \
|
||||
|
|
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]);
|
||||
|
|
196
vm_insnhelper.c
196
vm_insnhelper.c
|
@ -1294,137 +1294,152 @@ vm_call_iseq_setup_tailcall(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_in
|
|||
}
|
||||
|
||||
static VALUE
|
||||
call_cfunc_m2(const rb_call_info_t *ci, const VALUE *argv)
|
||||
call_cfunc_m2(VALUE (*func)(ANYARGS), const rb_call_info_t *ci, const VALUE *argv)
|
||||
{
|
||||
return (ci->aux.func)(ci->recv, rb_ary_new4(ci->argc, argv));
|
||||
return (*func)(ci->recv, rb_ary_new4(ci->argc, argv));
|
||||
}
|
||||
|
||||
static VALUE
|
||||
call_cfunc_m1(const rb_call_info_t *ci, const VALUE *argv)
|
||||
call_cfunc_m1(VALUE (*func)(ANYARGS), const rb_call_info_t *ci, const VALUE *argv)
|
||||
{
|
||||
return (ci->aux.func)(ci->argc, argv, ci->recv);
|
||||
return (*func)(ci->argc, argv, ci->recv);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
call_cfunc_0(const rb_call_info_t *ci, const VALUE *argv)
|
||||
call_cfunc_0(VALUE (*func)(ANYARGS), const rb_call_info_t *ci, const VALUE *argv)
|
||||
{
|
||||
return (ci->aux.func)(ci->recv);
|
||||
return (*func)(ci->recv);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
call_cfunc_1(const rb_call_info_t *ci, const VALUE *argv)
|
||||
call_cfunc_1(VALUE (*func)(ANYARGS), const rb_call_info_t *ci, const VALUE *argv)
|
||||
{
|
||||
return (ci->aux.func)(ci->recv, argv[0]);
|
||||
return (*func)(ci->recv, argv[0]);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
call_cfunc_2(const rb_call_info_t *ci, const VALUE *argv)
|
||||
call_cfunc_2(VALUE (*func)(ANYARGS), const rb_call_info_t *ci, const VALUE *argv)
|
||||
{
|
||||
return (ci->aux.func)(ci->recv, argv[0], argv[1]);
|
||||
return (*func)(ci->recv, argv[0], argv[1]);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
call_cfunc_3(const rb_call_info_t *ci, const VALUE *argv)
|
||||
call_cfunc_3(VALUE (*func)(ANYARGS), const rb_call_info_t *ci, const VALUE *argv)
|
||||
{
|
||||
return (ci->aux.func)(ci->recv, argv[0], argv[1], argv[2]);
|
||||
return (*func)(ci->recv, argv[0], argv[1], argv[2]);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
call_cfunc_4(const rb_call_info_t *ci, const VALUE *argv)
|
||||
call_cfunc_4(VALUE (*func)(ANYARGS), const rb_call_info_t *ci, const VALUE *argv)
|
||||
{
|
||||
return (ci->aux.func)(ci->recv, argv[0], argv[1], argv[2], argv[3]);
|
||||
return (*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)
|
||||
call_cfunc_5(VALUE (*func)(ANYARGS), 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]);
|
||||
return (*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)
|
||||
call_cfunc_6(VALUE (*func)(ANYARGS), 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]);
|
||||
return (*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)
|
||||
call_cfunc_7(VALUE (*func)(ANYARGS), 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]);
|
||||
return (*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)
|
||||
call_cfunc_8(VALUE (*func)(ANYARGS), 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]);
|
||||
return (*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)
|
||||
call_cfunc_9(VALUE (*func)(ANYARGS), 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]);
|
||||
return (*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)
|
||||
call_cfunc_10(VALUE (*func)(ANYARGS), 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]);
|
||||
return (*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)
|
||||
call_cfunc_11(VALUE (*func)(ANYARGS), 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]);
|
||||
return (*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)
|
||||
call_cfunc_12(VALUE (*func)(ANYARGS), 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]);
|
||||
return (*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)
|
||||
call_cfunc_13(VALUE (*func)(ANYARGS), 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]);
|
||||
return (*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)
|
||||
call_cfunc_14(VALUE (*func)(ANYARGS), 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]);
|
||||
return (*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)
|
||||
call_cfunc_15(VALUE (*func)(ANYARGS), 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]);
|
||||
return (*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);
|
||||
#ifndef VM_PROFILE
|
||||
#define VM_PROFILE 0
|
||||
#endif
|
||||
|
||||
#if VM_PROFILE
|
||||
static int vm_profile_counter[4];
|
||||
#define VM_PROFILE_UP(x) (vm_profile_counter[x]++)
|
||||
#define VM_PROFILE_ATEXIT() atexit(vm_profile_show_result)
|
||||
static void vm_profile_show_result(void) {
|
||||
fprintf(stderr, "VM Profile results: \n");
|
||||
fprintf(stderr, "r->c call: %d\n", vm_profile_counter[0]);
|
||||
fprintf(stderr, "r->c popf: %d\n", vm_profile_counter[1]);
|
||||
fprintf(stderr, "c->c call: %d\n", vm_profile_counter[2]);
|
||||
fprintf(stderr, "r->c popf: %d\n", vm_profile_counter[3]);
|
||||
}
|
||||
#else
|
||||
#define VM_PROFILE_UP(x)
|
||||
#define VM_PROFILE_ATEXIT()
|
||||
#endif
|
||||
|
||||
static VALUE
|
||||
vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
|
||||
vm_call_cfunc_with_frame(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
|
||||
{
|
||||
volatile VALUE val = 0;
|
||||
VALUE val;
|
||||
const rb_method_entry_t *me = ci->me;
|
||||
const rb_method_definition_t *def = me->def;
|
||||
int len = def->body.cfunc.argc;
|
||||
const rb_method_cfunc_t *cfunc = &me->def->body.cfunc;
|
||||
int len = cfunc->argc;
|
||||
VALUE recv = ci->recv;
|
||||
|
||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, ci->recv, me->called_id, me->klass);
|
||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass);
|
||||
|
||||
vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, ci->recv, ci->defined_class,
|
||||
vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, recv, ci->defined_class,
|
||||
VM_ENVVAL_BLOCK_PTR(ci->blockptr), 0, th->cfp->sp, 1, me);
|
||||
|
||||
if (len >= 0) rb_check_arity(ci->argc, len, len);
|
||||
|
||||
ci->aux.func = def->body.cfunc.func;
|
||||
val = vm_call_cfunc_call(th, reg_cfp, ci);
|
||||
reg_cfp->sp -= ci->argc + 1;
|
||||
VM_PROFILE_UP(0);
|
||||
val = (*cfunc->invoker)(cfunc->func, ci, reg_cfp->sp + 1);
|
||||
|
||||
if (reg_cfp != th->cfp + 1) {
|
||||
rb_bug("vm_call_cfunc - cfp consistency error");
|
||||
|
@ -1432,11 +1447,89 @@ vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
|
|||
|
||||
vm_pop_frame(th);
|
||||
|
||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, ci->recv, me->called_id, me->klass);
|
||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->klass);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
#if OPT_CALL_CFUNC_WITHOUT_FRAME
|
||||
static VALUE
|
||||
vm_call_cfunc_latter(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
|
||||
{
|
||||
VALUE val;
|
||||
int argc = ci->argc;
|
||||
VALUE *argv = STACK_ADDR_FROM_TOP(argc);
|
||||
const rb_method_cfunc_t *cfunc = &ci->me->def->body.cfunc;
|
||||
|
||||
th->passed_ci = ci;
|
||||
reg_cfp->sp -= argc + 1;
|
||||
ci->aux.inc_sp = argc + 1;
|
||||
VM_PROFILE_UP(0);
|
||||
val = (*cfunc->invoker)(cfunc->func, ci, argv);
|
||||
|
||||
/* check */
|
||||
if (reg_cfp == th->cfp) { /* no frame push */
|
||||
if (UNLIKELY(th->passed_ci != ci)) {
|
||||
rb_bug("vm_call_cfunc_latter: passed_ci error (ci: %p, passed_ci: %p)", ci, th->passed_ci);
|
||||
}
|
||||
th->passed_ci = 0;
|
||||
}
|
||||
else {
|
||||
if (UNLIKELY(reg_cfp != RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp))) {
|
||||
rb_bug("vm_call_cfunc_latter: cfp consistency error (%p, %p)", reg_cfp, th->cfp+1);
|
||||
}
|
||||
vm_pop_frame(th);
|
||||
VM_PROFILE_UP(1);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
|
||||
{
|
||||
VALUE val;
|
||||
const rb_method_entry_t *me = ci->me;
|
||||
int len = me->def->body.cfunc.argc;
|
||||
VALUE recv = ci->recv;
|
||||
|
||||
if (len >= 0) rb_check_arity(ci->argc, len, len);
|
||||
|
||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass);
|
||||
|
||||
if (!(ci->me->flag & NOEX_PROTECTED) &&
|
||||
!(ci->flag & VM_CALL_ARGS_SPLAT)) {
|
||||
CI_SET_FASTPATH(ci, vm_call_cfunc_latter, 1);
|
||||
}
|
||||
val = vm_call_cfunc_latter(th, reg_cfp, ci);
|
||||
|
||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->klass);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void
|
||||
vm_call_cfunc_push_frame(rb_thread_t *th)
|
||||
{
|
||||
rb_call_info_t *ci = th->passed_ci;
|
||||
const rb_method_entry_t *me = ci->me;
|
||||
th->passed_ci = 0;
|
||||
|
||||
vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, ci->recv, ci->defined_class,
|
||||
VM_ENVVAL_BLOCK_PTR(ci->blockptr), 0, th->cfp->sp + ci->aux.inc_sp, 1, me);
|
||||
|
||||
if (ci->call != vm_call_general) {
|
||||
ci->call = vm_call_cfunc_with_frame;
|
||||
}
|
||||
}
|
||||
#else /* OPT_CALL_CFUNC_WITHOUT_FRAME */
|
||||
static VALUE
|
||||
vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
|
||||
{
|
||||
return vm_call_cfunc_with_frame(th, reg_cfp, ci);
|
||||
}
|
||||
#endif
|
||||
|
||||
static VALUE
|
||||
vm_call_ivar(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
|
||||
{
|
||||
|
@ -1591,10 +1684,9 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
|
|||
return vm_call_iseq_setup(th, cfp, ci);
|
||||
}
|
||||
case VM_METHOD_TYPE_NOTIMPLEMENTED:
|
||||
case VM_METHOD_TYPE_CFUNC:{
|
||||
case VM_METHOD_TYPE_CFUNC:
|
||||
CI_SET_FASTPATH(ci, vm_call_cfunc, enable_fastpath);
|
||||
return vm_call_cfunc(th, cfp, ci);
|
||||
}
|
||||
case VM_METHOD_TYPE_ATTRSET:{
|
||||
rb_check_arity(ci->argc, 0, 1);
|
||||
ci->aux.index = 0;
|
||||
|
|
|
@ -304,7 +304,7 @@ method_added(VALUE klass, ID mid)
|
|||
}
|
||||
|
||||
static VALUE
|
||||
(*call_cfunc_invoker_func(int argc))(const rb_call_info_t *, const VALUE *)
|
||||
(*call_cfunc_invoker_func(int argc))(VALUE (*func)(ANYARGS), const rb_call_info_t *, const VALUE *)
|
||||
{
|
||||
switch (argc) {
|
||||
case -2: return call_cfunc_m2;
|
||||
|
|
Загрузка…
Ссылка в новой задаче