<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -9,3 +9,7 @@ end
 define rps
 p __show_simple__($arg0)
 end
+
+define validate
+p rubinius::VM::current_state()-&gt;om-&gt;validate_object($arg0)
+end</diff>
      <filename>.gdbinit</filename>
    </modified>
    <modified>
      <diff>@@ -80,11 +80,6 @@ end
 # of load order mattering)
 
 class IncludedModule &lt; Module
-  self.instance_fields = 8
-
-  # HACK: make this a VM exported constant
-  self.object_type = 7
-
   def superclass; @superclass ; end
   def module    ; @module     ; end
 </diff>
      <filename>kernel/bootstrap/class.rb</filename>
    </modified>
    <modified>
      <diff>@@ -113,6 +113,11 @@ initialize:
     return -1;
   }
 
+  void MethodContext::post_copy(MethodContext* old) {
+    this-&gt;position_stack(old-&gt;calculate_sp());
+    this-&gt;js.stack_top = this-&gt;stk + this-&gt;stack_size;
+  }
+
   /* Attempt to recycle +this+ context into the context cache, based
    * on it's size. Returns true if the context was recycled, otherwise
    * false. */</diff>
      <filename>vm/builtin/contexts.cpp</filename>
    </modified>
    <modified>
      <diff>@@ -107,6 +107,10 @@ namespace rubinius {
       return js.stack - stk;
     }
 
