<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>doc/life_of_a_context.txt</filename>
    </added>
    <added>
      <filename>shotgun/lib/memutil.h</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -56,9 +56,9 @@ struct rubinius_object {
 /* Mask the current flags2 to remove the current zone bits, then or
    them with the new desired ones. */
 #define GC_ZONE_SET(obj, val) (HEADER(obj)-&gt;flags2 = ((HEADER(obj)-&gt;flags2 &amp; ZONE_MASK) | (((val) &amp; ZONE_MASK) &lt;&lt; ZONE_OFFSET)))
-#define GC_MATURE_OBJECTS 0
-#define GC_YOUNG_OBJECTS  1
-#define GC_LARGE_OBJECTS  2
+#define GC_MATURE_OBJECTS 1
+#define GC_YOUNG_OBJECTS  2
+#define GC_LARGE_OBJECTS  3
 
 #define GC_MAKE_FOREVER_YOUNG(obj) (HEADER(obj)-&gt;gc |= 0x8000)
 </diff>
      <filename>include/rubinius.h</filename>
    </modified>
    <modified>
      <diff>@@ -65,8 +65,8 @@ int baker_gc_swap(baker_gc g) {
   g-&gt;current = g-&gt;next;
   g-&gt;next = tmp;
   
-  g-&gt;last_start = tmp-&gt;address;
-  g-&gt;last_end =   tmp-&gt;current;
+  g-&gt;last_start = (char*)tmp-&gt;address;
+  g-&gt;last_end =   (char*)tmp-&gt;current;
   
   heap_reset(tmp);
   /* Reset used to the what the current has used. */
@@ -105,7 +105,7 @@ OBJECT baker_gc_forwarded_object(OBJECT obj) {
   OBJECT ret;                                 \
   if(baker_gc_forwarded_p(iobj)) {            \
     ret = baker_gc_forwarded_object(iobj);    \
-  } else if(baker_gc_contains_p(g, iobj)) {   \
+  } else if(baker_gc_contains_p(g, iobj) || heap_contains_p(state-&gt;om-&gt;contexts, iobj)) {   \
     ret = baker_gc_mutate_object(st, g, iobj);    \
   } else {                                    \
     ret = iobj;                               \
@@ -170,7 +170,7 @@ static inline void _mutate_references(STATE, baker_gc g, OBJECT iobj) {
   
   SET_CLASS(iobj, cls);
   
-  assert(HEADER(iobj)-&gt;flags != FORWARDING_MAGIC);
+  xassert(HEADER(iobj)-&gt;flags != FORWARDING_MAGIC);
   
   if(WEAK_REFERENCES_P(iobj)) {
     // printf(&quot;%p has weak refs.\n&quot;, (void*)iobj);
@@ -197,7 +197,6 @@ static inline void _mutate_references(STATE, baker_gc g, OBJECT iobj) {
     }
   } else {
 #define fc_mutate(field) if(fc-&gt;field &amp;&amp; REFERENCE_P(fc-&gt;field)) SET_STRUCT_FIELD(iobj, fc-&gt;field, baker_gc_maybe_mutate(state, g, fc-&gt;field))
-// #define fc_mutate(field) if(REFERENCE_P(fc-&gt;field)) fc-&gt;field = baker_gc_maybe_mutate(state, g, fc-&gt;field)
     if(methctx_is_fast_p(state, iobj)) {
       struct fast_context *fc = FASTCTX(iobj);
       fc_mutate(sender);
@@ -221,11 +220,10 @@ static inline void _mutate_references(STATE, baker_gc g, OBJECT iobj) {
       fc_mutate(exception);
       fc_mutate(new_class_of);
       fc_mutate(enclosing_class);
-      fc_mutate(top_context);
       fc_mutate(exceptions);
       fc_mutate(active_context);
       fc_mutate(home_context);
-      fc_mutate(main);
+      fc_mutate(main);  
       fc_mutate(outstanding);
       fc_mutate(debug_channel);
       fc_mutate(control_channel);
@@ -252,12 +250,65 @@ static inline void _mutate_references(STATE, baker_gc g, OBJECT iobj) {
   depth--;
 }
 
+void baker_gc_mutate_context(STATE, baker_gc g, OBJECT iobj, int shifted, int top) {
+  #define fc_mutate(field) if(fc-&gt;field &amp;&amp; REFERENCE_P(fc-&gt;field)) fc-&gt;field = baker_gc_mutate_from(state, g, fc-&gt;field)
+  
+  struct fast_context *fc = FASTCTX(iobj);
+  OBJECT old_sender;
+  
+  
+  if(REFERENCE_P(fc-&gt;sender)) {
+    /* This is the top most stack context, handle it differently */
+    if(top) {
+      if(shifted) {
+        xassert(om_in_heap(state-&gt;om, fc-&gt;sender) || om_context_referenced_p(state-&gt;om, fc-&gt;sender));
+        xassert(HEADER(fc-&gt;sender) != Qnil);
+      } else {
+        xassert(om_in_heap(state-&gt;om, fc-&gt;sender));
+      }
+      fc_mutate(sender);
+    } else {
+      if(shifted) {
+        old_sender = fc-&gt;sender;
+        xassert(om_on_stack(state-&gt;om, old_sender));
+        fc-&gt;sender = HEADER(old_sender)-&gt;klass;
+        xassert(NIL_P(fc-&gt;sender) || fc-&gt;sender == om_stack_sender(iobj));
+      } else {
+        xassert(om_on_stack(state-&gt;om, fc-&gt;sender));
+      }
+    }
+  }
+  
+  fc_mutate(method);
+  fc_mutate(block);
+  fc_mutate(literals);
+  fc_mutate(self);
+  fc_mutate(locals);
+  fc_mutate(method_module);
+
+  /* We cache the bytecode in a char*, so adjust it. 
+     We mutate the data first so we cache the newest address. */
+  OBJECT ba;
+  ba = cmethod_get_bytecodes(fc-&gt;method);
+  ba = baker_gc_maybe_mutate(state, g, ba);
+
+  fc-&gt;data = BYTEARRAY_ADDRESS(ba);
+  fc-&gt;data_size = BYTEARRAY_SIZE(ba);
+#undef fc_mutate
+}
+
+static int saved_contexts;
+
 OBJECT baker_gc_mutate_object(STATE, baker_gc g, OBJECT obj) {
   OBJECT dest;
   if(obj == g-&gt;become_from) {
     return baker_gc_maybe_mutate(state, g, g-&gt;become_to);
   }
   
+  if(heap_contains_p(state-&gt;om-&gt;contexts, obj)) {
+    saved_contexts++;
+  }
+  
   if(_track_refs) {
     int i;
     for(i = 0; i &lt; _track_refs-&gt;len; i++) {
@@ -269,7 +320,7 @@ OBJECT baker_gc_mutate_object(STATE, baker_gc g, OBJECT obj) {
   
   if((AGE(obj) == g-&gt;tenure_age)) {
     // int age = AGE(obj);
-    assert(HEADER(obj)-&gt;klass != state-&gt;global-&gt;fastctx);
+    xassert(HEADER(obj)-&gt;klass != state-&gt;global-&gt;fastctx);
     CLEAR_AGE(obj);
     /*
     if(CLASS_OBJECT(obj) == state-&gt;global-&gt;cmethod) {
@@ -282,6 +333,7 @@ OBJECT baker_gc_mutate_object(STATE, baker_gc g, OBJECT obj) {
     _mutate_references(state, g, dest);
   } else {
     if(heap_enough_fields_p(g-&gt;next, NUM_FIELDS(obj))) {
+      xassert(HEADER(obj)-&gt;klass != Qnil);
       dest = heap_copy_object(g-&gt;next, obj);
       baker_gc_set_forwarding_address(obj, dest);
       if(!FOREVER_YOUNG(obj)) HEADER(dest)-&gt;gc++;
@@ -315,7 +367,8 @@ int baker_gc_contains_spill_p(baker_gc g, OBJECT obj) {
 
 
 OBJECT baker_gc_mutate_from(STATE, baker_gc g, OBJECT orig) {
-  OBJECT ret, iobj;
+  OBJECT ret, iobj, mut;
+  int count = 0;
   
   //printf(&quot;!!!\n   =&gt; From %p\n!!!\n&quot;, iobj);
   
@@ -326,8 +379,13 @@ OBJECT baker_gc_mutate_from(STATE, baker_gc g, OBJECT orig) {
   iobj = ret;
   
   while(iobj) {
+    if(baker_gc_forwarded_p(iobj)) {
+      mut = baker_gc_forwarded_object(iobj);
+      iobj = mut;
+    }
     _mutate_references(state, g, iobj);
     iobj = heap_next_unscanned(g-&gt;next);
+    count++;
   }
   
   return ret;
@@ -342,6 +400,8 @@ int baker_gc_collect(STATE, baker_gc g, GPtrArray *roots) {
   struct method_cache *end, *ent;
   GPtrArray *rs;
   
+  saved_contexts = 0;
+  
   g-&gt;num_collection++;
   
   /* empty it out. */
@@ -435,6 +495,8 @@ int baker_gc_collect(STATE, baker_gc g, GPtrArray *roots) {
     }
   }
   
+  object_memory_shift_contexts(state, state-&gt;om);
+  
   baker_gc_swap(g);
   
   if(g-&gt;current-&gt;size != g-&gt;next-&gt;size) {
@@ -446,12 +508,13 @@ int baker_gc_collect(STATE, baker_gc g, GPtrArray *roots) {
     baker_gc_enlarge_next(g, g-&gt;current-&gt;size * 1.5);
   }
   
+  // printf(&quot;Saved %d contexts.\n&quot;, saved_contexts);
   g_ptr_array_free(rs, TRUE);
   return TRUE;
 }
 
 void baker_gc_clear_gc_flag(baker_gc g, int flag) {
-  int sz, osz;
+  int osz;
   char *end, *cur;
   OBJECT obj;
   
@@ -495,8 +558,12 @@ void baker_gc_find_lost_souls(STATE, baker_gc g) {
       }
     }
     bs = ((osz + HEADER_SIZE) * REFSIZE);
-    memset(cur, 0, bs);
+    fast_memfill32(cur, 0, HEADER_SIZE + osz);
+    // memset(cur, 0, bs);
+    
+#ifdef XDEBUG
     HEADER(cur)-&gt;object_id = g-&gt;num_collection;
+#endif
     cur += bs;
   }
 }</diff>
      <filename>shotgun/lib/baker.c</filename>
    </modified>
    <modified>
      <diff>@@ -44,12 +44,26 @@ void baker_gc_describe(baker_gc g);
 void baker_gc_find_lost_souls(STATE, baker_gc g);
 void baker_gc_collect_references(STATE, baker_gc g, OBJECT mark, GPtrArray *refs);
 inline int baker_gc_forwarded_p(OBJECT obj);
+void baker_gc_mutate_context(STATE, baker_gc g, OBJECT iobj, int shifted, int top);
+
 
-#define baker_gc_allocate(g, size) (heap_allocate((g)-&gt;current, size))
-#define baker_gc_allocate_spilled(g, size) (heap_allocate((g)-&gt;next, size))
 
 #define baker_gc_allocate_ultra(g, size) heap_allocate_dirty((g)-&gt;current, size)
 #define baker_gc_allocate_spilled_ultra(g, size) heap_allocate_dirty((g)-&gt;next, size)
 
+// #define MEM_DEBUG 1
+
+#ifdef MEM_DEBUG
+
+#define baker_gc_allocate(g, size) (heap_allocate((g)-&gt;current, size))
+#define baker_gc_allocate_spilled(g, size) (heap_allocate((g)-&gt;next, size))
+
+#else
+
+#define baker_gc_allocate(g, size) baker_gc_allocate_ultra(g, size);
+#define baker_gc_allocate_spilled(g, size) baker_gc_allocate_spilled_ultra(g, size);
+
+#endif
+
 #endif
 </diff>
      <filename>shotgun/lib/baker.h</filename>
    </modified>
    <modified>
      <diff>@@ -450,15 +450,23 @@ void cpu_bootstrap(STATE) {
   BC(module) = _module_basic_class(state, obj);
   class_set_superclass(cls, BC(module));
   BC(metaclass) = _metaclass_basic_class(state, cls);
+  
+  BC(tuple) = _tuple_basic_class(state, obj);
+  BC(hash) =  _hash_basic_class(state, obj);
+  BC(methtbl) = _methtbl_basic_class(state, BC(hash));
+  
   object_create_metaclass(state, obj, cls);
   object_create_metaclass(state, BC(module), object_metaclass(state, obj));
   object_create_metaclass(state, BC(class), object_metaclass(state, BC(module)));
   
-  BC(hash) = _hash_class(state, obj);
-  BC(methtbl) = _methtbl_class(state, BC(hash));
+  object_create_metaclass(state, BC(tuple), (OBJECT)0);
+  object_create_metaclass(state, BC(hash), (OBJECT)0);
+  object_create_metaclass(state, BC(methtbl), (OBJECT)0);
+  
   module_setup_fields(state, object_metaclass(state, obj));
   module_setup_fields(state, object_metaclass(state, BC(module)));
   module_setup_fields(state, object_metaclass(state, BC(class)));
+  module_setup_fields(state, object_metaclass(state, BC(tuple)));
   module_setup_fields(state, object_metaclass(state, BC(hash)));
   module_setup_fields(state, object_metaclass(state, BC(methtbl)));
   BC(symbol) = _symbol_class(state, obj);</diff>
      <filename>shotgun/lib/bootstrap.c</filename>
    </modified>
    <modified>
      <diff>@@ -10,21 +10,33 @@ OBJECT bytearray_new(STATE, int size) {
   int words;
   OBJECT obj;
   
-  assert(size &gt;= 0);
-  
   words = size / REFSIZE;
   if(size % REFSIZE != 0) {
     words += 1;
   }
   
-  assert(words &gt;= 0);
-  
   obj = bytearray_allocate_with_extra(state, words);
   object_make_byte_storage(state, obj);
+  fast_memfill32(BYTES_OF(obj), 0, words);
   object_initialize_bytes(state, obj);
   return obj;
 }
 
+OBJECT bytearray_new_dirty(STATE, int size) {
+  int words;
+  OBJECT obj;
+    
+  words = size / REFSIZE;
+  if(size % REFSIZE != 0) {
+    words += 1;
+  }
+    
+  obj = object_memory_new_dirty_object(state-&gt;om, BASIC_CLASS(bytearray), words);
+  object_make_byte_storage(state, obj);
+  
+  return obj;
+}
+
 char *bytearray_as_string(STATE, OBJECT self) {
   char *str;
   char *out;</diff>
      <filename>shotgun/lib/bytearray.c</filename>
    </modified>
    <modified>
      <diff>@@ -71,7 +71,6 @@ void cpu_setup_top_scope(STATE, cpu c) {
 
 void cpu_initialize_context(STATE, cpu c) {
   c-&gt;active_context = Qnil;
-  c-&gt;top_context = c-&gt;active_context;
   c-&gt;home_context = c-&gt;active_context;
   c-&gt;enclosing_class = state-&gt;global-&gt;object;
   c-&gt;new_class_of = state-&gt;global-&gt;class;
@@ -114,13 +113,38 @@ void cpu_initialize_context(STATE, cpu c) {
   cpu_event_setup_children(state, c);
 }
 
+#define ON_STACK(obj) (HEADER(obj)-&gt;klass == Qnil)
+
 void cpu_add_roots(STATE, cpu c, GPtrArray *roots) {
   int i, len;
   gpointer t;
   #define ar(obj) if(REFERENCE_P(obj)) { \
     g_ptr_array_add(roots, (gpointer)obj); \
   }
-  ar(c-&gt;sender);
+  
+  if(!ON_STACK(c-&gt;active_context)) {
+    ar(c-&gt;active_context);
+    state-&gt;ac_on_stack = 0;
+  } else {
+    state-&gt;ac_on_stack = 1;
+  }
+  
+  if(!ON_STACK(c-&gt;home_context)) {
+    ar(c-&gt;home_context);
+    state-&gt;home_on_stack = 0;
+  } else {
+    state-&gt;home_on_stack = 1;
+  }
+  
+  if(REFERENCE_P(c-&gt;sender)) {
+    if(!ON_STACK(c-&gt;sender)) {
+      ar(c-&gt;sender);
+      state-&gt;sender_on_stack = 0;
+    } else {
+      state-&gt;sender_on_stack = 1;
+    }
+  }
+  
   ar(c-&gt;self);
   ar(c-&gt;exception);
   ar(c-&gt;enclosing_class);
@@ -128,12 +152,9 @@ void cpu_add_roots(STATE, cpu c, GPtrArray *roots) {
   ar(c-&gt;locals);
   ar(c-&gt;block);
   ar(c-&gt;method);
-  ar(c-&gt;active_context);
-  ar(c-&gt;home_context);
   ar(c-&gt;main);
   ar(c-&gt;literals);
   ar(c-&gt;exceptions);
-  ar(c-&gt;top_context);
   ar(c-&gt;method_module);
   ar(c-&gt;current_thread);
   ar(c-&gt;main_thread);
@@ -162,7 +183,35 @@ void cpu_update_roots(STATE, cpu c, GPtrArray *roots, int start) {
     tmp = g_ptr_array_index(roots, start++); \
     obj = (OBJECT)tmp; \
   }
-  ar(c-&gt;sender);
+  
+  if(state-&gt;ac_on_stack) {
+    /* if active_context is on the stack, it's the last object. */
+    /* if context_top is nil, then we didn't need to compact, they're
+       still pointed at the right point. */
+    
+    if(state-&gt;om-&gt;context_top != Qnil) {
+      c-&gt;active_context = state-&gt;om-&gt;context_top;
+    }
+  } else {
+    ar(c-&gt;active_context);
+  }
+  
+  if(state-&gt;home_on_stack) {
+    /* If it's on the stack, it's the same as active */
+    c-&gt;home_context = c-&gt;active_context;
+  } else {
+    ar(c-&gt;home_context);
+  }
+  
+  if(REFERENCE_P(c-&gt;sender)) {
+    if(state-&gt;sender_on_stack) {
+      /* If it's on the stack, it's the active_context's sender */
+      c-&gt;sender = FASTCTX(c-&gt;active_context)-&gt;sender;
+    } else {
+      ar(c-&gt;sender);
+    }
+  }
+  
   ar(c-&gt;self);
   ar(c-&gt;exception);
   ar(c-&gt;enclosing_class);
@@ -170,12 +219,9 @@ void cpu_update_roots(STATE, cpu c, GPtrArray *roots, int start) {
   ar(c-&gt;locals);
   ar(c-&gt;block);
   ar(c-&gt;method);
-  ar(c-&gt;active_context);
-  ar(c-&gt;home_context);
   ar(c-&gt;main);
   ar(c-&gt;literals);
   ar(c-&gt;exceptions);
-  ar(c-&gt;top_context);
   ar(c-&gt;method_module);
   ar(c-&gt;current_thread);
   ar(c-&gt;main_thread);</diff>
      <filename>shotgun/lib/cpu.c</filename>
    </modified>
    <modified>
      <diff>@@ -15,7 +15,7 @@
 #define USE_INTCODE 1
 
 /* Enable direct threading */
-#define DIRECT_THREADED 1
+#define DIRECT_THREADED 0
 
 #if USE_INTCODE
 #define IP_TYPE uint32_t
@@ -25,6 +25,9 @@
 #define BS_JUMP 5
 #endif
 
+/* This must be aligned on word boundries so fast_memcpy32 can
+   be used on it. */
+
 #define CPU_REGISTERS OBJECT sender; \
   unsigned long int ip; \
   unsigned long int sp; \
@@ -49,10 +52,6 @@ struct fast_context {
 
 #define InitialStackSize 4096
 
-#define FASTCTX_FIELDS 24
-#define FASTCTX_NORMAL 0
-#define FASTCTX_NMC    1
-
 #define TASK_NO_STACK 1
 #define TASK_FLAG_P(task, flag) ((task-&gt;flags &amp; flag) == flag)
 #define TASK_SET_FLAG(task, flag) (task-&gt;flags |= flag)
@@ -68,7 +67,6 @@ struct fast_context {
   OBJECT enclosing_class; \
   OBJECT new_class_of; \
   OBJECT exceptions; \
-  OBJECT top_context; \
   OBJECT active_context, home_context, main; \
   GPtrArray *paths; \
   unsigned int depth; \</diff>
      <filename>shotgun/lib/cpu.h</filename>
    </modified>
    <modified>
      <diff>@@ -435,18 +435,16 @@ static inline OBJECT cpu_create_context(STATE, cpu c, OBJECT recv, OBJECT mo,
   num_lcls = FIXNUM_TO_INT(cmethod_get_locals(mo));
   
   cpu_flush_sp(c);
+    
+  ctx = object_memory_new_context(state-&gt;om);
+  if(ctx &gt;= state-&gt;om-&gt;context_last) {
+    state-&gt;om-&gt;collect_now |= OMCollectYoung;
+  }
   
-#if CTX_USE_FAST
-
+  HEADER(ctx)-&gt;klass = Qnil;
+  HEADER(ctx)-&gt;fields = FASTCTX_FIELDS;
+  HEADER(ctx)-&gt;object_id = 47;
   /*
-  ctx = c-&gt;context_cache;
-  if(!ctx) {
-    ctx = object_memory_new_object(state-&gt;om, state-&gt;global-&gt;fastctx, FASTCTX_FIELDS);
-  } else {
-    c-&gt;context_cache = HEADER(ctx)-&gt;klass;
-    HEADER(ctx)-&gt;klass = state-&gt;global-&gt;fastctx;
-  }
-  */
   
   ctx = _om_new_ultra(state-&gt;om, state-&gt;global-&gt;fastctx, (HEADER_SIZE + FASTCTX_FIELDS) * REFSIZE);
   SET_NUM_FIELDS(ctx, FASTCTX_FIELDS);
@@ -455,10 +453,12 @@ static inline OBJECT cpu_create_context(STATE, cpu c, OBJECT recv, OBJECT mo,
   FLAG_SET(ctx, StoresBytesFlag);
     
   CHECK_PTR(mo);
+  */
   
   fc = FASTCTX(ctx);
   // memset(fc, 0, sizeof(struct fast_context));
   fc-&gt;sender = sender;
+  xassert(om_valid_sender_p(state-&gt;om, ctx, sender));
   fc-&gt;ip = 0;
   fc-&gt;sp = c-&gt;sp;
   /* fp_ptr points to the location on the stack as the context
@@ -474,6 +474,7 @@ static inline OBJECT cpu_create_context(STATE, cpu c, OBJECT recv, OBJECT mo,
   fc-&gt;self = recv;
   if(num_lcls &gt; 0) {
     fc-&gt;locals = tuple_new(state, num_lcls + 2);
+    GC_MAKE_FOREVER_YOUNG(fc-&gt;locals);
   } else {
     fc-&gt;locals = Qnil;
   }
@@ -481,19 +482,6 @@ static inline OBJECT cpu_create_context(STATE, cpu c, OBJECT recv, OBJECT mo,
   fc-&gt;name = name;
   fc-&gt;method_module = mod;
   fc-&gt;type = FASTCTX_NORMAL;
-    
-#else
-
-  ctx = methctx_s_from_method(state, mo, sender, mod);
-  methctx_set_receiver(ctx, recv);
-  methctx_set_name(ctx, name);
-  methctx_set_sp(ctx, I2N(c-&gt;sp));
-  methctx_set_method(ctx, mo);
-  methctx_set_block(ctx, block);
-  methctx_set_argcount(ctx, I2N(args));
-#endif
-
-  GC_MAKE_FOREVER_YOUNG(ctx);
 
   return ctx;
 }
@@ -569,7 +557,7 @@ inline void cpu_save_registers(STATE, cpu c, int offset) {
   if(!RTEST(c-&gt;active_context)) return;
   cpu_flush_ip(c);
   cpu_flush_sp(c);
-  if(methctx_is_fast_p(state, c-&gt;active_context)) {
+  if(HEADER(c-&gt;active_context)-&gt;klass == Qnil || methctx_is_fast_p(state, c-&gt;active_context)) {
     struct fast_context *fc;
     fc = (struct fast_context*)BYTES_OF(c-&gt;active_context);
     fc-&gt;sp = c-&gt;sp - offset;
@@ -584,99 +572,38 @@ inline void cpu_save_registers(STATE, cpu c, int offset) {
 void nmc_activate(STATE, cpu c, OBJECT nmc, int reraise);
 
 inline void cpu_restore_context_with_home(STATE, cpu c, OBJECT ctx, OBJECT home, int ret, int is_block) {
-  int ac;
+  struct fast_context *fc;
   
-  ac = c-&gt;argcount;
   c-&gt;depth--;
   
   /* Home is actually the main context here because it's the method
      context that holds all the data. So if it's a fast, we restore
      it's data, then if ctx != home, we restore a little more */
   
-  if(methctx_is_fast_p(state, home)) {
-    struct fast_context *fc;
-    fc = (struct fast_context*)BYTES_OF(home);
-    CHECK_PTR(fc-&gt;self);
-    CHECK_PTR(fc-&gt;method);
-    memcpy((void*)c, (void*)fc, sizeof(struct fast_context));
-    // printf(&quot;Restoring fast context %p\n&quot;, home);
-    /* Only happens if we're restoring a block. */
-    if(ctx != home) {
-      // assert(!ISA(ctx, state-&gt;global-&gt;fastctx));
-      c-&gt;sp = FIXNUM_TO_INT(methctx_get_sp(ctx));
-      c-&gt;ip = FIXNUM_TO_INT(methctx_get_ip(ctx));
-            
-      c-&gt;sender = methctx_get_sender(ctx);
-      /* FIXME: seems like we should set c-&gt;block too.. but that
-         seems to break things.. */
-    }
-    
-    /*
-    
-    sp is now adjusted when it's saved, so we don't have to do this now.
-    
-
-    if(ret &amp;&amp; ac &gt; 0) {
-      if (is_block) {
-        --c-&gt;sp;
-      } else {
-        c-&gt;sp -= ac;
-      }
-    }
-    */    
-    /* Ok, reason we'd be restoring a native context:
-       1) the native context used rb_funcall and we need to return
-          it the result of the call.
-    */
-    if(fc-&gt;type == FASTCTX_NMC) {
-      nmc_activate(state, c, home, FALSE);
-      /* We return because nmc_activate will setup the cpu to do whatever
-         it needs to next. */
-      return;
-    }
-    
-  } else {
-    abort();
-    /* This is all old, dead code. It's for support old, slow
-       method contexts. */
-    /*
+  fc = (struct fast_context*)BYTES_OF(home);
+  CHECK_PTR(fc-&gt;self);
+  CHECK_PTR(fc-&gt;method);
+  fast_memcpy32((void*)c, (void*)fc, sizeof(struct fast_context) &gt;&gt; 2);
+  /* Only happens if we're restoring a block. */
+  if(ctx != home) {
+    // assert(!ISA(ctx, state-&gt;global-&gt;fastctx));
     c-&gt;sp = FIXNUM_TO_INT(methctx_get_sp(ctx));
     c-&gt;ip = FIXNUM_TO_INT(methctx_get_ip(ctx));
-    if(ret &amp;&amp; c-&gt;argcount &gt; 0) {
-      if (is_block) {
-        --c-&gt;sp;
-      } else {
-        c-&gt;sp -= c-&gt;argcount;
-      }
-    }
-  
-    OBJECT ba;
-  
-    ba = methctx_get_bytecodes(home);
-    if(!RTEST(ba)) {
-      c-&gt;data = NULL;
-      c-&gt;data_size = 0;
-    } else {
-      c-&gt;data = bytearray_byte_address(state, ba);    
-      c-&gt;data_size = bytearray_bytes(state, ba);
-    }
-  
-    c-&gt;raiseable = RTEST(methctx_get_raiseable(home));
+          
     c-&gt;sender = methctx_get_sender(ctx);
-    c-&gt;self = methctx_get_receiver(home);
-    c-&gt;locals = methctx_get_locals(home);
-    c-&gt;block = methctx_get_block(home);
-    c-&gt;method = methctx_get_method(home);
-    c-&gt;literals = methctx_get_literals(home);
-    c-&gt;argcount = FIXNUM_TO_INT(methctx_get_argcount(home));
-    c-&gt;method_module = methctx_get_module(home);
-  
-    if(RTEST(c-&gt;method)) {
-      c-&gt;exceptions = cmethod_get_exceptions(c-&gt;method);
-    } else {
-      c-&gt;exceptions = Qnil;
-    }
-    */
+    /* FIXME: seems like we should set c-&gt;block too.. but that
+       seems to break things.. */
+  }
+  
+  /* Ok, reason we'd be restoring a native context:
+     1) the native context used rb_funcall and we need to return
+        it the result of the call.
+  */
+  if(fc-&gt;type == FASTCTX_NMC) {
+    nmc_activate(state, c, home, FALSE);
+    /* We return because nmc_activate will setup the cpu to do whatever
+       it needs to next. */
+    return;
   }
   
   cpu_cache_ip(c);
@@ -722,6 +649,9 @@ inline int cpu_return_to_sender(STATE, cpu c, int consider_block) {
     }    
   } else {
     
+    /* Implements a block causing the the context it was created in
+       to return (IE, a non local return) */
+    
     if(consider_block &amp;&amp; is_block) {
       home = blokctx_home(state, c-&gt;active_context);
       if(methctx_is_fast_p(state, home)) {
@@ -739,21 +669,23 @@ inline int cpu_return_to_sender(STATE, cpu c, int consider_block) {
       home = sender;
     }
     
-    /* Cache the context if we can. */
-#if CTX_USE_FAST &amp;&amp; CTX_CACHE_ENABLED
-    if(!is_block &amp;&amp; !methctx_s_was_referenced_p(state, c-&gt;active_context)) {
-      HEADER(c-&gt;active_context)-&gt;klass = 0;
-      if(!c-&gt;context_cache) {
-        c-&gt;context_cache = c-&gt;active_context;
-      } else {
-        HEADER(c-&gt;context_cache)-&gt;klass = c-&gt;active_context;
-      }
+    if(!is_block) {
+      /* Break the chain. Lets us detect invalid non-local returns, as well
+         is much nicer on the GC. */
+      FASTCTX(c-&gt;active_context)-&gt;sender = Qnil;
+      object_memory_retire_context(state-&gt;om, c-&gt;active_context);
     }
-#endif
-
+    
     if(EXCESSIVE_TRACING) {
-      printf(&quot;Returning to %s.\n&quot;, _inspect(sender));
+      if(HEADER(sender)-&gt;klass == Qnil) {
+        printf(&quot;Returning to a stack context.\n&quot;);
+      } else {
+        printf(&quot;Returning to %s.\n&quot;, _inspect(sender));
+      }
     }
+    xassert(om_valid_context_p(state, sender));
+    xassert(om_valid_context_p(state, home));
+    
     cpu_restore_context_with_home(state, c, sender, home, TRUE, is_block);
   }
   
@@ -908,7 +840,7 @@ static inline void cpu_unified_send(STATE, cpu c, OBJECT recv, int idx, int args
 static inline void cpu_unified_send_super(STATE, cpu c, OBJECT recv, int idx, int args, OBJECT block) {
   OBJECT sym, mo, klass, mod;
   int missing;
-  assert(RTEST(c-&gt;literals));
+  xassert(RTEST(c-&gt;literals));
   sym = tuple_at(state, c-&gt;literals, idx);
     
   missing = 0;</diff>
      <filename>shotgun/lib/cpu_instructions.c</filename>
    </modified>
    <modified>
      <diff>@@ -70,6 +70,10 @@ void cpu_task_select(STATE, cpu c, OBJECT nw) {
   // printf(&quot;Switching to task %s (%p, %d)\n&quot;, _inspect(nw), c-&gt;sp_ptr, c-&gt;sp);
   cur = c-&gt;current_task;
   
+  /* Invalidates the stack, so they don't get confused being used across boundries */
+  if(REFERENCE_P(c-&gt;active_context)) methctx_reference(state, c-&gt;active_context);
+  if(REFERENCE_P(c-&gt;home_context))   methctx_reference(state, c-&gt;home_context);
+  
   ct = (struct cpu_task*)CPU_TASKS_LOCATION(c);
   cur_task = (struct cpu_task*)BYTES_OF(cur);
   new_task = (struct cpu_task*)BYTES_OF(nw);</diff>
      <filename>shotgun/lib/cpu_task.c</filename>
    </modified>
    <modified>
      <diff>@@ -40,6 +40,12 @@ int heap_reset(rheap h) {
   return TRUE;
 }
 
+int heap_allocated_p(rheap h) {
+  return h-&gt;address &gt; 0;
+}
+
+#ifndef FAST_HEAP
+
 int heap_contains_p(rheap h, address addr) {
 
   if(addr &lt; h-&gt;address) return FALSE;
@@ -47,12 +53,6 @@ int heap_contains_p(rheap h, address addr) {
   return TRUE;
 }
 
-int heap_allocated_p(rheap h) {
-  return h-&gt;address &gt; 0;
-}
-
-#ifndef FAST_HEAP
-
 address heap_allocate(rheap h, int size) {
   address addr;
   /* maybe raise exception here? */</diff>
      <filename>shotgun/lib/heap.c</filename>
    </modified>
    <modified>
      <diff>@@ -18,7 +18,6 @@ int heap_deallocate(rheap h);
 int heap_allocate_memory(rheap h);
 int heap_allocate_extended(rheap h);
 int heap_reset(rheap h);
-int heap_contains_p(rheap h, address addr);
 int heap_enough_fields_p(rheap h, int fields);
 int heap_allocated_p(rheap h);
 int heap_using_extended_p(rheap h);
@@ -46,11 +45,23 @@ static inline address heap_allocate(rheap h, int size) {
 #define heap_allocate_dirty(h, size) ({ \
   address _a; _a = (address)h-&gt;current; h-&gt;current += size; _a; })
 
+#define heap_putback(h, size) (h-&gt;current -= size)
+
 static inline int heap_enough_space_p(rheap h, int size) {
   if(h-&gt;current + size &gt; h-&gt;last + 1) return FALSE;
   return TRUE;
 }
 
+static inline int heap_contains_p(rheap h, address addr) {
+
+  if(addr &lt; h-&gt;address) return FALSE;
+  if(addr &gt;= h-&gt;address + h-&gt;size) return FALSE;
+  return TRUE;
+}
+
+
+// #define heap_contains_p(h, addr) ((addr &gt; h-&gt;address) &amp;&amp; (addr &lt; h-&gt;last))
+
 // #define heap_enough_space_p(h, size) ((h)-&gt;current + size &lt;= (h)-&gt;last)
 
 // #define heap_allocate(h, size) ({ address addr = (address)((h)-&gt;current); (h)-&gt;current += size; addr; })</diff>
      <filename>shotgun/lib/heap.h</filename>
    </modified>
    <modified>
      <diff>@@ -883,6 +883,7 @@ CODE
     t1 = c-&gt;active_context;
     c-&gt;active_context = c-&gt;sender;
     if(cpu_return_to_sender(state, c, TRUE)) {
+      methctx_reference(state, t1);
       stack_push(t1);
     }
     CODE
@@ -1035,19 +1036,13 @@ CODE
     } else {
       t3 = t4;
     }
-    
-    // GUARD(t3 == Qnil) would like to use this...
-    if(t3 == Qnil) {
-      // can this be put somewhere else?
-      printf(&quot;Create block failed, %s!!\\n&quot;, _inspect(t4));
-      abort();
-    } else {
-      cpu_flush_sp(c);
-      cpu_flush_ip(c);
-      j = c-&gt;ip + BS_JUMP;
-      t2 = blokenv_s_under_context(state, t3, t4, j, t1, t2, _int);
-      stack_push(t2);
-    }
+    methctx_reference(state, t4);
+    methctx_reference(state, t3);
+    cpu_flush_sp(c);
+    cpu_flush_ip(c);
+    j = c-&gt;ip + BS_JUMP;
+    t2 = blokenv_s_under_context(state, t3, t4, j, t1, t2, _int);
+    stack_push(t2);
     CODE
   end
   
@@ -1079,6 +1074,7 @@ CODE
     &lt;&lt;-CODE
     cpu_flush_sp(c);
     cpu_flush_ip(c);
+    methctx_reference(state, c-&gt;active_context);
     if(c-&gt;debug_channel != Qnil) {
       cpu_channel_send(state, c, c-&gt;debug_channel, c-&gt;active_context);
       /* This is so when this task is reactivated, the sent value wont be placed</diff>
      <filename>shotgun/lib/instructions.rb</filename>
    </modified>
    <modified>
      <diff>@@ -33,12 +33,15 @@
 
 #define FREE_FLAG 0xff
 
-#define TRACK_REFERENCE 1
+#define TRACK_REFERENCE 0
 #define TRACK_DONT_FREE 0
 
 #undef MS_COLLECTION_FREQUENCY
 #define MS_COLLECTION_FREQUENCY 5000
 
+// 2 Megs
+#define MS_COLLECTION_BYTES 10485760
+
 
 mark_sweep_gc mark_sweep_new() {
   mark_sweep_gc ms;
@@ -49,7 +52,8 @@ mark_sweep_gc mark_sweep_new() {
   ms-&gt;chunks = ms-&gt;current;
   ms-&gt;enlarged = 0;
   ms-&gt;seen_weak_refs = NULL;
-  ms-&gt;next_collection = 0;
+  ms-&gt;next_collection_objects = MS_COLLECTION_FREQUENCY;
+  ms-&gt;next_collection_bytes =   MS_COLLECTION_BYTES;
 #if TRACK_REFERENCE
   if(getenv(&quot;MSTRACK&quot;)) {
     ms-&gt;track = (OBJECT)atoi(getenv(&quot;MSTRACK&quot;));
@@ -93,6 +97,7 @@ OBJECT mark_sweep_allocate(mark_sweep_gc ms, int obj_fields) {
   struct ms_entry *ent;
   ms_chunk *chk;
   OBJECT ro;
+  clock_t curt;
   
   bytes = sizeof(struct ms_header) + ((obj_fields + HEADER_SIZE) * REFSIZE);
   
@@ -111,12 +116,43 @@ OBJECT mark_sweep_allocate(mark_sweep_gc ms, int obj_fields) {
   ent-&gt;marked = 0;
   
   ms-&gt;allocated_bytes += bytes;
-  ms-&gt;next_collection++;
+  ms-&gt;last_allocated += bytes;
+  ms-&gt;allocated_objects++;
+  // ms-&gt;next_collection_objects--;
+  ms-&gt;next_collection_bytes -= bytes;
   
-  if(ms-&gt;next_collection &gt;= MS_COLLECTION_FREQUENCY) {
-    ms-&gt;next_collection = 0;
-    ms-&gt;enlarged = 1;
-    // printf(&quot;[GC M Collecting based on count (every %d objects)]\n&quot;, MS_COLLECTION_FREQUENCY);
+  if(obj_fields &gt; 10000) {
+    // printf(&quot;[GC M allocating large object %d]\n&quot;, obj_fields);
+  }
+  
+  if(!ms-&gt;enlarged) {
+    
+    if(ms-&gt;next_collection_objects &lt;= 0) {
+      // printf(&quot;[GC M Collecting based on objects]\n&quot;);
+      ms-&gt;enlarged = 1;
+      ms-&gt;next_collection_bytes = MS_COLLECTION_FREQUENCY;
+    } else if(ms-&gt;next_collection_bytes &lt;= 0) {
+      // printf(&quot;[GC M Collecting based on bytes: %d]\n&quot;, ms-&gt;allocated_bytes);
+      ms-&gt;enlarged = 1;
+    }
+    
+  
+  /*  
+  
+    if(ms-&gt;last_allocated_bytes) {
+      if(ms-&gt;last_allocated_bytes * 2 &lt;= ms-&gt;allocated_bytes) {
+        printf(&quot;[GC M Collecting based on heap size (%d, %d)]\n&quot;, ms-&gt;last_allocated_bytes, ms-&gt;allocated_bytes);
+        ms-&gt;enlarged = 1;
+      }
+    } else if(ms-&gt;last_allocated &gt;= ms-&gt;next_collection) {
+      curt = clock();
+      ms-&gt;last_allocated = 0;
+      ms-&gt;enlarged = 1;
+      printf(&quot;[GC M Collecting based on bytes (every %d bytes, %d total)]\n&quot;, MS_COLLECTION_BYTES, ms-&gt;allocated_bytes);
+      printf(&quot;[GC M last_clock=%d, cur=%d]\n&quot;, ms-&gt;last_clock, curt);
+      ms-&gt;last_clock = curt;
+    }
+    */
   }
   
   oh-&gt;entry = ent;
@@ -162,13 +198,14 @@ void mark_sweep_free_entry(STATE, mark_sweep_gc ms, struct ms_entry *ent) {
   memset(obj, 0, SIZE_IN_BYTES(obj));
   *((int*)(obj)) = 0xbaddecaf;
 #else
-  memset(obj, 55, SIZE_IN_BYTES(obj));
+  // memset(obj, 55, SIZE_IN_BYTES(obj));
   free(ent-&gt;object);
 #endif
   
   ms-&gt;last_freed++;
   
   ms-&gt;allocated_bytes -= ent-&gt;bytes;
+  ms-&gt;allocated_objects--;
   
   ent-&gt;bytes = 0;
   ent-&gt;marked = 0;
@@ -260,6 +297,8 @@ OBJECT mark_sweep_mark_object(STATE, mark_sweep_gc ms, OBJECT iobj) {
     if(methctx_is_fast_p(state, iobj)) {
       struct fast_context *fc = FASTCTX(iobj);
       fc_mutate(sender);
+      if(!NIL_P(fc-&gt;sender)) assert(blokctx_s_block_context_p(state, fc-&gt;sender) || methctx_is_fast_p(state, fc-&gt;sender));
+      
       fc_mutate(block);
       fc_mutate(method);
       fc_mutate(literals);
@@ -278,7 +317,6 @@ OBJECT mark_sweep_mark_object(STATE, mark_sweep_gc ms, OBJECT iobj) {
       fc_mutate(exception);
       fc_mutate(new_class_of);
       fc_mutate(enclosing_class);
-      fc_mutate(top_context);
       fc_mutate(exceptions);
       fc_mutate(active_context);
       fc_mutate(home_context);
@@ -317,6 +355,39 @@ OBJECT mark_sweep_mark_object(STATE, mark_sweep_gc ms, OBJECT iobj) {
   return iobj;
 }
 
+void mark_sweep_mark_context(STATE, mark_sweep_gc ms, OBJECT iobj) {
+  #define fc_mutate(field) if(fc-&gt;field &amp;&amp; REFERENCE_P(fc-&gt;field)) mark_sweep_mark_object(state, ms, fc-&gt;field)
+  if(MARKED_P(iobj)) return;
+  MARK_OBJ(iobj);
+  
+  struct fast_context *fc = FASTCTX(iobj);
+
+  if(REFERENCE_P(fc-&gt;sender) &amp;&amp; om_in_heap(state-&gt;om, fc-&gt;sender)) {
+    fc_mutate(sender);
+  }
+
+  fc_mutate(method);
+  fc_mutate(block);
+  fc_mutate(literals);
+  fc_mutate(self);
+  fc_mutate(locals);
+  fc_mutate(method_module);
+  
+  fc_mutate(locals);
+
+  /* We cache the bytecode in a char*, so adjust it. */
+  OBJECT ba;
+  ba = cmethod_get_bytecodes(fc-&gt;method);
+  fc-&gt;data = BYTEARRAY_ADDRESS(ba);
+  fc-&gt;data_size = BYTEARRAY_SIZE(ba);
+#undef fc_mutate
+}
+
+void mark_sweep_clear_mark(STATE, OBJECT iobj) {
+  UNMARK_OBJ(iobj);
+  assert(!MARKED_P(iobj));
+}
+
 void mark_sweep_mark_phase(STATE, mark_sweep_gc ms, GPtrArray *roots) {
   int i, sz;
   OBJECT root, tmp;
@@ -416,7 +487,8 @@ void mark_sweep_mark_phase(STATE, mark_sweep_gc ms, GPtrArray *roots) {
   cpu_sampler_collect(state,
                       (cpu_sampler_collect_cb) mark_sweep_mark_object,
                       ms);
-  
+                      
+  object_memory_mark_contexts(state, state-&gt;om);
 }
 
 void mark_sweep_sweep_phase(STATE, mark_sweep_gc ms) {
@@ -481,6 +553,9 @@ void mark_sweep_collect(STATE, mark_sweep_gc ms, GPtrArray *roots) {
   
   g_ptr_array_free(ms-&gt;seen_weak_refs, TRUE);
   ms-&gt;seen_weak_refs = NULL;
+  
+  // printf(&quot;[GC M compacted to %d bytes]\n&quot;, ms-&gt;allocated_bytes);
+  ms-&gt;next_collection_bytes = ms-&gt;allocated_bytes + MS_COLLECTION_BYTES;
 }
 
 /*</diff>
      <filename>shotgun/lib/marksweep.c</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,8 @@
 #ifndef __MARKSWEEP_H__
 #define __MARKSWEEP_H__
 
+#include &lt;time.h&gt;
+
 struct ms_header;
 
 struct ms_entry {
@@ -40,7 +42,12 @@ struct _mark_sweep_gc {
   int last_freed;
   int last_marked;
   unsigned int allocated_bytes;
-  int next_collection;
+  int next_collection_objects;
+  unsigned int last_allocated;
+  unsigned int allocated_objects;
+  int next_collection_bytes;
+  
+  clock_t last_clock;
   OBJECT track;
   
   struct ms_entry *free_list;
@@ -66,5 +73,7 @@ void mark_sweep_sweep_phase(STATE, mark_sweep_gc ms);
 void mark_sweep_collect(STATE, mark_sweep_gc ms, GPtrArray *roots);
 void mark_sweep_describe(mark_sweep_gc ms);
 void mark_sweep_collect_references(STATE, mark_sweep_gc ms, OBJECT mark, GPtrArray *refs);
+void mark_sweep_mark_context(STATE, mark_sweep_gc ms, OBJECT iobj);
+void mark_sweep_clear_mark(STATE, OBJECT iobj);
 
 #endif /* __MARKSWEEP_H__ */</diff>
      <filename>shotgun/lib/marksweep.h</filename>
    </modified>
    <modified>
      <diff>@@ -88,6 +88,8 @@ OBJECT blokenv_create_context(STATE, OBJECT self, OBJECT sender, int sp) {
   blokctx_set_sp(obj, I2N(sp));
   blokctx_set_env(obj, self);
   blokctx_set_locals(obj, tuple_new(state, blokenv_get_local_count(self)));
+
+  GC_MAKE_FOREVER_YOUNG(obj);
   return obj;
 }
 </diff>
      <filename>shotgun/lib/methctx.c</filename>
    </modified>
    <modified>
      <diff>@@ -20,25 +20,30 @@ static inline int methctx_s_was_referenced_p(STATE, OBJECT obj) {
   return FLAG_SET_P(obj, WasReferencedFlag);
 }
 
-static inline void methctx_reference(STATE, OBJECT self) {
-  OBJECT ctx;
+static inline void methctx_reference(STATE, OBJECT ctx) {  
+  /* If it has a class object setup, we've already adjusted it
+     and everything. Don't do it again. */
+  if(HEADER(ctx)-&gt;klass != Qnil) return;
   
-  ctx = self;
-  while(RTEST(ctx)) {
-    /* If it's already marked, so are it's senders. */
-    if(FLAG_SET_P(ctx, WasReferencedFlag)) return;
+  HEADER(ctx)-&gt;flags = 0;
+  HEADER(ctx)-&gt;flags2 = 0;
+  HEADER(ctx)-&gt;gc = 0;
+  HEADER(ctx)-&gt;object_id = 0;
+  GC_ZONE_SET(ctx, GC_YOUNG_OBJECTS);
+  
+  HEADER(ctx)-&gt;klass = state-&gt;global-&gt;fastctx;
+  SET_NUM_FIELDS(ctx, FASTCTX_FIELDS);
+  
+  FLAG_SET(ctx, CTXFastFlag);
+  FLAG_SET(ctx, StoresBytesFlag);
     
-    FLAG_SET(ctx, WasReferencedFlag);
-#if CTX_USE_FAST
-    ctx = FASTCTX(ctx)-&gt;sender;
-#else
-    ctx = methctx_get_sender(ctx);
-#endif
-  }
+  GC_MAKE_FOREVER_YOUNG(ctx);
+  
+  object_memory_context_referenced(state-&gt;om, ctx);
 }
 
 static inline int blokctx_s_block_context_p(STATE, OBJECT ctx) {
-  return FLAG_SET_P(ctx, IsBlockContextFlag);
+  return HEADER(ctx)-&gt;klass != Qnil &amp;&amp; FLAG_SET_P(ctx, IsBlockContextFlag);
 }
 
 #endif</diff>
      <filename>shotgun/lib/methctx.h</filename>
    </modified>
    <modified>
      <diff>@@ -5,8 +5,12 @@
 #include &quot;module.h&quot;
 
 void module_setup_fields(STATE, OBJECT module) {
-  module_set_constants(module, hash_new(state));
-  module_set_methods(module, methtbl_new(state));
+  if(NIL_P(module_get_constants(module))) {
+    module_set_constants(module, hash_new(state));
+  }
+  if(NIL_P(module_get_methods(module))) {
+    module_set_methods(module, methtbl_new(state));
+  }
 }
 
 void module_setup_name(STATE, OBJECT module, const char *name, OBJECT ns) {</diff>
      <filename>shotgun/lib/module.c</filename>
    </modified>
    <modified>
      <diff>@@ -149,46 +149,6 @@ void object_propgate_gc_info(STATE, OBJECT self, OBJECT dest) {
   }
 }
 
-int object_copy_fields_from(STATE, OBJECT self, OBJECT dest, int first, int count) {
-  int i, j;
-  
-  for(i = first, j = 0; j &lt; count; i++, j++) {
-    SET_FIELD(dest, j, NTH_FIELD(self, i));
-  }
-  
-  return TRUE;
-  
-/*
-  char *da;
-  void *start;
-  int sz;
-  
-  
-  
-  da = object_byte_start(state, dest);
-  sz = count * REFSIZE;
-  start = (void*)((first * REFSIZE) + object_byte_start(state, self));
-  
-  memcpy((void*)da, (const void *)start, (size_t)sz);
-  object_propgate_gc_info(state, self, dest);
-  return TRUE;
-*/
-}
-
-int object_copy_fields_shifted(STATE, OBJECT self, OBJECT dest, int dist) {
-  int count;
-  int i;
-
-  count = NUM_FIELDS(self);
-  
-  for(i = 0; i &lt; count; i++) {
-    SET_FIELD(dest, dist + i, NTH_FIELD(self, i));
-  }
-  
-  return TRUE;
-}
-
-
 int object_copy_bytes_into(STATE, OBJECT self, OBJECT dest, int count, int offset) {
   char *str, *start;
   </diff>
      <filename>shotgun/lib/object.c</filename>
    </modified>
    <modified>
      <diff>@@ -13,8 +13,6 @@ OBJECT object_set_ivar(STATE, OBJECT self, OBJECT sym, OBJECT val);
 OBJECT object_get_ivars(STATE, OBJECT self);
 OBJECT object_new(STATE);
 char *object_byte_start(STATE, OBJECT self);
-int object_copy_fields_from(STATE, OBJECT self, OBJECT dest, int first, int count);
-int object_copy_fields_shifted(STATE, OBJECT self, OBJECT dest, int dist);
 int object_copy_bytes_into(STATE, OBJECT self, OBJECT dest, int count, int offset);
 unsigned int object_hash_int(STATE, OBJECT self);
 int object_stores_bytes_p(STATE, OBJECT self);
@@ -46,4 +44,26 @@ static inline uint32_t object_get_id(STATE, OBJECT self) {
   }
 }
 
+static inline int object_copy_fields_shifted(STATE, OBJECT self, OBJECT dest, int dist) {
+  int count;
+  int i;
+  
+  count = NUM_FIELDS(self);
+
+  for(i = 0; i &lt; count; i++) {
+    SET_FIELD(dest, dist + i, NTH_FIELD(self, i));
+  }
+  return TRUE;
+}
+
+static inline int object_copy_fields_from(STATE, OBJECT self, OBJECT dest, int first, int count) {
+  int i, j;
+  
+  for(i = first, j = 0; j &lt; count; i++, j++) {
+    SET_FIELD(dest, j, NTH_FIELD(self, i));
+  }
+  return TRUE;  
+}
+
+
 #endif</diff>
      <filename>shotgun/lib/object.h</filename>
    </modified>
    <modified>
      <diff>@@ -23,20 +23,13 @@ static inline void object_memory_write_barrier(object_memory om, OBJECT target,
   tz = GC_ZONE(target);
   vz = GC_ZONE(val);
   
+  xassert(tz &gt; 0);
+  xassert(vz &gt; 0);
+  xassert(HEADER(val)-&gt;klass != Qnil);
+    
   /* if the target is in a higher numbered zone than val, then
      that means it needs to be in the remember set. */
   if(tz &lt; vz) {
-  
-  //if(mark_sweep_contains_p(om-&gt;ms, target) &amp;&amp; baker_gc_contains_spill_p(om-&gt;gc, val)) {
-    //assert(tz &lt; vz);
-    if(!FLAG_SET_ON_P(target, gc, REMEMBER_FLAG)) {
-      // printf(&quot;[Tracking %p in baker RS]\n&quot;, (void*)target);
-      g_ptr_array_add(om-&gt;gc-&gt;remember_set, (gpointer)target);
-      FLAG_SET_ON(target, gc, REMEMBER_FLAG);
-    }
+    object_memory_update_rs(om, target, val);
   } 
-  /* else {
-    assert(tz &gt;= vz);
-  }
-  */
 }</diff>
      <filename>shotgun/lib/object_memory-barrier.h</filename>
    </modified>
    <modified>
      <diff>@@ -1,5 +1,5 @@
 static inline OBJECT _om_inline_new_object(object_memory om, OBJECT cls, int fields) {
-  int size, i, f, loc;
+  int size, f, loc;
   OBJECT obj, flags;
   struct rubinius_object *header;
   
@@ -16,7 +16,7 @@ static inline OBJECT _om_inline_new_object(object_memory om, OBJECT cls, int fie
     size = (HEADER_SIZE + fields) * REFSIZE;
     if(!heap_enough_space_p(om-&gt;gc-&gt;current, size)) {
       obj = (OBJECT)baker_gc_allocate_spilled(om-&gt;gc, size);
-      assert(heap_enough_space_p(om-&gt;gc-&gt;next, size));
+      xassert(heap_enough_space_p(om-&gt;gc-&gt;next, size));
       // DEBUG(&quot;Ran out of space! spilled into %p\n&quot;, obj);
       om-&gt;collect_now |= OMCollectYoung;
       // baker_gc_enlarge_next(om-&gt;gc, om-&gt;gc-&gt;current-&gt;size * GC_SCALING_FACTOR);
@@ -27,7 +27,16 @@ static inline OBJECT _om_inline_new_object(object_memory om, OBJECT cls, int fie
     loc = GC_YOUNG_OBJECTS;
   }
   
+  // memset(obj, 0, HEADER_SIZE * REFSIZE);
+  
   header = (struct rubinius_object*)obj;
+  header-&gt;flags2 = 0;
+  header-&gt;gc = 0;
+  header-&gt;object_id = 0;
+  header-&gt;hash = 0;
+  
+  GC_ZONE_SET(obj, loc);
+  
   rbs_set_class(om, obj, cls);
   SET_NUM_FIELDS(obj, fields);
   if(cls &amp;&amp; REFERENCE_P(cls)) {
@@ -38,14 +47,15 @@ static inline OBJECT _om_inline_new_object(object_memory om, OBJECT cls, int fie
   } else {
     header-&gt;flags = 0;
   }
-  header-&gt;flags2 = 0;
-  for(i = 0; i &lt; fields; i++) {
-    rbs_set_field(om, obj, i, Qnil);
-  }
-  
-  GC_ZONE_SET(obj, loc);
+    
+  return obj;
+}
+
+static inline OBJECT _om_inline_new_object_init(object_memory om, OBJECT cls, int fields) {
+  OBJECT obj;
+  obj = _om_inline_new_object(om, cls, fields);
+  fast_memfill32((void*)BYTES_OF(obj), Qnil, fields);
   
-  header-&gt;object_id = 0;
   return obj;
 }
 
@@ -64,6 +74,8 @@ static inline OBJECT _om_new_ultra(object_memory om, OBJECT cls, int size) {
   HEADER(obj)-&gt;flags2 = 0;
   HEADER(obj)-&gt;gc = 0;
   HEADER(obj)-&gt;object_id = 0;
+  HEADER(obj)-&gt;hash = 0;
+  
   GC_ZONE_SET(obj, GC_YOUNG_OBJECTS);
   
   return obj; </diff>
      <filename>shotgun/lib/object_memory-inline.h</filename>
    </modified>
    <modified>
      <diff>@@ -8,17 +8,35 @@
 #include &quot;marksweep.h&quot;
 #include &quot;tuple.h&quot;
 #include &quot;flags.h&quot;
+#include &quot;methctx.h&quot;
 
 void *main_om;
 
 static int allocated_objects = 0;
 
+extern machine current_machine;
+
 void _describe(OBJECT ptr) {
   object_memory om;
   om = (object_memory)main_om;
   printf(&quot;Address:             %p (%lu)\n&quot;, (void*)ptr, (unsigned long int)ptr);
   printf(&quot;Contained in baker?: %d/%d\n&quot;, baker_gc_contains_p(om-&gt;gc, ptr), baker_gc_contains_spill_p(om-&gt;gc, ptr));
   printf(&quot;Contained in m/s?:   %d\n&quot;, GC_ZONE(ptr) == GC_MATURE_OBJECTS);
+  if(heap_contains_p(om-&gt;contexts, ptr)) {
+    printf(&quot;Is a context.\n&quot;);
+    if(ptr &lt; om-&gt;context_bottom) {
+      printf(&quot;  Referenced (below bottom)\n&quot;);
+    } else {
+      printf(&quot;  Normal on stack (not referenced)\n&quot;);
+    }
+  }
+  printf(&quot;stack_context_p: %d\n&quot;, om_stack_context_p(om, ptr));
+  printf(&quot;nil klass:       %d\n&quot;, HEADER(ptr)-&gt;klass == Qnil);
+  printf(&quot;context_refd_p:  %d\n&quot;, om_context_referenced_p(om, ptr));
+  printf(&quot;in_heap:         %d\n&quot;, om_in_heap(om, ptr));
+  printf(&quot;methctx_fast:    %d\n&quot;, methctx_is_fast_p(current_machine-&gt;s, ptr));
+  printf(&quot;blokctx_p:       %d\n&quot;, blokctx_s_block_context_p(current_machine-&gt;s, ptr));
+  printf(&quot;valid_ctx_p:     %d\n&quot;, om_valid_context_p(current_machine-&gt;s, ptr));
 }
 
 void _stats() {
@@ -74,6 +92,8 @@ int object_memory_actual_omsize() {
     return omsize;
 }
 
+#define CONTEXT_SIZE (1024 * 1024)
+
 object_memory object_memory_new() {
   object_memory om;
   om = (object_memory)calloc(1, sizeof(struct object_memory_struct));
@@ -84,6 +104,10 @@ object_memory object_memory_new() {
   
   om-&gt;ms = mark_sweep_new();
   
+  om-&gt;contexts = heap_new(CONTEXT_SIZE);
+  om-&gt;context_bottom = (OBJECT)(om-&gt;contexts-&gt;address);
+  om-&gt;context_last = (OBJECT)om-&gt;contexts-&gt;address + CONTEXT_SIZE - (CTX_SIZE * 3);
+  
   main_om = (void*)om;
   // Start the values up a bit higher so they don't collide
   // with the hashs of symbols right off the bat.
@@ -93,6 +117,139 @@ object_memory object_memory_new() {
   return om;
 }
 
+void object_memory_formalize_contexts(STATE, object_memory om) {
+  OBJECT ctx;
+  
+  EACH_REFD_CTX(om, ctx) {
+    methctx_reference(state, ctx);
+  } DONE_EACH_REFD_CTX(ctx);
+  
+  /*
+  char *addr;
+  addr = (char*)(om-&gt;contexts-&gt;address);
+  
+  while(addr &lt; (char*)om-&gt;context_bottom) {
+    ctx = (OBJECT)addr;
+    methctx_reference(state, ctx);
+    addr += CTX_SIZE;
+  }
+  */
+}
+
+void object_memory_shift_contexts(STATE, object_memory om) {
+  OBJECT ctx, new_ctx;
+  int inc = 0;
+  // char *addr, *cur;
+  struct fast_context *fc;
+  
+  // addr = (char*)(om-&gt;context_bottom);
+  // cur = (char*)(om-&gt;contexts-&gt;address);
+  
+  /* If the context_bottom is the true bottom, we haven't promoted
+     anything and everything can stay where it is. */
+  if(om_no_referenced_ctxs_p(om)) {
+    // printf(&quot;Nothing to shift!\n&quot;);
+    om-&gt;context_top = Qnil;
+    
+    /* Fixup the refs that are in the context stack */
+    EACH_STACK_CTX(om, ctx) {
+      baker_gc_mutate_context(state, om-&gt;gc, ctx, FALSE, inc == 0);
+      inc++;
+    } DONE_EACH_STACK_CTX(ctx); 
+    /*
+    while(addr &lt; (char*)om-&gt;contexts-&gt;current) {
+      ctx = (OBJECT)addr;
+      xassert(HEADER(ctx)-&gt;klass == Qnil);
+      addr += CTX_SIZE;
+    } 
+    */   
+  } else {
+    
+    new_ctx = (OBJECT)(om-&gt;contexts-&gt;address);
+    
+    EACH_STACK_CTX(om, ctx) {
+      /* The top context is a little special. Either it's sender
+         is nil or in the heap. Let mutate context know this is the case */
+      if(inc == 0) {
+        baker_gc_mutate_context(state, om-&gt;gc, ctx, TRUE, TRUE);
+        memcpy((void*)new_ctx, (void*)ctx, CTX_SIZE);
+        HEADER(ctx)-&gt;klass = new_ctx;
+      } else {
+        memcpy((void*)new_ctx, (void*)ctx, CTX_SIZE);
+        HEADER(ctx)-&gt;klass = new_ctx;
+        baker_gc_mutate_context(state, om-&gt;gc, new_ctx, TRUE, FALSE);        
+      }
+      new_ctx += CTX_SIZE;
+      inc++;
+    } DONE_EACH_STACK_CTX(ctx);
+    
+    om-&gt;contexts-&gt;current = (address)new_ctx;
+    om-&gt;context_top = new_ctx - CTX_SIZE;
+    
+    /*
+    
+    while(addr &lt; (char*)om-&gt;contexts-&gt;current) {
+      ctx = (OBJECT)cur;
+        
+      memcpy(cur, addr, CTX_SIZE);
+      // printf(&quot;Shifted context %p to %p\n&quot;, addr, cur);
+    
+      HEADER(addr)-&gt;klass = ctx;
+    
+      xassert(HEADER(ctx)-&gt;klass == Qnil);
+      baker_gc_mutate_context(state, om-&gt;gc, ctx, TRUE);
+    
+      cur += CTX_SIZE;
+      addr += CTX_SIZE;
+    }
+    
+     Reset current to be the moved top 
+    om-&gt;contexts-&gt;current = (address)(cur);
+    */
+  }
+  
+  om-&gt;context_bottom = (OBJECT)(om-&gt;contexts-&gt;address);
+  
+}
+
+void object_memory_mark_contexts(STATE, object_memory om) {
+  OBJECT ctx;
+  
+  EACH_CTX(om, ctx) {
+    mark_sweep_mark_context(state, om-&gt;ms, ctx);    
+  } DONE_EACH_CTX(ctx);
+  
+  /*
+  
+  OBJECT ctx, lst;
+  char *addr, *cur;
+  struct fast_context *fc;
+  
+  addr = (char*)(om-&gt;contexts-&gt;address);
+  
+  while(addr &lt; (char*)om-&gt;contexts-&gt;current) {
+    ctx = (OBJECT)addr;
+    addr += CTX_SIZE;
+  }
+  */ 
+}
+
+void object_memory_clear_marks(STATE, object_memory om) {
+  OBJECT ctx, lst;
+  char *addr, *cur;
+  struct fast_context *fc;
+  
+  addr = (char*)(om-&gt;contexts-&gt;address);
+  
+  /* Fixup the refs that are in the context stack */
+  while(addr &lt; (char*)om-&gt;contexts-&gt;current) {
+    ctx = (OBJECT)addr;
+    mark_sweep_clear_mark(state, ctx);
+    addr += CTX_SIZE;
+  } 
+}
+
+
 int object_memory_delete(object_memory om) {
   baker_gc_destroy(om-&gt;gc);
   return TRUE;
@@ -136,6 +293,7 @@ void object_memory_major_collect(STATE, object_memory om, GPtrArray *roots) {
   allocated_objects = 0;
   mark_sweep_collect(state, om-&gt;ms, roots);
   baker_gc_clear_gc_flag(om-&gt;gc, MS_MARK);
+  object_memory_clear_marks(state, om);
 }
 
 OBJECT object_memory_tenure_object(void *data, OBJECT obj) {
@@ -153,14 +311,7 @@ OBJECT object_memory_tenure_object(void *data, OBJECT obj) {
     om-&gt;collect_now |= OMCollectMature;
   }
   
-  /*
-  HEADER(dest)-&gt;flags = HEADER(obj)-&gt;flags;
-  HEADER(dest)-&gt;flags2 = HEADER(obj)-&gt;flags2;
-  HEADER(dest)-&gt;flags = HEADER(obj)-&gt;flags;
-  HEADER(dest)-&gt;gc = 0;
-  HEADER(dest)-&gt;klass = 
-  */
-  memcpy((void*)dest, (void*)obj, SIZE_IN_BYTES(obj));
+  fast_memcpy32((void*)dest, (void*)obj, NUM_FIELDS(obj) + HEADER_SIZE);
   GC_ZONE_SET(dest, GC_MATURE_OBJECTS);
   //printf(&quot;Allocated %d fields to %p\n&quot;, NUM_FIELDS(obj), obj);
   // printf(&quot; :: %p =&gt; %p (%d / %d )\n&quot;, obj, dest, NUM_FIELDS(obj), SIZE_IN_BYTES(obj));
@@ -175,7 +326,19 @@ void object_memory_check_ptr(void *ptr, OBJECT obj) {
   object_memory om = (object_memory)ptr;
   if(REFERENCE_P(obj)) {
     assert(baker_gc_contains_spill_p(om-&gt;gc, obj) ||
-           mark_sweep_contains_p(om-&gt;ms, obj));
+           mark_sweep_contains_p(om-&gt;ms, obj) ||
+           heap_contains_p(om-&gt;contexts, obj));
+    assert(HEADER(obj)-&gt;klass != Qnil);
+  } else if(SYMBOL_P(obj)) {
+    assert(obj &lt; 10000000);
+  }
+}
+
+void object_memory_update_rs(object_memory om, OBJECT target, OBJECT val) {
+  if(!FLAG_SET_ON_P(target, gc, REMEMBER_FLAG)) {
+    // printf(&quot;[Tracking %p in baker RS]\n&quot;, (void*)target);
+    g_ptr_array_add(om-&gt;gc-&gt;remember_set, (gpointer)target);
+    FLAG_SET_ON(target, gc, REMEMBER_FLAG);
   }
 }
 
@@ -367,7 +530,14 @@ OBJECT object_memory_new_object_mature(object_memory om, OBJECT cls, int fields)
     om-&gt;collect_now |= OMCollectMature;
   }
   
-  header = (struct rubinius_object*)obj;
+  header = (struct rubinius_object*)obj;  
+  header-&gt;flags2 = 0;
+  header-&gt;gc = 0;
+  header-&gt;object_id = 0;
+  header-&gt;hash = 0;
+  
+  GC_ZONE_SET(obj, GC_MATURE_OBJECTS);
+  
   rbs_set_class(om, obj, cls);
   SET_NUM_FIELDS(obj, fields);
   if(cls &amp;&amp; REFERENCE_P(cls)) {
@@ -377,14 +547,10 @@ OBJECT object_memory_new_object_mature(object_memory om, OBJECT cls, int fields)
   } else {
     header-&gt;flags = 0;
   }
-  header-&gt;flags2 = 0;
   for(i = 0; i &lt; fields; i++) {
     rbs_set_field(om, obj, i, Qnil);
   }
   
-  header-&gt;object_id = 0;
-  
-  GC_ZONE_SET(obj, GC_MATURE_OBJECTS);
   
   return obj;
 }
@@ -398,7 +564,7 @@ OBJECT object_memory_new_object_normal(object_memory om, OBJECT cls, int fields)
   size = (HEADER_SIZE + fields) * REFSIZE;
   if(!heap_enough_space_p(om-&gt;gc-&gt;current, size)) {
     obj = (OBJECT)baker_gc_allocate_spilled(om-&gt;gc, size);
-    assert(heap_enough_space_p(om-&gt;gc-&gt;next, size));
+    xassert(heap_enough_space_p(om-&gt;gc-&gt;next, size));
     // DEBUG(&quot;Ran out of space! spilled into %p\n&quot;, obj);
     om-&gt;collect_now |= OMCollectYoung;
     // baker_gc_enlarge_next(om-&gt;gc, om-&gt;gc-&gt;current-&gt;size * GC_SCALING_FACTOR);
@@ -407,6 +573,13 @@ OBJECT object_memory_new_object_normal(object_memory om, OBJECT cls, int fields)
   }
   
   header = (struct rubinius_object*)obj;
+  header-&gt;flags2 = 0;
+  header-&gt;gc = 0;
+  header-&gt;object_id = 0;
+  header-&gt;hash = 0;
+  
+  GC_ZONE_SET(obj, GC_YOUNG_OBJECTS);
+  
   rbs_set_class(om, obj, cls);
   SET_NUM_FIELDS(obj, fields);
   if(cls &amp;&amp; REFERENCE_P(cls)) {
@@ -416,13 +589,11 @@ OBJECT object_memory_new_object_normal(object_memory om, OBJECT cls, int fields)
   } else {
     header-&gt;flags = 0;
   }
-  header-&gt;flags2 = 0;
+  
   for(i = 0; i &lt; fields; i++) {
     rbs_set_field(om, obj, i, Qnil);
   }
-  header-&gt;object_id = 0;
   
-  GC_ZONE_SET(obj, GC_YOUNG_OBJECTS);
   return obj;
 }
 </diff>
      <filename>shotgun/lib/object_memory.c</filename>
    </modified>
    <modified>
      <diff>@@ -24,6 +24,11 @@ struct object_memory_struct {
   baker_gc gc;
   mark_sweep_gc ms;
   int last_tenured;
+  
+  rheap contexts;
+  OBJECT context_bottom;
+  OBJECT context_top;
+  OBJECT context_last;
 };
 
 typedef struct object_memory_struct *object_memory;
@@ -44,14 +49,75 @@ void object_memory_major_collect(STATE, object_memory om, GPtrArray *roots);
 OBJECT object_memory_collect_references(STATE, object_memory om, OBJECT mark);
 void object_memory_setup_become(STATE, object_memory om, OBJECT from, OBJECT to);
 void object_memory_clear_become(STATE, object_memory om);
+void object_memory_retire_context(object_memory om, OBJECT ctx);
+void object_memory_update_rs(object_memory om, OBJECT target, OBJECT val);
 
 #define FAST_NEW 1
 
 #ifdef FAST_NEW
-#define object_memory_new_object _om_inline_new_object
+#define object_memory_new_object _om_inline_new_object_init
 #else
 #define object_memory_new_object object_memory_new_object_normal
 #endif
 
-#endif
+#define object_memory_new_dirty_object _om_inline_new_object
+
+#define CTX_SIZE ((HEADER_SIZE + FASTCTX_FIELDS) * REFSIZE)
+  
+#define object_memory_new_context(om) ((OBJECT)heap_allocate_dirty(om-&gt;contexts, CTX_SIZE))
+
+#define om_on_stack(om, ctx) heap_contains_p(om-&gt;contexts, ctx)
+#define om_in_heap(om, ctx) heap_contains_p(om-&gt;gc-&gt;current, ctx)
+
+#define object_memory_retire_context(om, ctx) \
+if(om_on_stack(om, ctx) &amp;&amp; (ctx &gt;= om-&gt;context_bottom)) { \
+  fast_memfill32_s20((void*)ctx, 0); heap_putback(om-&gt;contexts, CTX_SIZE); \
+}
+
+#define object_memory_context_referenced(om, ctx) (void)({ \
+  OBJECT _nb = ctx + CTX_SIZE; \
+  if(om_on_stack(om, ctx) &amp;&amp; (om-&gt;context_bottom &lt; _nb)) { om-&gt;context_bottom = _nb; } })
+
+#define om_context_referenced_p(om, ctx) ((ctx &lt; om-&gt;context_bottom) &amp;&amp; (ctx &gt;= om-&gt;contexts-&gt;address))
+
+#define om_stack_context_p(om, ctx) (om_on_stack(om, ctx) &amp;&amp; (ctx &gt;= om-&gt;context_bottom))
+
+#define om_stack_next_ctx(ctx) ((OBJECT)(ctx + CTX_SIZE))
+#define om_stack_prev_ctx(ctx) ((OBJECT)(ctx - CTX_SIZE))
+#define om_stack_sender(ctx) om_stack_prev_ctx(ctx)
+
+#define om_valid_context_p(state, ctx) ( \
+  (om_stack_context_p(state-&gt;om, ctx) &amp;&amp; (HEADER(ctx)-&gt;klass == Qnil)) || \
+  (om_context_referenced_p(state-&gt;om, ctx)) || \
+  (om_in_heap(state-&gt;om, ctx) &amp;&amp; (methctx_is_fast_p(state, ctx) ||  blokctx_s_block_context_p(state, ctx))) \
+)
+
+#define EACH_CTX(om, addr) \
+  addr = om-&gt;contexts-&gt;address; \
+  while(addr &lt; om-&gt;contexts-&gt;current) {
+    
+#define DONE_EACH_CTX(addr) addr += CTX_SIZE; }
+
+#define EACH_REFD_CTX(om, addr) \
+  addr = om-&gt;contexts-&gt;address; \
+  while(addr &lt; om-&gt;context_bottom) {
+  
+#define DONE_EACH_REFD_CTX(addr) addr += CTX_SIZE; }
+
+#define EACH_STACK_CTX(om, addr) \
+  addr = om-&gt;context_bottom; \
+  while(addr &lt; om-&gt;contexts-&gt;current) {
+    
+#define DONE_EACH_STACK_CTX(addr) addr += CTX_SIZE; }
+
+#define om_no_referenced_ctxs_p(om) (om-&gt;context_bottom == om-&gt;contexts-&gt;address)
+
+/* These are the 4 scenarios detailed in doc/life_of_a_context.txt */
+
+#define om_valid_sender_p(om, ctx, sender) ( \
+  (NIL_P(sender) &amp;&amp; om_on_stack(om, ctx)) || \
+  (om_on_stack(om, ctx) &amp;&amp; om_on_stack(om, sender) &amp;&amp; (om_context_referenced_p(om, sender) || (sender == om_stack_sender(ctx)))) || \
+  (om_in_heap(om, sender) &amp;&amp; om_on_stack(om, ctx) &amp;&amp; (om-&gt;context_bottom == ctx)) || \
+  (om_in_heap(om, ctx) &amp;&amp; (om_context_referenced_p(om, sender) || om_in_heap(om, sender))))
 
+#endif
\ No newline at end of file</diff>
      <filename>shotgun/lib/object_memory.h</filename>
    </modified>
    <modified>
      <diff>@@ -278,7 +278,9 @@ class ShotgunPrimitives
     &lt;&lt;-CODE
     self = stack_pop(); 
     GUARD( RISA(self, blokenv) );
-
+    
+    methctx_reference(state, c-&gt;active_context);
+    
     cpu_flush_sp(c);
     t2 = blokenv_create_context(state, self, c-&gt;active_context, c-&gt;sp);    
     cpu_activate_context(state, c, t2, blokenv_get_home(self), 1);</diff>
      <filename>shotgun/lib/primitives.rb</filename>
    </modified>
    <modified>
      <diff>@@ -97,7 +97,7 @@ const char *rbs_inspect_verbose(STATE, OBJECT obj) {
     assert(RTEST(kls) &amp;&amp; &quot;class is nil&quot;);
     sprintf(buf, &quot;&lt;(NilClass!!):%p&gt;&quot;, (void*)obj);
   } else if(kls == state-&gt;global-&gt;class) {
-    sprintf(buf, &quot;%s&quot;, rbs_symbol_to_cstring(state, module_get_name(obj)));
+    sprintf(buf, &quot;&lt;Class:%s&gt;&quot;, rbs_symbol_to_cstring(state, module_get_name(obj)));
   } else if(kls == state-&gt;global-&gt;symbol || kls == state-&gt;global-&gt;string) {
     const char *s = NULL;
     sprintf(buf, &quot;&lt;%s:%p '&quot;, rbs_symbol_to_cstring(state, module_get_name(kls)), (void*)obj);</diff>
      <filename>shotgun/lib/rubinius.c</filename>
    </modified>
    <modified>
      <diff>@@ -55,6 +55,7 @@ void state_collect(STATE, cpu c) {
       can't keep objects alive. */
   
   cpu_sampler_suspend(state);
+  object_memory_formalize_contexts(state, state-&gt;om);
   roots = _gather_roots(state, c);
   object_memory_collect(state, state-&gt;om, roots);
   memcpy(state-&gt;global, roots-&gt;pdata, sizeof(struct rubinius_globals));
@@ -88,6 +89,8 @@ void state_major_collect(STATE, cpu c) {
   GPtrArray *roots;
   int stats = state-&gt;gc_stats;
   struct timeval start, fin;
+  
+  state_collect(state, c);
     
   if(stats) {
     gettimeofday(&amp;start, NULL);</diff>
      <filename>shotgun/lib/state.c</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,5 @@
 #include &quot;shotgun.h&quot;
+#include &quot;memutil.h&quot;
 
 #include &lt;ucontext.h&gt;
 #include &quot;subtend/PortableUContext.h&quot;
@@ -86,6 +87,7 @@ struct rubinius_state {
   /* Used to pass information down to the garbage collectors */
   OBJECT *current_stack;
   OBJECT *current_sp;
+  int ac_on_stack, home_on_stack, sender_on_stack;
 
 #ifdef USE_CINVOKE
   CInvContext *c_context;
@@ -126,6 +128,10 @@ struct rubinius_state {
 #define FIRE_NULL   2
 #define FIRE_STACK  3
 
+#define FASTCTX_FIELDS 24
+#define FASTCTX_NORMAL 0
+#define FASTCTX_NMC    1
+
 // rubinius.h defines STATE as void*, which means these prototypes fail to match.
 // This is pretty confusing, since they look identical before the pre-processor runs.
 // HACK
@@ -187,6 +193,18 @@ static inline OBJECT rbs_uint_to_fixnum(STATE, unsigned int num) {
 extern void* main_om;
 void object_memory_check_ptr(void *ptr, OBJECT obj);
 static inline void object_memory_write_barrier(object_memory om, OBJECT target, OBJECT val);
+
+// #define XDEBUG 0
+
+#ifdef XDEBUG
+/* Copied from assert.h */
+#define xassert(cond) ((void)((cond) ? 0 : xassert_message(#cond, __FILE__, __LINE__)))
+#define xassert_message(str, file, line) \
+  (printf(&quot;%s:%u: failed assertion '%s'\n&quot;, file, line, str), abort(), 0)
+#else
+#define xassert(cond) 
+#endif
+
 // #define CHECK_PTR(obj) object_memory_check_ptr(main_om, obj)
 #define CHECK_PTR(obj) 
 
@@ -207,7 +225,7 @@ extern int g_access_violation;
 
 void machine_handle_fire(int);
 
-#define ACCESS_MACROS 1
+#define ACCESS_MACROS 0
 
 #ifdef ACCESS_MACROS
 
@@ -261,6 +279,13 @@ static inline OBJECT rbs_get_field(OBJECT in, int fel) {
     }
   }
   
+  if(FLAG_SET_P(in, StoresBytesFlag)) {
+    printf(&quot;Attempted to access field of byte addressed object.\n&quot;);
+    if(g_use_firesuit) {
+      machine_handle_fire(FIRE_NULL);
+    }
+  }
+  
   if(fel &gt;= HEADER(in)-&gt;fields) {
     printf(&quot;Attempted to access field %d in an object with %lu fields.\n&quot;, 
       fel, (unsigned long)NUM_FIELDS(in));
@@ -293,6 +318,13 @@ static inline OBJECT rbs_set_field(object_memory om, OBJECT obj, int fel, OBJECT
   }
 #endif
 
+  if(FLAG_SET_P(obj, StoresBytesFlag)) {
+    printf(&quot;Attempted to access field of byte addressed object.\n&quot;);
+    if(g_use_firesuit) {
+      machine_handle_fire(FIRE_NULL);
+    }
+  }
+
   OBJECT *slot = (OBJECT*)ADDRESS_OF_FIELD(obj, fel);
 #ifdef INTERNAL_MACROS
   /* Check that it's even, ie a ref, and above the special range. */
@@ -315,3 +347,4 @@ typedef void (*state_cleanup_func)(STATE, OBJECT);
 #define SHOULD_CLEANUP_P(obj) (FLAG_SET_P(obj, RequiresCleanupFlag))
 void state_add_cleanup(STATE, OBJECT cls, state_cleanup_func func);
 void state_run_cleanup(STATE, OBJECT obj, OBJECT cls);
+</diff>
      <filename>shotgun/lib/state.h</filename>
    </modified>
    <modified>
      <diff>@@ -15,13 +15,13 @@ OBJECT string_new2(STATE, const char *str, int sz) {
   OBJECT obj, data;
   char *ba;
   
-  assert(sz &gt;= 0);
+  xassert(sz &gt;= 0);
   obj = string_allocate(state);
   string_set_bytes(obj, I2N(sz));
   string_set_characters(obj, I2N(sz));
   string_set_encoding(obj, Qnil);
 
-  data = bytearray_new(state, sz+1);
+  data = bytearray_new_dirty(state, sz+1);
   ba = bytearray_byte_address(state, data);
   if(str == NULL) {
     memset(ba, 0, sz);
@@ -42,7 +42,7 @@ OBJECT string_new(STATE, const char *str) {
 OBJECT string_dup(STATE, OBJECT self) {
   char *ba;
   
-  assert(STRING_P(self));
+  xassert(STRING_P(self));
   ba = bytearray_byte_address(state, string_get_data(self));
   
   return string_new2(state, ba, FIXNUM_TO_INT(string_get_bytes(self)));
@@ -50,11 +50,11 @@ OBJECT string_dup(STATE, OBJECT self) {
 
 OBJECT string_append(STATE, OBJECT self, OBJECT other) {
   OBJECT cur, obs, nd;
-  int cur_sz, oth_sz, ns, tmp;
+  int cur_sz, oth_sz, ns, tmp, extra;
   char *ba;
   
-  assert(STRING_P(self));
-  assert(STRING_P(other));
+  xassert(STRING_P(self));
+  xassert(STRING_P(other));
   
   cur = string_get_data(self);
   obs = string_get_data(other);
@@ -64,7 +64,9 @@ OBJECT string_append(STATE, OBJECT self, OBJECT other) {
   ns = cur_sz + oth_sz;
   tmp = bytearray_bytes(state, cur);
   if(ns+1 &gt; tmp) {
-    nd = bytearray_new(state, ns+100);
+    extra = ns * 0.01;
+    if(extra &lt; 10) extra = 10;
+    nd = bytearray_new_dirty(state, ns+extra);
     object_copy_bytes_into(state, cur, nd, cur_sz, 0);
     object_copy_bytes_into(state, obs, nd, oth_sz, cur_sz);
     ba = bytearray_byte_address(state, nd);
@@ -81,7 +83,7 @@ OBJECT string_append(STATE, OBJECT self, OBJECT other) {
 char *string_byte_address(STATE, OBJECT self) {
   OBJECT data;
 
-  assert(STRING_P(self));
+  xassert(STRING_P(self));
   data = string_get_data(self);
   if(NIL_P(data)) {
     return &quot;&quot;;
@@ -95,7 +97,7 @@ double string_to_double(STATE, OBJECT self) {
   double value;
   char *p, *n, *ba, *rest;
   
-  assert(STRING_P(self));
+  xassert(STRING_P(self));
   str = string_dup(state, self);
   data = string_get_data(str);
   ba = bytearray_byte_address(state, data);
@@ -150,7 +152,7 @@ unsigned int string_hash_int(STATE, OBJECT self) {
   unsigned int sz, h;
   OBJECT data;
   
-  assert(STRING_P(self));
+  xassert(STRING_P(self));
   data = string_get_data(self);
   if(HEADER(data)-&gt;hash != 0) {
     return HEADER(data)-&gt;hash;
@@ -173,6 +175,6 @@ unsigned int string_hash_str_with_size(STATE, const char *bp, int size) {
 }
 
 OBJECT string_to_sym(STATE, OBJECT self) {
-  assert(STRING_P(self));
+  xassert(STRING_P(self));
   return symtbl_lookup(state, state-&gt;global-&gt;symbols, self);
 }</diff>
      <filename>shotgun/lib/string.c</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>4f93ccbf7933ad22f4983b6d9d87b7fab835c38f</id>
    </parent>
  </parents>
  <author>
    <name>Evan Phoenix</name>
    <email>evan@fallingsnow.net</email>
  </author>
  <url>http://github.com/evanphx/rubinius/commit/3b7882afddb5ad00779fb3245728b9ac8d36f9b5</url>
  <id>3b7882afddb5ad00779fb3245728b9ac8d36f9b5</id>
  <committed-date>2007-08-09T20:24:35-07:00</committed-date>
  <authored-date>2007-08-09T20:24:35-07:00</authored-date>
  <message>The context optimization change your parents always talked about but never implemented.

Is now implemented!

The biggy is here is the change to have context's are allocated. They're now allocated in a stack fashion for easy reuse, and automatically converted to full objects each run of the garbage collector as needed. Only contexts which have been referenced are saved at collection.

Also in here is a little cleanup to object initialization. Object memory was clearing the body of an object 2 times too many, so I restructured the code so it's delayed until it really needs to be done. Also, added memutil.h, which contains some simple but fast memcpy and memset substitutes that only function on memory that is word aligned (all objects are, so thats easy.)</message>
  <tree>eb418f67abeb204d575781c11f56189da1401db9</tree>
  <committer>
    <name>Evan Phoenix</name>
    <email>evan@fallingsnow.net</email>
  </committer>
</commit>
