Lots of fixes and updates for this queue, but nothing that *really* touches
authorjorendorff@mozilla.com
Wed, 28 Nov 2007 13:10:26 -0600
changeset 9 01b3ffa4acb6f282cd673c1ac70c925355b4b93d
parent 8 6e30b55406170d46017ea7e169b27bfba22e3e5f
child 10 c5dfb5bb8df559a5a7cb7fc23fa86f23c23e9d33
push id1
push userbsmedberg@mozilla.com
push dateMon, 21 Apr 2008 01:54:18 +0000
Lots of fixes and updates for this queue, but nothing that *really* touches code in any interesting way. Just administrivia.
DO-NOT-USE
mmgc-graphviz
mmgc-rm-isd
mmgc-threadsafe-take2
mmgc-threadsafe-v1
series
sm-features
deleted file mode 100644
--- a/DO-NOT-USE
+++ /dev/null
@@ -1,118 +0,0 @@
-diff --git a/MMgc/GC.cpp b/MMgc/GC.cpp
---- a/MMgc/GC.cpp
-+++ b/MMgc/GC.cpp
-@@ -2083,6 +2083,17 @@ bail:
- 
- #endif
- 
-+#ifdef MMGC_INTERIOR_PTRS
-+	inline bool IsLargeAllocPage(int bits) {
-+		return (bits == GC::kGCLargeAllocPageFirst
-+				|| bits == GC::kGCLargeAllocPageRest);
-+	}
-+#else
-+	inline bool IsLargeAllocPage(int bits) {
-+		return bits == GC::kGCLargeAllocPageFirst;
-+	}
-+#endif
-+
- 	void GC::MarkItem(GCWorkItem &wi, GCStack<GCWorkItem> &work)
- 	{
- 		size_t size = wi.GetSize();
-@@ -2131,27 +2142,32 @@ bail:
- 			// normalize and divide by 4K to get index
- 			int bits = GetPageMapValue(val); 
- 			
--			if (bits == 1)
-+			if (bits == kGCAllocPage)
- 			{
--				//GCAlloc::ConservativeMark(work, (void*) (val&~7), workitem.ptr);
--				const void* item = (void*) (val&~7);
--
--				GCAlloc::GCBlock *block = (GCAlloc::GCBlock*) ((uintptr) item & ~0xFFF);
--
-+				const void *item;
-+				GCAlloc::GCBlock *block = (GCAlloc::GCBlock*) (val & ~0xFFF);
-+
-+#ifdef MMGC_INTERIOR_PTRS
-+				item = (void*) val;
-+#else
- 				// back up to real beginning
--				item = GetRealPointer((const void*) item);
-+				item = GetRealPointer((const void*) (val & ~7));
-+#endif
- 
- 				// guard against bogus pointers to the block header
- 				if(item < block->items)
- 					continue;
- 
--				// make sure this is a pointer to the beginning
--
- 				int itemNum = GCAlloc::GetIndex(block, item);
--
-+#ifdef MMGC_INTERIOR_PTRS
-+				// adjust |item| to the beginning of the allocation
-+				item = block->items + itemNum * block->size;
-+#else
-+				// if |item| doesn't point to the beginning of an allocation,
-+				// it's not considered a pointer.
- 				if(block->items + itemNum * block->size != item)
- 					continue;
--
-+#endif
- 				if (m_edgeCallbacks)
- 					FireFoundEdgeTo(item);
- 
-@@ -2205,15 +2221,34 @@ bail:
- 					#endif
- 				}
- 			}
--			else if (bits == 3)
-+			else if (IsLargeAllocPage(bits))
- 			{
- 				//largeAlloc->ConservativeMark(work, (void*) (val&~7), workitem.ptr);
--				const void* item = (void*) (val&~7);
--
-+				const void* item;
-+
-+#ifdef MMGC_INTERIOR_PTRS
-+				if (bits == kGCLargeAllocPageFirst)
-+				{
-+					// guard against bogus pointers to the block header
-+					if ((val & 0xffff) < sizeof(GCLargeAlloc::LargeBlock))
-+						continue;
-+
-+					item = (void *) ((val & ~0xfff) |
-+									 sizeof(GCLargeAlloc::LargeBlock));
-+				}
-+				else
-+				{
-+					item = FindBeginning((void *) val);
-+				}
-+#else
- 				// back up to real beginning
--				item = GetRealPointer((const void*) item);
--
--				if(((uintptr) item & 0xfff) == sizeof(GCLargeAlloc::LargeBlock))
-+				item = GetRealPointer((const void*) (val & ~7));
-+
-+				// If |item| doesn't point to the start of the page, it's not
-+				// really a pointer.
-+				if(((uintptr) item & 0xfff) != sizeof(GCLargeAlloc::LargeBlock))
-+					continue;
-+#endif
- 				{
- 					if (m_edgeCallbacks)
- 						FireFoundEdgeTo(item);
-diff --git a/MMgc/GC.h b/MMgc/GC.h
---- a/MMgc/GC.h
-+++ b/MMgc/GC.h
-@@ -232,7 +232,7 @@ namespace MMgc
- 		 * corresponding methods of <code>class GC</code> are
- 		 * private.)
- 		 */
--		virtual void lastmark(GCStack<GCWorkItem> &work) {}
-+		virtual void lastmark(GCStack<GCWorkItem> &) {}
- 
- 		/**
- 		 * This method is invoked after all marking and before any
--- a/mmgc-graphviz
+++ b/mmgc-graphviz
@@ -6,28 +6,28 @@ diff --git a/MMgc/GC.cpp b/MMgc/GC.cpp
  		  disableThreadCheck(false)
  #endif
 +#ifdef MMGC_GRAPHVIZ
 +		  , m_gvFile(NULL)
 +#endif
  	{
  		// sanity check for all our types
  		GCAssert (sizeof(int8) == 1);
-@@ -352,6 +355,10 @@ namespace MMgc
- 
+@@ -361,6 +364,10 @@ namespace MMgc
+ 	
  	GC::~GC()
  	{
 +#ifdef MMGC_GRAPHVIZ
 +		StopGraphing();
 +#endif
 +
  		// Force all objects to be destroyed
  		destroying = true;
  		ClearMarks();
-@@ -545,7 +552,19 @@ namespace MMgc
+@@ -554,7 +561,19 @@ namespace MMgc
  				cb->enterExclusiveGCNoLock();
  		}
  
 +#ifdef MMGC_GRAPHVIZ
 +		if (m_gvFile) {
 +			fprintf(m_gvFile, "digraph C%d {\n", sweeps);
 +			fprintf(m_gvFile, "    node [shape=box];\n");
 +		}
@@ -37,17 +37,17 @@ diff --git a/MMgc/GC.cpp b/MMgc/GC.cpp
 +
 +#ifdef MMGC_GRAPHVIZ
 +		if (m_gvFile)
 +			fprintf(m_gvFile, "}\n");
 +#endif
  
  #ifdef MMGC_THREADSAFE
  		m_lock.Acquire();
-@@ -619,6 +638,46 @@ namespace MMgc
+@@ -628,6 +647,46 @@ namespace MMgc
  #endif
  	}
  
 +#define GRAPHVIZ_ROOT_STYLE "style=\"filled\", color=\"#ccddbb\""
 +#define GRAPHVIZ_OBJECT_STYLE "style=\"filled\", color=\"#b3cc99\""
 +#define GRAPHVIZ_CONSERVATIVE_EDGE_STYLE "color=\"#808080\""
 +
 +#ifdef MMGC_GRAPHVIZ
@@ -84,74 +84,74 @@ diff --git a/MMgc/GC.cpp b/MMgc/GC.cpp
 +		if (m_gvFile)
 +			fprintf(m_gvFile, "    P%p -> P%p [%s];\n", fromObj, toObj, style);
 +	}
 +#endif
 +
  	void GC::Trace(const void *stackStart/*=NULL*/, size_t stackSize/*=0*/)
  	{
  		ASSERT_EXCLUSIVE_GC();
-@@ -638,6 +697,16 @@ namespace MMgc
+@@ -647,6 +706,16 @@ namespace MMgc
  			GCRoot *r = m_roots;
  			while(r) {
  				GCWorkItem item = r->GetWorkItem();
 +#ifdef MMGC_GRAPHVIZ
 +				if (m_gvFile) {
 +					fprintf(m_gvFile,
 +							"    P%p [label=\"root at %p\", %s];\n",
 +							item.ptr,
 +							item.ptr,
 +							GRAPHVIZ_ROOT_STYLE);
 +				}
 +#endif
 +
  				MarkItem(item, work);
  				r = r->next;
  			}
-@@ -2248,7 +2317,6 @@ bail:
+@@ -2261,7 +2330,6 @@ bail:
  #undef ALLOCA_AND_FILL_WITH_SPACES
  #endif
  
 -
  	void GC::StartIncrementalMark()
  	{
  		GCAssert(!marking);
-@@ -2406,6 +2474,11 @@ bail:
+@@ -2419,6 +2487,11 @@ bail:
  
  	void GC::MarkItem(GCWorkItem &wi, GCStack<GCWorkItem> &work)
  	{
 +#ifdef MMGC_GRAPHVIZ
 +		if (wi.IsGCItem())
 +			GraphNode(wi.ptr, GRAPHVIZ_OBJECT_STYLE);
 +#endif
 +
  		size_t size = wi.GetSize();
  		uintptr *p = (uintptr*) wi.ptr;
  
-@@ -2486,6 +2559,9 @@ bail:
+@@ -2499,6 +2572,9 @@ bail:
  				{
  					if(block->alloc->ContainsPointers())
  					{
 +#ifdef MMGC_GRAPHVIZ
 +						GraphEdge(wi.ptr, p, item, GRAPHVIZ_CONSERVATIVE_EDGE_STYLE);
 +#endif
  						// try custom marking
  						if ((bits2 & (GCAlloc::kFinalize<<shift)) != 0
  							&& ((GCFinalizedObject *) GetUserPointer(item))->CustomMark())
-@@ -2545,6 +2621,9 @@ bail:
+@@ -2558,6 +2634,9 @@ bail:
  						size_t usize = b->usableSize;
  						if((b->flags & GCLargeAlloc::kContainsPointers) != 0) 
  						{
 +#ifdef MMGC_GRAPHVIZ
 +							GraphEdge(wi.ptr, p, item, GRAPHVIZ_CONSERVATIVE_EDGE_STYLE);
 +#endif
  							// try custom marking
  							if ((b->flags & GCLargeAlloc::kFinalizeFlag) != 0
  								&& ((GCFinalizedObject *) GetUserPointer(item))->CustomMark())
-@@ -3169,5 +3248,4 @@ bail:
+@@ -3182,5 +3261,4 @@ bail:
  	}
  #endif
  
 -
  }
 diff --git a/MMgc/GC.h b/MMgc/GC.h
 --- a/MMgc/GC.h
 +++ b/MMgc/GC.h
@@ -161,107 +161,38 @@ diff --git a/MMgc/GC.h b/MMgc/GC.h
  #define __GC__
 +
 +#ifdef MMGC_GRAPHVIZ
 +#include <typeinfo>
 +#endif
  
  #if defined MMGC_IA32
  
-@@ -1515,8 +1519,8 @@ private:
+@@ -1526,8 +1530,8 @@ private:
  #endif
  #endif
  
 -public:
  #ifdef MEMORY_INFO
 +	public:
  		void DumpBackPointerChain(void *o);
  
  		// debugging routine that records who marked who, can be used to
-@@ -1526,6 +1530,7 @@ public:
+@@ -1537,6 +1541,7 @@ public:
  		static void WriteBackPointer(const void *item, const void *container, size_t itemSize);
  #endif
  #ifdef _DEBUG
 +	public:
  		// Dump a list of objects that have pointers to the given location.
  		void WhosPointingAtMe(void* me, int recurseDepth=0, int currentDepth=0);
  
-@@ -1539,8 +1544,9 @@ public:
- #ifdef MMGC_THREADSAFE
- 	public:
- 		/**
--		 * True if marking or sweeping is happening.  This implies that no
--		 * threads in requests are running right now.
-+		 * True if marking or sweeping is happening.  In an MMGC_THREADSAFE
-+		 * build, this implies that no threads in requests are running right
-+		 * now.
- 		 *
- 		 * Contrast Collecting().
- 		 *
-@@ -1664,6 +1670,31 @@ public:
- 		GCThread *m_exclusiveGCThread;
- 
- 		/**
-+		 * This is notified whenever m_exclusiveGCThread becomes NULL.
-+		 *
-+		 * @access Requires(m_lock)
-+		 */
-+		GCCondition m_condDone;
-+
-+		/**
-+		 * The number of threads currently in active requests.
-+		 *
-+		 * @access Requires(m_lock)
-+		 */
-+		int m_requestCount;
-+
-+		/**
-+		 * This is notified whenever m_requestCount becomes zero.
-+		 *
-+		 * At most one thread is ever waiting on this condition at a time; if
-+		 * a thread is waiting on it, that thread is `m_exclusiveGCThread` and
-+		 * `m_gcRunning` is false.
-+		 *
-+		 * @access Requires(m_lock)
-+		 */
-+		GCCondition m_condNoRequests;
-+
-+		/**
- 		 * True if a thread is doing GC-related work, having already ensured
- 		 * that no threads are in active requests.
- 		 *
-@@ -1674,31 +1705,31 @@ public:
- 		 * @access ReadWrite(request || exclusiveGC || m_lock, exclusiveGC && m_lock)
+@@ -1720,6 +1725,31 @@ public:
+ 		 * @access Requires(m_lock)
  		 */
- 		bool m_gcRunning;
--
--		/**
--		 * This is notified whenever m_exclusiveGCThread becomes NULL.
--		 *
--		 * @access Requires(m_lock)
--		 */
--		GCCondition m_condDone;
--
--		/**
--		 * The number of threads currently in active requests.
--		 *
--		 * @access Requires(m_lock)
--		 */
--		int m_requestCount;
--
--		/**
--		 * This is notified whenever m_requestCount becomes zero.
--		 *
--		 * At most one thread is ever waiting on this condition at a time; if
--		 * a thread is waiting on it, that thread is `m_exclusiveGCThread` and
--		 * `m_gcRunning` is false.
--		 *
--		 * @access Requires(m_lock)
--		 */
--		GCCondition m_condNoRequests;
+ 		GCCondition m_condNoRequests;
 +#endif
 +
 +#ifdef MMGC_GRAPHVIZ
 +	public:
 +		void StartGraphing(const char *filename)
 +		{
 +			StopGraphing();
 +			m_gvFile = fopen(filename, "w");
deleted file mode 100644
--- a/mmgc-rm-isd
+++ /dev/null
@@ -1,15 +0,0 @@
-diff --git a/MMgc/GC.h b/MMgc/GC.h
---- a/MMgc/GC.h
-+++ b/MMgc/GC.h
-@@ -530,11 +530,6 @@ namespace MMgc
- 		bool validateDefRef;		
- 		bool keepDRCHistory;
- 
--		/**
--		 * incremental space divisor
--		 */
--		int ISD;
--
- 		size_t collectThreshold;
- 
- 		bool gcstats;
--- a/mmgc-threadsafe-take2
+++ b/mmgc-threadsafe-take2
@@ -41,27 +41,27 @@ diff --git a/MMgc/GC.cpp b/MMgc/GC.cpp
 +		  m_condNoRequests(m_lock)
 +#else
 +		  disableThreadCheck(false)
 +#endif
 +	{
  		// sanity check for all our types
  		GCAssert (sizeof(int8) == 1);
  		GCAssert (sizeof(uint8) == 1);		
-@@ -372,7 +396,9 @@ namespace MMgc
- 
- 		heap->Free(pageMap);
+@@ -385,7 +409,9 @@ namespace MMgc
+ 		delete [] msgBuf;
+ #endif
  
 +#ifndef MMGC_THREADSAFE
  		CheckThread();
 +#endif
  
  		GCAssert(!m_roots);
  		GCAssert(!m_callbacks);
-@@ -380,15 +406,43 @@ namespace MMgc
+@@ -393,15 +419,43 @@ namespace MMgc
  
  	void GC::Collect()
  	{
 +		CollectWithBookkeeping(false, false);
 +	}
 +
 +	void GC::CollectWithBookkeeping(bool callerHoldsLock,
 +									bool callerHasActiveRequest)
@@ -102,17 +102,17 @@ diff --git a/MMgc/GC.cpp b/MMgc/GC.cpp
 +			if (!callerHoldsLock)
 +				m_lock.Release();
 +			return;
 +		}
 +#else
  		if (vetoed || nogc || collecting) {
  
  			return;
-@@ -400,8 +454,136 @@ namespace MMgc
+@@ -413,8 +467,136 @@ namespace MMgc
  
  			return;
  		}
 -
 +#endif
 +
 +#ifdef MMGC_THREADSAFE
 +		GCThread *thisThread = GCThread::GetCurrentThread();
@@ -240,49 +240,49 @@ diff --git a/MMgc/GC.cpp b/MMgc/GC.cpp
 +	void GC::CollectImpl()
 +	{
 +#ifndef MMGC_THREADSAFE
  		ReapZCT();
 +#endif
  
  		// if we're in the middle of an incremental mark kill it
  		// FIXME: we should just push it to completion 
-@@ -428,8 +610,6 @@ namespace MMgc
+@@ -441,8 +623,6 @@ namespace MMgc
  		FindUnmarkedPointers();
  #endif
  
 -		CheckThread();
 -
  #ifdef DEBUGGER
  		StopGCActivity();
  #endif
-@@ -437,6 +617,8 @@ namespace MMgc
+@@ -450,6 +630,8 @@ namespace MMgc
  
  	void GC::Trace(const void *stackStart/*=NULL*/, size_t stackSize/*=0*/)
  	{
 +		ASSERT_EXCLUSIVE_GC();
 +
  		SAMPLE_FRAME("[mark]", core());
  
  		// Clear all mark bits.
-@@ -460,8 +642,11 @@ namespace MMgc
+@@ -473,8 +655,11 @@ namespace MMgc
  		SAMPLE_CHECK();
  
  		// invoke lastmark on all callbacks
 -		for (GCCallback *cb = m_callbacks; cb; cb = cb->nextCB)
 -			cb->lastmark(work);
 +		{
 +			USING_CALLBACK_LIST(this);
 +			for (GCCallback *cb = m_callbacks; cb; cb = cb->nextCB)
 +				cb->lastmark(work);
 +		}
  
  		if(stackStart == NULL) {
  			MarkQueueAndStack(work);
-@@ -476,6 +661,17 @@ namespace MMgc
+@@ -489,6 +674,17 @@ namespace MMgc
  
  	void *GC::Alloc(size_t size, int flags/*0*/, int skip/*3*/)
  	{
 +#ifdef MMGC_THREADSAFE
 +		GCAutoLock _lock(m_lock);
 +		GCAssert(!m_gcRunning);
 +#else
 +		CheckThread();
@@ -290,28 +290,28 @@ diff --git a/MMgc/GC.cpp b/MMgc/GC.cpp
 +		return AllocAlreadyLocked(size, flags, skip);
 +	}
 +
 +	void *GC::AllocAlreadyLocked(size_t size, int flags/*0*/, int skip/*3*/)
 +	{
  #ifdef DEBUGGER
  		avmplus::AvmCore *core = (avmplus::AvmCore*)GetGCContextVariable(GCV_AVMCORE);
  		if(core)
-@@ -487,9 +683,8 @@ namespace MMgc
+@@ -500,9 +696,8 @@ namespace MMgc
  
  #ifdef _DEBUG
  		GCAssert(size + 7 > size);
 -		CheckThread();
  		if (GC::greedy) {
 -			Collect();
 +			CollectWithBookkeeping(true, true);
  		}
  		// always be marking in pedantic mode
  		if(incrementalValidationPedantic) {
-@@ -572,15 +767,21 @@ namespace MMgc
+@@ -585,15 +780,21 @@ namespace MMgc
  
  	void GC::Free(void *item)
  	{
 +#ifdef MMGC_THREADSAFE
 +		GCAutoLock _lock(m_lock);
 +		GCAssert(!m_gcRunning);
 +#else
  		CheckThread();
@@ -329,46 +329,46 @@ diff --git a/MMgc/GC.cpp b/MMgc/GC.cpp
 -			return;
 -		}
 -
 -		bool isLarge;
 -
  		if(collecting) {
  			goto bail;
  		}
-@@ -629,6 +830,8 @@ bail:
+@@ -642,6 +843,8 @@ bail:
  
  	void GC::ClearMarks()
  	{
 +		ASSERT_EXCLUSIVE_GC();
 +
  		for (int i=0; i < kNumSizeClasses; i++) {
  #ifdef MMGC_DRC
  			containsPointersRCAllocs[i]->ClearMarks();
-@@ -641,6 +844,8 @@ bail:
+@@ -654,6 +857,8 @@ bail:
  
  	void GC::Finalize()
  	{
 +		ASSERT_EXCLUSIVE_GC();
 +
  		for(int i=kNumSizeClasses; i-- > 0;) {
  #ifdef MMGC_DRC
  			containsPointersRCAllocs[i]->Finalize();
-@@ -662,7 +867,9 @@ bail:
+@@ -675,7 +880,9 @@ bail:
  	}
  
  	void GC::Sweep(bool force)
 -	{	
 +	{
 +		ASSERT_EXCLUSIVE_GC();
 +
  		SAMPLE_FRAME("[sweep]", core());
  		sweeps++;
  
-@@ -681,10 +888,13 @@ bail:
+@@ -694,10 +901,13 @@ bail:
  		collecting = true;
  
  		// invoke presweep on all callbacks
 -		GCCallback *cb = m_callbacks;
 -		while(cb) {
 -			cb->presweep();
 -			cb = cb->nextCB;
 +		{
@@ -376,17 +376,17 @@ diff --git a/MMgc/GC.cpp b/MMgc/GC.cpp
 +			GCCallback *cb = m_callbacks;
 +			while(cb) {
 +				cb->presweep();
 +				cb = cb->nextCB;
 +			}
  		}
  
  		SAMPLE_CHECK();
-@@ -737,12 +947,15 @@ bail:
+@@ -750,12 +960,15 @@ bail:
  		collecting = false;
  
  		// invoke postsweep callback
 -		cb = m_callbacks;
 -		while(cb) {
 -			cb->postsweep();
 -			cb = cb->nextCB;
 -		}
@@ -398,129 +398,129 @@ diff --git a/MMgc/GC.cpp b/MMgc/GC.cpp
 +				cb->postsweep();
 +				cb = cb->nextCB;
 +			}
 +		}
 +
  		SAMPLE_CHECK();
  
  		allocsSinceCollect = 0;
-@@ -779,6 +992,7 @@ bail:
+@@ -792,6 +1005,7 @@ bail:
  
  	void* GC::AllocBlock(int size, int pageType, bool zero)
  	{
 +		ASSERT_GC_LOCK();
  #ifdef DEBUGGER
  		AllocActivity(size);
  #endif
-@@ -796,7 +1010,7 @@ bail:
+@@ -809,7 +1023,7 @@ bail:
  			if(incremental)
  				StartIncrementalMark();
  			else
 -				Collect();
 +				CollectWithBookkeeping(true, true);
  		}
  
  		void *item;
-@@ -837,6 +1051,8 @@ bail:
+@@ -850,6 +1064,8 @@ bail:
  
  	void* GC::AllocBlockIncremental(int size, bool zero)
  	{
 +		ASSERT_GC_LOCK();
 +
  		if(!nogc && !collecting) {
  			uint64 now = GetPerformanceCounter();
  			if (marking) {		
-@@ -864,12 +1080,14 @@ bail:
+@@ -877,12 +1093,14 @@ bail:
  
  	void* GC::AllocBlockNonIncremental(int size, bool zero)
  	{
 +		ASSERT_GC_LOCK();
 +
  		void *item = heap->Alloc(size, false, zero);
  		if (!item) {
  			if (heap->GetTotalHeapSize() >= collectThreshold &&
  				allocsSinceCollect >= totalGCPages / kFreeSpaceDivisor) 
  			{
 -				Collect();
 +				CollectWithBookkeeping(true, true);
  				item = heap->Alloc(size, false, zero);
  			}
  		}
-@@ -878,6 +1096,11 @@ bail:
+@@ -891,6 +1109,11 @@ bail:
  
  	void GC::FreeBlock(void *ptr, uint32 size)
  	{
 +#ifdef MMGC_THREADSAFE
 +		GCAssert(m_lock.IsHeld() || destroying
 +				 || (m_gcRunning
 +					 && m_exclusiveGCThread == GCThread::GetCurrentThread()));
 +#endif
  #ifdef DEBUGGER
  		AllocActivity(- (int)size);
  #endif
-@@ -905,6 +1128,7 @@ bail:
+@@ -918,6 +1141,7 @@ bail:
  
  	void GC::Mark(GCStack<GCWorkItem> &work)
  	{
 +		ASSERT_EXCLUSIVE_GC();
  		while(work.Count()) {
  			MarkItem(work);
  		}
-@@ -912,6 +1136,7 @@ bail:
+@@ -925,6 +1149,7 @@ bail:
  
  	void GC::MarkGCPages(void *item, uint32 numPages, int to)
  	{
 +		USING_PAGE_MAP();
  		uintptr addr = (uintptr)item;
  		uint32 shiftAmount=0;
  		unsigned char *dst = pageMap;
-@@ -954,7 +1179,7 @@ bail:
+@@ -967,7 +1192,7 @@ bail:
  		addr = (uintptr)item;
  		while(numPages--)
  		{
 -			GCAssert(GetPageMapValue(addr) == 0);
 +			GCAssert(GetPageMapValueAlreadyLocked(addr) == 0);
  			SetPageMapValue(addr, to);
  			addr += GCHeap::kBlockSize;
  		}
-@@ -963,6 +1188,8 @@ bail:
+@@ -976,6 +1201,8 @@ bail:
  	void GC::UnmarkGCPages(void *item, uint32 numpages)
  	{
  		uintptr addr = (uintptr) item;
 +
 +		USING_PAGE_MAP();
  		while(numpages--)
  		{
  			ClearPageMapValue(addr);
-@@ -1128,6 +1355,7 @@ bail:
+@@ -1141,6 +1368,7 @@ bail:
  		gc->Mark(work);
  	}
  
 +#ifndef MMGC_THREADSAFE
  	void GC::CheckThread()
  	{
  #ifdef _DEBUG
-@@ -1136,12 +1364,13 @@ bail:
+@@ -1149,12 +1377,13 @@ bail:
  #endif
  #endif
  	}
 -
 +#endif
  
  	bool GC::IsPointerToGCPage(const void *item)
  	{
 +		USING_PAGE_MAP();
  		if((uintptr)item >= memStart && (uintptr)item < memEnd)
 -			return GetPageMapValue((uintptr) item) != 0;
 +			return GetPageMapValueAlreadyLocked((uintptr) item) != 0;
  		return false;
  	}
  
-@@ -1182,10 +1411,13 @@ bail:
+@@ -1195,10 +1424,13 @@ bail:
  		// note if we add things while reaping we could delete the object
  		// here if we had a way to monitor our stack usage
  		if(reaping && PLENTY_OF_STACK()) {
 -			GCCallback *cb = gc->m_callbacks;
 -			while(cb) {
 -				cb->prereap(obj);
 -				cb = cb->nextCB;
 +			{
@@ -528,17 +528,17 @@ diff --git a/MMgc/GC.cpp b/MMgc/GC.cpp
 +				GCCallback *cb = gc->m_callbacks;
 +				while(cb) {
 +					cb->prereap(obj);
 +					cb = cb->nextCB;
 +				}
  			}
  			if(gc->IsFinalized(obj))
  				((GCFinalizedObject*)obj)->~GCFinalizedObject();
-@@ -1376,10 +1608,13 @@ bail:
+@@ -1389,10 +1621,13 @@ bail:
  		nextPinnedIndex = 0;
  
  		// invoke prereap on all callbacks
 -		GCCallback *cb = gc->m_callbacks;
 -		while(cb) {
 -			cb->prereap();
 -			cb = cb->nextCB;
 +		{
@@ -546,17 +546,17 @@ diff --git a/MMgc/GC.cpp b/MMgc/GC.cpp
 +			GCCallback *cb = gc->m_callbacks;
 +			while(cb) {
 +				cb->prereap();
 +				cb = cb->nextCB;
 +			}
  		}
  
  #ifdef _DEBUG
-@@ -1420,10 +1655,13 @@ bail:
+@@ -1433,10 +1668,13 @@ bail:
  				}
  #endif
  				// invoke prereap on all callbacks
 -				GCCallback *cbb = gc->m_callbacks;
 -				while(cbb) {
 -					cbb->prereap(rcobj);
 -					cbb = cbb->nextCB;
 +				{
@@ -564,17 +564,17 @@ diff --git a/MMgc/GC.cpp b/MMgc/GC.cpp
 +					GCCallback *cbb = gc->m_callbacks;
 +					while(cbb) {
 +						cbb->prereap(rcobj);
 +						cbb = cbb->nextCB;
 +					}
  				}
  
  				GCAssert(*(int*)rcobj != 0);
-@@ -1457,10 +1695,13 @@ bail:
+@@ -1470,10 +1708,13 @@ bail:
  		zctIndex = nextPinnedIndex = 0;
  
  		// invoke postreap on all callbacks
 -		cb = gc->m_callbacks;
 -		while(cb) {
 -			cb->postreap();
 -			cb = cb->nextCB;
 +		{
@@ -582,27 +582,27 @@ diff --git a/MMgc/GC.cpp b/MMgc/GC.cpp
 +			GCCallback *cb = gc->m_callbacks;
 +			while(cb) {
 +				cb->postreap();
 +				cb = cb->nextCB;
 +			}
  		}
  #ifdef DEBUGGER
  		if(gc->gcstats && numObjects) {
-@@ -1607,7 +1848,8 @@ bail:
+@@ -1620,7 +1861,8 @@ bail:
  		va_end(argptr);
  
  		GCAssert(strlen(buf) < 4096);
 -			
 +
 +		USING_CALLBACK_LIST(this);
  		GCCallback *cb = m_callbacks;
  		while(cb) {
  			cb->log(buf);
-@@ -1659,23 +1901,27 @@ bail:
+@@ -1672,23 +1914,27 @@ bail:
  
  	bool GC::IsRCObject(const void *item)
  	{
 -		if((uintptr)item >= memStart && (uintptr)item < memEnd && ((uintptr)item&0xfff) != 0)
 -		{
 -			int bits = GetPageMapValue((uintptr)item);		
 -			item = GetRealPointer(item);
 -			switch(bits)
@@ -636,169 +636,169 @@ diff --git a/MMgc/GC.cpp b/MMgc/GC.cpp
 +		case kGCLargeAllocPageFirst:
 +			return GCLargeAlloc::IsRCObject(item);
 +		default:
 +			return false;
 +		}
  	}
  
  #endif // MMGC_DRC
-@@ -1761,7 +2007,7 @@ bail:
+@@ -1774,7 +2020,7 @@ bail:
  				continue;
  			
  			// normalize and divide by 4K to get index
 -			int bits = GetPageMapValue(val);
 +			int bits = GetPageMapValueAlreadyLocked(val);
  			switch(bits)
  			{
  			case 0:
-@@ -1782,6 +2028,8 @@ bail:
+@@ -1795,6 +2041,8 @@ bail:
  
  	void GC::FindUnmarkedPointers()
  	{
 +		ASSERT_EXCLUSIVE_GC();
 +
  		if(findUnmarkedPointers)
  		{
  			uintptr m = memStart;
-@@ -1920,6 +2168,11 @@ bail:
+@@ -1933,6 +2181,11 @@ bail:
  	 */
  	void GC::WhosPointingAtMe(void* me, int recurseDepth, int currentDepth)
  	{
 +#ifdef MMGC_THREADSAFE
 +		if (currentDepth == 0)
 +			pageMapLock.Acquire();
 +#endif
 +
  		uintptr val = (uintptr)me;
  		uintptr m = memStart;
  
-@@ -1942,7 +2195,7 @@ bail:
+@@ -1955,7 +2208,7 @@ bail:
  #endif
  
  			// divide by 4K to get index
 -			int bits = GetPageMapValue(m);
 +			int bits = GetPageMapValueAlreadyLocked(m);
  			if(bits == kNonGC) 
  			{
  				ProbeForMatch((const void*)m, GCHeap::kBlockSize, val, recurseDepth, currentDepth);
-@@ -1986,6 +2239,11 @@ bail:
+@@ -1999,6 +2252,11 @@ bail:
  			
  			}
  		}
 +
 +#ifdef MMGC_THREADSAFE
 +		if (currentDepth == 0)
 +			pageMapLock.Release();
 +#endif
  	}
  #undef ALLOCA_AND_FILL_WITH_SPACES
  #endif
-@@ -2354,9 +2612,11 @@ bail:
+@@ -2367,9 +2625,11 @@ bail:
  		return 1000000;
  		#endif
  	}
 -	
 +
  	void GC::IncrementalMark(uint32 time)
  	{
 +		ASSERT_EXCLUSIVE_GC();
 +
  		SAMPLE_FRAME("[mark]", core());
  		if(m_incrementalWork.Count() == 0 || hitZeroObjects) {
  			FinishIncrementalMark();
-@@ -2411,6 +2671,8 @@ bail:
+@@ -2424,6 +2684,8 @@ bail:
  
  	void GC::FinishIncrementalMark()
  	{
 +		ASSERT_EXCLUSIVE_GC();
 +
  		// Don't finish an incremental mark (i.e., sweep) if we
  		// are in the midst of a ZCT reap.
  		if (zct.reaping)
-@@ -2442,8 +2704,11 @@ bail:
+@@ -2455,8 +2717,11 @@ bail:
  		}
  
  		// invoke lastmark on all callbacks
 -		for (GCCallback *cb = m_callbacks; cb; cb = cb->nextCB)
 -			cb->lastmark(m_incrementalWork);
 +		{
 +			USING_CALLBACK_LIST(this);
 +			for (GCCallback *cb = m_callbacks; cb; cb = cb->nextCB)
 +				cb->lastmark(m_incrementalWork);
 +		}
  
  		MarkQueueAndStack(m_incrementalWork);
  
-@@ -2594,6 +2859,7 @@ bail:
+@@ -2607,6 +2872,7 @@ bail:
  	{
  		uint32 *bits;
  
 +		ASSERT_GC_LOCK();
  		GCAssert(numBytes % 4 == 0);
  
  		#ifdef MMGC_64BIT // we use first 8-byte slot for the free list
-@@ -2665,7 +2931,8 @@ bail:
+@@ -2678,7 +2944,8 @@ bail:
  
  	void GC::AddCallback(GCCallback *cb)
  	{
 -		CheckThread();
 +		USING_CALLBACK_LIST(this);
 +
  		cb->prevCB = NULL;
  		cb->nextCB = m_callbacks;
  		if(m_callbacks)
-@@ -2675,7 +2942,8 @@ bail:
+@@ -2688,7 +2955,8 @@ bail:
  
  	void GC::RemoveCallback(GCCallback *cb)
  	{
 -		CheckThread();
 +		USING_CALLBACK_LIST(this);
 +
  		if( m_callbacks == cb )
  			m_callbacks = cb->nextCB;
  		else
-@@ -2687,7 +2955,8 @@ bail:
+@@ -2700,7 +2968,8 @@ bail:
  
  	void GC::AddEdgeCallback(GCEdgeCallback *cb)
  	{
 -		CheckThread();
 +		USING_CALLBACK_LIST(this);
 +
  		cb->prevCB = NULL;
  		cb->nextCB = m_edgeCallbacks;
  		if(m_edgeCallbacks)
-@@ -2697,7 +2966,8 @@ bail:
+@@ -2710,7 +2979,8 @@ bail:
  
  	void GC::RemoveEdgeCallback(GCEdgeCallback *cb)
  	{
 -		CheckThread();
 +		USING_CALLBACK_LIST(this);
 +
  		if( m_edgeCallbacks == cb )
  			m_edgeCallbacks = cb->nextCB;
  		else
-@@ -2709,12 +2979,12 @@ bail:
+@@ -2722,12 +2992,12 @@ bail:
  
  	void GC::FireFoundEdgeTo(const void *p)
  	{
 +		// Don't acquire the spinlock here because (a) that would really hurt
 +		// performance; (b) the m_edgeCallbacks list, unlike the m_callbacks
 +		// list, is protected by the request model.
  		p = GetUserPointer(p);
 -		GCEdgeCallback *cb = m_edgeCallbacks;
 -		while(cb) {
 +		for (GCEdgeCallback *cb = m_edgeCallbacks; cb; cb = cb->nextCB)
  			cb->foundEdgeTo(p);
 -			cb = cb->nextCB;
 -		}
  	}
  
  	void GC::PushWorkItem(GCStack<GCWorkItem> &stack, GCWorkItem item)
-@@ -2727,9 +2997,18 @@ bail:
+@@ -2740,9 +3010,18 @@ bail:
  	GCWeakRef* GC::GetWeakRef(const void *item) 
  	{
  		GC *gc = GetGC(item);
 +#ifdef MMGC_THREADSAFE
 +		GCAutoLock _lock(gc->m_lock);
 +#endif
  		GCWeakRef *ref = (GCWeakRef*) gc->weakRefs.get(item);
 +
@@ -807,42 +807,42 @@ diff --git a/MMgc/GC.cpp b/MMgc/GC.cpp
 +			void *p = gc->AllocAlreadyLocked(sizeof(GCWeakRef), GC::kFinalize, 4);
 +			ref = new (p) GCWeakRef(item);
 +#else
  			ref = new (gc) GCWeakRef(item);
 +#endif
  			gc->weakRefs.put(item, ref);
  			item = GetRealPointer(item);
  			if (GCLargeAlloc::IsLargeBlock(item)) {
-@@ -2789,6 +3068,8 @@ bail:
+@@ -2802,6 +3081,8 @@ bail:
  
  	void GC::FindMissingWriteBarriers()
  	{
 +		ASSERT_EXCLUSIVE_GC();
 +
  		if(!incrementalValidation)
  			return;
  
-@@ -2850,6 +3131,7 @@ bail:
+@@ -2863,6 +3144,7 @@ bail:
  	void GC::StartGCActivity()
  	{
  		// invoke postsweep callback
 +		USING_CALLBACK_LIST(this);
  		GCCallback *cb = m_callbacks;
  		while(cb) {
  			cb->startGCActivity();
-@@ -2860,6 +3142,7 @@ bail:
+@@ -2873,6 +3155,7 @@ bail:
  	void GC::StopGCActivity()
  	{
  		// invoke postsweep callback
 +		USING_CALLBACK_LIST(this);
  		GCCallback *cb = m_callbacks;
  		while(cb) {
  			cb->stopGCActivity();
-@@ -2870,6 +3153,7 @@ bail:
+@@ -2883,6 +3166,7 @@ bail:
  	void GC::AllocActivity(int blocks)
  	{
  		// invoke postsweep callback
 +		USING_CALLBACK_LIST(this);
  		GCCallback *cb = m_callbacks;
  		while(cb) {
  			cb->allocActivity(blocks);
 diff --git a/MMgc/GC.h b/MMgc/GC.h
@@ -991,19 +991,19 @@ diff --git a/MMgc/GC.h b/MMgc/GC.h
  		/**
  		 * nogc is a debugging flag.  When set, garbage collection
  		 * never happens.
 +		 *
 +		 * @access Requires(m_lock)
  		 */
  		bool nogc;
  
-@@ -530,8 +603,28 @@ namespace MMgc
- 		bool validateDefRef;		
- 		bool keepDRCHistory;
+@@ -535,8 +608,28 @@ namespace MMgc
+ 		 */
+ 		int ISD;
  
 +		/**
 +		 * Expand, don't collect, until we reach this threshold. Units are
 +		 * pages, not KB, just like GCHeap::GetTotalHeapSize().
 +		 *
 +		 * In an MMGC_THREADSAFE build, the GC reads this configuration value
 +		 * only when holding the GC lock.  Set it during
 +		 * initialization, before the GC is visible to multiple threads.
@@ -1020,47 +1020,47 @@ diff --git a/MMgc/GC.h b/MMgc/GC.h
 +		 * stop-the-world collection.  Set it during initialization, before
 +		 * the GC is visible to multiple threads.
 +		 *
 +		 * @access Requires(exclusiveGC)
 +		 */
  		bool gcstats;
  
  		bool dontAddToZCTDuringCollection;
-@@ -541,6 +634,14 @@ namespace MMgc
+@@ -546,6 +639,14 @@ namespace MMgc
  		bool incrementalValidationPedantic;
  #endif
  
 +		/**
 +		 * Configuration flag enabling incremental collection.
 +		 *
 +		 * In an MMGC_THREADSAFE build, the GC reads this flag only when
 +		 * holding the GC lock.  Set it during initialization.
 +		 *
 +		 * @access Requires(m_lock)
 +		 */
  		bool incremental;
  
  		// -- Interface
-@@ -548,7 +649,13 @@ namespace MMgc
+@@ -553,7 +654,13 @@ namespace MMgc
  		virtual ~GC();
  		
  		/**
 -		 * Causes an immediate garbage collection
 +		 * Causes an immediate garbage collection.
 +		 *
 +		 * In an MMGC_THREADSAFE build, the caller must not be inside a
 +		 * request.  If the caller is inside a request, call
 +		 * CollectFromRequest() instead.
 +		 *
 +		 * @access Requires(!m_lock && !request)
  		 */
  		void Collect();
  
-@@ -573,15 +680,26 @@ namespace MMgc
+@@ -578,15 +685,26 @@ namespace MMgc
  
  		/**
  		 * Main interface for allocating memory.  Default flags is no
 -		 * finalization, contains pointers is set and zero is set
 +		 * finalization, contains pointers is set and zero is set.
 +		 *
 +		 * Do not call this from a finalizer.
 +		 *
@@ -1078,57 +1078,57 @@ diff --git a/MMgc/GC.h b/MMgc/GC.h
  		 * Calloc(num, sizeof(thing))
 +		 *
 +		 * Do not call this from a finalizer.
 +		 *
 +		 * @access Requires(request)
  		 */
  		void *Calloc(size_t num, size_t elsize, int flags=0, int skip=3);
  
-@@ -589,11 +707,15 @@ namespace MMgc
+@@ -594,11 +712,15 @@ namespace MMgc
  		 * One can free a GC allocated pointer, this will throw an assertion
  		 * if called during the Sweep phase (ie via a finalizer) it can only be
  		 * used outside the scope of a collection
 +		 *
 +		 * @access Requires(request)
  		 */
  		void Free(void *ptr);
  
  		/**
  		 * return the size of a piece of memory, may be bigger than what was asked for
 +		 *
 +		 * @access Requires(request || exclusiveGC)
  		 */
  		static size_t Size(const void *ptr)
  		{
-@@ -607,6 +729,8 @@ namespace MMgc
+@@ -612,6 +734,8 @@ namespace MMgc
  		/**
  		 * Tracers should employ GetMark and SetMark to
  		 * set the mark bits during the mark pass.
 +		 *
 +		 * @access Requires(request || exclusiveGC)
  		 */
  		static int GetMark(const void *item)
  		{
-@@ -713,9 +837,13 @@ namespace MMgc
+@@ -718,9 +842,13 @@ namespace MMgc
  		}
  
  		/**
 -		 * Used by sub-allocators to obtain memory
 +		 * Used by sub-allocators to obtain memory.
 +		 *
 +		 * @access Requires(m_lock)
  		 */
  		void* AllocBlock(int size, int pageType, bool zero=true);
 +
 +		/** @access Requires((request && m_lock) || exclusiveGC) */
  		void FreeBlock(void *ptr, uint32 size);
  
  		GCHeap *GetGCHeap() const { return heap; }
-@@ -743,11 +871,19 @@ namespace MMgc
+@@ -748,11 +876,19 @@ namespace MMgc
  		 */
  		bool IncrementalMarking() { return marking; }
  
 -		// a magical write barriers that finds the container's address and the GC, just
 -		// make sure address is a pointer to a GC page, only used by WB smart pointers
 +		/**
 +		 * A magical write barrier that finds the container's address and the
 +		 * GC, just make sure @a address is a pointer to a GC page. Only used
@@ -1140,17 +1140,17 @@ diff --git a/MMgc/GC.h b/MMgc/GC.h
 +
 +		/** @access Requires(request) */
  		static void WriteBarrierNoSub(const void *address, const void *value);
  
 +		/** @access Requires(request) */
  		void writeBarrier(const void *container, const void *address, const void *value)
  		{
  			GCAssert(IsPointerToGCPage(container));
-@@ -759,13 +895,19 @@ namespace MMgc
+@@ -764,13 +900,19 @@ namespace MMgc
  			WriteBarrierWrite(address, value);
  		}
  
 -		// optimized version with no RC checks or pointer masking
 +		/**
 +		 * optimized version with no RC checks or pointer masking
 +		 *
 +		 * @access Requires(request)
@@ -1164,43 +1164,43 @@ diff --git a/MMgc/GC.h b/MMgc/GC.h
 +		 * Write barrier when the value could be a pointer with anything in the lower 3 bits
 +		 * FIXME: maybe assert that the lower 3 bits are either zero or a pointer type signature,
 +		 * this would require the application to tell us what bit patterns are pointers.
 +		 *
 +		 * @access Requires(request)
  		 */
  		__forceinline void WriteBarrierNoSubstitute(const void *container, const void *value)
  		{
-@@ -773,9 +915,11 @@ namespace MMgc
+@@ -778,9 +920,11 @@ namespace MMgc
  		}
  			
  		/**
 -		 AVM+ write barrier, valuePtr is known to be pointer and the caller
 -		does the write
 -		*/
 +		 * AVM+ write barrier, valuePtr is known to be pointer and the caller
 +		 * does the write.
 +		 *
 +		 * @access Requires(request)
 +		 */
  		__forceinline void WriteBarrierTrap(const void *container, const void *valuePtr)
  		{
  			GCAssert(IsPointerToGCPage(container));
-@@ -799,8 +943,10 @@ namespace MMgc
+@@ -804,8 +948,10 @@ namespace MMgc
  
  	public:
  
 +		/** @access Requires(request || exclusiveGC) */
  		bool ContainsPointers(const void *item);
  
 +		/** @access Requires(request) */
  		void *FindBeginning(const void *gcItem)
  		{
  			GCAssert(gcItem != NULL);
-@@ -836,11 +982,23 @@ namespace MMgc
+@@ -841,11 +987,23 @@ namespace MMgc
  		bool IsRCObject(const void *) { return false; }
  #endif
  
 -
 -		bool Collecting() const { return collecting; }
 -
 +		/**
 +		 * True during Sweep phase.  Application code can use this to
@@ -1217,40 +1217,41 @@ diff --git a/MMgc/GC.h b/MMgc/GC.h
 +
 +		/** @access Requires(request || exclusiveGC) */
  		bool IsGCMemory (const void *);
  
 +		/** @access Requires(request || exclusiveGC) */
  		bool IsQueued(const void *item);
  
  		static uint64 GetPerformanceCounter();
-@@ -851,30 +1009,80 @@ namespace MMgc
+@@ -856,9 +1014,12 @@ namespace MMgc
  			return (double(GC::GetPerformanceCounter() - start) * 1000) / GC::GetPerformanceFrequency();
  		}
  
 +#ifndef MMGC_THREADSAFE
  		void DisableThreadCheck() { disableThreadCheck = true; }
 -		
 -		uint64 t0;
 +#endif
 +
 +		/** GC initialization time, in ticks.  Used for logging. */
 +		const uint64 t0;
  
- 		static uint64 ticksToMicros(uint64 ticks) { return (ticks*1000000)/GetPerformanceFrequency(); }
- 
+ #ifdef _DEBUG
+ 		char *msgBuf;
+@@ -870,21 +1031,69 @@ namespace MMgc
  		static uint64 ticksToMillis(uint64 ticks) { return (ticks*1000)/GetPerformanceFrequency(); }
  
--		// marking rate counter
+ 		// marking rate counter
 +		/**
 +		 * Total number of bytes of pointer-containing memory scanned by this
 +		 * GC.  Used to measure marking rate, which is
 +		 * <code>bytesMarked/ticksToMillis(markTicks)</code>.
 +		 *
-+		 * @access ReadWrite(request, exclusiveGC)
++		 * @access ReadWrite(request, exclusiveGC);
 +		 */
  		uint64 bytesMarked;
 +
 +		/**
 +		 * Total time spent doing incremental marking, in ticks.  See
 +		 * bytesMarked.
 +		 *
 +		 * @access ReadWrite(request, exclusiveGC)
@@ -1261,23 +1262,25 @@ diff --git a/MMgc/GC.h b/MMgc/GC.h
  		uint32 lastStartMarkIncrementCount;
  		uint32 markIncrements;
 +
 +		/**
 +		 * Number of calls to MarkItem().
 +		 * @access ReadWrite(request, exclusiveGC)
 +		 */
  		uint32 marks;
+-        uint32 sweeps;
+-
 +
 +		/**
 +		 * Number of calls to Sweep().
 +		 * @access ReadWrite(request, exclusiveGC)
 +		 */
-         uint32 sweeps;
- 
++		uint32 sweeps;
++
 +		/**
 +		 * Number of calls to MarkItem() during the current (or most recent)
 +		 * IncrementalMark().
 +		 *
 +		 * @access ReadWrite(request, exclusiveGC)
 +		 */
  		uint32 numObjects;
 +
@@ -1302,36 +1305,36 @@ diff --git a/MMgc/GC.h b/MMgc/GC.h
 +		 * incremental mark.  This means the next mark will force the GC cycle
 +		 * through to completion.
 +		 *
 +		 * @access ReadWrite(request, exclusiveGC)
 +		 */
  		bool hitZeroObjects;
  
  		// called at some apropos moment from the mututor, ideally at a point
-@@ -886,6 +1094,7 @@ namespace MMgc
+@@ -896,6 +1105,7 @@ namespace MMgc
  
  		bool Destroying() { return destroying; }
  
 +		/** @access Requires((request && m_lock) || exclusiveGC) */
  		void ClearWeakRef(const void *obj);
  
  		uintptr	GetStackTop() const;		
-@@ -901,7 +1110,10 @@ namespace MMgc
+@@ -911,7 +1121,10 @@ namespace MMgc
  		// FIXME: only used for FixedAlloc, GCAlloc sized dynamically
  		const static int kPageUsableSpace = 3936;
  
 +		/** @access Requires(request && m_lock) */
  		uint32 *GetBits(int numBytes, int sizeClass);
 +
 +		/** @access Requires((request && m_lock) || exclusiveGC) */
  		void FreeBits(uint32 *bits, int sizeClass)
  		{
  #ifdef _DEBUG
-@@ -910,35 +1122,60 @@ namespace MMgc
+@@ -920,35 +1133,60 @@ namespace MMgc
  			*(uint32**)bits = m_bitsFreelists[sizeClass];
  			m_bitsFreelists[sizeClass] = bits;
  		}
 +
 +		/** @access Requires((request && m_lock) || exclusiveGC) */
  		uint32 *m_bitsFreelists[kNumSizeClasses];
 +		/** @access Requires((request && m_lock) || exclusiveGC) */
  		uint32 *m_bitsNext;
@@ -1388,17 +1391,17 @@ diff --git a/MMgc/GC.h b/MMgc/GC.h
 -		
 +
 +		/** @access ReadWrite(request, exclusiveGC) */
  		uint64 lastMarkTicks;
 +		/** @access ReadWrite(request, exclusiveGC) */
  		uint64 lastSweepTicks;
  
  		const static int16 kSizeClasses[kNumSizeClasses];		
-@@ -950,14 +1187,44 @@ namespace MMgc
+@@ -960,14 +1198,44 @@ namespace MMgc
  		// 0 - not in use
  		// 1 - used by GCAlloc
  		// 3 - used by GCLargeAlloc
 +
 +		/** @access Requires(pageMapLock) */
  		uintptr memStart;
 +		/** @access Requires(pageMapLock) */
  		uintptr memEnd;
@@ -1433,17 +1436,17 @@ diff --git a/MMgc/GC.h b/MMgc/GC.h
 +			return GetPageMapValueAlreadyLocked(addr);
 +		}
 +
 +		/** @access Requires(pageMapLock) */
 +		inline int GetPageMapValueAlreadyLocked(uintptr addr) const
  		{
  			uintptr index = (addr-memStart) >> 12;
  
-@@ -969,7 +1236,20 @@ namespace MMgc
+@@ -979,7 +1247,20 @@ namespace MMgc
  			//return (pageMap[addr >> 2] & (3<<shiftAmount)) >> shiftAmount;
  			return (pageMap[index >> 2] >> shiftAmount) & 3;
  		}
 +
 +		/**
 +		 * Set the pageMap bits for the given address.  Those bits must be
 +		 * zero beforehand.
 +		 *
@@ -1454,17 +1457,17 @@ diff --git a/MMgc/GC.h b/MMgc/GC.h
 +		/**
 +		 * Zero out the pageMap bits for the given address.
 +		 *
 +		 * @access Requires(pageMapLock)
 +		 */
  		void ClearPageMapValue(uintptr addr);
  
  		void MarkGCPages(void *item, uint32 numpages, int val);
-@@ -988,69 +1268,163 @@ namespace MMgc
+@@ -998,69 +1279,163 @@ namespace MMgc
  		GCAlloc *noPointersAllocs[kNumSizeClasses];
  		GCLargeAlloc *largeAlloc;
  		GCHeap *heap;
 -		
 +
 +		/** @access Requires(m_lock) */
  		void* AllocBlockIncremental(int size, bool zero=true);
 +
@@ -1626,41 +1629,41 @@ diff --git a/MMgc/GC.h b/MMgc/GC.h
 +		 * even if the calling thread is not in a request at all, so this
 +		 * policy would be insufficient for m_callbacks.  Second,
 +		 * m_edgeCallbacks fires very frequently during marking, so a
 +		 * lock-free policy is probably much faster.
 +		 */
  		GCEdgeCallback *m_edgeCallbacks;
  		void AddEdgeCallback(GCEdgeCallback *cb);
  		void RemoveEdgeCallback(GCEdgeCallback *cb);
-@@ -1058,9 +1432,10 @@ namespace MMgc
+@@ -1068,9 +1443,10 @@ namespace MMgc
  		/**
  		 * Notify GCEdgeCallbacks of an edge.
  		 *
 -		 * p is a "real pointer".  This method converts it to
 -		 * a "user pointer" using GetUserPointer() before
 -		 * calling callbacks.
 +		 * p is a "real pointer".  This method converts it to a "user pointer"
 +		 * using GetUserPointer() before calling callbacks.
 +		 *
 +		 * @access Requires(exclusiveGC)
  		 */
  		void FireFoundEdgeTo(const void *p);
  
-@@ -1083,7 +1458,9 @@ private:
+@@ -1093,7 +1469,9 @@ private:
  private:
  #endif
  
 +#ifndef MMGC_THREADSAFE
  		void CheckThread();
 +#endif
  
  		void PushWorkItem(GCStack<GCWorkItem> &stack, GCWorkItem item);
  
-@@ -1100,17 +1477,37 @@ private:
+@@ -1110,17 +1488,37 @@ private:
  		void CheckFreelists();
  
  		int m_gcLastStackTrace;
 +
 +		/**
 +		 * Used by FindUnmarkedPointers.
 +		 *
 +		 * @access Requires(exclusiveGC)
@@ -1692,17 +1695,17 @@ diff --git a/MMgc/GC.h b/MMgc/GC.h
 +		 * Scan all GC memory (skipping roots). If a GC object is black make sure
 +		 * it has no pointers to white objects.
 +		 *
 +		 * @access Requires(exclusiveGC)
 +		 */
  		void FindMissingWriteBarriers();
  #ifdef WIN32
  		// store a handle to the thread that create the GC to ensure thread safety
-@@ -1131,7 +1528,187 @@ public:
+@@ -1141,7 +1539,187 @@ public:
  #ifdef _DEBUG
  		// Dump a list of objects that have pointers to the given location.
  		void WhosPointingAtMe(void* me, int recurseDepth=0, int currentDepth=0);
 +
 +		/**
 +		 * Used by WhosPointingAtMe.
 +		 * @access Requires(pageMapLock)
 +		 */
deleted file mode 100644
--- a/mmgc-threadsafe-v1
+++ /dev/null
@@ -1,834 +0,0 @@
-diff --git a/MMgc/GC.cpp b/MMgc/GC.cpp
---- a/MMgc/GC.cpp
-+++ b/MMgc/GC.cpp
-@@ -219,6 +219,8 @@ namespace MMgc
- 		  memEnd(0),
- 		  heap(gcheap),
- 		  allocsSinceCollect(0),
-+		  busy(false),
-+		  restartRequested(false),
- 		  collecting(false),
- 		  m_roots(0),
- 		  m_callbacks(0),
-@@ -246,6 +248,13 @@ namespace MMgc
- 		  finalizedValue(true),
- 		  // Expand, don't collect, until we hit this threshold
- 		  collectThreshold(256)
-+#ifdef MMGC_THREADSAFE
-+		  ,
-+		  condNotBusy(statusLock),
-+		  condNoRequests(statusLock),
-+		  requestCount(0)
-+#endif
-+
- 	{		
- 		// sanity check for all our types
- 		GCAssert (sizeof(int8) == 1);
-@@ -383,7 +392,61 @@ namespace MMgc
- 
- 	void GC::Collect()
- 	{
--		// invoke precollect callback
-+		AssertLockNotHeld();
-+
-+		{
-+#ifdef MMGC_THREADSAFE
-+			GC::AutoLock(this);
-+#endif
-+			if (vetoed || nogc || collecting)
-+				return;
-+
-+			// Don't start a collection if we are in the midst of a ZCT reap.
-+			if (zct.reaping)
-+				return;
-+
-+			ReapZCT();
-+
-+			// if we're in the middle of an incremental mark kill it
-+			// FIXME: we should just push it to completion 
-+			if(marking) 
-+			{
-+				marking = false;
-+				m_incrementalWork.Keep(0);
-+			}
-+
-+			busy = true;
-+		}
-+
-+#ifdef DEBUGGER
-+		StartGCActivity();
-+#endif
-+
-+		// Dumping the stack trace at GC time can be very helpful with stack walk bugs
-+		// where something was created, stored away in untraced, unmanaged memory and not 
-+		// reachable by the conservative stack walk
-+		//DumpStackTrace();
-+
-+		Trace();
-+		
-+		Sweep();
-+
-+#ifdef _DEBUG
-+		FindUnmarkedPointers();
-+#endif
-+
-+		CheckThread();
-+
-+#ifdef DEBUGGER
-+		StopGCActivity();
-+#endif
-+	}
-+
-+	void GC::CollectWithBookkeeping()
-+	{
-+		AssertLockNotHeld();
-+
-+		// Invoke the precollect callback.
- 		bool vetoed = false;
- 		GCCallback *cb = m_callbacks;
- 		while (cb) {
-@@ -391,55 +454,55 @@ namespace MMgc
- 				vetoed = true;
- 			cb = cb->nextCB;
- 		}
--
--		if (vetoed || nogc || collecting) {
--
-+		if (vetoed)
- 			return;
--		}
--
--		// Don't start a collection if we are in the midst of a ZCT reap.
--		if (zct.reaping)
--		{
--
-+
-+#ifdef MMGC_THREADSAFE
-+		// Lock before collecting, to update the GC status and detect
-+		// cases where we shouldn't collect.
-+		{
-+			GC::AutoLock _lock(this);
-+
-+			if (nogc)
-+				return;
-+
-+			// If we're already collecting on this thread, we've been called
-+			// from a finalizer.  Don't recurse.
-+			
-+		
-+			// If we're already collecting on another thread, just wait for that
-+			// to finish.
-+			???;
-+
-+			// We're going to do a collection.
-+			//
-+			// Suspend this thread's requests, update status, and wait for
-+			// other threads to end or suspend their requests.
-+			???;
-+
-+			// No requests are active.
-+			???;
-+		}
-+#else
-+		if (nogc || collecting || zct.reaping)
- 			return;
--		}
--
--		ReapZCT();
--
--		// if we're in the middle of an incremental mark kill it
--		// FIXME: we should just push it to completion 
--		if(marking) 
--		{
--			marking = false;
--			m_incrementalWork.Keep(0);
--		}
--
--#ifdef DEBUGGER
--		StartGCActivity();
--#endif
--
--		// Dumping the stack trace at GC time can be very helpful with stack walk bugs
--		// where something was created, stored away in untraced, unmanaged memory and not 
--		// reachable by the conservative stack walk
--		//DumpStackTrace();
--
--		Trace();
-+#endif
-+
-+		CollectImpl();
-+
-+#ifdef MMGC_THREADSAFE
-+		// Lock again afterwards to update status, allowing other threads
-+		// to proceed.
-+		{
-+			GC::AutoLock _lock(this);
-+			???;
-+		}
-+#endif
-+	}
-+
-+	void GC::Trace(const void *stackStart/*=NULL*/, size_t stackSize/*=0*/)
-+	{
- 		
--		Sweep();
--
--#ifdef _DEBUG
--		FindUnmarkedPointers();
--#endif
--
--		CheckThread();
--
--#ifdef DEBUGGER
--		StopGCActivity();
--#endif
--	}
--
--	void GC::Trace(const void *stackStart/*=NULL*/, size_t stackSize/*=0*/)
--	{
- 		SAMPLE_FRAME("[mark]", core());
- 
- 		// Clear all mark bits.
-@@ -479,6 +542,12 @@ namespace MMgc
- 
- 	void *GC::Alloc(size_t size, int flags/*0*/, int skip/*3*/)
- 	{
-+#ifdef MMGC_THREADSAFE
-+		AssertLockNotHeld();
-+		GC::AutoLock _lock(this);
-+		GCAssert(!busy);
-+#endif
-+
- #ifdef DEBUGGER
- 		avmplus::AvmCore *core = (avmplus::AvmCore*)GetGCContextVariable(GCV_AVMCORE);
- 		if(core)
-@@ -492,12 +561,12 @@ namespace MMgc
- 		GCAssert(size + 7 > size);
- 		CheckThread();
- 		if (GC::greedy) {
--			Collect();
-+			CollectImpl(true);
- 		}
- 		// always be marking in pedantic mode
- 		if(incrementalValidationPedantic) {
- 			if(!marking)
--				StartIncrementalMark();
-+				StartIncrementalMarkImpl(true);
- 		}
- #endif
- 
-@@ -575,19 +644,25 @@ namespace MMgc
- 
- 	void GC::Free(void *item)
- 	{
-+		if (item == NULL)
-+			return;
-+
-+#ifdef MMGC_THREADSAFE
-+		AssertLockNotHeld();
-+		GC::AutoLock _lock(this);
-+		GCAssert(!busy);
-+#else
- 		CheckThread();
-+#endif
-+
- 		// we can't allow free'ing something during Sweeping, otherwise alloc counters
- 		// get decremented twice and destructors will be called twice.
--		if(item == NULL) {
--			return;
--		}
- 
- 		bool isLarge;
- 
- 		if(collecting) {
- 			goto bail;
- 		}
--
- 		isLarge = GCLargeAlloc::IsLargeBlock(GetRealPointer(item));
- 
- 		if (marking) {
-@@ -665,7 +740,10 @@ bail:
- 	}
- 
- 	void GC::Sweep(bool force)
--	{	
-+	{
-+		AssertLockNotHeld();
-+		GCAssert(collecting);
-+
- 		SAMPLE_FRAME("[sweep]", core());
- 		sweeps++;
- 
-@@ -677,7 +755,7 @@ bail:
- 			DumpMemoryInfo();
- 		}
- #endif
--		
-+
- 		// collecting must be true because it indicates allocations should
- 		// start out marked, we can't rely on write barriers below since 
- 		// presweep could write a new GC object to a root
-@@ -736,8 +814,17 @@ bail:
- #endif
- 
- 		// don't want postsweep to fire WB's
--		marking = false;
--		collecting = false;
-+		{
-+#ifdef MMGC_THREADSAFE
-+			GC::AutoLock _lock(this);
-+#endif
-+			marking = false;
-+			collecting = false;
-+			busy = false;
-+#ifdef MMGC_THREADSAFE
-+			condNotBusy.NotifyAll();
-+#endif
-+		}
- 
- 		// invoke postsweep callback
- 		cb = m_callbacks;
-@@ -782,11 +869,12 @@ bail:
- 
- 	void* GC::AllocBlock(int size, int pageType, bool zero)
- 	{
-+		AssertLockHeld();
- #ifdef DEBUGGER
- 		AllocActivity(size);
- #endif
- 		GCAssert(size > 0);
--	
-+
- 		// perform gc if heap expanded due to fixed memory allocations
- 		// utilize burst logic to prevent this from happening back to back
- 		// this logic is here to apply to incremental and non-incremental
-@@ -799,7 +887,7 @@ bail:
- 			if(incremental)
- 				StartIncrementalMark();
- 			else
--				Collect();
-+				CollectImpl(true);
- 		}
- 
- 		void *item;
-@@ -840,6 +928,8 @@ bail:
- 
- 	void* GC::AllocBlockIncremental(int size, bool zero)
- 	{
-+		AssertLockHeld();
-+
- 		if(!nogc && !collecting) {
- 			uint64 now = GetPerformanceCounter();
- 			if (marking) {		
-@@ -1133,7 +1223,6 @@ bail:
- #endif
- #endif
- 	}
--
- 
- 	bool GC::IsPointerToGCPage(const void *item)
- 	{
-@@ -1280,7 +1369,70 @@ bail:
- 			}
- 		}
- 	}
--			
-+
-+#ifdef MMGC_THREADSAFE
-+
-+	void GC::AcquireLock()
-+	{
-+	}
-+
-+	void GC::ReleaseLock()
-+	{
-+	}
-+
-+	void GCRequestContext::BeginRequest()
-+	{
-+		if (m_requestDepth != 0) {
-+			// Nested request.
-+			m_requestDepth++;
-+			return;
-+		}
-+
-+		GC::AutoLock _lock(m_gc);
-+		m_gc->WaitForNotCollecting();
-+		m_gc->IncrementRequestCount();
-+		m_requestDepth = 1;
-+	}
-+
-+	void GCRequestContext::EndRequest()
-+	{
-+		GCAssert(m_requestDepth != 0);
-+		if (m_requestDepth > 1) {
-+			// Nested request.
-+			m_requestDepth--;
-+			return;
-+		}
-+
-+		GC::AutoLock _lock(m_gc);
-+		m_gc->DecrementRequestCount();
-+		m_requestDepth = 0;
-+	}
-+
-+	void GCRequestContext::SuspendRequest(GCSuspendedRequestState *state)
-+	{
-+		void *stack;
-+		size_t stackSize;
-+
-+		MMGC_GET_STACK_EXTENTS(m_gc, stack, stackSize);
-+		state->stack = new GCRoot(m_gc, stack, stackSize);
-+
-+		state->count = 0;
-+		while (requestDepth) {
-+			EndRequest();
-+			state->count++;
-+		}
-+	}
-+
-+	void GCRequestContext::ResumeRequest(GCSuspendedRequestState *state)
-+	{
-+		for (int i = 0; i < state->count; i++)
-+			BeginRequest();
-+
-+		delete state->stack;
-+	}
-+
-+#endif // MMGC_THREADSAFE
-+
- #ifdef _DEBUG
- 
- 	void GC::RCObjectZeroCheck(RCObject *item)
-@@ -1930,6 +2082,7 @@ bail:
- 
- 	void GC::StartIncrementalMark()
- 	{
-+		AssertLockHeld();
- 		GCAssert(!marking);
- 		GCAssert(!collecting);
- 
-@@ -2300,7 +2453,7 @@ bail:
- #ifdef DEBUGGER
- 		StartGCActivity();
- #endif
--		
-+
- 		markIncrements++;
- 		// FIXME: tune this so that getPerformanceCounter() overhead is noise
- 		static unsigned int checkTimeIncrements = 100;
-@@ -2584,7 +2737,7 @@ bail:
- 	}
- 
- 	void GC::RemoveRoot(GCRoot *root)
--	{		
-+	{
- #ifdef GCHEAP_LOCK
- 		GCAcquireSpinlock lock(m_rootListLock);
- #endif
-diff --git a/MMgc/GC.h b/MMgc/GC.h
---- a/MMgc/GC.h
-+++ b/MMgc/GC.h
-@@ -431,6 +431,149 @@ namespace MMgc
- 		{
- 			return obj >= zct && obj < (RCObject**)(zct+zctSize/sizeof(RCObject*));
- 		}
-+	};
-+
-+#ifdef MMGC_THREADSAFE
-+	/** State saved by GCRequestContext::SuspendRequest. */
-+	struct GCSuspendedRequestState
-+	{
-+		/** Number of nested BeginRequest calls that were suspended. */
-+		int count;
-+		/** Rooted stack. */
-+		GCRoot *stack;
-+	};
-+
-+	/**
-+	 * An execution context in which requests my run.  Each GCRequestRunner is
-+	 * single-threaded.  See MMgc::GCRequest.
-+	 */
-+	class GCRequestContext
-+	{
-+	public:
-+		GCRequestContext();
-+		virtual ~GCRequestContext() {}
-+
-+		/**
-+		 * Enter a request.  This is the low-level method that implements
-+		 * MMgc::GCRequest.
-+		 */
-+		void BeginRequest();
-+
-+		/** Leave the current request. */
-+		void EndRequest();
-+
-+		/**
-+		 * Suspend the current request.  This is the method that implements
-+		 * MMgc::GCSuspendRequest.
-+		 *
-+		 * The caller must provide `state`, which is a place to store
-+		 * information that will be needed later to resume the request.
-+		 * `state` must be non-null, and a GCSuspendedRequestState object can
-+		 * only be used for one suspended request at a time.
-+		 */
-+		void SuspendRequest(GCSuspendedRequestState *state);
-+
-+		/**
-+		 * Resume a suspended request.
-+		 *
-+		 * `state` must point to a struct previously passed to SuspendRequest.
-+		 */
-+		void ResumeRequest(GCSuspendedRequestState *state);
-+
-+	private:
-+		GC *m_gc;
-+		int m_requestDepth;
-+	};
-+
-+#else
-+	/*
-+	 * Dummy implementations of the request-related classes.  The compiler
-+	 * should optimize away calls to the *Request methods.
-+	 */
-+
-+	struct GCSuspendedRequestState {};
-+
-+	class GCRequestContext {
-+	public:
-+		explicit GCRequestContext(GC *) {}
-+		virtual ~GCRequestContext() {}
-+
-+		void BeginRequest() {}
-+		void EndRequest() {}
-+		void SuspendRequest(GCSuspendedRequestState *) {}
-+		void ResumeRequest(GCSuspendedRequestState *) {}
-+	};
-+#endif // MMGC_THREADSAFE
-+
-+
-+	/**
-+	 * Sentry object to protect application code that uses MMgc.
-+	 *
-+	 * When MMgc is compiled with MMGC_THREADSAFE defined, the application
-+	 * must use the request model to ensure that allocation and garbage
-+	 * collection interact safely. Wrapping some code in a request ensures two
-+	 * things: (1) garbage collection will not collide with that code, because
-+	 * the GC treats threads that are in requests with extra care; (2) when GC
-+	 * does happen, the stack of the thread that is in the request will be
-+	 * scanned.
-+	 *
-+	 * Threads that are not in requests do not get these guarantees.
-+	 * Therefore code must not interact with the GC or GC-managed objects
-+	 * outside a request!
-+	 *
-+	 * Code inside a request should not block or do CPU-intensive processing,
-+	 * as this would lock out garbage collection.  See GCSuspendRequest.
-+	 */
-+	class GCRequest
-+	{
-+	public:
-+		explicit GCRequest(GCRequestContext *cx) : m_cx(cx)
-+		{
-+			cx->BeginRequest();
-+		}
-+
-+		~GCRequest()
-+		{
-+			m_cx->EndRequest();
-+		}
-+
-+	private:
-+		// Prohibit copying.
-+		GCRequest(const GCRequest &);
-+		GCRequest & operator=(const GCRequest &);
-+
-+		GCRequestContext *m_cx;
-+	};
-+
-+	/**
-+	 * Sentry object to suspend a request temporarily. Suspending a request
-+	 * allows the GC to work while a thread is performing blocking IO or
-+	 * CPU-intensive work.
-+	 *
-+	 * While a request is suspended, the calling thread's stack is temporarily
-+	 * rooted so that if GC does happen, the appropriate stack frames will be
-+	 * scanned.
-+	 */
-+	class GCSuspendRequest
-+	{
-+	public:
-+		explicit GCSuspendRequest(GCRequestContext *cx) : m_cx(cx)
-+		{
-+			cx->SuspendRequest(&m_state);
-+		}
-+
-+		~GCSuspendRequest()
-+		{
-+			m_cx->ResumeRequest(&m_state);
-+		}
-+
-+	private:
-+		// Prohibit copying.
-+		GCSuspendRequest(const GCSuspendRequest &);
-+		GCSuspendRequest & operator=(const GCSuspendRequest &);
-+
-+		GCRequestContext *m_cx;
-+		GCSuspendedRequestState m_state;
- 	};
- 
- 	/**
-@@ -475,8 +618,20 @@ namespace MMgc
- 		friend class GCLargeAlloc;
- 		friend class RCObject;
- 		friend class GCInterval;
-+		friend class GCRequestContext;
- 		friend class ZCT;
- 	public:
-+
-+#ifdef MMGC_THREADSAFE
-+		void AcquireLock();
-+		void ReleaseLock();
-+
-+		void AssertLockHeld()    { GCAssert(statusLock.IsHeld()); }
-+		void AssertLockNotHeld() { GCAssert(!statusLock.IsHeld()); }
-+#else
-+		void AssertLockHeld() {}
-+		void AssertLockNotHeld() {}
-+#endif // MMGC_THREADSAFE
- 
- 		/**
- 		 * If you need context vars use this!
-@@ -708,7 +863,10 @@ namespace MMgc
- 		}
- 
- 		/**
--		 * Used by sub-allocators to obtain memory
-+		 * Used by sub-allocators to obtain memory.
-+		 *
-+		 * In MMGC_THREADSAFE builds, the caller must hold the GC-wide
-+		 * lock. See GC::AcquireLock().
- 		 */
- 		void* AllocBlock(int size, int pageType, bool zero=true);
- 		void FreeBlock(void *ptr, uint32 size);
-@@ -831,8 +989,17 @@ namespace MMgc
- 		bool IsRCObject(const void *) { return false; }
- #endif
- 
--
--		bool Collecting() const { return collecting; }
-+		/**
-+		 * True during finalization; false during ordinary or incremental
-+		 * marking.  See GC::collecting.
-+		 */
-+		bool Collecting() const
-+		{
-+#ifdef MMGC_THREADSAFE
-+			GC::AutoLock _lock(this);
-+#endif
-+			return collecting;
-+		}
- 
- 		bool IsGCMemory (const void *);
- 
-@@ -932,7 +1099,22 @@ namespace MMgc
- 		// for external which does thread safe multi-thread AS execution
- 		bool disableThreadCheck;
- 
-+		/**
-+		 * True if incremental marking has started for the current GC cycle.
-+		 * As long as this is false, write barriers do not need to do
-+		 * anything.
-+		 *
-+		 * This is true from the time StartIncrementalMark() is called to the
-+		 * end of the cycle, that is, until Collect() or
-+		 * FinishIncrementalMark() completes successfully.
-+		 *
-+		 * While `busy` and `collecting` indicate that the GC is actually
-+		 * actively doing something, `marking` only indicates that marking has
-+		 * started and is true even in between calls to IncrementalMark(),
-+		 * when no GC-related code is running.
-+		 */
- 		bool marking;
-+
- 		GCStack<GCWorkItem> m_incrementalWork;
- 		void StartIncrementalMark();
- 		void FinishIncrementalMark();
-@@ -1002,6 +1184,22 @@ namespace MMgc
- 		void Trace(const void *stackStart=NULL, size_t stackSize=0);
- #endif
- 
-+		/**
-+		 * A thread-wrangling wrapper around CollectImpl().
-+		 *
-+		 * Ordinarily this just calls CollectImpl, but in an MMGC_THREADSAFE
-+		 * build this does more work, implementing the GC side of the request
-+		 * model, and arranging for GC to restart if multiple threads request
-+		 * it.
-+		 */
-+		void CollectThreadSafe();
-+
-+		/**
-+		 * Actually do garbage collection.  This should only be
-+		 * called from CollectThreadSafe().
-+		 */
-+		void CollectImpl();
-+
- 		void Finalize();
- 		void Sweep(bool force=false);
- 		void ForceSweep() { Sweep(true); }
-@@ -1018,9 +1216,31 @@ namespace MMgc
- 		void TrapWrite(const void *black, const void *white);
- 
- 		unsigned int allocsSinceCollect;
--		// The collecting flag prevents an unwanted recursive collection.
-+
-+		/**
-+		 * True whenever any thread is (a) doing GC; (b) doing incremental
-+		 * marking; or (c) waiting for all threads to be ready for GC.
-+		 *
-+		 * In an MMGC_THREADSAFE build, this field is protected by statusLock.
-+		 */
-+		bool busy;
-+
-+		/**
-+		 * True when another thread has requested GC while GC or incremental
-+		 * marking is already underway.  This indicates that after the current
-+		 * GC, a new full GC will happen.  This field is protected by
-+		 * statusLock.
-+		 *
-+		 * In a non-MMGC_THREADSAFE build, this is always false.
-+		 */
-+		bool restartRequested;
-+
-+		/**
-+		 * True when Sweep() is running.  This is used to determine whether
-+		 * newly allocated objects should start out marked.
-+		 */
- 		bool collecting;
-- 
-+
- 		bool finalizedValue;
- 
- 		// list of pages to be swept, built up in Finalize
-@@ -1084,6 +1304,107 @@ private:
- #endif
- 
- 		void CheckThread();
-+
-+#ifdef MMGC_THREADSAFE
-+		/**
-+		 * The GC-wide lock exposed via AcquireLock() and ReleaseLock().
-+		 *
-+		 * This lock protects all gc-wide "status" information: GC::busy,
-+		 * GC::collecting, GC::marking, GC::requestCount, and
-+		 * GCRequestContext::requestDepth (but not ZCT::reaping, yet; DRC is
-+		 * not yet thread-safe in any sense). These fields may be read or
-+		 * written only by a thread that holds this lock.
-+		 *
-+		 * A slightly different locking scheme protects the GCAlloc and
-+		 * GCLargeAlloc objects and all the GCBlocks and per-object bits. We
-+		 * divide code that may touch these objects into two categories:
-+		 * application code (running in GCRequests) and collector code. At any
-+		 * given time, either one collector thread or multiple application
-+		 * threads may be running. That is, there is an invariant that
-+		 *
-+		 *    !(gc->busy && gc->requestCount > 0)
-+		 *
-+		 * So the collector may touch allocation-related data freely (because
-+		 * it makes sure there's no application code running before it begins)
-+		 * but application code must do so only when holding the lock.
-+		 *
-+		 * This lock does NOT protect m_roots, GCRoot::next, and
-+		 * GCRoot::prev. Those are protected by a separate spinlock. To avoid
-+		 * deadlock, never lock statusLock and m_rootListLock at the same
-+		 * time.
-+		 */
-+		GCLock statusLock;
-+
-+		/** This condition is notified when `busy` becomes false. */
-+		GCCondition condNotBusy;
-+
-+		/** This condition is notified when `reqeustCount==0` becomes true. */
-+		GCCondition condNoRequests;
-+
-+		/**
-+		 * The number of GCRequestContext objects with active requests.
-+		 *
-+		 * (Note: GCRequestContext doesn't have any data members that tell
-+		 * whether it's active or not. In particular,
-+		 * GCRequestContext::requestDepth is no indication; it may be nonzero
-+		 * while the request is temporarily inactive because GC is happening.)
-+		 */
-+		int requestCount;
-+
-+		/**
-+		 * Sentry object that acquires the GC-wide status lock, then releases
-+		 * it when it leaves scope.
-+		 */
-+		class AutoLock
-+		{
-+		public:
-+			explicit AutoLock(GC *gc) : m_gc(gc) { gc->AcquireLock(); }
-+			~AutoLock() { m_gc->ReleaseLock(); }
-+
-+		private:
-+			// Prohibit copying
-+			AutoLock(const AutoLock &);
-+			AutoLock & operator=(const AutoLock &);
-+
-+			GC *m_gc;
-+		};
-+
-+		/**
-+		 * Wait until garbage collection is *not* happening and it is safe for
-+		 * code within a request to proceed.
-+		 *
-+		 * The caller must hold `this->statusLock`.
-+		 */
-+		inline void WaitForNotBusy()
-+		{
-+			while (busy)
-+				condNotBusy.Wait();
-+		}
-+
-+		/**
-+		 * GCRequestContext::BeginRequest calls this to notify the GC that a
-+		 * context has entered a request.
-+		 *
-+		 * Caller must hold `this->statusLock`.
-+		 */
-+		inline void IncrementRequestCount()
-+		{
-+			requestCount++;
-+		}
-+
-+		/**
-+		 * GCRequestContext::EndRequest calls this to notify the GC that a
-+		 * context has left an outermost request.
-+		 *
-+		 * Caller must hold `this->statusLock`.
-+		 */
-+		inline void DecrementRequestCount()
-+		{
-+			GCAssert(requestCount > 0);
-+			if (--requestCount == 0)
-+				condNoRequests.NotifyAll();
-+		}
-+#endif // MMGC_THREADSAFE
- 
- 		void PushWorkItem(GCStack<GCWorkItem> &stack, GCWorkItem item);
- 
-diff --git a/MMgc/MMgc.h b/MMgc/MMgc.h
---- a/MMgc/MMgc.h
-+++ b/MMgc/MMgc.h
-@@ -107,6 +107,8 @@
- #endif
- #endif
- 
-+#include "GCThreads.h"
-+
- namespace MMgc
- {
- 	class GC;
--- a/series
+++ b/series
@@ -1,10 +1,6 @@
 configure-with-threadsafe-mmgc
-mmgc-rm-isd
 mmgc-threadsafe-take2
 mmgc-graphviz
-sm-features
-mmgc-threadsafe-v1
-DO-NOT-USE
 mmgc-decref-microfix
 mmgc-remove-precollect-hook
 mmgc-bit-checks
deleted file mode 100644