Merge changes from jorendorff
authorbenjamin@smedbergs.us
Mon, 10 Dec 2007 14:12:50 -0500
changeset 19 9440555b77389c85b8100c0e8215f3b460613e2d
parent 13 6a29ec7e67a19d85a0800edaa50ce47243b56e53 (diff)
parent 18 964b0d139a110b363e3eba3d08426300b59ed477 (current diff)
child 20 458babdaa518471a7a2e4b09f514955c86b7c60f
push id1
push userbsmedberg@mozilla.com
push dateMon, 21 Apr 2008 01:54:18 +0000
Merge changes from jorendorff
.hgignore
mmgc-threadsafe-take2
series
--- a/.hgignore
+++ b/.hgignore
@@ -1,1 +1,3 @@
+syntax: glob
 status
+guards
new file mode 100644
--- /dev/null
+++ b/alloc-backtrace
@@ -0,0 +1,79 @@
+diff --git a/MMgc/GC.cpp b/MMgc/GC.cpp
+--- a/MMgc/GC.cpp
++++ b/MMgc/GC.cpp
+@@ -97,6 +97,11 @@ extern "C" greg_t _getsp(void);
+ extern "C" greg_t _getsp(void);
+ #endif
+ 
++#include <execinfo.h>
++
++#include <map>
++#include <string>
++
+ #if defined(_MSC_VER) && defined(_DEBUG)
+ // we turn on exceptions in DEBUG builds
+ #pragma warning(disable:4291) // no matching operator delete found; memory will not be freed if initialization throws an exception
+@@ -112,6 +117,8 @@ extern "C" greg_t _getsp(void);
+ 
+ namespace MMgc
+ {
++	typedef std::map<const void*, std::string> AllocNameSet;
++	static AllocNameSet sAllocNameSet;
+ 
+ 	static const char kGraphvizRootStyle[] = "style=\"filled\", color=\"#ccddbb\"";
+ 	static const char kGraphvizStackStyle[] = "style=\"filled\", color=\"#bbddcc\"";
+@@ -589,6 +596,36 @@ namespace MMgc
+ 			memset(item, 0, Size(item));
+ 		}
+ #endif
++		static char const *const kSkipFrames[] = {
++			"_ZN4MMgc17GCFinalizedObjectnwEjPNS_2GCEj",
++			"_ZN4MMgc8GCObjectnwEjPNS_2GCEj",
++			"_ZN13XPCOMGCObjectnwEj",
++			"_ZN22XPCOMGCFinalizedObjectnwEj",
++			NULL
++		};
++
++		void *btbuf[4];
++		int btsize = backtrace(btbuf, 4);
++		char **btarray = backtrace_symbols(btbuf, btsize);
++
++		char **frame = btarray;
++
++		// skip btbuf[0] which is this func!
++		++frame;
++
++		for (char const *const *skipFrame = kSkipFrames; *skipFrame; ++skipFrame) {
++			if (strstr(*frame, *skipFrame))
++				++frame;
++		}
++
++		sAllocNameSet[item] = *frame;
++		
++		static FILE *sAllocLog = getenv("MMGC_ALLOC_LOG") ? fopen(getenv("MMGC_ALLOC_LOG"), "w") : NULL;
++
++		if (sAllocLog)
++			fprintf(sAllocLog, "Item\t%p\t%s\n", item, *frame);
++
++		free(btarray);
+ 
+ 		return item;
+ 	}
+@@ -2993,8 +3030,15 @@ bail:
+ 
+ 	void GC::GraphNode(const void *obj, const char *style)
+ 	{
+-		if (m_gvFile)
+-			fprintf(m_gvFile, "    P%p [%s];\n", obj, style);
++		if (m_gvFile) {
++			const char *type = "";
++
++			AllocNameSet::iterator i = sAllocNameSet.find(obj);
++			if (i != sAllocNameSet.end())
++				type = i->second.c_str();
++
++			fprintf(m_gvFile, "    P%p [label=\"%s\", %s];\n", obj, type, style);
++		}
+ 	}
+ 
+ 	void GC::GraphEdge(const void *fromObj,
new file mode 100644
--- /dev/null
+++ b/const-workitem.patch
@@ -0,0 +1,12 @@
+diff --git a/MMgc/GC.h b/MMgc/GC.h
+--- a/MMgc/GC.h
++++ b/MMgc/GC.h
+@@ -901,7 +901,7 @@ namespace MMgc
+ 
+ 		uintptr	GetStackTop() const;		
+ 		
+-		void PushWorkItem(GCWorkItem &item) { PushWorkItem(m_incrementalWork, item); }
++		void PushWorkItem(const GCWorkItem &item) { PushWorkItem(m_incrementalWork, item); }
+ 
+ 	private:
+ 
new file mode 100644
--- /dev/null
+++ b/gc-graph
@@ -0,0 +1,191 @@
+diff --git a/MMgc/GC.cpp b/MMgc/GC.cpp
+--- a/MMgc/GC.cpp
++++ b/MMgc/GC.cpp
+@@ -113,6 +113,11 @@ namespace MMgc
+ namespace MMgc
+ {
+ 
++	static const char kGraphvizRootStyle[] = "style=\"filled\", color=\"#ccddbb\"";
++	static const char kGraphvizStackStyle[] = "style=\"filled\", color=\"#bbddcc\"";
++	static const char kGraphvizObjectStyle[] = "style=\"filled\", color=\"#b3cc99\"";
++	static const char kGraphvizConservativeEdge[] = "color=\"#808080\"";
++
+ #ifdef MMGC_DRC
+ 
+ 	// how many objects trigger a reap, should be high
+@@ -257,6 +262,8 @@ namespace MMgc
+ 		  finalizedValue(true),
+ 		  // Expand, don't collect, until we hit this threshold
+ 		  collectThreshold(256)
++		, m_gvFile(NULL)
++		  
+ 	{		
+ 		// sanity check for all our types
+ 		GCAssert (sizeof(int8) == 1);
+@@ -325,10 +332,15 @@ namespace MMgc
+ 		// keep GC::Size honest
+ 		GCAssert(offsetof(GCLargeAlloc::LargeBlock, usableSize) == offsetof(GCAlloc::GCBlock, size));
+ 
++		const char *gvFile = getenv("MMGC_GRAPHVIZ_LOG");
++		if (gvFile)
++			StartGraphing(gvFile);
+ 	}
+ 
+ 	GC::~GC()
+ 	{
++		StopGraphing();
++
+ 		// Force all objects to be destroyed
+ 		destroying = true;
+ 		ClearMarks();
+@@ -381,6 +393,12 @@ namespace MMgc
+ 
+ 	void GC::Collect()
+ 	{
++		static int cnum = 0;
++
++		if (m_gvFile)
++			fprintf(m_gvFile, "subgraph GC%i {\n", ++cnum);
++			
++
+ 		// invoke precollect callback
+ 		bool vetoed = false;
+ 		GCCallback *cb = m_callbacks;
+@@ -434,6 +452,8 @@ namespace MMgc
+ #ifdef DEBUGGER
+ 		StopGCActivity();
+ #endif
++		if (m_gvFile)
++			fprintf(m_gvFile, "}\n");
+ 	}
+ 
+ 	void GC::Trace(const void *stackStart/*=NULL*/, size_t stackSize/*=0*/)
+@@ -455,6 +475,15 @@ namespace MMgc
+ 			GCRoot *r = m_roots;
+ 			while(r) {
+ 				GCWorkItem item = r->GetWorkItem();
++
++				if (m_gvFile) {
++					fprintf(m_gvFile,
++						"    P%p [label=\"root at %p\", %s];\n",
++						item.ptr,
++						item.ptr,
++						(const char*) kGraphvizRootStyle);
++				}
++
+ 				MarkItem(item, work);
+ 				r = r->next;
+ 			}
+@@ -1034,6 +1063,14 @@ bail:
+ 		// this is where we will clear to when CleanStack is called
+ 		if(rememberedStackTop == 0 || rememberedStackTop > item.ptr) {
+ 			rememberedStackTop = item.ptr;
++		}
++
++		if (m_gvFile) {
++			fprintf(m_gvFile,
++				"    P%p [label=\"stack at %p\", %s];\n",
++				item.ptr,
++				item.ptr,
++				(const char*) kGraphvizStackStyle);
+ 		}
+ 
+ 		PushWorkItem(work, item);
+@@ -2176,6 +2213,8 @@ bail:
+ 		// set the mark bits on this guy
+ 		if(wi.IsGCItem())
+ 		{
++			GraphNode(wi.ptr, kGraphvizObjectStyle);
++
+ 			int b = SetMark(wi.ptr);
+ 			(void)b;
+ #ifdef _DEBUG
+@@ -2250,6 +2289,8 @@ bail:
+ 				//if(GCAlloc::IsWhite(block, itemNum)) 
+ 				if((bits2 & ((GCAlloc::kMark|GCAlloc::kQueued)<<shift)) == 0)
+ 				{
++					GraphEdge(wi.ptr, p, item, kGraphvizConservativeEdge);
++
+ 					if(block->alloc->ContainsPointers())
+ 					{
+ 						// try custom marking
+@@ -2324,6 +2365,8 @@ bail:
+ 				GCLargeAlloc::LargeBlock *b = GCLargeAlloc::GetBlockHeader(item);
+ 				if((b->flags & (GCLargeAlloc::kQueuedFlag|GCLargeAlloc::kMarkFlag)) == 0) 
+ 				{
++					GraphEdge(wi.ptr, p, item, kGraphvizConservativeEdge);
++
+ 					if (m_edgeCallbacks)
+ 						FireFoundEdgeTo(item);
+ 
+@@ -2931,5 +2974,35 @@ bail:
+ 	}
+ #endif
+ 
+-
++	void GC::StartGraphing(const char *filename)
++	{
++		StopGraphing();
++		m_gvFile = fopen(filename, "w");
++		fprintf(m_gvFile, "digraph GC {\n    node [shape=box];\n");
++	}
++
++	void GC::StopGraphing()
++	{
++		if (m_gvFile) {
++			fprintf(m_gvFile, ";\n");
++
++			fclose(m_gvFile);
++			m_gvFile = NULL;
++		}
++	}
++
++	void GC::GraphNode(const void *obj, const char *style)
++	{
++		if (m_gvFile)
++			fprintf(m_gvFile, "    P%p [%s];\n", obj, style);
++	}
++
++	void GC::GraphEdge(const void *fromObj,
++			   const void *fromField,
++			   const void *toObj,
++			   const char *style)
++	{
++		if (m_gvFile)
++			fprintf(m_gvFile, "    P%p -> P%p [%s];\n", fromObj, toObj, style);
++	}
+ }
+diff --git a/MMgc/GC.h b/MMgc/GC.h
+--- a/MMgc/GC.h
++++ b/MMgc/GC.h
+@@ -1139,6 +1139,18 @@ public:
+ 		void WhosPointingAtMe(void* me, int recurseDepth=0, int currentDepth=0);
+     	void ProbeForMatch(const void *mem, size_t size, uintptr value, int recurseDepth, int currentDepth);
+ #endif
++
++	public:
++		void StartGraphing(const char *filename);
++		void StopGraphing();
++		void GraphNode(const void *obj, const char *style);
++		void GraphEdge(const void *fromObj,
++			       const void *fromField,
++			       const void *toObj,
++			       const char *style);
++
++	private:
++		FILE *m_gvFile;
+ 	};
+ 
+ 	// helper class to wipe out vtable pointer of members for DRC
+diff --git a/MMgc/GCTypes.h b/MMgc/GCTypes.h
+--- a/MMgc/GCTypes.h
++++ b/MMgc/GCTypes.h
+@@ -42,6 +42,8 @@
+ #ifdef _MAC
+ #include <stdint.h>
+ #endif
++
++#include <stdio.h>
+ 
+ #if defined(HAVE_VISIBILITY_ATTRIBUTE)
+ #define MMGC_VISIBILITY_DEFAULT __attribute__ ((visibility ("default")))
new file mode 100644
--- /dev/null
+++ b/gcstack-access
@@ -0,0 +1,66 @@
+diff --git a/MMgc/GC.cpp b/MMgc/GC.cpp
+--- a/MMgc/GC.cpp
++++ b/MMgc/GC.cpp
+@@ -1,3 +1,4 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+ /* ***** BEGIN LICENSE BLOCK *****
+  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+  *
+@@ -458,6 +459,8 @@ namespace MMgc
+ 		SAMPLE_CHECK();
+ 
+ 		GCStack<GCWorkItem> work;
++
++		m_currentQueue = &work;
+ 		{
+ #ifdef GCHEAP_LOCK
+ 			GCAcquireSpinlock lock(m_rootListLock);
+@@ -484,6 +487,8 @@ namespace MMgc
+ 			Mark(work);
+ 		}
+ 		
++		m_currentQueue = NULL;
++
+ 		SAMPLE_CHECK();
+ 	}
+ 
+@@ -2376,6 +2381,8 @@ bail:
+ 			return;
+ 		} 
+ 
++		m_currentQueue = &m_incrementalWork;
++
+ #ifdef DEBUGGER
+ 		StartGCActivity();
+ #endif
+@@ -2409,6 +2416,8 @@ bail:
+ 
+ 		lastMarkTicks = GetPerformanceCounter();
+ 		markTicks += lastMarkTicks - start;
++
++		m_currentQueue = NULL;
+ 
+ #ifdef DEBUGGER
+ 		if(GC::gcstats) {
+diff --git a/MMgc/GC.h b/MMgc/GC.h
+--- a/MMgc/GC.h
++++ b/MMgc/GC.h
+@@ -548,6 +548,9 @@ namespace MMgc
+ 
+ 		bool incremental;
+ 
++		// This member is only available during tracing
++		GCStack<GCWorkItem> *m_currentQueue;
++
+ 		// -- Interface
+ 		GC(GCHeap *heap);
+ 		virtual ~GC();
+@@ -901,7 +904,7 @@ namespace MMgc
+ 
+ 		uintptr	GetStackTop() const;		
+ 		
+-		void PushWorkItem(const GCWorkItem &item) { PushWorkItem(m_incrementalWork, item); }
++		void PushWorkItem(const GCWorkItem &item) { PushWorkItem(*m_currentQueue, item); }
+ 
+ 	private:
+ 
--- a/series
+++ b/series
@@ -1,6 +1,11 @@
 tweak-esc-main.sh
-configure-with-threadsafe-mmgc
-mmgc-threadsafe
-mmgc-threadsafe-gctests
-mmgc-graphviz
-mmgc-bit-checks
+const-workitem.patch
+gcstack-access
+workitems-notgc-noassert
+gc-graph #+graphviz
+alloc-backtrace #+graphviz
+configure-with-threadsafe-mmgc #+threadsafe
+mmgc-threadsafe #+threadsafe
+mmgc-threadsafe-gctests #+threadsafe
+mmgc-graphviz #+jorendorff-graphviz
+mmgc-bit-checks #+threadsafe
new file mode 100644
--- /dev/null
+++ b/workitems-notgc-noassert
@@ -0,0 +1,13 @@
+diff --git a/MMgc/GC.cpp b/MMgc/GC.cpp
+--- a/MMgc/GC.cpp
++++ b/MMgc/GC.cpp
+@@ -2191,7 +2191,9 @@ bail:
+ 		}
+ 		else
+ 		{
++#if 0 // We want to pass GCWorkItems which are interior pointers to a GC object
+ 			GCAssert(!IsPointerToGCPage(wi.ptr));
++#endif
+ 		}
+ 
+ 		uintptr _memStart = memStart;