ruby-changes:25133
From: ko1 <ko1@a...>
Date: Mon, 15 Oct 2012 04:59:28 +0900 (JST)
Subject: [ruby-changes:25133] ko1:r37185 (trunk): * vm_insnhelper.c: refactoring.
ko1 2012-10-15 04:58:59 +0900 (Mon, 15 Oct 2012) New Revision: 37185 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=37185 Log: * vm_insnhelper.c: refactoring. - move all `call' related functions to the last of file. - make functions for respective method types in vm_call_method(). (all functions have same function parameters) * vm_core.h: add `opt_pc' filed in `rb_call_info_t' as temporal variable. * vm_eval.c (vm_call0_body): catch up above cahnges. Modified files: trunk/ChangeLog trunk/vm_core.h trunk/vm_eval.c trunk/vm_insnhelper.c Index: ChangeLog =================================================================== --- ChangeLog (revision 37184) +++ ChangeLog (revision 37185) @@ -1,3 +1,15 @@ +Mon Oct 15 04:51:55 2012 Koichi Sasada <ko1@a...> + + * vm_insnhelper.c: refactoring. + - move all `call' related functions to the last of file. + - make functions for respective method types in vm_call_method(). + (all functions have same function parameters) + + * vm_core.h: add `opt_pc' filed in `rb_call_info_t' + as temporal variable. + + * vm_eval.c (vm_call0_body): catch up above cahnges. + Mon Oct 15 03:51:46 2012 Koichi Sasada <ko1@a...> * benchmark/bm_vm1_attr_ivar(_set).rb: added (for method dispatch speed). Index: vm_core.h =================================================================== --- vm_core.h (revision 37184) +++ vm_core.h (revision 37185) @@ -160,8 +160,10 @@ /* temporary values for method calling */ int argc; + int opt_pc; struct rb_block_struct *blockptr; VALUE recv; + VALUE (*call)(struct rb_thread_struct *th, struct rb_control_frame_struct *cfp, struct rb_call_info_struct *ci); } rb_call_info_t; Index: vm_eval.c =================================================================== --- vm_eval.c (revision 37184) +++ vm_eval.c (revision 37185) @@ -78,7 +78,7 @@ *reg_cfp->sp++ = argv[i]; } - vm_setup_method(th, reg_cfp, ci); + vm_call_iseq_setup(th, reg_cfp, ci); th->cfp->flag |= VM_FRAME_FLAG_FINISH; val = vm_exec(th); break; @@ -115,7 +115,7 @@ break; } case VM_METHOD_TYPE_BMETHOD: { - val = vm_call_bmethod(th, ci->recv, ci->argc, argv, ci->blockptr, ci->me, ci->defined_class); + val = vm_call_bmethod_body(th, ci, argv); break; } case VM_METHOD_TYPE_ZSUPER: Index: vm_insnhelper.c =================================================================== --- vm_insnhelper.c (revision 37184) +++ vm_insnhelper.c (revision 37185) @@ -158,667 +158,6 @@ rb_exc_raise(rb_arg_error_new(argc, min, max)); } -#define VM_CALLEE_SETUP_ARG(ret, th, ci, iseq, argv) \ - if (LIKELY((iseq)->arg_simple & 0x01)) { \ - /* simple check */ \ - if ((ci)->argc != (iseq)->argc) { \ - argument_error((iseq), ((ci)->argc), (iseq)->argc, (iseq)->argc); \ - } \ - (ret) = 0; \ - } \ - else { \ - (ret) = vm_callee_setup_arg_complex((th), (ci), (iseq), (argv)); \ - } - -static inline int -vm_callee_setup_arg_complex(rb_thread_t *th, rb_call_info_t *ci, const rb_iseq_t * iseq, VALUE *orig_argv) -{ - const int m = iseq->argc; - const int opts = iseq->arg_opts - (iseq->arg_opts > 0); - const int min = m + iseq->arg_post_len; - const int max = (iseq->arg_rest == -1) ? m + opts + iseq->arg_post_len : UNLIMITED_ARGUMENTS; - const int orig_argc = ci->argc; - int argc = orig_argc; - VALUE *argv = orig_argv; - rb_num_t opt_pc = 0; - VALUE keyword_hash = Qnil; - - th->mark_stack_len = argc + iseq->arg_size; - - if (iseq->arg_keyword != -1) { - int i, j; - if (argc > 0) keyword_hash = rb_check_hash_type(argv[argc-1]); - if (!NIL_P(keyword_hash)) { - argc--; - keyword_hash = rb_hash_dup(keyword_hash); - if (iseq->arg_keyword_check) { - for (i = j = 0; i < iseq->arg_keywords; i++) { - if (st_lookup(RHASH_TBL(keyword_hash), ID2SYM(iseq->arg_keyword_table[i]), 0)) j++; - } - if (RHASH_TBL(keyword_hash)->num_entries > (unsigned int) j) { - unknown_keyword_error(iseq, keyword_hash); - } - } - } - else { - keyword_hash = rb_hash_new(); - } - } - - /* mandatory */ - if ((argc < min) || (argc > max && max != UNLIMITED_ARGUMENTS)) { - argument_error(iseq, argc, min, max); - } - - argv += m; - argc -= m; - - /* post arguments */ - if (iseq->arg_post_len) { - if (!(orig_argc < iseq->arg_post_start)) { - VALUE *new_argv = ALLOCA_N(VALUE, argc); - MEMCPY(new_argv, argv, VALUE, argc); - argv = new_argv; - } - - MEMCPY(&orig_argv[iseq->arg_post_start], &argv[argc -= iseq->arg_post_len], - VALUE, iseq->arg_post_len); - } - - /* opt arguments */ - if (iseq->arg_opts) { - if (argc > opts) { - argc -= opts; - argv += opts; - opt_pc = iseq->arg_opt_table[opts]; /* no opt */ - } - else { - int i; - for (i = argc; i<opts; i++) { - orig_argv[i + m] = Qnil; - } - opt_pc = iseq->arg_opt_table[argc]; - argc = 0; - } - } - - /* rest arguments */ - if (iseq->arg_rest != -1) { - orig_argv[iseq->arg_rest] = rb_ary_new4(argc, argv); - argc = 0; - } - - /* keyword argument */ - if (iseq->arg_keyword != -1) { - orig_argv[iseq->arg_keyword] = keyword_hash; - } - - /* block arguments */ - if (iseq->arg_block != -1) { - VALUE blockval = Qnil; - const rb_block_t *blockptr = ci->blockptr; - - if (blockptr) { - /* make Proc object */ - if (blockptr->proc == 0) { - rb_proc_t *proc; - blockval = rb_vm_make_proc(th, blockptr, rb_cProc); - GetProcPtr(blockval, proc); - ci->blockptr = &proc->block; - } - else { - blockval = blockptr->proc; - } - } - - orig_argv[iseq->arg_block] = blockval; /* Proc or nil */ - } - - th->mark_stack_len = 0; - return (int)opt_pc; -} - -static void -vm_caller_setup_args(const rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) -{ - if (UNLIKELY(ci->flag & VM_CALL_ARGS_BLOCKARG_BIT)) { - rb_proc_t *po; - VALUE proc; - - proc = *(--cfp->sp); - - if (proc != Qnil) { - if (!rb_obj_is_proc(proc)) { - VALUE b = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc"); - if (NIL_P(b) || !rb_obj_is_proc(b)) { - rb_raise(rb_eTypeError, - "wrong argument type %s (expected Proc)", - rb_obj_classname(proc)); - } - proc = b; - } - GetProcPtr(proc, po); - ci->blockptr = &po->block; - RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp)->proc = proc; - } - } - else if (UNLIKELY(ci->blockiseq != 0)) { - ci->blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp); - ci->blockptr->iseq = ci->blockiseq; - ci->blockptr->proc = 0; - } - - /* expand top of stack? */ - - if (UNLIKELY(ci->flag & VM_CALL_ARGS_SPLAT_BIT)) { - VALUE ary = *(cfp->sp - 1); - VALUE *ptr; - int i; - VALUE tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_a"); - - if (NIL_P(tmp)) { - /* do nothing */ - } - else { - long len = RARRAY_LEN(tmp); - ptr = RARRAY_PTR(tmp); - cfp->sp -= 1; - - CHECK_STACK_OVERFLOW(cfp, len); - - for (i = 0; i < len; i++) { - *cfp->sp++ = ptr[i]; - } - ci->argc += i-1; - } - } -} - -static inline VALUE -call_cfunc(VALUE (*func)(), VALUE recv, - int len, int argc, const VALUE *argv) -{ - /* printf("len: %d, argc: %d\n", len, argc); */ - - if (len >= 0) rb_check_arity(argc, len, len); - - switch (len) { - case -2: - return (*func) (recv, rb_ary_new4(argc, argv)); - break; - case -1: - return (*func) (argc, argv, recv); - break; - case 0: - return (*func) (recv); - break; - case 1: - return (*func) (recv, argv[0]); - break; - case 2: - return (*func) (recv, argv[0], argv[1]); - break; - case 3: - return (*func) (recv, argv[0], argv[1], argv[2]); - break; - case 4: - return (*func) (recv, argv[0], argv[1], argv[2], argv[3]); - break; - case 5: - return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4]); - break; - case 6: - return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5]); - break; - case 7: - return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5], argv[6]); - break; - case 8: - return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5], argv[6], argv[7]); - break; - case 9: - return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5], argv[6], argv[7], argv[8]); - break; - case 10: - return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5], argv[6], argv[7], argv[8], argv[9]); - break; - case 11: - return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], - argv[5], argv[6], argv[7], argv[8], argv[9], - argv[10]); - break; - case 12: - return (*func) (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]); - break; - case 13: - return (*func) (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]); - break; - case 14: - return (*func) (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]); - break; - case 15: - return (*func) (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]); - break; - default: - rb_raise(rb_eArgError, "too many arguments(%d)", len); - UNREACHABLE; - } -} - -static inline VALUE -vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci) -{ - volatile VALUE val = 0; - const rb_method_entry_t *me = ci->me; - const rb_method_definition_t *def = me->def; - - EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, ci->recv, me->called_id, me->klass); - - vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, ci->recv, ci->defined_class, - VM_ENVVAL_BLOCK_PTR(ci->blockptr), 0, th->cfp->sp, 1, me); - - reg_cfp->sp -= ci->argc + 1; - - val = call_cfunc(def->body.cfunc.func, ci->recv, (int)def->body.cfunc.argc, ci->argc, reg_cfp->sp + 1); - - if (reg_cfp != th->cfp + 1) { - rb_bug("cfp consistency error - send"); - } - - vm_pop_frame(th); - - EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, ci->recv, me->called_id, me->klass); - - return val; -} - -static inline VALUE -vm_call_bmethod(rb_thread_t *th, VALUE recv, int argc, const VALUE *argv, - const rb_block_t *blockptr, const rb_method_entry_t *me, - VALUE defined_class) -{ - rb_proc_t *proc; - VALUE val; - - EXEC_EVENT_HOOK(th, RUBY_EVENT_CALL, recv, me->called_id, me->klass); - - /* control block frame */ - th->passed_me = me; - GetProcPtr(me->def->body.proc, proc); - val = vm_invoke_proc(th, proc, recv, defined_class, argc, argv, blockptr); - - EXEC_EVENT_HOOK(th, RUBY_EVENT_RETURN, recv, me->called_id, me->klass); - - return val; -} - -static inline VALUE -vm_method_missing(rb_thread_t *th, rb_control_frame_t *const reg_cfp, - ID id, VALUE recv, - int num, const rb_block_t *blockptr, int opt) -{ - VALUE ret, *argv = STACK_ADDR_FROM_TOP(num + 1); - - th->method_missing_reason = opt; - th->passed_block = blockptr; - argv[0] = ID2SYM(id); - ret = rb_funcall2(recv, idMethodMissing, num + 1, argv); - POPN(num + 1); - return ret; -} - -static inline void -vm_setup_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) -{ - int opt_pc, i; - VALUE *argv = cfp->sp - ci->argc; - rb_iseq_t *iseq = ci->me->def->body.iseq; - - VM_CALLEE_SETUP_ARG(opt_pc, th, ci, iseq, argv); - - /* stack overflow check */ - CHECK_STACK_OVERFLOW(cfp, iseq->stack_max); - - if (LIKELY(!(ci->flag & VM_CALL_TAILCALL_BIT))) { - VALUE *sp = argv + iseq->arg_size; - - /* clear local variables */ - for (i = 0; i < iseq->local_size - iseq->arg_size; i++) { - *sp++ = Qnil; - } - - vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD, ci->recv, ci->defined_class, - VM_ENVVAL_BLOCK_PTR(ci->blockptr), - iseq->iseq_encoded + opt_pc, sp, 0, ci->me); - - cfp->sp = argv - 1 /* recv */; - } - else { - VALUE *src_argv = argv; - VALUE *sp_orig, *sp; - VALUE finish_flag = VM_FRAME_TYPE_FINISH_P(cfp) ? VM_FRAME_FLAG_FINISH : 0; - - cfp = th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp); /* pop cf */ - sp_orig = sp = cfp->sp; - - /* push self */ - sp[0] = ci->recv; - sp++; - - /* copy arguments */ - for (i=0; i < iseq->arg_size; i++) { - *sp++ = src_argv[i]; - } - - /* clear local variables */ - for (i = 0; i < iseq->local_size - iseq->arg_size; i++) { - *sp++ = Qnil; - } - - vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD | finish_flag, - ci->recv, ci->defined_class, VM_ENVVAL_BLOCK_PTR(ci->blockptr), - iseq->iseq_encoded + opt_pc, sp, 0, ci->me); - - cfp->sp = sp_orig; - } -} - -/* yield */ - -static inline int -block_proc_is_lambda(const VALUE procval) -{ - rb_proc_t *proc; - - if (procval) { - GetProcPtr(procval, proc); - return proc->is_lambda; - } - else { - return 0; - } -} - -static inline VALUE -vm_yield_with_cfunc(rb_thread_t *th, const rb_block_t *block, - VALUE self, int argc, const VALUE *argv, - const rb_block_t *blockargptr) -{ - NODE *ifunc = (NODE *) block->iseq; - VALUE val, arg, blockarg; - int lambda = block_proc_is_lambda(block->proc); - rb_control_frame_t *cfp; - - if (lambda) { - arg = rb_ary_new4(argc, argv); - } - else if (argc == 0) { - arg = Qnil; - } - else { - arg = argv[0]; - } - - if (blockargptr) { - if (blockargptr->proc) { - blockarg = blockargptr->proc; - } - else { - blockarg = rb_vm_make_proc(th, blockargptr, rb_cProc); - } - } - else { - blockarg = Qnil; - } - - cfp = vm_push_frame(th, (rb_iseq_t *)ifunc, VM_FRAME_MAGIC_IFUNC, self, - 0, VM_ENVVAL_PREV_EP_PTR(block->ep), 0, - th->cfp->sp, 1, 0); - - if (blockargptr) { - VM_CF_LEP(cfp)[0] = VM_ENVVAL_BLOCK_PTR(blockargptr); - } - val = (*ifunc->nd_cfnc) (arg, ifunc->nd_tval, argc, argv, blockarg); - - th->cfp++; - return val; -} - - -/*-- - * @brief on supplied all of optional, rest and post parameters. - * @pre iseq is block style (not lambda style) - */ -static inline int -vm_yield_setup_block_args_complex(rb_thread_t *th, const rb_iseq_t *iseq, - int argc, VALUE *argv) -{ - rb_num_t opt_pc = 0; - int i; - const int m = iseq->argc; - const int r = iseq->arg_rest; - int len = iseq->arg_post_len; - int start = iseq->arg_post_start; - int rsize = argc > m ? argc - m : 0; /* # of arguments which did not consumed yet */ - int psize = rsize > len ? len : rsize; /* # of post arguments */ - int osize = 0; /* # of opt arguments */ - VALUE ary; - - /* reserves arguments for post parameters */ - rsize -= psize; - - if (iseq->arg_opts) { - const int opts = iseq->arg_opts - 1; - if (rsize > opts) { - osize = opts; - opt_pc = iseq->arg_opt_table[opts]; - } - else { - osize = rsize; - opt_pc = iseq->arg_opt_table[rsize]; - } - } - rsize -= osize; - - if (0) { - printf(" argc: %d\n", argc); - printf(" len: %d\n", len); - printf("start: %d\n", start); - printf("rsize: %d\n", rsize); - } - - if (r == -1) { - /* copy post argument */ - MEMMOVE(&argv[start], &argv[m+osize], VALUE, psize); - } - else { - ary = rb_ary_new4(rsize, &argv[r]); - - /* copy post argument */ - MEMMOVE(&argv[start], &argv[m+rsize+osize], VALUE, psize); - argv[r] = ary; - } - - for (i=psize; i<len; i++) { - argv[start + i] = Qnil; - } - - return (int)opt_pc; -} - -static inline int -vm_yield_setup_block_args(rb_thread_t *th, const rb_iseq_t * iseq, - int orig_argc, VALUE *argv, - const rb_block_t *blockptr) -{ - int i; - int argc = orig_argc; - const int m = iseq->argc; - VALUE ary, arg0; - int opt_pc = 0; - - th->mark_stack_len = argc; - - /* - * yield [1, 2] - * => {|a|} => a = [1, 2] - * => {|a, b|} => a, b = [1, 2] - */ - arg0 = argv[0]; - if (!(iseq->arg_simple & 0x02) && /* exclude {|a|} */ - (m + iseq->arg_opts + iseq->arg_post_len) > 0 && /* this process is meaningful */ - argc == 1 && !NIL_P(ary = rb_check_array_type(arg0))) { /* rhs is only an array */ - th->mark_stack_len = argc = RARRAY_LENINT(ary); - - CHECK_STACK_OVERFLOW(th->cfp, argc); - - MEMCPY(argv, RARRAY_PTR(ary), VALUE, argc); - } - else { - argv[0] = arg0; - } - - for (i=argc; i<m; i++) { - argv[i] = Qnil; - } - - if (iseq->arg_rest == -1 && iseq->arg_opts == 0) { - const int arg_size = iseq->arg_size; - if (arg_size < argc) { - /* - * yield 1, 2 - * => {|a|} # truncate - */ - th->mark_stack_len = argc = arg_size; - } - } - else { - int r = iseq->arg_rest; - - if (iseq->arg_post_len || - iseq->arg_opts) { /* TODO: implement simple version for (iseq->arg_post_len==0 && iseq->arg_opts > 0) */ - opt_pc = vm_yield_setup_block_args_complex(th, iseq, argc, argv); - } - else { - if (argc < r) { - /* yield 1 - * => {|a, b, *r|} - */ - for (i=argc; i<r; i++) { - argv[i] = Qnil; - } - argv[r] = rb_ary_new(); - } - else { - argv[r] = rb_ary_new4(argc-r, &argv[r]); - } - } - - th->mark_stack_len = iseq->arg_size; - } - - /* {|&b|} */ - if (iseq->arg_block != -1) { - VALUE procval = Qnil; - - if (blockptr) { - if (blockptr->proc == 0) { - procval = rb_vm_make_proc(th, blockptr, rb_cProc); - } - else { - procval = blockptr->proc; - } - } - - argv[iseq->arg_block] = procval; - } - - th->mark_stack_len = 0; - return opt_pc; -} - -static inline int -vm_yield_setup_args(rb_thread_t * const th, const rb_iseq_t *iseq, - int argc, VALUE *argv, const rb_block_t *blockptr, int lambda) -{ - if (0) { /* for debug */ - printf(" argc: %d\n", argc); - printf("iseq argc: %d\n", iseq->argc); - printf("iseq opts: %d\n", iseq->arg_opts); - printf("iseq rest: %d\n", iseq->arg_rest); - printf("iseq post: %d\n", iseq->arg_post_len); - printf("iseq blck: %d\n", iseq->arg_block); - printf("iseq smpl: %d\n", iseq->arg_simple); - printf(" lambda: %s\n", lambda ? "true" : "false"); - } - - if (lambda) { - /* call as method */ - int opt_pc; - rb_call_info_t ci_entry; - ci_entry.flag = 0; - ci_entry.argc = argc; - ci_entry.blockptr = (rb_block_t *)blockptr; - VM_CALLEE_SETUP_ARG(opt_pc, th, &ci_entry, iseq, argv); - return opt_pc; - } - else { - return vm_yield_setup_block_args(th, iseq, argc, argv, blockptr); - } -} - -static VALUE -vm_invoke_block(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci) -{ - const rb_block_t *block = VM_CF_BLOCK_PTR(reg_cfp); - rb_iseq_t *iseq; - VALUE type = GET_ISEQ()->local_iseq->type; - - if ((type != ISEQ_TYPE_METHOD && type != ISEQ_TYPE_CLASS) || block == 0) { - rb_vm_localjump_error("no block given (yield)", Qnil, 0); - } - iseq = block->iseq; - - vm_caller_setup_args(th, GET_CFP(), ci); - - if (BUILTIN_TYPE(iseq) != T_NODE) { - int opt_pc; - const int arg_size = iseq->arg_size; - VALUE * const rsp = GET_SP() - ci->argc; - SET_SP(rsp); - - CHECK_STACK_OVERFLOW(GET_CFP(), iseq->stack_max); - opt_pc = vm_yield_setup_args(th, iseq, ci->argc, rsp, 0, block_proc_is_lambda(block->proc)); - - vm_push_frame(th, iseq, VM_FRAME_MAGIC_BLOCK, block->self, - block->klass, - VM_ENVVAL_PREV_EP_PTR(block->ep), - iseq->iseq_encoded + opt_pc, - rsp + arg_size, - iseq->local_size - arg_size, 0); - - return Qundef; - } - else { - VALUE val = vm_yield_with_cfunc(th, block, block->self, ci->argc, STACK_ADDR_FROM_TOP(ci->argc), 0); - POPN(ci->argc); /* TODO: should put before C/yield? */ - return val; - } -} - /* svar */ static inline NODE * @@ -1669,8 +1008,487 @@ return bp; } +/* method call processes with call_info */ +static void +vm_caller_setup_args(const rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) +{ + if (UNLIKELY(ci->flag & VM_CALL_ARGS_BLOCKARG_BIT)) { + rb_proc_t *po; + VALUE proc; + + proc = *(--cfp->sp); + + if (proc != Qnil) { + if (!rb_obj_is_proc(pr (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/