diff -rux '*.o' ruby-1.8.7-p72/ChangeLog ruby-1.8.7-mbari/ChangeLog
--- ruby-1.8.7-p72/ChangeLog	2008-12-16 00:47:25.000000000 -0800
+++ ruby-1.8.7-mbari/ChangeLog	2008-12-16 23:06:21.000000000 -0800
@@ -1,3 +1,11 @@
+Tue Dec 15  9:15:36 2008  Brent Roman  <brent@mbari.org>
+
+        * eval.c:  factored rb_eval() into many separate non-inlined
+                  functions to reduce the size of its stack frame when
+                  compiled with gcc.
+                  Factored callcc into 2 functions.
+
+
 Tue Dec 13  6:10:36 2008  Brent Roman  <brent@mbari.org>
 
         * eval.c:  update stack extent just before and after every setjmp
diff -rux '*.o' ruby-1.8.7-p72/eval.c ruby-1.8.7-mbari/eval.c
--- ruby-1.8.7-p72/eval.c	2008-12-16 00:47:25.000000000 -0800
+++ ruby-1.8.7-mbari/eval.c	2008-12-16 23:28:08.000000000 -0800
@@ -3,7 +3,7 @@
   eval.c -
 
   $Author: brent $
-  $Date: 2008/12/14 07:23:06 $
+  $Date: 2008/12/17 07:28:08 $
   created at: Thu Jun 10 14:22:17 JST 1993
 
   Copyright (C) 1993-2003 Yukihiro Matsumoto
@@ -219,7 +219,7 @@
 VALUE rb_cBinding;
 static VALUE proc_invoke _((VALUE,VALUE,VALUE,VALUE));
 static VALUE rb_f_binding _((VALUE));
-static void rb_f_END _((void));
+NOINLINE(static void rb_f_END _((void)));
 static VALUE rb_f_block_given_p _((void));
 static VALUE block_pass _((VALUE,NODE*));
 
@@ -1240,12 +1240,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() == 0 ? get_backtrace(ruby_errinfo) : Qnil;
     if (EXEC_TAG()) goto error;
     if (NIL_P(errat)){
 	ruby_set_current_source();
@@ -1926,8 +1921,8 @@
     return rb_const_defined(cref->nd_clss, id);
 }
 
-static VALUE
-ev_const_get(cref, id, self)
+NOINLINE(static VALUE
+ev_const_get(cref, id, self))
     NODE *cref;
     ID id;
     VALUE self;
@@ -2942,40 +2937,960 @@
     }
 }
 
