Index: EcnlProtoTool/trunk/mruby-1.3.0/src/gc.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.2.0/src/gc.c	(revision 321)
+++ EcnlProtoTool/trunk/mruby-1.3.0/src/gc.c	(revision 331)
@@ -7,15 +7,16 @@
 #include <string.h>
 #include <stdlib.h>
-#include "mruby.h"
-#include "mruby/array.h"
-#include "mruby/class.h"
-#include "mruby/data.h"
-#include "mruby/hash.h"
-#include "mruby/proc.h"
-#include "mruby/range.h"
-#include "mruby/string.h"
-#include "mruby/variable.h"
-#include "mruby/gc.h"
-#include "mruby/error.h"
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+#include <mruby/hash.h>
+#include <mruby/proc.h>
+#include <mruby/range.h>
+#include <mruby/string.h>
+#include <mruby/variable.h>
+#include <mruby/gc.h>
+#include <mruby/error.h>
+#include <mruby/throw.h>
 
 /*
@@ -66,5 +67,5 @@
   mruby implementer and C extension library writer must insert a write
   barrier when updating a reference from a field of an object.
-  When updating a reference from a field of object A to object B, 
+  When updating a reference from a field of object A to object B,
   two different types of write barrier are available:
 
@@ -110,5 +111,7 @@
     struct RData data;
     struct RProc proc;
+    struct REnv env;
     struct RException exc;
+    struct RBreak brk;
 #ifdef MRB_WORD_BOXING
     struct RFloat floatv;
@@ -138,5 +141,5 @@
   fprintf(stderr, "gc_invoke: %19.3f\n", gettimeofday_time() - program_invoke_time);\
   fprintf(stderr, "is_generational: %d\n", is_generational(gc));\
-  fprintf(stderr, "is_major_gc: %d\n", is_major_gc(mrb));\
+  fprintf(stderr, "is_major_gc: %d\n", is_major_gc(gc));\
 } while(0)
 
@@ -214,6 +217,8 @@
 
   p2 = mrb_realloc_simple(mrb, p, len);
-  if (!p2 && len) {
+  if (len == 0) return p2;
+  if (p2 == NULL) {
     if (mrb->gc.out_of_memory) {
+      mrb_exc_raise(mrb, mrb_obj_value(mrb->nomem_err));
       /* mrb_panic(mrb); */
     }
@@ -367,5 +372,5 @@
 }
 
-static void obj_free(mrb_state *mrb, struct RBasic *obj);
+static void obj_free(mrb_state *mrb, struct RBasic *obj, int end);
 
 void
@@ -381,5 +386,5 @@
     for (p = objects(tmp), e=p+MRB_HEAP_PAGE_SIZE; p<e; p++) {
       if (p->as.free.tt != MRB_TT_FREE)
-        obj_free(mrb, &p->as.basic);
+        obj_free(mrb, &p->as.basic, TRUE);
     }
     mrb_free(mrb, tmp);
@@ -403,5 +408,5 @@
     /* arena overflow error */
     gc->arena_idx = MRB_GC_ARENA_SIZE - 4; /* force room in arena */
-    mrb_raise(mrb, E_RUNTIME_ERROR, "arena overflow error");
+    mrb_exc_raise(mrb, mrb_obj_value(mrb->arena_err));
   }
 #else
@@ -429,5 +434,5 @@
    Register your object when it's exported to C world,
    without reference from Ruby world, e.g. callback
-   arguments.  Don't forget to remove the obejct using
+   arguments.  Don't forget to remove the object using
    mrb_gc_unregister, otherwise your object will leak.
 */
@@ -453,5 +458,5 @@
   mrb_value table = mrb_gv_get(mrb, root);
   struct RArray *a;
-  mrb_int i, j;
+  mrb_int i;
 
   if (mrb_nil_p(table)) return;
@@ -462,10 +467,11 @@
   a = mrb_ary_ptr(table);
   mrb_ary_modify(mrb, a);
-  for (i=j=0; i<a->len; i++) {
-    if (!mrb_obj_eq(mrb, a->ptr[i], obj)) {
-      a->ptr[j++] = a->ptr[i];
-    }
-  }
-  a->len = j;
+  for (i = 0; i < a->len; i++) {
+    if (mrb_obj_eq(mrb, a->ptr[i], obj)) {
+      a->len--;
+      memmove(&a->ptr[i], &a->ptr[i + 1], (a->len - i) * sizeof(a->ptr[i]));
+      break;
+    }
+  }
 }
 
