Update to actionmonkey-tamarin tip.
authorjorendorff@mozilla.com
Wed, 28 Nov 2007 13:23:49 -0600
changeset 10 c5dfb5bb8df559a5a7cb7fc23fa86f23c23e9d33
parent 9 01b3ffa4acb6f282cd673c1ac70c925355b4b93d
child 11 553e043f72afe2b76d49737b9c0b960bc0fb2e0e
push id1
push userbsmedberg@mozilla.com
push dateMon, 21 Apr 2008 01:54:18 +0000
Update to actionmonkey-tamarin tip.
configure-with-threadsafe-mmgc
mmgc-threadsafe-take2
--- a/configure-with-threadsafe-mmgc
+++ b/configure-with-threadsafe-mmgc
@@ -14,46 +14,45 @@ diff --git a/configure b/configure
 +done
 +
 +echo "running $PYTHON $0.py --ignore-unknown-flags $args"
 +
 +eval "'$PYTHON' '$0.py' --ignore-unknown-flags $args"
 diff --git a/configure.py b/configure.py
 --- a/configure.py
 +++ b/configure.py
-@@ -71,15 +71,28 @@ DEBUG_CXXFLAGS = ""
+@@ -75,14 +75,27 @@ DEBUG_CXXFLAGS = ""
  DEBUG_CXXFLAGS = ""
  DEBUG_LDFLAGS = ""
  OS_LIBS = []
 +OS_LDFLAGS = ""
  MMGC_CPPFLAGS = ""
  AVMSHELL_CPPFLAGS = ""
  AVMSHELL_LDFLAGS = ""
  MMGC_DEFINES = {'SOFT_ASSERTS': None}
-+NSPR_INCLUDES=""
-+NSPR_LDOPTS=""
++NSPR_INCLUDES = ""
++NSPR_LDOPTS = ""
  
- MMGC_DYNAMIC = o.getBoolArg('mmgc-shared', False)
- if MMGC_DYNAMIC:
-     MMGC_DEFINES['MMGC_DLL'] = None
-     MMGC_CPPFLAGS += "-DMMGC_IMPL "
+ MMGC_INTERIOR_PTRS = o.getBoolArg('mmgc-interior-pointers', True)
+ if MMGC_INTERIOR_PTRS:
+     MMGC_DEFINES['MMGC_INTERIOR_PTRS'] = None
 +
 +MMGC_THREADSAFE = o.getBoolArg('threadsafe-mmgc', False)
 +if MMGC_THREADSAFE:
 +    MMGC_DEFINES['MMGC_THREADSAFE'] = None
 +    NSPR_INCLUDES = o.getStringArg('nspr-includes')
 +    MMGC_CPPFLAGS += NSPR_INCLUDES + " "
 +    APP_CPPFLAGS += NSPR_INCLUDES + " "
 +
 +    NSPR_LDOPTS = o.getStringArg('nspr-ldopts')
 +    OS_LDFLAGS += " " + NSPR_LDOPTS
  
