summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog27
-rw-r--r--class.c65
-rw-r--r--compile.c6
-rw-r--r--eval.c2
-rw-r--r--ext/objspace/objspace.c4
-rw-r--r--gc.c72
-rw-r--r--include/ruby/intern.h1
-rw-r--r--insns.def36
-rw-r--r--iseq.c14
-rw-r--r--method.h78
-rw-r--r--node.h47
-rw-r--r--proc.c206
-rw-r--r--vm.c37
-rw-r--r--vm_core.h39
-rw-r--r--vm_dump.c8
-rw-r--r--vm_eval.c248
-rw-r--r--vm_insnhelper.c236
-rw-r--r--vm_insnhelper.h6
-rw-r--r--vm_method.c535
19 files changed, 882 insertions, 785 deletions
diff --git a/ChangeLog b/ChangeLog
index cd156b0..e89536b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
diff --git a/class.c b/class.c
index 6413429..3c7b1f0 100644
--- a/class.c
+++ b/class.c
@@ -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 {\
diff --git a/compile.c b/compile.c
index 6198f07..c034ac8 100644
--- a/compile.c
+++ b/compile.c
@@ -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;
}
diff --git a/eval.c b/eval.c
index a877c2b..67d9873 100644
--- a/eval.c
+++ b/eval.c
@@ -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 d200e17..68c6086 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);
diff --git a/gc.c b/gc.c
index 87b6231..d7b1291 100644
--- a/gc.c
+++ b/gc.c
@@ -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 dfc3a35..09e71e9 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);
diff --git a/insns.def b/insns.def
index 7ce5b92..f9310be 100644
--- a/insns.def
+++ b/insns.def
@@ -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 {
diff --git a/iseq.c b/iseq.c
index 711712a..643e399 100644
--- a/iseq.c
+++ b/iseq.c
@@ -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 0000000..ff8ad91
--- /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 */
diff --git a/node.h b/node.h
index 58edbd4..8b77873 100644
--- a/node.h
+++ b/node.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 */
diff --git a/proc.c b/proc.c
index 9b7e3c6..691c45b 100644
--- a/proc.c
+++ b/proc.c
@@ -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);
diff --git a/vm.c b/vm.c
index c2d83d1..8b492fa 100644
--- a/vm.c
+++ b/vm.c
@@ -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();
}
diff --git a/vm_core.h b/vm_core.h
index 799ac52..9ff652e 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -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);
diff --git a/vm_dump.c b/vm_dump.c
index eb2a89f..d22c652 100644
--- a/vm_dump.c
+++ b/vm_dump.c
@@ -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 = "?";
diff --git a/vm_eval.c b/vm_eval.c
index 096c056..9b62327 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);
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index ac24054..0163db9 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 d927807..a96298c 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 292146d..e84d4cc 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);
}