diff -ru ruby.snapshot/ChangeLog ruby/ChangeLog
--- ruby.snapshot/ChangeLog	2005-09-01 02:39:00.000000000 -0700
+++ ruby/ChangeLog	2009-03-01 03:35:51.000000000 -0800
@@ -1,14 +1,221 @@
-Thu Sep  1 17:11:25 2005  Yukihiro Matsumoto  <matz@ruby-lang.org>
+Wed Feb 28 12:01:19 2009  Brent Roman  <brent@mbari.org>
+        
+        * rubysig.c:  added support for __anyPowerPC__
+        
+        * version.h:  bumped date, , MBARI version 7 --> 8B
+
+Wed Feb 25 12:01:19 2009  Brent Roman  <brent@mbari.org>
+
+        * gc.c:  default GC.limit=2e6*sizeof(VALUE)
+        
+        * eval.c:  added RB_GC_GUARDs to eval_slit() & more volatile tweaks
+        
+        * re.c:  removed unneeded volatile qualifier & copy in rb_regcomp()
+        
+Tue Feb 24 00:01:19 2009  Brent Roman  <brent@mbari.org>
+
+        * signal.c:  removed CHECK_INTS after kill
+        
+        * test/ruby/suicide.rb:  add tiny delay to let signal propogate
+        
+        * gc.c:  save regs properly on main stack before marking it!
+        
+        * eval.c:  numerous corrections in use of volatile variables w/setjmp()
+        
+        * version.h:  bumped date
+
+Fri Feb 13 00:01:19 2009  Brent Roman  <brent@mbari.org>
+
+        * signal.c:  CHECK_INTS after kill in case of suicide
+        
+        * version.h:  bumped date
+
+Tue Feb 10 00:01:19 2009  Brent Roman  <brent@mbari.org>
+
+        * gc.c:  don't redundantly mark stack before base of current thread
+        
+        * parse.y:  Urabe Shyouhei backported support for 1.9 style hashes
+        
+        * version.h:  bumped date
+
+Mon Feb 09 00:01:19 2009  Brent Roman  <brent@mbari.org>
+
+        * rubysig.h:  default values for STACK_WIPE_SITES if x86_64
+                      cast builtin_alloca result to (VALUE *)
+        
+        * gc.c:  don't use builtin-frame-address at all
+        
+        * version.h:  bumped date
+
+Sun Feb 08 00:01:19 2009  Brent Roman  <brent@mbari.org>
+
+        * rubysig.h:  changed default values for STACK_WIPE_SITES
+        
+        * gc.c:  don't trust config's USE_BUILTIN_FRAME_ADDRESS
+        
+        * version.h:  bumped date
+
+
+Thu Jan 23 00:01:19 2009  Brent Roman  <brent@mbari.org>
+
+        * rubysig.h:  remapped wipe methods to avoid values > 9
+                      added cases for __ppc64__ and __x86_64__
+        
+        * missing/alloca.c:  made 64-bit clean
+        
+        * version.h:  bumped date
+        
+        
+Sun Jan 18 20:15:36 2009  Brent Roman  <brent@mbari.org>
+
+        * rubysig.h:  added support for STACK_WIPE_METHOD==5 (x86 asm)
+
+        * gc.c:       allow another STACK_WIPE_METHOD
+
+        * version.h:  bumped date
+
+
+Sat Jan 17 20:15:36 2009  Brent Roman  <brent@mbari.org>
+
+        * gc.c:     use separate gc stack so it never need be wiped
+
+        * version.h:  bumped date
+
+
+Fri Jan 16 20:15:36 2009  Brent Roman  <brent@mbari.org>
+
+        * gc.c:     added GC_STACK_PAD, renamed stack_gc_limit->gc_stack_limit
+                    optionally wipe the entire GC stack after each gc pass
+        
+        * rubysig.h:  default STACK_WIPE_SITES changed to 0x4770
+        
+        * version.h:  bumped date
+
+
+Wed Jan 14 20:15:36 2009  Brent Roman  <brent@mbari.org>
+
+        * eval.c:     declare wipe_after with gnu always_inline attribute
+        
+        * rubysig.h:  use alloca(0) to get sp for all CPU except PowerPC
+                      (less likely to trash stack when clearing it)
+        
+        * version.h:  bumped date
+
+
+Sun Jan 13 20:15:36 2009  Brent Roman  <brent@mbari.org>
+
+        * rubysig.h:  moved #defs to configure alloca here from gc.c
+                      added missing # to #else
+        
+        * gc.c: removed #defs to configurure alloca
+                set_stack_size must handle signed rlim_t for Darwin & BSD Unix
+                
+        * version.h:  bumped date
+
+
+Sun Jan 11 20:15:36 2009  Brent Roman  <brent@mbari.org>
+
+        * rubysig.h:  added support for multiple STACK_WIPE_METHODs
+                      added __stack_depth()
+                      added 2nd param to stack_past()
+                      __sp() returns stack pointer in an efficent, portable way                     
+        
+        * gc.c: STACK_END uses __sp()
+                STACK_UPPER now takes only two parameters
+                added rb_gc_wipe_stack()               
+                rb_mark_tbl() and mark_hash() implemented as #define macros
+                added STACK_END parameters to __stack_past() invocations
+                exploited missed opportunities for tail recursion in markchilren
+                
+        * version.h:  bumped date
+
+
+Thu Jan  8 20:15:36 2009  Brent Roman  <brent@mbari.org>
+
+        * rubysig.h:  added ARM and PPC asm support for getting Stack Pointer
+                      fall back to more portable means if other CPU or not GNUC
+                      added STACK_WIPE_SITES cofiguration options
+                      when available, use gcc asm to optimize wipe_stack
+                      removed rb_gc_malloc_increase & limit
+                      repaired broken pseudo preemptive thread switching
+                      replaced buggy __stack_grown* with __stack_past* macros
+        
+        * Makefile.in:  added dependency on rubysig.h to version.h     
+        
+        * eval.c:  added wipeAfter and STACK_WIPE_SITES cofiguration options
+        
+        * gc.c: added STACK_WIPE_SITES cofiguration options
+                added GC.exorcise method       
+                optimized is_heap_pointer()
+        
+        * version.h:  include STACK_WIPE_SITES options in MBARI release string                
+        
+
+Fri Dec 14 16:11:36 2008  Brent Roman  <brent@mbari.org>
+
+     * eval.c:  Continuation#thread calls cc_purge()
+
+     * gc.c:  ruby_xrealloc() updates malloc_increase and 
+              garbage collects when it exceeds malloc_limit
+              got rid of obsolete "volatile" workarounds for gcc 2.7.x
+
+              
+Fri Nov 27 16:11:36 2008  Brent Roman  <brent@mbari.org>
+
+     * eval.c:  added Continuation.thread method
+                rb_thread_check frees the continuation's stack
+                if it refers to a dead thread
+                clear stack on thread switches
+                   
+                   
+Fri Dec 14 21:11:36 2007  Brent Roman  <brent@mbari.org>
+
+        * eval.c:  rb_thread_check compares dmark rather than dfree
+                   to prevent adding Continuations to ThreadGroups
+
+Sat Dec  8 00:26:32 2007  Brent Roman  <brent@mbari.org>
+
+        * eval.c:  Hide parent's frames when creating a new thread
+          Do not bother clearing stklen when REALLOC'ing current stack
+          Added cc_mark for GC marking Continuations to prevent
+          BLOCKs in use by those continuations from being prematurely
+          freed when their parent thread dies
+          inlined rb_thread_dead()
+
+
+Sun Nov 11 22:44:50 2007  Brent Roman  <brent@mbari.org>
+
+        * gc.c:  added limit=, limit and increase methods
+
+
+Sat Feb 10 22:44:50 2006  Brent Roman  <brent@mbari.org>
+
+	* eval.c: added method/proc_file_name/line
+        don't schedule new thread if Thread.critical
+        
+        * extmk.rb:  don't build in CVS subdirs
+        
+        * readline.c:  use ruby's IO classes for keyboard input
+        
+        * addrinfo.h:  compatibility with gcc >3.2
+        
+        * rubysig.h:  defer traps if Thread.critical
+        
+        * signal.c:   added trap for SIGTERM
+        
 
-	* eval.c (rb_call0): wrong condition for $SAFE restoration.
+Thu Sep  1 17:11:25 2005  Yukihiro Matsumoto  <matz@ruby-lang.org>
+     * eval.c (rb_call0): wrong condition for $SAFE restoration.
 
 Wed Aug 17 00:05:46 2005  Yukihiro Matsumoto  <matz@ruby-lang.org>
 
-	* eval.c (rb_add_method): preserve safe level in the environment
-	  where a method is defined .
+     * eval.c (rb_add_method): preserve safe level in the environment
+       where a method is defined .
+
+     * eval.c (rb_call0): restore preserved safe level in the method
+       execution. 
+
 
-	* eval.c (rb_call0): restore preserved safe level in the method
-	  execution. 
 
 Fri Apr 16 13:48:29 2004  Akinori MUSHA  <knu@iDaemons.org>
 
diff -ru ruby.snapshot/configure.in ruby/configure.in
--- ruby.snapshot/configure.in	2003-02-23 03:22:29.000000000 -0800
+++ ruby/configure.in	2009-02-01 22:10:29.000000000 -0800
@@ -47,9 +47,9 @@
 AC_SUBST(GNU_LD)])
 
 rb_version=`grep RUBY_VERSION $srcdir/version.h`
-MAJOR=`expr "$rb_version" : '#define RUBY_VERSION "\([0-9][0-9]*\)\.[0-9][0-9]*\.[0-9][0-9]*"'`
-MINOR=`expr "$rb_version" : '#define RUBY_VERSION "[0-9][0-9]*\.\([0-9][0-9]*\)\.[0-9][0-9]*"'`
-TEENY=`expr "$rb_version" : '#define RUBY_VERSION "[0-9][0-9]*\.[0-9][0-9]*\.\([0-9][0-9]*\)"'`
+MAJOR=`expr "$rb_version" : '#define RUBY_VERSION "\([0-9][0-9]*\)\.[0-9][0-9]*\.[0-9][0-9]*.*"'`
+MINOR=`expr "$rb_version" : '#define RUBY_VERSION "[0-9][0-9]*\.\([0-9][0-9]*\)\.[0-9][0-9]*.*"'`
+TEENY=`expr "$rb_version" : '#define RUBY_VERSION "[0-9][0-9]*\.[0-9][0-9]*\.\([0-9][0-9]*\).*"'`
 AC_SUBST(MAJOR)
 AC_SUBST(MINOR)
 AC_SUBST(TEENY)
@@ -519,6 +519,31 @@
   AC_DEFINE(NEED_IO_FLUSH_BEFORE_SEEK, 1)
 fi
 
+case "$target_cpu" in
+arm*|m68*|i?86|ia64|sparc*|alpha*) rb_cv_stack_grow_dir=-1;;
+hppa*) rb_cv_stack_grow_dir=+1;;
+esac
+AC_CACHE_CHECK(stack growing direction, rb_cv_stack_grow_dir,
+  [AC_TRY_RUN([
+/* recurse to get rid of inlining */
+static int
+stack_growup_p(addr, n)
+    volatile int *addr, n;
+{
+    volatile int end;
+    if (n > 0)
+	return *addr = stack_growup_p(addr, n - 1);
+    else
+	return (&end > addr);
+}
+int main()
+{
+    int x;
+    return stack_growup_p(&x, 10);
+}
+], rb_cv_stack_grow_dir=-1, rb_cv_stack_grow_dir=+1, rb_cv_stack_grow_dir=0)])
+AC_DEFINE_UNQUOTED(STACK_GROW_DIRECTION, $rb_cv_stack_grow_dir)
+
 dnl default value for $KANJI
 DEFAULT_KCODE="KCODE_NONE"
 
diff -ru ruby.snapshot/eval.c ruby/eval.c
--- ruby.snapshot/eval.c	2005-09-20 09:49:26.000000000 -0700
+++ ruby/eval.c	2009-03-01 13:19:02.000000000 -0800
@@ -2,8 +2,8 @@
 
   eval.c -
 
-  $Author: matz $
-  $Date: 2005/09/20 16:49:26 $
+  $Author: brent $
+  $Date: 2009/03/01 21:19:02 $
   created at: Thu Jun 10 14:22:17 JST 1993
 
   Copyright (C) 1993-2001 Yukihiro Matsumoto
@@ -29,12 +29,14 @@
 
 /* Make alloca work the best possible way.  */
 #ifdef __GNUC__
+#define noinline  __attribute__ ((noinline))
 # ifndef atarist
 #  ifndef alloca
 #   define alloca __builtin_alloca
 #  endif
 # endif /* atarist */
 #else
+#define noinline
 # ifdef HAVE_ALLOCA_H
 #  include <alloca.h>
 # else
@@ -101,12 +103,9 @@
 #include <sys/select.h>
 #endif
 
-#ifdef HAVE_SYS_RESOURCE_H
-#include <sys/resource.h>
-#endif
-
 #include <sys/stat.h>
 
+
 VALUE rb_cProc;
 static VALUE rb_cBinding;
 static VALUE proc_call _((VALUE,VALUE));
@@ -786,7 +785,26 @@
 #define PROT_FUNC   -1
 #define PROT_THREAD -2
 
-#define EXEC_TAG()    (FLUSH_REGISTER_WINDOWS, setjmp(prot_tag->buf))
+#if STACK_WIPE_SITES & 0x42
+#ifdef __GNUC__
+static inline int wipeAfter(int) __attribute__((always_inline));
+#endif
+static inline int wipeAfter(int status)
+{
+  rb_gc_wipe_stack();
+  return status;
+}
+#else
+#define wipeAfter(status) status
+#endif
+#if STACK_WIPE_SITES & 2
+#define wipeAfterTag(status) wipeAfter(status)
+#else
+#define wipeAfterTag(status) status
+#endif
+
+#define EXEC_TAG_0()  (FLUSH_REGISTER_WINDOWS, setjmp(prot_tag->buf))
+#define EXEC_TAG()    wipeAfterTag(EXEC_TAG_0())
 
 #define JUMP_TAG(st) {			\
     ruby_frame = prot_tag->frame;	\
@@ -840,9 +858,9 @@
     ruby_scope = _scope;		\
     scope_vmode = SCOPE_PUBLIC;
 
-typedef struct thread * rb_thread_t;
-static rb_thread_t curr_thread = 0;
-static rb_thread_t main_thread;
+rb_thread_t rb_main_thread, rb_curr_thread = 0;
+#define main_thread rb_main_thread
+#define curr_thread rb_curr_thread
 static void scope_dup _((struct SCOPE *));
 
 #define POP_SCOPE() 			\
@@ -863,12 +881,18 @@
 }
 
 static VALUE rb_eval _((VALUE,NODE*));
-static VALUE eval _((VALUE,VALUE,VALUE,char*,int));
+static VALUE eval _((VALUE,VALUE,volatile VALUE,char* volatile,int));
 static NODE *compile _((VALUE, char*, int));
 
-static VALUE rb_yield_0 _((VALUE, VALUE, VALUE, int));
+#if STACK_WIPE_SITES & 0x20
+#define wipeBeforeYield()  rb_gc_wipe_stack()
+#else
+#define wipeBeforeYield()  (void)0
+#endif
+
+static VALUE rb_yield_0 _((volatile VALUE, volatile VALUE, VALUE, int));
 static VALUE rb_call _((VALUE,VALUE,ID,int,VALUE*,int));
-static VALUE module_setup _((VALUE,NODE*));
+static VALUE module_setup _((VALUE,NODE *));
 
 static VALUE massign _((VALUE,NODE*,VALUE,int));
 static void assign _((VALUE,NODE*,VALUE,int));
@@ -920,12 +944,7 @@
     if (NIL_P(ruby_errinfo)) return;
 
     PUSH_TAG(PROT_NONE);
-    if (EXEC_TAG() == 0) {
-	errat = get_backtrace(ruby_errinfo);
-    }
-    else {
-	errat = Qnil;
-    }
+    errat = EXEC_TAG() ? Qnil : get_backtrace(ruby_errinfo);
     POP_TAG();
     if (NIL_P(errat)) {
 	if (ruby_sourcefile)
@@ -1075,7 +1094,7 @@
 }
 
 static VALUE
-eval_node(self, node)
+eval_tree(self, node)
     VALUE self;
     NODE *node;
 {
@@ -1086,8 +1105,7 @@
 	rb_eval(self, beg_tree);
     }
 
-    if (!node) return Qnil;
-    return rb_eval(self, node);
+    return node ? rb_eval(self, node) : Qnil;
 }
 
 int ruby_in_eval;
@@ -1193,10 +1211,11 @@
 }
 
 void
-ruby_stop(ex)
-    int ex;
+ruby_stop(exArg)
+    int exArg;
 {
     int state;
+    volatile int ex = exArg;
 
     PUSH_TAG(PROT_NONE);
     PUSH_ITER(ITER_NOT);
@@ -1232,7 +1251,7 @@
     /* default visibility is private at toplevel */
     SCOPE_SET(SCOPE_PRIVATE);
     if ((state = EXEC_TAG()) == 0) {
-	eval_node(ruby_top_self, ruby_eval_tree);
+	eval_tree(ruby_top_self, ruby_eval_tree);
     }
     POP_ITER();
     POP_TAG();
@@ -1275,13 +1294,14 @@
 }
 
 VALUE
-rb_eval_string_protect(str, state)
+rb_eval_string_protect(str, stateArg)
     const char *str;