- if config.COMPILER_IS_GCC:
-     APP_CXXFLAGS = "-fno-exceptions -Werror -Wall -Wno-reorder -Wno-switch -Wno-invalid-offsetof -Wno-uninitialized -Wno-strict-aliasing -fmessage-length=0 -finline-functions -finline-limit=65536 "
-@@ -178,6 +191,7 @@ config.subst("DEBUG_CXXFLAGS", DEBUG_CXX
+ MMGC_DYNAMIC = o.getBoolArg('mmgc-shared', False)
+ if MMGC_DYNAMIC:
+@@ -188,6 +201,7 @@ config.subst("DEBUG_CXXFLAGS", DEBUG_CXX
  config.subst("DEBUG_CXXFLAGS", DEBUG_CXXFLAGS)
  config.subst("DEBUG_LDFLAGS", DEBUG_LDFLAGS)
  config.subst("OS_LIBS", " ".join(OS_LIBS))
 +config.subst("OS_LDFLAGS", OS_LDFLAGS)
  config.subst("MMGC_CPPFLAGS", MMGC_CPPFLAGS)
  config.subst("AVMSHELL_CPPFLAGS", AVMSHELL_CPPFLAGS)
  config.subst("AVMSHELL_LDFLAGS", AVMSHELL_LDFLAGS)
 diff --git a/pcre/config.h b/pcre/config.h
--- 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);		
-@@ -385,7 +409,9 @@ namespace MMgc
- 		delete [] msgBuf;
- #endif
+@@ -372,7 +396,9 @@ namespace MMgc
+ 
+ 		heap->Free(pageMap);
  
 +#ifndef MMGC_THREADSAFE
  		CheckThread();
 +#endif
  
  		GCAssert(!m_roots);
  		GCAssert(!m_callbacks);
-@@ -393,15 +419,43 @@ namespace MMgc
+@@ -380,15 +406,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;
-@@ -413,8 +467,136 @@ namespace MMgc
+@@ -400,8 +454,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 
-@@ -441,8 +623,6 @@ namespace MMgc
+@@ -428,8 +610,6 @@ namespace MMgc
  		FindUnmarkedPointers();
  #endif
  
 -		CheckThread();
 -
  #ifdef DEBUGGER
  		StopGCActivity();
  #endif
-@@ -450,6 +630,8 @@ namespace MMgc
+@@ -437,6 +617,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.
-@@ -473,8 +655,11 @@ namespace MMgc
+@@ -460,8 +642,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);
-@@ -489,6 +674,17 @@ namespace MMgc
+@@ -476,6 +661,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)
-@@ -500,9 +696,8 @@ namespace MMgc
+@@ -487,9 +683,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) {
-@@ -585,15 +780,21 @@ namespace MMgc
+@@ -572,15 +767,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;
  		}