@@ -476,4 +482,26 @@
   static const RVALUE RVALUE_zero = { { { MRB_TT_FALSE } } };
   mrb_gc *gc = &mrb->gc;
+
+  if (cls) {
+    enum mrb_vtype tt;
+
+    switch (cls->tt) {
+    case MRB_TT_CLASS:
+    case MRB_TT_SCLASS:
+    case MRB_TT_MODULE:
+    case MRB_TT_ENV:
+      break;
+    default:
+      mrb_raise(mrb, E_TYPE_ERROR, "allocation failure");
+    }
+    tt = MRB_INSTANCE_TT(cls);
+    if (tt != MRB_TT_FALSE &&
+        ttype != MRB_TT_SCLASS &&
+        ttype != MRB_TT_ICLASS &&
+        ttype != MRB_TT_ENV &&
+        ttype != tt) {
+      mrb_raisef(mrb, E_TYPE_ERROR, "allocation failure of %S", mrb_obj_value(cls));
+    }
+  }
 
 #ifdef MRB_GC_STRESS
@@ -520,7 +548,15 @@
   size_t i;
   size_t e;
-
+  mrb_value nil;
+  int nregs;
+
+  if (c->stack == NULL) return;
   e = c->stack - c->stbase;
-  if (c->ci) e += c->ci->nregs;
+  if (c->ci) {
+    nregs = c->ci->argc + 2;
+    if (c->ci->nregs > nregs)
+      nregs = c->ci->nregs;
+    e += nregs;
+  }
   if (c->stbase + e > c->stend) e = c->stend - c->stbase;
   for (i=0; i<e; i++) {
@@ -528,11 +564,11 @@
 
     if (!mrb_immediate_p(v)) {
-      if (mrb_basic_ptr(v)->tt == MRB_TT_FREE) {
-        c->stbase[i] = mrb_nil_value();
-      }
-      else {
-        mrb_gc_mark(mrb, mrb_basic_ptr(v));
-      }
-    }
+      mrb_gc_mark(mrb, mrb_basic_ptr(v));
+    }
+  }
+  e = c->stend - c->stbase;
+  nil = mrb_nil_value();
+  for (; i<e; i++) {
+    c->stbase[i] = nil;
   }
 }
