diff options
author | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2009-07-15 14:59:41 +0000 |
---|---|---|
committer | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2009-07-15 14:59:41 +0000 |
commit | c330876d7c5065f89234becc5125426d0d136bdc (patch) | |
tree | d7a65121d7250d0137a2c75d7b7d454737815e7d | |
parent | d3cbda6e8dc5732f64b06cacb4c137f01ebe0461 (diff) | |
download | ruby-c330876d7c5065f89234becc5125426d0d136bdc.tar.gz |
* 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
-rw-r--r-- | ChangeLog | 27 | ||||
-rw-r--r-- | class.c | 65 | ||||
-rw-r--r-- | compile.c | 6 | ||||
-rw-r--r-- | eval.c | 2 | ||||
-rw-r--r-- | ext/objspace/objspace.c | 4 | ||||
-rw-r--r-- | gc.c | 72 | ||||
-rw-r--r-- | include/ruby/intern.h | 1 | ||||
-rw-r--r-- | insns.def | 36 | ||||
-rw-r--r-- | iseq.c | 14 | ||||
-rw-r--r-- | method.h | 78 | ||||
-rw-r--r-- | node.h | 47 | ||||
-rw-r--r-- | proc.c | 206 | ||||
-rw-r--r-- | vm.c | 37 | ||||
-rw-r--r-- | vm_core.h | 39 | ||||
-rw-r--r-- | vm_dump.c | 8 | ||||
-rw-r--r-- | vm_eval.c | 248 | ||||
-rw-r--r-- | vm_insnhelper.c | 236 | ||||
-rw-r--r-- | vm_insnhelper.h | 6 | ||||
-rw-r--r-- | vm_method.c | 535 |
19 files changed, 882 insertions, 785 deletions
@@ -1,3 +1,30 @@ +Wed Jul 15 23:46:55 2009 Koichi Sasada <ko1@atdot.net> + + * 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(). + Wed Jul 15 23:45:11 2009 Koichi Sasada <ko1@atdot.net> * dir.c (push_glob): fix GC problem. @@ -25,7 +25,8 @@ #include "ruby/ruby.h" #include "ruby/st.h" -#include "node.h" +#include "method.h" +#include "vm_core.h" #include <ctype.h> extern st_table *rb_class_tbl; @@ -123,28 +124,19 @@ struct clone_method_data { VALUE rb_iseq_clone(VALUE iseqval, VALUE newcbase); static int -clone_method(ID mid, NODE *body, struct clone_method_data *data) +clone_method(ID mid, const rb_method_entry_t *me, struct clone_method_data *data) { - if (body == 0) { - st_insert(data->tbl, mid, 0); - } - else { - NODE *fbody = body->nd_body->nd_body; - - if (nd_type(fbody) == RUBY_VM_METHOD_NODE) { - fbody = NEW_NODE(RUBY_VM_METHOD_NODE, 0, - rb_iseq_clone((VALUE)fbody->nd_body, data->klass), - 0); - } - st_insert(data->tbl, mid, - (st_data_t) - NEW_NODE_LONGLIFE( - NODE_FBODY, - 0, - NEW_NODE_LONGLIFE(NODE_METHOD, - rb_gc_write_barrier(data->klass), /* TODO */ - rb_gc_write_barrier((VALUE)fbody), - body->nd_body->nd_noex), 0)); + switch (me->type) { + case VM_METHOD_TYPE_ISEQ: { + VALUE newiseqval = rb_iseq_clone(me->body.iseq->self, data->klass); + rb_iseq_t *iseq; + GetISeqPtr(newiseqval, iseq); + rb_add_method(data->klass, mid, VM_METHOD_TYPE_ISEQ, iseq, me->flag); + break; + } + default: + rb_add_method_me(data->klass, mid, me, me->flag); + break; } return ST_CONTINUE; } @@ -674,7 +666,7 @@ ins_methods_pub_i(ID name, long type, VALUE ary) } static int -method_entry(ID key, NODE *body, st_table *list) +method_entry(ID key, const rb_method_entry_t *me, st_table *list) { long type; @@ -683,11 +675,11 @@ method_entry(ID key, NODE *body, st_table *list) } if (!st_lookup(list, key, 0)) { - if (body ==0 || !body->nd_body->nd_body) { + if (!me || me->type == VM_METHOD_TYPE_UNDEF) { type = -1; /* none */ } else { - type = VISI(body->nd_body->nd_noex); + type = VISI(me->flag); } st_add_direct(list, key, type); } @@ -874,44 +866,33 @@ rb_obj_singleton_methods(int argc, VALUE *argv, VALUE obj) } void -rb_define_method_id(VALUE klass, ID name, VALUE (*func)(ANYARGS), int argc) +rb_define_method_id(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc) { - if (func == rb_f_notimplement) - rb_define_notimplement_method_id(klass, name, NOEX_PUBLIC); - else - rb_add_method(klass, name, NEW_NODE_LONGLIFE(NODE_CFUNC, func, argc, 0), NOEX_PUBLIC); + rb_add_method_cfunc(klass, mid, func, argc, NOEX_PUBLIC); } void rb_define_method(VALUE klass, const char *name, VALUE (*func)(ANYARGS), int argc) { - rb_define_method_id(klass, rb_intern(name), func, argc); + rb_add_method_cfunc(klass, rb_intern(name), func, argc, NOEX_PUBLIC); } void rb_define_protected_method(VALUE klass, const char *name, VALUE (*func)(ANYARGS), int argc) { - ID id = rb_intern(name); - if (func == rb_f_notimplement) - rb_define_notimplement_method_id(klass, id, NOEX_PROTECTED); - else - rb_add_method(klass, id, NEW_NODE_LONGLIFE(NODE_CFUNC, func, argc, 0), NOEX_PROTECTED); + rb_add_method_cfunc(klass, rb_intern(name), func, argc, NOEX_PROTECTED); } void rb_define_private_method(VALUE klass, const char *name, VALUE (*func)(ANYARGS), int argc) { - ID id = rb_intern(name); - if (func == rb_f_notimplement) - rb_define_notimplement_method_id(klass, id, NOEX_PRIVATE); - else - rb_add_method(klass, id, NEW_NODE_LONGLIFE(NODE_CFUNC, func, argc, 0), NOEX_PRIVATE); + rb_add_method_cfunc(klass, rb_intern(name), func, argc, NOEX_PRIVATE); } void rb_undef_method(VALUE klass, const char *name) { - rb_add_method(klass, rb_intern(name), 0, NOEX_UNDEF); + rb_add_method(klass, rb_intern(name), VM_METHOD_TYPE_UNDEF, 0, NOEX_UNDEF); } #define SPECIAL_SINGLETON(x,c) do {\ @@ -1855,12 +1855,6 @@ iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj) } } } - - if (argc > 0) { - if (mid == idSend || mid == id__send__ ) { - OPERAND_AT(iobj, 3) |= INT2FIX(VM_CALL_SEND_BIT); - } - } } return COMPILE_OK; } @@ -684,7 +684,7 @@ frame_func_id(rb_control_frame_t *cfp) { rb_iseq_t *iseq = cfp->iseq; if (!iseq) { - return cfp->method_id; + return cfp->me->original_id; } while (iseq) { if (RUBY_VM_IFUNC_P(iseq)) { diff --git a/ext/objspace/objspace.c b/ext/objspace/objspace.c index d200e1736c..68c6086fa0 100644 --- a/ext/objspace/objspace.c +++ b/ext/objspace/objspace.c @@ -350,9 +350,6 @@ count_nodes(int argc, VALUE *argv, VALUE os) VALUE node; switch (i) { #define COUNT_NODE(n) case n: node = ID2SYM(rb_intern(#n)); break; - COUNT_NODE(NODE_METHOD); - COUNT_NODE(NODE_FBODY); - COUNT_NODE(NODE_CFUNC); COUNT_NODE(NODE_SCOPE); COUNT_NODE(NODE_BLOCK); COUNT_NODE(NODE_IF); @@ -441,7 +438,6 @@ count_nodes(int argc, VALUE *argv, VALUE os) COUNT_NODE(NODE_DOT3); COUNT_NODE(NODE_FLIP2); COUNT_NODE(NODE_FLIP3); - COUNT_NODE(NODE_ATTRSET); COUNT_NODE(NODE_SELF); COUNT_NODE(NODE_NIL); COUNT_NODE(NODE_TRUE); @@ -1435,12 +1435,6 @@ mark_tbl(rb_objspace_t *objspace, st_table *tbl, int lev) st_foreach(tbl, mark_entry, (st_data_t)&arg); } -void -rb_mark_tbl(st_table *tbl) -{ - mark_tbl(&rb_objspace, tbl, 0); -} - static int mark_key(VALUE key, VALUE value, st_data_t data) { @@ -1490,6 +1484,64 @@ rb_mark_hash(st_table *tbl) mark_hash(&rb_objspace, tbl, 0); } +static void +mark_method_entry(rb_objspace_t *objspace, const rb_method_entry_t *me, int lev) +{ + gc_mark(objspace, me->klass, lev); + switch (me->type) { + case VM_METHOD_TYPE_ISEQ: + gc_mark(objspace, me->body.iseq->self, lev); + break; + case VM_METHOD_TYPE_BMETHOD: + gc_mark(objspace, me->body.proc, lev); + break; + default: + break; /* ignore */ + } +} + +void +rb_gc_mark_method_entry(const rb_method_entry_t *me) +{ + mark_method_entry(&rb_objspace, me, 0); +} + +static int +mark_method_entry_i(ID key, const rb_method_entry_t *me, st_data_t data) +{ + struct mark_tbl_arg *arg = (void*)data; + mark_method_entry(arg->objspace, me, arg->lev); + return ST_CONTINUE; +} + +static void +mark_m_tbl(rb_objspace_t *objspace, st_table *tbl, int lev) { + struct mark_tbl_arg arg; + if (!tbl) return; + arg.objspace = objspace; + arg.lev = lev; + st_foreach(tbl, mark_method_entry_i, (st_data_t)&arg); +} + +static int +free_method_entry_i(ID key, rb_method_entry_t *me, st_data_t data) +{ + xfree(me); + return ST_CONTINUE; +} + +static void +free_m_table(st_table *tbl) +{ + st_foreach(tbl, free_method_entry_i, 0); +} + +void +rb_mark_tbl(st_table *tbl) +{ + mark_tbl(&rb_objspace, tbl, 0); +} + void rb_gc_mark_maybe(VALUE obj) { @@ -1591,7 +1643,6 @@ gc_mark_children(rb_objspace_t *objspace, VALUE ptr, int lev) ptr = (VALUE)obj->as.node.u3.node; goto again; - case NODE_METHOD: /* 1,2 */ case NODE_WHILE: case NODE_UNTIL: case NODE_AND: @@ -1612,7 +1663,6 @@ gc_mark_children(rb_objspace_t *objspace, VALUE ptr, int lev) case NODE_ARGSCAT: gc_mark(objspace, (VALUE)obj->as.node.u1.node, lev); /* fall through */ - case NODE_FBODY: /* 2 */ case NODE_GASGN: case NODE_LASGN: case NODE_DASGN: @@ -1653,7 +1703,6 @@ gc_mark_children(rb_objspace_t *objspace, VALUE ptr, int lev) case NODE_ZARRAY: /* - */ case NODE_ZSUPER: - case NODE_CFUNC: case NODE_VCALL: case NODE_GVAR: case NODE_LVAR: @@ -1669,7 +1718,6 @@ gc_mark_children(rb_objspace_t *objspace, VALUE ptr, int lev) case NODE_TRUE: case NODE_FALSE: case NODE_ERRINFO: - case NODE_ATTRSET: case NODE_BLOCK_ARG: break; case NODE_ALLOCA: @@ -1698,7 +1746,7 @@ gc_mark_children(rb_objspace_t *objspace, VALUE ptr, int lev) case T_ICLASS: case T_CLASS: case T_MODULE: - mark_tbl(objspace, RCLASS_M_TBL(obj), lev); + mark_m_tbl(objspace, RCLASS_M_TBL(obj), lev); mark_tbl(objspace, RCLASS_IV_TBL(obj), lev); ptr = RCLASS_SUPER(obj); goto again; @@ -2072,7 +2120,7 @@ obj_free(rb_objspace_t *objspace, VALUE obj) case T_MODULE: case T_CLASS: rb_clear_cache_by_class((VALUE)obj); - st_free_table(RCLASS_M_TBL(obj)); + free_m_table(RCLASS_M_TBL(obj)); if (RCLASS_IV_TBL(obj)) { st_free_table(RCLASS_IV_TBL(obj)); } diff --git a/include/ruby/intern.h b/include/ruby/intern.h index dfc3a355e2..09e71e9193 100644 --- a/include/ruby/intern.h +++ b/include/ruby/intern.h @@ -275,7 +275,6 @@ int rb_method_basic_definition_p(VALUE, ID); VALUE rb_eval_cmd(VALUE, VALUE, int); int rb_obj_respond_to(VALUE, ID, int); int rb_respond_to(VALUE, ID); -void rb_define_notimplement_method_id(VALUE mod, ID id, int noex); VALUE rb_f_notimplement(int argc, VALUE *argv, VALUE obj); void rb_interrupt(void); VALUE rb_apply(VALUE, ID, VALUE); @@ -785,11 +785,11 @@ defined break; case DEFINED_METHOD:{ VALUE klass = CLASS_OF(v); - NODE *method = (NODE *) rb_method_node(klass, SYM2ID(obj)); + const rb_method_entry_t *me = rb_method_entry(klass, SYM2ID(obj)); - if (method) { - if (!(method->nd_noex & NOEX_PRIVATE)) { - if (!((method->nd_noex & NOEX_PROTECTED) && + if (me) { + if (!(me->flag & NOEX_PRIVATE)) { + if (!((me->flag & NOEX_PROTECTED) && !rb_obj_is_kind_of(GET_SELF(), rb_class_real(klass)))) { expr_type = "method"; @@ -979,7 +979,7 @@ send (...) (VALUE val) // inc += - (int)(op_argc + ((op_flag & VM_CALL_ARGS_BLOCKARG_BIT) ? 1 : 0)); { - NODE *mn; + const rb_method_entry_t *me; VALUE recv, klass; rb_block_t *blockptr = 0; rb_num_t num = caller_setup_args(th, GET_CFP(), op_flag, (int)op_argc, @@ -990,14 +990,8 @@ send /* get receiver */ recv = (flag & VM_CALL_FCALL_BIT) ? GET_SELF() : TOPN(num); klass = CLASS_OF(recv); - mn = vm_method_search(id, klass, ic); - - /* send/funcall optimization */ - if (flag & VM_CALL_SEND_BIT) { - vm_send_optimize(GET_CFP(), &mn, &flag, &num, &id, klass); - } - - CALL_METHOD(num, blockptr, flag, id, mn, recv); + me = vm_method_search(id, klass, ic); + CALL_METHOD(num, blockptr, flag, id, me, recv); } /** @@ -1017,15 +1011,15 @@ invokesuper rb_num_t num = caller_setup_args(th, GET_CFP(), op_flag, (int)op_argc, blockiseq, &blockptr); VALUE recv, klass; - NODE *mn; ID id; - const VALUE flag = VM_CALL_SUPER_BIT | VM_CALL_FCALL_BIT; + VALUE flag = VM_CALL_SUPER_BIT | VM_CALL_FCALL_BIT; + const rb_method_entry_t *me; recv = GET_SELF(); vm_search_superclass(GET_CFP(), GET_ISEQ(), recv, TOPN(num), &id, &klass); - mn = rb_method_node(klass, id); + me = rb_method_entry(klass, id); - CALL_METHOD(num, blockptr, flag, id, mn, recv); + CALL_METHOD(num, blockptr, flag, id, me, recv); } /** @@ -1629,10 +1623,10 @@ opt_neq (VALUE val) { extern VALUE rb_obj_not_equal(VALUE obj1, VALUE obj2); - NODE *mn = vm_method_search(idNeq, CLASS_OF(recv), ic1); + const rb_method_entry_t *me = vm_method_search(idNeq, CLASS_OF(recv), ic1); val = Qundef; - if (check_cfunc(mn, rb_obj_not_equal)) { + if (check_cfunc(me, rb_obj_not_equal)) { val = opt_eq_func(recv, obj, ic2); if (val != Qundef) { @@ -1997,9 +1991,9 @@ opt_not (VALUE val) { extern VALUE rb_obj_not(VALUE obj); - NODE *mn = vm_method_search(idNot, CLASS_OF(recv), ic); + const rb_method_entry_t *me = vm_method_search(idNot, CLASS_OF(recv), ic); - if (check_cfunc(mn, rb_obj_not)) { + if (check_cfunc(me, rb_obj_not)) { val = RTEST(recv) ? Qfalse : Qtrue; } else { @@ -107,6 +107,9 @@ iseq_mark(void *ptr) for (i=0; i<iseq->ic_size; i++) { RUBY_MARK_UNLESS_NULL(iseq->ic_entries[i].ic_class); RUBY_MARK_UNLESS_NULL(iseq->ic_entries[i].ic_value); + if (iseq->ic_entries[i].ic_method) { + rb_gc_mark_method_entry(iseq->ic_entries[i].ic_method); + } } if (iseq->compile_data != 0) { @@ -1002,17 +1005,14 @@ rb_iseq_disasm(VALUE self) static VALUE iseq_s_disasm(VALUE klass, VALUE body) { - extern NODE *rb_method_body(VALUE body); - NODE *node; VALUE ret = Qnil; + rb_iseq_t *iseq; + extern rb_iseq_t *rb_method_get_iseq(VALUE body); rb_secure(1); - if ((node = rb_method_body(body)) != 0) { - if (nd_type(node) == RUBY_VM_METHOD_NODE) { - VALUE iseqval = (VALUE)node->nd_body; - ret = rb_iseq_disasm(iseqval); - } + if ((iseq = rb_method_get_iseq(body)) != 0) { + ret = rb_iseq_disasm(iseq->self); } return ret; diff --git a/method.h b/method.h new file mode 100644 index 0000000000..ff8ad910a4 --- /dev/null +++ b/method.h @@ -0,0 +1,78 @@ +/**********************************************************************
+
+ method.h -
+
+ $Author: ko1 $
+ created at: Wed Jul 15 20:02:33 2009
+
+ Copyright (C) 2009 Koichi Sasada
+
+**********************************************************************/
+#ifndef METHOD_H
+#define METHOD_H
+
+typedef enum {
+ NOEX_PUBLIC = 0x00,
+ NOEX_NOSUPER = 0x01,
+ NOEX_PRIVATE = 0x02,
+ NOEX_PROTECTED = 0x04,
+ NOEX_MASK = 0x06,
+ NOEX_BASIC = 0x08,
+ NOEX_UNDEF = NOEX_NOSUPER,
+ NOEX_MODFUNC = 0x12,
+ NOEX_SUPER = 0x20,
+ NOEX_VCALL = 0x40,
+} rb_method_flag_t;
+
+#define NOEX_SAFE(n) ((int)((n) >> 8) & 0x0F)
+#define NOEX_WITH(n, s) ((s << 8) | (n) | (ruby_running ? 0 : NOEX_BASIC))
+#define NOEX_WITH_SAFE(n) NOEX_WITH(n, rb_safe_level())
+
+/* method data type */
+
+typedef enum {
+ VM_METHOD_TYPE_ISEQ,
+ VM_METHOD_TYPE_CFUNC,
+ VM_METHOD_TYPE_ATTRSET,
+ VM_METHOD_TYPE_IVAR,
+ VM_METHOD_TYPE_BMETHOD,
+ VM_METHOD_TYPE_ZSUPER,
+ VM_METHOD_TYPE_UNDEF,
+ VM_METHOD_TYPE_NOTIMPLEMENTED,
+ VM_METHOD_TYPE_OPTIMIZED, /* Kernel#send, Proc#call, etc */
+} rb_method_type_t;
+
+typedef struct rb_method_cfunc_struct {
+ VALUE (*func)(ANYARGS);
+ int argc;
+} rb_method_cfunc_t;
+
+typedef struct rb_iseq_struct rb_iseq_t;
+
+typedef struct rb_method_entry_struct {
+ rb_method_flag_t flag;
+ rb_method_type_t type; /* method type */
+ ID called_id;
+ ID original_id;
+ VALUE klass; /* should be mark */
+ union {
+ rb_iseq_t *iseq; /* should be mark */
+ rb_method_cfunc_t cfunc;
+ ID attr_id;
+ VALUE proc;
+ enum method_optimized_type {
+ OPTIMIZED_METHOD_TYPE_SEND,
+ OPTIMIZED_METHOD_TYPE_CALL,
+ } optimize_type;
+ } body;
+ int alias_count;
+} rb_method_entry_t;
+
+void rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_method_flag_t noex);
+rb_method_entry_t *rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *option, rb_method_flag_t noex);
+void rb_add_method_me(VALUE klass, ID mid, const rb_method_entry_t *, rb_method_flag_t noex);
+rb_method_entry_t *rb_method_entry(VALUE klass, ID id);
+int rb_method_entry_arity(const rb_method_entry_t *me);
+void rb_gc_mark_method_entry(const rb_method_entry_t *me);
+
+#endif /* METHOD_H */
@@ -20,12 +20,6 @@ extern "C" { #endif enum node_type { - NODE_METHOD, -#define NODE_METHOD NODE_METHOD - NODE_FBODY, -#define NODE_FBODY NODE_FBODY - NODE_CFUNC, -#define NODE_CFUNC NODE_CFUNC NODE_SCOPE, #define NODE_SCOPE NODE_SCOPE NODE_BLOCK, @@ -202,8 +196,6 @@ enum node_type { #define NODE_FLIP2 NODE_FLIP2 NODE_FLIP3, #define NODE_FLIP3 NODE_FLIP3 - NODE_ATTRSET, -#define NODE_ATTRSET NODE_ATTRSET NODE_SELF, #define NODE_SELF NODE_SELF NODE_NIL, @@ -356,11 +348,8 @@ typedef struct RNode { #define NEW_NODE(t,a0,a1,a2) rb_node_newnode((t),(VALUE)(a0),(VALUE)(a1),(VALUE)(a2)) #define NEW_NODE_LONGLIFE(t,a0,a1,a2) rb_node_newnode_longlife((t),(VALUE)(a0),(VALUE)(a1),(VALUE)(a2)) -#define NEW_METHOD(n,x,v) NEW_NODE(NODE_METHOD,x,n,v) -#define NEW_FBODY(n,i) NEW_NODE(NODE_FBODY,i,n,0) #define NEW_DEFN(i,a,d,p) NEW_NODE(NODE_DEFN,0,i,NEW_SCOPE(a,d)) #define NEW_DEFS(r,i,a,d) NEW_NODE(NODE_DEFS,r,i,NEW_SCOPE(a,d)) -#define NEW_CFUNC(f,c) NEW_NODE(NODE_CFUNC,f,c,0) #define NEW_IFUNC(f,c) NEW_NODE(NODE_IFUNC,f,c,0) #define NEW_SCOPE(a,b) NEW_NODE(NODE_SCOPE,local_tbl(),b,a) #define NEW_BLOCK(a) NEW_NODE(NODE_BLOCK,a,0,0) @@ -446,7 +435,6 @@ typedef struct RNode { #define NEW_COLON3(i) NEW_NODE(NODE_COLON3,0,i,0) #define NEW_DOT2(b,e) NEW_NODE(NODE_DOT2,b,e,0) #define NEW_DOT3(b,e) NEW_NODE(NODE_DOT3,b,e,0) -#define NEW_ATTRSET(a) NEW_NODE(NODE_ATTRSET,a,0,0) #define NEW_SELF() NEW_NODE(NODE_SELF,0,0,0) #define NEW_NIL() NEW_NODE(NODE_NIL,0,0,0) #define NEW_TRUE() NEW_NODE(NODE_TRUE,0,0,0) @@ -460,30 +448,6 @@ typedef struct RNode { #define NEW_PRELUDE(p,b) NEW_NODE(NODE_PRELUDE,p,b,0) #define NEW_OPTBLOCK(a) NEW_NODE(NODE_OPTBLOCK,a,0,0) -#define NOEX_PUBLIC 0x00 -#define NOEX_NOSUPER 0x01 -#define NOEX_PRIVATE 0x02 -#define NOEX_PROTECTED 0x04 -#define NOEX_MASK 0x06 /* 0110 */ -#define NOEX_BASIC 0x08 - -#define NOEX_UNDEF NOEX_NOSUPER - -#define NOEX_MODFUNC 0x12 -#define NOEX_SUPER 0x20 -#define NOEX_VCALL 0x40 - -#define NOEX_SAFE(n) ((int)((n) >> 8) & 0x0F) -#define NOEX_WITH(n, s) ((s << 8) | (n) | (ruby_running ? 0 : NOEX_BASIC)) -#define NOEX_WITH_SAFE(n) NOEX_WITH(n, rb_safe_level()) - -#define CALL_PUBLIC 0 -#define CALL_FCALL 1 -#define CALL_VCALL 2 -#define CALL_SUPER 3 - -#define RUBY_VM_METHOD_NODE NODE_METHOD - VALUE rb_parser_new(void); VALUE rb_parser_end_seen_p(VALUE); VALUE rb_parser_encoding(VALUE); @@ -496,20 +460,9 @@ NODE *rb_compile_cstr(const char*, const char*, int, int); NODE *rb_compile_string(const char*, VALUE, int); NODE *rb_compile_file(const char*, VALUE, int); -void rb_add_method(VALUE, ID, NODE *, int); NODE *rb_node_newnode(enum node_type,VALUE,VALUE,VALUE); NODE *rb_node_newnode_longlife(enum node_type,VALUE,VALUE,VALUE); -NODE* rb_method_node(VALUE klass, ID id); -int rb_node_arity(NODE* node); - -int rb_notimplement_body_p(NODE*); - -struct global_entry *rb_global_entry(ID); -VALUE rb_gvar_get(struct global_entry *); -VALUE rb_gvar_set(struct global_entry *, VALUE); -VALUE rb_gvar_defined(struct global_entry *); - #if defined(__cplusplus) #if 0 { /* satisfy cc-mode */ @@ -13,11 +13,10 @@ #include "gc.h" struct METHOD { - VALUE oclass; /* class that holds the method */ - VALUE rclass; /* class of the receiver */ VALUE recv; - ID id, oid; - NODE *body; + VALUE rclass; + ID id; + rb_method_entry_t *me; }; VALUE rb_cUnboundMethod; @@ -30,7 +29,7 @@ VALUE rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc); static VALUE bmcall(VALUE, VALUE); static int method_arity(VALUE); static int rb_obj_is_method(VALUE m); -static rb_iseq_t *get_method_iseq(VALUE method); +rb_iseq_t *rb_method_get_iseq(VALUE method); /* Proc */ @@ -657,7 +656,7 @@ get_proc_iseq(VALUE self, int *is_proc) iseq = 0; if (nd_type(node) == NODE_IFUNC && node->nd_cfnc == bmcall) { /* method(:foo).to_proc */ - iseq = get_method_iseq(node->nd_tval); + iseq = rb_method_get_iseq(node->nd_tval); if (is_proc) *is_proc = 0; } } @@ -843,9 +842,8 @@ bm_mark(void *ptr) { struct METHOD *data = ptr; rb_gc_mark(data->rclass); - rb_gc_mark(data->oclass); rb_gc_mark(data->recv); - rb_gc_mark((VALUE)data->body); + rb_gc_mark_method_entry(data->me); } static size_t @@ -867,59 +865,47 @@ rb_obj_is_method(VALUE m) return rb_typeddata_is_kind_of(m, &method_data_type); } -NODE * -rb_method_body(VALUE method) -{ - if (rb_obj_is_method(method)) { - struct METHOD *data = DATA_PTR(method); - return data->body; - } - else { - return 0; - } -} - -NODE *rb_get_method_body(VALUE klass, ID id, ID *idp); - static VALUE mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope) { VALUE method; - NODE *body; - struct METHOD *data; VALUE rclass = klass; - ID oid = id; + ID rid = id; + struct METHOD *data; + rb_method_entry_t *me; again: - if ((body = rb_get_method_body(klass, id, 0)) == 0) { - rb_print_undef(rclass, oid, 0); + me = rb_method_entry(klass, id); + if (!me) { + rb_print_undef(klass, id, 0); } - if (scope && (body->nd_noex & NOEX_MASK) != NOEX_PUBLIC) { - rb_print_undef(rclass, oid, (int)(body->nd_noex & NOEX_MASK)); + if (scope && (me->flag & NOEX_MASK) != NOEX_PUBLIC) { + rb_print_undef(rclass, me->original_id, (int)(me->flag & NOEX_MASK)); } - - klass = body->nd_clss; - body = body->nd_body; - - if (nd_type(body) == NODE_ZSUPER) { - klass = RCLASS_SUPER(klass); + if (me->type == VM_METHOD_TYPE_ZSUPER) { + klass = RCLASS_SUPER(me->klass); + id = me->original_id; goto again; } + klass = me->klass; + while (rclass != klass && (FL_TEST(rclass, FL_SINGLETON) || TYPE(rclass) == T_ICLASS)) { rclass = RCLASS_SUPER(rclass); } - if (TYPE(klass) == T_ICLASS) + + if (TYPE(klass) == T_ICLASS) { klass = RBASIC(klass)->klass; + } + method = TypedData_Make_Struct(mclass, struct METHOD, &method_data_type, data); - data->oclass = klass; - data->recv = obj; - data->id = id; - data->body = body; + data->recv = obj; data->rclass = rclass; - data->oid = oid; + data->id = rid; + data->me = me; + OBJ_INFECT(method, klass); return method; @@ -958,11 +944,11 @@ mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope) * object and contain the same body. */ - static VALUE method_eq(VALUE method, VALUE other) { struct METHOD *m1, *m2; + extern int rb_method_entry_eq(rb_method_entry_t *m1, rb_method_entry_t *m2); if (!rb_obj_is_method(other)) return Qfalse; @@ -973,9 +959,11 @@ method_eq(VALUE method, VALUE other) m1 = (struct METHOD *)DATA_PTR(method); m2 = (struct METHOD *)DATA_PTR(other); - if (m1->oclass != m2->oclass || m1->rclass != m2->rclass || - m1->recv != m2->recv || m1->body != m2->body) + if (!rb_method_entry_eq(m1->me, m2->me) || + m1->rclass != m2->rclass || + m1->recv != m2->recv) { return Qfalse; + } return Qtrue; } @@ -994,10 +982,9 @@ method_hash(VALUE method) long hash; TypedData_Get_Struct(method, struct METHOD, &method_data_type, m); - hash = (long)m->oclass; - hash ^= (long)m->rclass; + hash = (long)m->rclass; hash ^= (long)m->recv; - hash ^= (long)m->body; + hash ^= (long)m->me; return INT2FIX(hash); } @@ -1018,14 +1005,12 @@ method_unbind(VALUE obj) struct METHOD *orig, *data; TypedData_Get_Struct(obj, struct METHOD, &method_data_type, orig); - method = - TypedData_Make_Struct(rb_cUnboundMethod, struct METHOD, &method_data_type, data); - data->oclass = orig->oclass; + method = TypedData_Make_Struct(rb_cUnboundMethod, struct METHOD, + &method_data_type, data); data->recv = Qundef; data->id = orig->id; - data->body = orig->body; + data->me = orig->me; data->rclass = orig->rclass; - data->oid = orig->oid; OBJ_INFECT(method, obj); return method; @@ -1076,7 +1061,7 @@ method_owner(VALUE obj) struct METHOD *data; TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data); - return data->oclass; + return data->me->klass; } /* @@ -1205,7 +1190,6 @@ rb_mod_define_method(int argc, VALUE *argv, VALUE mod) { ID id; VALUE body; - NODE *node; int noex = NOEX_PUBLIC; if (argc == 1) { @@ -1239,7 +1223,7 @@ rb_mod_define_method(int argc, VALUE *argv, VALUE mod) rb_class2name(rclass)); } } - node = method->body; + rb_add_method_me(mod, id, method->me, noex); } else if (rb_obj_is_proc(body)) { rb_proc_t *proc; @@ -1251,16 +1235,13 @@ rb_mod_define_method(int argc, VALUE *argv, VALUE mod) proc->is_lambda = Qtrue; proc->is_from_method = Qtrue; } - node = NEW_BMETHOD(body); + rb_add_method(mod, id, VM_METHOD_TYPE_BMETHOD, (void *)body, noex); } else { /* type error */ rb_raise(rb_eTypeError, "wrong argument type (expected Proc/Method)"); } - /* TODO: visibility */ - - rb_add_method(mod, id, node, noex); return body; } @@ -1351,12 +1332,11 @@ rb_method_call(int argc, VALUE *argv, VALUE method) } if ((state = EXEC_TAG()) == 0) { rb_thread_t *th = GET_THREAD(); - 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); + VALUE rb_vm_call(rb_thread_t *th, VALUE recv, VALUE id, int argc, const VALUE *argv, + const rb_method_entry_t *me); PASS_PASSED_BLOCK_TH(th); - result = rb_vm_call(th, data->oclass, data->recv, data->id, data->oid, - argc, argv, data->body, 0); + result = rb_vm_call(th, data->recv, data->id, argc, argv, data->me); } POP_TAG(); if (safe >= 0) @@ -1483,34 +1463,32 @@ umethod_bind(VALUE method, VALUE recv) } int -rb_node_arity(NODE* body) +rb_method_entry_arity(const rb_method_entry_t *me) { - switch (nd_type(body)) { - case NODE_CFUNC: - if (body->nd_argc < 0) + switch (me->type) { + case VM_METHOD_TYPE_CFUNC: + if (me->body.cfunc.argc < 0) return -1; - return check_argc(body->nd_argc); - case NODE_ZSUPER: + return check_argc(me->body.cfunc.argc); + case VM_METHOD_TYPE_ZSUPER: return -1; - case NODE_ATTRSET: + case VM_METHOD_TYPE_ATTRSET: return 1; - case NODE_IVAR: + case VM_METHOD_TYPE_IVAR: return 0; - case NODE_BMETHOD: - return rb_proc_arity(body->nd_cval); - case RUBY_VM_METHOD_NODE: - { - rb_iseq_t *iseq; - GetISeqPtr((VALUE)body->nd_body, iseq); - if (iseq->arg_rest == -1 && iseq->arg_opts == 0) { - return iseq->argc; - } - else { - return -(iseq->argc + 1 + iseq->arg_post_len); - } - } + case VM_METHOD_TYPE_BMETHOD: + return rb_proc_arity(me->body.proc); + case VM_METHOD_TYPE_ISEQ: { + rb_iseq_t *iseq = me->body.iseq; + if (iseq->arg_rest == -1 && iseq->arg_opts == 0) { + return iseq->argc; + } + else { + return -(iseq->argc + 1 + iseq->arg_post_len); + } + } default: - rb_raise(rb_eArgError, "invalid node 0x%x", nd_type(body)); + rb_bug("rb_method_entry_arity: invalid method entry type (%d)", me->type); } } @@ -1560,14 +1538,14 @@ method_arity(VALUE method) struct METHOD *data; TypedData_Get_Struct(method, struct METHOD, &method_data_type, data); - return rb_node_arity(data->body); + return rb_method_entry_arity(data->me); } int rb_mod_method_arity(VALUE mod, ID id) { - NODE *node = rb_method_node(mod, id); - return rb_node_arity(node); + rb_method_entry_t *me = rb_method_entry(mod, id); + return rb_method_entry_arity(me); } int @@ -1576,25 +1554,23 @@ rb_obj_method_arity(VALUE obj, ID id) return rb_mod_method_arity(CLASS_OF(obj), id); } -static rb_iseq_t * -get_method_iseq(VALUE method) +rb_iseq_t * +rb_method_get_iseq(VALUE method) { struct METHOD *data; - NODE *body; - rb_iseq_t *iseq; + rb_method_entry_t *me; TypedData_Get_Struct(method, struct METHOD, &method_data_type, data); - body = data->body; - switch (nd_type(body)) { - case NODE_BMETHOD: - return get_proc_iseq(body->nd_cval, 0); - case RUBY_VM_METHOD_NODE: - GetISeqPtr((VALUE)body->nd_body, iseq); - if (RUBY_VM_NORMAL_ISEQ_P(iseq)) break; + me = data->me; + + switch (me->type) { + case VM_METHOD_TYPE_BMETHOD: + return get_proc_iseq(me->body.proc, 0); + case VM_METHOD_TYPE_ISEQ: + return me->body.iseq; default: return 0; } - return iseq; } /* @@ -1608,7 +1584,7 @@ get_method_iseq(VALUE method) VALUE rb_method_location(VALUE method) { - return iseq_location(get_method_iseq(method)); + return iseq_location(rb_method_get_iseq(method)); } /* @@ -1621,7 +1597,7 @@ rb_method_location(VALUE method) static VALUE rb_method_parameters(VALUE method) { - rb_iseq_t *iseq = get_method_iseq(method); + rb_iseq_t *iseq = rb_method_get_iseq(method); if (!iseq) { return unnamed_parameters(method_arity(method)); } @@ -1652,11 +1628,11 @@ method_inspect(VALUE method) rb_str_buf_cat2(str, s); rb_str_buf_cat2(str, ": "); - if (FL_TEST(data->oclass, FL_SINGLETON)) { - VALUE v = rb_iv_get(data->oclass, "__attached__"); + if (FL_TEST(data->me->klass, FL_SINGLETON)) { + VALUE v = rb_iv_get(data->me->klass, "__attached__"); if (data->recv == Qundef) { - rb_str_buf_append(str, rb_inspect(data->oclass)); + rb_str_buf_append(str, rb_inspect(data->me->klass)); } else if (data->recv == v) { rb_str_buf_append(str, rb_inspect(v)); @@ -1672,15 +1648,15 @@ method_inspect(VALUE method) } else { rb_str_buf_cat2(str, rb_class2name(data->rclass)); - if (data->rclass != data->oclass) { + if (data->rclass != data->me->klass) { rb_str_buf_cat2(str, "("); - rb_str_buf_cat2(str, rb_class2name(data->oclass)); + rb_str_buf_cat2(str, rb_class2name(data->me->klass)); rb_str_buf_cat2(str, ")"); } } rb_str_buf_cat2(str, sharp); - rb_str_append(str, rb_id2str(data->oid)); - if (rb_notimplement_body_p(data->body)) { + rb_str_append(str, rb_id2str(data->me->original_id)); + if (data->me->type == VM_METHOD_TYPE_NOTIMPLEMENTED) { rb_str_buf_cat2(str, " (not-implemented)"); } rb_str_buf_cat2(str, ">"); @@ -1949,10 +1925,22 @@ Init_Proc(void) rb_cProc = rb_define_class("Proc", rb_cObject); rb_undef_alloc_func(rb_cProc); rb_define_singleton_method(rb_cProc, "new", rb_proc_s_new, -1); + +#if 0 /* incomplete. */ + rb_add_method(rb_cProc, rb_intern("call"), VM_METHOD_TYPE_OPTIMIZED, + (void *)OPTIMIZED_METHOD_TYPE_CALL, 0); + rb_add_method(rb_cProc, rb_intern("[]"), VM_METHOD_TYPE_OPTIMIZED, + (void *)OPTIMIZED_METHOD_TYPE_CALL, 0); + rb_add_method(rb_cProc, rb_intern("==="), VM_METHOD_TYPE_OPTIMIZED, + (void *)OPTIMIZED_METHOD_TYPE_CALL, 0); + rb_add_method(rb_cProc, rb_intern("yield"), VM_METHOD_TYPE_OPTIMIZED, + (void *)OPTIMIZED_METHOD_TYPE_CALL, 0); +#else rb_define_method(rb_cProc, "call", proc_call, -1); rb_define_method(rb_cProc, "[]", proc_call, -1); rb_define_method(rb_cProc, "===", proc_call, -1); rb_define_method(rb_cProc, "yield", proc_call, -1); +#endif rb_define_method(rb_cProc, "to_proc", proc_to_proc, 0); rb_define_method(rb_cProc, "arity", proc_arity, 0); rb_define_method(rb_cProc, "clone", proc_clone, 0); @@ -575,7 +575,7 @@ vm_yield(rb_thread_t *th, int argc, const VALUE *argv) VALUE rb_vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, VALUE self, - int argc, const VALUE *argv, rb_block_t * blockptr) + int argc, const VALUE *argv, const rb_block_t * blockptr) { VALUE val = Qundef; int state; @@ -734,7 +734,7 @@ vm_backtrace_each(rb_thread_t *th, int lev, rb_backtrace_iter_func *iter, void * } } else if (RUBYVM_CFUNC_FRAME_P(cfp)) { - if ((*iter)(arg, file, line_no, rb_id2name(cfp->method_id))) break; + if ((*iter)(arg, file, line_no, rb_id2name(cfp->me->original_id))) break; } cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp); } @@ -929,22 +929,23 @@ rb_iter_break(void) static st_table *vm_opt_method_table = 0; static void -rb_vm_check_redefinition_opt_method(const NODE *node) +rb_vm_check_redefinition_opt_method(const rb_method_entry_t *me) { VALUE bop; - - if (st_lookup(vm_opt_method_table, (st_data_t)node, &bop)) { - ruby_vm_redefined_flag[bop] = 1; + if (me->type == VM_METHOD_TYPE_CFUNC) { + if (st_lookup(vm_opt_method_table, (st_data_t)me, &bop)) { + ruby_vm_redefined_flag[bop] = 1; + } } } static void add_opt_method(VALUE klass, ID mid, VALUE bop) { - NODE *node; - if (st_lookup(RCLASS_M_TBL(klass), mid, (void *)&node) && - nd_type(node->nd_body->nd_body) == NODE_CFUNC) { - st_insert(vm_opt_method_table, (st_data_t)node, (st_data_t)bop); + rb_method_entry_t *me; + if (st_lookup(RCLASS_M_TBL(klass), mid, (void *)&me) && + me->type == VM_METHOD_TYPE_CFUNC) { + st_insert(vm_opt_method_table, (st_data_t)me, (st_data_t)bop); } else { rb_bug("undefined optimized method: %s", rb_id2name(mid)); @@ -1323,8 +1324,8 @@ rb_thread_method_id_and_class(rb_thread_t *th, rb_control_frame_t *cfp = th->cfp; rb_iseq_t *iseq = cfp->iseq; if (!iseq) { - if (idp) *idp = cfp->method_id; - if (klassp) *klassp = cfp->method_class; + if (idp) *idp = cfp->me->original_id; + if (klassp) *klassp = cfp->me->klass; return 1; } while (iseq) { @@ -1367,10 +1368,10 @@ rb_thread_current_status(const rb_thread_t *th) file, line_no, RSTRING_PTR(iseq->name)); } } - else if (cfp->method_id) { + else if (cfp->me->original_id) { str = rb_sprintf("`%s#%s' (cfunc)", - RSTRING_PTR(rb_class_name(cfp->method_class)), - rb_id2name(cfp->method_id)); + RSTRING_PTR(rb_class_name(cfp->me->klass)), + rb_id2name(cfp->me->original_id)); } return str; @@ -1739,7 +1740,6 @@ static void vm_define_method(rb_thread_t *th, VALUE obj, ID id, VALUE iseqval, rb_num_t is_singleton, NODE *cref) { - NODE *newbody; VALUE klass = cref->nd_clss; int noex = (int)cref->nd_visi; rb_iseq_t *miseq; @@ -1768,11 +1768,10 @@ vm_define_method(rb_thread_t *th, VALUE obj, ID id, VALUE iseqval, COPY_CREF(miseq->cref_stack, cref); miseq->klass = klass; miseq->defined_method_id = id; - newbody = NEW_NODE_LONGLIFE(RUBY_VM_METHOD_NODE, 0, rb_gc_write_barrier(miseq->self), 0); - rb_add_method(klass, id, newbody, noex); + rb_add_method(klass, id, VM_METHOD_TYPE_ISEQ, miseq, noex); if (!is_singleton && noex == NOEX_MODFUNC) { - rb_add_method(rb_singleton_class(klass), id, newbody, NOEX_PUBLIC); + rb_add_method(rb_singleton_class(klass), id, VM_METHOD_TYPE_ISEQ, miseq, NOEX_PUBLIC); } INC_VM_STATE_VERSION(); } @@ -21,6 +21,7 @@ #include "debug.h" #include "vm_opts.h" #include "id.h" +#include "method.h" #if defined(_WIN32) #include "thread_win32.h" @@ -92,6 +93,8 @@ typedef unsigned long rb_num_t; +/* iseq data type */ + struct iseq_compile_data_ensure_node_stack; typedef struct rb_compile_option_struct { @@ -109,12 +112,8 @@ typedef struct rb_compile_option_struct { struct iseq_inline_cache_entry { long ic_vmstat; VALUE ic_class; - union { - NODE *method; - VALUE value; - } value; -#define ic_value value.value -#define ic_method value.method + VALUE ic_value; + rb_method_entry_t *ic_method; #define ic_index ic_vmstat }; @@ -234,8 +233,6 @@ enum ruby_special_exceptions { ruby_special_error_count }; -typedef struct rb_iseq_struct rb_iseq_t; - #define GetVMPtr(obj, ptr) \ GetCoreDataFromValue(obj, rb_vm_t, ptr) @@ -296,8 +293,7 @@ typedef struct { VALUE *dfp; /* cfp[7] / block[2] */ rb_iseq_t *block_iseq; /* cfp[8] / block[3] */ VALUE proc; /* cfp[9] / block[4] */ - ID method_id; /* cfp[10] saved in special case */ - VALUE method_class; /* cfp[11] saved in special case */ + const rb_method_entry_t *me;/* cfp[10] */ } rb_control_frame_t; typedef struct rb_block_struct { @@ -359,7 +355,7 @@ typedef struct rb_thread_struct int state; /* for rb_iterate */ - rb_block_t *passed_block; + const rb_block_t *passed_block; /* for load(true) */ VALUE top_self; @@ -464,11 +460,6 @@ RUBY_EXTERN VALUE rb_mRubyVMFrozenCore; /* each thread has this size stack : 128KB */ #define RUBY_VM_THREAD_STACK_SIZE (128 * 1024) -struct global_entry { - struct global_variable *var; - ID id; -}; - #define GetProcPtr(obj, ptr) \ GetCoreDataFromValue(obj, rb_proc_t, ptr) @@ -500,6 +491,15 @@ typedef struct { VALUE env; } rb_binding_t; +struct global_entry { + struct global_variable *var; + ID id; +}; + +struct global_entry *rb_global_entry(ID); +VALUE rb_gvar_get(struct global_entry *); +VALUE rb_gvar_set(struct global_entry *, VALUE); +VALUE rb_gvar_defined(struct global_entry *); /* used by compile time and send insn */ #define VM_CALL_ARGS_SPLAT_BIT (0x01 << 1) @@ -509,7 +509,6 @@ typedef struct { #define VM_CALL_TAILCALL_BIT (0x01 << 5) #define VM_CALL_TAILRECURSION_BIT (0x01 << 6) #define VM_CALL_SUPER_BIT (0x01 << 7) -#define VM_CALL_SEND_BIT (0x01 << 8) #define VM_SPECIAL_OBJECT_VMCORE 0x01 #define VM_SPECIAL_OBJECT_CBASE 0x02 @@ -532,11 +531,9 @@ typedef struct { /* other frame flag */ #define VM_FRAME_FLAG_PASSED 0x0100 - #define RUBYVM_CFUNC_FRAME_P(cfp) \ (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_CFUNC) - /* inline cache */ typedef struct iseq_inline_cache_entry *IC; @@ -584,9 +581,7 @@ extern void rb_vmdebug_stack_dump_raw(rb_thread_t *, rb_control_frame_t *); #define SDR2(cfp) rb_vmdebug_stack_dump_raw(GET_THREAD(), (cfp)) void rb_vm_bugreport(void); - /* functions about thread/vm execution */ - VALUE rb_iseq_eval(VALUE iseqval); VALUE rb_iseq_eval_main(VALUE iseqval); void rb_enable_interrupt(void); @@ -594,7 +589,7 @@ void rb_disable_interrupt(void); int rb_thread_method_id_and_class(rb_thread_t *th, ID *idp, VALUE *klassp); VALUE rb_vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, VALUE self, - int argc, const VALUE *argv, rb_block_t *blockptr); + int argc, const VALUE *argv, const rb_block_t *blockptr); VALUE rb_vm_make_proc(rb_thread_t *th, const rb_block_t *block, VALUE klass); VALUE rb_vm_make_env_object(rb_thread_t *th, rb_control_frame_t *cfp); @@ -112,9 +112,9 @@ control_frame_dump(rb_thread_t *th, rb_control_frame_t *cfp) } } } - else if (cfp->method_id) { - iseq_name = rb_id2name(cfp->method_id); - snprintf(posbuf, MAX_POSBUF, ":%s", rb_id2name(cfp->method_id)); + else if (cfp->me) { + iseq_name = rb_id2name(cfp->me->original_id); + snprintf(posbuf, MAX_POSBUF, ":%s", rb_id2name(cfp->me->original_id)); line = -1; } @@ -253,7 +253,7 @@ vm_stack_dump_each(rb_thread_t *th, rb_control_frame_t *cfp) if (iseq == 0) { if (RUBYVM_CFUNC_FRAME_P(cfp)) { - name = rb_id2name(cfp->method_id); + name = rb_id2name(cfp->me->original_id); } else { name = "?"; @@ -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); diff --git a/vm_insnhelper.c b/vm_insnhelper.c index ac2405442b..0163db9620 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -350,21 +350,24 @@ call_cfunc(VALUE (*func)(), VALUE recv, break; default: rb_raise(rb_eArgError, "too many arguments(%d)", len); - break; + return Qundef; /* not reached */ } - return Qnil; /* not reached */ } static inline VALUE vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, - int num, ID id, ID oid, VALUE recv, VALUE klass, - VALUE flag, const NODE *mn, const rb_block_t *blockptr) + int num, VALUE recv, const rb_block_t *blockptr, VALUE flag, + const rb_method_entry_t *me) { VALUE val = 0; int state = 0; + VALUE klass = me->klass; + ID id = me->original_id; EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, id, klass); + TH_PUSH_TAG(th); + // TODO: fix me. separate event if (th->event_flags & RUBY_EVENT_C_RETURN) { state = TH_EXEC_TAG(); } @@ -376,12 +379,10 @@ vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_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; reg_cfp->sp -= num + 1; - val = call_cfunc(mn->nd_cfnc, recv, (int)mn->nd_argc, num, reg_cfp->sp + 1); + val = call_cfunc(me->body.cfunc.func, recv, (int)me->body.cfunc.argc, num, reg_cfp->sp + 1); if (reg_cfp != th->cfp + 1) { rb_bug("cfp consistency error - send"); @@ -397,25 +398,24 @@ vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, } static inline VALUE -vm_call_bmethod(rb_thread_t *th, ID id, VALUE procval, VALUE recv, - VALUE klass, int argc, VALUE *argv, rb_block_t *blockptr) +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) { rb_control_frame_t *cfp = th->cfp; rb_proc_t *proc; VALUE val; /* control block frame */ - (cfp-2)->method_id = id; - (cfp-2)->method_class = klass; + (cfp-2)->me = me; - GetProcPtr(procval, proc); + GetProcPtr(me->body.proc, proc); val = rb_vm_invoke_proc(th, proc, recv, argc, argv, blockptr); return val; } static inline void vm_method_missing_args(rb_thread_t *th, VALUE *argv, - int num, rb_block_t *blockptr, int opt) + int num, const rb_block_t *blockptr, int opt) { rb_control_frame_t * const reg_cfp = th->cfp; MEMCPY(argv, STACK_ADDR_FROM_TOP(num + 1), VALUE, num + 1); @@ -426,7 +426,7 @@ vm_method_missing_args(rb_thread_t *th, VALUE *argv, static inline VALUE vm_method_missing(rb_thread_t *th, ID id, VALUE recv, - int num, rb_block_t *blockptr, int opt) + int num, const rb_block_t *blockptr, int opt) { VALUE *argv = ALLOCA_N(VALUE, num + 1); vm_method_missing_args(th, argv, num, blockptr, opt); @@ -435,16 +435,14 @@ vm_method_missing(rb_thread_t *th, ID id, VALUE recv, } static inline void -vm_setup_method(rb_thread_t *th, rb_control_frame_t *cfp, - const int argc, const rb_block_t *blockptr, const VALUE flag, - const VALUE iseqval, const VALUE recv) +vm_setup_method(rb_thread_t *th, rb_control_frame_t *cfp, + VALUE recv, int argc, const rb_block_t *blockptr, VALUE flag, + const rb_method_entry_t *me) { - rb_iseq_t *iseq; int opt_pc, i; VALUE *sp, *rsp = cfp->sp - argc; + rb_iseq_t *iseq = me->body.iseq; - /* TODO: eliminate it */ - GetISeqPtr(iseqval, iseq); VM_CALLEE_SETUP_ARG(opt_pc, th, iseq, argc, rsp, &blockptr); /* stack overflow check */ @@ -491,69 +489,105 @@ vm_setup_method(rb_thread_t *th, rb_control_frame_t *cfp, } static inline VALUE -vm_call_method(rb_thread_t * const th, rb_control_frame_t * const cfp, - const int num, rb_block_t * const blockptr, const VALUE flag, - const ID id, const NODE * mn, const VALUE recv) +vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, + int num, const rb_block_t *blockptr, VALUE flag, + ID id, const rb_method_entry_t *me, VALUE recv) { VALUE val; start_method_dispatch: - if (mn != 0) { - if ((mn->nd_noex == 0)) { - /* dispatch method */ - NODE *node; - + if (me != 0) { + if ((me->flag == 0)) { normal_method_dispatch: - - node = mn->nd_body; - - switch (nd_type(node)) { - case RUBY_VM_METHOD_NODE:{ - vm_setup_method(th, cfp, num, blockptr, flag, (VALUE)node->nd_body, recv); + switch (me->type) { + case VM_METHOD_TYPE_ISEQ:{ + vm_setup_method(th, cfp, recv, num, blockptr, flag, me); return Qundef; } - case NODE_CFUNC:{ - val = vm_call_cfunc(th, cfp, num, id, (ID)mn->nd_file, recv, mn->nd_clss, flag, node, blockptr); + case VM_METHOD_TYPE_NOTIMPLEMENTED: + case VM_METHOD_TYPE_CFUNC:{ + val = vm_call_cfunc(th, cfp, num, recv, blockptr, flag, me); break; } - case NODE_ATTRSET:{ - val = rb_ivar_set(recv, node->nd_vid, *(cfp->sp - 1)); + case VM_METHOD_TYPE_ATTRSET:{ + if (num != 1) { + rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", num); + } + val = rb_ivar_set(recv, me->body.attr_id, *(cfp->sp - 1)); cfp->sp -= 2; break; } - case NODE_IVAR:{ + case VM_METHOD_TYPE_IVAR:{ if (num != 0) { - rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", - num); + rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", num); } - val = rb_attr_get(recv, node->nd_vid); + val = rb_attr_get(recv, me->body.attr_id); cfp->sp -= 1; break; } - case NODE_BMETHOD:{ + case VM_METHOD_TYPE_BMETHOD:{ VALUE *argv = ALLOCA_N(VALUE, num); MEMCPY(argv, cfp->sp - num, VALUE, num); cfp->sp += - num - 1; - val = vm_call_bmethod(th, (ID)mn->nd_file, node->nd_cval, recv, mn->nd_clss, num, argv, blockptr); + val = vm_call_bmethod(th, recv, num, argv, blockptr, me); break; } - case NODE_ZSUPER:{ - VALUE klass; - klass = RCLASS_SUPER(mn->nd_clss); - mn = rb_method_node(klass, id); + case VM_METHOD_TYPE_ZSUPER:{ + VALUE klass = RCLASS_SUPER(me->klass); + me = rb_method_entry(klass, id); - if (mn != 0) { + if (me != 0) { goto normal_method_dispatch; } else { goto start_method_dispatch; } } + case VM_METHOD_TYPE_OPTIMIZED:{ + switch (me->body.optimize_type) { + case OPTIMIZED_METHOD_TYPE_SEND: { + rb_control_frame_t *reg_cfp = cfp; + rb_num_t i = num - 1; + VALUE sym; + + if (num == 0) { + rb_raise(rb_eArgError, "no method name given"); + } + + sym = TOPN(i); + id = SYMBOL_P(sym) ? SYM2ID(sym) : rb_to_id(sym); + /* shift arguments */ + if (i > 0) { + MEMMOVE(&TOPN(i), &TOPN(i-1), VALUE, i); + } + me = rb_method_entry(CLASS_OF(recv), id); + num -= 1; + DEC_SP(1); + flag |= VM_CALL_FCALL_BIT; + + goto start_method_dispatch; + } + break; + case OPTIMIZED_METHOD_TYPE_CALL: { + rb_proc_t *proc; + int argc = num; + VALUE *argv = ALLOCA_N(VALUE, num); + GetProcPtr(recv, proc); + MEMCPY(argv, cfp->sp - num, VALUE, num); + cfp->sp -= num + 1; + + val = rb_vm_invoke_proc(th, proc, proc->block.self, argc, argv, blockptr); + } + break; + default: + rb_bug("eval_invoke_method: unsupported optimized method type (%d)", + me->body.optimize_type); + } + break; + } default:{ - printf("node: %s\n", ruby_node_name(nd_type(node))); - rb_bug("eval_invoke_method: unreachable"); - /* unreachable */ + rb_bug("eval_invoke_method: unsupported method type (%d)", me->type); break; } } @@ -562,7 +596,7 @@ vm_call_method(rb_thread_t * const th, rb_control_frame_t * const cfp, int noex_safe; if (!(flag & VM_CALL_FCALL_BIT) && - (mn->nd_noex & NOEX_MASK) & NOEX_PRIVATE) { + (me->flag & NOEX_MASK) & NOEX_PRIVATE) { int stat = NOEX_PRIVATE; if (flag & VM_CALL_VCALL_BIT) { @@ -570,9 +604,8 @@ vm_call_method(rb_thread_t * const th, rb_control_frame_t * const cfp, } val = vm_method_missing(th, id, recv, num, blockptr, stat); } - else if (((mn->nd_noex & NOEX_MASK) & NOEX_PROTECTED) && - !(flag & VM_CALL_SEND_BIT)) { - VALUE defined_class = mn->nd_clss; + else if ((me->flag & NOEX_MASK) & NOEX_PROTECTED) { + VALUE defined_class = me->klass; if (TYPE(defined_class) == T_ICLASS) { defined_class = RBASIC(defined_class)->klass; @@ -585,7 +618,7 @@ vm_call_method(rb_thread_t * const th, rb_control_frame_t * const cfp, goto normal_method_dispatch; } } - else if ((noex_safe = NOEX_SAFE(mn->nd_noex)) > th->safe_level && + else if ((noex_safe = NOEX_SAFE(me->flag)) > th->safe_level && (noex_safe > 2)) { rb_raise(rb_eSecurityError, "calling insecure method: %s", rb_id2name(id)); } @@ -617,33 +650,6 @@ vm_call_method(rb_thread_t * const th, rb_control_frame_t * const cfp, return val; } -static inline void -vm_send_optimize(rb_control_frame_t * const reg_cfp, NODE ** const mn, - rb_num_t * const flag, rb_num_t * const num, - ID * const id, const VALUE klass) -{ - if (*mn && nd_type((*mn)->nd_body) == NODE_CFUNC) { - NODE *node = (*mn)->nd_body; - extern VALUE rb_f_send(int argc, VALUE *argv, VALUE recv); - - if (node->nd_cfnc == rb_f_send) { - rb_num_t i = *num - 1; - VALUE sym = TOPN(i); - *id = SYMBOL_P(sym) ? SYM2ID(sym) : rb_to_id(sym); - - /* shift arguments */ - if (i > 0) { - MEMMOVE(&TOPN(i), &TOPN(i-1), VALUE, i); - } - - *mn = rb_method_node(klass, *id); - *num -= 1; - DEC_SP(1); - *flag |= VM_CALL_FCALL_BIT; - } - } -} - /* yield */ static inline int @@ -707,8 +713,8 @@ vm_yield_with_cfunc(rb_thread_t *th, const rb_block_t *block, * @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) +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; @@ -765,8 +771,8 @@ vm_yield_setup_block_args_complex(rb_thread_t *th, const rb_iseq_t * iseq, 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 orig_argc, VALUE *argv, + const rb_block_t *blockptr) { int i; int argc = orig_argc; @@ -839,7 +845,12 @@ vm_yield_setup_block_args(rb_thread_t *th, const rb_iseq_t * iseq, VALUE procval = Qnil; if (blockptr) { - procval = blockptr->proc; + if (blockptr->proc == 0) { + procval = rb_vm_make_proc(th, blockptr, rb_cProc); + } + else { + procval = blockptr->proc; + } } argv[iseq->arg_block] = procval; @@ -879,7 +890,7 @@ vm_yield_setup_args(rb_thread_t * const th, const rb_iseq_t *iseq, static VALUE vm_invoke_block(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_num_t num, rb_num_t flag) { - rb_block_t * const block = GET_BLOCK_PTR(); + const rb_block_t *block = GET_BLOCK_PTR(); rb_iseq_t *iseq; int argc = (int)num; @@ -1218,28 +1229,25 @@ vm_getivar(VALUE obj, ID id, IC ic) #endif } -static inline NODE * +static inline const rb_method_entry_t * vm_method_search(VALUE id, VALUE klass, IC ic) { - NODE *mn; - + rb_method_entry_t *me; #if OPT_INLINE_METHOD_CACHE - { - if (LIKELY(klass == ic->ic_class) && - LIKELY(GET_VM_STATE_VERSION() == ic->ic_vmstat)) { - mn = ic->ic_method; - } - else { - mn = rb_method_node(klass, id); - ic->ic_class = klass; - ic->ic_method = mn; - ic->ic_vmstat = GET_VM_STATE_VERSION(); - } + if (LIKELY(klass == ic->ic_class) && + LIKELY(GET_VM_STATE_VERSION() == ic->ic_vmstat)) { + me = ic->ic_method; + } + else { + me = rb_method_entry(klass, id); + ic->ic_class = klass; + ic->ic_method = me; + ic->ic_vmstat = GET_VM_STATE_VERSION(); } #else - mn = rb_method_node(klass, id); + me = rb_method_entry(klass, id); #endif - return mn; + return me; } static inline VALUE @@ -1300,8 +1308,8 @@ vm_search_superclass(rb_control_frame_t *reg_cfp, rb_iseq_t *ip, } } - id = lcfp->method_id; - klass = vm_search_normal_superclass(lcfp->method_class, recv); + id = lcfp->me->original_id; + klass = vm_search_normal_superclass(lcfp->me->klass, recv); } else { klass = vm_search_normal_superclass(ip->klass, recv); @@ -1520,10 +1528,10 @@ vm_expandarray(rb_control_frame_t *cfp, VALUE ary, rb_num_t num, int flag) } static inline int -check_cfunc(const NODE *mn, VALUE (*func)()) +check_cfunc(const rb_method_entry_t *me, VALUE (*func)()) { - if (mn && nd_type(mn->nd_body) == NODE_CFUNC && - mn->nd_body->nd_cfnc == func) { + if (me && me->type == VM_METHOD_TYPE_CFUNC && + me->body.cfunc.func == func) { return 1; } else { @@ -1572,10 +1580,10 @@ opt_eq_func(VALUE recv, VALUE obj, IC ic) val = rb_str_equal(recv, obj); } else { - NODE *mn = vm_method_search(idEq, CLASS_OF(recv), ic); + const rb_method_entry_t *me = vm_method_search(idEq, CLASS_OF(recv), ic); extern VALUE rb_obj_equal(VALUE obj1, VALUE obj2); - if (check_cfunc(mn, rb_obj_equal)) { + if (check_cfunc(me, rb_obj_equal)) { return recv == obj ? Qtrue : Qfalse; } } diff --git a/vm_insnhelper.h b/vm_insnhelper.h index d927807c56..a96298c561 100644 --- a/vm_insnhelper.h +++ b/vm_insnhelper.h @@ -159,8 +159,8 @@ extern VALUE ruby_vm_const_missing_count; c1->nd_next = (NODE *)rb_gc_write_barrier((VALUE)__tmp_c2->nd_next);\ } while (0) -#define CALL_METHOD(num, blockptr, flag, id, mn, recv) do { \ - VALUE v = vm_call_method(th, GET_CFP(), num, blockptr, flag, id, mn, recv); \ +#define CALL_METHOD(num, blockptr, flag, id, me, recv) do { \ + VALUE v = vm_call_method(th, GET_CFP(), num, blockptr, flag, id, me, recv); \ if (v == Qundef) { \ RESTORE_REGS(); \ NEXT_INSN(); \ @@ -189,7 +189,7 @@ extern VALUE ruby_vm_const_missing_count; #define CALL_SIMPLE_METHOD(num, id, recv) do { \ VALUE klass = CLASS_OF(recv); \ - CALL_METHOD(num, 0, 0, id, rb_method_node(klass, id), recv); \ + CALL_METHOD(num, 0, 0, id, rb_method_entry(klass, id), recv); \ } while (0) #endif /* RUBY_INSNHELPER_H */ diff --git a/vm_method.c b/vm_method.c index 292146dab9..e84d4ccba6 100644 --- a/vm_method.c +++ b/vm_method.c @@ -6,7 +6,7 @@ #define CACHE_MASK 0x7ff #define EXPR1(c,m) ((((c)>>3)^(m))&CACHE_MASK) -static void rb_vm_check_redefinition_opt_method(const NODE *node); +static void rb_vm_check_redefinition_opt_method(const rb_method_entry_t *me); static ID object_id; static ID removed, singleton_removed, undefined, singleton_undefined; @@ -14,18 +14,14 @@ static ID added, singleton_added; struct cache_entry { /* method hash table. */ ID mid; /* method's id */ - ID mid0; /* method's original id */ VALUE klass; /* receiver's class */ - VALUE oklass; /* original's class */ - NODE *method; + rb_method_entry_t *me; }; static struct cache_entry cache[CACHE_SIZE]; #define ruby_running (GET_VM()->running) /* int ruby_running = 0; */ -static NODE *notimplement_body = 0; - void rb_clear_cache(void) { @@ -38,7 +34,7 @@ rb_clear_cache(void) ent = cache; end = ent + CACHE_SIZE; while (ent < end) { - ent->mid = 0; + ent->me = ent->mid = 0; ent++; } } @@ -55,8 +51,8 @@ rb_clear_cache_for_undef(VALUE klass, ID id) ent = cache; end = ent + CACHE_SIZE; while (ent < end) { - if (ent->oklass == klass && ent->mid == id) { - ent->mid = 0; + if ((ent->me && ent->me->klass == klass) && ent->mid == id) { + ent->me = ent->mid = 0; } ent++; } @@ -75,7 +71,7 @@ rb_clear_cache_by_id(ID id) end = ent + CACHE_SIZE; while (ent < end) { if (ent->mid == id) { - ent->mid = 0; + ent->me = ent->mid = 0; } ent++; } @@ -93,17 +89,43 @@ rb_clear_cache_by_class(VALUE klass) ent = cache; end = ent + CACHE_SIZE; while (ent < end) { - if (ent->klass == klass || ent->oklass == klass) { - ent->mid = 0; + if (ent->klass == klass || (ent->me && ent->me->klass == klass)) { + ent->me = ent->mid = 0; } ent++; } } +VALUE rb_f_notimplement(int argc, VALUE *argv, VALUE obj) +{ + rb_notimplement(); +} + +static void rb_define_notimplement_method_id(VALUE mod, ID id, rb_method_flag_t noex) +{ + rb_add_method(mod, id, VM_METHOD_TYPE_NOTIMPLEMENTED, 0, noex); +} + void -rb_add_method(VALUE klass, ID mid, NODE * node, int noex) +rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_method_flag_t noex) { - NODE *body; + if (func != rb_f_notimplement) { + rb_method_cfunc_t opt = { + func, argc, + }; + rb_add_method(klass, mid, VM_METHOD_TYPE_CFUNC, &opt, noex); + } + else { + rb_define_notimplement_method_id(klass, mid, noex); + } +} + +rb_method_entry_t * +rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *opts, rb_method_flag_t noex) +{ + rb_method_entry_t *me; + st_table *mtbl; + st_data_t data; if (NIL_P(klass)) { klass = rb_cObject; @@ -113,15 +135,16 @@ rb_add_method(VALUE klass, ID mid, NODE * node, int noex) rb_raise(rb_eSecurityError, "Insecure: can't define method"); } if (!FL_TEST(klass, FL_SINGLETON) && - node && nd_type(node) != NODE_ZSUPER && + type != VM_METHOD_TYPE_NOTIMPLEMENTED && + type != VM_METHOD_TYPE_ZSUPER && (mid == rb_intern("initialize") || mid == rb_intern("initialize_copy"))) { noex = NOEX_PRIVATE | noex; } - else if (FL_TEST(klass, FL_SINGLETON) && node - && nd_type(node) == NODE_CFUNC && mid == rb_intern("allocate")) { - rb_warn - ("defining %s.allocate is deprecated; use rb_define_alloc_func()", - rb_class2name(rb_iv_get(klass, "__attached__"))); + else if (FL_TEST(klass, FL_SINGLETON) && + type == VM_METHOD_TYPE_CFUNC && + mid == rb_intern("allocate")) { + rb_warn("defining %s.allocate is deprecated; use rb_define_alloc_func()", + rb_class2name(rb_iv_get(klass, "__attached__"))); mid = ID_ALLOCATOR; } if (OBJ_FROZEN(klass)) { @@ -129,189 +152,178 @@ rb_add_method(VALUE klass, ID mid, NODE * node, int noex) } rb_clear_cache_by_id(mid); - /* - * NODE_METHOD (NEW_METHOD(body, klass, vis)): - * nd_file : original id // RBASIC()->klass (TODO: dirty hack) - * nd_body : method body // (2) // mark - * nd_clss : klass // (1) // mark - * nd_noex : visibility // (3) - * - * NODE_FBODY (NEW_FBODY(method, alias)): - * nd_body : method (NODE_METHOD) // (2) // mark - * nd_oid : original id // (1) - * nd_cnt : alias count // (3) - */ - if (node) { - NODE *method = NEW_NODE_LONGLIFE(NODE_METHOD, - rb_gc_write_barrier(klass), - rb_gc_write_barrier((VALUE)node), - NOEX_WITH_SAFE(noex)); - method->nd_file = (void *)mid; - body = NEW_NODE_LONGLIFE(NODE_FBODY, mid, method, 0); - } - else { - body = 0; - } - - { - /* check re-definition */ - st_data_t data; - NODE *old_node; - - if (st_lookup(RCLASS_M_TBL(klass), mid, &data)) { - old_node = (NODE *)data; - if (old_node) { - if (nd_type(old_node->nd_body->nd_body) == NODE_CFUNC) { - rb_vm_check_redefinition_opt_method(old_node); - } - if (RTEST(ruby_verbose) && node && old_node->nd_cnt == 0 && old_node->nd_body) { - rb_warning("method redefined; discarding old %s", rb_id2name(mid)); - } - } - } - if (klass == rb_cObject && node && mid == idInitialize) { - rb_warn("redefining Object#initialize may cause infinite loop"); + me = ALLOC(rb_method_entry_t); + me->type = type; + me->original_id = me->called_id = mid; + me->klass = klass; + me->flag = NOEX_WITH_SAFE(noex); + me->alias_count = 0; + + switch (type) { + case VM_METHOD_TYPE_ISEQ: + me->body.iseq = (rb_iseq_t *)opts; + break; + case VM_METHOD_TYPE_CFUNC: + me->body.cfunc = *(rb_method_cfunc_t *)opts; + break; + case VM_METHOD_TYPE_ATTRSET: + case VM_METHOD_TYPE_IVAR: + me->body.attr_id = (ID)opts; + break; + case VM_METHOD_TYPE_BMETHOD: + me->body.proc = (VALUE)opts; + break; + case VM_METHOD_TYPE_NOTIMPLEMENTED: + me->body.cfunc.func = rb_f_notimplement; + me->body.cfunc.argc = -1; + break; + case VM_METHOD_TYPE_OPTIMIZED: + me->body.optimize_type = (enum method_optimized_type)opts; + break; + case VM_METHOD_TYPE_ZSUPER: + case VM_METHOD_TYPE_UNDEF: + break; + default: + rb_bug("rb_add_method: unsupported method type (%d)\n", type); + } + + mtbl = RCLASS_M_TBL(klass); + + /* check re-definition */ + if (st_lookup(mtbl, mid, &data)) { + rb_method_entry_t *old_me = (rb_method_entry_t *)data; + rb_vm_check_redefinition_opt_method(old_me); + + if (RTEST(ruby_verbose) && + old_me->alias_count == 0 && + old_me->type != VM_METHOD_TYPE_UNDEF) { + rb_warning("method redefined; discarding old %s", rb_id2name(mid)); } - if (mid == object_id || mid == id__send__) { - if (node && nd_type(node) == RUBY_VM_METHOD_NODE) { - rb_warn("redefining `%s' may cause serious problems", - rb_id2name(mid)); - } + // TODO: free old_me + } + + /* check mid */ + if (klass == rb_cObject && mid == idInitialize) { + rb_warn("redefining Object#initialize may cause infinite loop"); + } + /* check mid */ + if (mid == object_id || mid == id__send__) { + if (type == VM_METHOD_TYPE_ISEQ) { + rb_warn("redefining `%s' may cause serious problems", rb_id2name(mid)); } } - st_insert(RCLASS_M_TBL(klass), mid, (st_data_t) body); + st_insert(mtbl, mid, (st_data_t) me); - if (node && mid != ID_ALLOCATOR && ruby_running) { + if (mid != ID_ALLOCATOR && ruby_running) { if (FL_TEST(klass, FL_SINGLETON)) { - rb_funcall(rb_iv_get(klass, "__attached__"), singleton_added, 1, - ID2SYM(mid)); + rb_funcall(rb_iv_get(klass, "__attached__"), singleton_added, 1, ID2SYM(mid)); } else { rb_funcall(klass, added, 1, ID2SYM(mid)); } } + + return me; } void rb_define_alloc_func(VALUE klass, VALUE (*func)(VALUE)) { Check_Type(klass, T_CLASS); - rb_add_method(rb_singleton_class(klass), ID_ALLOCATOR, - NEW_NODE_LONGLIFE(NODE_CFUNC, func, 0, 0), - NOEX_PRIVATE); + rb_add_method_cfunc(rb_singleton_class(klass), ID_ALLOCATOR, + func, 0, NOEX_PRIVATE); } void rb_undef_alloc_func(VALUE klass) { Check_Type(klass, T_CLASS); - rb_add_method(rb_singleton_class(klass), ID_ALLOCATOR, 0, NOEX_UNDEF); + rb_add_method(rb_singleton_class(klass), ID_ALLOCATOR, VM_METHOD_TYPE_UNDEF, 0, NOEX_UNDEF); } rb_alloc_func_t rb_get_alloc_func(VALUE klass) { - NODE *n; + rb_method_entry_t *me; Check_Type(klass, T_CLASS); - n = rb_method_node(CLASS_OF(klass), ID_ALLOCATOR); - if (!n) return 0; - if (nd_type(n) != NODE_METHOD) return 0; - n = n->nd_body; - if (nd_type(n) != NODE_CFUNC) return 0; - return (rb_alloc_func_t)n->nd_cfnc; + me = rb_method_entry(CLASS_OF(klass), ID_ALLOCATOR); + + if (me && me->type == VM_METHOD_TYPE_CFUNC) { + return (rb_alloc_func_t)me->body.cfunc.func; + } + else { + return 0; + } } -static NODE * -search_method(VALUE klass, ID id, VALUE *klassp) +static rb_method_entry_t* +search_method(VALUE klass, ID id) { st_data_t body; - if (!klass) { return 0; } while (!st_lookup(RCLASS_M_TBL(klass), id, &body)) { klass = RCLASS_SUPER(klass); - if (!klass) + if (!klass) { return 0; + } } - if (klassp) { - *klassp = klass; - } - - return (NODE *)body; + return (rb_method_entry_t *)body; } /* - * search method body (NODE_METHOD) - * with : klass and id - * without : method cache + * search method entry without method cache. * - * if you need method node with method cache, use - * rb_method_node() + * if you need method entry with method cache, use + * rb_method_entry() */ -NODE * -rb_get_method_body(VALUE klass, ID id, ID *idp) +rb_method_entry_t * +rb_get_method_entry(VALUE klass, ID id) { - NODE *volatile fbody, *body; - NODE *method; - - if ((fbody = search_method(klass, id, 0)) == 0 || !fbody->nd_body) { - /* store empty info in cache */ - struct cache_entry *ent; - ent = cache + EXPR1(klass, id); - ent->klass = klass; - ent->mid = ent->mid0 = id; - ent->method = 0; - ent->oklass = 0; - return 0; - } - - method = fbody->nd_body; + rb_method_entry_t *me = search_method(klass, id); if (ruby_running) { - /* store in cache */ struct cache_entry *ent; ent = cache + EXPR1(klass, id); ent->klass = klass; - ent->mid = id; - ent->mid0 = fbody->nd_oid; - ent->method = body = method; - ent->oklass = method->nd_clss; - } - else { - body = method; - } - if (idp) { - *idp = fbody->nd_oid; + if (!me || me->type == VM_METHOD_TYPE_UNDEF) { + ent->mid = id; + ent->me = 0; + me = 0; + } + else { + ent->mid = id; + ent->me = me; + } } - return body; + return me; } -NODE * -rb_method_node(VALUE klass, ID id) +rb_method_entry_t * +rb_method_entry(VALUE klass, ID id) { struct cache_entry *ent; ent = cache + EXPR1(klass, id); if (ent->mid == id && ent->klass == klass) { - if (ent->method) return ent->method; - return 0; + return ent->me; } - return rb_get_method_body(klass, id, 0); + return rb_get_method_entry(klass, id); } static void remove_method(VALUE klass, ID mid) { st_data_t data; - NODE *body = 0; + rb_method_entry_t *me = 0; if (klass == rb_cObject) { rb_secure(4); @@ -324,26 +336,26 @@ remove_method(VALUE klass, ID mid) if (mid == object_id || mid == id__send__ || mid == idInitialize) { rb_warn("removing `%s' may cause serious problems", rb_id2name(mid)); } + if (st_lookup(RCLASS_M_TBL(klass), mid, &data)) { - body = (NODE *)data; - if (!body || !body->nd_body) body = 0; + me = (rb_method_entry_t *)data; + if (!me || me->type == VM_METHOD_TYPE_UNDEF) { + me = 0; + } else { st_delete(RCLASS_M_TBL(klass), &mid, &data); } } - if (!body) { + if (!me) { rb_name_error(mid, "method `%s' not defined in %s", rb_id2name(mid), rb_class2name(klass)); } - if (nd_type(body->nd_body->nd_body) == NODE_CFUNC) { - rb_vm_check_redefinition_opt_method(body); - } - + rb_vm_check_redefinition_opt_method(me); rb_clear_cache_for_undef(klass, mid); + if (FL_TEST(klass, FL_SINGLETON)) { - rb_funcall(rb_iv_get(klass, "__attached__"), singleton_removed, 1, - ID2SYM(mid)); + rb_funcall(rb_iv_get(klass, "__attached__"), singleton_removed, 1, ID2SYM(mid)); } else { rb_funcall(klass, removed, 1, ID2SYM(mid)); @@ -393,49 +405,45 @@ rb_enable_super(VALUE klass, const char *name) static void rb_export_method(VALUE klass, ID name, ID noex) { - NODE *fbody; - VALUE origin; + rb_method_entry_t *me; if (klass == rb_cObject) { rb_secure(4); } - fbody = search_method(klass, name, &origin); - if (!fbody && TYPE(klass) == T_MODULE) { - fbody = search_method(rb_cObject, name, &origin); + + me = search_method(klass, name); + if (!me && TYPE(klass) == T_MODULE) { + me = search_method(rb_cObject, name); } - if (!fbody || !fbody->nd_body) { + + if (!me || me->type == VM_METHOD_TYPE_UNDEF) { rb_print_undef(klass, name, 0); } - if (fbody->nd_body->nd_noex != noex) { - if (nd_type(fbody->nd_body->nd_body) == NODE_CFUNC) { - rb_vm_check_redefinition_opt_method(fbody); - } - if (klass == origin) { - fbody->nd_body->nd_noex = noex; + + if (me->flag != noex) { + rb_vm_check_redefinition_opt_method(me); + + if (klass == me->klass) { + me->flag = noex; } else { - rb_add_method(klass, name, NEW_ZSUPER(), noex); + rb_add_method(klass, name, VM_METHOD_TYPE_ZSUPER, 0, noex); } } } int -rb_notimplement_body_p(NODE *method) -{ - return method == notimplement_body ? Qtrue : Qfalse; -} - -int rb_method_boundp(VALUE klass, ID id, int ex) { - NODE *method; + rb_method_entry_t *me = rb_method_entry(klass, id); - if ((method = rb_method_node(klass, id)) != 0) { - if (ex && (method->nd_noex & NOEX_PRIVATE)) { + if (me != 0) { + if (ex && (me->flag & NOEX_PRIVATE)) { return Qfalse; } - if (rb_notimplement_body_p(method->nd_body)) + if (me->type == VM_METHOD_TYPE_NOTIMPLEMENTED) { return Qfalse; + } return Qtrue; } return Qfalse; @@ -447,7 +455,7 @@ rb_attr(VALUE klass, ID id, int read, int write, int ex) const char *name; ID attriv; VALUE aname; - int noex; + rb_method_flag_t noex; if (!ex) { noex = NOEX_PUBLIC; @@ -478,32 +486,32 @@ rb_attr(VALUE klass, ID id, int read, int write, int ex) rb_enc_copy(aname, rb_id2str(id)); attriv = rb_intern_str(aname); if (read) { - rb_add_method(klass, id, NEW_IVAR(attriv), noex); + rb_add_method(klass, id, VM_METHOD_TYPE_IVAR, (void *)attriv, noex); } if (write) { - rb_add_method(klass, rb_id_attrset(id), NEW_ATTRSET(attriv), noex); + rb_add_method(klass, rb_id_attrset(id), VM_METHOD_TYPE_ATTRSET, (void *)attriv, noex); } } void rb_undef(VALUE klass, ID id) { - VALUE origin; - NODE *body; + rb_method_entry_t *me; if (rb_vm_cbase() == rb_cObject && klass == rb_cObject) { rb_secure(4); } if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(klass)) { - rb_raise(rb_eSecurityError, "Insecure: can't undef `%s'", - rb_id2name(id)); + rb_raise(rb_eSecurityError, "Insecure: can't undef `%s'", rb_id2name(id)); } rb_frozen_class_p(klass); if (id == object_id || id == id__send__ || id == idInitialize) { rb_warn("undefining `%s' may cause serious problems", rb_id2name(id)); } - body = search_method(klass, id, &origin); - if (!body || !body->nd_body) { + + me = search_method(klass, id); + + if (!me || me->type == VM_METHOD_TYPE_UNDEF) { const char *s0 = " class"; VALUE c = klass; @@ -524,11 +532,10 @@ rb_undef(VALUE klass, ID id) rb_id2name(id), s0, rb_class2name(c)); } - rb_add_method(klass, id, 0, NOEX_PUBLIC); + rb_add_method(klass, id, VM_METHOD_TYPE_UNDEF, 0, NOEX_PUBLIC); if (FL_TEST(klass, FL_SINGLETON)) { - rb_funcall(rb_iv_get(klass, "__attached__"), - singleton_undefined, 1, ID2SYM(id)); + rb_funcall(rb_iv_get(klass, "__attached__"), singleton_undefined, 1, ID2SYM(id)); } else { rb_funcall(klass, undefined, 1, ID2SYM(id)); @@ -622,6 +629,18 @@ rb_mod_method_defined(VALUE mod, VALUE mid) #define VISI_CHECK(x,f) (((x)&NOEX_MASK) == (f)) +static VALUE +check_definition(VALUE mod, VALUE mid, rb_method_flag_t noex) +{ + const rb_method_entry_t *me; + me = rb_method_entry(mod, mid); + if (me) { + if (VISI_CHECK(me->flag, noex)) + return Qtrue; + } + return Qfalse; +} + /* * call-seq: * mod.public_method_defined?(symbol) => true or false @@ -651,15 +670,7 @@ rb_mod_method_defined(VALUE mod, VALUE mid) static VALUE rb_mod_public_method_defined(VALUE mod, VALUE mid) { - ID id = rb_to_id(mid); - NODE *method; - - method = rb_method_node(mod, id); - if (method) { - if (VISI_CHECK(method->nd_noex, NOEX_PUBLIC)) - return Qtrue; - } - return Qfalse; + return check_definition(mod, rb_to_id(mid), NOEX_PUBLIC); } /* @@ -691,15 +702,7 @@ rb_mod_public_method_defined(VALUE mod, VALUE mid) static VALUE rb_mod_private_method_defined(VALUE mod, VALUE mid) { - ID id = rb_to_id(mid); - NODE *method; - - method = rb_method_node(mod, id); - if (method) { - if (VISI_CHECK(method->nd_noex, NOEX_PRIVATE)) - return Qtrue; - } - return Qfalse; + return check_definition(mod, rb_to_id(mid), NOEX_PRIVATE); } /* @@ -731,70 +734,100 @@ rb_mod_private_method_defined(VALUE mod, VALUE mid) static VALUE rb_mod_protected_method_defined(VALUE mod, VALUE mid) { - ID id = rb_to_id(mid); - NODE *method; + return check_definition(mod, rb_to_id(mid), NOEX_PROTECTED); +} - method = rb_method_node(mod, id); - if (method) { - if (VISI_CHECK(method->nd_noex, NOEX_PROTECTED)) - return Qtrue; +static void * +me_opts(const rb_method_entry_t *me) +{ + switch (me->type) { + case VM_METHOD_TYPE_ISEQ: + return me->body.iseq; + case VM_METHOD_TYPE_CFUNC: + return (void *)&me->body.cfunc; + case VM_METHOD_TYPE_ATTRSET: + case VM_METHOD_TYPE_IVAR: + return (void *)me->body.attr_id; + case VM_METHOD_TYPE_BMETHOD: + return (void *)me->body.proc; + case VM_METHOD_TYPE_ZSUPER: + case VM_METHOD_TYPE_NOTIMPLEMENTED: + case VM_METHOD_TYPE_UNDEF: + return 0; + default: + rb_bug("rb_add_method: unsupported method type (%d)\n", me->type); + return 0; + } +} + +void +rb_add_method_me(VALUE klass, ID mid, const rb_method_entry_t *me, rb_method_flag_t noex) +{ + rb_add_method(klass, mid, me->type, me_opts(me), noex); +} + +int +rb_method_entry_eq(const rb_method_entry_t *m1, const rb_method_entry_t *m2) +{ + if (m1->type != m2->type) { + return 0; + } + switch (m1->type) { + case VM_METHOD_TYPE_ISEQ: + return m1->body.iseq == m2->body.iseq; + case VM_METHOD_TYPE_CFUNC: + return + m1->body.cfunc.func == m2->body.cfunc.func && + m1->body.cfunc.argc == m2->body.cfunc.argc; + case VM_METHOD_TYPE_ATTRSET: + case VM_METHOD_TYPE_IVAR: + return m1->body.attr_id == m2->body.attr_id; + case VM_METHOD_TYPE_BMETHOD: + return m1->body.proc == m2->body.proc; + case VM_METHOD_TYPE_ZSUPER: + case VM_METHOD_TYPE_NOTIMPLEMENTED: + case VM_METHOD_TYPE_UNDEF: + return 1; + default: + rb_bug("rb_add_method: unsupported method type (%d)\n", m1->type); + return 0; } - return Qfalse; } void rb_alias(VALUE klass, ID name, ID def) { - NODE *orig_fbody, *node, *method; + rb_method_entry_t *orig_me, *me; VALUE singleton = 0; - st_data_t data; rb_frozen_class_p(klass); if (klass == rb_cObject) { rb_secure(4); } - orig_fbody = search_method(klass, def, 0); - if (!orig_fbody || !orig_fbody->nd_body) { + + orig_me = search_method(klass, def); + + if (!orig_me || orig_me->type == VM_METHOD_TYPE_UNDEF) { if (TYPE(klass) == T_MODULE) { - orig_fbody = search_method(rb_cObject, def, 0); + orig_me = search_method(rb_cObject, def); + + if (!orig_me || !orig_me->type == VM_METHOD_TYPE_UNDEF) { + rb_print_undef(klass, def, 0); + } } } - if (!orig_fbody || !orig_fbody->nd_body) { - rb_print_undef(klass, def, 0); - } if (FL_TEST(klass, FL_SINGLETON)) { singleton = rb_iv_get(klass, "__attached__"); } - orig_fbody->nd_cnt++; - - if (st_lookup(RCLASS_M_TBL(klass), name, &data)) { - node = (NODE *)data; - if (node) { - if (RTEST(ruby_verbose) && node->nd_cnt == 0 && node->nd_body) { - rb_warning("discarding old %s", rb_id2name(name)); - } - if (nd_type(node->nd_body->nd_body) == NODE_CFUNC) { - rb_vm_check_redefinition_opt_method(node); - } - } - } + orig_me->alias_count++; + me = rb_add_method(klass, name, orig_me->type, me_opts(orig_me), orig_me->flag); + me->original_id = def; - st_insert(RCLASS_M_TBL(klass), name, - (st_data_t) NEW_NODE_LONGLIFE( - NODE_FBODY, - def, - method = NEW_NODE_LONGLIFE(NODE_METHOD, - rb_gc_write_barrier((VALUE)orig_fbody->nd_body->nd_clss), - rb_gc_write_barrier((VALUE)orig_fbody->nd_body->nd_body), - NOEX_WITH_SAFE(orig_fbody->nd_body->nd_noex)), - 0)); - method->nd_file = (void *)def; + if (!ruby_running) return; rb_clear_cache_by_id(name); - if (!ruby_running) return; - if (singleton) { rb_funcall(singleton, singleton_added, 1, ID2SYM(name)); } @@ -832,18 +865,6 @@ rb_mod_alias_method(VALUE mod, VALUE newname, VALUE oldname) return mod; } -VALUE -rb_f_notimplement(int argc, VALUE *argv, VALUE obj) -{ - rb_notimplement(); -} - -void -rb_define_notimplement_method_id(VALUE mod, ID id, int noex) -{ - rb_add_method(mod, id, notimplement_body, noex); -} - static void secure_visibility(VALUE self) { @@ -1042,7 +1063,7 @@ rb_mod_modfunc(int argc, VALUE *argv, VALUE module) { int i; ID id; - NODE *fbody; + const rb_method_entry_t *me; if (TYPE(module) != T_MODULE) { rb_raise(rb_eTypeError, "module_function must be called for modules"); @@ -1061,22 +1082,21 @@ rb_mod_modfunc(int argc, VALUE *argv, VALUE module) id = rb_to_id(argv[i]); for (;;) { - fbody = search_method(m, id, &m); - if (fbody == 0) { - fbody = search_method(rb_cObject, id, &m); + me = search_method(m, id); + if (me == 0) { + me = search_method(rb_cObject, id); } - if (fbody == 0 || fbody->nd_body == 0) { + if (me == 0 || me->type == VM_METHOD_TYPE_UNDEF) { rb_print_undef(module, id, 0); } - if (nd_type(fbody->nd_body->nd_body) != NODE_ZSUPER) { - break; /* normal case: need not to follow 'super' link */ + if (me->type != VM_METHOD_TYPE_ZSUPER) { + break; /* normal case: need not to follow 'super' link */ } m = RCLASS_SUPER(m); if (!m) break; } - rb_add_method(rb_singleton_class(module), id, fbody->nd_body->nd_body, - NOEX_PUBLIC); + rb_add_method_me(rb_singleton_class(module), id, me, NOEX_PUBLIC); } return module; } @@ -1084,8 +1104,8 @@ rb_mod_modfunc(int argc, VALUE *argv, VALUE module) int rb_method_basic_definition_p(VALUE klass, ID id) { - NODE *node = rb_method_node(klass, id); - if (node && (node->nd_noex & NOEX_BASIC)) + const rb_method_entry_t *me = rb_method_entry(klass, id); + if (me && (me->flag & NOEX_BASIC)) return 1; return 0; } @@ -1174,8 +1194,5 @@ Init_eval_method(void) singleton_removed = rb_intern("singleton_method_removed"); undefined = rb_intern("method_undefined"); singleton_undefined = rb_intern("singleton_method_undefined"); - - notimplement_body = NEW_CFUNC(rb_f_notimplement, -1); - rb_gc_register_mark_object((VALUE)notimplement_body); } |