-static VALUE
-rb_eval(self, n)
-    VALUE self;
-    NODE *n;
+
+/*
+  functions factored out of rb_eval() to reduce its stack frame size
+*/
+NOINLINE(static VALUE eval_match2(self, node))
+  VALUE self;
+  NODE *node;
+{
+    VALUE l = rb_eval(self,node->nd_recv);
+    VALUE r = rb_eval(self,node->nd_value);
+    return rb_reg_match(l, r);
+}
+
+NOINLINE(static VALUE
+eval_match3(self, node))
+  VALUE self;
+  NODE *node;
+{
+  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);
+}
+
+
+NOINLINE(static void
+eval_opt_n(self, node))
+  VALUE self;
+  NODE *node;
+{
+  int state;
+  PUSH_TAG(PROT_LOOP);
+  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);
+}
+
+
+NOINLINE(static NODE *
+eval_when(self, node))
+  VALUE self;
+  NODE *node;
+{
+  do {
+      NODE *tag = node->nd_head;
+      while (tag) {
+	  EXEC_EVENT_HOOK(RUBY_EVENT_LINE, tag, self,
+			  ruby_frame->last_func,
+			  ruby_frame->last_class);
+	  if (tag->nd_head && nd_type(tag->nd_head) == NODE_WHEN) {
+	      VALUE v = rb_eval(self, tag->nd_head->nd_head);
+	      long i;
+
+	      if (TYPE(v) != T_ARRAY) v = rb_ary_to_ary(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;
+}
+
+
+NOINLINE (static NODE *
+eval_case(self, node))
+  VALUE self;
+  NODE *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) {
+	  EXEC_EVENT_HOOK(RUBY_EVENT_LINE, tag, self,
+			  ruby_frame->last_func,
+			  ruby_frame->last_class);
+	  if (tag->nd_head && nd_type(tag->nd_head) == NODE_WHEN) {
+	      VALUE v = rb_eval(self, tag->nd_head->nd_head);
+	      long i;
+
+	      if (TYPE(v) != T_ARRAY) v = rb_ary_to_ary(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;
+}
+
+
+NOINLINE (static VALUE
+eval_while(self, node))
+  VALUE self;
+  NODE *node;
+{
+  int state;
+  volatile VALUE result = Qnil;
+  PUSH_TAG(PROT_LOOP);
+  switch (state = EXEC_TAG()) {
+    case 0:
+      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:
+      if (TAG_DST()) {
+	  state = 0;
+	  result = prot_tag->retval;
+      }
+      /* fall through */
+    default:
+      break;
+  }
+while_out:
+  POP_TAG();
+  if (state) JUMP_TAG(state);
+  return result;
+}
+
+
+NOINLINE (static VALUE
+eval_until(self, node))
+  VALUE self;
+  NODE *node;
+{
+  int state;
+  volatile VALUE result = Qnil;
+  PUSH_TAG(PROT_LOOP);
+  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:
+      if (TAG_DST()) {
+	  state = 0;
+	  result = prot_tag->retval;
+      }
+      /* fall through */
+    default:
+      break;
+  }
+ until_out:
+  POP_TAG();
+  if (state) JUMP_TAG(state);
+  return result;
+}
+
+
+NOINLINE (static VALUE
+eval_iter(self, node))
+  VALUE self;
+  NODE *node;
+{
+  int state;
+  volatile VALUE result = Qnil;
+
+  PUSH_TAG(PROT_LOOP);
+  PUSH_BLOCK(node->nd_var, node->nd_body);
+
+  state = EXEC_TAG();
+  switch (state) {
+    case TAG_RETRY:
+      state = 0;  /* fall thru to case 0 */
+    case 0:
+      PUSH_ITER(ITER_PRE);
+      if (nd_type(node) == NODE_ITER) {
+	  result = rb_eval(self, node->nd_iter);
+      }
+      else {
+	  VALUE recv;
+
+	  _block.flags &= ~BLOCK_D_SCOPE;
+	  BEGIN_CALLARGS;
+	  recv = rb_eval(self, node->nd_iter);
+	  END_CALLARGS;
+	  ruby_current_node = node;
+	  SET_CURRENT_SOURCE();
+	  result = rb_call(CLASS_OF(recv),recv,each,0,0,0,self);
+      }
+      POP_ITER();
+      break;
+      
+    case TAG_BREAK:
+      if (TAG_DST()) {
+        result = prot_tag->retval;
+        state = 0;
+      }
+  }
+  POP_BLOCK();
+  POP_TAG();
+  if (state) JUMP_TAG(state);
+  return result;
+}
+
+
+NOINLINE (static VALUE
+eval_rescue(self, node))
+  VALUE self;
+  NODE *node;
 {
-    NODE * volatile contnode = 0;
-    NODE * volatile node = n;
+    volatile VALUE e_info = ruby_errinfo;
+    volatile int rescuing = 0;
     int state;
     volatile VALUE result = Qnil;
-    st_data_t data;
 
-#define RETURN(v) do { \
-    result = (v); \
-    goto finish; \
-} while (0)
+    PUSH_TAG(PROT_NONE);
+    if ((state = EXEC_TAG()) == 0) {
+      retry_entry:
+	result = rb_eval(self, node->nd_head);
+    }
+    else if (rescuing) {
+	if (rescuing < 0) {
+	    /* in rescue argument, just reraise */
+	}
+	else if (state == TAG_RETRY) {
+	    rescuing = state = 0;
+	    ruby_errinfo = e_info;
+	    goto retry_entry;
+	}
+	else if (state != TAG_RAISE) {
+	    result = prot_tag->retval;
+	}
+    }
+    else if (state == TAG_RAISE) {
+	NODE *resq = node->nd_resq;
 
-  again:
-    if (!node) RETURN(Qnil);
+	rescuing = -1;
+	while (resq) {
+	    ruby_current_node = resq;
+	    if (handle_rescue(self, resq)) {
+		state = 0;
+		rescuing = 1;
+		result = rb_eval(self, resq->nd_body);
+		break;
+	    }
+	    resq = resq->nd_head; /* next rescue */
+	}
+    }
+    else {
+	result = prot_tag->retval;
+    }
+    POP_TAG();
+    if (state != TAG_RAISE) ruby_errinfo = e_info;
+    if (state) {
+	JUMP_TAG(state);
+    }
+    /* no exception raised */
+    if (!rescuing && node->nd_else) { /* else clause given */
+	result = Qundef;  /* caller must eval this! */
+    }
+    return result;
+}
 
+
+NOINLINE (static VALUE
+eval_ensure(self, node))
+  VALUE self;
+  NODE *node;
+{
+  int state;
+  volatile VALUE result = Qnil;
+
+  PUSH_TAG(PROT_NONE);
+  if ((state = EXEC_TAG()) == 0) {
+      result = rb_eval(self, node->nd_head);
+  }
+  POP_TAG();
+  if (node->nd_ensr && !thread_no_ensure()) {
+      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;
+}
+
+
+NOINLINE (static VALUE
+eval_dot(self, node))
+  VALUE self;
+  NODE *node;
+{
+  VALUE beg = rb_eval(self, node->nd_beg);
+  VALUE end = rb_eval(self, node->nd_end);
+  return rb_range_new(beg, end, nd_type(node) == NODE_DOT3);
+}
+
+
+NOINLINE (static VALUE
+eval_flip2(self, node))
+  VALUE self;
+  NODE *node;
+{
+  VALUE *flip = rb_svar(node->nd_cnt);
+  if (!flip) rb_bug("unexpected local variable");
+  if (!RTEST(*flip)) {
+    if (!RTEST(rb_eval(self, node->nd_beg)))
+      return Qfalse;
+    *flip = RTEST(rb_eval(self, node->nd_end))?Qfalse:Qtrue;
+  }
+  else if (RTEST(rb_eval(self, node->nd_end)))
+    *flip = Qfalse;
+  return Qtrue;
+}
+
+
+NOINLINE (static VALUE
+eval_flip3(self, node))
+  VALUE self;
+  NODE *node;
+{
+  VALUE *flip = rb_svar(node->nd_cnt);
+  if (!flip) rb_bug("unexpected local variable");
+  if (!RTEST(*flip))
+    return *flip = (RTEST(rb_eval(self, node->nd_beg)) ? Qtrue : Qfalse);
+  if (RTEST(rb_eval(self, node->nd_end)))
+    *flip = Qfalse;
+  return Qtrue;
+}
+
+
+NOINLINE (static VALUE
+eval_attrasgn(self, node))
+  VALUE self;
+  NODE *node;
+{
+  VALUE recv;
+  int argc; VALUE *argv; /* used in SETUP_ARGS */
+  int scope;
+  TMP_PROTECT;
+
+  BEGIN_CALLARGS;
+  if (node->nd_recv == (NODE *)1) {
+      recv = self;
+      scope = 1;
+  }
+  else {
+      recv = rb_eval(self, node->nd_recv);
+      scope = 0;
+  }
+  SETUP_ARGS(node->nd_args);
+  END_CALLARGS;
+
+  ruby_current_node = node;
+  SET_CURRENT_SOURCE();
+  rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,scope,self);
+  return argv[argc-1];
+}
+
+
+NOINLINE (static VALUE
+eval_call(self, node))
+  VALUE self;
+  NODE *node;
+{
+  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;
+
+  ruby_current_node = node;
+  SET_CURRENT_SOURCE();
+  return rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,0,self);
+}
+
+
+NOINLINE (static VALUE
+eval_fcall(self, node))
+  VALUE self;
+  NODE *node;
+{
+  int argc; VALUE *argv; /* used in SETUP_ARGS */
+  TMP_PROTECT;
+
+  BEGIN_CALLARGS;
+  SETUP_ARGS(node->nd_args);
+  END_CALLARGS;
+
+  ruby_current_node = node;
+  SET_CURRENT_SOURCE();
+  return rb_call(CLASS_OF(self),self,node->nd_mid,argc,argv,1,self);
+}
+
+NOINLINE (static VALUE
+eval_super(self, node))
+  VALUE self;
+  NODE *node;
+{
+  int argc; VALUE *argv; /* used in SETUP_ARGS */
+  TMP_PROTECT;
+
+  if (ruby_frame->last_class == 0) {
+      if (ruby_frame->last_func) {
+	  rb_name_error(ruby_frame->last_func,
+			"superclass method `%s' disabled",
+			rb_id2name(ruby_frame->orig_func));
+      }
+      else {
+	  rb_raise(rb_eNoMethodError, "super called outside of method");
+      }
+  }
+  if (nd_type(node) == NODE_ZSUPER) {
+      argc = ruby_frame->argc;
+      if (argc && DMETHOD_P()) {
+	  if (TYPE(RBASIC(ruby_scope)->klass) != T_ARRAY ||
+	      RARRAY(RBASIC(ruby_scope)->klass)->len != argc) {
+	      rb_raise(rb_eRuntimeError, 
+		       "super: specify arguments explicitly");
+	  }
+	  argv = RARRAY(RBASIC(ruby_scope)->klass)->ptr;
+      }
+      else if (!ruby_scope->local_vars) {
+	  argc = 0;
+	  argv = 0;
+      }
+      else {
+	  argv = ruby_scope->local_vars + 2;
+      }
+  }
+  else {
+      BEGIN_CALLARGS;
+      SETUP_ARGS(node->nd_args);
+      END_CALLARGS;
+      ruby_current_node = node;
+  }
+
+  SET_CURRENT_SOURCE();
+  return rb_call_super(argc, argv);
+}
+
+
+NOINLINE (static VALUE
+eval_scope(self, node))
+  VALUE self;
+  NODE *node;
+{
+  int state;
+  volatile VALUE result = Qnil;
+  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;
+  }
+  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;
+}
+
+NOINLINE (static VALUE
+eval_op_asgn1(self, node))
+  VALUE self;
+  NODE *node;
+{
+  int argc; VALUE *argv; /* used in SETUP_ARGS */
+  VALUE recv, val, tmp;
+  NODE *rval;
+  TMP_PROTECT;
+
+  recv = rb_eval(self, node->nd_recv);
+  rval = node->nd_args->nd_head;
+  SETUP_ARGS0(node->nd_args->nd_body, 1);
+  val = rb_funcall3(recv, aref, argc, 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:
+    tmp = rb_eval(self, rval);
+    val = rb_funcall3(val, node->nd_mid, 1, &tmp);
+  }
+  argv[argc] = val;
+  rb_funcall2(recv, aset, argc+1, argv);
+  return val;
+}
+
+
+NOINLINE (static VALUE
+eval_op_asgn2(self, node))
+  VALUE self;
+  NODE *node;
+{
+  ID id = node->nd_next->nd_vid;
+  VALUE recv, val, tmp;
+
+  recv = rb_eval(self, node->nd_recv);
+  val = rb_funcall3(recv, id, 0, 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:
+    tmp = rb_eval(self, node->nd_value);
+    val = rb_funcall3(val, node->nd_next->nd_mid, 1, &tmp);
+  }
+
+  rb_funcall2(recv, node->nd_next->nd_aid, 1, &val);
+  return val;
+}
+
+
+NOINLINE (static VALUE
+eval_hash(self, node))
+  VALUE self;
+  NODE *node;
+{
+  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);
+  }
+  return hash;
+}
+
+
+NOINLINE (static VALUE
+eval_array(self, node))
+  VALUE self;
+  NODE *node;
+{
+  VALUE ary;
+  long 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;
+}
+
+
+NOINLINE (static VALUE
+eval_slit(self, node))
+  VALUE self;
+  NODE *node;
+{
+  VALUE str, str2;
+  NODE *list = node->nd_next;
+
+  str = rb_str_new3(node->nd_lit);
+  while (list) {
+      if (list->nd_head) {
+	  switch (nd_type(list->nd_head)) {
+	    case NODE_STR:
+	      str2 = list->nd_head->nd_lit;
+	      break;
+	    default:
+	      str2 = 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:
+      return rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len,
+			  node->nd_cflag);
+    case NODE_DREGX_ONCE:	/* regexp expand once */
+      str2 = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len,
+			  node->nd_cflag);
+      nd_set_type(node, NODE_LIT);
+      return node->nd_lit = str2;
+    case NODE_LIT:
+      /* other thread may replace NODE_DREGX_ONCE to NODE_LIT */
+      return Qundef;
+    case NODE_DXSTR:
+      return rb_funcall(self, '`', 1, str);
+    case NODE_DSYM:
+      return rb_str_intern(str);
+  }
+  return str;
+}
+
+        
+NOINLINE (static void
+eval_defn(self, node))
+  VALUE self;
+  NODE *node;
+{
+  NODE *body,  *defn;
+  VALUE origin = 0;
+  int noex;
+
+  if (NIL_P(ruby_class)) {
+      rb_raise(rb_eTypeError, "no class/module 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 && body->nd_body) {
+	  rb_warning("method redefined; discarding old %s", rb_id2name(node->nd_mid));
+      }
+  }
+
+  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_body == 0) {
+      noex |= NOEX_NOSUPER;
+  }
+
+  defn = rb_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);
+  }
+}
+
+
+NOINLINE (static void
+eval_defs(self, node))
+  VALUE self;
+  NODE *node;
+{
+  VALUE recv = rb_eval(self, node->nd_recv);
+  VALUE klass;
+  NODE *body = 0, *defn;
+  st_data_t data;
+
+  if (ruby_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_obj_classname(recv));
+  }
+
+  if (OBJ_FROZEN(recv)) rb_error_frozen("object");
+  klass = rb_singleton_class(recv);
+  if (st_lookup(RCLASS(klass)->m_tbl, node->nd_mid, &data)) {
+      body = (NODE *)data;
+      if (ruby_safe_level >= 4) {
+	  rb_raise(rb_eSecurityError, "redefining method prohibited");
+      }
+      if (RTEST(ruby_verbose)) {
+	  rb_warning("redefine %s", rb_id2name(node->nd_mid));
+      }
+  }
+  defn = rb_copy_node_scope(node->nd_defn, ruby_cref);
+  rb_add_method(klass, node->nd_mid, defn,
+		NOEX_PUBLIC|(body?body->nd_noex&NOEX_UNDEF:0));
+}
+
+
+NOINLINE (static VALUE
+eval_class(self, node))
+  VALUE self;
+  NODE *node;
+{
+    VALUE super, klass, tmp, cbase;
+    ID cname;
+    int gen = Qfalse;
+
+    cbase = class_prefix(self, node->nd_cpath);
+    cname = node->nd_cpath->nd_mid;
+
+    if (NIL_P(ruby_cbase)) {
+	rb_raise(rb_eTypeError, "no outer class/module");
+    }
+    if (node->nd_super) {
+       super = rb_eval(self, node->nd_super);
+       rb_check_inheritable(super);
+    }
+    else {
+	super = 0;
+    }
+
+    if (rb_const_defined_at(cbase, cname)) {
+	klass = rb_const_get_at(cbase, cname);
+	if (TYPE(klass) != T_CLASS) {
+	    rb_raise(rb_eTypeError, "%s is not a class",
+		     rb_id2name(cname));
+	}
+	if (super) {
+	    tmp = rb_class_real(RCLASS(klass)->super);
+	    if (tmp != super) {
+		rb_raise(rb_eTypeError, "superclass mismatch for class %s",
+			 rb_id2name(cname));
+	    }
+	    super = 0;
+	}
+	if (ruby_safe_level >= 4) {
+	    rb_raise(rb_eSecurityError, "extending class prohibited");
+	}
+    }
+    else {
+	if (!super) super = rb_cObject;
+	klass = rb_define_class_id(cname, super);
+	rb_set_class_path(klass, cbase, rb_id2name(cname));
+	rb_const_set(cbase, cname, klass);
+	gen = Qtrue;
+    }
+    if (ruby_wrapper) {
+	rb_extend_object(klass, ruby_wrapper);
+	rb_include_module(klass, ruby_wrapper);
+    }
+    if (super && gen) {
+	rb_class_inherited(super, klass);
+    }
+    return module_setup(klass, node);
+}
+
+
+NOINLINE (static VALUE
+eval_module(self, node))
+  VALUE self;
+  NODE *node;
+{
+  VALUE module, cbase;
+  ID cname;
+
+  if (NIL_P(ruby_cbase)) {
+      rb_raise(rb_eTypeError, "no outer class/module");
+  }
+  cbase = class_prefix(self, node->nd_cpath);
+  cname = node->nd_cpath->nd_mid;
+  if (rb_const_defined_at(cbase, cname)) {
+      module = rb_const_get_at(cbase, cname);
+      if (TYPE(module) != T_MODULE) {
+	  rb_raise(rb_eTypeError, "%s is not a module",
+		   rb_id2name(cname));
+      }
+      if (ruby_safe_level >= 4) {
+	  rb_raise(rb_eSecurityError, "extending module prohibited");
+      }
+  }
+  else {
+      module = rb_define_module_id(cname);
+      rb_set_class_path(module, cbase, rb_id2name(cname));
+      rb_const_set(cbase, cname, module);
+  }
+  if (ruby_wrapper) {
+      rb_extend_object(module, ruby_wrapper);
+      rb_include_module(module, ruby_wrapper);
+  }
+
+  return module_setup(module, node);
+}
+
+
+NOINLINE (static VALUE
+eval_sclass(self, node))
+  VALUE self;
+  NODE *node;
+{
+  VALUE klass, result;
+
+  result = rb_eval(self, node->nd_recv);
+  if (FIXNUM_P(result) || SYMBOL_P(result)) {
+      rb_raise(rb_eTypeError, "no virtual class for %s",
+	       rb_obj_classname(result));
+  }
+  if (ruby_safe_level >= 4 && !OBJ_TAINTED(result))
+      rb_raise(rb_eSecurityError, "Insecure: can't extend object");
+  klass = rb_singleton_class(result);
+
+  if (ruby_wrapper) {
+      rb_extend_object(klass, ruby_wrapper);
+      rb_include_module(klass, ruby_wrapper);
+  }
+
+  return module_setup(klass, node);
+}
+
+
+NOINLINE (static VALUE
+eval_defined(self, node))
+  VALUE self;
+  NODE *node;
+{
+    char buf[20];
+    const char *desc = is_defined(self, node->nd_head, buf);
+    return desc ? rb_str_new2(desc) : Qnil;
+}
+
+
+NOINLINE (static void
+eval_cvar_set(result, node, bool))
+  VALUE result, bool;
+  NODE *node;
+{
+  rb_cvar_set(cvar_cbase(), node->nd_vid, result, bool);
+}
+
+
+NOINLINE (static void
+eval_cdecl(self, node, result))
+  VALUE self, result;
+  NODE *node;
+{
+  if (node->nd_vid == 0)
+      rb_const_set(class_prefix(self, node->nd_else), 
+                          node->nd_else->nd_mid, result);
+  else
+      rb_const_set(ruby_cbase, node->nd_vid, result);
+}
+
+
+static VALUE
+rb_eval(self, node)
+  VALUE self;
+  NODE *node;
+{
+  VALUE result;
+
+again:
+  CHECK_INTS;
+  result = Qnil;
+  if (node) {
     ruby_current_node = node;
+    
     switch (nd_type(node)) {
       case NODE_BLOCK:
-	if (contnode) {
-	    result = rb_eval(self, node);
-	    break;
+	while (node->nd_next) {
+	    rb_eval(self, node->nd_head);
+	    node = node->nd_next;
 	}
-	contnode = node->nd_next;
 	node = node->nd_head;
 	goto again;
 
       case NODE_POSTEXE:
 	rb_f_END();
 	nd_set_type(node, NODE_NIL); /* exec just once */
-	result = Qnil;
 	break;
 
 	/* begin .. end without clauses */
@@ -2990,65 +3905,33 @@
 
 	/* nodes for speed-up(literal match) */
       case NODE_MATCH2:
-	{
-	    VALUE l = rb_eval(self,node->nd_recv);
-	    VALUE r = rb_eval(self,node->nd_value);
-	    result = rb_reg_match(l, r);
-	}
+        result = eval_match2(self, node);
 	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);
-	    }
-	}
+        result = eval_match3(self,node);
 	break;
 
 	/* node for speed-up(top-level loop for -n/-p) */
       case NODE_OPT_N:
-	PUSH_TAG(PROT_LOOP);
-	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_opt_n(self, node);
+        break;
 
       case NODE_SELF:
-	RETURN(self);
+	result = self;
+        break;
 
       case NODE_NIL:
-	RETURN(Qnil);
+	break;
 
       case NODE_TRUE:
-	RETURN(Qtrue);
+	result = Qtrue;
+        break;
 
       case NODE_FALSE:
-	RETURN(Qfalse);
+	result = Qfalse;
+        break;
 
       case NODE_IF:
 	if (RTEST(rb_eval(self, node->nd_cond))) {
@@ -3066,150 +3949,20 @@
 	goto again;
 
       case NODE_WHEN:
-	while (node) {
-	    NODE *tag;
-
-	    if (nd_type(node) != NODE_WHEN) goto again;
-	    tag = node->nd_head;
-	    while (tag) {
-		EXEC_EVENT_HOOK(RUBY_EVENT_LINE, tag, self,
-				ruby_frame->last_func,
-				ruby_frame->last_class);
-		if (tag->nd_head && nd_type(tag->nd_head) == NODE_WHEN) {
-		    VALUE v = rb_eval(self, tag->nd_head->nd_head);
-		    long i;
-
-		    if (TYPE(v) != T_ARRAY) v = rb_ary_to_ary(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);
+        if (node = eval_when(self, node)) goto again;
+        break;
 
       case NODE_CASE:
-	{
-	    VALUE val;
-
-	    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) {
-		    EXEC_EVENT_HOOK(RUBY_EVENT_LINE, tag, self,
-				    ruby_frame->last_func,
-				    ruby_frame->last_class);
-		    if (tag->nd_head && nd_type(tag->nd_head) == NODE_WHEN) {
-			VALUE v = rb_eval(self, tag->nd_head->nd_head);
-			long i;
-
-			if (TYPE(v) != T_ARRAY) v = rb_ary_to_ary(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);
+        if (node = eval_case(self, node)) goto again;
+        break;
 
       case NODE_WHILE:
-	PUSH_TAG(PROT_LOOP);
-	result = Qnil;
-	switch (state = EXEC_TAG()) {
-	  case 0:
-	    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:
-	    if (TAG_DST()) {
-		state = 0;
-		result = prot_tag->retval;
-	    }
-	    /* fall through */
-	  default:
-	    break;
-	}
-      while_out:
-	POP_TAG();
-	if (state) JUMP_TAG(state);
-	RETURN(result);
+        result = eval_while(self,node);
+        break;
 
       case NODE_UNTIL:
-	PUSH_TAG(PROT_LOOP);
-	result = Qnil;
-	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:
-	    if (TAG_DST()) {
-		state = 0;
-		result = prot_tag->retval;
-	    }
-	    /* fall through */
-	  default:
-	    break;
-	}
-      until_out:
-	POP_TAG();
-	if (state) JUMP_TAG(state);
-	RETURN(result);
+        result = eval_until(self,node);
+        break;
 
       case NODE_BLOCK_PASS:
 	result = block_pass(self, node);
@@ -3217,47 +3970,7 @@
 
       case NODE_ITER:
       case NODE_FOR:
-	{
-	    PUSH_TAG(PROT_LOOP);
-	    PUSH_BLOCK(node->nd_var, node->nd_body);
-
-	    state = EXEC_TAG();
-	    if (state == 0) {
-	      iter_retry:
-		PUSH_ITER(ITER_PRE);
-		if (nd_type(node) == NODE_ITER) {
-		    result = rb_eval(self, node->nd_iter);
-		}
-		else {
-		    VALUE recv;
-
-		    _block.flags &= ~BLOCK_D_SCOPE;
-		    BEGIN_CALLARGS;
-		    recv = rb_eval(self, node->nd_iter);
-		    END_CALLARGS;
-		    ruby_current_node = node;
-		    SET_CURRENT_SOURCE();
-		    result = rb_call(CLASS_OF(recv),recv,each,0,0,0,self);
-		}
-		POP_ITER();
-	    }
-	    else if (state == TAG_BREAK && TAG_DST()) {
-		result = prot_tag->retval;
-		state = 0;
-	    }
-	    else if (state == TAG_RETRY) {
-		state = 0;
-		goto iter_retry;
-	    }
-	    POP_BLOCK();
-	    POP_TAG();
-	    switch (state) {
-	      case 0:
-		break;
-	      default:
-		JUMP_TAG(state);
-	    }
-	}
+	result = eval_iter(self, node);
 	break;
 
       case NODE_BREAK:
@@ -3265,17 +3978,14 @@
 	break;
 
       case NODE_NEXT:
-	CHECK_INTS;
 	next_jump(rb_eval(self, node->nd_stts));
 	break;
 
       case NODE_REDO:
-	CHECK_INTS;
 	JUMP_TAG(TAG_REDO);
 	break;
 
       case NODE_RETRY:
-	CHECK_INTS;
 	JUMP_TAG(TAG_RETRY);
 	break;
 
@@ -3305,73 +4015,15 @@
 	break;
 
       case NODE_RESCUE:
-	{
-	    volatile VALUE e_info = ruby_errinfo;
-	    volatile int rescuing = 0;
-
-	    PUSH_TAG(PROT_NONE);
-	    if ((state = EXEC_TAG()) == 0) {
-	      retry_entry:
-		result = rb_eval(self, node->nd_head);
-	    }
-	    else if (rescuing) {
-		if (rescuing < 0) {
-		    /* in rescue argument, just reraise */
-		}
-		else if (state == TAG_RETRY) {
-		    rescuing = state = 0;
-		    ruby_errinfo = e_info;
-		    goto retry_entry;
-		}
-		else if (state != TAG_RAISE) {
-		    result = prot_tag->retval;
-		}
-	    }
-	    else if (state == TAG_RAISE) {
-		NODE *resq = node->nd_resq;
-
-		rescuing = -1;
-		while (resq) {
-		    ruby_current_node = resq;
-		    if (handle_rescue(self, resq)) {
-			state = 0;
-			rescuing = 1;
-			result = rb_eval(self, resq->nd_body);
-			break;
-		    }
-		    resq = resq->nd_head; /* next rescue */
-		}
-	    }
-	    else {
-		result = prot_tag->retval;
-	    }
-	    POP_TAG();
-	    if (state != TAG_RAISE) ruby_errinfo = e_info;
-	    if (state) {
-		JUMP_TAG(state);
-	    }
-	    /* no exception raised */
-	    if (!rescuing && (node = node->nd_else)) { /* else clause given */
-		goto again;
-	    }
-	}
+        result = eval_rescue(self,node);
+        if (result == Qundef) {  /* handle else clause w/o recursion */
+          node = node->nd_else;
+          goto again;
+        }
 	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 && !thread_no_ensure()) {
-	    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);
+        result = eval_ensure(self,node);
 	break;
 
       case NODE_AND:
@@ -3387,56 +4039,20 @@
 	goto again;
 
       case NODE_NOT:
-	if (RTEST(rb_eval(self, node->nd_body))) result = Qfalse;
-	else result = Qtrue;
+	result = RTEST(rb_eval(self, node->nd_body)) ? Qfalse : Qtrue;
 	break;
 
       case NODE_DOT2:
       case NODE_DOT3:
-        {
-	    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);
-	}	
-	break;
+        result = eval_dot(self,node);
+        break;
 
       case NODE_FLIP2:		/* like AWK */
-	{
-	    VALUE *flip = rb_svar(node->nd_cnt);
-	    if (!flip) rb_bug("unexpected local variable");
-	    if (!RTEST(*flip)) {
-		if (RTEST(rb_eval(self, node->nd_beg))) {
-		    *flip = RTEST(rb_eval(self, node->nd_end))?Qfalse:Qtrue;
-		    result = Qtrue;
-		}
-		else {
-		    result = Qfalse;
-		}
-	    }
-	    else {
-		if (RTEST(rb_eval(self, node->nd_end))) {
-		    *flip = Qfalse;
-		}
-		result = Qtrue;
-	    }
-	}
+        result = eval_flip2(self,node);
 	break;
 
       case NODE_FLIP3:		/* like SED */
-	{
-	    VALUE *flip = rb_svar(node->nd_cnt);
-	    if (!flip) rb_bug("unexpected local variable");
-	    if (!RTEST(*flip)) {
-		result = RTEST(rb_eval(self, node->nd_beg)) ? Qtrue : Qfalse;
-		*flip = result;
-	    }
-	    else {
-		if (RTEST(rb_eval(self, node->nd_end))) {
-		    *flip = Qfalse;
-		}
-		result = Qtrue;
-	    }
-	}
+        result = eval_flip3(self,node);
 	break;
 
       case NODE_RETURN:
@@ -3444,75 +4060,25 @@
 	break;
 
       case NODE_ARGSCAT:
-	{
-	    VALUE args = rb_eval(self, node->nd_head);
-	    result = rb_ary_concat(args, splat_value(rb_eval(self, node->nd_body)));
-	}
+	result = rb_eval(self, node->nd_head);
+	result = rb_ary_concat(result, splat_value(rb_eval(self, node->nd_body)));
 	break;
 
       case NODE_ARGSPUSH:
-	{
-	    VALUE args = rb_ary_dup(rb_eval(self, node->nd_head));
-	    result = rb_ary_push(args, rb_eval(self, node->nd_body));
-	}
+	result = rb_ary_dup(rb_eval(self, node->nd_head));
+	result = rb_ary_push(result, rb_eval(self, node->nd_body));
 	break;
 
       case NODE_ATTRASGN:
-	{
-	    VALUE recv;
-	    int argc; VALUE *argv; /* used in SETUP_ARGS */
-	    int scope;
-	    TMP_PROTECT;
-
-	    BEGIN_CALLARGS;
-	    if (node->nd_recv == (NODE *)1) {
-		recv = self;
-		scope = 1;
-	    }
-	    else {
-		recv = rb_eval(self, node->nd_recv);
-		scope = 0;
-	    }
-	    SETUP_ARGS(node->nd_args);
-	    END_CALLARGS;
-
-	    ruby_current_node = node;
-	    SET_CURRENT_SOURCE();
-	    rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,scope,self);
-	    result = argv[argc-1];
-	}
-	break;
+        result = eval_attrasgn(self,node);
+        break;
 
       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;
-
-	    ruby_current_node = node;
-	    SET_CURRENT_SOURCE();
-	    result = rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,0,self);
-	}
+        result = eval_call(self,node);
 	break;
 
       case NODE_FCALL:
-	{
-	    int argc; VALUE *argv; /* used in SETUP_ARGS */
-	    TMP_PROTECT;
-
-	    BEGIN_CALLARGS;
-	    SETUP_ARGS(node->nd_args);
-	    END_CALLARGS;
-
-	    ruby_current_node = node;
-	    SET_CURRENT_SOURCE();
-	    result = rb_call(CLASS_OF(self),self,node->nd_mid,argc,argv,1,self);
-	}
+        result = eval_fcall(self,node);
 	break;
 
       case NODE_VCALL:
@@ -3522,142 +4088,19 @@
 
       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_name_error(ruby_frame->last_func,
-				  "superclass method `%s' disabled",
-				  rb_id2name(ruby_frame->orig_func));
-		}
-		else {
-		    rb_raise(rb_eNoMethodError, "super called outside of method");
-		}
-	    }
-	    if (nd_type(node) == NODE_ZSUPER) {
-		argc = ruby_frame->argc;
-		if (argc && DMETHOD_P()) {
-		    if (TYPE(RBASIC(ruby_scope)->klass) != T_ARRAY ||
-			RARRAY(RBASIC(ruby_scope)->klass)->len != argc) {
-			rb_raise(rb_eRuntimeError, 
-				 "super: specify arguments explicitly");
-		    }
-		    argv = RARRAY(RBASIC(ruby_scope)->klass)->ptr;
-		}
-		else if (!ruby_scope->local_vars) {
-		    argc = 0;
-		    argv = 0;
-		}
-		else {
-		    argv = ruby_scope->local_vars + 2;
-		}
-	    }
-	    else {
-		BEGIN_CALLARGS;
-		SETUP_ARGS(node->nd_args);
-		END_CALLARGS;
-		ruby_current_node = node;
-	    }
-
-	    SET_CURRENT_SOURCE();
-	    result = rb_call_super(argc, argv);
-	}
+        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;
-	    }
-	    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, tmp;
-	    NODE *rval;
-	    TMP_PROTECT;
-
-	    recv = rb_eval(self, node->nd_recv);
-	    rval = node->nd_args->nd_head;
-	    SETUP_ARGS0(node->nd_args->nd_body, 1);
-	    val = rb_funcall3(recv, aref, argc, 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:
-	      tmp = rb_eval(self, rval);
-	      val = rb_funcall3(val, node->nd_mid, 1, &tmp);
-	    }
-	    argv[argc] = val;
-	    rb_funcall2(recv, aset, argc+1, argv);
-	    result = val;
-	}
+        result = eval_op_asgn1(self,node);
 	break;
 
       case NODE_OP_ASGN2:
