[前][次][番号順一覧][スレッド一覧]

ruby-changes:12428

From: ko1 <ko1@a...>
Date: Thu, 16 Jul 2009 00:00:05 +0900 (JST)
Subject: [ruby-changes:12428] Ruby:r24128 (trunk): * method.h, vm_core.h: add rb_method_entry_t. Remove nodes around

ko1	2009-07-15 23:59:41 +0900 (Wed, 15 Jul 2009)

  New Revision: 24128

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=24128

  Log:
    * 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().

  Added files:
    trunk/method.h
  Modified files:
    trunk/ChangeLog
    trunk/class.c
    trunk/compile.c
    trunk/eval.c
    trunk/ext/objspace/objspace.c
    trunk/gc.c
    trunk/include/ruby/intern.h
    trunk/insns.def
    trunk/iseq.c
    trunk/node.h
    trunk/proc.c
    trunk/vm.c
    trunk/vm_core.h
    trunk/vm_dump.c
    trunk/vm_eval.c
    trunk/vm_insnhelper.c
    trunk/vm_insnhelper.h
    trunk/vm_method.c

Index: method.h
===================================================================
--- method.h	(revision 0)
+++ method.h	(revision 24128)
@@ -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 */
Index: include/ruby/intern.h
===================================================================
--- include/ruby/intern.h	(revision 24127)
+++ include/ruby/intern.h	(revision 24128)
@@ -275,7 +275,6 @@
 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);
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 24127)
+++ ChangeLog	(revision 24128)
@@ -1,3 +1,30 @@
+Wed Jul 15 23:46:55 2009  Koichi Sasada  <ko1@a...>
+
+	* 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@a...>
 
 	* dir.c (push_glob): fix GC problem.
Index: insns.def
===================================================================
--- insns.def	(revision 24127)
+++ insns.def	(revision 24128)
@@ -785,11 +785,11 @@
 	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 @@
 (...)
 (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 @@
     /* 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 @@
     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 @@
 (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 @@
 (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 {
Index: vm_core.h
===================================================================
--- vm_core.h	(revision 24127)
+++ vm_core.h	(revision 24128)
@@ -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 @@
 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 @@
     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 @@
     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 @@
     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 @@
 /* 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,7 +491,16 @@
     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)
 #define VM_CALL_ARGS_BLOCKARG_BIT  (0x01 << 2)
@@ -509,7 +509,6 @@
 #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 @@
 /* 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 @@
 #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 @@
 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);
 
Index: iseq.c
===================================================================
--- iseq.c	(revision 24127)
+++ iseq.c	(revision 24128)
@@ -107,6 +107,9 @@
 	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 @@
 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;
Index: compile.c
===================================================================
--- compile.c	(revision 24127)
+++ compile.c	(revision 24128)
@@ -1855,12 +1855,6 @@
 		}
 	    }
 	}
-
-	if (argc > 0) {
-	    if (mid == idSend || mid == id__send__ ) {
-		OPERAND_AT(iobj, 3) |= INT2FIX(VM_CALL_SEND_BIT);
-	    }
-	}
     }
     return COMPILE_OK;
 }
Index: vm_eval.c
===================================================================
--- vm_eval.c	(revision 24127)
+++ vm_eval.c	(revision 24128)
@@ -21,141 +21,153 @@
 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;
+    VALUE klass = me->klass;
+    const 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);
-
     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 @@
 }
 
 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 @@
 		 "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;
+	if (!ent->me) {
+	  return method_missing(recv, mid, argc, argv,
+				scope == CALL_VCALL ? NOEX_VCALL : 0);
+	}
+	me = ent->me;
+	klass = me->klass;
     }
-    else if ((method = rb_get_method_body(klass, id, &id)) != 0) {
-	noex = (int)method->nd_noex;
-	klass = method->nd_clss;
-	body = method->nd_body;
+    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 @@
     }
 
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
 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 @@
     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);
Index: proc.c
===================================================================
--- proc.c	(revision 24127)
+++ proc.c	(revision 24128)
@@ -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 @@
 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 @@
 	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 @@
 {
     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 @@
     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 @@
  * 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 @@
     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 @@
     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 @@
     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 @@
     struct METHOD *data;
 
     TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data);
-    return data->oclass;
+    return data->me->klass;
 }
 
 /*
@@ -1205,7 +1190,6 @@
 {
     ID id;
     VALUE body;
-    NODE *node;
     int noex = NOEX_PUBLIC;
 
     if (argc == 1) {
@@ -1239,7 +1223,7 @@
 			 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 @@
 	    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 @@
     }
     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 @@
 }
 
 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 @@
     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 @@
     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 @@
 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 @@
 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 @@
     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 @@
     }
     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 @@
     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);
Index: vm_method.c
===================================================================
--- vm_method.c	(revision 24127)
+++ vm_method.c	(revision 24128)
@@ -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 @@
 
 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 @@
     ent = cache;
     end = ent + CACHE_SIZE;
     while (ent < end) {
-	ent->mid = 0;
+	ent->me = ent->mid = 0;
 	ent++;
     }
 }
@@ -55,8 +51,8 @@
     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 @@
     end = ent + CACHE_SIZE;
     while (ent < end) {
 	if (ent->mid == id) {
-	    ent->mid = 0;
+	    ent->me = ent->mid = 0;
 	}
 	ent++;
     }
@@ -93,18 +89,44 @@
     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_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_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);
+    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);
     }
-    else {
-	body = 0;
-    }
 
-    {
-	/* check re-definition */
-	st_data_t data;
-	NODE *old_node;
+    mtbl = RCLASS_M_TBL(klass);
 
-	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));
-		}
-	    }
+    /* 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 (klass == rb_cObject && node && mid == idInitialize) {
-	    rb_warn("redefining Object#initialize may cause infinite loop");
-	}
 
-	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;
+    rb_method_entry_t *me = search_method(klass, id);
 
-    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;
-
     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 @@
     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);
 
-    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 @@
 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 (me->flag != noex) {
+	rb_vm_check_redefinition_opt_method(me);
+
+	if (klass == me->klass) {
+	    me->flag = noex;
 	}
-	if (klass == origin) {
-	    fbody->nd_body->nd_noex = 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 @@
     const char *name;
     ID attriv;
     VALUE aname;
-    int noex;
+    rb_method_flag_t noex;
 
     if (!ex) {
 	noex = NOEX_PUBLIC;
@@ -478,32 +486,32 @@
     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_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 @@
 
 #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 @@
 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 @@
 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 @@
 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;
     }
-    return Qfalse;
 }
 
 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;
+    }
+}
+
+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++;
+    orig_me->alias_count++;
+    me = rb_add_method(klass, name, orig_me->type, me_opts(orig_me), orig_me->flag);
+    me->original_id = def;
 
-    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);
-	    }
-	}
-    }
+    if (!ruby_running) return;
 
-    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;
-
     rb_clear_cache_by_id(name);
 
-    if (!ruby_running) return;
-
     if (singleton) {
 	rb_funcall(singleton, singleton_added, 1, ID2SYM(name));
     }
@@ -832,18 +865,6 @@
     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 @@
 {
     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 @@
 
 	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 @@
 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 @@
     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);
 }
 
Index: eval.c
===================================================================
--- eval.c	(revision 24127)
+++ eval.c	(revision 24128)
@@ -684,7 +684,7 @@
 {
     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)) {
Index: gc.c
===================================================================
--- gc.c	(revision 24127)
+++ gc.c	(revision 24128)
@@ -1435,12 +1435,6 @@
     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,7 +1484,65 @@
     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)
 {
     if (is_pointer_to_heap(&rb_objspace, (void *)obj)) {
@@ -1591,7 +1643,6 @@
 	    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 @@
 	  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 @@
 
 	  case NODE_ZARRAY:	/* - */
 	  case NODE_ZSUPER:
-	  case NODE_CFUNC:
 	  case NODE_VCALL:
 	  case NODE_GVAR:
 	  case NODE_LVAR:
@@ -1669,7 +1718,6 @@
 	  case NODE_TRUE:
 	  case NODE_FALSE:
 	  case NODE_ERRINFO:
-	  case NODE_ATTRSET:
 	  case NODE_BLOCK_ARG:
 	    break;
 	  case NODE_ALLOCA:
@@ -1698,7 +1746,7 @@
       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 @@
       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));
 	}
Index: class.c
===================================================================
--- class.c	(revision 24127)
+++ class.c	(revision 24128)
@@ -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,29 +124,20 @@
 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);
+    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;
     }
-    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));
-    }
     return ST_CONTINUE;
 }
 
@@ -674,7 +666,7 @@
 }
 
 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 @@
     }
 
     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 @@
 }
 
 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 {\
Index: ext/objspace/objspace.c
===================================================================
--- ext/objspace/objspace.c	(revision 24127)
+++ ext/objspace/objspace.c	(revision 24128)
@@ -350,9 +350,6 @@
 	    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_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);
Index: vm.c
===================================================================
--- vm.c	(revision 24127)
+++ vm.c	(revision 24128)
@@ -575,7 +575,7 @@
 
 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 @@
 	    }
 	}
 	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 @@
 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_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 @@
 			     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 @@
 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 @@
     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();
 }
Index: vm_dump.c
===================================================================
--- vm_dump.c	(revision 24127)
+++ vm_dump.c	(revision 24128)
@@ -112,9 +112,9 @@
 	    }
 	}
     }
-    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 @@
 
     if (iseq == 0) {
 	if (RUBYVM_CFUNC_FRAME_P(cfp)) {
-	    name = rb_id2name(cfp->method_id);
+	    name = rb_id2name(cfp->me->original_id);
 	}
 	else {
 	    name = "?";
Index: vm_insnhelper.c
===================================================================
--- vm_insnhelper.c	(revision 24127)
+++ vm_insnhelper.c	(revision 24128)
@@ -350,21 +350,24 @@
 	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_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 @@
 }
 
 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 @@
 
 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 @@
 }
 
 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 @@
 }
 
 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 @@
 	    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 @@
 		}
 		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 @@
 		    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 @@
     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 @@
  * @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 @@
 
 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 @@
         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 @@
 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 @@
 #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 @@
 	    }
 	}
 
-	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 @@
 }
 
 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 @@
 	    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;
 	    }
 	}
Index: vm_insnhelper.h
===================================================================
--- vm_insnhelper.h	(revision 24127)
+++ vm_insnhelper.h	(revision 24128)
@@ -159,8 +159,8 @@
   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 @@
 
 #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 */
Index: node.h
===================================================================
--- node.h	(revision 24127)
+++ node.h	(revision 24128)
@@ -20,12 +20,6 @@
 #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 @@
 #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 @@
 #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 @@
 #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 @@
 #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_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 */

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]