-@@ -642,6 +843,8 @@ bail:
+@@ -629,6 +830,8 @@ bail:
  
  	void GC::ClearMarks()
  	{
 +		ASSERT_EXCLUSIVE_GC();
 +
  		for (int i=0; i < kNumSizeClasses; i++) {
  #ifdef MMGC_DRC
  			containsPointersRCAllocs[i]->ClearMarks();
-@@ -654,6 +857,8 @@ bail:
+@@ -641,6 +844,8 @@ bail:
  
  	void GC::Finalize()
  	{
 +		ASSERT_EXCLUSIVE_GC();
 +
  		for(int i=kNumSizeClasses; i-- > 0;) {
  #ifdef MMGC_DRC
  			containsPointersRCAllocs[i]->Finalize();
-@@ -675,7 +880,9 @@ bail:
+@@ -662,7 +867,9 @@ bail:
  	}
  
  	void GC::Sweep(bool force)
 -	{	
 +	{
 +		ASSERT_EXCLUSIVE_GC();
 +
  		SAMPLE_FRAME("[sweep]", core());
  		sweeps++;
  
-@@ -694,10 +901,13 @@ bail:
+@@ -681,10 +888,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();
-@@ -750,12 +960,15 @@ bail:
+@@ -737,12 +947,15 @@ bail:
  		collecting = false;
  
  		// invoke postsweep callback
 -		cb = m_callbacks;
 -		while(cb) {
 -			cb->postsweep();
 -			cb = cb->nextCB;
 -		}
@@ -398,147 +398,147 @@ diff --git a/MMgc/GC.cpp b/MMgc/GC.cpp
 +				cb->postsweep();
 +				cb = cb->nextCB;
 +			}
 +		}
 +
  		SAMPLE_CHECK();
  
  		allocsSinceCollect = 0;
-@@ -792,6 +1005,7 @@ bail:
+@@ -779,6 +992,7 @@ bail:
  
  	void* GC::AllocBlock(int size, int pageType, bool zero)
  	{
 +		ASSERT_GC_LOCK();
  #ifdef DEBUGGER
  		AllocActivity(size);
  #endif
-@@ -809,7 +1023,7 @@ bail:
+@@ -796,7 +1010,7 @@ bail:
  			if(incremental)
  				StartIncrementalMark();
  			else
 -				Collect();
 +				CollectWithBookkeeping(true, true);
  		}
  
  		void *item;
-@@ -850,6 +1064,8 @@ bail:
+@@ -837,6 +1051,8 @@ bail:
  
  	void* GC::AllocBlockIncremental(int size, bool zero)
  	{
 +		ASSERT_GC_LOCK();
 +
  		if(!nogc && !collecting) {
  			uint64 now = GetPerformanceCounter();
  			if (marking) {		
-@@ -877,12 +1093,14 @@ bail:
+@@ -864,12 +1080,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);
  			}
  		}
-@@ -891,6 +1109,11 @@ bail:
+@@ -878,6 +1096,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
-@@ -918,6 +1141,7 @@ bail:
+@@ -905,6 +1128,7 @@ bail:
  
  	void GC::Mark(GCStack<GCWorkItem> &work)
  	{
 +		ASSERT_EXCLUSIVE_GC();
  		while(work.Count()) {
  			MarkItem(work);
  		}
-@@ -925,6 +1149,7 @@ bail:
+@@ -912,6 +1136,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;
-@@ -967,7 +1192,7 @@ bail:
+@@ -954,7 +1179,7 @@ bail:
  		addr = (uintptr)item;
  		while(numPages--)
  		{
 -			GCAssert(GetPageMapValue(addr) == 0);
 +			GCAssert(GetPageMapValueAlreadyLocked(addr) == 0);
  			SetPageMapValue(addr, to);
  			addr += GCHeap::kBlockSize;
  		}
-@@ -976,6 +1201,8 @@ bail:
+@@ -963,6 +1188,8 @@ bail:
  	void GC::UnmarkGCPages(void *item, uint32 numpages)
  	{
  		uintptr addr = (uintptr) item;
 +
 +		USING_PAGE_MAP();
  		while(numpages--)
  		{
  			ClearPageMapValue(addr);
-@@ -1141,6 +1368,7 @@ bail:
+@@ -1128,6 +1355,7 @@ bail:
  		gc->Mark(work);
  	}
  
 +#ifndef MMGC_THREADSAFE
  	void GC::CheckThread()
  	{
  #ifdef _DEBUG
-@@ -1149,12 +1377,13 @@ bail:
+@@ -1136,12 +1364,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;
  	}
  
-@@ -1195,10 +1424,13 @@ bail:
+@@ -1182,10 +1411,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;
 +			{
 +				USING_CALLBACK_LIST(gc);
 +				GCCallback *cb = gc->m_callbacks;
 +				while(cb) {
 +					cb->prereap(obj);
 +					cb = cb->nextCB;
 +				}
  			}
  			if(gc->IsFinalized(obj))
- 				((GCFinalizedObject*)obj)->~GCFinalizedObject();
-@@ -1389,10 +1621,13 @@ bail:
+ 				((GCFinalizable*)obj)->~GCFinalizable();
+@@ -1376,10 +1608,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
-@@ -1433,10 +1668,13 @@ bail:
+@@ -1420,10 +1655,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);
-@@ -1470,10 +1708,13 @@ bail:
+@@ -1457,10 +1695,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) {
-@@ -1620,7 +1861,8 @@ bail:
+@@ -1607,7 +1848,8 @@ bail:
  		va_end(argptr);
  
  		GCAssert(strlen(buf) < 4096);
 -			
 +
 +		USING_CALLBACK_LIST(this);
  		GCCallback *cb = m_callbacks;
  		while(cb) {
  			cb->log(buf);
-@@ -1672,23 +1914,27 @@ bail:
+@@ -1659,23 +1901,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
-@@ -1774,7 +2020,7 @@ bail:
+@@ -1761,7 +2007,7 @@ bail:
  				continue;
  			
  			// normalize and divide by 4K to get index
 -			int bits = GetPageMapValue(val);
 +			int bits = GetPageMapValueAlreadyLocked(val);
  			switch(bits)
  			{
  			case 0:
-@@ -1795,6 +2041,8 @@ bail:
+@@ -1782,6 +2028,8 @@ bail:
  
  	void GC::FindUnmarkedPointers()
  	{
 +		ASSERT_EXCLUSIVE_GC();
 +
  		if(findUnmarkedPointers)
  		{
  			uintptr m = memStart;
-@@ -1933,6 +2181,11 @@ bail:
+@@ -1920,6 +2168,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;
  
-@@ -1955,7 +2208,7 @@ bail:
+@@ -1942,7 +2195,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);
-@@ -1999,6 +2252,11 @@ bail:
+@@ -1986,6 +2239,11 @@ bail:
  			
  			}
  		}
 +
 +#ifdef MMGC_THREADSAFE
 +		if (currentDepth == 0)
 +			pageMapLock.Release();
 +#endif
  	}
  #undef ALLOCA_AND_FILL_WITH_SPACES
  #endif
-@@ -2367,9 +2625,11 @@ bail:
+@@ -2389,9 +2647,11 @@ bail:
  		return 1000000;
  		#endif
  	}
 -	
 +
  	void GC::IncrementalMark(uint32 time)
  	{
 +		ASSERT_EXCLUSIVE_GC();
 +
  		SAMPLE_FRAME("[mark]", core());
  		if(m_incrementalWork.Count() == 0 || hitZeroObjects) {
  			FinishIncrementalMark();
-@@ -2424,6 +2684,8 @@ bail:
+@@ -2446,6 +2706,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)
-@@ -2455,8 +2717,11 @@ bail:
+@@ -2477,8 +2739,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);
  
-@@ -2607,6 +2872,7 @@ bail:
+@@ -2629,6 +2894,7 @@ bail:
  	{
  		uint32 *bits;
  
 +		ASSERT_GC_LOCK();
  		GCAssert(numBytes % 4 == 0);
  
  		#ifdef MMGC_64BIT // we use first 8-byte slot for the free list
-@@ -2678,7 +2944,8 @@ bail:
+@@ -2700,7 +2966,8 @@ bail:
  
  	void GC::AddCallback(GCCallback *cb)
  	{
 -		CheckThread();
 +		USING_CALLBACK_LIST(this);
 +
  		cb->prevCB = NULL;
  		cb->nextCB = m_callbacks;
  		if(m_callbacks)
-@@ -2688,7 +2955,8 @@ bail:
+@@ -2710,7 +2977,8 @@ bail:
  
  	void GC::RemoveCallback(GCCallback *cb)
  	{
 -		CheckThread();
 +		USING_CALLBACK_LIST(this);
 +
  		if( m_callbacks == cb )
  			m_callbacks = cb->nextCB;
  		else
-@@ -2700,7 +2968,8 @@ bail:
+@@ -2722,7 +2990,8 @@ bail:
  
  	void GC::AddEdgeCallback(GCEdgeCallback *cb)
  	{
 -		CheckThread();
 +		USING_CALLBACK_LIST(this);
 +
  		cb->prevCB = NULL;
  		cb->nextCB = m_edgeCallbacks;
  		if(m_edgeCallbacks)
-@@ -2710,7 +2979,8 @@ bail:
+@@ -2732,7 +3001,8 @@ bail:
  
  	void GC::RemoveEdgeCallback(GCEdgeCallback *cb)
  	{
 -		CheckThread();
 +		USING_CALLBACK_LIST(this);
 +
  		if( m_edgeCallbacks == cb )
  			m_edgeCallbacks = cb->nextCB;
  		else
-@@ -2722,12 +2992,12 @@ bail:
+@@ -2744,12 +3014,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)
-@@ -2740,9 +3010,18 @@ bail:
+@@ -2762,9 +3032,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)) {
-@@ -2802,6 +3081,8 @@ bail:
+@@ -2824,6 +3103,8 @@ bail:
  
  	void GC::FindMissingWriteBarriers()
  	{
 +		ASSERT_EXCLUSIVE_GC();
 +
  		if(!incrementalValidation)
  			return;
  
-@@ -2863,6 +3144,7 @@ bail:
+@@ -2885,6 +3166,7 @@ bail:
  	void GC::StartGCActivity()
  	{
  		// invoke postsweep callback
 +		USING_CALLBACK_LIST(this);
  		GCCallback *cb = m_callbacks;
  		while(cb) {
  			cb->startGCActivity();
-@@ -2873,6 +3155,7 @@ bail:
+@@ -2895,6 +3177,7 @@ bail:
  	void GC::StopGCActivity()
  	{
  		// invoke postsweep callback
 +		USING_CALLBACK_LIST(this);
  		GCCallback *cb = m_callbacks;
  		while(cb) {
  			cb->stopGCActivity();
-@@ -2883,6 +3166,7 @@ bail:
+@@ -2905,6 +3188,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
@@ -1217,32 +1217,31 @@ 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();
-@@ -856,9 +1014,12 @@ namespace MMgc
+@@ -856,30 +1014,81 @@ 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;
  
- #ifdef _DEBUG
- 		char *msgBuf;
-@@ -870,21 +1031,69 @@ namespace MMgc
+ 		static uint64 ticksToMicros(uint64 ticks) { return (ticks*1000000)/GetPerformanceFrequency(); }
+ 
  		static uint64 ticksToMillis(uint64 ticks) { return (ticks*1000)/GetPerformanceFrequency(); }
  
  		// 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>.
 +		 *
@@ -1305,52 +1304,50 @@ 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
-@@ -896,6 +1105,7 @@ namespace MMgc
+@@ -891,7 +1100,10 @@ namespace MMgc
  
  		bool Destroying() { return destroying; }
  
++		/** @access Requires(request) */
+ 		static GCWeakRef *GetWeakRef(const void *obj);
++
 +		/** @access Requires((request && m_lock) || exclusiveGC) */
  		void ClearWeakRef(const void *obj);
  
  		uintptr	GetStackTop() const;		
-@@ -911,7 +1121,10 @@ namespace MMgc
+@@ -907,7 +1119,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
-@@ -920,35 +1133,60 @@ namespace MMgc
+@@ -916,32 +1131,55 @@ 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;
  
 +		/** @access Requires((request && m_lock) || exclusiveGC) */
  		GCHashtable weakRefs;
- 		friend class GCObject;
- 		friend class GCFinalizedObject;
-+
-+		/** @access Requires(request) */
- 		static GCWeakRef *GetWeakRef(const void *obj);
  
  		bool destroying;
  
 -		// we track the heap size so if it expands due to fixed memory allocations
 -		// we can trigger a mark/sweep, other wise we can have lots of small GC 
 -		// objects allocating tons of fixed memory which results in huge heaps
 -		// and possible out of memory situations.
 +		/**
@@ -1391,17 +1388,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];		
-@@ -960,14 +1198,44 @@ namespace MMgc
+@@ -953,14 +1191,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;
@@ -1436,17 +1433,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;
  
-@@ -979,7 +1247,20 @@ namespace MMgc
+@@ -972,7 +1240,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.
 +		 *
@@ -1457,17 +1454,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);
-@@ -998,69 +1279,163 @@ namespace MMgc
+@@ -991,69 +1272,163 @@ namespace MMgc
  		GCAlloc *noPointersAllocs[kNumSizeClasses];
  		GCLargeAlloc *largeAlloc;
  		GCHeap *heap;
 -		
 +
 +		/** @access Requires(m_lock) */
  		void* AllocBlockIncremental(int size, bool zero=true);
 +
@@ -1629,41 +1626,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);
-@@ -1068,9 +1443,10 @@ namespace MMgc
+@@ -1061,9 +1436,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);
  
-@@ -1093,7 +1469,9 @@ private:
+@@ -1086,7 +1462,9 @@ private:
  private:
  #endif
  
 +#ifndef MMGC_THREADSAFE
  		void CheckThread();
 +#endif
  
  		void PushWorkItem(GCStack<GCWorkItem> &stack, GCWorkItem item);
  
-@@ -1110,17 +1488,37 @@ private:
+@@ -1103,17 +1481,37 @@ private:
  		void CheckFreelists();
  
  		int m_gcLastStackTrace;
 +
 +		/**
 +		 * Used by FindUnmarkedPointers.
 +		 *
 +		 * @access Requires(exclusiveGC)
@@ -1695,17 +1692,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
-@@ -1141,7 +1539,187 @@ public:
+@@ -1134,7 +1532,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)
 +		 */
@@ -2337,16 +2334,16 @@ diff --git a/MMgc/manifest.mk b/MMgc/man
    $(curdir)/GCTests.cpp \
 +  $(curdir)/GCThreads.cpp \
    $(NULL)
  
  ifeq (windows,$(TARGET_OS))
 diff --git a/configure.py b/configure.py
 --- a/configure.py
 +++ b/configure.py
-@@ -87,6 +87,7 @@ MMGC_THREADSAFE = o.getBoolArg('threadsa
+@@ -90,6 +90,7 @@ MMGC_THREADSAFE = o.getBoolArg('threadsa
  MMGC_THREADSAFE = o.getBoolArg('threadsafe-mmgc', False)
  if MMGC_THREADSAFE:
      MMGC_DEFINES['MMGC_THREADSAFE'] = None
 +    MMGC_DEFINES['MMGC_INTERIOR_PTRS'] = None
      NSPR_INCLUDES = o.getStringArg('nspr-includes')
      MMGC_CPPFLAGS += NSPR_INCLUDES + " "
      APP_CPPFLAGS += NSPR_INCLUDES + " "