-	{
-	    ID id = node->nd_next->nd_vid;
-	    VALUE recv, val, tmp;
-
-	    recv = rb_eval(self, node->nd_recv);
-	    val = rb_funcall3(recv, id, 0, 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:
-	      tmp = rb_eval(self, node->nd_value);
-	      val = rb_funcall3(val, node->nd_next->nd_mid, 1, &tmp);
-	    }
-
-	    rb_funcall2(recv, node->nd_next->nd_aid, 1, &val);
-	    result = val;
-	}
+        result = eval_op_asgn2(self,node);
 	break;
 
       case NODE_OP_ASGN_AND:
@@ -3706,26 +4149,21 @@
 	break;
 
       case NODE_CDECL:
-	result = rb_eval(self, node->nd_value);
-	if (node->nd_vid == 0) {
-	    rb_const_set(class_prefix(self, node->nd_else), node->nd_else->nd_mid, result);
-	}
-	else {
-	    rb_const_set(ruby_cbase, node->nd_vid, result);
-	}
+        result = rb_eval(self, node->nd_value);
+        eval_cdecl(self, node, result);
 	break;
 
       case NODE_CVDECL:
 	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_set(cvar_cbase(), node->nd_vid, result, Qtrue);
+        result = rb_eval(self, node->nd_value);
+        eval_cvar_set(result, node, Qtrue);
 	break;
 
       case NODE_CVASGN:
