From d5ec9ec308dccaeea2a723e070a98df4159183de Mon Sep 17 00:00:00 2001 From: ko1 Date: Sat, 19 Sep 2015 17:59:58 +0000 Subject: * vm_core.h: split rb_call_info_t into several structs. * rb_call_info (ci) has compiled fixed information. * if ci->flag & VM_CALL_KWARG, then rb_call_info is also rb_call_info_with_kwarg. This technique reduce one word for major rb_call_info data. * rb_calling_info has temporary data (argc, blockptr, recv). for each method dispatch. This data is allocated only on machine stack. * rb_call_cache is for inline method cache. Before this patch, only rb_call_info_t data is passed. After this patch, above three structs are passed. This patch improves: * data locarity (rb_call_info is now read-only data). * reduce memory consumption (rb_call_info_with_kwarg, rb_calling_info). * compile.c: use above data. * insns.def: ditto. * iseq.c: ditto. * vm_args.c: ditto. * vm_eval.c: ditto. * vm_insnhelper.c: ditto. * vm_insnhelper.h: ditto. * iseq.h: add iseq_compile_data::ci_index and iseq_compile_data::ci_kw_indx. * tool/instruction.rb: introduce TS_CALLCACHE operand type. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51903 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- vm_args.c | 96 +++++++++++++++++++++++++++++++++------------------------------ 1 file changed, 50 insertions(+), 46 deletions(-) (limited to 'vm_args.c') diff --git a/vm_args.c b/vm_args.c index fe7a9b96e9..bc336dd395 100644 --- a/vm_args.c +++ b/vm_args.c @@ -15,9 +15,10 @@ VALUE rb_keyword_error_new(const char *error, VALUE keys); /* class.c */ struct args_info { /* basic args info */ - rb_call_info_t *ci; + struct rb_calling_info *calling; VALUE *argv; int argc; + const struct rb_call_info_kw_arg *kw_arg; /* additional args info */ int rest_index; @@ -235,8 +236,9 @@ args_pop_keyword_hash(struct args_info *args, VALUE *kw_hash_ptr, rb_thread_t *t static int args_kw_argv_to_hash(struct args_info *args) { - const VALUE *const passed_keywords = args->ci->kw_arg->keywords; - const int kw_len = args->ci->kw_arg->keyword_len; + const struct rb_call_info_kw_arg *kw_arg = args->kw_arg; + const VALUE *const passed_keywords = kw_arg->keywords; + const int kw_len = kw_arg->keyword_len; VALUE h = rb_hash_new(); const int kw_start = args->argc - kw_len; const VALUE * const kw_argv = args->argv + kw_start; @@ -257,8 +259,9 @@ args_stored_kw_argv_to_hash(struct args_info *args) { VALUE h = rb_hash_new(); int i; - const VALUE *const passed_keywords = args->ci->kw_arg->keywords; - const int passed_keyword_len = args->ci->kw_arg->keyword_len; + const struct rb_call_info_kw_arg *kw_arg = args->kw_arg; + const VALUE *const passed_keywords = kw_arg->keywords; + const int passed_keyword_len = kw_arg->keyword_len; for (i=0; ikw_argv[i]); @@ -462,10 +465,10 @@ args_setup_kw_rest_parameter(VALUE keyword_hash, VALUE *locals) } static inline void -args_setup_block_parameter(rb_thread_t *th, rb_call_info_t *ci, VALUE *locals) +args_setup_block_parameter(rb_thread_t *th, struct rb_calling_info *calling, VALUE *locals) { VALUE blockval = Qnil; - const rb_block_t *blockptr = ci->blockptr; + const rb_block_t *blockptr = calling->blockptr; if (blockptr) { /* make Proc object */ @@ -473,7 +476,7 @@ args_setup_block_parameter(rb_thread_t *th, rb_call_info_t *ci, VALUE *locals) rb_proc_t *proc; blockval = rb_vm_make_proc(th, blockptr, rb_cProc); GetProcPtr(blockval, proc); - ci->blockptr = &proc->block; + calling->blockptr = &proc->block; } else { blockval = blockptr->proc; @@ -499,7 +502,9 @@ fill_keys_values(st_data_t key, st_data_t val, st_data_t ptr) } static int -setup_parameters_complex(rb_thread_t * const th, const rb_iseq_t * const iseq, rb_call_info_t * const ci, +setup_parameters_complex(rb_thread_t * const th, const rb_iseq_t * const iseq, + struct rb_calling_info *const calling, + const struct rb_call_info *ci, VALUE * const locals, const enum arg_setup_type arg_setup_type) { const int min_argc = iseq->body->param.lead_num + iseq->body->param.post_num; @@ -525,20 +530,22 @@ setup_parameters_complex(rb_thread_t * const th, const rb_iseq_t * const iseq, r * <- iseq->body->param.size------------> * ^ locals ^ sp */ - for (i=ci->argc; ibody->param.size; i++) { + for (i=calling->argc; ibody->param.size; i++) { locals[i] = Qnil; } th->cfp->sp = &locals[i]; /* setup args */ args = &args_body; - args->ci = ci; - given_argc = args->argc = ci->argc; + args->calling = calling; + given_argc = args->argc = calling->argc; args->argv = locals; - if (ci->kw_arg) { + if (ci->flag & VM_CALL_KWARG) { + args->kw_arg = ((struct rb_call_info_with_kwarg *)ci)->kw_arg; + if (iseq->body->param.flags.has_kw) { - int kw_len = ci->kw_arg->keyword_len; + int kw_len = args->kw_arg->keyword_len; /* copy kw_argv */ args->kw_argv = ALLOCA_N(VALUE, kw_len); args->argc -= kw_len; @@ -551,6 +558,7 @@ setup_parameters_complex(rb_thread_t * const th, const rb_iseq_t * const iseq, r } } else { + args->kw_arg = NULL; args->kw_argv = NULL; } @@ -642,7 +650,8 @@ setup_parameters_complex(rb_thread_t * const th, const rb_iseq_t * const iseq, r VALUE * const klocals = locals + iseq->body->param.keyword->bits_start - iseq->body->param.keyword->num; if (args->kw_argv != NULL) { - args_setup_kw_parameters(args->kw_argv, args->ci->kw_arg->keyword_len, args->ci->kw_arg->keywords, iseq, klocals); + const struct rb_call_info_kw_arg *kw_arg = args->kw_arg; + args_setup_kw_parameters(args->kw_argv, kw_arg->keyword_len, kw_arg->keywords, iseq, klocals); } else if (!NIL_P(keyword_hash)) { int kw_len = rb_long2int(RHASH_SIZE(keyword_hash)); @@ -665,7 +674,7 @@ setup_parameters_complex(rb_thread_t * const th, const rb_iseq_t * const iseq, r } if (iseq->body->param.flags.has_block) { - args_setup_block_parameter(th, ci, locals + iseq->body->param.block_start); + args_setup_block_parameter(th, calling, locals + iseq->body->param.block_start); } #if 0 @@ -717,10 +726,11 @@ argument_kw_error(rb_thread_t *th, const rb_iseq_t *iseq, const char *error, con } static inline void -vm_caller_setup_arg_splat(rb_control_frame_t *cfp, rb_call_info_t *ci) +vm_caller_setup_arg_splat(rb_control_frame_t *cfp, struct rb_calling_info *calling) { - VALUE *argv = cfp->sp - ci->argc; - VALUE ary = argv[ci->argc-1]; + int argc = calling->argc; + VALUE *argv = cfp->sp - argc; + VALUE ary = argv[argc-1]; cfp->sp--; @@ -733,15 +743,16 @@ vm_caller_setup_arg_splat(rb_control_frame_t *cfp, rb_call_info_t *ci) for (i = 0; i < len; i++) { *cfp->sp++ = ptr[i]; } - ci->argc += i - 1; + calling->argc += i - 1; } } static inline void -vm_caller_setup_arg_kw(rb_control_frame_t *cfp, rb_call_info_t *ci) +vm_caller_setup_arg_kw(rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci) { - const VALUE *const passed_keywords = ci->kw_arg->keywords; - const int kw_len = ci->kw_arg->keyword_len; + struct rb_call_info_with_kwarg *ci_kw = (struct rb_call_info_with_kwarg *)ci; + const VALUE *const passed_keywords = ci_kw->kw_arg->keywords; + const int kw_len = ci_kw->kw_arg->keyword_len; const VALUE h = rb_hash_new(); VALUE *sp = cfp->sp; int i; @@ -752,18 +763,12 @@ vm_caller_setup_arg_kw(rb_control_frame_t *cfp, rb_call_info_t *ci) (sp-kw_len)[0] = h; cfp->sp -= kw_len - 1; - ci->argc -= kw_len - 1; + calling->argc -= kw_len - 1; } -#define SAVE_RESTORE_CI(expr, ci) do { \ - int saved_argc = (ci)->argc; rb_block_t *saved_blockptr = (ci)->blockptr; /* save */ \ - expr; \ - (ci)->argc = saved_argc; (ci)->blockptr = saved_blockptr; /* restore */ \ -} while (0) - static void -vm_caller_setup_arg_block(const rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci, - rb_iseq_t *blockiseq, const int is_super) +vm_caller_setup_arg_block(const rb_thread_t *th, rb_control_frame_t *reg_cfp, + struct rb_calling_info *calling, const struct rb_call_info *ci, rb_iseq_t *blockiseq, const int is_super) { if (ci->flag & VM_CALL_ARGS_BLOCKARG) { rb_proc_t *po; @@ -774,8 +779,7 @@ vm_caller_setup_arg_block(const rb_thread_t *th, rb_control_frame_t *reg_cfp, rb if (proc != Qnil) { if (!rb_obj_is_proc(proc)) { VALUE b; - - SAVE_RESTORE_CI(b = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc"), ci); + b = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc"); if (NIL_P(b) || !rb_obj_is_proc(b)) { rb_raise(rb_eTypeError, @@ -785,32 +789,32 @@ vm_caller_setup_arg_block(const rb_thread_t *th, rb_control_frame_t *reg_cfp, rb proc = b; } GetProcPtr(proc, po); - ci->blockptr = &po->block; + calling->blockptr = &po->block; RUBY_VM_GET_BLOCK_PTR_IN_CFP(reg_cfp)->proc = proc; } else { - ci->blockptr = NULL; + calling->blockptr = NULL; } } else if (blockiseq != 0) { /* likely */ - ci->blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP(reg_cfp); - ci->blockptr->iseq = blockiseq; - ci->blockptr->proc = 0; + rb_block_t *blockptr = calling->blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP(reg_cfp); + blockptr->iseq = blockiseq; + blockptr->proc = 0; } else { if (is_super) { - ci->blockptr = GET_BLOCK_PTR(); + calling->blockptr = GET_BLOCK_PTR(); } else { - ci->blockptr = NULL; + calling->blockptr = NULL; } } } -#define IS_ARGS_SPLAT(ci) ((ci)->flag & VM_CALL_ARGS_SPLAT) -#define IS_ARGS_KEYWORD(ci) ((ci)->kw_arg != NULL) +#define IS_ARGS_SPLAT(ci) ((ci)->flag & VM_CALL_ARGS_SPLAT) +#define IS_ARGS_KEYWORD(ci) ((ci)->flag & VM_CALL_KWARG) -#define CALLER_SETUP_ARG(cfp, ci) do { \ - if (UNLIKELY(IS_ARGS_SPLAT(ci))) vm_caller_setup_arg_splat((cfp), (ci)); \ - if (UNLIKELY(IS_ARGS_KEYWORD(ci))) vm_caller_setup_arg_kw((cfp), (ci)); \ +#define CALLER_SETUP_ARG(cfp, calling, ci) do { \ + if (UNLIKELY(IS_ARGS_SPLAT(ci))) vm_caller_setup_arg_splat((cfp), (calling)); \ + if (UNLIKELY(IS_ARGS_KEYWORD(ci))) vm_caller_setup_arg_kw((cfp), (calling), (ci)); \ } while (0) -- cgit v1.2.3