+    /* Run after a context is copied, allowing it to fix up
+     * it's internal pointers */
+    void post_copy(MethodContext* old);
+
     class Info : public TypeInfo {
     public:
       BASIC_TYPEINFO(TypeInfo)</diff>
      <filename>vm/builtin/contexts.hpp</filename>
    </modified>
    <modified>
      <diff>@@ -333,7 +333,9 @@ namespace rubinius {
     // between all duplicates made from this object
     // TODO - Verify this statement
     dup = state-&gt;om-&gt;new_object(lookup_begin(state), field_count);
+    gc_zone zone = dup-&gt;zone;
     dup-&gt;all_flags = all_flags;
+    dup-&gt;zone = zone;
 
     if(stores_bytes_p()) {
       std::memcpy(dup-&gt;bytes, bytes, field_count * sizeof(OBJECT));
@@ -352,11 +354,13 @@ namespace rubinius {
     LookupTable* source_constants = this-&gt;metaclass(state)-&gt;constants-&gt;dup(state);
     OBJECT new_object = this-&gt;dup(state);
 
+    // TODO why can't we use new_object-&gt;metaclass(state) here? Why are
+    // we creating a metaclass by hand?
     // Clone gets a new MetaClass
     SET(new_object, klass, (MetaClass*)state-&gt;new_object(G(metaclass)));
     // Set the clone's method and constants tables to those
     // of the receiver's metaclass
-    SET(new_object-&gt;klass, method_table, source_methods);
+    SET(new_object-&gt;metaclass(state), method_table, source_methods);
     SET(new_object-&gt;klass, constants, source_constants);
 
     return new_object;</diff>
      <filename>vm/builtin/object.cpp</filename>
    </modified>
    <modified>
      <diff>@@ -20,6 +20,7 @@ namespace rubinius {
     SET(ss, sender, Qnil);
     SET(ss, selector, Selector::lookup(state, name));
     ss-&gt;hits = ss-&gt;misses = 0;
+    ss-&gt;resolver = NULL;
 
     ss-&gt;initialize(state);
     ss-&gt;selector-&gt;associate(state, ss);</diff>
      <filename>vm/builtin/sendsite.cpp</filename>
    </modified>
    <modified>
      <diff>@@ -49,7 +49,7 @@ namespace rubinius {
   Task* Task::create(STATE, size_t stack_size) {
     Task* task = (Task*)state-&gt;new_struct(G(task), sizeof(Task));
     task-&gt;state = state;
-    task-&gt;probe = state-&gt;probe;
+    SET(task, probe, state-&gt;probe.get());
     task-&gt;msg = new Message(state);
     SET(task, control_channel, Qnil);
     SET(task, debug_channel, Qnil);
@@ -619,11 +619,13 @@ stack_cleanup:
     if(state-&gt;om-&gt;collect_young_now) {
       state-&gt;om-&gt;collect_young_now = false;
       state-&gt;om-&gt;collect_young(state-&gt;globals.roots);
+      state-&gt;global_cache-&gt;clear();
     }
 
     if(state-&gt;om-&gt;collect_mature_now) {
       state-&gt;om-&gt;collect_mature_now = false;
       state-&gt;om-&gt;collect_mature(state-&gt;globals.roots);
+      state-&gt;global_cache-&gt;clear();
     }
   }
 
@@ -640,8 +642,9 @@ stack_cleanup:
         // If we're switching tasks, return to the task monitor
         if(state-&gt;interrupts.switch_task) {
           state-&gt;interrupts.switch_task = false;
-          return;
         }
+
+        return;
       }
     }
   }
@@ -674,7 +677,12 @@ stack_cleanup:
         }
       }
 
-      std::cout &lt;&lt; &quot;:&quot; &lt;&lt; ctx-&gt;line() &lt;&lt; &quot; in &quot; &lt;&lt; ctx-&gt;cm-&gt;file-&gt;to_str(state)-&gt;byte_address();
+      std::cout &lt;&lt; &quot;:&quot; &lt;&lt; ctx-&gt;line() &lt;&lt; &quot; in &quot;;
+      if(SYMBOL file_sym = try_as&lt;Symbol&gt;(ctx-&gt;cm-&gt;file)) {
+        std::cout &lt;&lt; file_sym-&gt;c_str(state);
+      } else {
+        std::cout &lt;&lt; &quot;&lt;unknown&gt;&quot;;
+      }
 
       std::cout &lt;&lt; &quot;\n&quot;;
       ctx = ctx-&gt;sender;</diff>
      <filename>vm/builtin/task.cpp</filename>
    </modified>
    <modified>
      <diff>@@ -2,11 +2,20 @@
 #include &quot;vm.hpp&quot;
 #include &quot;objectmemory.hpp&quot;
 #include &quot;builtin/fixnum.hpp&quot;
+#include &quot;builtin/compactlookuptable.hpp&quot;
 
 #include &lt;cstdarg&gt;
 #include &lt;iostream&gt;
 
 namespace rubinius {
+
+  template &lt;&gt;
+    bool kind_of&lt;Tuple&gt;(OBJECT obj) {
+      return obj-&gt;reference_p() &amp;&amp; (
+              obj-&gt;obj_type == Tuple::type ||
+              obj-&gt;obj_type == CompactLookupTable::type);
+    }
+
   OBJECT Tuple::at(size_t index) {
     if(field_count &lt;= index) {
       ObjectBoundsExceeded::raise(this, index);</diff>
      <filename>vm/builtin/tuple.cpp</filename>
    </modified>
    <modified>
      <diff>@@ -21,7 +21,7 @@ namespace rubinius {
   Environment::Environment() {
     state = new VM();
     TaskProbe* probe = TaskProbe::create(state);
-    state-&gt;probe = probe-&gt;parse_env(NULL) ? probe : (TaskProbe*)Qnil;
+    state-&gt;probe.set(probe-&gt;parse_env(NULL) ? probe : (TaskProbe*)Qnil);
   }
 
   Environment::~Environment() {</diff>
      <filename>vm/environment.cpp</filename>
    </modified>
    <modified>
      <diff>@@ -55,6 +55,14 @@ namespace rubinius {
       if(slot) object_memory-&gt;set_class(obj, slot);
     }
 
+    if(obj-&gt;ivars &amp;&amp; obj-&gt;ivars-&gt;reference_p()) {
+      slot = saw_object(obj-&gt;ivars);
+      if(slot) {
+        obj-&gt;ivars = slot;
+        object_memory-&gt;write_barrier(obj, slot);
+      }
+    }
+
     TypeInfo* ti = object_memory-&gt;type_info[obj-&gt;obj_type];
     if(ti) {
       ObjectMark mark(this);</diff>
      <filename>vm/gc.cpp</filename>
    </modified>
    <modified>
      <diff>@@ -4,6 +4,7 @@
 #include &quot;gc_baker.hpp&quot;
 #include &quot;objectmemory.hpp&quot;
 #include &quot;builtin/tuple.hpp&quot;
+#include &quot;builtin/contexts.hpp&quot;
 
 namespace rubinius {
 
@@ -40,6 +41,8 @@ namespace rubinius {
     tmp-&gt;all_flags   = orig-&gt;all_flags;
     tmp-&gt;field_count = orig-&gt;field_count;
     tmp-&gt;klass       = orig-&gt;klass;
+    tmp-&gt;ivars       = orig-&gt;ivars;
+    tmp-&gt;Forwarded   = 0;
 
     for(size_t i = 0; i &lt; orig-&gt;field_count; i++) {
       tmp-&gt;field[i] = orig-&gt;field[i];
@@ -64,13 +67,33 @@ namespace rubinius {
 
     if(obj-&gt;forwarded_p()) return obj-&gt;forward();
 
+    // This object is already in the next space, we don't want to
+    // copy it again!
+    // TODO test this!
+    if(next-&gt;contains_p(obj)) return obj;
+
     if(obj-&gt;age++ &gt;= lifetime) {
       copy = object_memory-&gt;promote_object(obj);
+
+      // We promoted it, so our scan pointer loop wont see it to walk
+      // it's references. Instead we scan in manually here.
+      // HACK TODO this can cause a cascading C stack as a lot of
+      // objects are promoted at once and cause a stack overflow.
+      //
+      // We should keep track of all the promoted objects and walk
+      // them at the end.
+      scan_object(copy);
     } else if(next-&gt;enough_space_p(obj-&gt;size_in_bytes())) {
       copy = next-&gt;copy_object(obj);
       total_objects++;
     } else {
       copy = object_memory-&gt;promote_object(obj);
+      // See note above concerning promoted objects.
+      scan_object(copy);
+    }
+
+    if(MethodContext* ctx = try_as&lt;MethodContext&gt;(copy)) {
+      ctx-&gt;post_copy(as&lt;MethodContext&gt;(obj));
     }
 
     obj-&gt;set_forward(copy);
@@ -97,9 +120,13 @@ namespace rubinius {
 
     ObjectArray::iterator oi;
     for(oi = current_rs-&gt;begin(); oi != current_rs-&gt;end(); oi++) {
-      assert((*oi)-&gt;zone == MatureObjectZone);
-      assert(!(*oi)-&gt;forwarded_p());
-      scan_object(*oi);
+      tmp = *oi;
+      assert(tmp-&gt;zone == MatureObjectZone);
+      assert(!tmp-&gt;forwarded_p());
+
+      /* Remove the Remember bit, since we're clearing the set. */
+      tmp-&gt;Remember = 0;
+      scan_object(tmp);
     }
 
     delete current_rs;
@@ -196,4 +223,14 @@ namespace rubinius {
       }
     }
   }
+
+  ObjectPosition BakerGC::validate_object(OBJECT obj) {
+    if(current-&gt;contains_p(obj)) {
+      return cValid;
+    } else if(next-&gt;contains_p(obj)) {
+      return cInWrongYoungHalf;
+    } else {
+      return cUnknown;
+    }
+  }
 }</diff>
      <filename>vm/gc_baker.cpp</filename>
    </modified>
    <modified>
      <diff>@@ -3,6 +3,8 @@
 
 #include &quot;gc.hpp&quot;
 #include &quot;gc_root.hpp&quot;
+#include &quot;object_position.hpp&quot;
+
 #include &lt;iostream&gt;
 
 namespace rubinius {
@@ -45,14 +47,14 @@ namespace rubinius {
       }
 
       bool contains_p(address addr) {
-        if(addr &lt; start) return FALSE;
-        if(addr &gt;= last) return FALSE;
-        return TRUE;
+        if(addr &lt; start) return false;
+        if(addr &gt;= last) return false;
+        return true;
       }
 
       bool enough_space_p(size_t size) {
-        if((uintptr_t)current + size &gt; (uintptr_t)last) return FALSE;
-        return TRUE;
+        if((uintptr_t)current + size &gt; (uintptr_t)last) return false;
+        return true;
       }
 
       bool fully_scanned_p() {
@@ -95,14 +97,16 @@ namespace rubinius {
       OBJECT obj;
 
       if(!current-&gt;enough_space_p(bytes)) {
+#if 0
         if(!next-&gt;enough_space_p(bytes)) {
           return NULL;
         } else {
           total_objects++;
           obj = (OBJECT)next-&gt;allocate(bytes);
         }
-
+#endif
         *collect_now = true;
+        return NULL;
       } else {
         total_objects++;
         obj = (OBJECT)current-&gt;allocate(bytes);
@@ -122,6 +126,8 @@ namespace rubinius {
     OBJECT  next_object(OBJECT obj);
     void    find_lost_souls();
     void    clean_weakrefs();
+
+    ObjectPosition validate_object(OBJECT obj);
   };
 };
 </diff>
      <filename>vm/gc_baker.hpp</filename>
    </modified>
    <modified>
      <diff>@@ -82,10 +82,13 @@ namespace rubinius {
     bool collect;
     OBJECT obj = allocate(orig-&gt;field_count, &amp;collect);
 
+    // HACK this code is exactly duplicated from BakerGC
+
     obj-&gt;all_flags   = orig-&gt;all_flags;
     obj-&gt;field_count = orig-&gt;field_count;
     obj-&gt;klass       = orig-&gt;klass;
     obj-&gt;age         = 0;
+    obj-&gt;ivars       = orig-&gt;ivars;
 
     for(size_t i = 0; i &lt; orig-&gt;field_count; i++) {
       obj-&gt;field[i] = orig-&gt;field[i];
@@ -149,6 +152,19 @@ namespace rubinius {
     }
   }
 
+  ObjectPosition MarkSweepGC::validate_object(OBJECT obj) {
+    std::list&lt;Entry*&gt;::iterator i;
+
+    for(i = entries.begin(); i != entries.end(); i++) {
+      Entry* entry = *i;
+      if(entry-&gt;header-&gt;to_object() == obj) {
+        return cMatureObject;
+      }
+    }
+
+    return cUnknown;
+  }
+
   // HACK todo test this!
   void MarkSweepGC::clean_weakrefs() {
     if(!weak_refs) return;</diff>
      <filename>vm/gc_marksweep.cpp</filename>
    </modified>
    <modified>
      <diff>@@ -4,6 +4,7 @@
 #include &quot;object.hpp&quot;
 #include &quot;gc.hpp&quot;
 #include &quot;gc_root.hpp&quot;
+#include &quot;object_position.hpp&quot;
 
 #include &lt;list&gt;
 
@@ -82,6 +83,8 @@ namespace rubinius {
     void   free_object(Entry *entry);
     virtual OBJECT saw_object(OBJECT obj);
     void   collect(Roots &amp;roots);
+
+    ObjectPosition validate_object(OBJECT obj);
   };
 };
 </diff>
      <filename>vm/gc_marksweep.hpp</filename>
    </modified>
    <modified>
      <diff>@@ -3,5 +3,8 @@
 
 namespace rubinius {
   Root::Root(STATE) : object(NULL), roots(&amp;state-&gt;globals.roots) { }
-  Root::Root(STATE, OBJECT obj) : object(obj), roots(&amp;state-&gt;globals.roots) { }
+
+  Root::Root(STATE, OBJECT obj) : object(obj), roots(&amp;state-&gt;globals.roots) {
+    roots-&gt;push_back(this);
+  }
 }</diff>
      <filename>vm/gc_root.cpp</filename>
    </modified>
    <modified>
      <diff>@@ -21,7 +21,7 @@ namespace rubinius {
 
     struct cache_entry entries[CPU_CACHE_SIZE];
 
-    GlobalCache() {
+    void clear() {
       for(size_t i = 0; i &lt; CPU_CACHE_SIZE; i++) {
         entries[i].klass = 0;
         entries[i].name  = 0;
@@ -31,6 +31,10 @@ namespace rubinius {
       }
     }
 
+    GlobalCache() {
+      clear();
+    }
+
     struct cache_entry* lookup(Module* cls, SYMBOL name) {
       struct cache_entry* entry;
 </diff>
      <filename>vm/global_cache.hpp</filename>
    </modified>
    <modified>
      <diff>@@ -94,6 +94,7 @@ namespace rubinius {
   /* Store an object into the remember set. Called when we've calculated
    * externally that the object in question needs to be remembered */
   void ObjectMemory::remember_object(OBJECT target) {
+    assert(target-&gt;zone == MatureObjectZone);
     /* If it's already remembered, ignore this request */
     if(target-&gt;Remember) return;
     target-&gt;Remember = 1;
@@ -219,21 +220,8 @@ namespace rubinius {
 
   OBJECT ObjectMemory::create_object(Class* cls, size_t fields) {
     OBJECT obj;
-    gc_zone loc;
-
-    if(fields &gt; large_object_threshold) {
-      obj = mature.allocate(fields, &amp;collect_mature_now);
-      loc = MatureObjectZone;
-    } else {
-      if((obj = young.allocate(fields, &amp;collect_young_now))) {
-        loc = YoungObjectZone;
-      } else {
-        obj = mature.allocate(fields, &amp;collect_mature_now);
-        loc = MatureObjectZone;
-      }
-    }
 
-    obj-&gt;init(loc, fields);
+    obj = allocate_object(fields);
     set_class(obj, cls);
 
     obj-&gt;obj_type = (object_type)cls-&gt;instance_type-&gt;to_native();
@@ -245,6 +233,15 @@ namespace rubinius {
   TypeInfo* ObjectMemory::find_type_info(OBJECT obj) {
     return type_info[obj-&gt;obj_type];
   }
+
+  ObjectPosition ObjectMemory::validate_object(OBJECT obj) {
+    ObjectPosition pos;
+
+    pos = young.validate_object(obj);
+    if(pos != cUnknown) return pos;
+
+    return mature.validate_object(obj);
+  }
 };
 
 void* XMALLOC(size_t bytes) {</diff>
      <filename>vm/objectmemory.cpp</filename>
    </modified>
    <modified>
      <diff>@@ -6,6 +6,8 @@
 #include &quot;gc_baker.hpp&quot;
 #include &quot;type_info.hpp&quot;
 
+#include &quot;object_position.hpp&quot;
+
 namespace rubinius {
 
   /* ObjectMemory is the primary API that the rest of the VM uses to interact
@@ -64,6 +66,8 @@ namespace rubinius {
     bool valid_object_p(OBJECT obj);
     void debug_marksweep(bool val);
     void add_type_info(TypeInfo* ti);
+
+    ObjectPosition validate_object(OBJECT obj);
   };
 
 // Type-safe, write-barrier-enabled version of 'SET'</diff>
      <filename>vm/objectmemory.hpp</filename>
    </modified>
    <modified>
      <diff>@@ -25,15 +25,14 @@
 #define GO(whatever) globals.whatever
 
 namespace rubinius {
-  VM::VM(size_t bytes) : probe(NULL), wait_events(false) {
+  VM::VM(size_t bytes) : wait_events(false) {
     config.compile_up_front = false;
     context_cache = NULL;
 
-    probe = (TaskProbe*)Qnil;
-
     user_config = new ConfigParser();
 
     om = new ObjectMemory(bytes);
+    probe.set(Qnil, &amp;globals.roots);
 
     MethodContext::initialize_cache(this);
     TypeInfo::init(this);
@@ -247,6 +246,7 @@ namespace rubinius {
 
   void VM::run_and_monitor() {
     for(;;) {
+      G(current_task)-&gt;check_interrupts();
       G(current_task)-&gt;execute();
     }
   }</diff>
      <filename>vm/vm.cpp</filename>
    </modified>
    <modified>
      <diff>@@ -48,7 +48,7 @@ namespace rubinius {
     event::Loop* events;
     event::Loop* signal_events;
     GlobalCache* global_cache;
-    TaskProbe* probe;
+    TypedRoot&lt;TaskProbe*&gt; probe;
     Primitives* primitives;
     Configuration config;
     Interrupts interrupts;</diff>
      <filename>vm/vm.hpp</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>8543558a2e64ce100d270e53b28394a37fe41caf</id>
    </parent>
  </parents>
  <author>
    <name>Evan Phoenix</name>
    <email>ephoenix@engineyard.com</email>
  </author>
  <url>http://github.com/evanphx/rubinius/commit/8906a3fb12ce37ca6ad11813c4b572675ea292df</url>
  <id>8906a3fb12ce37ca6ad11813c4b572675ea292df</id>
  <committed-date>2008-09-11T17:37:18-07:00</committed-date>
  <authored-date>2008-09-11T14:10:47-07:00</authored-date>
  <message>A slew of GC fixes

* When we fill up the young object space, we spill right away to the
  mature space and set a flag that we need to collect the young space.
* GC is only done currently when a task completes</message>
  <tree>69af81bf67b2e5f5182afffa50864e2ddfabdfde</tree>
  <committer>
    <name>Evan Phoenix</name>
    <email>ephoenix@engineyard.com</email>
  </committer>
</commit>