-	result = rb_eval(self, node->nd_value);
-	rb_cvar_set(cvar_cbase(), node->nd_vid, result, Qfalse);
+        result = rb_eval(self, node->nd_value);
+        eval_cvar_set(result, node, Qfalse);
 	break;
 
       case NODE_LVAR:
@@ -3768,26 +4206,21 @@
 	break;
 
       case NODE_COLON2:
-	{
-	    VALUE klass;
-
-	    klass = rb_eval(self, node->nd_head);
-	    if (rb_is_const_id(node->nd_mid)) {
-		switch (TYPE(klass)) {
-		  case T_CLASS:
-		  case T_MODULE:
-		    result = rb_const_get_from(klass, node->nd_mid);
-		    break;
-		  default:
-		    rb_raise(rb_eTypeError, "%s is not a class/module",
-			     RSTRING(rb_obj_as_string(klass))->ptr);
-		    break;
-		}
-	    }
-	    else {
-		result = rb_funcall(klass, node->nd_mid, 0, 0);
+	result = rb_eval(self, node->nd_head);
+	if (rb_is_const_id(node->nd_mid)) {
+	    switch (TYPE(result)) {
+	      case T_CLASS:
+	      case T_MODULE:
+		result = rb_const_get_from(result, node->nd_mid);
+		break;
+	      default:
+		rb_raise(rb_eTypeError, "%s is not a class/module",
+			 RSTRING(rb_obj_as_string(result))->ptr);
+		break;
 	    }
 	}
+	else
+	    result = rb_funcall(result, node->nd_mid, 0, 0);
 	break;
 
       case NODE_COLON3:
@@ -3818,23 +4251,7 @@
 	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;
-	}
+        result = eval_hash(self,node);
 	break;
 
       case NODE_ZARRAY:		/* zero length list */
@@ -3842,19 +4259,7 @@
 	break;
 
       case NODE_ARRAY:
-	{
-	    VALUE ary;
-	    long 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;
-	}
+        result = eval_array(self,node);
 	break;
 
       case NODE_STR:
@@ -3870,51 +4275,8 @@
       case NODE_DREGX:
       case NODE_DREGX_ONCE:
       case NODE_DSYM:
-	{
-	    VALUE str, str2;
-	    NODE *list = node->nd_next;
-
-	    str = rb_str_new3(node->nd_lit);
-	    while (list) {
-		if (list->nd_head) {
-		    switch (nd_type(list->nd_head)) {
-		      case NODE_STR:
-			str2 = list->nd_head->nd_lit;
-			break;
-		      default:
-			str2 = 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_LIT:
-		/* other thread may replace NODE_DREGX_ONCE to NODE_LIT */
-		goto again;
-	      case NODE_DXSTR:
-		result = rb_funcall(self, '`', 1, str);
-		break;
-	      case NODE_DSYM:
-		result = rb_str_intern(str);
-		break;
-	      default:
-		result = str;
-		break;
-	    }
-	}
+        result = eval_slit(self, node);
+        if (result == Qundef) goto again;
 	break;
 
       case NODE_XSTR:
@@ -3926,84 +4288,13 @@
 	break;
 
       case NODE_DEFN:
-	if (node->nd_defn) {
-	    NODE *body,  *defn;
-	    VALUE origin = 0;
-	    int noex;
-
-	    if (NIL_P(ruby_class)) {
-		rb_raise(rb_eTypeError, "no class/module 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 && body->nd_body) {
-		    rb_warning("method redefined; discarding old %s", rb_id2name(node->nd_mid));
-		}
-	    }
-
-	    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_body == 0) {
-		noex |= NOEX_NOSUPER;
-	    }
-
-	    defn = rb_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);
-	    }
-	    result = Qnil;
-	}
+	if (node->nd_defn)
+          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 (ruby_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_obj_classname(recv));
-	    }
-
-	    if (OBJ_FROZEN(recv)) rb_error_frozen("object");
-	    klass = rb_singleton_class(recv);
-	    if (st_lookup(RCLASS(klass)->m_tbl, node->nd_mid, &data)) {
-		body = (NODE *)data;
-		if (ruby_safe_level >= 4) {
-		    rb_raise(rb_eSecurityError, "redefining method prohibited");
-		}
-		if (RTEST(ruby_verbose)) {
-		    rb_warning("redefine %s", rb_id2name(node->nd_mid));
-		}
-	    }
-	    defn = rb_copy_node_scope(node->nd_defn, ruby_cref);
-	    rb_add_method(klass, node->nd_mid, defn,
-			  NOEX_PUBLIC|(body?body->nd_noex&NOEX_UNDEF:0));
-	    result = Qnil;
-	}
+	if (node->nd_defn) 
+          eval_defs(self,node);
 	break;
 
       case NODE_UNDEF:
