Updates and imports
authorBenjamin Smedberg <benjamin@smedbergs.us>
Sun, 20 Apr 2008 21:43:09 -0400
changeset 42 53c5098cb79e
parent 41 84ba4253dc28
child 43 a2f5122ed78b
push id1
push userbsmedberg@mozilla.com
push dateMon, 21 Apr 2008 01:54:18 +0000
Updates and imports
bug-427030-v1.patch
gcc43-strict-warnings
series
uninline-fixedmalloc
new file mode 100644
--- /dev/null
+++ b/bug-427030-v1.patch
@@ -0,0 +1,300 @@
+Bug 427030 - A=>B API from jorendorff
+
+diff --git a/MMgc/GC.cpp b/MMgc/GC.cpp
+--- a/MMgc/GC.cpp
++++ b/MMgc/GC.cpp
+@@ -630,6 +630,7 @@ namespace MMgc
+ 			PushWorkItem(work, item);
+ 			Mark(work);
+ 		}
++		MarkLinks(work);
+ 		
+ 		m_currentQueue = NULL;
+ 
+@@ -839,6 +840,14 @@ namespace MMgc
+ 		} else {
+ 			GCAlloc::Free(GetRealPointer(item));
+ 		}
++
++		// Remove all links leading from item.
++		{
++			HardLinks::iterator i =
++				m_hardLinks.lower_bound(PtrPair(item, NULL));  // is NULL guaranteed to be less than all other pointers?
++			while (i != m_hardLinks.end() && i->first.first == item)
++				m_hardLinks.erase(i++);
++		}
+ 		return;
+ 
+ bail:
+@@ -863,6 +872,18 @@ bail:
+ 			noPointersAllocs[i]->ClearMarks();
+ 		}
+ 		largeAlloc->ClearMarks();
++	}
++
++	void GC::SweepLinks()
++	{
++		HardLinks::iterator i = m_hardLinks.begin();
++		while (i != m_hardLinks.end()) {
++			void *source = i->first.first;
++			if (!GetMark(source))
++				m_hardLinks.erase(i++);
++			else
++				++i;
++		}
+ 	}
+ 
+ 	void GC::Finalize()
+@@ -909,7 +930,7 @@ bail:
+ 			DumpMemoryInfo();
+ 		}
+ #endif
+-		
++		SweepLinks();
+ 
+ 		// invoke presweep on all callbacks
+ 		for (GCCallback *cb = m_callbacks; cb; cb = cb->nextCB)
+@@ -1293,6 +1314,29 @@ bail:
+ 
+ 		PushWorkItem(work, item);
+ 		Mark(work);
++	}
++
++	void GC::MarkLinks(GCStack<GCWorkItem> &work)
++	{
++		for (;;) {
++			bool found = false;
++			for (HardLinks::iterator i = m_hardLinks.begin();
++			     i != m_hardLinks.end();
++			     ++i) {
++				void *source = i->first.first;
++				void *target = i->first.second;
++
++				GCAssert(i->second != 0);
++				if (GetMark(source) && !GetMark(target)) {
++					GCWorkItem item(target, Size(target), true);
++					PushWorkItem(work, item);
++					found = true;
++				}
++			}
++			if (!found)
++				break;
++			Mark(work);
++		}
+ 	}
+ 
+ 	GCRoot::GCRoot(GC * _gc) : gc(_gc)
+@@ -2759,6 +2803,7 @@ bail:
+ 			cb->lastmark(m_incrementalWork);
+ 
+ 		MarkQueueAndStack(m_incrementalWork);
++		MarkLinks(m_incrementalWork);
+ 
+ 		m_currentQueue = NULL;
+ 
+@@ -2976,6 +3021,43 @@ bail:
+ 			root->next->prev = root->prev;
+ 	}
+ 
++	void GC::Link(void *source, void *target)
++	{
++#ifdef MMGC_THREADSAFE
++		GCAutoLock _lock(m_lock);
++		GCAssert(!m_gcRunning);
++#else
++		CheckThread();
++#endif
++		GCAssert(source != NULL);
++		GCAssert(IsGCMemory(source));
++		GCAssert(source == FindBeginning(source));
++		GCAssert(ContainsPointers(source));
++		GCAssert(target != NULL);
++		GCAssert(IsGCMemory(target));
++		GCAssert(target == FindBeginning(target));
++
++		size_t i = ++m_hardLinks[PtrPair(source, target)];
++		(void) i;
++		GCAssert(i != 0);
++	}
++
++	void GC::Unlink(void *source, void *target)
++	{
++#ifdef MMGC_THREADSAFE
++		GCAutoLock _lock(m_lock);
++		GCAssert(!m_gcRunning);
++#else
++		CheckThread();
++#endif
++
++		PtrPair pair(source, target);
++		HardLinks::iterator iter = m_hardLinks.find(pair);
++		GCAssert(iter != m_hardLinks.end());
++		if (--iter->second == 0)
++			m_hardLinks.erase(iter);
++	}
++
+ 	void GC::AddCallback(GCCallback *cb)
+ 	{
+ 		cb->prevCB = NULL;
+diff --git a/MMgc/GC.h b/MMgc/GC.h
+--- a/MMgc/GC.h
++++ b/MMgc/GC.h
+@@ -39,6 +39,9 @@
+ 
+ #ifndef __GC__
+ #define __GC__
++
++#include <map>
++#include <utility>
+ 
+ #if defined MMGC_IA32
+ 
+@@ -731,6 +734,12 @@ namespace MMgc
+ 		 */
+ 		void Free(void *ptr);
+ 
++		/** @access Requires(request) */
++		void Link(void *source, void *target);
++
++		/** @access Requires(request) */
++		void Unlink(void *source, void *target);
++
+ 		/**
+ 		 * return the size of a piece of memory, may be bigger than what was asked for
+ 		 *
+@@ -1358,9 +1367,13 @@ namespace MMgc
+ 		/** @access Requires(exclusiveGC) */
+ 		void ForceSweep() { Sweep(true); }
+ 		/** @access Requires(exclusiveGC) */
++		void SweepLinks();
++		/** @access Requires(exclusiveGC) */
+ 		void Mark(GCStack<GCWorkItem> &work);
+ 		/** @access Requires(exclusiveGC) */
+ 		void MarkQueueAndStack(GCStack<GCWorkItem> &work);
++		/** @access Requires(exclusiveGC) */
++		void MarkLinks(GCStack<GCWorkItem> &work);
+ 		/** @access Requires(exclusiveGC) */
+ 		void MarkItem(GCStack<GCWorkItem> &work)
+ 		{
+@@ -1435,7 +1448,12 @@ namespace MMgc
+ 		GCRoot *m_roots;
+ 		void AddRoot(GCRoot *root);
+ 		void RemoveRoot(GCRoot *root);
+-		
++
++		typedef std::pair<void *, void *> PtrPair;
++		typedef std::map<PtrPair, size_t> HardLinks;
++		/** @access Requires(request && m_lock || exclusiveGC) */
++		HardLinks m_hardLinks;
++
+ 		/**
+ 		 * Points to the head of a linked list of callback objects.
+ 		 *
+diff --git a/MMgc/GCTests.cpp b/MMgc/GCTests.cpp
+--- a/MMgc/GCTests.cpp
++++ b/MMgc/GCTests.cpp
+@@ -173,6 +173,96 @@ namespace MMgc
+ 			delete wr->get();
+ 	}
+ 
++	class HardLinkTests {
++		static GCObject *a;
++		static GCObject *b;
++		static GCWeakRef *wra;
++		static GCWeakRef *wrb;
++
++		template <class Fn>
++		static void _tidy2(Fn fn)
++		{
++			char buf[64];
++			sprintf(buf, "%p", buf);  // don't optimize away buf
++			fn();
++		}
++
++		// Call a function and wipe its prints off the stack afterwards.
++		template <class Fn>
++		static void tidy(Fn fn)
++		{
++			_tidy2(fn);
++			gc->CleanStack(true);
++		}
++
++		static void makeObjects(bool linkAB, bool linkBA) {
++			a = new(gc) GCObject;
++			b = new(gc) GCObject;
++			if (linkAB) gc->Link(a, b);
++			if (linkBA) gc->Link(b, a);
++			wra = a->GetWeakRef();
++			wrb = b->GetWeakRef();
++		}
++
++		static void makeNonLinkedObjects() { makeObjects(false, false); }
++		static void makeLinkedObjects() { makeObjects(true, false); }
++		static void makeLinkCycle() { makeObjects(true, true); }
++
++		// Test 0: make A and B, then make A unreachable.
++		// Check that only A is collected.
++		static void test0() {
++			tidy(makeNonLinkedObjects);
++			volatile void *keep[] = {b, wra, wrb};  (void) keep;
++			collect();
++			GCAssert(wra->get() == NULL);
++			GCAssert(wrb->get() != NULL);
++		}
++
++		// Test 1: link A->B, then make B unreachable.
++		// Check that neither is collected.
++		static void test1() {
++			tidy(makeLinkedObjects);
++			volatile void *keep[] = {a, wra, wrb};  (void) keep;
++			collect();
++			GCAssert(wra->get() != NULL);
++			GCAssert(wrb->get() != NULL);
++		}
++
++		// Test 2: link A->B, then make A unreachable.
++		// Check that A is collected.
++		static void test2() {
++			tidy(makeLinkedObjects);
++			volatile void *keep[] = {b, wra, wrb};  (void) keep;
++			collect();
++			GCAssert(wra->get() == NULL);
++			GCAssert(wrb->get() != NULL);
++		}
++
++		// Test 3: link A->B, B->A, then make both unreachable.
++		// Check that both are collected.
++		static void test3() {
++			tidy(makeLinkCycle);
++			volatile void *keep[] = {wra, wrb};  (void) keep;
++			collect();
++			GCAssert(wra->get() == NULL);
++			GCAssert(wrb->get() == NULL);
++		}
++
++	public:
++		static void run()
++		{
++			tidy(test0);
++			tidy(test1);
++			tidy(test2);
++			tidy(test3);
++		}
++	};
++
++	GCObject *HardLinkTests::a;
++	GCObject *HardLinkTests::b;
++	GCWeakRef *HardLinkTests::wra;
++	GCWeakRef *HardLinkTests::wrb;
++
+ 	void RunGCTests(GC *g)
+ 	{
+ 		gc = g;
+@@ -184,6 +274,7 @@ namespace MMgc
+ 		weakRefFreeSmall();
+ 		weakRefFreeLarge();
+ 		drcApolloTest();
++		HardLinkTests::run();
+ #ifdef MMGC_THREADSAFE
+ 		g->OnLeaveRequest();
+ #endif
new file mode 100644
--- a/series
+++ b/series
@@ -1,12 +1,16 @@
+# Currently based against actionmonkey-tamarin revision 3756f5b237c3
 remove-extra-auto-storage-specifiers
 const-workitem.patch
 gcstack-access
 workitems-notgc-noassert
 enable-traces
 debug-print-finalizers
 finalizable-merge-fixup
 remove-finalize-method
 export-gcthread
 valgrind-annotations
 stack-access2
 double-mark-is-ok
+uninline-fixedmalloc
+gcc43-strict-warnings
+bug-427030-v1.patch
new file mode 100644
--- /dev/null
+++ b/uninline-fixedmalloc
@@ -0,0 +1,91 @@
+diff --git a/MMgc/FixedMalloc.cpp b/MMgc/FixedMalloc.cpp
+--- a/MMgc/FixedMalloc.cpp
++++ b/MMgc/FixedMalloc.cpp
+@@ -122,6 +122,41 @@
+ 		GCAssert(instance != NULL);
+ 		delete instance;
+ 		instance = NULL;
++	}
++
++	void* FixedMalloc::Alloc(size_t size)
++	{
++		void *item;
++		GCAssert(size + 3 > size);
++		// overflow detection
++		if(size+3 < size)
++			return NULL;
++		size = (size+3)&~3;
++		if (size <= (size_t)kLargestAlloc) {
++			item = FindSizeClass(size)->Alloc(size);
++		} else {
++			item = LargeAlloc(size);
++		}
++		VALGRIND_MEMPOOL_ALLOC(this, item, size);
++		VALGRIND_CHECK_MEM_IS_DEFINED(item, size);
++		fprintf(stderr, "FixedMalloc::Alloc = %p\n", item);
++		return item;
++	}
++		
++	void FixedMalloc::Free(void *item)
++	{
++		if(item == 0)
++			return;
++
++		VALGRIND_MEMPOOL_FREE(this, item);
++		
++		// small things are never allocated on the 4K boundary b/c the block
++		// header structure is stored there, large things always are		
++		if(IsLargeAlloc(item)) {
++			LargeFree(item);
++		} else {		
++			FixedAllocSafe::GetFixedAllocSafe(item)->Free(item);
++		}
+ 	}
+ 
+ 	FixedMalloc::FixedMalloc(GCHeap* heap)
+diff --git a/MMgc/FixedMalloc.h b/MMgc/FixedMalloc.h
+--- a/MMgc/FixedMalloc.h
++++ b/MMgc/FixedMalloc.h
+@@ -62,40 +62,8 @@
+ 			return instance;
+ 		}
+ 
+-		inline void* Alloc(size_t size)
+-		{
+-			void *item;
+-			GCAssert(size + 3 > size);
+-			// overflow detection
+-			if(size+3 < size)
+-				return NULL;
+-			size = (size+3)&~3;
+-			if (size <= (size_t)kLargestAlloc) {
+-				item = FindSizeClass(size)->Alloc(size);
+-			} else {
+-				item = LargeAlloc(size);
+-			}
+-                        VALGRIND_MEMPOOL_ALLOC(this, item, size);
+-			VALGRIND_CHECK_MEM_IS_DEFINED(item, size);
+-			fprintf(stderr, "FixedMalloc::Alloc = %p\n", item);
+-			return item;
+-		}
+-
+-		inline void Free(void *item)
+-		{
+-			if(item == 0)
+-				return;
+-
+-			VALGRIND_MEMPOOL_FREE(this, item);
+-
+-			// small things are never allocated on the 4K boundary b/c the block
+-			// header structure is stored there, large things always are		
+-			if(IsLargeAlloc(item)) {
+-				LargeFree(item);
+-			} else {		
+-				FixedAllocSafe::GetFixedAllocSafe(item)->Free(item);
+-			}
+-		}
++		void* Alloc(size_t size);
++		void Free(void *item);
+ 
+ 		size_t Size(const void *item)
+ 		{