summaryrefslogtreecommitdiff
path: root/vm_eval.c
diff options
context:
space:
mode:
authorko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-07-15 14:59:41 +0000
committerko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-07-15 14:59:41 +0000
commitc330876d7c5065f89234becc5125426d0d136bdc (patch)
treed7a65121d7250d0137a2c75d7b7d454737815e7d /vm_eval.c
parentd3cbda6e8dc5732f64b06cacb4c137f01ebe0461 (diff)
* 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
Diffstat (limited to 'vm_eval.c')
-rw-r--r--vm_eval.c248
1 files changed, 134 insertions, 114 deletions
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);