@@ -4011,7 +4302,6 @@
 	    rb_raise(rb_eTypeError, "no class to undef method");
 	}
 	rb_undef(ruby_class, rb_to_id(rb_eval(self, node->u2.node)));
-	result = Qnil;
 	break;
 
       case NODE_ALIAS:
@@ -4020,134 +4310,26 @@
 	}
 	rb_alias(ruby_class, rb_to_id(rb_eval(self, node->u1.node)),
 		             rb_to_id(rb_eval(self, node->u2.node)));
-	result = Qnil;
 	break;
 
       case NODE_VALIAS:
 	rb_alias_variable(node->u1.id, node->u2.id);
-	result = Qnil;
 	break;
 
       case NODE_CLASS:
-	{
-	    VALUE super, klass, tmp, cbase;
-	    ID cname;
-	    int gen = Qfalse;
-
-	    cbase = class_prefix(self, node->nd_cpath);
-	    cname = node->nd_cpath->nd_mid;
-
-	    if (NIL_P(ruby_cbase)) {
-		rb_raise(rb_eTypeError, "no outer class/module");
-	    }
-	    if (node->nd_super) {
-	       super = rb_eval(self, node->nd_super);
-	       rb_check_inheritable(super);
-	    }
-	    else {
-		super = 0;
-	    }
-
-	    if (rb_const_defined_at(cbase, cname)) {
-		klass = rb_const_get_at(cbase, cname);
-		if (TYPE(klass) != T_CLASS) {
-		    rb_raise(rb_eTypeError, "%s is not a class",
-			     rb_id2name(cname));
-		}
-		if (super) {
-		    tmp = rb_class_real(RCLASS(klass)->super);
-		    if (tmp != super) {
-			rb_raise(rb_eTypeError, "superclass mismatch for class %s",
-				 rb_id2name(cname));
-		    }
-		    super = 0;
-		}
-		if (ruby_safe_level >= 4) {
-		    rb_raise(rb_eSecurityError, "extending class prohibited");
-		}
-	    }
-	    else {
-		if (!super) super = rb_cObject;
-		klass = rb_define_class_id(cname, super);
-		rb_set_class_path(klass, cbase, rb_id2name(cname));
-		rb_const_set(cbase, cname, klass);
-		gen = Qtrue;
-	    }
-	    if (ruby_wrapper) {
-		rb_extend_object(klass, ruby_wrapper);
-		rb_include_module(klass, ruby_wrapper);
-	    }
-	    if (super && gen) {
-		rb_class_inherited(super, klass);
-	    }
-	    result = module_setup(klass, node);
-	}
+        result = eval_class(self,node);
 	break;
 
       case NODE_MODULE:
