Feature #10256 » 0001-rb_call_info_t-reduce-from-96-88-bytes-on-64-bit.patch
compile.c | ||
---|---|---|
{
|
||
rb_call_info_t *ci = (rb_call_info_t *)compile_data_alloc(iseq, sizeof(rb_call_info_t));
|
||
ci->mid = mid;
|
||
/* ci->fn = no default */
|
||
ci->flag = flag;
|
||
ci->orig_argc = argc;
|
||
ci->argc = argc;
|
||
... | ... | |
ci->class_serial = 0;
|
||
ci->blockptr = 0;
|
||
ci->recv = Qundef;
|
||
ci->call = 0; /* TODO: should set default function? */
|
||
ci->aux.index = iseq->callinfo_size++;
|
||
vm_core.h | ||
---|---|---|
typedef struct rb_call_info_struct {
|
||
/* fixed at compile time */
|
||
ID mid;
|
||
unsigned int flag;
|
||
uint16_t fn; /* temporary for method calling */
|
||
uint16_t flag; /* only uses 9 bits */
|
||
int orig_argc;
|
||
rb_iseq_t *blockiseq;
|
||
... | ... | |
int missing_reason; /* used by method_missing */
|
||
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);
|
||
} rb_call_info_t;
|
||
#if 1
|
vm_insnhelper.c | ||
---|---|---|
ci->me = rb_method_entry(klass, ci->mid, &ci->defined_class);
|
||
ci->klass = klass;
|
||
ci->call = vm_call_general;
|
||
ci->fn = VM_CIFN_GENERAL;
|
||
#if OPT_INLINE_METHOD_CACHE
|
||
ci->method_state = GET_GLOBAL_METHOD_STATE();
|
||
ci->class_serial = RCLASS_SERIAL(klass);
|
||
... | ... | |
ci->aux.opt_pc = 0;
|
||
CI_SET_FASTPATH(ci,
|
||
(UNLIKELY(ci->flag & VM_CALL_TAILCALL) ?
|
||
vm_call_iseq_setup_tailcall :
|
||
vm_call_iseq_setup_normal),
|
||
VM_CIFN_ISEQ_SETUP_TAILCALL :
|
||
VM_CIFN_ISEQ_SETUP_NORMAL),
|
||
(!is_lambda &&
|
||
!(ci->flag & VM_CALL_ARGS_SPLAT) && /* argc may differ for each calls */
|
||
!(ci->me->flag & NOEX_PROTECTED)));
|
||
... | ... | |
if (!(ci->me->flag & NOEX_PROTECTED) &&
|
||
!(ci->flag & VM_CALL_ARGS_SPLAT)) {
|
||
CI_SET_FASTPATH(ci, vm_call_cfunc_latter, 1);
|
||
CI_SET_FASTPATH(ci, VM_CIFN_CFUNC_LATTER, 1);
|
||
}
|
||
val = vm_call_cfunc_latter(th, reg_cfp, ci);
|
||
... | ... | |
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;
|
||
if (ci->fn != VM_CIFN_GENERAL) {
|
||
ci->fn = VM_CIFN_CFUNC_WITH_FRAME;
|
||
}
|
||
}
|
||
#else /* OPT_CALL_CFUNC_WITHOUT_FRAME */
|
||
... | ... | |
normal_method_dispatch:
|
||
switch (ci->me->def->type) {
|
||
case VM_METHOD_TYPE_ISEQ:{
|
||
CI_SET_FASTPATH(ci, vm_call_iseq_setup, enable_fastpath);
|
||
CI_SET_FASTPATH(ci, VM_CIFN_ISEQ_SETUP, enable_fastpath);
|
||
return vm_call_iseq_setup(th, cfp, ci);
|
||
}
|
||
case VM_METHOD_TYPE_NOTIMPLEMENTED:
|
||
case VM_METHOD_TYPE_CFUNC:
|
||
CI_SET_FASTPATH(ci, vm_call_cfunc, enable_fastpath);
|
||
CI_SET_FASTPATH(ci, VM_CIFN_CFUNC, enable_fastpath);
|
||
return vm_call_cfunc(th, cfp, ci);
|
||
case VM_METHOD_TYPE_ATTRSET:{
|
||
rb_check_arity(ci->argc, 1, 1);
|
||
ci->aux.index = 0;
|
||
CI_SET_FASTPATH(ci, vm_call_attrset, enable_fastpath && !(ci->flag & VM_CALL_ARGS_SPLAT));
|
||
CI_SET_FASTPATH(ci, VM_CIFN_CALL_ATTRSET,
|
||
enable_fastpath && !(ci->flag & VM_CALL_ARGS_SPLAT));
|
||
return vm_call_attrset(th, cfp, ci);
|
||
}
|
||
case VM_METHOD_TYPE_IVAR:{
|
||
rb_check_arity(ci->argc, 0, 0);
|
||
ci->aux.index = 0;
|
||
CI_SET_FASTPATH(ci, vm_call_ivar, enable_fastpath && !(ci->flag & VM_CALL_ARGS_SPLAT));
|
||
CI_SET_FASTPATH(ci, VM_CIFN_IVAR,
|
||
enable_fastpath && !(ci->flag & VM_CALL_ARGS_SPLAT));
|
||
return vm_call_ivar(th, cfp, ci);
|
||
}
|
||
case VM_METHOD_TYPE_MISSING:{
|
||
ci->aux.missing_reason = 0;
|
||
CI_SET_FASTPATH(ci, vm_call_method_missing, enable_fastpath);
|
||
CI_SET_FASTPATH(ci, VM_CIFN_METHOD_MISSING, enable_fastpath);
|
||
return vm_call_method_missing(th, cfp, ci);
|
||
}
|
||
case VM_METHOD_TYPE_BMETHOD:{
|
||
CI_SET_FASTPATH(ci, vm_call_bmethod, enable_fastpath);
|
||
CI_SET_FASTPATH(ci, VM_CIFN_BMETHOD, enable_fastpath);
|
||
return vm_call_bmethod(th, cfp, ci);
|
||
}
|
||
case VM_METHOD_TYPE_ZSUPER:{
|
||
... | ... | |
case VM_METHOD_TYPE_OPTIMIZED:{
|
||
switch (ci->me->def->body.optimize_type) {
|
||
case OPTIMIZED_METHOD_TYPE_SEND:
|
||
CI_SET_FASTPATH(ci, vm_call_opt_send, enable_fastpath);
|
||
CI_SET_FASTPATH(ci, VM_CIFN_OPT_SEND, enable_fastpath);
|
||
return vm_call_opt_send(th, cfp, ci);
|
||
case OPTIMIZED_METHOD_TYPE_CALL:
|
||
CI_SET_FASTPATH(ci, vm_call_opt_call, enable_fastpath);
|
||
CI_SET_FASTPATH(ci, VM_CIFN_OPT_CALL, enable_fastpath);
|
||
return vm_call_opt_call(th, cfp, ci);
|
||
default:
|
||
rb_bug("vm_call_method: unsupported optimized method type (%d)",
|
||
... | ... | |
}
|
||
me = rb_method_entry(refinement, ci->mid, &defined_class);
|
||
if (me) {
|
||
if (ci->call == vm_call_super_method) {
|
||
if (ci->fn == VM_CIFN_SUPER_METHOD) {
|
||
rb_control_frame_t *top_cfp = current_method_entry(th, cfp);
|
||
if (top_cfp->me &&
|
||
rb_method_definition_eq(me->def, top_cfp->me->def)) {
|
||
... | ... | |
stat |= NOEX_VCALL;
|
||
}
|
||
ci->aux.missing_reason = stat;
|
||
CI_SET_FASTPATH(ci, vm_call_method_missing, 1);
|
||
CI_SET_FASTPATH(ci, VM_CIFN_METHOD_MISSING, 1);
|
||
return vm_call_method_missing(th, cfp, ci);
|
||
}
|
||
else if (!(ci->flag & VM_CALL_OPT_SEND) && (ci->me->flag & NOEX_MASK) & NOEX_PROTECTED) {
|
||
... | ... | |
}
|
||
else {
|
||
ci->aux.missing_reason = stat;
|
||
CI_SET_FASTPATH(ci, vm_call_method_missing, 1);
|
||
CI_SET_FASTPATH(ci, VM_CIFN_METHOD_MISSING, 1);
|
||
return vm_call_method_missing(th, cfp, ci);
|
||
}
|
||
}
|
||
... | ... | |
if (!ci->klass) {
|
||
/* bound instance method of module */
|
||
ci->aux.missing_reason = NOEX_SUPER;
|
||
CI_SET_FASTPATH(ci, vm_call_method_missing, 1);
|
||
CI_SET_FASTPATH(ci, VM_CIFN_METHOD_MISSING, 1);
|
||
return;
|
||
}
|
||
/* TODO: use inline cache */
|
||
ci->me = rb_method_entry(ci->klass, ci->mid, &ci->defined_class);
|
||
ci->call = vm_call_super_method;
|
||
ci->fn = VM_CIFN_SUPER_METHOD;
|
||
while (iseq && !iseq->klass) {
|
||
iseq = iseq->parent_iseq;
|
||
... | ... | |
is->once.running_thread = NULL;
|
||
return Qnil;
|
||
}
|
||
/* test w/o C99 support so we may ensure it works on non-C99 compilers: */
|
||
#if 0 && (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)
|
||
# define map_(en,fn) [en] = fn
|
||
#else
|
||
# define map_(en,fn) fn
|
||
#endif
|
||
static inline vm_cifn
|
||
cifn_lookup(const rb_call_info_t *ci)
|
||
{
|
||
static const vm_cifn fn_map[] = {
|
||
map_(VM_CIFN_GENERAL, vm_call_general),
|
||
map_(VM_CIFN_SUPER_METHOD, vm_call_super_method),
|
||
map_(VM_CIFN_CFUNC, vm_call_cfunc),
|
||
#if OPT_CALL_CFUNC_WITHOUT_FRAME
|
||
map_(VM_CIFN_CFUNC_LATTER, vm_call_cfunc_latter),
|
||
#endif
|
||
map_(VM_CIFN_CFUNC_WITH_FRAME, vm_call_cfunc_with_frame),
|
||
map_(VM_CIFN_ISEQ_SETUP, vm_call_iseq_setup),
|
||
map_(VM_CIFN_ISEQ_SETUP_NORMAL, vm_call_iseq_setup_normal),
|
||
map_(VM_CIFN_ISEQ_SETUP_TAILCALL, vm_call_iseq_setup_tailcall),
|
||
map_(VM_CIFN_CALL_ATTRSET, vm_call_attrset),
|
||
map_(VM_CIFN_IVAR, vm_call_ivar),
|
||
map_(VM_CIFN_BMETHOD, vm_call_bmethod),
|
||
map_(VM_CIFN_OPT_SEND, vm_call_opt_send),
|
||
map_(VM_CIFN_OPT_CALL, vm_call_opt_call),
|
||
map_(VM_CIFN_METHOD_MISSING, vm_call_method_missing)
|
||
};
|
||
return fn_map[ci->fn];
|
||
}
|
||
#undef map_
|
vm_insnhelper.h | ||
---|---|---|
} \
|
||
} while (0)
|
||
typedef VALUE (*vm_cifn)(rb_thread_t *, rb_control_frame_t *, rb_call_info_t *);
|
||
static inline vm_cifn cifn_lookup(const rb_call_info_t *);
|
||
enum vm_cifn_type {
|
||
VM_CIFN_GENERAL = 0,
|
||
VM_CIFN_SUPER_METHOD,
|
||
VM_CIFN_CFUNC,
|
||
#if OPT_CALL_CFUNC_WITHOUT_FRAME
|
||
VM_CIFN_CFUNC_LATTER,
|
||
#endif
|
||
VM_CIFN_CFUNC_WITH_FRAME,
|
||
VM_CIFN_ISEQ_SETUP,
|
||
VM_CIFN_ISEQ_SETUP_NORMAL,
|
||
VM_CIFN_ISEQ_SETUP_TAILCALL,
|
||
VM_CIFN_CALL_ATTRSET,
|
||
VM_CIFN_IVAR,
|
||
VM_CIFN_BMETHOD,
|
||
VM_CIFN_OPT_SEND,
|
||
VM_CIFN_OPT_CALL,
|
||
VM_CIFN_METHOD_MISSING
|
||
};
|
||
#define CALL_METHOD(ci) do { \
|
||
VALUE v = (*(ci)->call)(th, GET_CFP(), (ci)); \
|
||
VALUE v = (cifn_lookup((ci)))(th, GET_CFP(), (ci)); \
|
||
if (v == Qundef) { \
|
||
RESTORE_REGS(); \
|
||
NEXT_INSN(); \
|
||
... | ... | |
#endif
|
||
#if OPT_CALL_FASTPATH
|
||
#define CI_SET_FASTPATH(ci, func, enabled) do { \
|
||
if (LIKELY(enabled)) ((ci)->call = (func)); \
|
||
#define CI_SET_FASTPATH(ci, func_idx, enabled) do { \
|
||
if (LIKELY(enabled)) ((ci)->fn = (func_idx)); \
|
||
} while (0)
|
||
#else
|
||
#define CI_SET_FASTPATH(ci, func, enabled) /* do nothing */
|
||
-
|