@@ -541,16 +577,13 @@
 mark_context(mrb_state *mrb, struct mrb_context *c)
 {
-  int i, e = 0;
+  int i;
   mrb_callinfo *ci;
 
-  /* mark stack */
+  /* mark VM stack */
   mark_context_stack(mrb, c);
 
-  /* mark VM stack */
+  /* mark call stack */
   if (c->cibase) {
     for (ci = c->cibase; ci <= c->ci; ci++) {
-      if (ci->eidx > e) {
-        e = ci->eidx;
-      }
       mrb_gc_mark(mrb, (struct RBasic*)ci->env);
       mrb_gc_mark(mrb, (struct RBasic*)ci->proc);
@@ -559,10 +592,12 @@
   }
   /* mark ensure stack */
-  for (i=0; i<e; i++) {
+  for (i=0; i<c->esize; i++) {
+    if (c->ensure[i] == NULL) break;
     mrb_gc_mark(mrb, (struct RBasic*)c->ensure[i]);
   }
   /* mark fibers */
-  if (c->prev && c->prev->fib) {
-    mrb_gc_mark(mrb, (struct RBasic*)c->prev->fib);
+  mrb_gc_mark(mrb, (struct RBasic*)c->fib);
+  if (c->prev) {
+    mark_context(mrb, c->prev);
   }
 }
@@ -614,12 +649,15 @@
     {
       struct REnv *e = (struct REnv*)obj;
-
-      if (!MRB_ENV_STACK_SHARED_P(e)) {
-        mrb_int i, len;
-
-        len = MRB_ENV_STACK_LEN(e);
-        for (i=0; i<len; i++) {
-          mrb_gc_mark_value(mrb, e->stack[i]);
+      mrb_int i, len;
+
+      if (MRB_ENV_STACK_SHARED_P(e)) {
+        if (e->cxt.c->fib) {
+          mrb_gc_mark(mrb, (struct RBasic*)e->cxt.c->fib);
         }
+        break;
+      }
+      len = MRB_ENV_STACK_LEN(e);
+      for (i=0; i<len; i++) {
+        mrb_gc_mark_value(mrb, e->stack[i]);
       }
     }
@@ -679,7 +717,7 @@
 
 static void
-obj_free(mrb_state *mrb, struct RBasic *obj)
-{
-  DEBUG(printf("obj_free(%p,tt=%d)\n",obj,obj->tt));
+obj_free(mrb_state *mrb, struct RBasic *obj, int end)
+{
+  DEBUG(fprintf(stderr, "obj_free(%p,tt=%d)\n",obj,obj->tt));
   switch (obj->tt) {
     /* immediate - no mark */
@@ -698,4 +736,7 @@
 
   case MRB_TT_OBJECT:
+    mrb_gc_free_iv(mrb, (struct RObject*)obj);
+    break;
+
   case MRB_TT_EXCEPTION:
     mrb_gc_free_iv(mrb, (struct RObject*)obj);
@@ -716,8 +757,10 @@
       struct REnv *e = (struct REnv*)obj;
 
-      if (!MRB_ENV_STACK_SHARED_P(e)) {
-        mrb_free(mrb, e->stack);
-        e->stack = NULL;
+      if (MRB_ENV_STACK_SHARED_P(e)) {
+        /* cannot be freed */
+        return;
       }
+      mrb_free(mrb, e->stack);
+      e->stack = NULL;
     }
     break;
@@ -727,6 +770,18 @@
       struct mrb_context *c = ((struct RFiber*)obj)->cxt;
 
-      if (c != mrb->root_c)
+      if (!end && c && c != mrb->root_c) {
+        mrb_callinfo *ci = c->ci;
+        mrb_callinfo *ce = c->cibase;
+
+        while (ce <= ci) {
+          struct REnv *e = ci->env;
+          if (e && !is_dead(&mrb->gc, e) &&
+              e->tt == MRB_TT_ENV && MRB_ENV_STACK_SHARED_P(e)) {
+            mrb_env_unshare(mrb, e);
+          }
+          ci--;
+        }
         mrb_free_context(mrb, c);
+      }
     }
     break;
@@ -781,5 +836,5 @@
 root_scan_phase(mrb_state *mrb, mrb_gc *gc)
 {
-  size_t i, e;
+  int i, e;
 
   if (!is_minor_gc(gc)) {
@@ -795,4 +850,24 @@
   /* mark class hierarchy */
   mrb_gc_mark(mrb, (struct RBasic*)mrb->object_class);
+
+  /* mark built-in classes */
+  mrb_gc_mark(mrb, (struct RBasic*)mrb->class_class);
+  mrb_gc_mark(mrb, (struct RBasic*)mrb->module_class);
+  mrb_gc_mark(mrb, (struct RBasic*)mrb->proc_class);
+  mrb_gc_mark(mrb, (struct RBasic*)mrb->string_class);
+  mrb_gc_mark(mrb, (struct RBasic*)mrb->array_class);
+  mrb_gc_mark(mrb, (struct RBasic*)mrb->hash_class);
+
+  mrb_gc_mark(mrb, (struct RBasic*)mrb->float_class);
+  mrb_gc_mark(mrb, (struct RBasic*)mrb->fixnum_class);
+  mrb_gc_mark(mrb, (struct RBasic*)mrb->true_class);
+  mrb_gc_mark(mrb, (struct RBasic*)mrb->false_class);
+  mrb_gc_mark(mrb, (struct RBasic*)mrb->nil_class);
+  mrb_gc_mark(mrb, (struct RBasic*)mrb->symbol_class);
+  mrb_gc_mark(mrb, (struct RBasic*)mrb->kernel_module);
+
+  mrb_gc_mark(mrb, (struct RBasic*)mrb->eException_class);
+  mrb_gc_mark(mrb, (struct RBasic*)mrb->eStandardError_class);
+
   /* mark top_self */
   mrb_gc_mark(mrb, (struct RBasic*)mrb->top_self);
@@ -801,11 +876,12 @@
   /* mark pre-allocated exception */
   mrb_gc_mark(mrb, (struct RBasic*)mrb->nomem_err);
-
-  mark_context(mrb, mrb->root_c);
-  if (mrb->root_c->fib) {
-    mrb_gc_mark(mrb, (struct RBasic*)mrb->root_c->fib);
-  }
+  mrb_gc_mark(mrb, (struct RBasic*)mrb->stack_err);
+#ifdef MRB_GC_FIXED_ARENA
+  mrb_gc_mark(mrb, (struct RBasic*)mrb->arena_err);
+#endif
+
+  mark_context(mrb, mrb->c);
   if (mrb->root_c != mrb->c) {
-    mark_context(mrb, mrb->c);
+    mark_context(mrb, mrb->root_c);
   }
 }
@@ -859,5 +935,5 @@
 
       /* mark ensure stack */
-      children += (c->ci) ? c->ci->eidx : 0;
+      children += c->eidx;
 
       /* mark closure */
@@ -920,5 +996,14 @@
 final_marking_phase(mrb_state *mrb, mrb_gc *gc)
 {
-  mark_context_stack(mrb, mrb->root_c);
+  int i, e;
+
+  /* mark arena */
+  for (i=0,e=gc->arena_idx; i<e; i++) {
+    mrb_gc_mark(mrb, gc->arena[i]);
+  }
+  mrb_gc_mark_gv(mrb);
+  mark_context(mrb, mrb->c);
+  mark_context(mrb, mrb->root_c);
+  mrb_gc_mark(mrb, (struct RBasic*)mrb->exc);
   gc_mark_gray_list(mrb, gc);
   mrb_assert(gc->gray_list == NULL);
@@ -958,8 +1043,13 @@
       if (is_dead(gc, &p->as.basic)) {
         if (p->as.basic.tt != MRB_TT_FREE) {
-          obj_free(mrb, &p->as.basic);
-          p->as.free.next = page->freelist;
-          page->freelist = (struct RBasic*)p;
-          freed++;
+          obj_free(mrb, &p->as.basic, FALSE);
+          if (p->as.basic.tt == MRB_TT_FREE) {
+            p->as.free.next = page->freelist;
+            page->freelist = (struct RBasic*)p;
+            freed++;
+          }
+          else {
+            dead_slot = FALSE;
+          }
         }
       }
@@ -967,5 +1057,5 @@
         if (!is_generational(gc))
           paint_partial_white(gc, &p->as.basic); /* next gc target */
-        dead_slot = 0;
+        dead_slot = FALSE;
       }
       p++;
@@ -1080,5 +1170,5 @@
   mrb_gc *gc = &mrb->gc;
 
-  if (gc->disabled) return;
+  if (gc->disabled || gc->iterating) return;
 
   GC_INVOKE_TIME_REPORT("mrb_incremental_gc()");
@@ -1120,5 +1210,5 @@
   mrb_gc *gc = &mrb->gc;
 
-  if (gc->disabled) return;
+  if (gc->disabled || gc->iterating) return;
 
   GC_INVOKE_TIME_REPORT("mrb_full_gc()");
@@ -1357,4 +1447,8 @@
 change_gen_gc_mode(mrb_state *mrb, mrb_gc *gc, mrb_bool enable)
 {
+  if (gc->disabled || gc->iterating) {
+    mrb_raise(mrb, E_RUNTIME_ERROR, "generational mode changed when GC disabled");
+    return;
+  }
   if (is_generational(gc) && !enable) {
     clear_all_old(mrb, gc);
@@ -1408,15 +1502,16 @@
 gc_each_objects(mrb_state *mrb, mrb_gc *gc, mrb_each_object_callback *callback, void *data)
 {
-  mrb_heap_page* page = gc->heaps;
-
+  mrb_heap_page* page;
+
+  page = gc->heaps;
   while (page != NULL) {
-    RVALUE *p, *pend;
+    RVALUE *p;
+    int i;
 
     p = objects(page);
-    pend = p + MRB_HEAP_PAGE_SIZE;
-    for (;p < pend; p++) {
-      (*callback)(mrb, &p->as.basic, data);
-    }
-
+    for (i=0; i < MRB_HEAP_PAGE_SIZE; i++) {
+      if ((*callback)(mrb, &p[i].as.basic, data) == MRB_EACH_OBJ_BREAK)
+        return;
+    }
     page = page->next;
   }
@@ -1426,5 +1521,25 @@
 mrb_objspace_each_objects(mrb_state *mrb, mrb_each_object_callback *callback, void *data)
 {
-  gc_each_objects(mrb, &mrb->gc, callback, data);
+  mrb_bool iterating = mrb->gc.iterating;
+
+  mrb->gc.iterating = TRUE;
+  if (iterating) {
+    gc_each_objects(mrb, &mrb->gc, callback, data);
+  }
+  else {
+    struct mrb_jmpbuf *prev_jmp = mrb->jmp;
+    struct mrb_jmpbuf c_jmp;
+
+    MRB_TRY(&c_jmp) {
+      mrb->jmp = &c_jmp;
+      gc_each_objects(mrb, &mrb->gc, callback, data);
+      mrb->jmp = prev_jmp;
+      mrb->gc.iterating = iterating; 
+   } MRB_CATCH(&c_jmp) {
+      mrb->gc.iterating = iterating;
+      mrb->jmp = prev_jmp;
+      MRB_THROW(prev_jmp);
+    } MRB_END_EXC(&c_jmp);
+  }
 }
 
