Index: /usr/ben/ruby-1.8.5/parse.y
===================================================================
--- /usr/ben/ruby-1.8.5/parse.y (revision 7140)
+++ /usr/ben/ruby-1.8.5/parse.y (revision 7142)
@@ -4500,5 +4500,13 @@
     VALUE a0, a1, a2;
 {
-    NODE *n = (NODE*)rb_newobj();
+	NODE *n;
+	
+	switch (type) {
+		case NODE_METHOD:
+    		n = (NODE*)rb_newobj_mutable();
+			break;
+		default:
+    		n = (NODE*)rb_newobj();
+	}
 
     n->flags |= T_NODE;
Index: /usr/ben/ruby-1.8.5/class.c
===================================================================
--- /usr/ben/ruby-1.8.5/class.c (revision 7140)
+++ /usr/ben/ruby-1.8.5/class.c (revision 7142)
@@ -23,5 +23,5 @@
     VALUE super;
 {
-    NEWOBJ(klass, struct RClass);
+    NEWOBJ_MUT(klass, struct RClass);
     OBJSETUP(klass, rb_cClass, T_CLASS);
 
@@ -111,5 +111,5 @@
     else {
 	/* copy singleton(unnamed) class */
-	NEWOBJ(clone, struct RClass);
+	NEWOBJ_MUT(clone, struct RClass);
 	OBJSETUP(clone, 0, RBASIC(klass)->flags);
 
@@ -273,5 +273,5 @@
 rb_module_new()
 {
-    NEWOBJ(mdl, struct RClass);
+    NEWOBJ_MUT(mdl, struct RClass);
     OBJSETUP(mdl, rb_cModule, T_MODULE);
 
@@ -344,5 +344,5 @@
     VALUE module, super;
 {
-    NEWOBJ(klass, struct RClass);
+    NEWOBJ_MUT(klass, struct RClass);
     OBJSETUP(klass, rb_cClass, T_ICLASS);
 
Index: /usr/ben/ruby-1.8.5/array.c
===================================================================
--- /usr/ben/ruby-1.8.5/array.c (revision 7140)
+++ /usr/ben/ruby-1.8.5/array.c (revision 7142)
@@ -101,5 +101,5 @@
     VALUE klass;
 {
-    NEWOBJ(ary, struct RArray);
+    NEWOBJ_MUT(ary, struct RArray);
     OBJSETUP(ary, klass, T_ARRAY);
 
@@ -464,5 +464,5 @@
 {
     if (!FL_TEST(ary, ELTS_SHARED)) {
-	NEWOBJ(shared, struct RArray);
+	NEWOBJ_MUT(shared, struct RArray);
 	OBJSETUP(shared, rb_cArray, T_ARRAY);
 
Index: /usr/ben/ruby-1.8.5/hash.c
===================================================================
--- /usr/ben/ruby-1.8.5/hash.c (revision 7141)
+++ /usr/ben/ruby-1.8.5/hash.c (revision 7142)
@@ -230,5 +230,5 @@
     VALUE klass;
 {
-    NEWOBJ(hash, struct RHash);
+    NEWOBJ_MUT(hash, struct RHash);
     OBJSETUP(hash, klass, T_HASH);
 
Index: /usr/ben/ruby-1.8.5/string.c
===================================================================
--- /usr/ben/ruby-1.8.5/string.c (revision 7140)
+++ /usr/ben/ruby-1.8.5/string.c (revision 7142)
@@ -65,5 +65,5 @@
     VALUE klass;
 {
-    NEWOBJ(str, struct RString);
+    NEWOBJ_MUT(str, struct RString);
     OBJSETUP(str, klass, T_STRING);
 
Index: /usr/ben/ruby-1.8.5/ruby.h
===================================================================
--- /usr/ben/ruby-1.8.5/ruby.h (revision 7140)
+++ /usr/ben/ruby-1.8.5/ruby.h (revision 7142)
@@ -292,5 +292,7 @@
 
 VALUE rb_newobj _((void));
+VALUE rb_newobj_mutable _((void));
 #define NEWOBJ(obj,type) type *obj = (type*)rb_newobj()
+#define NEWOBJ_MUT(obj,type) type *obj = (type*)rb_newobj_mutable()
 #define OBJSETUP(obj,c,t) do {\
     RBASIC(obj)->flags = (t);\
@@ -511,4 +513,5 @@
 void rb_gc_register_address _((VALUE*));
 void rb_gc_unregister_address _((VALUE*));
+int gc_is_node_marked(void *p);
 
 ID rb_intern _((const char*));
Index: /usr/ben/ruby-1.8.5/eval.c
===================================================================
--- /usr/ben/ruby-1.8.5/eval.c (revision 7140)
+++ /usr/ben/ruby-1.8.5/eval.c (revision 7142)
@@ -852,5 +852,5 @@
     struct RVarmap *prev;
 {
-    NEWOBJ(vars, struct RVarmap);
+    NEWOBJ_MUT(vars, struct RVarmap);
     OBJSETUP(vars, 0, T_VARMAP);
     vars->id = id;
@@ -1070,5 +1070,5 @@
     volatile int _vmode = scope_vmode;	\
     struct SCOPE * volatile _old;	\
-    NEWOBJ(_scope, struct SCOPE);	\
+    NEWOBJ_MUT(_scope, struct SCOPE);	\
     OBJSETUP(_scope, 0, T_SCOPE);	\
     _scope->local_tbl = 0;		\
@@ -8499,5 +8499,5 @@
     _block.frame.flags = ruby_frame->flags;
     if (_block.frame.argc && (ruby_frame->flags & FRAME_DMETH)) {
-        NEWOBJ(scope, struct SCOPE);
+        NEWOBJ_MUT(scope, struct SCOPE);
         OBJSETUP(scope, tmp, T_SCOPE);
         scope->local_tbl = _block.scope->local_tbl;
@@ -10117,20 +10117,25 @@
     if (loading_tbl) st_foreach(loading_tbl, mark_loading_thread, 0);
 }
+int gc_is_node_marked(void *p);
 
 void
 rb_gc_abort_threads()
 {
-    rb_thread_t th;
+    rb_thread_t th = NULL;
 
     if (!main_thread)
         return;
 
-    FOREACH_THREAD_FROM(main_thread, th) {
-	if (FL_TEST(th->thread, FL_MARK)) continue;
-	if (th->status == THREAD_STOPPED) {
-	    th->status = THREAD_TO_KILL;
-	    rb_gc_mark(th->thread);
-	}
-    } END_FOREACH_FROM(main_thread, th);
+    while ( th != main_thread )  {
+    	if ( !th ) 
+		th = main_thread->next;
+	if (!gc_is_node_marked((void *)th->thread)) {
+		if (th->status == THREAD_STOPPED) {
+		    th->status = THREAD_TO_KILL;
+		    rb_gc_mark(th->thread);
+		}
+	}
+	th = th->next;	
+    } 
 }
 
Index: /usr/ben/ruby-1.8.5/gc.c
===================================================================
--- /usr/ben/ruby-1.8.5/gc.c (revision 7141)
+++ /usr/ben/ruby-1.8.5/gc.c (revision 7142)
@@ -426,5 +426,7 @@
 #endif
 
-static RVALUE *freelist = 0;
+#undef MUTATION_PROFILING
+static RVALUE *freelist_mutable = 0;
+static RVALUE *freelist_immutable = 0;
 static RVALUE *deferred_final_list = 0;
 
@@ -432,6 +434,12 @@
 static struct heaps_slot {
     void *membase;
+	unsigned char *markfield;
     RVALUE *slot;
+#ifdef	MUTATION_PROFILING
+	RVALUE *last_state;
+#endif
     int limit;
+	int frozen;
+	int mutable;
 } *heaps;
 static int heaps_length = 0;
@@ -441,5 +449,7 @@
 static int heap_slots = 10000;
 
-static int heap_free_min = 4096;
+#define	HEAP_MAX_SLOTS 125000
+
+static int heap_free_min = 2048;
 
 static long initial_malloc_limit = GC_MALLOC_LIMIT;
@@ -572,9 +582,21 @@
 }
 
+static inline void add_to_free_list(RVALUE *p, int mutable)
+{
+	if ( mutable ) {
+		p->as.free.next = freelist_mutable;
+		p->as.free.flags = 0;
+		freelist_mutable = p;
+	} else {
+		p->as.free.next = freelist_immutable;
+		p->as.free.flags = 0;
+		freelist_immutable = p;
+	}
+}
 
 static void
-add_heap()
-{
-    RVALUE *p, *pend;
+add_heap(int mutable)
+{
+	RVALUE *p, *pend, *tmp, *list;
 
     if (heaps_used == heaps_length) {
@@ -609,22 +631,37 @@
             heap_slots += 1;
         else
-            p = (RVALUE*)((VALUE)p + sizeof(RVALUE) - ((VALUE)p % sizeof(RVALUE)));
+			/* I think this cache aligns shit on the heap? not sure. */
+			p = (RVALUE *) ((VALUE) p + sizeof(RVALUE) -
+					((VALUE) p % sizeof(RVALUE)));
         heaps[heaps_used].slot = p;
         heaps[heaps_used].limit = heap_slots;
+		heaps[heaps_used].markfield = malloc(sizeof(unsigned char) * (heap_slots + 1));
+		memset(heaps[heaps_used].markfield, 0, sizeof(unsigned char) * (heap_slots + 1));
+		heaps[heaps_used].frozen = 0;
+		heaps[heaps_used].mutable = mutable;
 	break;
     }
+#ifdef	MUTATION_PROFILING
+	RUBY_CRITICAL ( heaps[heaps_used].last_state = (RVALUE *) malloc(sizeof(RVALUE) * (heap_slots + 1)));
+	memset(heaps[heaps_used].last_state, 0, sizeof(RVALUE) * (heap_slots + 1));
+#endif
+
     pend = p + heap_slots;
     if (lomem == 0 || lomem > p) lomem = p;
     if (himem < pend) himem = pend;
     heaps_used++;
-    heap_slots *= 1.8;
-    if (heap_slots <= 0) heap_slots = heap_min_slots;
+
 
     while (p < pend) {
-	p->as.free.flags = 0;
-	p->as.free.next = freelist;
-	freelist = p;
+		add_to_free_list(p, mutable);
 	p++;
     }
+	
+	if (heap_slots < HEAP_MAX_SLOTS && heaps_used % 2 == 0)
+		heap_slots *= 1.8;
+
+	if (heap_slots <= 0)
+		heap_slots = heap_min_slots;
+
 }
 #define RANY(o) ((RVALUE*)(o))
@@ -635,8 +672,10 @@
     VALUE obj;
 
-    if (!freelist) garbage_collect();
-
-    obj = (VALUE)freelist;
-    freelist = freelist->as.free.next;
+	/* ICKY: maybe this won't add a heap. */
+	if (!freelist_immutable)
+		garbage_collect();
+
+	obj = (VALUE) freelist_immutable;
+	freelist_immutable = freelist_immutable->as.free.next;
     MEMZERO((void*)obj, RVALUE, 1);
 #ifdef GC_DEBUG
@@ -647,6 +686,23 @@
 }
 
-VALUE
-rb_data_object_alloc(klass, datap, dmark, dfree)
+VALUE rb_newobj_mutable()
+{
+	VALUE obj;
+
+	/* ICKY: maybe this won't add a heap. */
+	if (!freelist_mutable)
+		garbage_collect();
+
+	obj = (VALUE) freelist_mutable;
+	freelist_mutable = freelist_mutable->as.free.next;
+	MEMZERO((void *) obj, RVALUE, 1);
+#ifdef GC_DEBUG
+	RANY(obj)->file = ruby_sourcefile;
+	RANY(obj)->line = ruby_sourceline;
+#endif
+	return obj;
+}
+
+VALUE rb_data_object_alloc(klass, datap, dmark, dfree)
     VALUE klass;
     void *datap;
@@ -813,4 +869,71 @@
 }
 
+
+static int
+locate_pointer_on_heap(ptr)
+    void *ptr;
+{
+    register RVALUE *p = RANY(ptr);
+    register RVALUE *heap_org;
+    register long i;
+
+    if (p < lomem || p > himem) return -1;
+
+    /* check if p looks like a pointer */
+    for (i=0; i < heaps_used; i++) {
+	heap_org = heaps[i].slot;
+	if (heap_org <= p && p < heap_org + heaps[i].limit &&
+	    ((((char*)p)-((char*)heap_org))%sizeof(RVALUE)) == 0)
+	    return i;
+   }
+   return -1;
+}
+
+int gc_is_node_marked(void *p)
+{
+	unsigned char bit;
+	unsigned int offset;
+	int heap = locate_pointer_on_heap(p);
+
+	if ( heap == -1 ) {
+		fprintf(stderr, "couldn't find node.\n");
+		return 0;
+	}
+	offset = (RVALUE *)p - heaps[heap].slot;	
+	bit = *(heaps[heap].markfield + (offset / 8));
+	return bit & 1<<(offset % 8);
+}
+
+static int mark_node(void *p)
+{
+	unsigned char *bit;
+	unsigned int offset;
+	int heap = locate_pointer_on_heap(p);
+
+	if ( heap == -1 ) 
+		return 0;
+	
+	offset = (RVALUE *)p - heaps[heap].slot;	
+	bit = heaps[heap].markfield + (offset / 8);
+	*bit |= 1<<(offset % 8);
+	return 1;
+}
+
+static int unmark_node(void *p)
+{
+	unsigned char *bit;
+	unsigned int offset;
+	int heap = locate_pointer_on_heap(p);
+
+	if ( heap == -1 ) 
+		return 0;
+	
+	offset = (RVALUE *)p - heaps[heap].slot;	
+	bit = heaps[heap].markfield + (offset / 8);
+	*bit ^= 1<<(offset % 8);
+	return 1;
+}
+
+
 static void gc_mark _((VALUE ptr, int lev));
 static void gc_mark_children _((VALUE ptr, int lev));
@@ -826,6 +949,5 @@
 	p = heaps[i].slot; pend = p + heaps[i].limit;
 	while (p < pend) {
-	    if ((p->as.basic.flags & FL_MARK) &&
-		(p->as.basic.flags != FL_MARK)) {
+			if (gc_is_node_marked(p) && p->as.basic.flags != 0) {
 		gc_mark_children((VALUE)p, 0);
 	    }
@@ -968,8 +1090,11 @@
 
     obj = RANY(ptr);
-    if (rb_special_const_p(ptr)) return; /* special const not marked */
-    if (obj->as.basic.flags == 0) return;       /* free cell */
-    if (obj->as.basic.flags & FL_MARK) return;  /* already marked */
-    obj->as.basic.flags |= FL_MARK;
+	if (rb_special_const_p(ptr))
+		return;		/* special const not marked */
+	if (obj->as.basic.flags == 0)
+		return;		/* free cell */
+	if (gc_is_node_marked(obj))
+		return;
+	mark_node(obj);
 
     if (lev > GC_LEVEL_MAX || (lev == 0 && ruby_stack_check())) {
@@ -1006,8 +1131,11 @@
   again:
     obj = RANY(ptr);
-    if (rb_special_const_p(ptr)) return; /* special const not marked */
-    if (obj->as.basic.flags == 0) return;       /* free cell */
-    if (obj->as.basic.flags & FL_MARK) return;  /* already marked */
-    obj->as.basic.flags |= FL_MARK;
+	if (rb_special_const_p(ptr))
+		return;		/* special const not marked */
+	if (obj->as.basic.flags == 0)
+		return;		/* free cell */
+	if (gc_is_node_marked(obj))
+		return;		/* already marked */
+	mark_node(obj);
 
   marking:
@@ -1261,7 +1389,5 @@
 	run_final((VALUE)p);
 	if (!FL_TEST(p, FL_SINGLETON)) { /* not freeing page */
-	    p->as.free.flags = 0;
-	    p->as.free.next = freelist;
-	    freelist = p;
+			add_to_free_list(p, 0);
 	}
 	p = tmp;
@@ -1310,4 +1436,5 @@
 	if (heaps[i].limit == 0) {
 	    free(heaps[i].membase);
+			free(heaps[i].markfield);
 	    heaps_used--;
 	}
@@ -1323,9 +1450,225 @@
 void rb_gc_abort_threads(void);
 
-static void
-gc_sweep()
+char * node_type(int type)
+{
+    switch(type) { 
+    case NODE_METHOD:
+	return "NODE_METHOD";
+    case NODE_FBODY:
+	return "NODE_FBODY";
+    case NODE_CFUNC:
+	return "NODE_CFUNC";
+    case NODE_SCOPE:
+	return "NODE_SCOPE";
+    case NODE_BLOCK:
+	return "NODE_BLOCK";
+    case NODE_IF:
+	return "NODE_IF";
+    case NODE_CASE:
+	return "NODE_CASE";
+    case NODE_WHEN:
+	return "NODE_WHEN";
+    case NODE_OPT_N:
+	return "NODE_OPT_N";
+    case NODE_WHILE:
+	return "NODE_WHILE";
+    case NODE_UNTIL:
+	return "NODE_UNTIL";
+    case NODE_ITER:
+	return "NODE_ITER";
+    case NODE_FOR:
+	return "NODE_FOR";
+    case NODE_BREAK:
+	return "NODE_BREAK";
+    case NODE_NEXT:
+	return "NODE_NEXT";
+    case NODE_REDO:
+	return "NODE_REDO";
+    case NODE_RETRY:
+	return "NODE_RETRY";
+    case NODE_BEGIN:
+	return "NODE_BEGIN";
+    case NODE_RESCUE:
+	return "NODE_RESCUE";
+    case NODE_RESBODY:
+	return "NODE_RESBODY";
+    case NODE_ENSURE:
+	return "NODE_ENSURE";
+    case NODE_AND:
+	return "NODE_AND";
+    case NODE_OR:
+	return "NODE_OR";
+    case NODE_NOT:
+	return "NODE_NOT";
+    case NODE_MASGN:
+	return "NODE_MASGN";
+    case NODE_LASGN:
+	return "NODE_LASGN";
+    case NODE_DASGN:
+	return "NODE_DASGN";
+    case NODE_DASGN_CURR:
+	return "NODE_DASGN_CURR";
+    case NODE_GASGN:
+	return "NODE_GASGN";
+    case NODE_IASGN:
+	return "NODE_IASGN";
+    case NODE_CDECL:
+	return "NODE_CDECL";
+    case NODE_CVASGN:
+	return "NODE_CVASGN";
+    case NODE_CVDECL:
+	return "NODE_CVDECL";
+    case NODE_OP_ASGN1:
+	return "NODE_OP_ASGN1";
+    case NODE_OP_ASGN2:
+	return "NODE_OP_ASGN2";
+    case NODE_OP_ASGN_AND:
+	return "NODE_OP_ASGN_AND";
+    case NODE_OP_ASGN_OR:
+	return "NODE_OP_ASGN_OR";
+    case NODE_CALL:
+	return "NODE_CALL";
+    case NODE_FCALL:
+	return "NODE_FCALL";
+    case NODE_VCALL:
+	return "NODE_VCALL";
+    case NODE_SUPER:
+	return "NODE_SUPER";
+    case NODE_ZSUPER:
+	return "NODE_ZSUPER";
+    case NODE_ARRAY:
+	return "NODE_ARRAY";
+    case NODE_ZARRAY:
+	return "NODE_ZARRAY";
+    case NODE_HASH:
+	return "NODE_HASH";
+    case NODE_RETURN:
+	return "NODE_RETURN";
+    case NODE_YIELD:
+	return "NODE_YIELD";
+    case NODE_LVAR:
+	return "NODE_LVAR";
+    case NODE_DVAR:
+	return "NODE_DVAR";
+    case NODE_GVAR:
+	return "NODE_GVAR";
+    case NODE_IVAR:
+	return "NODE_IVAR";
+    case NODE_CONST:
+	return "NODE_CONST";
+    case NODE_CVAR:
+	return "NODE_CVAR";
+    case NODE_NTH_REF:
+	return "NODE_NTH_REF";
+    case NODE_BACK_REF:
+	return "NODE_BACK_REF";
+    case NODE_MATCH:
+	return "NODE_MATCH";
+    case NODE_MATCH2:
+	return "NODE_MATCH2";
+    case NODE_MATCH3:
+	return "NODE_MATCH3";
+    case NODE_LIT:
+	return "NODE_LIT";
+    case NODE_STR:
+	return "NODE_STR";
+    case NODE_DSTR:
+	return "NODE_DSTR";
+    case NODE_XSTR:
+	return "NODE_XSTR";
+    case NODE_DXSTR:
+	return "NODE_DXSTR";
+    case NODE_EVSTR:
+	return "NODE_EVSTR";
+    case NODE_DREGX:
+	return "NODE_DREGX";
+    case NODE_DREGX_ONCE:
+	return "NODE_DREGX_ONCE";
+    case NODE_ARGS:
+	return "NODE_ARGS";
+    case NODE_ARGSCAT:
+	return "NODE_ARGSCAT";
+    case NODE_ARGSPUSH:
+	return "NODE_ARGSPUSH";
+    case NODE_SPLAT:
+	return "NODE_SPLAT";
+    case NODE_TO_ARY:
+	return "NODE_TO_ARY";
+    case NODE_SVALUE:
+	return "NODE_SVALUE";
+    case NODE_BLOCK_ARG:
+	return "NODE_BLOCK_ARG";
+    case NODE_BLOCK_PASS:
+	return "NODE_BLOCK_PASS";
+    case NODE_DEFN:
+	return "NODE_DEFN";
+    case NODE_DEFS:
+	return "NODE_DEFS";
+    case NODE_ALIAS:
+	return "NODE_ALIAS";
+    case NODE_VALIAS:
+	return "NODE_VALIAS";
+    case NODE_UNDEF:
+	return "NODE_UNDEF";
+    case NODE_CLASS:
+	return "NODE_CLASS";
+    case NODE_MODULE:
+	return "NODE_MODULE";
+    case NODE_SCLASS:
+	return "NODE_SCLASS";
+    case NODE_COLON2:
+	return "NODE_COLON2";
+    case NODE_COLON3:
+	return "NODE_COLON3";
+    case NODE_CREF:
+	return "NODE_CREF";
+    case NODE_DOT2:
+	return "NODE_DOT2";
+    case NODE_DOT3:
+	return "NODE_DOT3";
+    case NODE_FLIP2:
+	return "NODE_FLIP2";
+    case NODE_FLIP3:
+	return "NODE_FLIP3";
+    case NODE_ATTRSET:
+	return "NODE_ATTRSET";
+    case NODE_SELF:
+	return "NODE_SELF";
+    case NODE_NIL:
+	return "NODE_NIL";
+    case NODE_TRUE:
+	return "NODE_TRUE";
+    case NODE_FALSE:
+	return "NODE_FALSE";
+    case NODE_DEFINED:
+	return "NODE_DEFINED";
+    case NODE_NEWLINE:
+	return "NODE_NEWLINE";
+    case NODE_POSTEXE:
+	return "NODE_POSTEXE";
+    case NODE_ALLOCA:
+	return "NODE_ALLOCA";
+    case NODE_DMETHOD:
+	return "NODE_DMETHOD";
+    case NODE_BMETHOD:
+	return "NODE_BMETHOD";
+    case NODE_MEMO:
+	return "NODE_MEMO";
+    case NODE_IFUNC:
+	return "NODE_IFUNC";
+    case NODE_DSYM:
+	return "NODE_DSYM";
+    case NODE_ATTRASGN:
+	return "NODE_ATTRASGN";
+    case NODE_LAST:
+	return "case NODE_LAST";
+    }
+}
+
+
+static void gc_sweep()
 {
     RVALUE *p, *pend, *final_list;
-    int freed = 0;
+	int freed_m = 0, freed_i = 0;
     int i;
     unsigned long live = 0;
@@ -1337,13 +1680,16 @@
     int do_gc_stats = gc_statistics & verbose_gc_stats;
 
-    for (i = 0; i < heaps_used; i++) {
-        free_min += heaps[i].limit;
-    }
-    free_min = free_min * 0.2;
-    if (free_min < heap_free_min)
+	// for (i = 0; i < heaps_used; i++) {
+// 		free_min += heaps[i].limit;
+// 	}
+//	free_min = free_min * 0.1;
+//	if (free_min < heap_free_min)
+
         free_min = heap_free_min;
 
     if (do_gc_stats) {
-	for (i = 0 ; i< 256; i++) { free_counts[i] = live_counts[i] = 0; }
+		for (i = 0; i < 256; i++) {
+			free_counts[i] = live_counts[i] = 0;
+		}
     }
 
@@ -1352,7 +1698,8 @@
            if yacc's semantic stack is not allocated on machine stack */
 	for (i = 0; i < heaps_used; i++) {
-	    p = heaps[i].slot; pend = p + heaps[i].limit;
+			p = heaps[i].slot;
+			pend = p + heaps[i].limit;
 	    while (p < pend) {
-		if (!(p->as.basic.flags&FL_MARK) && BUILTIN_TYPE(p) == T_NODE)
+				if (!(gc_is_node_marked(p)) && BUILTIN_TYPE(p) == T_NODE)
 		    gc_mark((VALUE)p, 0);
 		p++;
@@ -1366,15 +1713,42 @@
     }
 
-    freelist = 0;
+	freelist_mutable = 0;
+	freelist_immutable = 0;
     final_list = deferred_final_list;
     deferred_final_list = 0;
-    for (i = 0; i < heaps_used; i++) {
-	int n = 0;
-	RVALUE *free = freelist;
+	for (i = heaps_used - 1; i >= 0; i--) {
+		int n = 0, n_i = 0, n_m = 0, l=0;
+		RVALUE *free_mutable = freelist_mutable;
+		RVALUE *free_immutable = freelist_immutable;
 	RVALUE *final = final_list;
 
-	p = heaps[i].slot; pend = p + heaps[i].limit;
+		p = heaps[i].slot;
+		pend = p + heaps[i].limit;
+
+		if (heaps[i].frozen) {
+#ifdef	MUTATION_PROFILING
+			while (p < pend) {
+				RVALUE *old_node = heaps[i].last_state + (p - heaps[i].slot);
+				if ( memcmp(old_node, p, sizeof(RVALUE)) != 0 ) {
+					fprintf(stderr, "%x", TYPE(p));
+					if ( TYPE(p) == T_NODE ) { 
+						if ( nd_type(p) != nd_type(old_node) ) {
+							fprintf(stderr, "\tIGNORE");
+						} else {
+							fprintf(stderr, "\t%s", node_type(nd_type(p)));
+						}
+					}
+					fprintf(stderr, "\n");
+
+				}
+				p++;
+			}
+#endif
+			memset(heaps[i].markfield, 0, sizeof(unsigned char) * (heaps[i].limit + 1));
+			continue;
+		}
+
 	while (p < pend) {
-	    if (!(p->as.basic.flags & FL_MARK)) {
+			if (!gc_is_node_marked(p)) {
 		if (p->as.basic.flags) {
 		    obj_free((VALUE)p);
@@ -1383,10 +1757,12 @@
 		    }
 		}
+				
+				heaps[i].mutable ? n_m++ : n_i++;
+				
 		if (need_call_final && FL_TEST(p, FL_FINALIZE)) {
-		    p->as.free.flags = FL_MARK; /* remain marked */
+					mark_node(p);
 		    p->as.free.next = final_list;
 		    final_list = p;
-		}
-		else {
+				} else {
 		    if (do_gc_stats) {
 			int obt = p->as.basic.flags & T_MASK;
@@ -1395,17 +1771,12 @@
 			}
 		    }
-		    p->as.free.flags = 0;
-		    p->as.free.next = freelist;
-		    freelist = p;
-		}
-		n++;
+					add_to_free_list(p, heaps[i].mutable);
 	    }
-	    else if (RBASIC(p)->flags == FL_MARK) {
+			} else if (RBASIC(p)->flags == 0) {
 		/* objects to be finalized */
 		/* do nothing remain marked */
-	    }
-	    else {
-		RBASIC(p)->flags &= ~FL_MARK;
-		live++;
+			} else {
+				//unmark_node(p);	
+				live++; l++;
 		if (do_gc_stats) {
  		    live_counts[RANY((VALUE)p)->as.basic.flags & T_MASK]++;
@@ -1414,37 +1785,51 @@
 	    p++;
 	}
-	if (n == heaps[i].limit && freed > free_min) {
+
+		memset(heaps[i].markfield, 0, sizeof(unsigned char) * (heaps[i].limit + 1));
+		if ((n_i + n_m) == heaps[i].limit && (heaps[i].mutable ? freed_m > free_min  : freed_i > free_min)) {
+			/* heap is empty, ditch it. */
 	    RVALUE *pp;
 
+			fprintf(stderr, "freeing heap #%d\n", i);	
 	    heaps[i].limit = 0;
 	    for (pp = final_list; pp != final; pp = pp->as.free.next) {
 		pp->as.free.flags |= FL_SINGLETON; /* freeing page mark */
 	    }
-	    freelist = free;	/* cancel this page from freelist */
-	}
-	else {
-	    freed += n;
+
+			if ( heaps[i].mutable )
+				freelist_mutable = free_mutable;	/* cancel this page from freelist */
+			else
+				freelist_immutable = free_immutable;	/* cancel this page from freelist */
+		} else {
+			fprintf(stderr, "heap #%d (%s): %d of %d free, %d live\n", i, heaps[i].mutable ? "mutable" : "immutable", (n_i + n_m), heaps[i].limit, l);
+			freed_i += n_i;
+			freed_m += n_m;
 	}
     }
     if (malloc_increase > malloc_limit) {
-	malloc_limit += (malloc_increase - malloc_limit) * (double)live / (live + freed);
+	malloc_limit += (malloc_increase - malloc_limit) * (double)live / (live + freed_i + freed_m);
 	if (malloc_limit < initial_malloc_limit) malloc_limit = initial_malloc_limit;
     }
     malloc_increase = 0;
-    if (freed < free_min) {
-	add_heap();
-    }
+	if (freed_i < free_min)
+		add_heap(0);
+	if (freed_m < free_min)
+		add_heap(1);
     during_gc = 0;
 
     if (do_gc_stats) {
-	fprintf(gc_data_file, "objects processed: %.7d\n", live+freed);
+		fprintf(gc_data_file, "objects processed: %.7d\n",
+			live + freed_i + freed_m);
 	fprintf(gc_data_file, "live objects	: %.7d\n", live);
-	fprintf(gc_data_file, "freelist objects : %.7d\n", freed - really_freed);
-	fprintf(gc_data_file, "freed objects	: %.7d\n", really_freed);
+		fprintf(gc_data_file, "freelist objects : %.7d\n",
+			(freed_i + freed_m) - really_freed);
+		fprintf(gc_data_file, "freed objects	: %.7d\n",
+			really_freed);
 	for(i=0; i<256; i++) {
 	    if (free_counts[i]>0) {
 		fprintf(gc_data_file,
 			"kept %.7d / freed %.7d objects of type %s\n",
-			live_counts[i], free_counts[i], obj_type(i));
+					live_counts[i], free_counts[i],
+					obj_type(i));
 	    }
 	}
@@ -1459,11 +1844,12 @@
 }
 
-void
-rb_gc_force_recycle(p)
+void rb_gc_force_recycle(p)
     VALUE p;
 {
-    RANY(p)->as.free.flags = 0;
-    RANY(p)->as.free.next = freelist;
-    freelist = RANY(p);
+	int heap = locate_pointer_on_heap(RANY(p));
+	if ( heap != -1 )
+		add_to_free_list(RANY(p), heaps[heap].mutable);
+	else
+		add_to_free_list(RANY(p), 1);	
 }
 
@@ -1654,7 +2040,8 @@
 #endif
     if (dont_gc || during_gc) {
-	if (!freelist) {
-	    add_heap();
-	}
+		if (!freelist_immutable)
+			add_heap(0);
+		if (!freelist_mutable)
+			add_heap(1);
 	return;
     }
@@ -1795,6 +2182,29 @@
 }
 
-void
-ruby_set_stack_size(size)
+VALUE rb_gc_freeze()
+{
+	int i;
+	rb_gc();
+	/* TODO: make sure all the finalizers are called? */
+
+	for (i = 0; i < heaps_used; i++) {
+		if ( heaps[i].mutable == 0 ) {
+#ifdef	MUTATION_PROFILING
+			memcpy(heaps[i].last_state, heaps[i].slot, heaps[i].limit * sizeof(RVALUE));
+#endif
+			heaps[i].frozen = 1;
+		}
+	}
+
+	/* intentionally leak the memory on the freelist. */
+	freelist_immutable = NULL;
+	heap_slots = 10000;
+
+	add_heap(0);
+	return Qnil;
+}
+
+
+void ruby_set_stack_size(size)
     size_t size;
 {
@@ -1883,5 +2293,6 @@
     }
     set_gc_parameters();
-    add_heap();
+	add_heap(0);
+	add_heap(1);
 }
 
@@ -2350,4 +2761,5 @@
     rb_define_singleton_method(rb_mGC, "enable", rb_gc_enable, 0);
     rb_define_singleton_method(rb_mGC, "disable", rb_gc_disable, 0);
+	rb_define_singleton_method(rb_mGC, "freeze!", rb_gc_freeze, 0);
     rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0);
 