-	{
-	    VALUE module, cbase;
-	    ID cname;
-
-	    if (NIL_P(ruby_cbase)) {
-		rb_raise(rb_eTypeError, "no outer class/module");
-	    }
-	    cbase = class_prefix(self, node->nd_cpath);
-	    cname = node->nd_cpath->nd_mid;
-	    if (rb_const_defined_at(cbase, cname)) {
-		module = rb_const_get_at(cbase, cname);
-		if (TYPE(module) != T_MODULE) {
-		    rb_raise(rb_eTypeError, "%s is not a module",
-			     rb_id2name(cname));
-		}
-		if (ruby_safe_level >= 4) {
-		    rb_raise(rb_eSecurityError, "extending module prohibited");
-		}
-	    }
-	    else {
-		module = rb_define_module_id(cname);
-		rb_set_class_path(module, cbase, rb_id2name(cname));
-		rb_const_set(cbase, cname, module);
-	    }
-	    if (ruby_wrapper) {
-		rb_extend_object(module, ruby_wrapper);
-		rb_include_module(module, ruby_wrapper);
-	    }
-
-	    result = module_setup(module, node);
-	}
+        result = eval_module(self,node);
 	break;
 
       case NODE_SCLASS:
-	{
-	    VALUE klass;
-
-	    result = rb_eval(self, node->nd_recv);
-	    if (FIXNUM_P(result) || SYMBOL_P(result)) {
-		rb_raise(rb_eTypeError, "no virtual class for %s",
-			 rb_obj_classname(result));
-	    }
-	    if (ruby_safe_level >= 4 && !OBJ_TAINTED(result))
-		rb_raise(rb_eSecurityError, "Insecure: can't extend object");
-	    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);
-	}
+        result = eval_sclass(self,node);
 	break;
 
       case NODE_DEFINED:
