diff -urpN yarv000c.orig/yarv/insns.def yarv000c/yarv/insns.def
--- yarv000c.orig/yarv/insns.def	2004-01-14 18:18:00.000000000 +0900
+++ yarv000c/yarv/insns.def	2004-01-21 15:31:27.850148800 +0900
@@ -828,4 +828,102 @@ opt_lt
   }
 }
 
+/**
+  @c optimize
+  @e send and return from this scope.
+  @j send and return from this scope.
+ */
+DEFINE_INSN
+tailsend
+(ID id, ulong num)
+(...)
+(VALUE val)
+{
+  VALUE recv;
+  NODE *mn;
+  int i;
 
+  recv = TOPN(num);
+  mn = rb_method_node(CLASS_OF(recv), id);
+  TOS2STACK();
+
+  switch(nd_type(mn)){
+  case NODE_CFUNC:{
+    /* call cfunc */
+    val = call_cfunc(mn->nd_cfnc, recv, mn->nd_argc, num,
+                     STACK_ADDR_FROM_TOP(num));
+    
+    /* pop stacks (recv + argc) */
+    POPN(1 + num);
+    END(val);
+    break;
+  }
+  case NODE_NEWLINE:{
+    struct frame_base *fb;
+    struct bs_object  *newbs;
+    VALUE  newbsobj;
+    /* BS method */
+    newbsobj = (VALUE)mn->nd_body;
+    GetBSVal(newbsobj, newbs);
+
+    if(GET_DFP()){
+      rb_bug("sorry unsupport with dfp");
+    }
+    fb = (struct frame_base*)(GET_LFP() + 1 + bs->local_size);
+    if(fb->magic != FRAME_MAGIC){
+      rb_bug("yarv frame bug!!: %d, %d", fb->magic, GET_SP_COUNT());
+    }
+
+    if (__builtin_expect((num <= bs->local_size), 1)) {
+      memcpy(GET_LFP(),
+             GET_SP() - (num + 1),
+             sizeof(VALUE) * (1 + num));
+      if (__builtin_expect((newbs->local_size != bs->local_size), 0)) {
+        struct frame_base *newfb =
+          (struct frame_base*)(GET_LFP() + 1 + newbs->local_size);
+        memmove(newfb, fb, sizeof(struct frame_base));
+        fb = newfb;
+      }
+    } else {
+      struct frame_base tmp = *fb;
+      memmove(GET_LFP(),
+              GET_SP() - (num + 1),
+              sizeof(VALUE) * (1 + num));
+      fb = (struct frame_base*)(GET_LFP() + 1 + newbs->local_size);
+      *fb = tmp;
+    }
+    SET_SP(GET_LFP() + 1 + num);
+
+    /* clear locals */
+    if(newbs->local_tbl){
+      for(i=0; i<newbs->local_size - num; i++){
+        PUSH(Qnil);
+      }
+    }
+
+    INC_SP(FRAME_BASE_WORD());
+    SET_PC(GET_SEQ(newbs));
+    SET_DFP(0);
+
+    bsobj = newbsobj;
+    bs    = newbs;
+    
+//    END_INSN();
+    goto first;
+    
+    
+    break;
+  }
+  default:
+    rb_bug("sorry, don't support this method type: %s", node_name(nd_type(mn)));
+  }
+  
+  /* printf("method: %s", node_name(nd_type(mn))); */
+  /*
+  debugp("send recv", recv);
+  for(i=0;i<num;i++){
+    debugp("send arg ", TOPN(num+1+i));
+  }
+  SEND(id, num);
+   */
+}
diff -urpN yarv000c.orig/yarv/yarvcore.c yarv000c/yarv/yarvcore.c
--- yarv000c.orig/yarv/yarvcore.c	2004-01-13 09:59:24.000000000 +0900
+++ yarv000c/yarv/yarvcore.c	2004-01-21 02:45:19.285161600 +0900
@@ -14,6 +14,7 @@
 
 #include "yarvcore.h"
 #include "version.h"
+#include "insns.h"
 
 VALUE mYARVCore;
 VALUE cBS;
@@ -107,6 +108,30 @@ static VALUE bs_alloc(VALUE klass){
   return obj;
 }
 
+static VALUE
+bs_optimize_tail_call(VALUE self){
+  struct bs_object *bsobj;
+  int i, len;
+  GetBSVal(self, bsobj);
+
+  for(i=0; i<bsobj->size; /* */){
+    int insn = bsobj->bcseq[i];
+    int len  = insn_len(insn);
+
+    if (insn == BIN(send)) {
+      int insn2 = bsobj->bcseq[i+len];
+      if (insn2 == BIN(end) ||
+	  (insn2 == BIN(jump) &&
+	   bsobj->bcseq[(i+len) + insn_len(insn2) + bsobj->bcseq[i+len+1]] == BIN(end))) {
+	bsobj->bcseq[i] = BIN(tailsend);
+      }
+    }
+
+    i += len;
+  }
+  return self;
+}
+
 #ifdef DISPATCH_DIRECT_THREADED_CODE
 static VALUE bs_translate_direct_threaded_code(VALUE self){
   struct bs_object *bsobj;
@@ -132,6 +157,7 @@ static VALUE bs_init(VALUE self, VALUE n
   bsobj->name = name;
   bs_compile(self, node);
 
+  bs_optimize_tail_call(self);
 #ifdef DISPATCH_DIRECT_THREADED_CODE
   bs_translate_direct_threaded_code(self);
 #endif
