From c330876d7c5065f89234becc5125426d0d136bdc Mon Sep 17 00:00:00 2001 From: ko1 Date: Wed, 15 Jul 2009 14:59:41 +0000 Subject: * method.h, vm_core.h: add rb_method_entry_t. Remove nodes around method management. This change affect some VM control stack structure. * vm.c, vm_insnhelper.c, vm_method.c, vm_eval.c: ditto. and make some refactoring. * insns.def, class.c, eval.c, proc.c, vm_dump.c : ditto. * vm_core.h, compile.c (iseq_specialized_instruction): remove VM_CALL_SEND_BIT. use another optimization tech for Kernel#send. * node.h: remove unused node types. * ext/objspace/objspace.c (count_nodes): ditto. * gc.c: add mark/free functions for method entry. * include/ruby/intern.h: remove decl of rb_define_notimplement_method_id(). nobody can use it because noex is not opend. * iseq.c (iseq_mark): fix to check ic_method is available. * iseq.c (rb_iseq_disasm): fix to use rb_method_get_iseq(). git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@24128 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- vm_eval.c | 248 +++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 134 insertions(+), 114 deletions(-) (limited to 'vm_eval.c') diff --git a/vm_eval.c b/vm_eval.c index 096c0565ba..9b623277e9 100644 --- a/vm_eval.c +++ b/vm_eval.c @@ -21,141 +21,153 @@ static NODE *vm_cref_push(rb_thread_t *th, VALUE klass, int noex); static VALUE vm_exec(rb_thread_t *th); static void vm_set_eval_stack(rb_thread_t * th, VALUE iseqval, const NODE *cref); static int vm_collect_local_variables_in_heap(rb_thread_t *th, VALUE *dfp, VALUE ary); +static VALUE send_internal(int argc, const VALUE *argv, VALUE recv, int scope); + +typedef enum call_type { + CALL_PUBLIC, + CALL_FCALL, + CALL_VCALL, +} call_type; static inline VALUE -vm_call0(rb_thread_t * th, VALUE klass, VALUE recv, VALUE id, ID oid, - int argc, const VALUE *argv, const NODE *body, int nosuper) +vm_call0(rb_thread_t* th, VALUE recv, VALUE id, int argc, const VALUE *argv, + const rb_method_entry_t *me) { VALUE val; - rb_block_t *blockptr = 0; - - if (0) printf("id: %s, nd: %s, argc: %d, passed: %p\n", - rb_id2name(id), ruby_node_name(nd_type(body)), - argc, (void *)th->passed_block); + VALUE klass = me->klass; + const rb_block_t *blockptr = 0; if (th->passed_block) { blockptr = th->passed_block; th->passed_block = 0; } + again: - switch (nd_type(body)) { - case RUBY_VM_METHOD_NODE:{ - rb_control_frame_t *reg_cfp; - VALUE iseqval = (VALUE)body->nd_body; - int i; + switch (me->type) { + case VM_METHOD_TYPE_ISEQ: { + rb_control_frame_t *reg_cfp; + int i; - rb_vm_set_finish_env(th); - reg_cfp = th->cfp; + rb_vm_set_finish_env(th); + reg_cfp = th->cfp; - CHECK_STACK_OVERFLOW(reg_cfp, argc + 1); + CHECK_STACK_OVERFLOW(reg_cfp, argc + 1); - *reg_cfp->sp++ = recv; - for (i = 0; i < argc; i++) { - *reg_cfp->sp++ = argv[i]; - } + *reg_cfp->sp++ = recv; + for (i = 0; i < argc; i++) { + *reg_cfp->sp++ = argv[i]; + } - vm_setup_method(th, reg_cfp, argc, blockptr, 0, iseqval, recv); - val = vm_exec(th); - break; + vm_setup_method(th, reg_cfp, recv, argc, blockptr, 0 /* flag */, me); + val = vm_exec(th); + break; } - case NODE_CFUNC: { - EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, id, klass); - { - rb_control_frame_t *reg_cfp = th->cfp; - rb_control_frame_t *cfp = + case VM_METHOD_TYPE_CFUNC: { + EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, id, klass); + { + rb_control_frame_t *reg_cfp = th->cfp; + rb_control_frame_t *cfp = vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, recv, (VALUE)blockptr, 0, reg_cfp->sp, 0, 1); - cfp->method_id = oid; - cfp->method_class = klass; + cfp->me = me; + val = call_cfunc(me->body.cfunc.func, recv, me->body.cfunc.argc, argc, argv); - val = call_cfunc(body->nd_cfnc, recv, (int)body->nd_argc, argc, argv); - - if (reg_cfp != th->cfp + 1) { - SDR2(reg_cfp); - SDR2(th->cfp-5); - rb_bug("cfp consistency error - call0"); - th->cfp = reg_cfp; - } - vm_pop_frame(th); - } - EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, id, klass); - break; + if (reg_cfp != th->cfp + 1) { + rb_bug("cfp consistency error - call0"); + } + vm_pop_frame(th); + } + EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, id, klass); + break; } - case NODE_ATTRSET:{ - if (argc != 1) { - rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc); - } - val = rb_ivar_set(recv, body->nd_vid, argv[0]); - break; + case VM_METHOD_TYPE_ATTRSET: { + if (argc != 1) { + rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc); + } + val = rb_ivar_set(recv, me->body.attr_id, argv[0]); + break; } - case NODE_IVAR: { - if (argc != 0) { - rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", - argc); - } - val = rb_attr_get(recv, body->nd_vid); - break; + case VM_METHOD_TYPE_IVAR: { + if (argc != 0) { + rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc); + } + val = rb_attr_get(recv, me->body.attr_id); + break; } - case NODE_BMETHOD:{ - val = vm_call_bmethod(th, oid, body->nd_cval, - recv, klass, argc, (VALUE *)argv, blockptr); - break; + case VM_METHOD_TYPE_BMETHOD: { + val = vm_call_bmethod(th, recv, argc, argv, blockptr, me); + break; } - case NODE_ZSUPER:{ - klass = RCLASS_SUPER(klass); - if (!klass || !(body = rb_method_node(klass, id))) { - return method_missing(recv, id, argc, argv, 0); - } - RUBY_VM_CHECK_INTS(); - nosuper = CALL_SUPER; - body = body->nd_body; - goto again; + case VM_METHOD_TYPE_ZSUPER: { + klass = RCLASS_SUPER(klass); + if (!klass || !(me = rb_method_entry(klass, id))) { + return method_missing(recv, id, argc, argv, 0); + } + RUBY_VM_CHECK_INTS(); + goto again; + } + case VM_METHOD_TYPE_OPTIMIZED: { + switch (me->body.optimize_type) { + case OPTIMIZED_METHOD_TYPE_SEND: + val = send_internal(argc, argv, recv, NOEX_NOSUPER | NOEX_PRIVATE); + break; + case OPTIMIZED_METHOD_TYPE_CALL: { + rb_proc_t *proc; + GetProcPtr(recv, proc); + val = rb_vm_invoke_proc(th, proc, proc->block.self, argc, argv, blockptr); + break; + } + default: + rb_bug("vm_call0: unsupported optimized method type (%d)", me->body.optimize_type); + val = Qundef; + break; + } + break; } default: - rb_bug("unsupported: vm_call0(%s)", ruby_node_name(nd_type(body))); + rb_bug("vm_call0: unsupported method type (%d)", me->type); + val = Qundef; } RUBY_VM_CHECK_INTS(); return val; } VALUE -rb_vm_call(rb_thread_t * th, VALUE klass, VALUE recv, VALUE id, ID oid, - int argc, const VALUE *argv, const NODE *body, int nosuper) +rb_vm_call(rb_thread_t *th, VALUE recv, VALUE id, int argc, const VALUE *argv, + const rb_method_entry_t *me) { - return vm_call0(th, klass, recv, id, oid, argc, argv, body, nosuper); + return vm_call0(th, recv, id, argc, argv, me); } static inline VALUE -vm_call_super(rb_thread_t * const th, const int argc, const VALUE * const argv) +vm_call_super(rb_thread_t *th, int argc, const VALUE *argv) { VALUE recv = th->cfp->self; VALUE klass; ID id; - NODE *body; + rb_method_entry_t *me; rb_control_frame_t *cfp = th->cfp; if (!cfp->iseq) { - klass = cfp->method_class; + klass = cfp->me->klass; klass = RCLASS_SUPER(klass); if (klass == 0) { - klass = vm_search_normal_superclass(cfp->method_class, recv); + klass = vm_search_normal_superclass(cfp->me->klass, recv); } - - id = cfp->method_id; + id = cfp->me->original_id; } else { rb_bug("vm_call_super: should not be reached"); } - body = rb_method_node(klass, id); /* this returns NODE_METHOD */ - if (!body) { + me = rb_method_entry(klass, id); + if (!me) { return method_missing(recv, id, argc, argv, 0); } - return vm_call0(th, klass, recv, id, (ID)body->nd_file, - argc, argv, body->nd_body, CALL_SUPER); + return vm_call0(th, recv, id, argc, argv, me); } VALUE @@ -177,14 +189,15 @@ stack_check(void) } static inline VALUE -rb_call0(VALUE klass, VALUE recv, ID mid, int argc, const VALUE *argv, - int scope, VALUE self) +rb_call0(VALUE recv, ID mid, int argc, const VALUE *argv, + call_type scope, VALUE self) { - NODE *body, *method; - int noex; - ID id = mid; + VALUE klass = CLASS_OF(recv); + rb_method_entry_t *me; struct cache_entry *ent; rb_thread_t *th = GET_THREAD(); + ID oid; + int noex; if (!klass) { const char *adj = "terminated"; @@ -194,40 +207,41 @@ rb_call0(VALUE klass, VALUE recv, ID mid, int argc, const VALUE *argv, "method `%s' called on %s object (%p)", rb_id2name(mid), adj, (void *)recv); } + /* is it in the method cache? */ ent = cache + EXPR1(klass, mid); if (ent->mid == mid && ent->klass == klass) { - if (!ent->method) - return method_missing(recv, mid, argc, argv, - scope == 2 ? NOEX_VCALL : 0); - id = ent->mid0; - noex = (int)ent->method->nd_noex; - klass = ent->method->nd_clss; - body = ent->method->nd_body; - } - else if ((method = rb_get_method_body(klass, id, &id)) != 0) { - noex = (int)method->nd_noex; - klass = method->nd_clss; - body = method->nd_body; + if (!ent->me) { + return method_missing(recv, mid, argc, argv, + scope == CALL_VCALL ? NOEX_VCALL : 0); + } + me = ent->me; + klass = me->klass; + } + else if ((me = rb_method_entry(klass, mid)) != 0) { + klass = me->klass; } else { if (scope == 3) { return method_missing(recv, mid, argc, argv, NOEX_SUPER); } return method_missing(recv, mid, argc, argv, - scope == 2 ? NOEX_VCALL : 0); + scope == CALL_VCALL ? NOEX_VCALL : 0); } - if (mid != idMethodMissing) { + oid = me->original_id; + noex = me->flag; + + if (oid != idMethodMissing) { /* receiver specified form for private method */ if (UNLIKELY(noex)) { - if (((noex & NOEX_MASK) & NOEX_PRIVATE) && scope == 0) { + if (((noex & NOEX_MASK) & NOEX_PRIVATE) && scope == CALL_PUBLIC) { return method_missing(recv, mid, argc, argv, NOEX_PRIVATE); } /* self must be kind of a specified form for protected method */ - if (((noex & NOEX_MASK) & NOEX_PROTECTED) && scope == 0) { + if (((noex & NOEX_MASK) & NOEX_PROTECTED) && scope == CALL_PUBLIC) { VALUE defined_class = klass; if (TYPE(defined_class) == T_ICLASS) { @@ -249,13 +263,13 @@ rb_call0(VALUE klass, VALUE recv, ID mid, int argc, const VALUE *argv, } stack_check(); - return vm_call0(th, klass, recv, mid, id, argc, argv, body, noex & NOEX_NOSUPER); + return vm_call0(th, recv, mid, argc, argv, me); } static inline VALUE -rb_call(VALUE klass, VALUE recv, ID mid, int argc, const VALUE *argv, int scope) +rb_call(VALUE recv, ID mid, int argc, const VALUE *argv, call_type scope) { - return rb_call0(klass, recv, mid, argc, argv, scope, Qundef); + return rb_call0(recv, mid, argc, argv, scope, Qundef); } NORETURN(static void raise_method_missing(rb_thread_t *th, int argc, const VALUE *argv, @@ -404,7 +418,7 @@ rb_apply(VALUE recv, ID mid, VALUE args) argc = RARRAY_LENINT(args); argv = ALLOCA_N(VALUE, argc); MEMCPY(argv, RARRAY_PTR(args), VALUE, argc); - return rb_call(CLASS_OF(recv), recv, mid, argc, argv, CALL_FCALL); + return rb_call(recv, mid, argc, argv, CALL_FCALL); } VALUE @@ -427,23 +441,23 @@ rb_funcall(VALUE recv, ID mid, int n, ...) else { argv = 0; } - return rb_call(CLASS_OF(recv), recv, mid, n, argv, CALL_FCALL); + return rb_call(recv, mid, n, argv, CALL_FCALL); } VALUE rb_funcall2(VALUE recv, ID mid, int argc, const VALUE *argv) { - return rb_call(CLASS_OF(recv), recv, mid, argc, argv, CALL_FCALL); + return rb_call(recv, mid, argc, argv, CALL_FCALL); } VALUE rb_funcall3(VALUE recv, ID mid, int argc, const VALUE *argv) { - return rb_call(CLASS_OF(recv), recv, mid, argc, argv, CALL_PUBLIC); + return rb_call(recv, mid, argc, argv, CALL_PUBLIC); } static VALUE -send_internal(int argc, VALUE *argv, VALUE recv, int scope) +send_internal(int argc, const VALUE *argv, VALUE recv, int scope) { VALUE vid; VALUE self = RUBY_VM_PREVIOUS_CONTROL_FRAME(GET_THREAD()->cfp)->self; @@ -456,7 +470,7 @@ send_internal(int argc, VALUE *argv, VALUE recv, int scope) vid = *argv++; argc--; PASS_PASSED_BLOCK_TH(th); - return rb_call0(CLASS_OF(recv), recv, rb_to_id(vid), argc, argv, scope, self); + return rb_call0(recv, rb_to_id(vid), argc, argv, scope, self); } /* @@ -667,8 +681,7 @@ iterate_method(VALUE obj) const struct iter_method_arg * arg = (struct iter_method_arg *) obj; - return rb_call(CLASS_OF(arg->obj), arg->obj, arg->mid, - arg->argc, arg->argv, CALL_FCALL); + return rb_call(arg->obj, arg->mid, arg->argc, arg->argv, CALL_FCALL); } VALUE @@ -687,7 +700,7 @@ rb_block_call(VALUE obj, ID mid, int argc, VALUE * argv, VALUE rb_each(VALUE obj) { - return rb_call(CLASS_OF(obj), obj, idEach, 0, 0, CALL_FCALL); + return rb_call(obj, idEach, 0, 0, CALL_FCALL); } static VALUE @@ -1486,8 +1499,15 @@ Init_vm_eval(void) rb_define_method(rb_cBasicObject, "instance_exec", rb_obj_instance_exec, -1); rb_define_private_method(rb_cBasicObject, "method_missing", rb_method_missing, -1); +#if 1 + rb_add_method(rb_cBasicObject, rb_intern("__send__"), + VM_METHOD_TYPE_OPTIMIZED, (void *)OPTIMIZED_METHOD_TYPE_SEND, 0); + rb_add_method(rb_mKernel, rb_intern("send"), + VM_METHOD_TYPE_OPTIMIZED, (void *)OPTIMIZED_METHOD_TYPE_SEND, 0); +#else rb_define_method(rb_cBasicObject, "__send__", rb_f_send, -1); rb_define_method(rb_mKernel, "send", rb_f_send, -1); +#endif rb_define_method(rb_mKernel, "public_send", rb_f_public_send, -1); rb_define_method(rb_cModule, "module_exec", rb_mod_module_exec, -1); -- cgit v1.2.3