-	{
-	    char buf[20];
-	    const char *desc = is_defined(self, node->nd_head, buf);
-
-	    if (desc) result = rb_str_new2(desc);
-	    else result = Qnil;
-	}
+        result = eval_defined(self,node);
 	break;
 
       case NODE_NEWLINE:
@@ -4160,14 +4342,8 @@
       default:
 	unknown_node(node);
     }
-  finish:
-    CHECK_INTS;
-    if (contnode) {
-	node = contnode;
-	contnode = 0;
-	goto again;
-    }
-    return result;
+  }
+  return result;
 }
 
 static VALUE
@@ -13081,6 +13257,32 @@
 
 VALUE rb_cCont;
 
+
+static rb_thread_t prep4callcc(void)
+{
+  rb_thread_t th;
+  struct tag *tag;
+  struct RVarmap *vars;
+
+  THREAD_ALLOC(th);
+  /* must finish th initialization before any possible gc */
+  th->thread = curr_thread->thread;    /* brent@mbari.org */
+  th->thgroup = cont_protect;
+
+  scope_dup(ruby_scope);
+  for (tag=prot_tag; tag; tag=tag->prev) {
+      if (tag->tag == PROT_THREAD) break;
+      scope_dup(tag->scope);
+  }
+
+  for (vars = ruby_dyna_vars; vars; vars = vars->next) {
+      if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break;
+      FL_SET(vars, DVAR_DONT_RECYCLE);
+  }
+  return th;
+}
+
+
 /*
  *  call-seq:
  *     callcc {|cont| block }   =>  obj
@@ -13099,37 +13301,14 @@
 rb_callcc(self)
     VALUE self;
 {
-    volatile VALUE cont;
-    rb_thread_t th;
-    volatile rb_thread_t th_save;
-    struct tag *tag;
-    struct RVarmap *vars;
-
-    THREAD_ALLOC(th);
-    /* must finish th initialization before any possible gc */
-    th->thread = curr_thread->thread;    /* brent@mbari.org */
-    th->thgroup = cont_protect;
-    cont = Data_Wrap_Struct(rb_cCont, cc_mark, thread_free, th);
-
-    scope_dup(ruby_scope);
-    for (tag=prot_tag; tag; tag=tag->prev) {
-        if (tag->tag == PROT_THREAD) break;
-	scope_dup(tag->scope);
-    }
-
-    for (vars = ruby_dyna_vars; vars; vars = vars->next) {
-	if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break;
-	FL_SET(vars, DVAR_DONT_RECYCLE);
-    }
-    th_save = th;
-    if (THREAD_SAVE_CONTEXT(th)) {
-	return th_save->result;
-    }
-    else {
-	return rb_yield(cont);
-    }
+    rb_thread_t th = prep4callcc();
+    return THREAD_SAVE_CONTEXT(th) ?
+      th->result
+          :
+      rb_yield(Data_Wrap_Struct(rb_cCont, cc_mark, thread_free, th));
 }
 