-    int *state;
+    int *stateArg;
 {
-    VALUE result;		/* OK */
+    VALUE result;
     int status;
 
+    int *volatile state = stateArg;
     PUSH_TAG(PROT_NONE);
     if ((status = EXEC_TAG()) == 0) {
 	result = rb_eval_string(str);
@@ -1290,11 +1310,7 @@
     if (state) {
 	*state = status;
     }
-    if (status != 0) {
-	return Qnil;
-    }
-
-    return result;
+    return status ? Qnil : result;
 }
 
 VALUE
@@ -1367,8 +1383,8 @@
     VALUE cmd, arg;
 {
     int state;
-    VALUE val;			/* OK */
-    struct SCOPE *saved_scope;
+    VALUE val;
+    struct SCOPE * volatile saved_scope;
     volatile int safe = ruby_safe_level;
 
     if (TYPE(cmd) != T_STRING) {
@@ -1410,9 +1426,9 @@
 static VALUE
 superclass(self, node)
     VALUE self;
-    NODE *node;
+    NODE *volatile node;
 {
-    VALUE val;			/* OK */
+    VALUE val;
     int state;
 
     PUSH_TAG(PROT_NONE);
@@ -1446,7 +1462,7 @@
 
 #define ruby_cbase (RNODE(ruby_frame->cbase)->nd_clss)
 
-static VALUE
+static VALUE noinline
 ev_const_defined(cref, id, self)
     NODE *cref;
     ID id;
@@ -1466,7 +1482,7 @@
     return rb_const_defined(cref->nd_clss, id);
 }
 
-static VALUE
+static VALUE noinline
 ev_const_get(cref, id, self)
     NODE *cref;
     ID id;
@@ -1759,10 +1775,10 @@
 static char*
 is_defined(self, node, buf)
     VALUE self;
-    NODE *node;			/* OK */
+    NODE *node;
     char *buf;
 {
-    VALUE val;			/* OK */
+    VALUE val;
     int state;
 
   again:
@@ -1990,8 +2006,8 @@
 {
     int state;
     struct FRAME *prev;
-    char *file_save = ruby_sourcefile;
-    int line_save = ruby_sourceline;
+    char * volatile file_save = ruby_sourcefile;
+    volatile int line_save = ruby_sourceline;
     VALUE srcfile;
 
     if (!trace_func) return;
@@ -2035,807 +2051,1217 @@
     if (state) JUMP_TAG(state);
 }
 
+
 static void return_check _((void));
 #define return_value(v) prot_tag->retval = (v)
 
-static VALUE
-rb_eval(self, n)
-    VALUE self;
-    NODE *n;
-{
-    NODE * volatile node = n;
-    int state;
-    volatile VALUE result = Qnil;
-
-#define RETURN(v) { result = (v); goto finish; }
-
-  again:
-    if (!node) RETURN(Qnil);
+/*
+  functions factored out of rb_eval() to reduce its stack frame size
+*/
+#define eval_node_0(n,retType, self, node)  \
+static noinline retType TOKEN_PASTE(eval_,n) _((self, node));\
+static retType TOKEN_PASTE(eval_,n)(self, node)
+
+#define eval_node(n,retType) \
+  eval_node_0(n,retType, VALUE self, NODE *node)
+#define eval_node_volatile(n,retType) \
+  eval_node_0(n,retType, volatile VALUE self, NODE * volatile node)
+
+eval_node(match2, VALUE)
+{
+    VALUE l = rb_eval(self,node->nd_recv);
+    VALUE r = rb_eval(self,node->nd_value);
+    return rb_reg_match(l, r);
+}
+
+eval_node(match3, VALUE)
+{
+  VALUE r = rb_eval(self,node->nd_recv);
+  VALUE l = rb_eval(self,node->nd_value);
+  return TYPE(l) == T_STRING ? rb_reg_match(r, l) : rb_funcall(l, match, 1, r);
+}
+
+
+eval_node_volatile(opt_n, void)
+{
+  int state;
+  PUSH_TAG(PROT_NONE);
+  switch (state = EXEC_TAG()) {
+    case TAG_NEXT:
+      state = 0;
+    case 0:
+      while (!NIL_P(rb_gets())) {
+	opt_n_redo:
+	  rb_eval(self, node->nd_body);
+      }
+      break;
+
+    case TAG_REDO:
+      state = 0;
+      goto opt_n_redo;
+
+    case TAG_BREAK:
+      state = 0;
+    default:
+      break;
+  }
+  POP_TAG();
+  if (state) JUMP_TAG(state);
+}
+
+
+eval_node_volatile(while, void)
+{
+  int state;
+  PUSH_TAG(PROT_NONE);
+  switch (state = EXEC_TAG()) {
+    case 0:
+      ruby_sourceline = nd_line(node);
+      if (!(node->nd_state) || RTEST(rb_eval(self, node->nd_cond))) {
+        do {
+	  while_redo:
+#if STACK_WIPE_SITES & 0x10
+            rb_gc_wipe_stack();
+#endif
+	    rb_eval(self, node->nd_body);
+	  while_next:
+	    ;
+        } while (RTEST(rb_eval(self, node->nd_cond)));
+      }
+      break;
+
+    case TAG_REDO:
+      state = 0;
+      goto while_redo;
+    case TAG_NEXT:
+      state = 0;
+      goto while_next;
+    case TAG_BREAK:
+      state = 0;
+      break;
+  }
+  POP_TAG();
+  if (state) JUMP_TAG(state);
+}
+
+
+eval_node_volatile(until, void)
+{
+  int state;
+  PUSH_TAG(PROT_NONE);
+  switch (state = EXEC_TAG()) {
+    case 0:
+      ruby_sourceline = nd_line(node);
+      if (!(node->nd_state) || !RTEST(rb_eval(self, node->nd_cond))) {
+        do {
+	  until_redo:
+#if STACK_WIPE_SITES & 0x10
+            rb_gc_wipe_stack();
+#endif
+	    rb_eval(self, node->nd_body);
+	  until_next:
+	    ;
+        } while (!RTEST(rb_eval(self, node->nd_cond)));
+      }
+      break;
+
+    case TAG_REDO:
+      state = 0;
+      goto until_redo;
+    case TAG_NEXT:
+      state = 0;
+      goto until_next;
+    case TAG_BREAK:
+      state = 0;
+      break;
+  }
+  POP_TAG();
+  if (state) JUMP_TAG(state);
+}
+
+
+eval_node(when, NODE*)
+{
+  do {
+      NODE *tag = node->nd_head;
+      while (tag) {
+	  if (trace_func) {
+	      call_trace_func("line", tag->nd_file, nd_line(tag), self,
+			      ruby_frame->last_func,
+			      ruby_frame->last_class);	
+	  }
+	  ruby_sourcefile = tag->nd_file;
+	  ruby_sourceline = nd_line(tag);
+	  if (nd_type(tag->nd_head) == NODE_WHEN) {
+	      VALUE v = rb_eval(self, tag->nd_head->nd_head);
+	      int i;
+
+	      if (TYPE(v) != T_ARRAY) v = rb_Array(v);
+	      for (i=0; i<RARRAY(v)->len; i++) {
+		  if (RTEST(RARRAY(v)->ptr[i])) return node->nd_body;
+	      }
+	      tag = tag->nd_next;
+	      continue;
+	  }
+	  if (RTEST(rb_eval(self, tag->nd_head))) return node->nd_body;
+	  tag = tag->nd_next;
+      }
+  } while ((node = node->nd_next) && nd_type(node) == NODE_WHEN);
+  return node;
+}
+
+
+eval_node(case, NODE*)
+{
+  VALUE val = rb_eval(self, node->nd_head);
+  node = node->nd_body;
+  while (node) {
+      NODE *tag;
+
+      if (nd_type(node) != NODE_WHEN) break;
+      tag = node->nd_head;
+      while (tag) {
+	  if (trace_func) {
+	      call_trace_func("line", tag->nd_file, nd_line(tag), self,
+			      ruby_frame->last_func,
+			      ruby_frame->last_class);	
+	  }
+	  ruby_sourcefile = tag->nd_file;
+	  ruby_sourceline = nd_line(tag);
+	  if (nd_type(tag->nd_head) == NODE_WHEN) {
+	      VALUE v = rb_eval(self, tag->nd_head->nd_head);
+	      int i;
+
+	      if (TYPE(v) != T_ARRAY) v = rb_Array(v);
+	      for (i=0; i<RARRAY(v)->len; i++) {
+		  if (RTEST(rb_funcall2(RARRAY(v)->ptr[i], eqq, 1, &val)))
+		      return  node->nd_body;
+	      }
+	      tag = tag->nd_next;
+	      continue;
+	  }
+	  if (RTEST(rb_funcall2(rb_eval(self, tag->nd_head), eqq, 1, &val)))
+	      return node->nd_body;
+	  tag = tag->nd_next;
+      }
+      node = node->nd_next;
+  }
+  return node;
+}
+
+
+eval_node_volatile(iter, VALUE)
+{
+  int state;
+  VALUE result;
+  
+  iter_retry:
+    PUSH_TAG(PROT_FUNC);
+    PUSH_BLOCK(node->nd_var, node->nd_body);
 
-    switch (nd_type(node)) {
-      case NODE_BLOCK:
-	while (node->nd_next) {
-	    rb_eval(self, node->nd_head);
-	    node = node->nd_next;
+    state = EXEC_TAG();
+    if (state == 0) {
+	PUSH_ITER(ITER_PRE);
+	if (nd_type(node) == NODE_ITER) {
+	    result = rb_eval(self, node->nd_iter);
 	}
-	node = node->nd_head;
-	goto again;
+	else 
+        {
+	    char *file = ruby_sourcefile;
+	    int line = ruby_sourceline;
 
-      case NODE_POSTEXE:
-	rb_f_END();
-	nd_set_type(node, NODE_NIL); /* exec just once */
-	result = Qnil;
+	    _block.flags &= ~BLOCK_D_SCOPE;
+	    BEGIN_CALLARGS;
+	    result = rb_eval(self, node->nd_iter);
+	    END_CALLARGS;
+	    ruby_sourcefile = file;
+	    ruby_sourceline = line;
+	    result = rb_call(CLASS_OF(result),result,each,0,0,0);
+	}
+	POP_ITER();
+    }
+    else if (_block.tag->dst == state) {
+	state &= TAG_MASK;
+	if (state == TAG_RETURN) {
+	    result = prot_tag->retval;
+	}
+    }
+    POP_BLOCK();
+    POP_TAG();
+    switch (state) {
+      case 0:
 	break;
 
-	/* begin .. end without clauses */
-      case NODE_BEGIN:
-	node = node->nd_body;
-	goto again;
+      case TAG_RETRY:
+	goto iter_retry;
 
-	/* nodes for speed-up(default match) */
-      case NODE_MATCH:
-	result = rb_reg_match2(node->nd_head->nd_lit);
+      case TAG_BREAK:
+	result = Qnil;
 	break;
+      case TAG_RETURN:
+	return_value(result);
+	/* fall through */
+      default:
+	JUMP_TAG(state);
+    }
+  return result;
+}
 
-	/* nodes for speed-up(literal match) */
-      case NODE_MATCH2:
-	result = rb_reg_match(rb_eval(self,node->nd_recv),
-			      rb_eval(self,node->nd_value));
-	break;
 
-	/* nodes for speed-up(literal match) */
-      case NODE_MATCH3:
-        {
-	    VALUE r = rb_eval(self,node->nd_recv);
-	    VALUE l = rb_eval(self,node->nd_value);
-	    if (TYPE(l) == T_STRING) {
-		result = rb_reg_match(r, l);
-	    }
-	    else {
-		result = rb_funcall(l, match, 1, r);
-	    }
-	}
-	break;
+eval_node_volatile(rescue, VALUE)
+{
+  int state;
+  VALUE result;
+  
+  retry_entry:
+  {
+      volatile VALUE e_info = ruby_errinfo;
+
+      PUSH_TAG(PROT_NONE);
+      if ((state = EXEC_TAG()) == 0) {
+	  result = rb_eval(self, node->nd_head);
+      }
+      POP_TAG();
+      if (state == TAG_RAISE) {
+	  NODE * volatile resq = node->nd_resq;
+
+	  ruby_sourceline = nd_line(node);
+	  while (resq) {
+	      if (handle_rescue(self, resq)) {
+		  PUSH_TAG(PROT_NONE);
+		  if ((state = EXEC_TAG()) == 0) {
+		      result = rb_eval(self, resq->nd_body);
+		  }
+		  POP_TAG();
+		  if (state == TAG_RETRY) {
+		      state = 0;
+		      ruby_errinfo = Qnil;
+		      goto retry_entry;
+		  }
+		  if (state != TAG_RAISE) {
+		      ruby_errinfo = e_info;
+		  }
+		  break;
+	      }
+	      resq = resq->nd_head; /* next rescue */
+	  }
+      }
+      else if (node->nd_else) { /* else clause given */
+	  if (!state) {	/* no exception raised */
+	      result = rb_eval(self, node->nd_else);
+	  }
+      }
+      if (state) JUMP_TAG(state);
+  }
+  return result;
+}
+
+
+eval_node_volatile(ensure, VALUE)
+{
+  int state;
+  VALUE result;
+
+  PUSH_TAG(PROT_NONE);
+  if ((state = EXEC_TAG()) == 0) {
+      result = rb_eval(self, node->nd_head);
+  }
+  POP_TAG();
+  if (node->nd_ensr) {
+      VALUE retval = prot_tag->retval; /* save retval */
+      VALUE errinfo = ruby_errinfo;
+
+      rb_eval(self, node->nd_ensr);
+      return_value(retval);
+      ruby_errinfo = errinfo;
+  }
+  if (state) JUMP_TAG(state);
+  return result;
+}
 
-	/* node for speed-up(top-level loop for -n/-p) */
-      case NODE_OPT_N:
-	PUSH_TAG(PROT_NONE);
-	switch (state = EXEC_TAG()) {
-	  case 0:
-	  opt_n_next:
-	    while (!NIL_P(rb_gets())) {
-	      opt_n_redo:
-		rb_eval(self, node->nd_body);
-	    }
-	    break;
 
-	  case TAG_REDO:
-	    state = 0;
-	    goto opt_n_redo;
-	  case TAG_NEXT:
-	    state = 0;
-	    goto opt_n_next;
-	  case TAG_BREAK:
-	    state = 0;
-	  default:
-	    break;
-	}
-	POP_TAG();
-	if (state) JUMP_TAG(state);
-	RETURN(Qnil);
+eval_node(call, VALUE)
+{
+    int argc; VALUE *argv; /* used in SETUP_ARGS */
+    VALUE recv;
 
-      case NODE_SELF:
-	RETURN(self);
+    TMP_PROTECT;
 
-      case NODE_NIL:
-	RETURN(Qnil);
+    BEGIN_CALLARGS;
+    recv = rb_eval(self, node->nd_recv);
+    SETUP_ARGS(node->nd_args);
+    END_CALLARGS;
 
-      case NODE_TRUE:
-	RETURN(Qtrue);
+    return rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,0);
+}
 
-      case NODE_FALSE:
-	RETURN(Qfalse);
 
-      case NODE_IF:
-	ruby_sourceline = nd_line(node);
-	if (RTEST(rb_eval(self, node->nd_cond))) {
-	    node = node->nd_body;
-	}
-	else {
-	    node = node->nd_else;
-	}
-	goto again;
+eval_node(fcall, VALUE)
+{
+    int argc; VALUE *argv; /* used in SETUP_ARGS */
+    
+    TMP_PROTECT;
 
-      case NODE_WHEN:
-	while (node) {
-	    NODE *tag;
+    BEGIN_CALLARGS;
+    SETUP_ARGS(node->nd_args);
+    END_CALLARGS;
 
-	    if (nd_type(node) != NODE_WHEN) goto again;
-	    tag = node->nd_head;
-	    while (tag) {
-		if (trace_func) {
-		    call_trace_func("line", tag->nd_file, nd_line(tag), self,
-				    ruby_frame->last_func,
-				    ruby_frame->last_class);	
-		}
-		ruby_sourcefile = tag->nd_file;
-		ruby_sourceline = nd_line(tag);
-		if (nd_type(tag->nd_head) == NODE_WHEN) {
-		    VALUE v = rb_eval(self, tag->nd_head->nd_head);
-		    int i;
-
-		    if (TYPE(v) != T_ARRAY) v = rb_Array(v);
-		    for (i=0; i<RARRAY(v)->len; i++) {
-			if (RTEST(RARRAY(v)->ptr[i])) {
-			    node = node->nd_body;
-			    goto again;
-			}
-		    }
-		    tag = tag->nd_next;
-		    continue;
-		}
-		if (RTEST(rb_eval(self, tag->nd_head))) {
-		    node = node->nd_body;
-		    goto again;
-		}
-		tag = tag->nd_next;
-	    }
-	    node = node->nd_next;
-	}
-	RETURN(Qnil);
+    return rb_call(CLASS_OF(self),self,node->nd_mid,argc,argv,1);
+}
 
-      case NODE_CASE:
-	{
-	    VALUE val;
+eval_node(dot, VALUE)
+{
+  VALUE result;
+  VALUE beg = rb_eval(self, node->nd_beg);
+  VALUE end = rb_eval(self, node->nd_end);
+  result = rb_range_new(beg, end, nd_type(node) == NODE_DOT3);
+  if (!node->nd_state) {
+    if (nd_type(node->nd_beg) == NODE_LIT && FIXNUM_P(node->nd_beg->nd_lit) &&
+        nd_type(node->nd_end) == NODE_LIT && FIXNUM_P(node->nd_end->nd_lit))
+    {
+        nd_set_type(node, NODE_LIT);
+        node->nd_lit = result;
+    }
+    else
+        node->nd_state = 1;
+  }
+  return result;
+}
 
-	    val = rb_eval(self, node->nd_head);
-	    node = node->nd_body;
-	    while (node) {
-		NODE *tag;
 
-		if (nd_type(node) != NODE_WHEN) {
-		    goto again;
-		}
-		tag = node->nd_head;
-		while (tag) {
-		    if (trace_func) {
-			call_trace_func("line", tag->nd_file, nd_line(tag), self,
-					ruby_frame->last_func,
-					ruby_frame->last_class);	
-		    }
-		    ruby_sourcefile = tag->nd_file;
-		    ruby_sourceline = nd_line(tag);
-		    if (nd_type(tag->nd_head) == NODE_WHEN) {
-			VALUE v = rb_eval(self, tag->nd_head->nd_head);
-			int i;
-
-			if (TYPE(v) != T_ARRAY) v = rb_Array(v);
-			for (i=0; i<RARRAY(v)->len; i++) {
-			    if (RTEST(rb_funcall2(RARRAY(v)->ptr[i], eqq, 1, &val))){
-				node = node->nd_body;
-				goto again;
-			    }
-			}
-			tag = tag->nd_next;
-			continue;
-		    }
-		    if (RTEST(rb_funcall2(rb_eval(self, tag->nd_head), eqq, 1, &val))) {
-			node = node->nd_body;
-			goto again;
-		    }
-		    tag = tag->nd_next;
-		}
-		node = node->nd_next;
-	    }
-	}
-	RETURN(Qnil);
+eval_node(flip2, VALUE)
+{
+  if (ruby_scope->local_vars == 0) {
+      rb_bug("unexpected local variable");
+  }
+  if (!RTEST(ruby_scope->local_vars[node->nd_cnt])) {
+      if (RTEST(rb_eval(self, node->nd_beg))) {
+	  ruby_scope->local_vars[node->nd_cnt] = 
+	      RTEST(rb_eval(self, node->nd_end))?Qfalse:Qtrue;
+	  return Qtrue;
+      }
+      else
+	return Qfalse;
+  }
+  else {
+      if (RTEST(rb_eval(self, node->nd_end))) {
+	  ruby_scope->local_vars[node->nd_cnt] = Qfalse;
+      }
+      return Qtrue;
+  }
+}
 
-      case NODE_WHILE:
-	PUSH_TAG(PROT_NONE);
-	switch (state = EXEC_TAG()) {
-	  case 0:
-	    ruby_sourceline = nd_line(node);
-	    if (node->nd_state && !RTEST(rb_eval(self, node->nd_cond)))
-		goto while_out;
-	    do {
-	      while_redo:
-		rb_eval(self, node->nd_body);
-	      while_next:
-		;
-	    } while (RTEST(rb_eval(self, node->nd_cond)));
-	    break;
 
-	  case TAG_REDO:
-	    state = 0;
-	    goto while_redo;
-	  case TAG_NEXT:
-	    state = 0;
-	    goto while_next;
-	  case TAG_BREAK:
-	    state = 0;
-	  default:
-	    break;
-	}
-      while_out:
-	POP_TAG();
-	if (state) JUMP_TAG(state);
-	RETURN(Qnil);
+eval_node(flip3, VALUE)
+{       
+  if (ruby_scope->local_vars == 0)
+      rb_bug("unexpected local variable");
+  if (!RTEST(ruby_scope->local_vars[node->nd_cnt]))
+    return ruby_scope->local_vars[node->nd_cnt] = 
+             RTEST(rb_eval(self, node->nd_beg)) ? Qtrue : Qfalse;
+  else{
+      if (RTEST(rb_eval(self, node->nd_end))) {
+	  ruby_scope->local_vars[node->nd_cnt] = Qfalse;
+      }
+      return Qtrue;
+  }
+}
 
-      case NODE_UNTIL:
-	PUSH_TAG(PROT_NONE);
-	switch (state = EXEC_TAG()) {
-	  case 0:
-	    if (node->nd_state && RTEST(rb_eval(self, node->nd_cond)))
-		goto until_out;
-	    do {
-	      until_redo:
-		rb_eval(self, node->nd_body);
-	      until_next:
-		;
-	    } while (!RTEST(rb_eval(self, node->nd_cond)));
-	    break;
 
-	  case TAG_REDO:
-	    state = 0;
-	    goto until_redo;
-	  case TAG_NEXT:
-	    state = 0;
-	    goto until_next;
-	  case TAG_BREAK:
-	    state = 0;
-	  default:
-	    break;
+eval_node(super, VALUE)      
+{
+  VALUE result;
+    int argc; VALUE *argv; /* used in SETUP_ARGS */
+    TMP_PROTECT;
+
+    if (ruby_frame->last_class == 0) {	
+	if (ruby_frame->last_func) {
+	    rb_raise(rb_eNameError, "superclass method `%s' disabled",
+		     rb_id2name(ruby_frame->last_func));
 	}
-      until_out:
-	POP_TAG();
-	if (state) JUMP_TAG(state);
-	RETURN(Qnil);
+	else {
+	    rb_raise(rb_eRuntimeError, "super called outside of method");
+	}
+    }
+    if (nd_type(node) == NODE_ZSUPER) {
+	argc = ruby_frame->argc;
+	argv = ruby_frame->argv;
+    }
+    else {
+	BEGIN_CALLARGS;
+	SETUP_ARGS(node->nd_args);
+	END_CALLARGS;
+    }
 
-      case NODE_BLOCK_PASS:
-	result = block_pass(self, node);
-	break;
+    PUSH_ITER(ruby_iter->iter?ITER_PRE:ITER_NOT);
+    result = rb_call(RCLASS(ruby_frame->last_class)->super,
+		     ruby_frame->self, ruby_frame->last_func,
+		     argc, argv, 3);
+    POP_ITER();
+  return result;
+}
 
-      case NODE_ITER:
-      case NODE_FOR:
-	{
-	  iter_retry:
-	    PUSH_TAG(PROT_FUNC);
-	    PUSH_BLOCK(node->nd_var, node->nd_body);
 
-	    state = EXEC_TAG();
-	    if (state == 0) {
-		PUSH_ITER(ITER_PRE);
-		if (nd_type(node) == NODE_ITER) {
-		    result = rb_eval(self, node->nd_iter);
-		}
-		else {
-		    VALUE recv;
-		    char *file = ruby_sourcefile;
-		    int line = ruby_sourceline;
-
-		    _block.flags &= ~BLOCK_D_SCOPE;
-		    BEGIN_CALLARGS;
-		    recv = rb_eval(self, node->nd_iter);
-		    END_CALLARGS;
-		    ruby_sourcefile = file;
-		    ruby_sourceline = line;
-		    result = rb_call(CLASS_OF(recv),recv,each,0,0,0);
-		}
-		POP_ITER();
-	    }
-	    else if (_block.tag->dst == state) {
-		state &= TAG_MASK;
-		if (state == TAG_RETURN) {
-		    result = prot_tag->retval;
-		}
-	    }
-	    POP_BLOCK();
-	    POP_TAG();
-	    switch (state) {
-	      case 0:
-		break;
+eval_node_volatile(scope, VALUE)
+{
+  int state;
+  VALUE result;
+  struct FRAME frame;
+  NODE *volatile saved_cref = 0;
+
+  frame = *ruby_frame;
+  frame.tmp = ruby_frame;
+  ruby_frame = &frame;
+
+  PUSH_SCOPE();
+  PUSH_TAG(PROT_NONE);
+  if (node->nd_rval) {
+      saved_cref = ruby_cref;
+      ruby_cref = (NODE*)node->nd_rval;
+      ruby_frame->cbase = node->nd_rval;
+  }
+  ruby_scope->scope_node = (VALUE)node;
+  if (node->nd_tbl) {
+      VALUE *vars = ALLOCA_N(VALUE, node->nd_tbl[0]+1);
+      *vars++ = (VALUE)node;
+      ruby_scope->local_vars = vars;
+      rb_mem_clear(ruby_scope->local_vars, node->nd_tbl[0]);
+      ruby_scope->local_tbl = node->nd_tbl;
+  }
+  else {
+      ruby_scope->local_vars = 0;
+      ruby_scope->local_tbl  = 0;
+  }
+  if ((state = EXEC_TAG()) == 0) {
+      result = rb_eval(self, node->nd_next);
+  }
+  POP_TAG();
+  POP_SCOPE();
+  ruby_frame = frame.tmp;
+  if (saved_cref)
+      ruby_cref = saved_cref;
+  if (state) JUMP_TAG(state);
+  return result;
+}
 
-	      case TAG_RETRY:
-		goto iter_retry;
 
-	      case TAG_BREAK:
-		result = Qnil;
-		break;
-	      case TAG_RETURN:
-		return_value(result);
-		/* fall through */
-	      default:
-		JUMP_TAG(state);
-	    }
-	}
-	break;
+eval_node(asgn1, VALUE)
+{
+    int argc; VALUE *argv; /* used in SETUP_ARGS */
+    VALUE recv, val;
+    NODE *rval;
+    TMP_PROTECT;
 
-      case NODE_BREAK:
-	JUMP_TAG(TAG_BREAK);
+    recv = rb_eval(self, node->nd_recv);
+    rval = node->nd_args->nd_head;
+    SETUP_ARGS(node->nd_args->nd_next);
+    val = rb_funcall2(recv, aref, argc-1, argv);
+    switch (node->nd_mid) {
+    case 0: /* OR */
+	if (RTEST(val)) return val;
+	val = rb_eval(self, rval);
 	break;
-
-      case NODE_NEXT:
-	CHECK_INTS;
-	JUMP_TAG(TAG_NEXT);
+    case 1: /* AND */
+	if (!RTEST(val)) return val;
+	val = rb_eval(self, rval);
 	break;
+    default:
+	val = rb_funcall(val, node->nd_mid, 1, rb_eval(self, rval));
+    }
+    argv[argc-1] = val;
+    return rb_funcall2(recv, aset, argc, argv);
+}
 
-      case NODE_REDO:
-	CHECK_INTS;
-	JUMP_TAG(TAG_REDO);
-	break;
 
-      case NODE_RETRY:
-	CHECK_INTS;
-	JUMP_TAG(TAG_RETRY);
-	break;
+eval_node(asgn2, VALUE)
+{
+    ID id = node->nd_next->nd_vid;
+    VALUE recv, val;
 
-      case NODE_RESTARGS:
-	result = rb_eval(self, node->nd_head);
-	if (TYPE(result) != T_ARRAY) {
-	    result = rb_Array(result);
-	}
+    recv = rb_eval(self, node->nd_recv);
+    val = rb_funcall(recv, id, 0);
+    switch (node->nd_next->nd_mid) {
+    case 0: /* OR */
+	if (RTEST(val)) return val;
+	val = rb_eval(self, node->nd_value);
 	break;
-
-      case NODE_YIELD:
-	if (node->nd_stts) {
-	    result = rb_eval(self, node->nd_stts);
-	    if (nd_type(node->nd_stts) == NODE_RESTARGS &&
-		RARRAY(result)->len == 1)
-	    {
-		result = RARRAY(result)->ptr[0];
-	    }
-	}
-	else {
-	    result = Qnil;
-	}
-	result = rb_yield_0(result, 0, 0, 0);
+    case 1: /* AND */
+	if (!RTEST(val)) return val;
+	val = rb_eval(self, node->nd_value);
 	break;
+    default:
+	val = rb_funcall(val, node->nd_next->nd_mid, 1,
+			 rb_eval(self, node->nd_value));
+    }
 
-      case NODE_RESCUE:
-      retry_entry:
-        {
-	    volatile VALUE e_info = ruby_errinfo;
+    return rb_funcall2(recv, node->nd_next->nd_aid, 1, &val);
+}
 
-	    PUSH_TAG(PROT_NONE);
-	    if ((state = EXEC_TAG()) == 0) {
-		result = rb_eval(self, node->nd_head);
-	    }
-	    POP_TAG();
-	    if (state == TAG_RAISE) {
-		NODE * volatile resq = node->nd_resq;
-
-		ruby_sourceline = nd_line(node);
-		while (resq) {
-		    if (handle_rescue(self, resq)) {
-			state = 0;
-			PUSH_TAG(PROT_NONE);
-			if ((state = EXEC_TAG()) == 0) {
-			    result = rb_eval(self, resq->nd_body);
-			}
-			POP_TAG();
-			if (state == TAG_RETRY) {
-			    state = 0;
-			    ruby_errinfo = Qnil;
-			    goto retry_entry;
-			}
-			if (state != TAG_RAISE) {
-			    ruby_errinfo = e_info;
-			}
-			break;
-		    }
-		    resq = resq->nd_head; /* next rescue */
-		}
-	    }
-	    else if (node->nd_else) { /* else clause given */
-		if (!state) {	/* no exception raised */
-		    result = rb_eval(self, node->nd_else);
-		}
-	    }
-	    if (state) JUMP_TAG(state);
-	}
-        break;
 
-      case NODE_ENSURE:
-	PUSH_TAG(PROT_NONE);
-	if ((state = EXEC_TAG()) == 0) {
-	    result = rb_eval(self, node->nd_head);
-	}
-	POP_TAG();
-	if (node->nd_ensr) {
-	    VALUE retval = prot_tag->retval; /* save retval */
-	    VALUE errinfo = ruby_errinfo;
-
-	    rb_eval(self, node->nd_ensr);
-	    return_value(retval);
-	    ruby_errinfo = errinfo;
-	}
-	if (state) JUMP_TAG(state);
+eval_node(colon2, VALUE)
+{
+    VALUE klass = rb_eval(self, node->nd_head);
+    switch (TYPE(klass)) {
+      case T_CLASS:
+      case T_MODULE:
 	break;
+      default:
+	return rb_funcall(klass, node->nd_mid, 0, 0);
+    }
+    return rb_const_get(klass, node->nd_mid);
+}
 
-      case NODE_AND:
-	result = rb_eval(self, node->nd_1st);
-	if (!RTEST(result)) break;
-	node = node->nd_2nd;
-	goto again;
 
-      case NODE_OR:
-	result = rb_eval(self, node->nd_1st);
-	if (RTEST(result)) break;
-	node = node->nd_2nd;
-	goto again;
+eval_node(hash, VALUE)
+{
+    NODE *list;
+    VALUE hash = rb_hash_new();
+    VALUE key, val;
 
-      case NODE_NOT:
-	if (RTEST(rb_eval(self, node->nd_body))) result = Qfalse;
-	else result = Qtrue;
-	break;
+    list = node->nd_head;
+    while (list) {
+	key = rb_eval(self, list->nd_head);
+	list = list->nd_next;
+	if (list == 0)
+	    rb_bug("odd number list for Hash");
+	val = rb_eval(self, list->nd_head);
+	list = list->nd_next;
+	rb_hash_aset(hash, key, val);
+    }
+    return hash;
+}
 
-      case NODE_DOT2:
-      case NODE_DOT3:
-	result = rb_range_new(rb_eval(self, node->nd_beg),
-			      rb_eval(self, node->nd_end),
-			      nd_type(node) == NODE_DOT3);
-	if (node->nd_state) break;
-	if (nd_type(node->nd_beg) == NODE_LIT && FIXNUM_P(node->nd_beg->nd_lit) &&
-	    nd_type(node->nd_end) == NODE_LIT && FIXNUM_P(node->nd_end->nd_lit))
-	{
-	    nd_set_type(node, NODE_LIT);
-	    node->nd_lit = result;
-	}
-	else {
-	    node->nd_state = 1;
+
+eval_node(array, VALUE)
+{
+    VALUE ary;
+    int i;
+
+    i = node->nd_alen;
+    ary = rb_ary_new2(i);
+    for (i=0;node;node=node->nd_next) {
+        RARRAY(ary)->ptr[i++] = rb_eval(self, node->nd_head);
+        RARRAY(ary)->len = i;
+    }
+
+    return ary;
+}
+
+
+eval_node(regx, VALUE)
+{
+    VALUE str, str2, result;
+    NODE *list = node->nd_next;
+
+    str = rb_str_new3(node->nd_lit);
+    if (!ruby_dyna_vars) rb_dvar_push(0, 0);
+    while (list) {
+	if (list->nd_head) {
+	    switch (nd_type(list->nd_head)) {
+	      case NODE_STR:
+		str2 = list->nd_head->nd_lit;
+		break;
+	      case NODE_EVSTR:
+		result = ruby_errinfo;
+		ruby_errinfo = Qnil;
+		ruby_sourceline = nd_line(list->nd_head);
+		ruby_in_eval++;
+		list->nd_head = compile(list->nd_head->nd_lit,
+					ruby_sourcefile,
+					ruby_sourceline);
+		if (ruby_scope->local_tbl) {
+		    NODE *body = (NODE *)ruby_scope->scope_node;
+		    if (body && body->nd_tbl != ruby_scope->local_tbl) {
+			if (body->nd_tbl) free(body->nd_tbl);
+			ruby_scope->local_vars[-1] = (VALUE)body;
+			body->nd_tbl = ruby_scope->local_tbl;
+		    }
+		}
+		ruby_eval_tree = 0;
+		ruby_in_eval--;
+		if (ruby_nerrs > 0) {
+		    compile_error("string expansion");
+		}
+		if (!NIL_P(result)) ruby_errinfo = result;
+		/* fall through */
+	      default:
+		str2 = rb_obj_as_string(rb_eval(self, list->nd_head));
+		break;
+	    }
+	    rb_str_append(str, str2);
+	    OBJ_INFECT(str, str2);
 	}
+	list = list->nd_next;
+    }
+    switch (nd_type(node)) {
+      case NODE_DREGX:
+	result = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len,
+			 node->nd_cflag);
 	break;
+      case NODE_DREGX_ONCE:	/* regexp expand once */
+	result = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len,
+			 node->nd_cflag);
+	nd_set_type(node, NODE_LIT);
+	node->nd_lit = result;
+	break;
+      case NODE_DXSTR:
+	result = rb_funcall(self, '`', 1, str);
+	break;
+      default:
+	result = str;
+	break;
+    }
+    RB_GC_GUARD(str);  /* ensure str is not GC'd in rb_reg_new */
+    return result;
+}
 
-      case NODE_FLIP2:		/* like AWK */
-	if (ruby_scope->local_vars == 0) {
-	    rb_bug("unexpected local variable");
+        
+eval_node(defn, VALUE)
+{
+    NODE *body,  *defn;
+    VALUE origin, symbol;
+    int noex;
+
+    if (NIL_P(ruby_class)) {
+	rb_raise(rb_eTypeError, "no class to add method");
+    }
+    if (ruby_class == rb_cObject && node->nd_mid == init) {
+	rb_warn("redefining Object#initialize may cause infinite loop");
+    }
+    if (node->nd_mid == __id__ || node->nd_mid == __send__) {
+	rb_warn("redefining `%s' may cause serious problem",
+		rb_id2name(node->nd_mid));
+    }
+    rb_frozen_class_p(ruby_class);
+    body = search_method(ruby_class, node->nd_mid, &origin);
+    if (body){
+	if (RTEST(ruby_verbose) && ruby_class == origin && body->nd_cnt == 0) {
+	    rb_warning("method redefined; discarding old %s", rb_id2name(node->nd_mid));
 	}
-	if (!RTEST(ruby_scope->local_vars[node->nd_cnt])) {
-	    if (RTEST(rb_eval(self, node->nd_beg))) {
-		ruby_scope->local_vars[node->nd_cnt] = 
-		    RTEST(rb_eval(self, node->nd_end))?Qfalse:Qtrue;
-		result = Qtrue;
-	    }
-	    else {
-		result = Qfalse;
-	    }
+    }
+
+    if (node->nd_noex == NOEX_PUBLIC) {
+	noex = NOEX_PUBLIC; 	/* means is is an attrset */
+    }
+    else if (SCOPE_TEST(SCOPE_PRIVATE) || node->nd_mid == init) {
+	noex = NOEX_PRIVATE;
+    }
+    else if (SCOPE_TEST(SCOPE_PROTECTED)) {
+	noex = NOEX_PROTECTED;
+    }
+    else {
+	noex = NOEX_PUBLIC;
+    }
+    if (body && origin == ruby_class && body->nd_noex & NOEX_UNDEF) {
+	noex |= NOEX_UNDEF;
+    }
+
+    defn = copy_node_scope(node->nd_defn, ruby_cref);
+    rb_add_method(ruby_class, node->nd_mid, defn, noex);
+    symbol = ID2SYM(node->nd_mid);
+    if (scope_vmode == SCOPE_MODFUNC) {
+	rb_add_method(rb_singleton_class(ruby_class),
+		      node->nd_mid, defn, NOEX_PUBLIC);
+	rb_funcall(ruby_class, singleton_added, 1, symbol);
+    }
+    if (FL_TEST(ruby_class, FL_SINGLETON)) {
+	rb_funcall(rb_iv_get(ruby_class, "__attached__"),
+		   singleton_added, 1, symbol);
+    }
+    else {
+	rb_funcall(ruby_class, added, 1, symbol);
+    }
+    return symbol;
+}
+
+
+eval_node(defs, VALUE)
+{
+    VALUE recv = rb_eval(self, node->nd_recv);
+    VALUE klass, symbol;
+    NODE *body = 0, *defn;
+
+    if (rb_safe_level() >= 4 && !OBJ_TAINTED(recv)) {
+	rb_raise(rb_eSecurityError, "Insecure: can't define singleton method");
+    }
+    if (FIXNUM_P(recv) || SYMBOL_P(recv)) {
+	rb_raise(rb_eTypeError,
+		 "can't define singleton method \"%s\" for %s",
+		 rb_id2name(node->nd_mid),
+		 rb_class2name(CLASS_OF(recv)));
+    }
+
+    if (OBJ_FROZEN(recv)) rb_error_frozen("object");
+    klass = rb_singleton_class(recv);
+    if (st_lookup(RCLASS(klass)->m_tbl, node->nd_mid, &body)) {
+	if (rb_safe_level() >= 4) {
+	    rb_raise(rb_eSecurityError, "redefining method prohibited");
 	}
-	else {
-	    if (RTEST(rb_eval(self, node->nd_end))) {
-		ruby_scope->local_vars[node->nd_cnt] = Qfalse;
-	    }
-	    result = Qtrue;
+	if (RTEST(ruby_verbose)) {
+	    rb_warning("redefine %s", rb_id2name(node->nd_mid));
 	}
-	break;
+    }
+    defn = copy_node_scope(node->nd_defn, ruby_cref);
+    defn->nd_rval = (VALUE)ruby_cref;
+    rb_add_method(klass, node->nd_mid, defn, 
+		  NOEX_PUBLIC|(body?body->nd_noex&NOEX_UNDEF:0));
+    rb_funcall(recv, singleton_added, 1, symbol=ID2SYM(node->nd_mid));
+    return symbol;
+}
 
-      case NODE_FLIP3:		/* like SED */
-	if (ruby_scope->local_vars == 0) {
-	    rb_bug("unexpected local variable");
-	}
-	if (!RTEST(ruby_scope->local_vars[node->nd_cnt])) {
-	    result = RTEST(rb_eval(self, node->nd_beg)) ? Qtrue : Qfalse;
-	    ruby_scope->local_vars[node->nd_cnt] = result;
+
+eval_node(class, VALUE)
+{
+    VALUE super, klass;
+
+    if (NIL_P(ruby_class)) {
+	rb_raise(rb_eTypeError, "no outer class/module");
+    }
+    if (node->nd_super) {
+	super = superclass(self, node->nd_super);
+    }
+    else {
+	super = 0;
+    }
+
+    if ((ruby_class == rb_cObject) && rb_autoload_defined(node->nd_cname)) {
+	rb_autoload_load(node->nd_cname);
+    }
+    if (rb_const_defined_at(ruby_class, node->nd_cname)) {
+	klass = rb_const_get(ruby_class, node->nd_cname);
+	if (TYPE(klass) != T_CLASS) {
+	    rb_raise(rb_eTypeError, "%s is not a class",
+		     rb_id2name(node->nd_cname));
 	}
-	else {
-	    if (RTEST(rb_eval(self, node->nd_end))) {
-		ruby_scope->local_vars[node->nd_cnt] = Qfalse;
-	    }
-	    result = Qtrue;
+	if (super && rb_class_real(RCLASS(klass)->super) != super)
+	  goto override_class;
+	if (rb_safe_level() >= 4) {
+	    rb_raise(rb_eSecurityError, "extending class prohibited");
 	}
-	break;
+	rb_clear_cache();
+    }
+    else {
+      override_class:
+	if (!super) super = rb_cObject;
+	klass = rb_define_class_id(node->nd_cname, super);
+	rb_set_class_path(klass,ruby_class,rb_id2name(node->nd_cname));
+	rb_class_inherited(super, klass);
+	rb_const_set(ruby_class, node->nd_cname, klass);
+    }
+    if (ruby_wrapper) {
+	rb_extend_object(klass, ruby_wrapper);
+	rb_include_module(klass, ruby_wrapper);
+    }
 
-      case NODE_RETURN:
-	if (node->nd_stts) {
- 	    return_value(rb_eval(self, node->nd_stts));
- 	}
-	else {
-	    return_value(Qnil);
+    return module_setup(klass, node->nd_body);
+}
+
+
+eval_node(sclass, VALUE)
+{
+    VALUE klass, result;
+
+    result = rb_eval(self, node->nd_recv);
+    if (result == Qtrue) {
+	klass = rb_cTrueClass;
+    }
+    else if (result == Qfalse) {
+	klass = rb_cTrueClass;
+    }
+    else if (result == Qnil) {
+	klass = rb_cNilClass;
+    }
+    else {
+	if (rb_special_const_p(result)) {
+	    rb_raise(rb_eTypeError, "no virtual class for %s",
+		     rb_class2name(CLASS_OF(result)));
 	}
-	return_check();
-	JUMP_TAG(TAG_RETURN);
-	break;
+	if (rb_safe_level() >= 4 && !OBJ_TAINTED(result))
+	    rb_raise(rb_eSecurityError, "Insecure: can't extend object");
+	if (FL_TEST(CLASS_OF(result), FL_SINGLETON)) {
+	    rb_clear_cache();
+	}
+	klass = rb_singleton_class(result);
+    }
 
-      case NODE_ARGSCAT:
-	result = rb_ary_concat(rb_eval(self, node->nd_head),
-			       rb_eval(self, node->nd_body));
-	break;
+    if (ruby_wrapper) {
+	rb_extend_object(klass, ruby_wrapper);
+	rb_include_module(klass, ruby_wrapper);
+    }
 
-      case NODE_ARGSPUSH:
-	result = rb_ary_push(rb_obj_dup(rb_eval(self, node->nd_head)),
-			     rb_eval(self, node->nd_body));
-	break;
+    return module_setup(klass, node->nd_body);
+}
 
-      case NODE_CALL:
-	{
-	    VALUE recv;
-	    int argc; VALUE *argv; /* used in SETUP_ARGS */
-	    TMP_PROTECT;
 
-	    BEGIN_CALLARGS;
-	    recv = rb_eval(self, node->nd_recv);
-	    SETUP_ARGS(node->nd_args);
-	    END_CALLARGS;
+eval_node(module, VALUE)
+{
+    VALUE module;
 
-	    result = rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,0);
+    if (NIL_P(ruby_class)) {
+	rb_raise(rb_eTypeError, "no outer class/module");
+    }
+    if ((ruby_class == rb_cObject) && rb_autoload_defined(node->nd_cname)) {
+	rb_autoload_load(node->nd_cname);
+    }
+    if (rb_const_defined_at(ruby_class, node->nd_cname)) {
+	module = rb_const_get(ruby_class, node->nd_cname);
+	if (TYPE(module) != T_MODULE) {
+	    rb_raise(rb_eTypeError, "%s is not a module",
+		     rb_id2name(node->nd_cname));
 	}
-	break;
+	if (rb_safe_level() >= 4) {
+	    rb_raise(rb_eSecurityError, "extending module prohibited");
+	}
+    }
+    else {
+	module = rb_define_module_id(node->nd_cname);
+	rb_set_class_path(module,ruby_class,rb_id2name(node->nd_cname));
+	rb_const_set(ruby_class, node->nd_cname, module);
+    }
+    if (ruby_wrapper) {
+	rb_extend_object(module, ruby_wrapper);
+	rb_include_module(module, ruby_wrapper);
+    }
 
-      case NODE_FCALL:
-	{
-	    int argc; VALUE *argv; /* used in SETUP_ARGS */
-	    TMP_PROTECT;
+    return module_setup(module, node->nd_body);
+}
 
-	    BEGIN_CALLARGS;
-	    SETUP_ARGS(node->nd_args);
-	    END_CALLARGS;
 
-	    result = rb_call(CLASS_OF(self),self,node->nd_mid,argc,argv,1);
-	}
-	break;
+eval_node(defined, VALUE)
+{
+    char buf[20];
+    char *desc = is_defined(self, node->nd_head, buf);
+
+    return desc ? rb_str_new2(desc) : Qnil;
+}
+
+static VALUE
+rb_eval(self, node)
+  VALUE self;
+  NODE *node;
+{
+  VALUE result;
+  int state;
+
+again:
+  CHECK_INTS;
+  result = Qnil;
+  if (node) {
+    switch (nd_type(node)) {
+      case NODE_BLOCK:
+        while (node->nd_next) {
+	    rb_eval(self, node->nd_head);
+	    node = node->nd_next;
+        }
+        node = node->nd_head;
+        goto again;
+
+      case NODE_POSTEXE:
+        rb_f_END();
+        nd_set_type(node, NODE_NIL); /* exec just once */
+        break;
+
+        /* begin .. end without clauses */
+      case NODE_BEGIN:
+        node = node->nd_body;
+        goto again;
+
+        /* nodes for speed-up(default match) */
+      case NODE_MATCH:
+        result = rb_reg_match2(node->nd_head->nd_lit);
+        break;
+
+        /* nodes for speed-up(literal match) */
+      case NODE_MATCH2:        
+        result = eval_match2(self, node);
+        break;
+
+        /* nodes for speed-up(literal match) */
+      case NODE_MATCH3:
+        result = eval_match3(self,node);
+        break;
+
+        /* node for speed-up(top-level loop for -n/-p) */
+      case NODE_OPT_N:
+        eval_opt_n(self, node);
+        break;
+
+      case NODE_SELF:
+        result = self;
+        break;
+
+      case NODE_NIL:
+        break;
+
+      case NODE_TRUE:
+        result = Qtrue;
+        break;
+
+      case NODE_FALSE:
+        result = Qfalse;
+        break;
+
+      case NODE_IF:
+        ruby_sourceline = nd_line(node);
+        node = RTEST(rb_eval(self, node->nd_cond)) ? 
+                                     node->nd_body : node->nd_else;
+        goto again;
+
+      case NODE_WHEN:
+        if (node = eval_when(self, node)) goto again;
+        break;
+
+      case NODE_CASE:
+        if (node = eval_case(self, node)) goto again;
+        break;
+
+      case NODE_WHILE:
+        eval_while(self,node);
+        break;
+
+      case NODE_UNTIL:
+        eval_until(self,node);
+        break;
+
+      case NODE_BLOCK_PASS:
+        result = block_pass(self, node);
+        break;
+
+      case NODE_ITER:
+      case NODE_FOR:
+        result = eval_iter(self,node);
+        break;
+
+      case NODE_BREAK:
+        JUMP_TAG(TAG_BREAK);
+        break;
+
+      case NODE_NEXT:
+        JUMP_TAG(TAG_NEXT);
+        break;
+
+      case NODE_REDO:
+        JUMP_TAG(TAG_REDO);
+        break;
+
+      case NODE_RETRY:
+        JUMP_TAG(TAG_RETRY);
+        break;
+
+      case NODE_RESTARGS:
+        result = rb_eval(self, node->nd_head);
+        if (TYPE(result) != T_ARRAY)
+	  result = rb_Array(result);
+        break;
+
+      case NODE_YIELD:
+        if (node->nd_stts) {
+	    result = rb_eval(self, node->nd_stts);
+	    if (nd_type(node->nd_stts) == NODE_RESTARGS && 
+                RARRAY(result)->len == 1) 
+	      result = RARRAY(result)->ptr[0];
+        }
+        result = rb_yield_0(result, 0, 0, 0);
+        break;
+
+      case NODE_RESCUE:
+        result = eval_rescue(self,node);
+        break;
+
+      case NODE_ENSURE:
+        result = eval_ensure(self,node);
+        break;
+
+      case NODE_AND:
+        result = rb_eval(self, node->nd_1st);
+        if (!RTEST(result)) break;
+        node = node->nd_2nd;
+        goto again;
+
+      case NODE_OR:
+        result = rb_eval(self, node->nd_1st);
+        if (RTEST(result)) break;
+        node = node->nd_2nd;
+        goto again;
+
+      case NODE_NOT:
+        result = RTEST(rb_eval(self, node->nd_body)) ? Qfalse : Qtrue;
+        break;
+
+      case NODE_DOT2:
+      case NODE_DOT3:
+        result = eval_dot(self,node);
+        break;
+
+      case NODE_FLIP2:		/* like AWK */
+        result = eval_flip2(self,node);
+        break;
+
+      case NODE_FLIP3:		/* like SED */
+        result = eval_flip3(self,node);
+        break;
+
+      case NODE_RETURN:
+        return_value(node->nd_stts ? rb_eval(self, node->nd_stts) : Qnil);
+        return_check();
+        JUMP_TAG(TAG_RETURN);
+        break;
+
+      case NODE_ARGSCAT:
+        result = rb_eval(self, node->nd_head);
+        result = rb_ary_concat(result, rb_eval(self, node->nd_body));
+        break;
+
+      case NODE_ARGSPUSH:
+        result = rb_obj_dup(rb_eval(self, node->nd_head));
+        result = rb_ary_push(result, rb_eval(self, node->nd_body));
+        break;
+
+      case NODE_CALL:
+        result = eval_call(self,node);
+        break;
+
+      case NODE_FCALL:
+        result = eval_fcall(self,node);
+        break;
 
       case NODE_VCALL:
-	result = rb_call(CLASS_OF(self),self,node->nd_mid,0,0,2);
-	break;
+        result = rb_call(CLASS_OF(self),self,node->nd_mid,0,0,2);
+        break;
 
       case NODE_SUPER:
       case NODE_ZSUPER:
-	{
-	    int argc; VALUE *argv; /* used in SETUP_ARGS */
-	    TMP_PROTECT;
-
-	    if (ruby_frame->last_class == 0) {	
-		if (ruby_frame->last_func) {
-		    rb_raise(rb_eNameError, "superclass method `%s' disabled",
-			     rb_id2name(ruby_frame->last_func));
-		}
-		else {
-		    rb_raise(rb_eRuntimeError, "super called outside of method");
-		}
-	    }
-	    if (nd_type(node) == NODE_ZSUPER) {
-		argc = ruby_frame->argc;
-		argv = ruby_frame->argv;
-	    }
-	    else {
-		BEGIN_CALLARGS;
-		SETUP_ARGS(node->nd_args);
-		END_CALLARGS;
-	    }
-
-	    PUSH_ITER(ruby_iter->iter?ITER_PRE:ITER_NOT);
-	    result = rb_call(RCLASS(ruby_frame->last_class)->super,
-			     ruby_frame->self, ruby_frame->last_func,
-			     argc, argv, 3);
-	    POP_ITER();
-	}
-	break;
+        result = eval_super(self,node);
+        break;
 
       case NODE_SCOPE:
-	{
-	    struct FRAME frame;
-	    NODE *saved_cref = 0;
-
-	    frame = *ruby_frame;
-	    frame.tmp = ruby_frame;
-	    ruby_frame = &frame;
-
-	    PUSH_SCOPE();
-	    PUSH_TAG(PROT_NONE);
-	    if (node->nd_rval) {
-		saved_cref = ruby_cref;
-		ruby_cref = (NODE*)node->nd_rval;
-		ruby_frame->cbase = node->nd_rval;
-	    }
-	    ruby_scope->scope_node = (VALUE)node;
-	    if (node->nd_tbl) {
-		VALUE *vars = ALLOCA_N(VALUE, node->nd_tbl[0]+1);
-		*vars++ = (VALUE)node;
-		ruby_scope->local_vars = vars;
-		rb_mem_clear(ruby_scope->local_vars, node->nd_tbl[0]);
-		ruby_scope->local_tbl = node->nd_tbl;
-	    }
-	    else {
-		ruby_scope->local_vars = 0;
-		ruby_scope->local_tbl  = 0;
-	    }
-	    if ((state = EXEC_TAG()) == 0) {
-		result = rb_eval(self, node->nd_next);
-	    }
-	    POP_TAG();
-	    POP_SCOPE();
-	    ruby_frame = frame.tmp;
-	    if (saved_cref)
-		ruby_cref = saved_cref;
-	    if (state) JUMP_TAG(state);
-	}
-	break;
+        result = eval_scope(self,node);
+        break;
 
       case NODE_OP_ASGN1:
-	{
-	    int argc; VALUE *argv; /* used in SETUP_ARGS */
-	    VALUE recv, val;
-	    NODE *rval;
-	    TMP_PROTECT;
-
-	    recv = rb_eval(self, node->nd_recv);
-	    rval = node->nd_args->nd_head;
-	    SETUP_ARGS(node->nd_args->nd_next);
-	    val = rb_funcall2(recv, aref, argc-1, argv);
-	    switch (node->nd_mid) {
-	    case 0: /* OR */
-		if (RTEST(val)) RETURN(val);
-		val = rb_eval(self, rval);
-		break;
-	    case 1: /* AND */
-		if (!RTEST(val)) RETURN(val);
-		val = rb_eval(self, rval);
-		break;
-	    default:
-		val = rb_funcall(val, node->nd_mid, 1, rb_eval(self, rval));
-	    }
-	    argv[argc-1] = val;
-	    val = rb_funcall2(recv, aset, argc, argv);
-	    result = val;
-	}
-	break;
+        result = eval_asgn1(self,node);
+        break;
 
       case NODE_OP_ASGN2:
-	{
-	    ID id = node->nd_next->nd_vid;
-	    VALUE recv, val;
-
-	    recv = rb_eval(self, node->nd_recv);
-	    val = rb_funcall(recv, id, 0);
-	    switch (node->nd_next->nd_mid) {
-	    case 0: /* OR */
-		if (RTEST(val)) RETURN(val);
-		val = rb_eval(self, node->nd_value);
-		break;
-	    case 1: /* AND */
-		if (!RTEST(val)) RETURN(val);
-		val = rb_eval(self, node->nd_value);
-		break;
-	    default:
-		val = rb_funcall(val, node->nd_next->nd_mid, 1,
-				 rb_eval(self, node->nd_value));
-	    }
-
-	    rb_funcall2(recv, node->nd_next->nd_aid, 1, &val);
-	    result = val;
-	}
-	break;
+        result = eval_asgn2(self,node);
+        break;
 
       case NODE_OP_ASGN_AND:
-	result = rb_eval(self, node->nd_head);
-	if (!RTEST(result)) break;
-	node = node->nd_value;
-	goto again;
+        result = rb_eval(self, node->nd_head);
+        if (!RTEST(result)) break;
+        node = node->nd_value;
+        goto again;
 
       case NODE_OP_ASGN_OR:
-	if ((node->nd_aid && !rb_ivar_defined(self, node->nd_aid)) ||
+        if ((node->nd_aid && !rb_ivar_defined(self, node->nd_aid)) ||
 	    !RTEST(result = rb_eval(self, node->nd_head))) {
 	    node = node->nd_value;
 	    goto again;
-	}
-	break;
+        }
+        break;
 
       case NODE_MASGN:
-	result = massign(self, node, rb_eval(self, node->nd_value),0);
-	break;
+        result = massign(self, node, rb_eval(self, node->nd_value),0);
+        break;
 
       case NODE_LASGN:
-	if (ruby_scope->local_vars == 0)
+        if (ruby_scope->local_vars == 0)
 	    rb_bug("unexpected local variable assignment");
-	result = rb_eval(self, node->nd_value);
-	ruby_scope->local_vars[node->nd_cnt] = result;
-	break;
+        result = rb_eval(self, node->nd_value);
+        ruby_scope->local_vars[node->nd_cnt] = result;
+        break;
 
       case NODE_DASGN:
-	result = rb_eval(self, node->nd_value);
-	dvar_asgn(node->nd_vid, result);
-	break;
+        result = rb_eval(self, node->nd_value);
+        dvar_asgn(node->nd_vid, result);
+        break;
 
       case NODE_DASGN_CURR:
-	result = rb_eval(self, node->nd_value);
-	dvar_asgn_curr(node->nd_vid, result);
-	break;
+        result = rb_eval(self, node->nd_value);
+        dvar_asgn_curr(node->nd_vid, result);
+        break;
 
       case NODE_GASGN:
-	result = rb_eval(self, node->nd_value);
-	rb_gvar_set(node->nd_entry, result);
-	break;
+        result = rb_eval(self, node->nd_value);
+        rb_gvar_set(node->nd_entry, result);
+        break;
 
       case NODE_IASGN:
-	result = rb_eval(self, node->nd_value);
-	rb_ivar_set(self, node->nd_vid, result);
-	break;
+        result = rb_eval(self, node->nd_value);
+        rb_ivar_set(self, node->nd_vid, result);
+        break;
 
       case NODE_CDECL:
-	if (NIL_P(ruby_class)) {
+        if (NIL_P(ruby_class)) {
 	    rb_raise(rb_eTypeError, "no class/module to define constant");
-	}
-	result = rb_eval(self, node->nd_value);
-	rb_const_set(ruby_class, node->nd_vid, result);
-	break;
+        }
+        result = rb_eval(self, node->nd_value);
+        rb_const_set(ruby_class, node->nd_vid, result);
+        break;
 
       case NODE_CVDECL:
-	if (NIL_P(ruby_cbase)) {
+        if (NIL_P(ruby_cbase)) {
 	    rb_raise(rb_eTypeError, "no class/module to define class variable");
-	}
-	result = rb_eval(self, node->nd_value);
-	rb_cvar_declare(cvar_cbase(), node->nd_vid, result);
-	break;
+        }
+        result = rb_eval(self, node->nd_value);
+        rb_cvar_declare(cvar_cbase(), node->nd_vid, result);
+        break;
 
       case NODE_CVASGN:
-	result = rb_eval(self, node->nd_value);
-	rb_cvar_set(cvar_cbase(), node->nd_vid, result);
-	break;
+        result = rb_eval(self, node->nd_value);
+        rb_cvar_set(cvar_cbase(), node->nd_vid, result);
+        break;
 
       case NODE_LVAR:
-	if (ruby_scope->local_vars == 0) {
+        if (ruby_scope->local_vars == 0) {
 	    rb_bug("unexpected local variable");
-	}
-	result = ruby_scope->local_vars[node->nd_cnt];
-	break;
+        }
+        result = ruby_scope->local_vars[node->nd_cnt];
+        break;
 
       case NODE_DVAR:
-	result = rb_dvar_ref(node->nd_vid);
-	break;
+        result = rb_dvar_ref(node->nd_vid);
+        break;
 
       case NODE_GVAR:
-	result = rb_gvar_get(node->nd_entry);
-	break;
+        result = rb_gvar_get(node->nd_entry);
+        break;
 
       case NODE_IVAR:
-	result = rb_ivar_get(self, node->nd_vid);
-	break;
+        result = rb_ivar_get(self, node->nd_vid);
+        break;
 
       case NODE_CONST:
-	result = ev_const_get(RNODE(ruby_frame->cbase), node->nd_vid, self);
-	break;
+        result = ev_const_get(RNODE(ruby_frame->cbase), node->nd_vid, self);
+        break;
 
       case NODE_CVAR:
-	result = rb_cvar_get(cvar_cbase(), node->nd_vid);
-	break;
+        result = rb_cvar_get(cvar_cbase(), node->nd_vid);
+        break;
 
       case NODE_BLOCK_ARG:
-	if (ruby_scope->local_vars == 0)
+        if (ruby_scope->local_vars == 0)
 	    rb_bug("unexpected block argument");
-	if (rb_block_given_p()) {
+        if (rb_block_given_p()) {
 	    result = rb_f_lambda();
 	    ruby_scope->local_vars[node->nd_cnt] = result;
-	}
-	else {
-	    result = Qnil;
-	}
-	break;
+        }
+        break;
 
       case NODE_COLON2:
-	{
-	    VALUE klass;
-
-	    klass = rb_eval(self, node->nd_head);
-	    switch (TYPE(klass)) {
-	      case T_CLASS:
-	      case T_MODULE:
-		break;
-	      default:
-		return rb_funcall(klass, node->nd_mid, 0, 0);
-	    }
-	    result = rb_const_get(klass, node->nd_mid);
-	}
-	break;
+        result = eval_colon2(self,node);
+        break;
 
       case NODE_COLON3:
-	result = rb_const_get_at(rb_cObject, node->nd_mid);
-	break;
+        result = rb_const_get_at(rb_cObject, node->nd_mid);
+        break;
 
       case NODE_NTH_REF:
-	result = rb_reg_nth_match(node->nd_nth, MATCH_DATA);
-	break;
+        result = rb_reg_nth_match(node->nd_nth, MATCH_DATA);
+        break;
 
       case NODE_BACK_REF:
-	switch (node->nd_nth) {
+        switch (node->nd_nth) {
 	  case '&':
 	    result = rb_reg_last_match(MATCH_DATA);
 	    break;
@@ -2850,400 +3276,108 @@
 	    break;
 	  default:
 	    rb_bug("unexpected back-ref");
-	}
-	break;
+        }
+        break;
 
       case NODE_HASH:
-	{
-	    NODE *list;
-	    VALUE hash = rb_hash_new();
-	    VALUE key, val;
-
-	    list = node->nd_head;
-	    while (list) {
-		key = rb_eval(self, list->nd_head);
-		list = list->nd_next;
-		if (list == 0)
-		    rb_bug("odd number list for Hash");
-		val = rb_eval(self, list->nd_head);
-		list = list->nd_next;
-		rb_hash_aset(hash, key, val);
-	    }
-	    result = hash;
-	}
-	break;
+        result = eval_hash(self,node);
+        break;
 
       case NODE_ZARRAY:		/* zero length list */
-	result = rb_ary_new();
-	break;
+        result = rb_ary_new();
+        break;
 
       case NODE_ARRAY:
-	{
-	    VALUE ary;
-	    int i;
-
-	    i = node->nd_alen;
-	    ary = rb_ary_new2(i);
-	    for (i=0;node;node=node->nd_next) {
-		RARRAY(ary)->ptr[i++] = rb_eval(self, node->nd_head);
-		RARRAY(ary)->len = i;
-	    }
-
-	    result = ary;
-	}
-	break;
+        result = eval_array(self,node);
+        break;
 
       case NODE_STR:
-	result = rb_str_new3(node->nd_lit);
-	break;
+        result = rb_str_new3(node->nd_lit);
+        break;
 
       case NODE_DSTR:
       case NODE_DXSTR:
       case NODE_DREGX:
       case NODE_DREGX_ONCE:
-	{
-	    VALUE str, str2;
-	    NODE *list = node->nd_next;
-
-	    str = rb_str_new3(node->nd_lit);
-	    if (!ruby_dyna_vars) rb_dvar_push(0, 0);
-	    while (list) {
-		if (list->nd_head) {
-		    switch (nd_type(list->nd_head)) {
-		      case NODE_STR:
-			str2 = list->nd_head->nd_lit;
-			break;
-		      case NODE_EVSTR:
-			result = ruby_errinfo;
-			ruby_errinfo = Qnil;
-			ruby_sourceline = nd_line(list->nd_head);
-			ruby_in_eval++;
-			list->nd_head = compile(list->nd_head->nd_lit,
-						ruby_sourcefile,
-						ruby_sourceline);
-			if (ruby_scope->local_tbl) {
-			    NODE *body = (NODE *)ruby_scope->scope_node;
-			    if (body && body->nd_tbl != ruby_scope->local_tbl) {
-				if (body->nd_tbl) free(body->nd_tbl);
-				ruby_scope->local_vars[-1] = (VALUE)body;
-				body->nd_tbl = ruby_scope->local_tbl;
-			    }
-			}
-			ruby_eval_tree = 0;
-			ruby_in_eval--;
-			if (ruby_nerrs > 0) {
-			    compile_error("string expansion");
-			}
-			if (!NIL_P(result)) ruby_errinfo = result;
-			/* fall through */
-		      default:
-			str2 = rb_obj_as_string(rb_eval(self, list->nd_head));
-			break;
-		    }
-		    rb_str_append(str, str2);
-		    OBJ_INFECT(str, str2);
-		}
-		list = list->nd_next;
-	    }
-	    switch (nd_type(node)) {
-	      case NODE_DREGX:
-		result = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len,
-				 node->nd_cflag);
-		break;
-	      case NODE_DREGX_ONCE:	/* regexp expand once */
-		result = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len,
-				 node->nd_cflag);
-		nd_set_type(node, NODE_LIT);
-		node->nd_lit = result;
-		break;
-	      case NODE_DXSTR:
-		result = rb_funcall(self, '`', 1, str);
-		break;
-	      default:
-		result = str;
-		break;
-	    }
-	}
-	break;
+        result = eval_regx(self,node);
+        break;
 
       case NODE_XSTR:
-	result = rb_funcall(self, '`', 1, node->nd_lit);
-	break;
+        result = rb_funcall(self, '`', 1, node->nd_lit);
+        break;
 
       case NODE_LIT:
-	result = node->nd_lit;
-	break;
+        result = node->nd_lit;
+        break;
 
       case NODE_ATTRSET:
-	if (ruby_frame->argc != 1)
+        if (ruby_frame->argc != 1)
 	    rb_raise(rb_eArgError, "wrong # of arguments(%d for 1)",
 		     ruby_frame->argc);
-	result = rb_ivar_set(self, node->nd_vid, ruby_frame->argv[0]);
-	break;
+        result = rb_ivar_set(self, node->nd_vid, ruby_frame->argv[0]);
+        break;
 
       case NODE_DEFN:
-	if (node->nd_defn) {
-	    NODE *body,  *defn;
-	    VALUE origin;
-	    int noex;
-
-	    if (NIL_P(ruby_class)) {
-		rb_raise(rb_eTypeError, "no class to add method");
-	    }
-	    if (ruby_class == rb_cObject && node->nd_mid == init) {
-		rb_warn("redefining Object#initialize may cause infinite loop");
-	    }
-	    if (node->nd_mid == __id__ || node->nd_mid == __send__) {
-		rb_warn("redefining `%s' may cause serious problem",
-			rb_id2name(node->nd_mid));
-	    }
-	    rb_frozen_class_p(ruby_class);
-	    body = search_method(ruby_class, node->nd_mid, &origin);
-	    if (body){
-		if (RTEST(ruby_verbose) && ruby_class == origin && body->nd_cnt == 0) {
-		    rb_warning("method redefined; discarding old %s", rb_id2name(node->nd_mid));
-		}
-	    }
-
-	    if (node->nd_noex == NOEX_PUBLIC) {
-		noex = NOEX_PUBLIC; 	/* means is is an attrset */
-	    }
-	    else if (SCOPE_TEST(SCOPE_PRIVATE) || node->nd_mid == init) {
-		noex = NOEX_PRIVATE;
-	    }
-	    else if (SCOPE_TEST(SCOPE_PROTECTED)) {
-		noex = NOEX_PROTECTED;
-	    }
-	    else {
-		noex = NOEX_PUBLIC;
-	    }
-	    if (body && origin == ruby_class && body->nd_noex & NOEX_UNDEF) {
-		noex |= NOEX_UNDEF;
-	    }
-
-	    defn = copy_node_scope(node->nd_defn, ruby_cref);
-	    rb_add_method(ruby_class, node->nd_mid, defn, noex);
-	    if (scope_vmode == SCOPE_MODFUNC) {
-		rb_add_method(rb_singleton_class(ruby_class),
-			      node->nd_mid, defn, NOEX_PUBLIC);
-		rb_funcall(ruby_class, singleton_added, 1, ID2SYM(node->nd_mid));
-	    }
-	    if (FL_TEST(ruby_class, FL_SINGLETON)) {
-		rb_funcall(rb_iv_get(ruby_class, "__attached__"),
-			   singleton_added, 1, ID2SYM(node->nd_mid));
-	    }
-	    else {
-		rb_funcall(ruby_class, added, 1, ID2SYM(node->nd_mid));
-	    }
-	    result = Qnil;
-	}
-	break;
+        if (node->nd_defn) 
+          result = eval_defn(self,node);
+        break;
 
       case NODE_DEFS:
-	if (node->nd_defn) {
-	    VALUE recv = rb_eval(self, node->nd_recv);
-	    VALUE klass;
-	    NODE *body = 0, *defn;
-
-	    if (rb_safe_level() >= 4 && !OBJ_TAINTED(recv)) {
-		rb_raise(rb_eSecurityError, "Insecure: can't define singleton method");
-	    }
-	    if (FIXNUM_P(recv) || SYMBOL_P(recv)) {
-		rb_raise(rb_eTypeError,
-			 "can't define singleton method \"%s\" for %s",
-			 rb_id2name(node->nd_mid),
-			 rb_class2name(CLASS_OF(recv)));
-	    }
-
-	    if (OBJ_FROZEN(recv)) rb_error_frozen("object");
-	    klass = rb_singleton_class(recv);
-	    if (st_lookup(RCLASS(klass)->m_tbl, node->nd_mid, &body)) {
-		if (rb_safe_level() >= 4) {
-		    rb_raise(rb_eSecurityError, "redefining method prohibited");
-		}
-		if (RTEST(ruby_verbose)) {
-		    rb_warning("redefine %s", rb_id2name(node->nd_mid));
-		}
-	    }
-	    defn = copy_node_scope(node->nd_defn, ruby_cref);
-	    defn->nd_rval = (VALUE)ruby_cref;
-	    rb_add_method(klass, node->nd_mid, defn, 
-			  NOEX_PUBLIC|(body?body->nd_noex&NOEX_UNDEF:0));
-	    rb_funcall(recv, singleton_added, 1, ID2SYM(node->nd_mid));
-	    result = Qnil;
-	}
-	break;
+        if (node->nd_defn) 
+          result = eval_defs(self,node);
+        break;
 
       case NODE_UNDEF:
-	if (NIL_P(ruby_class)) {
+        if (NIL_P(ruby_class)) {
 	    rb_raise(rb_eTypeError, "no class to undef method");
-	}
-	rb_undef(ruby_class, node->nd_mid);
-	result = Qnil;
-	break;
+        }
+        rb_undef(ruby_class, node->nd_mid);
+        break;
 
       case NODE_ALIAS:
-	if (NIL_P(ruby_class)) {
+        if (NIL_P(ruby_class)) {
 	    rb_raise(rb_eTypeError, "no class to make alias");
-	}
-	rb_alias(ruby_class, node->nd_new, node->nd_old);
-	rb_funcall(ruby_class, added, 1, ID2SYM(node->nd_mid));
-	result = Qnil;
-	break;
+        }
+        rb_alias(ruby_class, node->nd_new, node->nd_old);
+        rb_funcall(ruby_class, added, 1, ID2SYM(node->nd_mid));
+        break;
 
       case NODE_VALIAS:
-	rb_alias_variable(node->nd_new, node->nd_old);
-	result = Qnil;
-	break;
+        rb_alias_variable(node->nd_new, node->nd_old);
+        break;
 
       case NODE_CLASS:
-	{
-	    VALUE super, klass, tmp;
-
-	    if (NIL_P(ruby_class)) {
-		rb_raise(rb_eTypeError, "no outer class/module");
-	    }
-	    if (node->nd_super) {
-		super = superclass(self, node->nd_super);
-	    }
-	    else {
-		super = 0;
-	    }
-
-	    if ((ruby_class == rb_cObject) && rb_autoload_defined(node->nd_cname)) {
-		rb_autoload_load(node->nd_cname);
-	    }
-	    if (rb_const_defined_at(ruby_class, node->nd_cname)) {
-		klass = rb_const_get(ruby_class, node->nd_cname);
-		if (TYPE(klass) != T_CLASS) {
-		    rb_raise(rb_eTypeError, "%s is not a class",
-			     rb_id2name(node->nd_cname));
-		}
-		if (super) {
-		    tmp = rb_class_real(RCLASS(klass)->super);
-		    if (tmp != super) {
-			goto override_class;
-		    }
-		}
-		if (rb_safe_level() >= 4) {
-		    rb_raise(rb_eSecurityError, "extending class prohibited");
-		}
-		rb_clear_cache();
-	    }
-	    else {
-	      override_class:
-		if (!super) super = rb_cObject;
-		klass = rb_define_class_id(node->nd_cname, super);
-		rb_set_class_path(klass,ruby_class,rb_id2name(node->nd_cname));
-		rb_class_inherited(super, klass);
-		rb_const_set(ruby_class, node->nd_cname, klass);
-	    }
-	    if (ruby_wrapper) {
-		rb_extend_object(klass, ruby_wrapper);
-		rb_include_module(klass, ruby_wrapper);
-	    }
-
-	    result = module_setup(klass, node->nd_body);
-	}
-	break;
+        result = eval_class(self,node);
+        break;
 
       case NODE_MODULE:
-	{
-	    VALUE module;
-
-	    if (NIL_P(ruby_class)) {
-		rb_raise(rb_eTypeError, "no outer class/module");
-	    }
-	    if ((ruby_class == rb_cObject) && rb_autoload_defined(node->nd_cname)) {
-		rb_autoload_load(node->nd_cname);
-	    }
-	    if (rb_const_defined_at(ruby_class, node->nd_cname)) {
-		module = rb_const_get(ruby_class, node->nd_cname);
-		if (TYPE(module) != T_MODULE) {
-		    rb_raise(rb_eTypeError, "%s is not a module",
-			     rb_id2name(node->nd_cname));
-		}
-		if (rb_safe_level() >= 4) {
-		    rb_raise(rb_eSecurityError, "extending module prohibited");
-		}
-	    }
-	    else {
-		module = rb_define_module_id(node->nd_cname);
-		rb_set_class_path(module,ruby_class,rb_id2name(node->nd_cname));
-		rb_const_set(ruby_class, node->nd_cname, module);
-	    }
-	    if (ruby_wrapper) {
-		rb_extend_object(module, ruby_wrapper);
-		rb_include_module(module, ruby_wrapper);
-	    }
-
-	    result = module_setup(module, node->nd_body);
-	}
-	break;
+        result = eval_module(self,node);
+        break;
 
       case NODE_SCLASS:
-	{
-	    VALUE klass;
-
-	    result = rb_eval(self, node->nd_recv);
-	    if (result == Qtrue) {
-		klass = rb_cTrueClass;
-	    }
-	    else if (result == Qfalse) {
-		klass = rb_cTrueClass;
-	    }
-	    else if (result == Qnil) {
-		klass = rb_cNilClass;
-	    }
-	    else {
-		if (rb_special_const_p(result)) {
-		    rb_raise(rb_eTypeError, "no virtual class for %s",
-			     rb_class2name(CLASS_OF(result)));
-		}
-		if (rb_safe_level() >= 4 && !OBJ_TAINTED(result))
-		    rb_raise(rb_eSecurityError, "Insecure: can't extend object");
-		if (FL_TEST(CLASS_OF(result), FL_SINGLETON)) {
-		    rb_clear_cache();
-		}
-		klass = rb_singleton_class(result);
-	    }
-	    
-	    if (ruby_wrapper) {
-		rb_extend_object(klass, ruby_wrapper);
-		rb_include_module(klass, ruby_wrapper);
-	    }
-	    
-	    result = module_setup(klass, node->nd_body);
-	}
-	break;
+        result = eval_sclass(self,node);
+        break;
 
       case NODE_DEFINED:
-	{
-	    char buf[20];
-	    char *desc = is_defined(self, node->nd_head, buf);
-
-	    if (desc) result = rb_str_new2(desc);
-	    else result = Qnil;
-	}
-	break;
+        result = eval_defined(self,node);
+        break;
 
     case NODE_NEWLINE:
-	ruby_sourcefile = node->nd_file;
-	ruby_sourceline = node->nd_nth;
-	if (trace_func) {
+        ruby_sourcefile = node->nd_file;
+        ruby_sourceline = node->nd_nth;
+        if (trace_func) {
 	    call_trace_func("line", ruby_sourcefile, ruby_sourceline, self,
 			    ruby_frame->last_func,
 			    ruby_frame->last_class);	
-	}
-	node = node->nd_next;
-	goto again;
+        }
+        node = node->nd_next;
+        goto again;
 
       default:
-	rb_bug("unknown node type %d", nd_type(node));
+        rb_bug("unknown node type %d", nd_type(node));
     }
-  finish:
-    CHECK_INTS;
-    return result;
+  }
+  return result;
 }
 
 static VALUE
@@ -3254,9 +3388,9 @@
     NODE * volatile node = n;
     int state;
     struct FRAME frame;
-    VALUE result;		/* OK */
-    char *file = ruby_sourcefile;
-    int line = ruby_sourceline;
+    VALUE result;
+    char *volatile file = ruby_sourcefile;
+    volatile int line = ruby_sourceline;
     TMP_PROTECT;
 
     frame = *ruby_frame;
@@ -3557,18 +3691,21 @@
 
 static VALUE
 rb_yield_0(val, self, klass, acheck)
-    VALUE val, self, klass;	/* OK */
+    volatile VALUE val, self;
+    VALUE klass;
     int acheck;
 {
-    NODE *node;
+    char *volatile const file = ruby_sourcefile;
+    volatile int line = ruby_sourceline;
+    
     volatile VALUE result = Qnil;
+  
+    NODE *volatile node;
     volatile VALUE old_cref;
     volatile VALUE old_wrapper;
     struct BLOCK * volatile block;
     struct SCOPE * volatile old_scope;
     struct FRAME frame;
-    char *const file = ruby_sourcefile;
-    int line = ruby_sourceline;
     int state;
     static unsigned serial = 1;
 
@@ -3637,8 +3774,11 @@
 
     PUSH_ITER(block->iter);
     PUSH_TAG(PROT_NONE);
-    if ((state = EXEC_TAG()) == 0) {
-      redo:
+    switch (state = EXEC_TAG()) {
+      case TAG_REDO:
+	state = 0;
+	CHECK_INTS;
+      case 0:
 	if (!node) {
 	    result = Qnil;
 	}
@@ -3649,26 +3789,19 @@
 	else {
 	    result = rb_eval(self, node);
 	}
-    }
-    else {
-	switch (state) {
-	  case TAG_REDO:
-	    state = 0;
-	    CHECK_INTS;
-	    goto redo;
-	  case TAG_NEXT:
-	    state = 0;
-	    result = Qnil;
-	    break;
-	  case TAG_BREAK:
-	  case TAG_RETURN:
-	    state |= (serial++ << 8);
-	    state |= 0x10;
-	    block->tag->dst = state;
-	    break;
-	  default:
-	    break;
-	}
+        break;
+
+      case TAG_NEXT:
+	state = 0;
+	result = Qnil;
+	break;
+
+      case TAG_BREAK:
+      case TAG_RETURN:
+	state |= (serial++ << 8);
+	state |= 0x10;
+	block->tag->dst = state;
+	break;
     }
     POP_TAG();
     POP_ITER();
@@ -3735,6 +3868,7 @@
 rb_yield(val)
     VALUE val;
 {
+    wipeBeforeYield();
     return rb_yield_0(val, 0, 0, 0);
 }
 
@@ -3742,6 +3876,7 @@
 rb_f_loop()
 {
     for (;;) {
+        wipeBeforeYield();
 	rb_yield_0(Qnil, 0, 0, 0);
 	CHECK_INTS;
     }
@@ -3863,17 +3998,14 @@
 
       case NODE_CALL:
 	{
-	    VALUE recv;
-	    recv = rb_eval(self, lhs->nd_recv);
+	    VALUE recv = rb_eval(self, lhs->nd_recv);
 	    if (!lhs->nd_args) {
 		/* attr set */
 		rb_call(CLASS_OF(recv), recv, lhs->nd_mid, 1, &val, 0);
 	    }
 	    else {
 		/* array set */
-		VALUE args;
-
-		args = rb_eval(self, lhs->nd_args);
+		VALUE args = rb_eval(self, lhs->nd_args);
 		rb_ary_push(args, val);
 		rb_call(CLASS_OF(recv), recv, lhs->nd_mid,
 			RARRAY(args)->len, RARRAY(args)->ptr, 0);
@@ -3889,11 +4021,12 @@
 
 VALUE
 rb_iterate(it_proc, data1, bl_proc, data2)
-    VALUE (*it_proc)(), (*bl_proc)();
-    VALUE data1, data2;
+    VALUE (* volatile it_proc)(), (*bl_proc)();
+    volatile VALUE data1;
+    VALUE data2;
 {
     int state;
-    volatile VALUE retval = Qnil;
+    VALUE retval;
     NODE *node = NEW_IFUNC(bl_proc, data2);
     VALUE self = ruby_top_self;
 
@@ -3903,9 +4036,7 @@
     PUSH_TAG(PROT_NONE);
 
     state = EXEC_TAG();
-    if (state == 0) {
-	retval = (*it_proc)(data1);
-    }
+    retval = state ? Qnil : (*it_proc)(data1);
     if (ruby_block->tag->dst == state) {
 	state &= TAG_MASK;
 	if (state == TAG_RETURN) {
@@ -3964,16 +4095,17 @@
 
 VALUE
 #ifdef HAVE_STDARG_PROTOTYPES
-rb_rescue2(VALUE (*b_proc)(), VALUE data1, VALUE (*r_proc)(), VALUE data2, ...)
+rb_rescue2(VALUE (* volatile b_proc)(ANYARGS), volatile VALUE data1, 
+           VALUE (* volatile r_proc)(ANYARGS), volatile VALUE data2, ...)
 #else
 rb_rescue2(b_proc, data1, r_proc, data2, va_alist)
-    VALUE (*b_proc)(), (*r_proc)();
-    VALUE data1, data2;
+    VALUE (* volatile b_proc)(ANYARGS), (* volatile r_proc)(ANYARGS);
+    volatile VALUE data1, data2;
     va_dcl
 #endif
 {
     int state;
-    volatile VALUE result;
+    VALUE result;
     volatile VALUE e_info = ruby_errinfo;
     va_list args;
 
@@ -4035,9 +4167,9 @@
 rb_protect(proc, data, state)
     VALUE (*proc)();
     VALUE data;
-    int *state;
+    int *volatile state;
 {
-    VALUE result;		/* OK */
+    VALUE result;
     int status;
 
     PUSH_TAG(PROT_NONE);
@@ -4048,21 +4180,18 @@
     if (state) {
 	*state = status;
     }
-    if (status != 0) {
-	return Qnil;
-    }
-
-    return result;
+    return status ? Qnil : result;
 }
 
 VALUE
 rb_ensure(b_proc, data1, e_proc, data2)
     VALUE (*b_proc)();
-    VALUE (*e_proc)();
-    VALUE data1, data2;
+    VALUE data1;
+    VALUE (* volatile e_proc)();
+    volatile VALUE data2;
 {
     int state;
-    volatile VALUE result = Qnil;
+    VALUE result;
     VALUE retval;
 
     PUSH_TAG(PROT_NONE);
@@ -4070,7 +4199,7 @@
 	result = (*b_proc)(data1);
     }
     POP_TAG();
-    retval = prot_tag ? prot_tag->retval : Qnil;	/* save retval */
+    if (prot_tag) retval = prot_tag->retval;  /* save retval */
     (*e_proc)(data2);
     if (prot_tag) return_value(retval);
 
@@ -4083,7 +4212,7 @@
     VALUE (*proc)();
     VALUE data;
 {
-    VALUE result;		/* OK */
+    VALUE result;
     int status;
 
     DEFER_INTS;
@@ -4205,54 +4334,11 @@
     return rb_funcall2(obj, missing, argc+1, nargv);
 }
 
-#ifdef DJGPP
-static unsigned int STACK_LEVEL_MAX = 65535;
-#else
-#ifdef __human68k__
-extern unsigned int _stacksize;
-# define STACK_LEVEL_MAX (_stacksize - 4096)
-#undef HAVE_GETRLIMIT
-#else
-#ifdef HAVE_GETRLIMIT
-static unsigned int STACK_LEVEL_MAX = 655300;
-#else
-# define STACK_LEVEL_MAX 655300
-#endif
-#endif
-#endif
-
-extern VALUE *rb_gc_stack_start;
-static int
-stack_length(p)
-    VALUE **p;
-{
-#ifdef C_ALLOCA
-    VALUE stack_end;
-    alloca(0);
-# define STACK_END (&stack_end)
-#else
-# if defined(__GNUC__) && (defined(__i386__) || defined(__m68k__))
-    VALUE *stack_end = __builtin_frame_address(0);
-# else
-    VALUE *stack_end = alloca(1);
-# endif
-# define STACK_END (stack_end)
-#endif
-    if (p) *p = STACK_END;
-
-#if defined(sparc) || defined(__sparc__)
-    return rb_gc_stack_start - STACK_END + 0x80;
-#else
-    return (STACK_END < rb_gc_stack_start) ? rb_gc_stack_start - STACK_END
-	                                   : STACK_END - rb_gc_stack_start;
-#endif
-}
-
 void
 rb_stack_check()
 {
     static int overflowing = 0;
-    if (!overflowing && stack_length(0) > STACK_LEVEL_MAX) {
+    if (!overflowing && ruby_stack_check()) {
 	int state;
 	overflowing = 1;
 	PUSH_TAG(PROT_NONE);
@@ -4347,12 +4433,202 @@
 		       argv[11], argv[12], argv[13], argv[14]);
 	break;
       default:
-	rb_raise(rb_eArgError, "too many arguments(%d)", len);
+	rb_raise(rb_eArgError, "too many arguments(%d)", len);
+	break;
+    }
+    return Qnil;		/* not reached */
+}
+
+
+static VALUE 
+call0scope (klass, recv, id, argc, argv, body, flags)
+    VALUE klass, recv;
+    ID    id;
+    int argc;			/* OK */
+    VALUE *argv;		/* OK */
+    NODE *body;			/* OK */
+    int flags;
+{
+    int state;
+    VALUE *local_vars;	/* OK */
+    NODE *volatile saved_cref = 0;
+    NODE *b2;
+    VALUE result;
+    volatile int safe = -1;
+
+    PUSH_SCOPE();
+    if (body->nd_rval) {
+	saved_cref = ruby_cref;
+	ruby_cref = (NODE*)body->nd_rval;
+	ruby_frame->cbase = body->nd_rval;
+    }
+    ruby_scope->scope_node = (VALUE)body;
+    if (body->nd_tbl) {
+	local_vars = TMP_ALLOC(body->nd_tbl[0]+1);
+	*local_vars++ = (VALUE)body;
+	rb_mem_clear(local_vars, body->nd_tbl[0]);
+	ruby_scope->local_tbl = body->nd_tbl;
+	ruby_scope->local_vars = local_vars;
+    }
+    else {
+	local_vars = ruby_scope->local_vars = 0;
+	ruby_scope->local_tbl  = 0;
+    }
+    b2 = body = body->nd_next;
+
+    if (NOEX_SAFE(flags) > ruby_safe_level) {
+	if (!(flags&NOEX_TAINTED) && ruby_safe_level == 0 && NOEX_SAFE(flags) > 2) {
+	    rb_raise(rb_eSecurityError, "calling insecure method: %s",
+		     rb_id2name(id));
+	}
+	safe = ruby_safe_level;
+	ruby_safe_level = NOEX_SAFE(flags);
+    }
+    PUSH_VARS();
+    PUSH_TAG(PROT_FUNC);
+    if ((state = EXEC_TAG()) == 0) {
+	NODE *node = 0;
+	int i;
+
+	if (nd_type(body) == NODE_ARGS) {
+	    node = body;
+	    body = 0;
+	}
+	else if (nd_type(body) == NODE_BLOCK) {
+	    node = body->nd_head;
+	    body = body->nd_next;
+	}
+	if (node) {
+	    if (nd_type(node) != NODE_ARGS) {
+		rb_bug("no argument-node");
+	    }
+
+	    i = node->nd_cnt;
+	    if (i > argc) {
+		rb_raise(rb_eArgError, "wrong # of arguments(%d for %d)",
+			 argc, i);
+	    }
+	    if (node->nd_rest == -1) {
+		int opt = i;
+		NODE *optnode = node->nd_opt;
+
+		while (optnode) {
+		    opt++;
+		    optnode = optnode->nd_next;
+		}
+		if (opt < argc) {
+		    rb_raise(rb_eArgError, "wrong # of arguments(%d for %d)",
+			     argc, opt);
+		}
+		ruby_frame->argc = opt;
+		ruby_frame->argv = local_vars+2;
+	    }
+
+	    if (local_vars) {
+		if (i > 0) {
+		    /* +2 for $_ and $~ */
+		    MEMCPY(local_vars+2, argv, VALUE, i);
+		}
+		argv += i; argc -= i;
+		if (node->nd_opt) {
+		    NODE *opt = node->nd_opt;
+
+		    while (opt && argc) {
+			assign(recv, opt->nd_head, *argv, 1);
+			argv++; argc--;
+			opt = opt->nd_next;
+		    }
+		    if (opt) {
+			ruby_sourcefile = opt->nd_file;
+			ruby_sourceline = nd_line(opt);
+			rb_eval(recv, opt);
+		    }
+		}
+		if (node->nd_rest >= 0) {
+		    VALUE v;
+
+		    if (argc > 0)
+			v = rb_ary_new4(argc,argv);
+		    else
+			v = rb_ary_new2(0);
+		    ruby_scope->local_vars[node->nd_rest] = v;
+		}
+	    }
+	}
+
+	if (trace_func) {
+	    char *file = b2->nd_file;
+	    int line = nd_line(b2);
+	    call_trace_func("call", file, line, recv, id, klass);
+	    ruby_sourcefile = file;
+	    ruby_sourceline = line;
+	}
+	result = rb_eval(recv, body);
+    }
+    else if (state == TAG_RETURN) {
+	result = prot_tag->retval;
+	state = 0;
+    }
+    if (safe >= 0) ruby_safe_level = safe;
+    POP_TAG();
+    POP_VARS();
+    POP_SCOPE();
+    ruby_cref = saved_cref;
+    if (trace_func) {
+	char *file = ruby_frame->prev->file;
+	int line = ruby_frame->prev->line;
+	if (!file) {
+	    file = ruby_sourcefile;
+	    line = ruby_sourceline;
+	}
+	call_trace_func("return", file, line, recv, id, klass);
+    }
+    switch (state) {
+      case 0:
+	break;
+
+      case TAG_RETRY:
+	if (rb_block_given_p()) {
+           JUMP_TAG(state);
+	}
+	/* fall through */
+      default:
+	jump_tag_but_local_jump(state);
 	break;
     }
-    return Qnil;		/* not reached */
+  return result;
+}
+
+
+static VALUE 
+call0ctrace (klass, recv, id, argc, argv, body, len)
+    VALUE klass, recv;
+    ID    id;
+    int argc;			/* OK */
+    VALUE *argv;		/* OK */
+    NODE *body;			/* OK */
+    int len;
+{
+    int state;
+    char *file = ruby_frame->prev->file;
+    int line = ruby_frame->prev->line;
+    volatile VALUE result = Qnil;
+    if (!file) {
+	file = ruby_sourcefile;
+	line = ruby_sourceline;
+    }
+
+    call_trace_func("c-call", 0, 0, recv, id, klass);
+    PUSH_TAG(PROT_FUNC);
+    if ((state = EXEC_TAG()) == 0)
+      result = call_cfunc(body->nd_cfnc, recv, len, argc, argv);
+    POP_TAG();
+    call_trace_func("c-return", 0, 0, recv, id, klass);
+    if (state) JUMP_TAG(state);
+    return result;
 }
 
+
 static VALUE
 rb_call0(klass, recv, id, argc, argv, body, flags)
     VALUE klass, recv;
@@ -4362,12 +4638,11 @@
     NODE *body;			/* OK */
     int flags;
 {
-    NODE *b2;		/* OK */
-    volatile VALUE result = Qnil;
-    int itr;
     static int tick;
+    int itr;
+    VALUE result;
+
     TMP_PROTECT;
-    volatile int safe = -1;
 
     switch (ruby_iter->iter) {
       case ITER_PRE:
@@ -4401,27 +4676,9 @@
 		rb_bug("bad argc(%d) specified for `%s(%s)'",
 		       len, rb_class2name(klass), rb_id2name(id));
 	    }
-	    if (trace_func) {
-		int state;
-		char *file = ruby_frame->prev->file;
-		int line = ruby_frame->prev->line;
-		if (!file) {
-		    file = ruby_sourcefile;
-		    line = ruby_sourceline;
-		}
-
-		call_trace_func("c-call", 0, 0, recv, id, klass);
-		PUSH_TAG(PROT_FUNC);
-		if ((state = EXEC_TAG()) == 0) {
-		    result = call_cfunc(body->nd_cfnc, recv, len, argc, argv);
-		}
-		POP_TAG();
-		call_trace_func("c-return", 0, 0, recv, id, klass);
-		if (state) JUMP_TAG(state);
-	    }
-	    else {
-		result = call_cfunc(body->nd_cfnc, recv, len, argc, argv);
-	    }
+	    result = trace_func ?
+	      call0ctrace(klass, recv, id, argc, argv, body, len) :
+	      call_cfunc(body->nd_cfnc, recv, len, argc, argv);
 	}
 	break;
 
@@ -4445,152 +4702,7 @@
 	break;
 
       case NODE_SCOPE:
-	{
-	    int state;
-	    VALUE *local_vars;	/* OK */
-	    NODE *saved_cref = 0;
-
-	    PUSH_SCOPE();
-	    if (body->nd_rval) {
-		saved_cref = ruby_cref;
-		ruby_cref = (NODE*)body->nd_rval;
-		ruby_frame->cbase = body->nd_rval;
-	    }
-	    ruby_scope->scope_node = (VALUE)body;
-	    if (body->nd_tbl) {
-		local_vars = TMP_ALLOC(body->nd_tbl[0]+1);
-		*local_vars++ = (VALUE)body;
-		rb_mem_clear(local_vars, body->nd_tbl[0]);
-		ruby_scope->local_tbl = body->nd_tbl;
-		ruby_scope->local_vars = local_vars;
-	    }
-	    else {
-		local_vars = ruby_scope->local_vars = 0;
-		ruby_scope->local_tbl  = 0;
-	    }
-	    b2 = body = body->nd_next;
-
-	    if (NOEX_SAFE(flags) > ruby_safe_level) {
-		if (!(flags&NOEX_TAINTED) && ruby_safe_level == 0 && NOEX_SAFE(flags) > 2) {
-		    rb_raise(rb_eSecurityError, "calling insecure method: %s",
-			     rb_id2name(id));
-		}
-		safe = ruby_safe_level;
-		ruby_safe_level = NOEX_SAFE(flags);
-	    }
-	    PUSH_VARS();
-	    PUSH_TAG(PROT_FUNC);
-	    if ((state = EXEC_TAG()) == 0) {
-		NODE *node = 0;
-		int i;
-
-		if (nd_type(body) == NODE_ARGS) {
-		    node = body;
-		    body = 0;
-		}
-		else if (nd_type(body) == NODE_BLOCK) {
-		    node = body->nd_head;
-		    body = body->nd_next;
-		}
-		if (node) {
-		    if (nd_type(node) != NODE_ARGS) {
-			rb_bug("no argument-node");
-		    }
-
-		    i = node->nd_cnt;
-		    if (i > argc) {
-			rb_raise(rb_eArgError, "wrong # of arguments(%d for %d)",
-				 argc, i);
-		    }
-		    if (node->nd_rest == -1) {
-			int opt = i;
-			NODE *optnode = node->nd_opt;
-
-			while (optnode) {
-			    opt++;
-			    optnode = optnode->nd_next;
-			}
-			if (opt < argc) {
-			    rb_raise(rb_eArgError, "wrong # of arguments(%d for %d)",
-				     argc, opt);
-			}
-			ruby_frame->argc = opt;
-			ruby_frame->argv = local_vars+2;
-		    }
-
-		    if (local_vars) {
-			if (i > 0) {
-			    /* +2 for $_ and $~ */
-			    MEMCPY(local_vars+2, argv, VALUE, i);
-			}
-			argv += i; argc -= i;
-			if (node->nd_opt) {
-			    NODE *opt = node->nd_opt;
-
-			    while (opt && argc) {
-				assign(recv, opt->nd_head, *argv, 1);
-				argv++; argc--;
-				opt = opt->nd_next;
-			    }
-			    if (opt) {
-				ruby_sourcefile = opt->nd_file;
-				ruby_sourceline = nd_line(opt);
-				rb_eval(recv, opt);
-			    }
-			}
-			if (node->nd_rest >= 0) {
-			    VALUE v;
-
-			    if (argc > 0)
-				v = rb_ary_new4(argc,argv);
-			    else
-				v = rb_ary_new2(0);
-			    ruby_scope->local_vars[node->nd_rest] = v;
-			}
-		    }
-		}
-
-		if (trace_func) {
-		    char *file = b2->nd_file;
-		    int line = nd_line(b2);
-		    call_trace_func("call", file, line, recv, id, klass);
-		    ruby_sourcefile = file;
-		    ruby_sourceline = line;
-		}
-		result = rb_eval(recv, body);
-	    }
-	    else if (state == TAG_RETURN) {
-		result = prot_tag->retval;
-		state = 0;
-	    }
-	    if (safe >= 0) ruby_safe_level = safe;
-	    POP_TAG();
-	    POP_VARS();
-	    POP_SCOPE();
-	    ruby_cref = saved_cref;
-	    if (trace_func) {
-		char *file = ruby_frame->prev->file;
-		int line = ruby_frame->prev->line;
-		if (!file) {
-		    file = ruby_sourcefile;
-		    line = ruby_sourceline;
-		}
-		call_trace_func("return", file, line, recv, id, klass);
-	    }
-	    switch (state) {
-	      case 0:
-		break;
-
-	      case TAG_RETRY:
-		if (rb_block_given_p()) {
-                   JUMP_TAG(state);
-		}
-		/* fall through */
-	      default:
-		jump_tag_but_local_jump(state);
-		break;
-	    }
-	}
+      	result = call0scope(klass, recv, id, argc, argv, body, flags);
 	break;
 
       default:
@@ -4599,7 +4711,7 @@
     }
     POP_FRAME();
     POP_ITER();
-    return result;
+  return result;
 }
 
 static VALUE
@@ -4876,12 +4988,13 @@
 
 static VALUE
 eval(self, src, scope, file, line)
-    VALUE self, src, scope;
-    char *file;
+    VALUE self, src;
+    volatile VALUE scope;
+    char * volatile file;
     int line;
 {
     struct BLOCK *data;
-    volatile VALUE result = Qnil;
+    VALUE result;
     struct SCOPE * volatile old_scope;
     struct BLOCK * volatile old_block;
     struct RVarmap * volatile old_dyna_vars;
@@ -4889,8 +5002,8 @@
     int volatile old_vmode;
     volatile VALUE old_wrapper;
     struct FRAME frame;
-    char *filesave = ruby_sourcefile;
-    int linesave = ruby_sourceline;
+    char *volatile filesave = ruby_sourcefile;
+    volatile int linesave = ruby_sourceline;
     volatile int iter = ruby_frame->iter;
     int state;
 
@@ -4953,7 +5066,7 @@
 	    compile_error(0);
 	}
 	if (!NIL_P(result)) ruby_errinfo = result;
-	result = eval_node(self, node); 
+	result = eval_tree(self, node); 
     }
     POP_TAG();
     POP_CLASS();
@@ -4975,6 +5088,7 @@
 
            scope_dup(ruby_scope);
 	   for (tag=prot_tag; tag; tag=tag->prev) {
+               if (tag->tag == PROT_THREAD) break;
 	       scope_dup(tag->scope);
 	   }
 	   if (ruby_block) {
@@ -5068,12 +5182,13 @@
 static VALUE
 exec_under(func, under, cbase, args)
     VALUE (*func)();
-    VALUE under, cbase;
+    VALUE under;
+    volatile VALUE cbase;
     void *args;
 {
-    VALUE val;			/* OK */
+    VALUE val;
     int state;
-    int mode;
+    volatile int mode;
 
     PUSH_CLASS();
     ruby_class = under;
@@ -5226,8 +5341,8 @@
     int state;
     volatile ID last_func;
     volatile VALUE wrapper = 0;
-    volatile VALUE self = ruby_top_self;
-    NODE *saved_cref = ruby_cref;
+    VALUE self = ruby_top_self;
+    NODE *volatile saved_cref = ruby_cref;
     TMP_PROTECT;
 
     if (wrap && ruby_safe_level >= 4) {
@@ -5281,7 +5396,7 @@
 	node = ruby_eval_tree;
 	ALLOW_INTS;
 	if (ruby_nerrs == 0) {
-	    eval_node(self, node);
+	    eval_tree(self, node);
 	}
     }
     ruby_frame->last_func = last_func;
@@ -5310,7 +5425,7 @@
 rb_load_protect(fname, wrap, state)
     VALUE fname;
     int wrap;
-    int *state;
+    int *volatile state;
 {
     int status;
 
@@ -5376,7 +5491,6 @@
 		    return Qtrue;
 		}
 		CHECK_INTS;
-		rb_thread_schedule();
 	    }
 	}
     }
@@ -5424,7 +5538,8 @@
     VALUE obj, fname;
 {
     VALUE feature, tmp;
-    char *ext, *ftptr; /* OK */
+    char *ext;
+    char *volatile ftptr;
     volatile VALUE load;
     int state;
     volatile int safe = ruby_safe_level;
@@ -5920,7 +6035,7 @@
     POP_ITER();
 }
 
-static void
+static void noinline
 rb_f_END()
 {
     PUSH_FRAME();
@@ -6063,19 +6178,6 @@
     rb_global_variable(&trace_func);
 
     rb_define_virtual_variable("$SAFE", safe_getter, safe_setter);
-
-#ifdef HAVE_GETRLIMIT
-    {
-	struct rlimit rlim;
-
-	if (getrlimit(RLIMIT_STACK, &rlim) == 0) {
-	    double space = (double)rlim.rlim_cur*0.2;
-
-	    if (space > 1024*1024) space = 1024*1024;
-	    STACK_LEVEL_MAX = (rlim.rlim_cur - space) / sizeof(VALUE);
-	}
-    }
-#endif
 }
 
 VALUE rb_f_autoload();
@@ -6417,12 +6519,12 @@
 
 static VALUE
 proc_call(proc, args)
-    VALUE proc, args;		/* OK */
+    VALUE proc, args;
 {
     struct BLOCK * volatile old_block;
     struct BLOCK _block;
     struct BLOCK *data;
-    volatile VALUE result = Qnil;
+    VALUE result;
     int state;
     volatile int orphan;
     volatile int safe = ruby_safe_level;
@@ -6466,21 +6568,21 @@
     ruby_wrapper = old_wrapper;
     ruby_safe_level = safe;
 
-    if (state) {
-	switch (state) {
-	  case TAG_BREAK:
-	    break;
-	  case TAG_RETRY:
-	    rb_raise(rb_eLocalJumpError, "retry from proc-closure");
-	    break;
-	  case TAG_RETURN:
-	    if (orphan) {	/* orphan procedure */
-		rb_raise(rb_eLocalJumpError, "return from proc-closure");
-	    }
-	    /* fall through */
-	  default:
-	    JUMP_TAG(state);
+    switch (state) {
+      case TAG_BREAK:
+        result = Qnil;
+      case 0:
+	break;
+      case TAG_RETRY:
+	rb_raise(rb_eLocalJumpError, "retry from proc-closure");
+	break;
+      case TAG_RETURN:
+	if (orphan) {	/* orphan procedure */
+	    rb_raise(rb_eLocalJumpError, "return from proc-closure");
 	}
+	/* fall through */
+      default:
+	JUMP_TAG(state);
     }
     return result;
 }
@@ -6549,11 +6651,11 @@
     VALUE self;
     NODE *node;
 {
-    VALUE block = rb_eval(self, node->nd_body);	/* OK */
+    VALUE block = rb_eval(self, node->nd_body);
     struct BLOCK * volatile old_block;
     struct BLOCK _block;
     struct BLOCK *data;
-    volatile VALUE result = Qnil;
+    VALUE result;
     int state;
     volatile int orphan;
     volatile int safe = ruby_safe_level;
@@ -6989,6 +7091,99 @@
     return body;
 }
 
+/*
+ * call-seq:
+ *    meth.__file__  => String  
+ *
+ * returns the ruby source filename containing this method's definition
+ * raises ArgumentError if this method was not defined in ruby (i.e. native)
+ */
+ 
+static VALUE
+method_source_file_name(VALUE method)
+{
+    struct METHOD *data;
+    NODE *node;
+
+    Data_Get_Struct(method, struct METHOD, data);   
+    if (node = data->body) {
+      const char *filename = node->nd_file;
+      if (filename)
+        return rb_str_new2(filename);
+    }
+    rb_raise(rb_eArgError, "native Method");
+}
+
+/*
+ * call-seq:
+ *    meth.__line__  => Fixnum  
+ *
+ * returns the starting ruby source lineno of this method of nil if unknown
+ * raises ArgumentError if this method was not defined in ruby (i.e. native)
+ */
+ 
+
+static VALUE
+method_source_line(VALUE method)
+{
+    struct METHOD *data;
+    NODE *node;
+
+    Data_Get_Struct(method, struct METHOD, data);
+    if (node = data->body) {
+      int lineno = nd_line(node);
+      if (lineno)
+        return INT2FIX(nd_line(node));
+    }
+    rb_raise(rb_eArgError, "native Method");
+}
+
+
+
+/*
+ * call-seq:
+ *    prc.__file__  => String  
+ *
+ * returns the ruby source filename containing this proc
+ *         or nil for proc{}
+ * raises ArgumentError if this proc was not defined in ruby (i.e. native)
+ */
+ 
+static VALUE
+proc_source_file_name(VALUE block)
+{
+    struct BLOCK *data;
+    const char *filename;
+    NODE *node;
+
+    Data_Get_Struct(block, struct BLOCK, data);
+    if (node = data->body)
+      return rb_str_new2(node->nd_file);
+    rb_raise(rb_eArgError, "native or empty Proc");
+}
+
+
+/*
+ * call-seq:
+ *    prc.__line__  => Fixnum  
+ *
+ * returns the starting ruby source lineno of this proc or nil if none known
+ * raises ArgumentError if this proc was not defined in ruby (i.e. native)
+ */
+ 
+static VALUE
+proc_source_line(VALUE block)
+{
+    struct BLOCK *data;
+    NODE *node;
+    
+    Data_Get_Struct(block, struct BLOCK, data);
+    if (node = data->body)
+      return INT2FIX( nd_line(node) );
+    rb_raise(rb_eArgError, "native or empty Proc");
+}
+
+
 void
 Init_Proc()
 {
@@ -7003,6 +7198,8 @@
     rb_define_method(rb_cProc, "[]", proc_call, -2);
     rb_define_method(rb_cProc, "==", proc_eq, 1);
     rb_define_method(rb_cProc, "to_s", proc_to_s, 0);
+    rb_define_method(rb_cProc, "__file__", proc_source_file_name, 0); /* BAR */
+    rb_define_method(rb_cProc, "__line__", proc_source_line, 0); /* BAR */    
     rb_define_global_function("proc", rb_f_lambda, 0);
     rb_define_global_function("lambda", rb_f_lambda, 0);
     rb_define_global_function("binding", rb_f_binding, 0);
@@ -7020,6 +7217,8 @@
     rb_define_method(rb_cMethod, "to_s", method_inspect, 0);
     rb_define_method(rb_cMethod, "to_proc", method_proc, 0);
     rb_define_method(rb_cMethod, "unbind", method_unbind, 0);
+    rb_define_method(rb_cMethod, "__file__", method_source_file_name, 0); /* NK */
+    rb_define_method(rb_cMethod, "__line__", method_source_line, 0); /* NK */    
     rb_define_method(rb_mKernel, "method", rb_obj_method, 1);
 
     rb_cUnboundMethod = rb_define_class("UnboundMethod", rb_cMethod);
@@ -7093,13 +7292,6 @@
 
 extern VALUE rb_last_status;
 
-enum thread_status {
-    THREAD_TO_KILL,
-    THREAD_RUNNABLE,
-    THREAD_STOPPED,
-    THREAD_KILLED
-};
-
 #define WAIT_FD		(1<<0)
 #define WAIT_SELECT	(1<<1)
 #define WAIT_TIME	(1<<2)
@@ -7109,64 +7301,6 @@
 /* +infty, for this purpose */
 #define DELAY_INFTY 1E30
 
-/* typedef struct thread * rb_thread_t; */
-
-struct thread {
-    struct thread *next, *prev;
-    jmp_buf context;
-#ifdef SAVE_WIN32_EXCEPTION_LIST
-    DWORD win32_exception_list;
-#endif
-
-    VALUE result;
-
-    int   stk_len;
-    int   stk_max;
-    VALUE*stk_ptr;
-    VALUE*stk_pos;
-
-    struct FRAME *frame;
-    struct SCOPE *scope;
-    struct RVarmap *dyna_vars;
-    struct BLOCK *block;
-    struct iter *iter;
-    struct tag *tag;
-    VALUE klass;
-    VALUE wrapper;
-    NODE *cref;
-
-    int flags;		/* misc. states (vmode/rb_trap_immediate/raised) */
-
-    char *file;
-    int   line;
-
-    int tracing;
-    VALUE errinfo;
-    VALUE last_status;
-    VALUE last_line;
-    VALUE last_match;
-
-    int safe;
-
-    enum thread_status status;
-    int wait_for;
-    int fd;
-    fd_set readfds;
-    fd_set writefds;
-    fd_set exceptfds;
-    int select_value;
-    double delay;
-    rb_thread_t join;
-
-    int abort;
-    int priority;
-    int gid;
-
-    st_table *locals;
-
-    VALUE thread;
-};
-
 #define THREAD_RAISED 0x200	 /* temporary flag */
 #define THREAD_TERMINATING 0x400 /* persistent flag */
 #define THREAD_FLAGS_MASK  0x400 /* mask for persistent flags */
@@ -7189,7 +7323,7 @@
 
     int safe;
 
-    enum thread_status status;
+    enum rb_thread_status status;
     int wait_for;
     int fd;
     fd_set readfds;
@@ -7231,7 +7365,7 @@
     int sig;
 {
     int state;
-    VALUE val;			/* OK */
+    VALUE val;
     struct thread_status_t save;
 
     THREAD_COPY_STATUS(curr_thread, &save);
@@ -7259,7 +7393,7 @@
 
 static const char *
 thread_status_name(status)
-    enum thread_status status;
+    enum rb_thread_status status;
 {
     switch (status) {
       case THREAD_RUNNABLE:
@@ -7315,8 +7449,8 @@
     return (double)tv.tv_sec + (double)tv.tv_usec * 1e-6;
 }
 
-#define STACK(addr) (th->stk_pos<(VALUE*)(addr) && (VALUE*)(addr)<th->stk_pos+th->stk_len)
-#define ADJ(addr) (void*)(STACK(addr)?(((VALUE*)(addr)-th->stk_pos)+th->stk_ptr):(VALUE*)(addr))
+#define ADJ(addr) \
+   if ((size_t)((void *)addr - stkBase) < stkSize) addr=(void *)addr + stkShift
 
 static void
 thread_mark(th)
@@ -7324,6 +7458,9 @@
 {
     struct FRAME *frame;
     struct BLOCK *block;
+    void *stkBase;
+    ptrdiff_t stkShift;
+    size_t stkSize;
 
     rb_gc_mark(th->result);
     rb_gc_mark(th->thread);
@@ -7336,6 +7473,7 @@
     rb_gc_mark((VALUE)th->scope);
     rb_gc_mark((VALUE)th->dyna_vars);
     rb_gc_mark(th->errinfo);
+    rb_gc_mark(th->last_status);
     rb_gc_mark(th->last_line);
     rb_gc_mark(th->last_match);
     rb_mark_tbl(th->locals);
@@ -7350,15 +7488,23 @@
 	rb_gc_mark_locations(th->stk_ptr+2, th->stk_ptr+th->stk_len+2);
 #endif
     }
+    
+    stkBase = (void *)th->stk_start;
+    stkSize = th->stk_len * sizeof(VALUE);
+#if STACK_GROW_DIRECTION < 0
+    stkBase -= stkSize;
+#endif
+    stkShift = (void *)th->stk_ptr - stkBase;
+    
     frame = th->frame;
     while (frame && frame != top_frame) {
-	frame = ADJ(frame);
+        ADJ(frame);
 	rb_gc_mark_frame(frame);
 	if (frame->tmp) {
 	    struct FRAME *tmp = frame->tmp;
 
 	    while (tmp && tmp != top_frame) {
-		tmp = ADJ(tmp);
+		ADJ(tmp);
 		rb_gc_mark_frame(tmp);
 		tmp = tmp->prev;
 	    }
@@ -7367,12 +7513,36 @@
     }
     block = th->block;
     while (block) {
-	block = ADJ(block);
+	ADJ(block);
 	rb_gc_mark_frame(&block->frame);
 	block = block->prev;
     }
 }
 
+#define THREAD_DATA(threadObject)  ((rb_thread_t)RDATA(threadObject)->data)
+
+static inline void
+cc_purge(cc)
+    rb_thread_t cc;
+{  /* free continuation's stack if it has just died */
+  if (cc->thread != Qnil && THREAD_DATA(cc->thread)->status == THREAD_KILLED) {
+    cc->thread = Qnil;
+    if (cc->stk_ptr) {  //can't possibly activate this stack, so free it.
+      free(cc->stk_ptr);
+      cc->stk_ptr = 0;
+      cc->stk_len = 0;
+    }
+  }  
+}
+
+static void
+cc_mark(cc)
+    rb_thread_t cc;
+{  /* mark this continuation's stack only if its parent thread is still alive */
+  cc_purge(cc);
+  thread_mark(cc);
+}
+
 void
 rb_gc_mark_threads()
 {
@@ -7384,12 +7554,28 @@
     } END_FOREACH(th);
 }
 
+void
+rb_gc_abort_threads()
+{
+    rb_thread_t th;
+
+    if (!main_thread)
+        return;
+
+    FOREACH_THREAD_FROM(main_thread, th) {
+	if (FL_TEST(th->thread, FL_MARK)) continue;
+	if (th->status == THREAD_STOPPED) {
+	    th->status = THREAD_TO_KILL;
+	    rb_gc_mark(th->thread);
+	}
+    } END_FOREACH_FROM(main_thread, th);
+}
+
 static void
 thread_free(th)
     rb_thread_t th;
 {
     if (th->stk_ptr) free(th->stk_ptr);
-    th->stk_ptr = 0;
     if (th->locals) st_free_table(th->locals);
     if (th->status != THREAD_KILLED) {
 	if (th->prev) th->prev->next = th->next;
@@ -7402,11 +7588,11 @@
 rb_thread_check(data)
     VALUE data;
 {
-    if (TYPE(data) != T_DATA || RDATA(data)->dfree != (RUBY_DATA_FUNC)thread_free) {
-	rb_raise(rb_eTypeError, "wrong argument type %s (expected Thread)",
-		 rb_class2name(CLASS_OF(data)));
-    }
-    return (rb_thread_t)RDATA(data)->data;
+  if (TYPE(data) != T_DATA || RDATA(data)->dmark != (RUBY_DATA_FUNC)thread_mark) {
+    rb_raise(rb_eTypeError, "wrong argument type %s (expected Thread)",
+	     rb_class2name(CLASS_OF(data)));
+  }
+  return THREAD_DATA(data);
 }
 
 static VALUE rb_thread_raise _((int, VALUE*, rb_thread_t));
@@ -7430,21 +7616,19 @@
 rb_thread_save_context(th)
     rb_thread_t th;
 {
-    VALUE *pos;
-    int len;
+    VALUE *pos=th->stk_start;
+    size_t len;
     static VALUE tval;
 
-    len = stack_length(&pos);
-    th->stk_len = 0;
-    th->stk_pos = (rb_gc_stack_start<pos)?rb_gc_stack_start
-				         :rb_gc_stack_start - len;
-    if (len > th->stk_max) {
-	REALLOC_N(th->stk_ptr, VALUE, len);
-	th->stk_max = len;
-    }
-    th->stk_len = len;
+    len = stack_length(pos);
+#if STACK_GROW_DIRECTION < 0
+    pos -= len;
+#endif
+    if (len > th->stk_max)
+      REALLOC_N(th->stk_ptr, VALUE, th->stk_max = len);
+//fprintf(stderr,"SAVE pos=%p, stk_ptr=%p, len=%d\n", pos, th->stk_ptr, len);
     FLUSH_REGISTER_WINDOWS; 
-    MEMCPY(th->stk_ptr, th->stk_pos, VALUE, th->stk_len);
+    MEMCPY(th->stk_ptr, pos, VALUE, th->stk_len=len);
 #ifdef SAVE_WIN32_EXCEPTION_LIST
     th->win32_exception_list = win32_get_exception_list();
 #endif
@@ -7479,6 +7663,9 @@
 thread_switch(n)
     int n;
 {
+#if STACK_WIPE_SITES & 1
+    rb_gc_wipe_stack();
+#endif
     switch (n) {
       case 0:
 	return 0;
@@ -7509,18 +7696,17 @@
 
 #define THREAD_SAVE_CONTEXT(th) \
     (rb_thread_save_context(th),\
-     thread_switch((FLUSH_REGISTER_WINDOWS, setjmp((th)->context))))
+     thread_switch(wipeAfter((FLUSH_REGISTER_WINDOWS, setjmp((th)->context)))))
 
 static void rb_thread_restore_context _((rb_thread_t,int));
 
 static void
-stack_extend(th, exit)
+stack_extend(values, th, exit)
+    size_t values;
     rb_thread_t th;
     int exit;
 {
-    VALUE space[1024];
-
-    memset(space, 0, 1);	/* prevent array from optimization */
+    (volatile VALUE *)ALLOCA_N(VALUE, values);
     rb_thread_restore_context(th, exit);
 }
 
@@ -7530,21 +7716,21 @@
     int exit;
 {
     VALUE v;
+    VALUE *pos = th->stk_start;
     static rb_thread_t tmp;
     static int ex;
     static VALUE tval;
 
     if (!th->stk_ptr) rb_bug("unsaved context");
 
-    if (&v < rb_gc_stack_start) {
-	/* Stack grows downward */
-	if (&v > th->stk_pos) stack_extend(th, exit);
-    }
-    else {
-	/* Stack grows upward */
-	if (&v < th->stk_pos + th->stk_len) stack_extend(th, exit);
-    }
+#if STACK_GROW_DIRECTION > 0  /* stack grows upward */
+    if (&v < pos + th->stk_len) stack_extend(pos+th->stk_len - &v, th, exit);
+#else /* stack grows downward */
+    pos -= th->stk_len;
+    if (&v > pos) stack_extend(&v-pos, th, exit);
+#endif
 
+//fprintf(stderr,"RSTR pos=%p, stk_ptr=%p, len=%d\n", pos, th->stk_ptr, th->stk_len);
     ruby_frame = th->frame;
     ruby_scope = th->scope;
     ruby_class = th->klass;
@@ -7570,7 +7756,7 @@
     tmp = th;
     ex = exit;
     FLUSH_REGISTER_WINDOWS;
-    MEMCPY(tmp->stk_pos, tmp->stk_ptr, VALUE, tmp->stk_len);
+    MEMCPY(pos, tmp->stk_ptr, VALUE, tmp->stk_len);
 
     tval = rb_lastline_get();
     rb_lastline_set(tmp->last_line);
@@ -7602,7 +7788,7 @@
     th->next->prev = th->prev;
 }
 
-static int
+static inline int
 rb_thread_dead(th)
     rb_thread_t th;
 {
@@ -7722,7 +7908,7 @@
     int need_select = 0;
     int select_timeout = 0;
 
-    rb_thread_pending = 0;
+    rb_thread_pending = rb_thread_critical = 0;
     if (curr_thread == curr_thread->next
 	&& curr_thread->status == THREAD_RUNNABLE)
 	return;
@@ -8117,8 +8303,8 @@
 rb_thread_join(thread)
     VALUE thread;
 {
-    rb_thread_t th = rb_thread_check(thread);
-    enum thread_status last_status = THREAD_RUNNABLE;
+    rb_thread_t th = THREAD_DATA(thread);
+    enum rb_thread_status last_status = THREAD_RUNNABLE;
 
     if (rb_thread_critical) rb_thread_deadlock();
     if (!rb_thread_dead(th)) {
@@ -8185,7 +8371,7 @@
 rb_thread_wakeup(thread)
     VALUE thread;
 {
-    rb_thread_t th = rb_thread_check(thread);
+    rb_thread_t th = THREAD_DATA(thread);
 
     if (th->status == THREAD_KILLED)
 	rb_raise(rb_eThreadError, "killed thread");
@@ -8208,7 +8394,7 @@
 rb_thread_kill(thread)
     VALUE thread;
 {
-    rb_thread_t th = rb_thread_check(thread);
+    rb_thread_t th = THREAD_DATA(thread);
 
     if (th != curr_thread && th->safe < 4) {
 	rb_secure(4);
@@ -8247,9 +8433,8 @@
 VALUE
 rb_thread_stop()
 {
-    enum thread_status last_status = THREAD_RUNNABLE;
+    enum rb_thread_status last_status = THREAD_RUNNABLE;
 
-    rb_thread_critical = 0;
     if (curr_thread == curr_thread->next) {
 	rb_raise(rb_eThreadError, "stopping only thread\n\tnote: use sleep to stop forever");
     }
@@ -8317,7 +8502,7 @@
 rb_thread_priority(thread)
     VALUE thread;
 {
-    return INT2NUM(rb_thread_check(thread)->priority);
+    return INT2NUM(THREAD_DATA(thread)->priority);
 }
 
 static VALUE
@@ -8327,7 +8512,7 @@
     rb_thread_t th;
 
     rb_secure(4);
-    th = rb_thread_check(thread);
+    th = THREAD_DATA(thread);
 
     th->priority = NUM2INT(prio);
     rb_thread_schedule();
@@ -8340,7 +8525,7 @@
 {
     rb_thread_t th;
 
-    th = rb_thread_check(thread);
+    th = THREAD_DATA(thread);
     if (th == curr_thread) {
 	return INT2NUM(rb_safe_level());
     }
@@ -8368,7 +8553,7 @@
 rb_thread_abort_exc(thread)
     VALUE thread;
 {
-    return rb_thread_check(thread)->abort?Qtrue:Qfalse;
+    return THREAD_DATA(thread)->abort?Qtrue:Qfalse;
 }
 
 static VALUE
@@ -8376,12 +8561,14 @@
     VALUE thread, val;
 {
     rb_secure(4);
-    rb_thread_check(thread)->abort = RTEST(val);
+    THREAD_DATA(thread)->abort = RTEST(val);
     return val;
 }
 
+extern VALUE *rb_gc_stack_start;
+
 #define THREAD_ALLOC(th) do {\
-    th = ALLOC(struct thread);\
+    th = ALLOC(struct rb_thread);\
 \
     th->next = 0;\
     th->prev = 0;\
@@ -8392,6 +8579,7 @@
 \
     th->stk_ptr = 0;\
     th->stk_len = 0;\
+    th->stk_start = rb_gc_stack_start;\
     th->stk_max = 0;\
     th->wait_for = 0;\
     FD_ZERO(&th->readfds);\
@@ -8494,10 +8682,12 @@
 {
     volatile rb_thread_t th = th_arg;
     volatile VALUE thread = th->thread;
-    struct BLOCK* saved_block = 0;
-    enum thread_status status;
+    struct BLOCK *volatile saved_block = 0;
+    enum rb_thread_status status;
     int state;
 
+    th_arg->stk_start = (VALUE *)(ruby_frame+(STACK_GROW_DIRECTION<0));
+
 #if defined(HAVE_SETITIMER)
     if (!thread_init) {
 #ifdef POSIX_SIGNAL
@@ -8538,6 +8728,8 @@
     PUSH_TAG(PROT_THREAD);
     if ((state = EXEC_TAG()) == 0) {
 	if (THREAD_SAVE_CONTEXT(th) == 0) {
+            ruby_frame->prev = top_frame;     /* hide parent thread's frames */
+            ruby_frame->tmp = 0;
 	    curr_thread = th;
 	    th->result = (*fn)(arg, th);
 	}
@@ -8586,6 +8778,7 @@
     return 0;			/* not reached */
 }
 
+
 VALUE
 rb_thread_create(fn, arg)
     VALUE (*fn)();
@@ -8595,6 +8788,7 @@
     return rb_thread_start_0(fn, arg, rb_thread_alloc(rb_cThread));
 }
 
+
 int
 rb_thread_scope_shared_p()
 {
@@ -8617,11 +8811,8 @@
     VALUE klass;
 {
     rb_thread_t th = rb_thread_alloc(klass);
-    volatile VALUE *pos;
-
-    pos = th->stk_pos;
     rb_obj_call_init(th->thread, argc, argv);
-    if (th->stk_pos == 0) {
+    if (!th->stk_ptr) {
 	rb_raise(rb_eThreadError, "uninitialized thread - check `%s#initialize'",
 		 rb_class2name(klass));
     }
@@ -8636,7 +8827,7 @@
     if (!rb_block_given_p()) {
 	rb_raise(rb_eThreadError, "must be called with a block");
     }
-    return rb_thread_start_0(rb_thread_yield, args, rb_thread_check(thread));
+    return rb_thread_start_0(rb_thread_yield, args, THREAD_DATA(thread));
 }
 
 static VALUE
@@ -8653,18 +8844,15 @@
 rb_thread_value(thread)
     VALUE thread;
 {
-    rb_thread_t th = rb_thread_check(thread);
-
     rb_thread_join(thread);
-
-    return th->result;
+    return THREAD_DATA(thread)->result;
 }
 
 static VALUE
 rb_thread_status(thread)
     VALUE thread;
 {
-    rb_thread_t th = rb_thread_check(thread);
+    rb_thread_t th = THREAD_DATA(thread);
 
     if (rb_thread_dead(th)) {
 	if (!NIL_P(th->errinfo) && (th->flags & THREAD_RAISED))
@@ -8679,7 +8867,7 @@
 rb_thread_alive_p(thread)
     VALUE thread;
 {
-    rb_thread_t th = rb_thread_check(thread);
+    rb_thread_t th = THREAD_DATA(thread);
 
     if (rb_thread_dead(th)) return Qfalse;
     return Qtrue;
@@ -8689,7 +8877,7 @@
 rb_thread_stop_p(thread)
     VALUE thread;
 {
-    rb_thread_t th = rb_thread_check(thread);
+    rb_thread_t th = THREAD_DATA(thread);
 
     if (rb_thread_dead(th)) return Qtrue;
     if (th->status == THREAD_STOPPED) return Qtrue;
@@ -8783,8 +8971,8 @@
     VALUE cmd;
     int sig;
 {
-#if 0
     rb_thread_critical = 0;
+#if 0  //first, try to eval trap on the current thread, if it's alive
     if (!rb_thread_dead(curr_thread)) {
 	rb_thread_ready(curr_thread);
 	rb_trap_eval(cmd, sig);
@@ -8794,22 +8982,17 @@
     if (THREAD_SAVE_CONTEXT(curr_thread)) {
 	return;
     }
-    th_cmd = cmd;
-    th_sig = sig;
-    curr_thread = main_thread;
-    rb_thread_restore_context(curr_thread, RESTORE_TRAP);
-#else
-    rb_thread_critical = 0;
+#else  //always eval trap on the main thread
     if (!rb_thread_dead(curr_thread)) {
 	if (THREAD_SAVE_CONTEXT(curr_thread)) {
 	    return;
 	}
     }
+#endif
     th_cmd = cmd;
     th_sig = sig;
     curr_thread = main_thread;
     rb_thread_restore_context(curr_thread, RESTORE_TRAP);
-#endif
 }
 
 static VALUE
@@ -8844,7 +9027,7 @@
     VALUE *argv;
     VALUE thread;
 {
-    rb_thread_t th = rb_thread_check(thread);
+    rb_thread_t th = THREAD_DATA(thread);
 
     if (ruby_safe_level > th->safe) {
 	rb_secure(4);
@@ -8861,7 +9044,7 @@
     rb_thread_t th;
     VALUE val;
 
-    th = rb_thread_check(thread);
+    th = THREAD_DATA(thread);
     if (rb_safe_level() >= 4 && th != curr_thread) {
 	rb_raise(rb_eSecurityError, "Insecure: thread locals");
     }
@@ -8885,7 +9068,7 @@
     ID id;
     VALUE val;
 {
-    rb_thread_t th = rb_thread_check(thread);
+    rb_thread_t th = THREAD_DATA(thread);
 
     if (rb_safe_level() >= 4 && th != curr_thread) {
 	rb_raise(rb_eSecurityError, "Insecure: can't modify thread locals");
@@ -8915,7 +9098,7 @@
 rb_thread_key_p(thread, id)
     VALUE thread, id;
 {
-    rb_thread_t th = rb_thread_check(thread);
+    rb_thread_t th = THREAD_DATA(thread);
 
     if (!th->locals) return Qfalse;
     if (st_lookup(th->locals, rb_to_id(id), 0))
@@ -8928,7 +9111,7 @@
     VALUE thread;
 {
     char *cname = rb_class2name(CLASS_OF(thread));
-    rb_thread_t th = rb_thread_check(thread);
+    rb_thread_t th = THREAD_DATA(thread);
     const char *status = thread_status_name(th->status);
     VALUE str;
 
@@ -8961,20 +9144,18 @@
 
 static VALUE rb_cCont;
 
-static VALUE
-rb_callcc(self)
-    VALUE self;
+static rb_thread_t prep4callcc(void)
 {
-    volatile VALUE cont;
     rb_thread_t th;
     struct tag *tag;
     struct RVarmap *vars;
 
     THREAD_ALLOC(th);
-    cont = Data_Wrap_Struct(rb_cCont, thread_mark, thread_free, th);
+    th->thread = curr_thread->thread;
 
     scope_dup(ruby_scope);
     for (tag=prot_tag; tag; tag=tag->prev) {
+        if (tag->tag == PROT_THREAD) break;
 	scope_dup(tag->scope);
     }
     if (ruby_block) {
@@ -8985,19 +9166,34 @@
 	    block = block->prev;
 	}
     }
-    th->thread = curr_thread->thread;
 
     for (vars = th->dyna_vars; vars; vars = vars->next) {
 	if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break;
 	FL_SET(vars, DVAR_DONT_RECYCLE);
     }
+    return th;
+}
 
-    if (THREAD_SAVE_CONTEXT(th)) {
-	return th->result;
-    }
-    else {
-	return rb_yield(cont);
-    }
+
+static VALUE
+rb_callcc(self)
+    VALUE self;
+{
+    volatile rb_thread_t th = prep4callcc();
+    return THREAD_SAVE_CONTEXT(th) ?
+	th->result
+      :
+	rb_yield(Data_Wrap_Struct(rb_cCont, cc_mark, thread_free, th));
+}
+
+static VALUE
+rb_cont_thread(cont)
+  VALUE cont;
+// return the active parent thread, nil if it has died
+{
+  rb_thread_t th = THREAD_DATA(cont);
+  cc_purge(th);
+  return th->thread;
 }
 
 static VALUE
@@ -9006,7 +9202,7 @@
     VALUE *argv;
     VALUE cont;
 {
-    rb_thread_t th = rb_thread_check(cont);
+    rb_thread_t th = THREAD_DATA(cont);
 
     if (th->thread != curr_thread->thread) {
 	rb_raise(rb_eRuntimeError, "continuation called across threads");
@@ -9141,6 +9337,7 @@
 
     rb_cCont = rb_define_class("Continuation", rb_cObject);
     rb_undef_method(CLASS_OF(rb_cCont), "new");
+    rb_define_method(rb_cCont, "thread", rb_cont_thread, 0);
     rb_define_method(rb_cCont, "call", rb_cont_call, -1);
     rb_define_global_function("callcc", rb_callcc, 0);
 
@@ -9156,12 +9353,12 @@
     VALUE dmy, tag;
 {
     int state;
-    ID t;
-    VALUE val;			/* OK */
+    volatile ID t;
+    VALUE val;
 
     t = rb_to_id(tag);
     PUSH_TAG(t);
-    if ((state = EXEC_TAG()) == 0) {
+    if ((state = wipeAfter(EXEC_TAG_0())) == 0) {
 	val = rb_yield_0(tag, 0, 0, 0);
     }
     else if (state == TAG_THROW && t == prot_tag->dst) {
diff -ru ruby.snapshot/ext/extmk.rb.in ruby/ext/extmk.rb.in
--- ruby.snapshot/ext/extmk.rb.in	2003-04-09 00:15:42.000000000 -0700
+++ ruby/ext/extmk.rb.in	2006-02-09 17:37:19.000000000 -0800
@@ -172,9 +172,11 @@
   if File.directory? libdir
     Find.find(libdir) do |f|
       next unless /\.rb$/ =~ f
+      d = File.dirname f
+      next if File.basename(d)=='Base' && File.basename(File.dirname d)=='CVS'
       f = f[libdir.length+1..-1]
       path.push f
-      dir |= [File.dirname(f)]
+      dir |= [d]
     end
   end
   for f in dir
@@ -706,6 +708,7 @@
 
 ext_prefix = "#{$top_srcdir}/ext"
 for d in Dir["#{ext_prefix}/**/*"]
+  File.basename(d) == 'Base' && File.basename(File.dirname d) == 'CVS' && next
   File.directory?(d) || next
   File.file?(d + "/MANIFEST") || next
   
diff -ru ruby.snapshot/ext/readline/depend ruby/ext/readline/depend
--- ruby.snapshot/ext/readline/depend	1999-10-21 00:08:00.000000000 -0700
+++ ruby/ext/readline/depend	2006-02-09 17:37:50.000000000 -0800
@@ -1 +1 @@
-readline.o: readline.c $(hdrdir)/ruby.h $(topdir)/config.h $(hdrdir)/defines.h
+readline.o: readline.c $(hdrdir)/ruby.h $(hdrdir)/rubyio.h $(topdir)/config.h $(hdrdir)/defines.h
diff -ru ruby.snapshot/ext/readline/readline.c ruby/ext/readline/readline.c
--- ruby.snapshot/ext/readline/readline.c	2002-06-20 05:14:18.000000000 -0700
+++ ruby/ext/readline/readline.c	2006-02-09 17:38:18.000000000 -0800
@@ -8,6 +8,7 @@
 
 #include "ruby.h"
 #include "rubysig.h"
+#include "rubyio.h"
 
 static VALUE mReadline;
 
@@ -23,13 +24,14 @@
 #endif
 
 static int
-readline_event()
+readline_getc (ignored)
+  FILE *ignored;
 {
-    CHECK_INTS;
-    rb_thread_schedule();
-    return 0;
+  VALUE string = rb_funcall (rb_stdin, rb_intern("sysread"), 1, INT2FIX(1));
+  return RSTRING(string)->ptr[0];  //single byte read
 }
 
+
 static VALUE
 readline_readline(argc, argv, self)
     int argc;
@@ -461,6 +463,6 @@
 
     rl_attempted_completion_function
 	= (CPPFunction *) readline_attempted_completion_function;
-    rl_event_hook = readline_event;
+    rl_getc_function = readline_getc;
     rl_clear_signals();
 }
diff -ru ruby.snapshot/ext/socket/addrinfo.h ruby/ext/socket/addrinfo.h
--- ruby.snapshot/ext/socket/addrinfo.h	2002-12-31 03:24:49.000000000 -0800
+++ ruby/ext/socket/addrinfo.h	2006-02-09 17:38:39.000000000 -0800
@@ -156,7 +156,7 @@
 
 extern void freehostent __P((struct hostent *));
 extern void freeaddrinfo __P((struct addrinfo *));
-#if defined __UCLIBC__
+#if defined __UCLIBC__  || __GNUC__>3 || (__GNUC__==3 && __GNUC_MINOR__>=3)
 const
 #endif
 extern char *gai_strerror __P((int));
diff -ru ruby.snapshot/ext/socket/getaddrinfo.c ruby/ext/socket/getaddrinfo.c
--- ruby.snapshot/ext/socket/getaddrinfo.c	2002-02-28 18:31:02.000000000 -0800
+++ ruby/ext/socket/getaddrinfo.c	2006-02-09 17:38:43.000000000 -0800
@@ -191,7 +191,7 @@
 
 #define ERR(err) { error = (err); goto bad; }
 
-#if defined __UCLIBC__
+#if defined __UCLIBC__ || __GNUC__>3 || (__GNUC__==3 && __GNUC_MINOR__>=3)
 const
 #endif
 char *
diff -ru ruby.snapshot/file.c ruby/file.c
--- ruby.snapshot/file.c	2003-01-09 00:32:26.000000000 -0800
+++ ruby/file.c	2009-08-17 19:35:40.000000000 -0700
@@ -2,8 +2,8 @@
 
   file.c -
 
-  $Author: eban $
-  $Date: 2003/01/09 08:32:26 $
+  $Author: brent $
+  $Date: 2009/08/18 02:35:40 $
   created at: Mon Nov 15 12:24:34 JST 1993
 
   Copyright (C) 1993-2000 Yukihiro Matsumoto
@@ -392,7 +392,7 @@
 }
 
 static int
-group_member(gid)
+groupMember(gid)
     GETGROUPS_T gid;
 {
 #if !defined(NT)
@@ -448,7 +448,7 @@
 
   if (st.st_uid == euid)        /* owner */
       mode <<= 6;
-  else if (getegid() == st.st_gid || group_member(st.st_gid))
+  else if (getegid() == st.st_gid || groupMember(st.st_gid))
       mode <<= 3;
 
   if ((st.st_mode & mode) == mode) return 0;
@@ -1900,7 +1900,7 @@
 	return st->st_mode & S_IRUSR ? Qtrue : Qfalse;
 #endif
 #ifdef S_IRGRP
-    if (group_member(get_stat(obj)->st_gid))
+    if (groupMember(get_stat(obj)->st_gid))
 	return st->st_mode & S_IRGRP ? Qtrue : Qfalse;
 #endif
 #ifdef S_IROTH
@@ -1940,7 +1940,7 @@
 	return st->st_mode & S_IWUSR ? Qtrue : Qfalse;
 #endif
 #ifdef S_IWGRP
-    if (group_member(get_stat(obj)->st_gid))
+    if (groupMember(get_stat(obj)->st_gid))
 	return st->st_mode & S_IWGRP ? Qtrue : Qfalse;
 #endif
 #ifdef S_IWOTH
@@ -1980,7 +1980,7 @@
 	return st->st_mode & S_IXUSR ? Qtrue : Qfalse;
 #endif
 #ifdef S_IXGRP
-    if (group_member(get_stat(obj)->st_gid))
+    if (groupMember(get_stat(obj)->st_gid))
 	return st->st_mode & S_IXGRP ? Qtrue : Qfalse;
 #endif
 #ifdef S_IXOTH
diff -ru ruby.snapshot/gc.c ruby/gc.c
--- ruby.snapshot/gc.c	2003-06-27 20:28:53.000000000 -0700
+++ ruby/gc.c	2009-03-01 03:35:50.000000000 -0800
@@ -2,8 +2,8 @@
 
   gc.c -
 
-  $Author: nobu $
-  $Date: 2003/06/28 03:28:53 $
+  $Author: brent $
+  $Date: 2009/03/01 11:35:50 $
   created at: Tue Oct  5 09:44:46 JST 1993
 
   Copyright (C) 1993-2000 Yukihiro Matsumoto
@@ -21,6 +21,10 @@
 #include <stdio.h>
 #include <setjmp.h>
 
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
 void re_free_registers _((struct re_registers*));
 void rb_io_fptr_finalize _((struct OpenFile*));
 
@@ -28,38 +32,90 @@
 #define setjmp(env) _setjmp(env)
 #endif
 
-/* Make alloca work the best possible way.  */
-#ifdef __GNUC__
-# ifndef atarist
-#  ifndef alloca
-#   define alloca __builtin_alloca
-#  endif
-# endif /* atarist */
-#else
-# ifdef HAVE_ALLOCA_H
-#  include <alloca.h>
-# else
-#  ifdef _AIX
- #pragma alloca
-#  else
-#   ifndef alloca /* predefined by HP cc +Olibcalls */
-void *alloca ();
-#   endif
-#  endif /* AIX */
-# endif /* HAVE_ALLOCA_H */
-#endif /* __GNUC__ */
-
-static void run_final();
-
 #ifndef GC_MALLOC_LIMIT
 #if defined(MSDOS) || defined(__human68k__)
 #define GC_MALLOC_LIMIT 200000
 #else
-#define GC_MALLOC_LIMIT 8000000
+#define GC_MALLOC_LIMIT (2000000*sizeof(VALUE))
 #endif
 #endif
 
-static unsigned long malloc_memories = 0;
+#ifndef GC_LEVEL_MAX  /*maximum # of VALUEs on 'C' stack during GC*/
+#define GC_LEVEL_MAX  8000
+#endif
+#ifndef GC_STACK_PAD
+#define GC_STACK_PAD  200  /* extra padding VALUEs for GC stack */
+#endif
+#define GC_STACK_MAX  (GC_LEVEL_MAX+GC_STACK_PAD)
+
+static VALUE *stack_limit, *gc_stack_limit;
+
+static size_t malloc_increase = 0;
+static size_t malloc_limit = GC_MALLOC_LIMIT;
+
+/*
+ *  call-seq:
+ *     GC.limit    => increase limit in bytes
+ *
+ *  Get the # of bytes that may be allocated before triggering
+ *  a mark and sweep by the garbarge collector to reclaim unused storage.
+ *
+ */
+static VALUE gc_getlimit(VALUE mod)
+{
+  return ULONG2NUM(malloc_limit);
+}
+
+/*
+ *  call-seq:
+ *     GC.limit=   => updated increase limit in bytes
+ *
+ *  Set the # of bytes that may be allocated before triggering
+ *  a mark and sweep by the garbarge collector to reclaim unused storage.
+ *  Attempts to set the GC.limit= less than 0 will be ignored.
+ *
+ *     GC.limit=5000000   #=> 5000000
+ *     GC.limit           #=> 5000000
+ *     GC.limit=-50       #=> 5000000
+ *     GC.limit=0         #=> 0
+ *
+ */
+static VALUE gc_setlimit(VALUE mod, VALUE newLimit)
+{
+  long limit = NUM2LONG(newLimit);
+  rb_secure(2);
+  if (limit < 0) return gc_getlimit(mod);
+  malloc_limit = limit;
+  return newLimit;
+}
+
+
+/*
+ *  call-seq:
+ *     GC.growth
+ *
+ *  Get # of bytes that have been allocated since the last mark & sweep
+ *
+ */
+static VALUE gc_growth(VALUE mod)
+{
+  return ULONG2NUM(malloc_increase);
+}
+
+
+/*
+ *  call-seq:
+ *     GC.exorcise
+ *
+ *  Purge ghost references from recently freed stack space
+ *
+ */
+static VALUE gc_exorcise(VALUE mod)
+{
+  rb_gc_wipe_stack();
+  return Qnil;
+}
+
 
 static void
 mem_error(mesg)
@@ -78,6 +134,10 @@
     exit(1);
 }
 
+static void run_final();
+static void garbage_collect();
+
+
 void *
 ruby_xmalloc(size)
     long size;
@@ -88,23 +148,22 @@
 	rb_raise(rb_eNoMemError, "negative allocation size (or too big)");
     }
     if (size == 0) size = 1;
-    malloc_memories += size;
 
-    if (malloc_memories > GC_MALLOC_LIMIT) {
-	rb_gc();
+    if ((malloc_increase+=size) > malloc_limit) {
+	garbage_collect();
+        malloc_increase = size;
     }
     RUBY_CRITICAL(mem = malloc(size));
     if (!mem) {
-	rb_gc();
+	garbage_collect();
 	RUBY_CRITICAL(mem = malloc(size));
 	if (!mem) {
-	    if (size >= 10 * 1024 * 1024) {
-		rb_raise(rb_eNoMemError, "tried to allocate too big memory");
-	    }
 	    mem_error("failed to allocate memory");
 	}
     }
-
+#if STACK_WIPE_SITES & 0x100
+    rb_gc_update_stack_extent();
+#endif
     return mem;
 }
 
@@ -132,19 +191,21 @@
     }
     if (!ptr) return xmalloc(size);
     if (size == 0) size = 1;
-    malloc_memories += size;
+    if ((malloc_increase+=size) > malloc_limit) {
+	garbage_collect();
+        malloc_increase = size;
+    }
     RUBY_CRITICAL(mem = realloc(ptr, size));
     if (!mem) {
-	rb_gc();
+	garbage_collect();
 	RUBY_CRITICAL(mem = realloc(ptr, size));
 	if (!mem) {
-	    if (size >= 50 * 1024 * 1024) {
-		rb_raise(rb_eNoMemError, "tried to re-allocate too big memory");
-	    }
 	    mem_error("failed to allocate memory(realloc)");
-	}
+        }
     }
-
+#if STACK_WIPE_SITES & 0x200
+    rb_gc_update_stack_extent();
+#endif
     return mem;
 }
 
@@ -162,8 +223,22 @@
 static int need_call_final = 0;
 static st_table *finalizer_table = 0;
 
-static VALUE
-gc_enable()
+
+/*
+ *  call-seq:
+ *     GC.enable    => true or false
+ *
+ *  Enables garbage collection, returning <code>true</code> if garbage
+ *  collection was previously disabled.
+ *
+ *     GC.disable   #=> false
+ *     GC.enable    #=> true
+ *     GC.enable    #=> false
+ *
+ */
+
+VALUE
+rb_gc_enable()
 {
     int old = dont_gc;
 
@@ -171,8 +246,20 @@
     return old;
 }
 
-static VALUE
-gc_disable()
+/*
+ *  call-seq:
+ *     GC.disable    => true or false
+ *
+ *  Disables garbage collection, returning <code>true</code> if garbage
+ *  collection was already disabled.
+ *
+ *     GC.disable   #=> false
+ *     GC.disable   #=> true
+ *
+ */
+
+VALUE
+rb_gc_disable()
 {
     int old = dont_gc;
 
@@ -222,6 +309,8 @@
     }
 }
 
+#undef GC_DEBUG
+
 void
 rb_global_variable(var)
     VALUE *var;
@@ -229,10 +318,14 @@
     rb_gc_register_address(var);
 }
 
+#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CYGWIN__)
+#pragma pack(push, 1) /* magic for reducing sizeof(RVALUE): 24 -> 20 */
+#endif
+
 typedef struct RVALUE {
     union {
 	struct {
-	    unsigned long flag;	/* always 0 for freed obj */
+	    unsigned long flags;	/* always 0 for freed obj */
 	    struct RVALUE *next;
 	} free;
 	struct RBasic  basic;
@@ -249,21 +342,32 @@
 	struct RFile   file;
 	struct RNode   node;
 	struct RMatch  match;
-	struct RVarmap varmap; 
+	struct RVarmap varmap;
 	struct SCOPE   scope;
     } as;
+#ifdef GC_DEBUG
+    char *file;
+    int   line;
+#endif
 } RVALUE;
 
+#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CYGWIN__)
+#pragma pack(pop)
+#endif
+
 static RVALUE *freelist = 0;
 static RVALUE *deferred_final_list = 0;
 
 #define HEAPS_INCREMENT 10
-static RVALUE **heaps;
+static struct heaps_slot {
+    void *membase;
+    RVALUE *slot;
+    int limit;
+} *heaps;
 static int heaps_length = 0;
 static int heaps_used   = 0;
 
 #define HEAP_MIN_SLOTS 10000
-static int *heaps_limits;
 static int heap_slots = HEAP_MIN_SLOTS;
 
 #define FREE_MIN  4096
@@ -277,37 +381,49 @@
 
     if (heaps_used == heaps_length) {
 	/* Realloc heaps */
+	struct heaps_slot *p;
+	int length;
+
 	heaps_length += HEAPS_INCREMENT;
-	RUBY_CRITICAL(heaps = (heaps_used>0)?
-			(RVALUE**)realloc(heaps, heaps_length*sizeof(RVALUE*)):
-			(RVALUE**)malloc(heaps_length*sizeof(RVALUE*)));
-	if (heaps == 0) mem_error("heaps: can't alloc memory");
-	RUBY_CRITICAL(heaps_limits = (heaps_used>0)?
-			(int*)realloc(heaps_limits, heaps_length*sizeof(int)):
-			(int*)malloc(heaps_length*sizeof(int)));
-	if (heaps_limits == 0) mem_error("heaps_limits: can't alloc memory");
+	length = heaps_length*sizeof(struct heaps_slot);
+	RUBY_CRITICAL(
+	    if (heaps_used > 0) {
+		p = (struct heaps_slot *)realloc(heaps, length);
+		if (p) heaps = p;
+	    }
+	    else {
+		p = heaps = (struct heaps_slot *)malloc(length);
+	    });
+	if (p == 0) mem_error("can't realloc heap slot");
     }
 
     for (;;) {
-	RUBY_CRITICAL(p = heaps[heaps_used] = (RVALUE*)malloc(sizeof(RVALUE)*heap_slots));
-	heaps_limits[heaps_used] = heap_slots;
+	RUBY_CRITICAL(p = (RVALUE*)malloc(sizeof(RVALUE)*(heap_slots+1)));
 	if (p == 0) {
 	    if (heap_slots == HEAP_MIN_SLOTS) {
-		mem_error("add_heap: can't alloc memory");
+		mem_error("can't alloc heap slot");
 	    }
 	    heap_slots = HEAP_MIN_SLOTS;
 	    continue;
 	}
+        heaps[heaps_used].membase = p;
+        if ((VALUE)p % sizeof(RVALUE) == 0)
+            heap_slots += 1;
+        else
+            p = (RVALUE*)((VALUE)p + sizeof(RVALUE) - ((VALUE)p % sizeof(RVALUE)));
+        heaps[heaps_used].slot = p;
+        heaps[heaps_used].limit = heap_slots;
 	break;
     }
     pend = p + heap_slots;
     if (lomem == 0 || lomem > p) lomem = p;
     if (himem < pend) himem = pend;
     heaps_used++;
-    heap_slots *= 2;
+    heap_slots *= 1.8;
+    if (heap_slots <= 0) heap_slots = HEAP_MIN_SLOTS;
 
     while (p < pend) {
-	p->as.free.flag = 0;
+	p->as.free.flags = 0;
 	p->as.free.next = freelist;
 	freelist = p;
 	p++;
@@ -315,16 +431,29 @@
 }
 #define RANY(o) ((RVALUE*)(o))
 
+int 
+rb_during_gc()
+{
+    return during_gc;
+}
+
 VALUE
 rb_newobj()
 {
     VALUE obj;
 
-    if (!freelist) rb_gc();
+    if (during_gc)
+	rb_bug("object allocation during garbage collection phase");
+
+    if (!malloc_limit || !freelist) garbage_collect();
 
     obj = (VALUE)freelist;
     freelist = freelist->as.free.next;
     MEMZERO((void*)obj, RVALUE, 1);
+#ifdef GC_DEBUG
+    RANY(obj)->file = ruby_sourcefile;
+    RANY(obj)->line = ruby_sourceline;
+#endif
     return obj;
 }
 
@@ -346,27 +475,128 @@
 
 extern st_table *rb_class_tbl;
 VALUE *rb_gc_stack_start = 0;
+#ifdef __ia64
+VALUE *rb_gc_register_stack_start = 0;
+#endif
 
-static inline int
-is_pointer_to_heap(ptr)
-    void *ptr;
+VALUE *rb_gc_stack_end = (VALUE *)STACK_GROW_DIRECTION;
+
+
+#ifdef DJGPP
+/* set stack size (http://www.delorie.com/djgpp/v2faq/faq15_9.html) */
+unsigned int _stklen = 0x180000; /* 1.5 kB */
+#endif
+
+#if defined(DJGPP) || defined(_WIN32_WCE)
+static unsigned int STACK_LEVEL_MAX = 65535;
+#elif defined(__human68k__)
+unsigned int _stacksize = 262144;
+# define STACK_LEVEL_MAX (_stacksize - 4096)
+# undef HAVE_GETRLIMIT
+#elif defined(HAVE_GETRLIMIT) || defined(_WIN32)
+static unsigned int STACK_LEVEL_MAX = 655300;
+#else
+# define STACK_LEVEL_MAX 655300
+#endif
+
+#ifndef nativeAllocA
+  /* portable way to return an approximate stack pointer */
+VALUE *__sp(void) {
+  VALUE tos;
+  return &tos;
+}
+# define SET_STACK_END VALUE stack_end
+# define STACK_END (&stack_end)
+#else
+# define SET_STACK_END ((void)0)
+# define STACK_END __sp()
+#endif
+
+#if STACK_GROW_DIRECTION < 0
+# define STACK_LENGTH(start)  ((start) - STACK_END)
+#elif STACK_GROW_DIRECTION > 0
+# define STACK_LENGTH(start)  (STACK_END - (start) + 1)
+#else
+# define STACK_LENGTH(start)  ((STACK_END < (start)) ? \
+                                 (start) - STACK_END : STACK_END - (start) + 1)
+#endif
+
+#if STACK_GROW_DIRECTION > 0
+# define STACK_UPPER(a, b) a
+#else
+# define STACK_UPPER(a, b) b
+#endif
+
+size_t
+stack_length(start)
+    VALUE *start;
+{
+    SET_STACK_END;
+    return STACK_LENGTH(start);
+}
+
+int
+ruby_stack_check()
+{
+    SET_STACK_END;
+    return __stack_past(stack_limit, STACK_END);
+}
+
+/*
+  Zero memory that was (recently) part of the stack, but is no longer.
+  Invoke when stack is deep to mark its extent and when it's shallow to wipe it.
+*/
+#if STACK_WIPE_METHOD != 4
+#if STACK_WIPE_METHOD
+void rb_gc_wipe_stack(void)
+{
+  VALUE *stack_end = rb_gc_stack_end;
+  VALUE *sp = __sp();
+  rb_gc_stack_end = sp;
+#if STACK_WIPE_METHOD == 1
+#warning clearing of "ghost references" from the call stack has been disabled
+#elif STACK_WIPE_METHOD == 2  /* alloca ghost stack before clearing it */
+  if (__stack_past(sp, stack_end)) {
+    size_t bytes = __stack_depth((char *)stack_end, (char *)sp);
+    STACK_UPPER(sp = nativeAllocA(bytes), stack_end = nativeAllocA(bytes));
+    __stack_zero(stack_end, sp);
+  }
+#elif STACK_WIPE_METHOD == 3    /* clear unallocated area past stack pointer */
+  __stack_zero(stack_end, sp);  /* will crash if compiler pushes a temp. here */
+#else
+#error unsupported method of clearing ghost references from the stack
+#endif
+}
+#else
+#warning clearing of "ghost references" from the call stack completely disabled
+#endif
+#endif
+
+#define MARK_STACK_MAX 1024
+static VALUE mark_stack[MARK_STACK_MAX];
+static VALUE *mark_stack_ptr;
+static int mark_stack_overflow;
+
+static void
+init_mark_stack()
 {
-    register RVALUE *p = RANY(ptr);
-    register RVALUE *heap_org;
-    register long i;
+    mark_stack_overflow = 0;
+    mark_stack_ptr = mark_stack;
+}
 
-    if (p < lomem || p > himem) return Qfalse;
+#define MARK_STACK_EMPTY (mark_stack_ptr == mark_stack)
 
-    /* check if p looks like a pointer */
-    for (i=0; i < heaps_used; i++) {
-	heap_org = heaps[i];
-	if (heap_org <= p && p < heap_org + heaps_limits[i] &&
-	    ((((char*)p)-((char*)heap_org))%sizeof(RVALUE)) == 0)
-	    return Qtrue;
+static inline void
+push_mark_stack(VALUE ptr)
+{
+    if (!mark_stack_overflow) {
+	if (mark_stack_ptr - mark_stack < MARK_STACK_MAX)
+	    *mark_stack_ptr++ = ptr;
+	else
+	    mark_stack_overflow = 1;
     }
-    return Qfalse;
 }
-
+    
 static st_table *source_filenames;
 
 char *
@@ -395,7 +625,7 @@
     }
 }
 
-static enum st_retval
+static int
 sweep_source_filename(key, value)
     char *key, *value;
 {
@@ -409,33 +639,82 @@
     }
 }
 
+#define gc_mark(ptr) rb_gc_mark(ptr)
+static void gc_mark_children _((VALUE ptr));
+
+static void
+gc_mark_all()
+{
+    RVALUE *p, *pend;
+    struct heaps_slot *heap = heaps+heaps_used;
+
+    init_mark_stack();
+    while (--heap >= heaps) {
+	p = heap->slot; pend = p + heap->limit;
+	while (p < pend) {
+	    if ((p->as.basic.flags & FL_MARK) &&
+		(p->as.basic.flags != FL_MARK)) {
+		gc_mark_children((VALUE)p);
+	    }
+	    p++;
+	}
+    }
+}
+
+static void
+gc_mark_rest()
+{
+    size_t stackLen = mark_stack_ptr - mark_stack;
+#ifdef nativeAllocA
+    VALUE *tmp_arry = nativeAllocA(stackLen*sizeof(VALUE));
+#else
+    VALUE tmp_arry[MARK_STACK_MAX];
+#endif
+    VALUE *p = tmp_arry + stackLen;
+    
+    MEMCPY(tmp_arry, mark_stack, VALUE, stackLen);
+
+    init_mark_stack();
+    while(--p >= tmp_arry) gc_mark_children(*p);
+}
+
+static inline int
+is_pointer_to_heap(ptr)
+    void *ptr;
+{
+    RVALUE *p = RANY(ptr);
+    struct heaps_slot *heap;
+
+    if (p < lomem || p > himem || (VALUE)p % sizeof(RVALUE)) return Qfalse;
+
+    /* check if p looks like a pointer */
+    heap = heaps+heaps_used;
+    while (--heap >= heaps) 
+      if (p >= heap->slot && p < heap->slot + heap->limit)
+        return Qtrue;
+    return Qfalse;
+}
+
 static void
 mark_locations_array(x, n)
-    register VALUE *x;
-    register long n;
+    VALUE *x;
+    size_t n;
 {
+    VALUE v;
     while (n--) {
-	if (is_pointer_to_heap((void *)*x)) {
-	    rb_gc_mark(*x);
+        v = *x;
+	if (is_pointer_to_heap((void *)v)) {
+	    gc_mark(v);
 	}
 	x++;
     }
 }
 
-void
+inline void
 rb_gc_mark_locations(start, end)
     VALUE *start, *end;
 {
-    VALUE *tmp;
-    long n;
-
-    if (start > end) {
-	tmp = start;
-	start = end;
-	end = tmp;
-    }
-    n = end - start;
-    mark_locations_array(start,n);
+    mark_locations_array(start,end - start);
 }
 
 static int
@@ -443,7 +722,7 @@
     ID key;
     VALUE value;
 {
-    rb_gc_mark(value);
+    gc_mark(value);
     return ST_CONTINUE;
 }
 
@@ -454,14 +733,15 @@
     if (!tbl) return;
     st_foreach(tbl, mark_entry, 0);
 }
+#define mark_tbl(tbl)  rb_mark_tbl(tbl)
 
 static int
-mark_hashentry(key, value)
+mark_keyvalue(key, value)
     VALUE key;
     VALUE value;
 {
-    rb_gc_mark(key);
-    rb_gc_mark(value);
+    gc_mark(key);
+    gc_mark(value);
     return ST_CONTINUE;
 }
 
@@ -470,15 +750,16 @@
     st_table *tbl;
 {
     if (!tbl) return;
-    st_foreach(tbl, mark_hashentry, 0);
+    st_foreach(tbl, mark_keyvalue, 0);
 }
+#define mark_hash(tbl)  rb_mark_hash(tbl)
 
 void
 rb_gc_mark_maybe(obj)
     VALUE obj;
 {
     if (is_pointer_to_heap((void *)obj)) {
-	rb_gc_mark(obj);
+	gc_mark(obj);
     }
 }
 
@@ -486,17 +767,39 @@
 rb_gc_mark(ptr)
     VALUE ptr;
 {
-    register RVALUE *obj = RANY(ptr);
-
-  Top:
-    if (rb_special_const_p((VALUE)obj)) return; /* special const not marked */
+    RVALUE *obj = RANY(ptr);
+    SET_STACK_END;
+    
+    if (rb_special_const_p(ptr)) return; /* special const not marked */
     if (obj->as.basic.flags == 0) return;       /* free cell */
     if (obj->as.basic.flags & FL_MARK) return;  /* already marked */
+    obj->as.basic.flags |= FL_MARK;
+
+    if (__stack_past(gc_stack_limit, STACK_END))
+      push_mark_stack(ptr);
+    else{
+      gc_mark_children(ptr);
+    }
+}
+
+static void
+gc_mark_children(ptr)
+    VALUE ptr;
+{
+    RVALUE *obj = RANY(ptr);
 
+    goto marking;		/* skip */
+
+  again:
+    obj = RANY(ptr);
+    if (rb_special_const_p(ptr)) return; /* special const not marked */
+    if (obj->as.basic.flags == 0) return;       /* free cell */
+    if (obj->as.basic.flags & FL_MARK) return;  /* already marked */
     obj->as.basic.flags |= FL_MARK;
 
+  marking:
     if (FL_TEST(obj, FL_EXIVAR)) {
-	rb_mark_generic_ivar((VALUE)obj);
+	rb_mark_generic_ivar(ptr);
     }
 
     switch (obj->as.basic.flags & T_MASK) {
@@ -516,7 +819,7 @@
 	  case NODE_MASGN:
 	  case NODE_RESCUE:
 	  case NODE_RESBODY:
-	    rb_gc_mark((VALUE)obj->as.node.u2.node);
+	    gc_mark((VALUE)obj->as.node.u2.node);
 	    /* fall through */
 	  case NODE_BLOCK:	/* 1,3 */
 	  case NODE_ARRAY:
@@ -530,14 +833,14 @@
 	  case NODE_CALL:
 	  case NODE_DEFS:
 	  case NODE_OP_ASGN1:
-	    rb_gc_mark((VALUE)obj->as.node.u1.node);
+	    gc_mark((VALUE)obj->as.node.u1.node);
 	    /* fall through */
 	  case NODE_SUPER:	/* 3 */
 	  case NODE_FCALL:
 	  case NODE_DEFN:
 	  case NODE_NEWLINE:
-	    obj = RANY(obj->as.node.u3.node);
-	    goto Top;
+	    ptr = (VALUE)obj->as.node.u3.node;
+	    goto again;
 
 	  case NODE_WHILE:	/* 1,2 */
 	  case NODE_UNTIL:
@@ -553,7 +856,7 @@
 	  case NODE_MATCH3:
 	  case NODE_OP_ASGN_OR:
 	  case NODE_OP_ASGN_AND:
-	    rb_gc_mark((VALUE)obj->as.node.u1.node);
+	    gc_mark((VALUE)obj->as.node.u1.node);
 	    /* fall through */
 	  case NODE_METHOD:	/* 2 */
 	  case NODE_NOT:
@@ -568,8 +871,8 @@
 	  case NODE_MODULE:
 	  case NODE_COLON3:
 	  case NODE_OPT_N:
-	    obj = RANY(obj->as.node.u2.node);
-	    goto Top;
+	    ptr = (VALUE)obj->as.node.u2.node;
+	    goto again;
 
 	  case NODE_HASH:	/* 1 */
 	  case NODE_LIT:
@@ -583,15 +886,15 @@
 	  case NODE_YIELD:
 	  case NODE_COLON2:
 	  case NODE_ARGS:
-	    obj = RANY(obj->as.node.u1.node);
-	    goto Top;
+	    ptr = (VALUE)obj->as.node.u1.node;
+	    goto again;
 
 	  case NODE_SCOPE:	/* 2,3 */
 	  case NODE_CLASS:
 	  case NODE_BLOCK_PASS:
-	    rb_gc_mark((VALUE)obj->as.node.u3.node);
-	    obj = RANY(obj->as.node.u2.node);
-	    goto Top;
+	    gc_mark((VALUE)obj->as.node.u3.node);
+	    ptr = (VALUE)obj->as.node.u2.node;
+	    goto again;
 
 	  case NODE_ZARRAY:	/* - */
 	  case NODE_ZSUPER:
@@ -621,54 +924,52 @@
 	  case NODE_ALLOCA:
 	    mark_locations_array((VALUE*)obj->as.node.u1.value,
 				 obj->as.node.u3.cnt);
-	    obj = RANY(obj->as.node.u2.node);
-	    goto Top;
+	    ptr = (VALUE)obj->as.node.u2.node;
+	    goto again;
 #endif
-
 	  default:
 	    if (is_pointer_to_heap(obj->as.node.u1.node)) {
-		rb_gc_mark((VALUE)obj->as.node.u1.node);
+		gc_mark((VALUE)obj->as.node.u1.node);
 	    }
 	    if (is_pointer_to_heap(obj->as.node.u2.node)) {
-		rb_gc_mark((VALUE)obj->as.node.u2.node);
+		gc_mark((VALUE)obj->as.node.u2.node);
 	    }
 	    if (is_pointer_to_heap(obj->as.node.u3.node)) {
-		obj = RANY(obj->as.node.u3.node);
-		goto Top;
+                ptr = (VALUE)obj->as.node.u3.node;
+                goto again;
 	    }
 	}
-	return;			/* no need to mark class. */
+        return;	/* no need to mark class. */
     }
 
-    rb_gc_mark(obj->as.basic.klass);
+    gc_mark(obj->as.basic.klass);
     switch (obj->as.basic.flags & T_MASK) {
       case T_ICLASS:
       case T_CLASS:
       case T_MODULE:
-	rb_gc_mark(obj->as.klass.super);
-	rb_mark_tbl(obj->as.klass.m_tbl);
-	rb_mark_tbl(obj->as.klass.iv_tbl);
-	break;
+	mark_tbl(obj->as.klass.m_tbl);
+	mark_tbl(obj->as.klass.iv_tbl);
+	ptr = obj->as.klass.super;
+	goto again;
 
       case T_ARRAY:
 	{
-	    int i, len = obj->as.array.len;
 	    VALUE *ptr = obj->as.array.ptr;
-
-	    for (i=0; i < len; i++)
-		rb_gc_mark(*ptr++);
-	}
+            VALUE *pend = ptr + obj->as.array.len;
+          while (ptr < pend)
+		gc_mark(*ptr++);
+	    }
 	break;
 
       case T_HASH:
-	rb_mark_hash(obj->as.hash.tbl);
-	rb_gc_mark(obj->as.hash.ifnone);
-	break;
+	mark_hash(obj->as.hash.tbl);
+	ptr = obj->as.hash.ifnone;
+	goto again;
 
       case T_STRING:
 	if (obj->as.string.orig) {
-	    obj = RANY(obj->as.string.orig);
-	    goto Top;
+	  ptr = obj->as.string.orig;
+	    goto again;
 	}
 	break;
 
@@ -677,7 +978,7 @@
 	break;
 
       case T_OBJECT:
-	rb_mark_tbl(obj->as.object.iv_tbl);
+	mark_tbl(obj->as.object.iv_tbl);
 	break;
 
       case T_FILE:
@@ -689,16 +990,15 @@
 
       case T_MATCH:
 	if (obj->as.match.str) {
-	    obj = RANY(obj->as.match.str);
-	    goto Top;
+	    ptr = obj->as.match.str;
+	    goto again;
 	}
 	break;
 
       case T_VARMAP:
-	rb_gc_mark(obj->as.varmap.val);
-	obj = RANY(obj->as.varmap.next);
-	goto Top;
-	break;
+	gc_mark(obj->as.varmap.val);
+	ptr = (VALUE)obj->as.varmap.next;
+	goto again;
 
       case T_SCOPE:
 	if (obj->as.scope.local_vars && (obj->as.scope.flag & SCOPE_MALLOC)) {
@@ -706,19 +1006,17 @@
 	    VALUE *vars = &obj->as.scope.local_vars[-1];
 
 	    while (n--) {
-		rb_gc_mark(*vars);
-		vars++;
+		gc_mark(*vars++);
 	    }
 	}
 	break;
 
       case T_STRUCT:
 	{
-	    int i, len = obj->as.rstruct.len;
 	    VALUE *ptr = obj->as.rstruct.ptr;
-
-	    for (i=0; i < len; i++)
-		rb_gc_mark(*ptr++);
+            VALUE *pend = ptr + obj->as.rstruct.len;
+            while (ptr < pend)
+	       gc_mark(*ptr++);
 	}
 	break;
 
@@ -732,47 +1030,96 @@
 static void obj_free _((VALUE));
 
 static void
+finalize_list(p)
+    RVALUE *p;
+{
+    while (p) {
+	RVALUE *tmp = p->as.free.next;
+	run_final((VALUE)p);
+	if (!FL_TEST(p, FL_SINGLETON)) { /* not freeing page */
+	    p->as.free.flags = 0;
+	    p->as.free.next = freelist;
+	    freelist = p;
+	}
+	p = tmp;
+    }
+}
+
+static void
+free_unused_heaps()
+{
+    int i, j;
+
+    for (i = j = 1; j < heaps_used; i++) {
+	if (heaps[i].limit == 0) {
+	    free(heaps[i].membase);
+	    heaps_used--;
+	}
+	else {
+	    if (i != j) {
+		heaps[j] = heaps[i];
+	    }
+	    j++;
+	}
+    }
+}
+
+void rb_gc_abort_threads(void);
+
+static void
 gc_sweep()
 {
     RVALUE *p, *pend, *final_list;
     int freed = 0;
-    int i, used = heaps_used;
+    int i;
+    long free_min = 0;
+
+    for (i = 0; i < heaps_used; i++) {
+        free_min += heaps[i].limit;
+    }
+    free_min /= 5;
+    if (free_min < FREE_MIN)
+        free_min = FREE_MIN;
 
     if (ruby_in_compile && ruby_parser_stack_on_heap()) {
 	/* should not reclaim nodes during compilation
            if yacc's semantic stack is not allocated on machine stack */
-	for (i = 0; i < used; i++) {
-	    p = heaps[i]; pend = p + heaps_limits[i];
+	for (i = 0; i < heaps_used; i++) {
+	    p = heaps[i].slot; pend = p + heaps[i].limit;
 	    while (p < pend) {
 		if (!(p->as.basic.flags&FL_MARK) && BUILTIN_TYPE(p) == T_NODE)
-		    rb_gc_mark((VALUE)p);
+		    gc_mark((VALUE)p);
 		p++;
 	    }
 	}
     }
 
     mark_source_filename(ruby_sourcefile);
-    st_foreach(source_filenames, sweep_source_filename, 0);
+    if (source_filenames) {
+        st_foreach(source_filenames, sweep_source_filename, 0);
+    }
 
     freelist = 0;
     final_list = deferred_final_list;
     deferred_final_list = 0;
-    for (i = 0; i < used; i++) {
+    for (i = 0; i < heaps_used; i++) {
 	int n = 0;
+	RVALUE *free = freelist;
+	RVALUE *final = final_list;
 
-	p = heaps[i]; pend = p + heaps_limits[i];
+	p = heaps[i].slot; pend = p + heaps[i].limit;
 	while (p < pend) {
 	    if (!(p->as.basic.flags & FL_MARK)) {
 		if (p->as.basic.flags) {
 		    obj_free((VALUE)p);
 		}
 		if (need_call_final && FL_TEST(p, FL_FINALIZE)) {
-		    p->as.free.flag = FL_MARK; /* remain marked */
+		    p->as.free.flags = FL_MARK; /* remain marked */
 		    p->as.free.next = final_list;
 		    final_list = p;
 		}
 		else {
-		    p->as.free.flag = 0;
+		    p->as.free.flags = 0;
 		    p->as.free.next = freelist;
 		    freelist = p;
 		}
@@ -780,44 +1127,45 @@
 	    }
 	    else if (RBASIC(p)->flags == FL_MARK) {
 		/* objects to be finalized */
-		/* do notning remain marked */
+		/* do nothing remain marked */
 	    }
 	    else {
 		RBASIC(p)->flags &= ~FL_MARK;
 	    }
 	    p++;
 	}
-	freed += n;
+	if (n == heaps[i].limit && freed > free_min) {
+	    RVALUE *pp;
+
+	    heaps[i].limit = 0;
+	    for (pp = final_list; pp != final; pp = pp->as.free.next) {
+		pp->as.free.flags |= FL_SINGLETON; /* freeing page mark */
+	    }
+	    freelist = free;	/* cancel this page from freelist */
+	}
+	else {
+	    freed += n;
+	}
     }
-    if (freed < FREE_MIN) {
+    malloc_increase = 0;
+    if (freed < free_min) {
 	add_heap();
     }
     during_gc = 0;
 
     /* clear finalization list */
     if (final_list) {
-	RVALUE *tmp;
-
-	if (rb_prohibit_interrupt || ruby_in_compile) {
-	    deferred_final_list = final_list;
-	    return;
-	}
-
-	for (p = final_list; p; p = tmp) {
-	    tmp = p->as.free.next;
-	    run_final((VALUE)p);
-	    p->as.free.flag = 0;
-	    p->as.free.next = freelist;
-	    freelist = p;
-	}
+	deferred_final_list = final_list;
+	return;
     }
+    free_unused_heaps();
 }
 
 void
 rb_gc_force_recycle(p)
     VALUE p;
 {
-    RANY(p)->as.free.flag = 0;
+    RANY(p)->as.free.flags = 0;
     RANY(p)->as.free.next = freelist;
     freelist = RANY(p);
 }
@@ -961,6 +1309,8 @@
 
 #ifdef __GNUC__
 #if defined(__human68k__) || defined(DJGPP)
+#undef rb_setjmp
+#undef rb_jmp_buf
 #if defined(__human68k__)
 typedef unsigned long rb_jmp_buf[8];
 __asm__ (".even\n\
@@ -969,9 +1319,6 @@
 	movem.l	d3-d7/a3-a5,(a0)\n\
 	moveq.l	#0,d0\n\
 	rts");
-#ifdef setjmp
-#undef setjmp
-#endif
 #else
 #if defined(DJGPP)
 typedef unsigned long rb_jmp_buf[6];
@@ -992,46 +1339,38 @@
 #endif
 #endif
 int rb_setjmp (rb_jmp_buf);
-#define jmp_buf rb_jmp_buf
-#define setjmp rb_setjmp
 #endif /* __human68k__ or DJGPP */
 #endif /* __GNUC__ */
 
-void
-rb_gc()
+
+
+static void
+garbage_collect_0(VALUE *top_frame)
 {
     struct gc_list *list;
-    struct FRAME * volatile frame; /* gcc 2.7.2.3 -O2 bug??  */
-    jmp_buf save_regs_gc_mark;
-#ifdef C_ALLOCA
-    VALUE stack_end;
-    alloca(0);
-# define STACK_END (&stack_end)
-#else
-# if defined(__GNUC__) && (defined(__i386__) || defined(__mc68000__))
-    VALUE *stack_end = __builtin_frame_address(0);
-# else
-    VALUE *stack_end = alloca(1);
-# endif
-# define STACK_END (stack_end)
-#endif
+    struct FRAME * frame;
+    SET_STACK_END;
 
+#ifdef HAVE_NATIVETHREAD
+    if (!is_ruby_native_thread()) {
+	rb_bug("cross-thread violation on rb_gc()");
+    }
+#endif
     if (dont_gc || during_gc) {
-	if (!freelist || malloc_memories > GC_MALLOC_LIMIT) {
-	    malloc_memories = 0;
+	if (!freelist) {
 	    add_heap();
 	}
 	return;
     }
-
-    malloc_memories = 0;
-
     if (during_gc) return;
     during_gc++;
 
+    gc_stack_limit = __stack_grow(STACK_END, GC_LEVEL_MAX);
+    init_mark_stack();
+
     /* mark frame stack */
     for (frame = ruby_frame; frame; frame = frame->prev) {
-	rb_gc_mark_frame(frame); 
+	rb_gc_mark_frame(frame);
 	if (frame->tmp) {
 	    struct FRAME *tmp = frame->tmp;
 	    while (tmp) {
@@ -1044,23 +1383,33 @@
     rb_gc_mark((VALUE)ruby_scope);
     rb_gc_mark((VALUE)ruby_dyna_vars);
     if (finalizer_table) {
-	rb_mark_tbl(finalizer_table);
+	mark_tbl(finalizer_table);
     }
 
-    FLUSH_REGISTER_WINDOWS;
-    /* This assumes that all registers are saved into the jmp_buf */
-    setjmp(save_regs_gc_mark);
-    mark_locations_array((VALUE*)save_regs_gc_mark, sizeof(save_regs_gc_mark) / sizeof(VALUE *));
-    rb_gc_mark_locations(rb_gc_stack_start, (VALUE*)STACK_END);
-#if defined(__human68k__)
-    rb_gc_mark_locations((VALUE*)((char*)rb_gc_stack_start + 2),
-			 (VALUE*)((char*)STACK_END + 2));
+#if STACK_GROW_DIRECTION < 0
+    rb_gc_mark_locations(top_frame, rb_curr_thread->stk_start);
+#elif STACK_GROW_DIRECTION > 0
+    rb_gc_mark_locations(rb_curr_thread->stk_start, top_frame + 1);
+#else
+    if (rb_gc_stack_grow_direction < 0)
+	rb_gc_mark_locations(top_frame, rb_curr_thread->stk_start);
+    else
+	rb_gc_mark_locations(rb_curr_thread->stk_start, top_frame + 1);
+#endif
+#ifdef __ia64
+    /* mark backing store (flushed register window on the stack) */
+    /* the basic idea from guile GC code                         */
+    rb_gc_mark_locations(rb_gc_register_stack_start, (VALUE*)rb_ia64_bsp());
+#endif
+#if defined(__human68k__) || defined(__mc68000__)
+    rb_gc_mark_locations((VALUE*)((char*)STACK_END + 2),
+			 (VALUE*)((char*)rb_curr_thread->stk_start + 2));
 #endif
     rb_gc_mark_threads();
 
     /* mark protected global variables */
     for (list = Global_List; list; list = list->next) {
-	rb_gc_mark(*list->varptr);
+	rb_gc_mark_maybe(*list->varptr);
     }
     rb_mark_end_proc();
     rb_gc_mark_global_tbl();
@@ -1073,52 +1422,240 @@
 
     rb_gc_mark_parser();
 
+    /* gc_mark objects whose marking are not completed*/
+    do {
+	while (!MARK_STACK_EMPTY) {
+	    if (mark_stack_overflow){
+		gc_mark_all();
+	    }
+	    else {
+		gc_mark_rest();
+	    }
+	}
+	rb_gc_abort_threads();
+    } while (!MARK_STACK_EMPTY);
     gc_sweep();
 }
 
-static VALUE
-gc_start()
+static void
+garbage_collect()
+{
+  jmp_buf save_regs_gc_mark;
+  VALUE *top = __sp();
+  FLUSH_REGISTER_WINDOWS;
+  /* This assumes that all registers are saved into the jmp_buf (and stack) */
+  setjmp(save_regs_gc_mark);
+
+#if STACK_WIPE_SITES & 0x400
+# ifdef nativeAllocA
+  if (__stack_past (top, stack_limit)) {
+  /* allocate a large frame to ensure app stack cannot grow into GC stack */
+    (volatile void*) nativeAllocA(__stack_depth((void*)stack_limit,(void*)top));
+  }  
+  garbage_collect_0(top);
+# else /* no native alloca() available */
+  garbage_collect_0(top);
+  {
+    VALUE *paddedLimit = __stack_grow(gc_stack_limit, GC_STACK_PAD);
+    if (__stack_past(rb_gc_stack_end, paddedLimit))
+      rb_gc_stack_end = paddedLimit;
+  }
+  rb_gc_wipe_stack();  /* wipe the whole stack area reserved for this gc */  
+# endif
+#else
+  garbage_collect_0(top);
+#endif
+}
+
+
+void
+rb_gc_finalize_deferred()
+{
+    RVALUE *p = deferred_final_list;
+
+    deferred_final_list = 0;
+    if (p) {
+	finalize_list(p);
+	free_unused_heaps();
+    }
+}
+
+
+void
+rb_gc()
+{
+    garbage_collect();
+    rb_gc_finalize_deferred();
+}
+
+/*
+ *  call-seq:
+ *     GC.start                     => nil
+ *     gc.garbage_collect           => nil
+ *     ObjectSpace.garbage_collect  => nil
+ *
+ *  Initiates garbage collection, unless manually disabled.
+ *
+ */
+
+VALUE
+rb_gc_start()
 {
     rb_gc();
     return Qnil;
 }
 
-#if !defined(__human68k__)
-static int
-stack_growup_p(addr)
-    VALUE *addr;
-{
-    VALUE dummy;
 
-    if (&dummy > addr) return Qtrue;
-    return Qfalse;
+void
+ruby_set_stack_size(size)
+    size_t size;
+{
+#ifndef STACK_LEVEL_MAX
+    STACK_LEVEL_MAX = size / sizeof(VALUE);
+#endif
+    stack_limit = __stack_grow(rb_gc_stack_start, STACK_LEVEL_MAX-GC_STACK_MAX);
 }
+
+static void
+set_stack_size(void)
+{
+#ifdef HAVE_GETRLIMIT
+  struct rlimit rlim;
+  if (getrlimit(RLIMIT_STACK, &rlim) == 0) {
+    if (rlim.rlim_cur > 0 && rlim.rlim_cur != RLIM_INFINITY) {
+      size_t maxStackBytes = rlim.rlim_cur;
+      if (rlim.rlim_cur != maxStackBytes)
+        maxStackBytes = -1;
+      {
+        size_t space = maxStackBytes/5;
+        if (space > 1024*1024) space = 1024*1024;
+        ruby_set_stack_size(maxStackBytes - space);
+        return;
+      }
+    }
+  }
 #endif
+  ruby_set_stack_size(STACK_LEVEL_MAX*sizeof(VALUE));
+}
 
 void
 Init_stack(addr)
     VALUE *addr;
 {
-#if defined(__human68k__)
-    extern void *_SEND;
-    rb_gc_stack_start = _SEND;
+#ifdef __ia64
+    if (rb_gc_register_stack_start == 0) {
+# if defined(__FreeBSD__)
+        /*
+         * FreeBSD/ia64 currently does not have a way for a process to get the
+         * base address for the RSE backing store, so hardcode it.
+         */
+        rb_gc_register_stack_start = (4ULL<<61);
+# elif defined(HAVE___LIBC_IA64_REGISTER_BACKING_STORE_BASE)
+#  pragma weak __libc_ia64_register_backing_store_base
+        extern unsigned long __libc_ia64_register_backing_store_base;
+        rb_gc_register_stack_start = (VALUE*)__libc_ia64_register_backing_store_base;
+# endif
+    }
+    {
+        VALUE *bsp = (VALUE*)rb_ia64_bsp();
+        if (rb_gc_register_stack_start == 0 ||
+            bsp < rb_gc_register_stack_start) {
+            rb_gc_register_stack_start = bsp;
+        }
+    }
+#endif
+#if defined(_WIN32) || defined(__CYGWIN__)
+    MEMORY_BASIC_INFORMATION m;
+    memset(&m, 0, sizeof(m));
+    VirtualQuery(&m, &m, sizeof(m));
+    rb_gc_stack_start =
+	STACK_UPPER((VALUE *)m.BaseAddress,
+		    (VALUE *)((char *)m.BaseAddress + m.RegionSize) - 1);
+#elif defined(STACK_END_ADDRESS)
+    {
+        extern void *STACK_END_ADDRESS;
+        rb_gc_stack_start = STACK_END_ADDRESS;
+    }
 #else
-    if (!addr) addr = (VALUE *)&addr;
+    if (!addr) addr = (void *)&addr;
+    STACK_UPPER(addr, ++addr);
     if (rb_gc_stack_start) {
-	if (stack_growup_p(addr)) {
-	    if (rb_gc_stack_start > --addr)
-		rb_gc_stack_start = addr;
-	}
-	else {
-	    if (rb_gc_stack_start < ++addr)
-		rb_gc_stack_start = addr;
-	}
+	if (STACK_UPPER(rb_gc_stack_start > addr,
+			rb_gc_stack_start < addr))
+	    rb_gc_stack_start = addr;
 	return;
     }
     rb_gc_stack_start = addr;
 #endif
+    set_stack_size();
 }
 
+void ruby_init_stack(VALUE *addr
+#ifdef __ia64
+    , void *bsp
+#endif
+    )
+{
+    if (!rb_gc_stack_start ||
+        STACK_UPPER(rb_gc_stack_start > addr,
+                    rb_gc_stack_start < addr)) {
+        rb_gc_stack_start = addr;
+    }
+#ifdef __ia64
+    if (!rb_gc_register_stack_start ||
+        (VALUE*)bsp < rb_gc_register_stack_start) {
+        rb_gc_register_stack_start = (VALUE*)bsp;
+    }
+#endif
+#ifdef HAVE_GETRLIMIT
+    set_stack_size();
+#elif defined _WIN32
+    {
+	MEMORY_BASIC_INFORMATION mi;
+	DWORD size;
+	DWORD space;
+
+	if (VirtualQuery(&mi, &mi, sizeof(mi))) {
+	    size = (char *)mi.BaseAddress - (char *)mi.AllocationBase;
+	    space = size / 5;
+	    if (space > 1024*1024) space = 1024*1024;
+	    ruby_set_stack_size(size - space);
+	}
+    }
+#endif
+}
+
+/*
+ * Document-class: ObjectSpace
+ *
+ *  The <code>ObjectSpace</code> module contains a number of routines
+ *  that interact with the garbage collection facility and allow you to
+ *  traverse all living objects with an iterator.
+ *
+ *  <code>ObjectSpace</code> also provides support for object
+ *  finalizers, procs that will be called when a specific object is
+ *  about to be destroyed by garbage collection.
+ *
+ *     include ObjectSpace
+ *
+ *
+ *     a = "A"
+ *     b = "B"
+ *     c = "C"
+ *
+ *
+ *     define_finalizer(a, proc {|id| puts "Finalizer one on #{id}" })
+ *     define_finalizer(a, proc {|id| puts "Finalizer two on #{id}" })
+ *     define_finalizer(b, proc {|id| puts "Finalizer three on #{id}" })
+ *
+ *  <em>produces:</em>
+ *
+ *     Finalizer three on 537763470
+ *     Finalizer one on 537763480
+ *     Finalizer two on 537763480
+ *
+ */
+
 void
 Init_heap()
 {
@@ -1137,10 +1674,11 @@
     for (i = 0; i < heaps_used; i++) {
 	RVALUE *p, *pend;
 
-	p = heaps[i]; pend = p + heaps_limits[i];
+	p = heaps[i].slot; pend = p + heaps[i].limit;
 	for (;p < pend; p++) {
 	    if (p->as.basic.flags) {
-		switch (TYPE(p)) {
+		switch (BUILTIN_TYPE(p)) {
+                  case T_NONE:
 		  case T_ICLASS:
 		  case T_VARMAP:
 		  case T_SCOPE:
@@ -1156,7 +1694,6 @@
 	    }
 	}
     }
-
     return INT2FIX(n);
 }
 
@@ -1170,10 +1707,11 @@
     for (i = 0; i < heaps_used; i++) {
 	RVALUE *p, *pend;
 
-	p = heaps[i]; pend = p + heaps_limits[i];
+	p = heaps[i].slot; pend = p + heaps[i].limit;
 	for (;p < pend; p++) {
 	    if (p->as.basic.flags) {
-		switch (TYPE(p)) {
+		switch (BUILTIN_TYPE(p)) {
+		  case T_NONE:
 		  case T_ICLASS:
 		  case T_VARMAP:
 		  case T_SCOPE:
@@ -1191,10 +1729,42 @@
 	    }
 	}
     }
-
     return INT2FIX(n);
 }
 
+/*
+ *  call-seq:
+ *     ObjectSpace.each_object([module]) {|obj| ... } => fixnum
+ *
+ *  Calls the block once for each living, nonimmediate object in this
+ *  Ruby process. If <i>module</i> is specified, calls the block
+ *  for only those classes or modules that match (or are a subclass of)
+ *  <i>module</i>. Returns the number of objects found. Immediate
+ *  objects (<code>Fixnum</code>s, <code>Symbol</code>s
+ *  <code>true</code>, <code>false</code>, and <code>nil</code>) are
+ *  never returned. In the example below, <code>each_object</code>
+ *  returns both the numbers we defined and several constants defined in
+ *  the <code>Math</code> module.
+ *
+ *     a = 102.7
+ *     b = 95       # Won't be returned
+ *     c = 12345678987654321
+ *     count = ObjectSpace.each_object(Numeric) {|x| p x }
+ *     puts "Total count: #{count}"
+ *
+ *  <em>produces:</em>
+ *
+ *     12345678987654321
+ *     102.7
+ *     2.71828182845905
+ *     3.14159265358979
+ *     2.22044604925031e-16
+ *     1.7976931348623157e+308
+ *     2.2250738585072e-308
+ *     Total count: 7
+ *
+ */
+
 static VALUE
 os_each_obj(argc, argv)
     int argc;
@@ -1206,8 +1776,8 @@
 	return os_live_obj();
     }
     else {
-	return os_obj_of(of);
-    }
+    return os_obj_of(of);
+}
 }
 
 static VALUE finalizers;
@@ -1245,7 +1815,7 @@
 call_final(os, obj)
     VALUE os, obj;
 {
-    rb_warn("ObjectSpace::call_final is deprecated; use define_finalizer");
+    rb_warn("ObjectSpace::call_finalizer is deprecated; use define_finalizer");
     need_call_final = 1;
     FL_SET(obj, FL_FINALIZE);
     return obj;
@@ -1255,8 +1825,6 @@
 undefine_final(os, obj)
     VALUE os, obj;
 {
-    VALUE table;
-
     if (finalizer_table) {
 	st_delete(finalizer_table, &obj, 0);
     }
@@ -1318,7 +1886,7 @@
 	for (i=0; i<RARRAY(table)->len; i++) {
 	    args[0] = RARRAY(table)->ptr[i];
 	    rb_protect(run_single_final, (VALUE)args, &status);
-	}
+}
     }
 }
 
@@ -1331,7 +1899,7 @@
     /* run finalizers */
     if (need_call_final) {
 	if (deferred_final_list) {
-	    p = deferred_final_list;
+	p = deferred_final_list;
 	    while (p) {
 		RVALUE *tmp = p;
 		p = p->as.free.next;
@@ -1339,7 +1907,7 @@
 	    }
 	}
 	for (i = 0; i < heaps_used; i++) {
-	    p = heaps[i]; pend = p + heaps_limits[i];
+	    p = heaps[i].slot; pend = p + heaps[i].limit;
 	    while (p < pend) {
 		if (FL_TEST(p, FL_FINALIZE)) {
 		    FL_UNSET(p, FL_FINALIZE);
@@ -1350,13 +1918,13 @@
 	    }
 	}
     }
-    /* run data object's finaliers */
+    /* run data object's finalizers */
     for (i = 0; i < heaps_used; i++) {
-	p = heaps[i]; pend = p + heaps_limits[i];
+	p = heaps[i].slot; pend = p + heaps[i].limit;
 	while (p < pend) {
 	    if (BUILTIN_TYPE(p) == T_DATA &&
 		DATA_PTR(p) && RANY(p)->as.data.dfree) {
-		p->as.free.flag = 0;
+		p->as.free.flags = 0;
 		if ((long)RANY(p)->as.data.dfree == -1) {
 		    RUBY_CRITICAL(free(DATA_PTR(p)));
 		}
@@ -1365,7 +1933,7 @@
 		}
 	    }
 	    else if (BUILTIN_TYPE(p) == T_FILE) {
-		p->as.free.flag = 0;
+		p->as.free.flags = 0;
 		rb_io_fptr_finalize(RANY(p)->as.file.fptr);
 	    }
 	    p++;
@@ -1373,6 +1941,19 @@
     }
 }
 
+/*
+ *  call-seq:
+ *     ObjectSpace._id2ref(object_id) -> an_object
+ *
+ *  Converts an object id to a reference to the object. May not be
+ *  called on an object id passed as a parameter to a finalizer.
+ *
+ *     s = "I am a string"                    #=> "I am a string"
+ *     r = ObjectSpace._id2ref(s.object_id)   #=> "I am a string"
+ *     r == s                                 #=> true
+ *
+ */
+
 static VALUE
 id2ref(obj, id)
     VALUE obj, id;
@@ -1399,20 +1980,47 @@
     return (VALUE)ptr;
 }
 
+/*
+ *  Document-method: __id__
+ *  Document-method: object_id
+ *
+ *  call-seq:
+ *     obj.__id__       => fixnum
+ *     obj.object_id    => fixnum
+ *
+ *  Returns an integer identifier for <i>obj</i>. The same number will
+ *  be returned on all calls to <code>id</code> for a given object, and
+ *  no two active objects will share an id.
+ *  <code>Object#object_id</code> is a different concept from the
+ *  <code>:name</code> notation, which returns the symbol id of
+ *  <code>name</code>. Replaces the deprecated <code>Object#id</code>.
+ */
+
+
+/*
+ *  The <code>GC</code> module provides an interface to Ruby's mark and
+ *  sweep garbage collection mechanism. Some of the underlying methods
+ *  are also available via the <code>ObjectSpace</code> module.
+ */
+
 void
 Init_GC()
 {
     VALUE rb_mObSpace;
 
     rb_mGC = rb_define_module("GC");
-    rb_define_singleton_method(rb_mGC, "start", gc_start, 0);
-    rb_define_singleton_method(rb_mGC, "enable", gc_enable, 0);
-    rb_define_singleton_method(rb_mGC, "disable", gc_disable, 0);
-    rb_define_method(rb_mGC, "garbage_collect", gc_start, 0);
+    rb_define_singleton_method(rb_mGC, "start", rb_gc_start, 0);
+    rb_define_singleton_method(rb_mGC, "enable", rb_gc_enable, 0);
+    rb_define_singleton_method(rb_mGC, "disable", rb_gc_disable, 0);
+    rb_define_singleton_method(rb_mGC, "limit", gc_getlimit, 0);
+    rb_define_singleton_method(rb_mGC, "limit=", gc_setlimit, 1);
+    rb_define_singleton_method(rb_mGC, "growth", gc_growth, 0);
+    rb_define_singleton_method(rb_mGC, "exorcise", gc_exorcise, 0);
+    rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0);
 
     rb_mObSpace = rb_define_module("ObjectSpace");
     rb_define_module_function(rb_mObSpace, "each_object", os_each_obj, -1);
-    rb_define_module_function(rb_mObSpace, "garbage_collect", gc_start, 0);
+    rb_define_module_function(rb_mObSpace, "garbage_collect", rb_gc_start, 0);
     rb_define_module_function(rb_mObSpace, "add_finalizer", add_final, 1);
     rb_define_module_function(rb_mObSpace, "remove_finalizer", rm_final, 1);
     rb_define_module_function(rb_mObSpace, "finalizers", finals, 0);
Only in ruby: gc-patch.txt
diff -ru ruby.snapshot/Makefile.in ruby/Makefile.in
--- ruby.snapshot/Makefile.in	2003-02-20 06:15:04.000000000 -0800
+++ ruby/Makefile.in	2009-01-10 00:57:46.000000000 -0800
@@ -86,7 +86,7 @@
 MANTYPE	      = @MANTYPE@
 
 all:		miniruby$(EXEEXT) @PREP@ rbconfig.rb $(LIBRUBY)
-		@@MINIRUBY@ -Cext extmk.rb @EXTSTATIC@
+		@./miniruby -Cext extmk.rb @EXTSTATIC@
 
 miniruby$(EXEEXT):	config.status $(LIBRUBY_A) $(MAINOBJ) dmyext.@OBJEXT@
 		@rm -f $@
@@ -102,15 +102,15 @@
 
 $(LIBRUBY_SO):	$(OBJS) dmyext.@OBJEXT@ miniruby$(EXEEXT)
 		$(LDSHARED) $(DLDFLAGS) $(OBJS) dmyext.@OBJEXT@ $(SOLIBS) -o $@
-		@-@MINIRUBY@ -e 'ARGV.each{|link| File.delete link if File.exist? link; \
+		@-./miniruby -e 'ARGV.each{|link| File.delete link if File.exist? link; \
 						  File.symlink "$(LIBRUBY_SO)", link}' \
 				$(LIBRUBY_ALIASES) || true
 
 install:	rbconfig.rb
-		@MINIRUBY@ $(srcdir)/instruby.rb --mantype=$(MANTYPE) $(DESTDIR)
+		@./miniruby $(srcdir)/instruby.rb --mantype=$(MANTYPE) $(DESTDIR)
 
 clean-ext:
-		@-@MINIRUBY@ -Cext extmk.rb clean 2> /dev/null || true
+		@-./miniruby -Cext extmk.rb clean 2> /dev/null || true
 
 clean: clean-ext
 		@rm -f $(OBJS) $(MAINOBJ) $(LIBRUBY_A) $(LIBRUBY_SO) $(LIBRUBY_ALIASES)
@@ -118,10 +118,10 @@
 		@rm -f $(PROGRAM) miniruby$(EXEEXT)
 
 distclean-ext:
-		@-@MINIRUBY@ -Cext extmk.rb distclean 2> /dev/null || true
+		@-./miniruby -Cext extmk.rb distclean 2> /dev/null || true
 
 distclean: distclean-ext clean
-		@rm -f Makefile ext/extmk.rb config.h rbconfig.rb
+		@rm -f Makefile ext/extmk.rb config.h rbconfig.rb fake.rb
 		@rm -f ext/config.cache config.cache config.log config.status
 		@rm -f *~ core *.core gmon.out y.tab.c y.output ruby.imp
 
@@ -130,18 +130,16 @@
 		@rm -f lex.c
 
 test:		miniruby$(EXEEXT) rbconfig.rb
-		@./miniruby$(EXEEXT) $(srcdir)/rubytest.rb
+		@./miniruby $(srcdir)/rubytest.rb
 
 rbconfig.rb:	miniruby$(EXEEXT) $(srcdir)/mkconfig.rb config.status
-		@@MINIRUBY@ $(srcdir)/mkconfig.rb rbconfig.rb
+		@./miniruby $(srcdir)/mkconfig.rb rbconfig.rb
 
 fake.rb:	miniruby$(EXEEXT)
 		@echo ' \
 		class Object; \
 		  remove_const :RUBY_PLATFORM; \
-		  remove_const :RUBY_VERSION; \
 		  RUBY_PLATFORM = "@arch@"; \
-		  RUBY_VERSION = "@MAJOR@.@MINOR@.@TEENY@"; \
 		  CROSS_COMPILING = true; \
 		end \
 		' > $@
@@ -280,4 +278,4 @@
 time.@OBJEXT@: time.c ruby.h config.h defines.h intern.h
 util.@OBJEXT@: util.c ruby.h config.h defines.h intern.h util.h
 variable.@OBJEXT@: variable.c ruby.h config.h defines.h intern.h env.h node.h st.h
-version.@OBJEXT@: version.c ruby.h config.h defines.h intern.h version.h
+version.@OBJEXT@: version.c ruby.h rubysig.h config.h defines.h intern.h version.h
diff -ru ruby.snapshot/missing/alloca.c ruby/missing/alloca.c
--- ruby.snapshot/missing/alloca.c	2001-05-01 01:45:26.000000000 -0700
+++ ruby/missing/alloca.c	2009-01-29 16:29:15.000000000 -0800
@@ -28,6 +28,7 @@
 static char	SCCSid[] = "@(#)alloca.c	1.1";	/* for the "what" utility */
 #endif
 
+#include <sys/types.h>
 #include "config.h"
 #ifdef emacs
 #ifdef static
@@ -43,11 +44,7 @@
 #endif /* static */
 #endif /* emacs */
 
-#ifdef X3J11
 typedef void	*pointer;		/* generic pointer type */
-#else
-typedef char	*pointer;		/* generic pointer type */
-#endif /* X3J11 */
 
 #define	NULL	0			/* null pointer constant */
 
@@ -134,8 +131,7 @@
 static header *last_alloca_header = NULL; /* -> last alloca header */
 
 pointer
-alloca (size)			/* returns pointer to storage */
-     unsigned	size;		/* # bytes to allocate */
+alloca (size_t size)		/* returns pointer to storage */
 {
   auto char	probe;		/* probes stack depth: */
   register char	*depth = &probe;
diff -ru ruby.snapshot/mkconfig.rb ruby/mkconfig.rb
--- ruby.snapshot/mkconfig.rb	2002-10-26 19:16:55.000000000 -0700
+++ ruby/mkconfig.rb	2009-02-01 21:52:57.000000000 -0800
@@ -25,22 +25,62 @@
 print "  DESTDIR = '' if not defined? DESTDIR\n  CONFIG = {}\n"
 v_fast = []
 v_others = []
+vars = {}
 has_srcdir = false
 has_version = false
-File.foreach "config.status" do |$_|
-  next if /^#/
-  if /^s[%,]@program_transform_name@[%,]s,(.*)/
-    next if $install_name
-    ptn = $1.sub(/\$\$/, '$').split(/,/)	#'
-    v_fast << "  CONFIG[\"ruby_install_name\"] = \"" + "ruby".sub(ptn[0],ptn[1]) + "\"\n"
-  elsif /^s[%,]@(\w+)@[%,](.*)[%,]/
+continued_name = nil
+continued_line = nil
+File.foreach "config.status" do |line|
+  next if /^#/ =~ line
+  name = nil
+  case line
+  when /^s([%,])@(\w+)@\1(?:\|\#_!!_\#\|)?(.*)\1/
+    name = $2
+    val = $3.gsub(/\\(?=,)/, '')
+  when /^S\["(\w+)"\]\s*=\s*"(.*)"\s*(\\)?$/
     name = $1
-    val = $2 || ""
-    next if name =~ /^(INSTALL|DEFS|configure_input|srcdir|top_srcdir)$/
-    next if $install_name and name =~ /^RUBY_INSTALL_NAME$/
-    next if $so_name and name =~ /^RUBY_SO_NAME$/
-    v = "  CONFIG[\"" + name + "\"] = " +
-      val.strip.gsub(/\$\{?(\w+)\}?/) {"$(#{$1})"}.dump + "\n"
+    val = $2
+    if $3
+      continued_line = []
+      continued_line << val
+      continued_name = name
+      next
+    end
+  when /^"(.+)"\s*(\\)?$/
+    if continued_line
+      continued_line <<  $1
+      unless $2
+	val = continued_line.join("")
+	name = continued_name
+	continued_line = nil
+      end
+    end
+  when /^(?:ac_given_)?INSTALL=(.*)/
+    v_fast << "  CONFIG[\"INSTALL\"] = " + $1 + "\n"
+  end
+
+  if name
+    next if /^(?:ac_.*|configure_input|(?:top_)?srcdir|\w+OBJS)$/ =~ name
+    next if /^\$\(ac_\w+\)$/ =~ val
+    next if /^\$\{ac_\w+\}$/ =~ val
+    next if /^\$ac_\w+$/ =~ val
+    next if $install_name and /^RUBY_INSTALL_NAME$/ =~ name
+    next if $so_name and /^RUBY_SO_NAME$/ =~  name
+    next if /^(?:X|(?:MINI|RUN)RUBY$)/ =~ name
+    if /^program_transform_name$/ =~ name and /^s(\\?.)(.*)\1$/ =~ val
+      next if $install_name
+      sep = %r"#{Regexp.quote($1)}"
+      ptn = $2.sub(/\$\$/, '$').split(sep, 2)
+      name = "ruby_install_name"
+      val = "ruby".sub(/#{ptn[0]}/, ptn[1])
+    end
+    val.gsub!(/ +(?!-)/, "=") if name == "configure_args" && /mswin32/ =~ RUBY_PLATFORM
+    val = val.gsub(/\$(?:\$|\{?(\w+)\}?)/) {$1 ? "$(#{$1})" : $&}.dump
+    if /^prefix$/ =~ name
+      val = "(TOPDIR || DESTDIR + #{val})"
+    end
+    v = "  CONFIG[\"#{name}\"] #{vars[name] ? '<< "\n"' : '='} #{val}\n"
+    vars[name] = true
     if fast[name]
       v_fast << v
     else
diff -ru ruby.snapshot/node.h ruby/node.h
--- ruby.snapshot/node.h	2002-10-26 08:57:23.000000000 -0700
+++ ruby/node.h	2009-02-10 20:32:50.000000000 -0800
@@ -2,8 +2,8 @@
 
   node.h -
 
-  $Author: knu $
-  $Date: 2002/10/26 15:57:23 $
+  $Author: brent $
+  $Date: 2009/02/11 04:32:50 $
   created at: Fri May 28 15:14:02 JST 1993
 
   Copyright (C) 1993-2000 Yukihiro Matsumoto
@@ -17,6 +17,9 @@
 extern "C" {
 #endif
 
+#include <setjmp.h>
+#include "st.h"
+
 enum node_type {
     NODE_METHOD,
     NODE_FBODY,
@@ -347,6 +350,71 @@
 VALUE rb_gvar_set _((struct global_entry *, VALUE));
 VALUE rb_gvar_defined _((struct global_entry *));
 
+enum rb_thread_status {
+    THREAD_TO_KILL,
+    THREAD_RUNNABLE,
+    THREAD_STOPPED,
+    THREAD_KILLED
+};
+
+typedef struct rb_thread * rb_thread_t;
+
+struct rb_thread {
+    rb_thread_t next, prev;
+    jmp_buf context;
+#ifdef SAVE_WIN32_EXCEPTION_LIST
+    DWORD win32_exception_list;
+#endif
+
+    VALUE result;
+
+    size_t stk_len, stk_max;
+    VALUE *stk_ptr, *stk_start;
+
+    struct FRAME *frame;
+    struct SCOPE *scope;
+    struct RVarmap *dyna_vars;
+    struct BLOCK *block;
+    struct iter *iter;
+    struct tag *tag;
+    VALUE klass;
+    VALUE wrapper;
+    NODE *cref;
+
+    int flags;		/* misc. states (vmode/rb_trap_immediate/raised) */
+
+    char *file;
+    int   line;
+
+    int tracing;
+    VALUE errinfo;
+    VALUE last_status;
+    VALUE last_line;
+    VALUE last_match;
+
+    int safe;
+
+    enum rb_thread_status status;
+    int wait_for;
+    int fd;
+    fd_set readfds;
+    fd_set writefds;
+    fd_set exceptfds;
+    int select_value;
+    double delay;
+    rb_thread_t join;
+
+    int abort;
+    int priority;
+    int gid;
+
+    st_table *locals;
+
+    VALUE thread;
+};
+
+extern rb_thread_t rb_curr_thread, rb_main_thread;
+
 #if defined(__cplusplus)
 }  /* extern "C" { */
 #endif
diff -ru ruby.snapshot/parse.y ruby/parse.y
--- ruby.snapshot/parse.y	2003-04-19 11:19:34.000000000 -0700
+++ ruby/parse.y	2009-02-11 00:01:08.000000000 -0800
@@ -2,8 +2,8 @@
 
   parse.y -
 
-  $Author: eban $
-  $Date: 2003/04/19 18:19:34 $
+  $Author: brent $
+  $Date: 2009/02/11 08:01:08 $
   created at: Fri May 28 18:02:42 JST 1993
 
   Copyright (C) 1993-2001 Yukihiro Matsumoto
@@ -54,6 +54,7 @@
     EXPR_FNAME,			/* ignore newline, no reserved words. */
     EXPR_DOT,			/* right after `.' or `::', no reserved words. */
     EXPR_CLASS,			/* immediate after `class', no here document. */
+    EXPR_VALUE			/* alike EXPR_BEG but label is disallowed. */
 } lex_state;
 
 #if SIZEOF_LONG_LONG > 0
@@ -195,7 +196,7 @@
 	k__LINE__
 	k__FILE__
 
-%token <id>   tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR
+%token <id>   tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL
 %token <val>  tINTEGER tFLOAT tSTRING tXSTRING tREGEXP
 %token <node> tDSTRING tDXSTRING tDREGEXP tNTH_REF tBACK_REF tQWORDS
 
@@ -1907,6 +1908,10 @@
 		    {
 			$$ = list_append(NEW_LIST($1), $3);
 		    }
+                | tLABEL arg
+                    {
+                        $$ = list_append(NEW_LIST(NEW_LIT(ID2SYM($1))), $2);
+                    }
 		;
 
 operation	: tIDENTIFIER
@@ -2928,6 +2933,9 @@
     rb_warning("ambiguous first argument; make sure");
 }
 
+#define IS_BEG() (lex_state == EXPR_BEG || lex_state == EXPR_MID || \
+                  lex_state == EXPR_VALUE || lex_state == EXPR_CLASS)
+
 static int
 yylex()
 {
@@ -2961,6 +2969,7 @@
 	  case EXPR_FNAME:
 	  case EXPR_DOT:
 	  case EXPR_CLASS:
+          case EXPR_VALUE:
 	    goto retry;
 	  default:
 	    break;
@@ -2989,7 +2998,7 @@
 		rb_warning("`*' interpreted as argument prefix");
 		c = tSTAR;
 	    }
-	    else if (lex_state == EXPR_BEG || lex_state == EXPR_MID) {
+	    else if (IS_BEG()) {
 		c = tSTAR;
 	    }
 	    else {
@@ -3143,7 +3152,7 @@
 
       case '?':
 	if (lex_state == EXPR_END) {
-	    lex_state = EXPR_BEG;
+	    lex_state = EXPR_VALUE;
 	    return '?';
 	}
 	c = nextc();
@@ -3173,7 +3182,7 @@
 	    }
 	    else {
 		pushback(c);
-		lex_state = EXPR_BEG;
+		lex_state = EXPR_VALUE;
 		return '?';
 	    }
 	}
@@ -3206,7 +3215,7 @@
 	    rb_warning("`&' interpreted as argument prefix");
 	    c = tAMPER;
 	}
-	else if (lex_state == EXPR_BEG || lex_state == EXPR_MID) {
+	else if (IS_BEG()) {
 	    c = tAMPER;
 	}
 	else {
@@ -3260,7 +3269,7 @@
 	    lex_state = EXPR_BEG;
 	    return tOP_ASGN;
 	}
-	if (lex_state == EXPR_BEG || lex_state == EXPR_MID ||
+	if (IS_BEG() ||
 	    (lex_state == EXPR_ARG && space_seen && !ISSPACE(c))) {
 	    if (lex_state == EXPR_ARG) arg_ambiguous();
 	    lex_state = EXPR_BEG;
@@ -3290,7 +3299,7 @@
 	    lex_state = EXPR_BEG;
 	    return tOP_ASGN;
 	}
-	if (lex_state == EXPR_BEG || lex_state == EXPR_MID ||
+	if (IS_BEG() ||
 	    (lex_state == EXPR_ARG && space_seen && !ISSPACE(c))) {
 	    if (lex_state == EXPR_ARG) arg_ambiguous();
 	    lex_state = EXPR_BEG;
@@ -3519,8 +3528,7 @@
       case ':':
 	c = nextc();
 	if (c == ':') {
-	    if (lex_state == EXPR_BEG ||  lex_state == EXPR_MID ||
-		(lex_state == EXPR_ARG && space_seen)) {
+	    if (IS_BEG() || (lex_state == EXPR_ARG && space_seen)) {
 		lex_state = EXPR_BEG;
 		return tCOLON3;
 	    }
@@ -3536,7 +3544,7 @@
 	return tSYMBEG;
 
       case '/':
-	if (lex_state == EXPR_BEG || lex_state == EXPR_MID) {
+	if (IS_BEG()) {
 	    return parse_regx('/', '/');
 	}
 	if ((c = nextc()) == '=') {
@@ -3597,7 +3605,7 @@
 	if (cond_nest > 0) {
 	    cond_stack = (cond_stack<<1)|0;
 	}
-	if (lex_state == EXPR_BEG || lex_state == EXPR_MID) {
+	if (IS_BEG()) {
 	    c = tLPAREN;
 	}
 	else if (lex_state == EXPR_ARG && space_seen) {
@@ -3619,7 +3627,7 @@
 	    pushback(c);
 	    return '[';
 	}
-	else if (lex_state == EXPR_BEG || lex_state == EXPR_MID) {
+	else if (IS_BEG()) {
 	    c = tLBRACK;
 	}
 	else if (lex_state == EXPR_ARG && space_seen) {
@@ -3644,7 +3652,7 @@
 	return '\\';
 
       case '%':
-	if (lex_state == EXPR_BEG || lex_state == EXPR_MID) {
+	if (IS_BEG()) {
 	    int term;
 	    int paren;
 
@@ -3859,6 +3867,16 @@
 		result = tIVAR;
 	    break;
 	  default:
+            if ((lex_state == EXPR_BEG) ||
+                lex_state == EXPR_ARG) {
+                if (peek(':') && !(lex_p + 1 < lex_pend && lex_p[1] == ':')) {
+                    lex_state = EXPR_BEG;
+                    nextc();
+                    yylval.id = rb_intern(tok());
+                    return tLABEL;
+                }
+            }
+
 	    if (lex_state != EXPR_DOT) {
 		/* See if it is a reserved word.  */
 		kw = rb_reserved_word(tok(), toklen());
@@ -3873,7 +3891,7 @@
 			if (CMDARG_P()) return kDO_BLOCK;
 			return kDO;
 		    }
-		    if (state == EXPR_BEG)
+		    if (state == EXPR_BEG || state == EXPR_VALUE)
 			return kw->id[0];
 		    else {
 			if (kw->id[0] != kw->id[1])
@@ -3908,14 +3926,8 @@
 		    result = tIDENTIFIER;
 		}
 	    }
-	    if (lex_state == EXPR_BEG ||
-		lex_state == EXPR_DOT ||
-		lex_state == EXPR_ARG) {
-		lex_state = EXPR_ARG;
-	    }
-	    else {
-		lex_state = EXPR_END;
-	    }
+            lex_state = lex_state != EXPR_FNAME && lex_state != EXPR_END ? 
+                                                        EXPR_ARG : EXPR_END;
 	}
 	tokfix();
 	yylval.id = rb_intern(tok());
@@ -4550,8 +4562,6 @@
 	  case NODE_UNTIL:
 	  case NODE_CLASS:
 	  case NODE_MODULE:
-	  case NODE_DEFN:
-	  case NODE_DEFS:
 	    if (!cond) yyerror("void value expression");
 	    return Qfalse;
 
diff -ru ruby.snapshot/re.c ruby/re.c
--- ruby.snapshot/re.c	2003-02-03 22:52:29.000000000 -0800
+++ ruby/re.c	2009-03-01 03:38:19.000000000 -0800
@@ -2,7 +2,7 @@
 
   re.c -
 
-  $Author: matz $
+  $Author: brent $
   created at: Mon Aug  9 18:24:49 JST 1993
 
   Copyright (C) 1993-2000 Yukihiro Matsumoto
@@ -895,16 +895,18 @@
 rb_reg_regcomp(str)
     VALUE str;
 {
-    if (reg_cache && RREGEXP(reg_cache)->len == RSTRING(str)->len
-	&& case_cache == ruby_ignorecase
-	&& kcode_cache == reg_kcode
-	&& memcmp(RREGEXP(reg_cache)->str, RSTRING(str)->ptr, RSTRING(str)->len) == 0)
-	return reg_cache;
-
-    case_cache = ruby_ignorecase;
-    kcode_cache = reg_kcode;
-    return reg_cache = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len,
-				  ruby_ignorecase);
+  if (reg_cache && RREGEXP(reg_cache)->len == RSTRING(str)->len
+      && case_cache == ruby_ignorecase
+      && kcode_cache == reg_kcode
+      && memcmp(
+           RREGEXP(reg_cache)->str, RSTRING(str)->ptr, RSTRING(str)->len) == 0)
+      return reg_cache;
+
+  case_cache = ruby_ignorecase;
+  kcode_cache = reg_kcode;
+  reg_cache = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len, ruby_ignorecase);
+  RB_GC_GUARD(str);
+  return reg_cache;
 }
 
 static int
diff -ru ruby.snapshot/ruby.h ruby/ruby.h
--- ruby.snapshot/ruby.h	2002-05-01 02:37:59.000000000 -0700
+++ ruby/ruby.h	2009-08-17 19:37:15.000000000 -0700
@@ -2,7 +2,7 @@
 
   ruby.h -
 
-  $Author: matz $
+  $Author: brent $
   created at: Thu Jun 10 14:26:32 JST 1993
 
   Copyright (C) 1993-2000 Yukihiro Matsumoto
@@ -196,6 +196,8 @@
 
 #define TYPE(x) rb_type((VALUE)(x))
 
+#define RB_GC_GUARD(v) (*(volatile VALUE *)&(v))
+
 void rb_check_type _((VALUE,int));
 #define Check_Type(v,t) rb_check_type((VALUE)(v),t)
 void rb_check_safe_str _((VALUE));
@@ -476,7 +478,7 @@
 
 void rb_raise __((VALUE, const char*, ...)) NORETURN;
 void rb_fatal __((const char*, ...)) NORETURN;
-void rb_bug __((const char*, ...)) NORETURN;
+void rb_bug __((const char*, ...)); //removed NORETURN to preserve gdb backtrace
 void rb_sys_fail _((const char*)) NORETURN;
 void rb_iter_break _((void)) NORETURN;
 void rb_exit _((int)) NORETURN;
diff -ru ruby.snapshot/rubysig.h ruby/rubysig.h
--- ruby.snapshot/rubysig.h	2002-02-26 20:50:30.000000000 -0800
+++ ruby/rubysig.h	2009-03-01 03:35:50.000000000 -0800
@@ -2,8 +2,8 @@
 
   rubysig.h -
 
-  $Author: matz $
-  $Date: 2002/02/27 04:50:30 $
+  $Author: brent $
+  $Date: 2009/03/01 11:35:50 $
   created at: Wed Aug 16 01:15:38 JST 1995
 
   Copyright (C) 1993-2000 Yukihiro Matsumoto
@@ -13,6 +13,78 @@
 #ifndef SIG_H
 #define SIG_H
 
+
+#if defined __ppc__ || defined __powerpc__ || \
+    defined __ppc64__ || defined __powerpc64__
+#define __anyPowerPC__ 1  /* for compatibility with older gcc versions */
+#endif
+
+/* STACK_WIPE_SITES determines where attempts are made to exorcise
+   "ghost object refereces" from the stack and how the stack is cleared:
+   
+   0x*001 -->  wipe stack just after every thread_switch
+   0x*002 -->  wipe stack just after every EXEC_TAG()
+   0x*004 -->  wipe stack in CHECK_INTS
+   0x*010 -->  wipe stack in while & until loops
+   0x*020 -->  wipe stack before yield() in iterators and outside eval.c
+   0x*040 -->  wipe stack on catch and thread save context
+   0x*100 -->  update stack extent on each object allocation
+   0x*200 -->  update stack extent on each object reallocation
+   0x*400 -->  update stack extent during GC marking passes
+   0x*800 -->  update stack extent on each throw (use with 0x040)
+   0x1000 -->  use inline assembly code for x86, PowerPC, or ARM CPUs
+
+   0x0*** -->  do not even call rb_wipe_stack()
+   0x2*** -->  call dummy rb_wipe_stack() (for debugging and profiling)
+   0x4*** -->  safe, portable stack clearing in memory allocated with alloca
+   0x6*** -->  use faster, but less safe stack clearing in unallocated stack
+   0x8*** -->  use faster, but less safe stack clearing (with inline code)
+   
+   for most effective gc use 0x*707
+   for fastest micro-benchmarking use 0x0000
+   0x*770 prevents almost all memory leaks caused by ghost references
+   without adding much overhead for stack clearing.
+   Other good trade offs are 0x*270, 0x*703, 0x*303 or even 0x*03
+   
+   In general, you may lessen the default -mpreferred-stack-boundary
+   only if using less safe stack clearing (0x6***).  Lessening the
+   stack alignment with portable stack clearing (0x4***) may fail to clear 
+   all ghost references off the stack.
+   
+   When using 0x6*** or 0x8***, the compiler could insert 
+   stack push(s) between reading the stack pointer and clearing 
+   the ghost references.  The register(s) pushed will be
+   cleared by the rb_gc_stack_wipe(), typically resulting in a segfault
+   or an interpreter hang.
+   
+   STACK_WIPE_SITES of 0x8770 works well compiled with gcc on most machines
+   using the recommended CFLAGS="-O2 -fno-stack-protector".  However...
+   If it hangs or crashes for you, try changing STACK_WIPE_SITES to 0x4770
+   and please report your details.  i.e. CFLAGS, compiler, version, CPU
+   
+   Note that it is redundant to wipe_stack in looping constructs if 
+   also doing so in CHECK_INTS.  It is also redundant to wipe_stack on
+   each thread_switch if wiping after every thread save context.
+*/
+#ifndef STACK_WIPE_SITES
+# ifdef __x86_64__     /* deal with "red zone" by not inlining stack clearing */
+#  define STACK_WIPE_SITES  0x6770
+# elif defined __anyPowerPC__   /* On any PowerPC, deal with... */
+#  define STACK_WIPE_SITES  0x7764   /* red zone & alloc(0) doesn't return sp */
+# else
+#  define STACK_WIPE_SITES  0x8770 /*normal case, use 0x4770 if problems arise*/
+# endif
+#endif
+
+#if (STACK_WIPE_SITES & 0x14) == 0x14
+#warning  wiping stack in CHECK_INTS makes wiping in loops redundant
+#endif
+#if (STACK_WIPE_SITES & 0x41) == 0x41
+#warning  wiping stack after thread save makes wiping on thread_switch redundant
+#endif
+
+#define STACK_WIPE_METHOD (STACK_WIPE_SITES>>13)
+
 #ifdef NT
 typedef LONG rb_atomic_t;
 
@@ -64,24 +136,169 @@
 
 EXTERN int rb_thread_critical;
 void rb_thread_schedule _((void));
+
+#define THREAD_INTERRUPTABLE  (!(rb_prohibit_interrupt | rb_thread_critical))
+
+EXTERN VALUE *rb_gc_stack_end;
+
+#if STACK_GROW_DIRECTION > 0
+
+/* clear stack space between end and sp (not including *sp) */
+#define __stack_zero(end,sp)  __stack_zero_up(end,sp)
+
+/* true if top has grown past limit, i.e. top deeper than limit */
+#define __stack_past(limit,top)  __stack_past_up(limit,top)
+
+/* depth of mid below stack top */
+#define __stack_depth(top,mid)   __stack_depth_up(top,mid)
+
+/* stack pointer top adjusted to include depth more items */
+#define __stack_grow(top,depth)  __stack_grow_up(top,depth)
+
+
+#elif STACK_GROW_DIRECTION < 0
+#define __stack_zero(end,sp)  __stack_zero_down(end,sp)
+#define __stack_past(limit,top)  __stack_past_down(limit,top)
+#define __stack_depth(top,mid)   __stack_depth_down(top,mid)
+#define __stack_grow(top,depth)  __stack_grow_down(top,depth)
+
+#else  /* limp along if stack direction can't be determined at compile time */
+#define __stack_zero(end,sp) if (rb_gc_stack_grow_direction<0) \
+        __stack_zero_down(end,sp); else __stack_zero_up(end,sp);
+#define __stack_past(limit,top)  (rb_gc_stack_grow_direction<0 ? \
+                      __stack_past_down(limit,top) : __stack_past_up(limit,top))
+#define __stack_depth(top,mid) (rb_gc_stack_grow_direction<0 ? \
+                       __stack_depth_down(top,mid) : __stack_depth_up(top,mid))
+#define __stack_grow(top,depth) (rb_gc_stack_grow_direction<0 ? \
+                      __stack_grow_down(top,depth) : __stack_grow_up(top,depth))
+#endif
+ 
+#define __stack_zero_up(end,sp)  while (end >= ++sp) *sp=0
+#define __stack_past_up(limit,top)  ((limit) < (top))
+#define __stack_depth_up(top,mid) ((top) - (mid))
+#define __stack_grow_up(top,depth) ((top)+(depth))
+
+#define __stack_zero_down(end,sp)  while (end <= --sp) *sp=0
+#define __stack_past_down(limit,top)  ((limit) > (top))
+#define __stack_depth_down(top,mid) ((mid) - (top))
+#define __stack_grow_down(top,depth) ((top)-(depth))
+
+/* Make alloca work the best possible way.  */
+#ifdef __GNUC__
+# ifndef atarist
+#  ifndef alloca
+#   define alloca __builtin_alloca
+#  endif
+# endif /* atarist */
+
+# define nativeAllocA __builtin_alloca
+
+/* use assembly to get stack pointer quickly */
+# if STACK_WIPE_SITES & 0x1000
+#  define __defspfn(asmb)  \
+static inline VALUE *__sp(void) __attribute__((always_inline)); \
+static inline VALUE *__sp(void) \
+{ \
+  VALUE *sp; asm(asmb); \
+  return sp; \
+}
+#  ifdef __anyPowerPC__
+__defspfn("addi %0, r1, 0": "=r"(sp))
+#  elif defined  __i386__
+__defspfn("movl %%esp, %0": "=r"(sp))
+#  elif defined __x86_64__
+#warn ===> x86_64 inline assembler is known to crash -- change STACK_WIPE_SITES
+__defspfn("movq %%rsp, %0": "=r"(sp))
+#  elif __arm__
+__defspfn("mov %0, sp": "=r"(sp))
+#  else
+#   define __sp()  ((VALUE *)__builtin_alloca(0))
+#   warning No assembly version of __sp() defined for this CPU.
+#  endif
+# else
+#  define __sp()  ((VALUE *)__builtin_alloca(0))
+# endif
+
+#else  // not GNUC
+
+# ifdef HAVE_ALLOCA_H
+#  include <alloca.h>
+# else
+#  ifndef _AIX
+#   ifndef alloca /* predefined by HP cc +Olibcalls */
+void *alloca ();
+#   endif
+#  endif /* AIX */
+# endif /* HAVE_ALLOCA_H */
+
+# if STACK_WIPE_SITES & 0x1000
+#  warning No assembly versions of __sp() defined for this compiler.
+# endif
+# if HAVE_ALLOCA
+#  define __sp()  ((VALUE *)alloca(0))
+#  define nativeAllocA alloca
+# else
+RUBY_EXTERN VALUE *__sp(void);
+#  if STACK_WIPE_SITES
+#   define STACK_WIPE_SITES 0
+#   warning Disabled Stack Wiping because there is no native alloca()
+#  endif
+# endif
+#endif /* __GNUC__ */
+
+
+/*
+  Zero memory that was (recently) part of the stack, but is no longer.
+  Invoke when stack is deep to mark its extent and when it's shallow to wipe it.
+*/
+#if STACK_WIPE_METHOD == 0
+#define rb_gc_wipe_stack() ((void)0)
+#elif STACK_WIPE_METHOD == 4
+#define rb_gc_wipe_stack() {     \
+  VALUE *end = rb_gc_stack_end;  \
+  VALUE *sp = __sp();            \
+  rb_gc_stack_end = sp;          \
+  __stack_zero(end, sp);   \
+}
+#else
+RUBY_EXTERN void rb_gc_wipe_stack(void);
+#endif
+
+/*
+  Update our record of maximum stack extent without zeroing unused stack
+*/
+#define rb_gc_update_stack_extent() do { \
+    VALUE *sp = __sp(); \
+    if __stack_past(rb_gc_stack_end, sp) rb_gc_stack_end = sp; \
+} while(0)
+
+
+#if STACK_WIPE_SITES & 4
+# define CHECK_INTS_wipe_stack()  rb_gc_wipe_stack()
+#else
+# define CHECK_INTS_wipe_stack()  (void)0
+#endif
+
 #if defined(HAVE_SETITIMER) && !defined(__BOW__)
 EXTERN int rb_thread_pending;
-# define CHECK_INTS if (!rb_prohibit_interrupt) {\
+# define CHECK_INTS \
+    CHECK_INTS_wipe_stack(); \
+    if THREAD_INTERRUPTABLE {\
+    if (rb_thread_pending) rb_thread_schedule();\
     if (rb_trap_pending) rb_trap_exec();\
-    if (rb_thread_pending && !rb_thread_critical) rb_thread_schedule();\
 }
 #else
 /* pseudo preemptive thread switching */
 EXTERN int rb_thread_tick;
-#define THREAD_TICK 500
-#define CHECK_INTS if (!rb_prohibit_interrupt) {\
-    if (rb_trap_pending) rb_trap_exec();\
-    if (!rb_thread_critical) {\
-	if (rb_thread_tick-- <= 0) {\
-	    rb_thread_tick = THREAD_TICK;\
-	    rb_thread_schedule();\
-	}\
+# define THREAD_TICK 500
+# define CHECK_INTS \
+  CHECK_INTS_wipe_stack(); \
+  if THREAD_INTERRUPTABLE {\
+    if (rb_thread_tick-- <= 0) {\
+	rb_thread_tick = THREAD_TICK;\
+	rb_thread_schedule();\
     }\
+    if (rb_trap_pending) rb_trap_exec();\
 }
 #endif
 
diff -ru ruby.snapshot/signal.c ruby/signal.c
--- ruby.snapshot/signal.c	2002-03-07 22:59:53.000000000 -0800
+++ ruby/signal.c	2009-08-17 19:36:16.000000000 -0700
@@ -2,8 +2,8 @@
 
   signal.c -
 
-  $Author: matz $
-  $Date: 2002/03/08 06:59:53 $
+  $Author: brent $
+  $Date: 2009/08/18 02:36:16 $
   created at: Tue Dec 20 10:13:44 JST 1994
 
   Copyright (C) 1993-2000 Yukihiro Matsumoto
@@ -259,6 +259,7 @@
 		rb_sys_fail(0);
 	}
     }
+    CHECK_INTS;  /* in case we killed ourselves */
     return INT2FIX(i-1);
 }
 
@@ -330,6 +331,9 @@
 #ifdef SIGALRM
 	  case SIGALRM:
 #endif
+#ifdef SIGTERM
+	  case SIGTERM:
+#endif
 #ifdef SIGUSR1
 	  case SIGUSR1:
 #endif
@@ -364,7 +368,7 @@
     ruby_signal(sig, sighandle);
 #endif
 
-    if (ATOMIC_TEST(rb_trap_immediate)) {
+    if (ATOMIC_TEST(rb_trap_immediate) && THREAD_INTERRUPTABLE) {
 	IN_MAIN_CONTEXT(signal_exec, sig);
 	ATOMIC_SET(rb_trap_immediate, 1);
     }
@@ -544,6 +548,9 @@
 #ifdef SIGALRM
 	  case SIGALRM:
 #endif
+#ifdef SIGTERM
+	  case SIGTERM:
+#endif
 #ifdef SIGUSR1
 	  case SIGUSR1:
 #endif
@@ -663,6 +670,9 @@
 #ifdef SIGALRM
     ruby_signal(SIGALRM, sighandle);
 #endif
+#ifdef SIGTERM
+    ruby_signal(SIGTERM, sighandle);
+#endif
 #ifdef SIGUSR1
     ruby_signal(SIGUSR1, sighandle);
 #endif
diff -ru ruby.snapshot/variable.c ruby/variable.c
--- ruby.snapshot/variable.c	2002-12-15 23:36:14.000000000 -0800
+++ ruby/variable.c	2008-11-26 15:25:29.000000000 -0800
@@ -2,8 +2,8 @@
 
   variable.c -
 
-  $Author: matz $
-  $Date: 2002/12/16 07:36:14 $
+  $Author: brent $
+  $Date: 2008/11/26 23:25:29 $
   created at: Tue Apr 19 23:55:15 JST 1994
 
   Copyright (C) 1993-2000 Yukihiro Matsumoto
@@ -446,6 +446,52 @@
     rb_raise(rb_eNameError, "can't set variable %s", rb_id2name(id));
 }
 
+#ifdef DEBUG_REACHABILITY
+extern VALUE rbx_reach_test_path;
+extern int   rbx_reach_test_len;
+
+static int
+mark_global_entry(key, entry)
+    ID key;
+    struct global_entry *entry;
+{
+    struct trace_var *trace;
+    char buf[100];
+    int i;
+    
+    if (rbx_reach_test_path != Qnil) {
+      sprintf(buf, "Ruby global %s", rb_id2name(key));
+      rb_ary_store(rbx_reach_test_path, rbx_reach_test_len, rb_str_new2(buf));
+      rbx_reach_test_len++;
+      (*entry->marker)(entry->data);
+      rbx_reach_test_len--;
+    }
+    else {
+      (*entry->marker)(entry->data);
+    }
+
+    trace = entry->trace;
+    i = 0;
+    while (trace) {
+        if (trace->data) {
+          if (rbx_reach_test_path != Qnil) {
+            char buf[100];
+            sprintf(buf, "Ruby global %s trace %d", rb_id2name(key), i);
+            rb_ary_store(rbx_reach_test_path, rbx_reach_test_len, rb_str_new2(buf));
+            rbx_reach_test_len++;
+            rb_gc_mark_maybe(trace->data);
+            rbx_reach_test_len--;
+          }
+          else {
+            rb_gc_mark_maybe(trace->data);
+          }
+        }
+	trace = trace->next;
+        i++;
+    }
+    return ST_CONTINUE;
+}
+#else
 static int
 mark_global_entry(key, entry)
     ID key;
@@ -461,6 +507,7 @@
     }
     return ST_CONTINUE;
 }
+#endif
 
 void
 rb_gc_mark_global_tbl()
@@ -944,7 +991,7 @@
 rb_ivar_set(obj, id, val)
     VALUE obj;
     ID id;
-    VALUE val;
+    volatile VALUE val;  //allows x86 GCC 3.3.5 to GC -- loop {@x=callcc {|c|c}}
 {
     if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)
 	rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable");
diff -ru ruby.snapshot/version.h ruby/version.h
--- ruby.snapshot/version.h	2005-09-20 09:49:26.000000000 -0700
+++ ruby/version.h	2009-08-17 19:48:26.000000000 -0700
@@ -1,11 +1,17 @@
-#define RUBY_VERSION "1.6.8"
-#define RUBY_RELEASE_DATE "2005-09-21"
+#include "rubysig.h"  /* for STACK_WIPE_SITES */
+
+#define string_arg(s) #s
+#define MBARI_RELEASE(wipe_sites) "-mbari8B/" string_arg(wipe_sites)
+
+#define RUBY_VERSION "1.6.8" MBARI_RELEASE(STACK_WIPE_SITES)
+#define RUBY_RELEASE_DATE "2009-8-17"
 #define RUBY_VERSION_CODE 168
-#define RUBY_RELEASE_CODE 20050921
+#define RUBY_RELEASE_CODE 20090817
 
 #define RUBY_VERSION_MAJOR 1
 #define RUBY_VERSION_MINOR 6
 #define RUBY_VERSION_TEENY 8
-#define RUBY_RELEASE_YEAR 2005
-#define RUBY_RELEASE_MONTH 09
-#define RUBY_RELEASE_DAY 21
+
+#define RUBY_RELEASE_YEAR 2009
+#define RUBY_RELEASE_MONTH 8
+#define RUBY_RELEASE_DAY 17