+
 /*
  *  call-seq:
  *     cont.call(args, ...) 
diff -rux '*.o' ruby-1.8.7-p72/version.h ruby-1.8.7-mbari/version.h
--- ruby-1.8.7-p72/version.h	2008-12-16 00:47:26.000000000 -0800
+++ ruby-1.8.7-mbari/version.h	2008-12-16 20:02:42.000000000 -0800
@@ -1,7 +1,7 @@
 #define RUBY_VERSION "1.8.7"
-#define RUBY_RELEASE_DATE "2008-12-13"
+#define RUBY_RELEASE_DATE "2008-12-16"
 #define RUBY_VERSION_CODE 187
-#define RUBY_RELEASE_CODE 20081213
+#define RUBY_RELEASE_CODE 20081216
 #define RUBY_PATCHLEVEL 72
 
 #define RUBY_VERSION_MAJOR 1
@@ -9,7 +9,7 @@
 #define RUBY_VERSION_TEENY 7
 #define RUBY_RELEASE_YEAR 2008
 #define RUBY_RELEASE_MONTH 12
-#define RUBY_RELEASE_DAY 13
+#define RUBY_RELEASE_DAY 16
 
 #ifdef RUBY_EXTERN
 RUBY_EXTERN const char ruby_version[];
@@ -25,7 +25,7 @@
 #define RUBY_BIRTH_MONTH 2
 #define RUBY_BIRTH_DAY 24
 
-#define RUBY_RELEASE_STR "MBARI 3 on patchlevel"
+#define RUBY_RELEASE_STR "MBARI 4 on patchlevel"
 #define RUBY_RELEASE_NUM RUBY_PATCHLEVEL
 
 
