зеркало из https://github.com/mozilla/gecko-dev.git
Fix for bug 466157 (Enable dumping of cycle-collector graphs in any build). r=dbaron, a=jst.
--HG-- extra : rebase_source : b47d149434c735981a9a80ae6016624120fee371
This commit is contained in:
Родитель
0efed87d47
Коммит
79c4d12751
|
@ -575,7 +575,7 @@ nsDOMWindowUtils::Focus(nsIDOMElement* aElement)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::GarbageCollect()
|
||||
nsDOMWindowUtils::GarbageCollect(nsICycleCollectorListener *aListener)
|
||||
{
|
||||
// Always permit this in debug builds.
|
||||
#ifndef DEBUG
|
||||
|
@ -584,7 +584,7 @@ nsDOMWindowUtils::GarbageCollect()
|
|||
}
|
||||
#endif
|
||||
|
||||
nsJSContext::CC();
|
||||
nsJSContext::CC(aListener);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -307,7 +307,7 @@ NS_IMETHODIMP
|
|||
nsCCMemoryPressureObserver::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
const PRUnichar* aData)
|
||||
{
|
||||
nsJSContext::CC();
|
||||
nsJSContext::CC(nsnull);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -3512,7 +3512,7 @@ nsJSContext::ScriptExecuted()
|
|||
|
||||
//static
|
||||
void
|
||||
nsJSContext::CC()
|
||||
nsJSContext::CC(nsICycleCollectorListener *aListener)
|
||||
{
|
||||
NS_TIME_FUNCTION_MIN(1.0);
|
||||
|
||||
|
@ -3527,7 +3527,7 @@ nsJSContext::CC()
|
|||
// nsCycleCollector_collect() no longer forces a JS garbage collection,
|
||||
// so we have to do it ourselves here.
|
||||
nsContentUtils::XPConnect()->GarbageCollect();
|
||||
sCollectedObjectsCounts = nsCycleCollector_collect();
|
||||
sCollectedObjectsCounts = nsCycleCollector_collect(aListener);
|
||||
sCCSuspectedCount = nsCycleCollector_suspectedCount();
|
||||
sSavedGCCount = JS_GetGCParameter(nsJSRuntime::sRuntime, JSGC_NUMBER);
|
||||
#ifdef DEBUG_smaug
|
||||
|
@ -3615,7 +3615,7 @@ nsJSContext::IntervalCC()
|
|||
{
|
||||
if ((PR_Now() - sPreviousCCTime) >=
|
||||
PRTime(NS_MIN_CC_INTERVAL * PR_USEC_PER_MSEC)) {
|
||||
nsJSContext::CC();
|
||||
nsJSContext::CC(nsnull);
|
||||
return PR_TRUE;
|
||||
}
|
||||
#ifdef DEBUG_smaug
|
||||
|
|
|
@ -188,7 +188,7 @@ public:
|
|||
|
||||
// CC does always call cycle collector and it also updates the counters
|
||||
// that MaybeCC uses.
|
||||
static void CC();
|
||||
static void CC(nsICycleCollectorListener *aListener);
|
||||
|
||||
// MaybeCC calls cycle collector if certain conditions are fulfilled.
|
||||
// The conditions are:
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
* getInterface on a DOMWindow.
|
||||
*/
|
||||
|
||||
interface nsICycleCollectorListener;
|
||||
interface nsIDOMNode;
|
||||
interface nsIDOMNodeList;
|
||||
interface nsIDOMElement;
|
||||
|
@ -53,7 +54,7 @@ interface nsIDOMEvent;
|
|||
interface nsITransferable;
|
||||
interface nsIQueryContentEventResult;
|
||||
|
||||
[scriptable, uuid(8430e730-a085-421e-bb72-39fcf73fe57b)]
|
||||
[scriptable, uuid(bf4df3a0-4567-47ec-be6d-9ec60eaed63c)]
|
||||
interface nsIDOMWindowUtils : nsISupports {
|
||||
|
||||
/**
|
||||
|
@ -267,13 +268,16 @@ interface nsIDOMWindowUtils : nsISupports {
|
|||
void focus(in nsIDOMElement aElement);
|
||||
|
||||
/**
|
||||
* Force a garbage collection. This will run the cycle-collector twice to
|
||||
* make sure all garbage is collected.
|
||||
* Force a garbage collection followed by a cycle collection.
|
||||
*
|
||||
* Will throw a DOM security error if called without UniversalXPConnect
|
||||
* privileges in non-debug builds. Available to all callers in debug builds.
|
||||
*
|
||||
* @param aListener listener that receives information about the CC graph
|
||||
* (see @mozilla.org/cycle-collector-logger;1 for a logger
|
||||
* component)
|
||||
*/
|
||||
void garbageCollect();
|
||||
void garbageCollect([optional] in nsICycleCollectorListener aListener);
|
||||
|
||||
/**
|
||||
* Force processing of any queued paints
|
||||
|
|
|
@ -126,6 +126,7 @@ XPIDLSRCS = \
|
|||
nsIConsoleListener.idl \
|
||||
nsIConsoleMessage.idl \
|
||||
nsIConsoleService.idl \
|
||||
nsICycleCollectorListener.idl \
|
||||
nsIDebug2.idl \
|
||||
nsIErrorService.idl \
|
||||
nsIException.idl \
|
||||
|
|
|
@ -146,6 +146,7 @@
|
|||
#include "nsTPtrArray.h"
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "nsICycleCollectorListener.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
@ -651,11 +652,6 @@ struct GCGraph
|
|||
// Add/Remove/Has rather than PutEntry/RemoveEntry/GetEntry.
|
||||
typedef nsTHashtable<nsVoidPtrHashKey> PointerSet;
|
||||
|
||||
#ifdef DEBUG_CC
|
||||
static void
|
||||
WriteGraph(FILE *stream, GCGraph &graph, const void *redPtr);
|
||||
#endif
|
||||
|
||||
static inline void
|
||||
ToParticipant(nsISupports *s, nsXPCOMCycleCollectionParticipant **cp);
|
||||
|
||||
|
@ -995,8 +991,9 @@ struct nsCycleCollector
|
|||
nsPurpleBufferEntry* Suspect2(nsISupports *n);
|
||||
PRBool Forget2(nsPurpleBufferEntry *e);
|
||||
|
||||
PRUint32 Collect(PRUint32 aTryCollections = 1);
|
||||
PRBool BeginCollection();
|
||||
PRUint32 Collect(PRUint32 aTryCollections,
|
||||
nsICycleCollectorListener *aListener);
|
||||
PRBool BeginCollection(nsICycleCollectorListener *aListener);
|
||||
PRBool FinishCollection();
|
||||
PRUint32 SuspectedCount();
|
||||
void Shutdown();
|
||||
|
@ -1013,7 +1010,6 @@ struct nsCycleCollector
|
|||
|
||||
FILE *mPtrLog;
|
||||
|
||||
void MaybeDrawGraphs();
|
||||
void Allocated(void *n, size_t sz);
|
||||
void Freed(void *n);
|
||||
|
||||
|
@ -1105,20 +1101,6 @@ Fault(const char *msg, const void *ptr=nsnull)
|
|||
else
|
||||
printf("Fatal fault in cycle collector: %s\n", msg);
|
||||
|
||||
|
||||
if (sCollector->mGraph.mRootCount > 0) {
|
||||
FILE *stream;
|
||||
#ifdef WIN32
|
||||
const char fname[] = "c:\\fault-graph.dot";
|
||||
#else
|
||||
const char fname[] = "/tmp/fault-graph.dot";
|
||||
#endif
|
||||
printf("depositing faulting cycle-collection graph in %s\n", fname);
|
||||
stream = fopen(fname, "w+");
|
||||
WriteGraph(stream, sCollector->mGraph, ptr);
|
||||
fclose(stream);
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
@ -1263,6 +1245,95 @@ GraphWalker<Visitor>::DoWalk(nsDeque &aQueue)
|
|||
}
|
||||
|
||||
|
||||
class nsCycleCollectorLogger : public nsICycleCollectorListener
|
||||
{
|
||||
public:
|
||||
nsCycleCollectorLogger() : mStream(nsnull)
|
||||
{
|
||||
}
|
||||
~nsCycleCollectorLogger()
|
||||
{
|
||||
if (mStream) {
|
||||
fclose(mStream);
|
||||
}
|
||||
}
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD Begin()
|
||||
{
|
||||
char name[255];
|
||||
sprintf(name, "cc-edges-%d.log", ++gLogCounter);
|
||||
mStream = fopen(name, "w");
|
||||
|
||||
return mStream ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
NS_IMETHOD NoteObject(PRUint64 aAddress, const char *aObjectDescription)
|
||||
{
|
||||
fprintf(mStream, "%p %s\n", (void*)aAddress, aObjectDescription);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHOD NoteEdge(PRUint64 aFromAddress, PRUint64 aToAddress,
|
||||
const char *aEdgeName)
|
||||
{
|
||||
fprintf(mStream, "> %p %s\n", (void*)aToAddress, aEdgeName);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHOD BeginDescriptions()
|
||||
{
|
||||
fputs("==========\n", mStream);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHOD DescribeRefcountedObject(PRUint64 aAddress, PRUint32 aKnownEdges,
|
||||
PRUint32 aTotalEdges)
|
||||
{
|
||||
PRBool root = aKnownEdges != aTotalEdges;
|
||||
fprintf(mStream, "%p", (void*)aAddress);
|
||||
if (root) {
|
||||
fprintf(mStream, " [root] [%u/%u]", aKnownEdges, aTotalEdges);
|
||||
}
|
||||
fputc('\n', mStream);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHOD DescribeGCedObject(PRUint64 aAddress, PRBool aMarked)
|
||||
{
|
||||
fprintf(mStream, "%p%s\n", (void*)aAddress, aMarked ? " [root]" : "");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHOD End()
|
||||
{
|
||||
fclose(mStream);
|
||||
mStream = nsnull;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
FILE *mStream;
|
||||
|
||||
static PRUint32 gLogCounter;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsCycleCollectorLogger, nsICycleCollectorListener)
|
||||
|
||||
PRUint32 nsCycleCollectorLogger::gLogCounter = 0;
|
||||
|
||||
nsresult
|
||||
nsCycleCollectorLoggerConstructor(nsISupports* aOuter,
|
||||
const nsIID& aIID,
|
||||
void* *aInstancePtr)
|
||||
{
|
||||
NS_ENSURE_TRUE(!aOuter, NS_ERROR_NO_AGGREGATION);
|
||||
|
||||
nsISupports *logger = new nsCycleCollectorLogger();
|
||||
|
||||
return logger->QueryInterface(aIID, aInstancePtr);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Bacon & Rajan's |MarkRoots| routine.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1301,13 +1372,13 @@ private:
|
|||
PLDHashTable mPtrToNodeMap;
|
||||
PtrInfo *mCurrPi;
|
||||
nsCycleCollectionLanguageRuntime **mRuntimes; // weak, from nsCycleCollector
|
||||
#ifdef DEBUG_CC
|
||||
nsCString mNextEdgeName;
|
||||
#endif
|
||||
nsCOMPtr<nsICycleCollectorListener> mListener;
|
||||
|
||||
public:
|
||||
GCGraphBuilder(GCGraph &aGraph,
|
||||
nsCycleCollectionLanguageRuntime **aRuntimes);
|
||||
nsCycleCollectionLanguageRuntime **aRuntimes,
|
||||
nsICycleCollectorListener *aListener);
|
||||
~GCGraphBuilder();
|
||||
bool Initialized();
|
||||
|
||||
|
@ -1342,19 +1413,25 @@ private:
|
|||
};
|
||||
|
||||
GCGraphBuilder::GCGraphBuilder(GCGraph &aGraph,
|
||||
nsCycleCollectionLanguageRuntime **aRuntimes)
|
||||
nsCycleCollectionLanguageRuntime **aRuntimes,
|
||||
nsICycleCollectorListener *aListener)
|
||||
: mNodeBuilder(aGraph.mNodes),
|
||||
mEdgeBuilder(aGraph.mEdges),
|
||||
mRuntimes(aRuntimes)
|
||||
mRuntimes(aRuntimes),
|
||||
mListener(aListener)
|
||||
{
|
||||
if (!PL_DHashTableInit(&mPtrToNodeMap, &PtrNodeOps, nsnull,
|
||||
sizeof(PtrToNodeEntry), 32768))
|
||||
mPtrToNodeMap.ops = nsnull;
|
||||
#ifdef DEBUG_CC
|
||||
// Do we need to set these all the time?
|
||||
mFlags |= nsCycleCollectionTraversalCallback::WANT_DEBUG_INFO |
|
||||
nsCycleCollectionTraversalCallback::WANT_ALL_TRACES;
|
||||
// We want all edges and all info if DEBUG_CC is set or if we have a
|
||||
// listener. Do we want them all the time?
|
||||
#ifndef DEBUG_CC
|
||||
if (mListener)
|
||||
#endif
|
||||
{
|
||||
mFlags |= nsCycleCollectionTraversalCallback::WANT_DEBUG_INFO |
|
||||
nsCycleCollectionTraversalCallback::WANT_ALL_TRACES;
|
||||
}
|
||||
}
|
||||
|
||||
GCGraphBuilder::~GCGraphBuilder()
|
||||
|
@ -1461,6 +1538,10 @@ GCGraphBuilder::DescribeNode(CCNodeType type, nsrefcnt refCount,
|
|||
mCurrPi->mName = PL_strdup(objName);
|
||||
#endif
|
||||
|
||||
if (mListener) {
|
||||
mListener->NoteObject((PRUint64)mCurrPi->mPointer, objName);
|
||||
}
|
||||
|
||||
if (type == RefCounted) {
|
||||
if (refCount == 0 || refCount == PR_UINT32_MAX)
|
||||
Fault("zero or overflowing refcount", mCurrPi);
|
||||
|
@ -1478,10 +1559,11 @@ GCGraphBuilder::DescribeNode(CCNodeType type, nsrefcnt refCount,
|
|||
NS_IMETHODIMP_(void)
|
||||
GCGraphBuilder::NoteXPCOMChild(nsISupports *child)
|
||||
{
|
||||
#ifdef DEBUG_CC
|
||||
nsCString edgeName(mNextEdgeName);
|
||||
mNextEdgeName.Truncate();
|
||||
#endif
|
||||
nsCString edgeName;
|
||||
if (WantDebugInfo()) {
|
||||
edgeName.Assign(mNextEdgeName);
|
||||
mNextEdgeName.Truncate();
|
||||
}
|
||||
if (!child || !(child = canonicalize(child)))
|
||||
return;
|
||||
|
||||
|
@ -1500,6 +1582,10 @@ GCGraphBuilder::NoteXPCOMChild(nsISupports *child)
|
|||
#ifdef DEBUG_CC
|
||||
mCurrPi->mEdgeNames.AppendElement(edgeName);
|
||||
#endif
|
||||
if (mListener) {
|
||||
mListener->NoteEdge((PRUint64)mCurrPi->mPointer, (PRUint64)child,
|
||||
edgeName.get());
|
||||
}
|
||||
++childPi->mInternalRefs;
|
||||
}
|
||||
}
|
||||
|
@ -1508,10 +1594,11 @@ NS_IMETHODIMP_(void)
|
|||
GCGraphBuilder::NoteNativeChild(void *child,
|
||||
nsCycleCollectionParticipant *participant)
|
||||
{
|
||||
#ifdef DEBUG_CC
|
||||
nsCString edgeName(mNextEdgeName);
|
||||
mNextEdgeName.Truncate();
|
||||
#endif
|
||||
nsCString edgeName;
|
||||
if (WantDebugInfo()) {
|
||||
edgeName.Assign(mNextEdgeName);
|
||||
mNextEdgeName.Truncate();
|
||||
}
|
||||
if (!child)
|
||||
return;
|
||||
|
||||
|
@ -1524,16 +1611,21 @@ GCGraphBuilder::NoteNativeChild(void *child,
|
|||
#ifdef DEBUG_CC
|
||||
mCurrPi->mEdgeNames.AppendElement(edgeName);
|
||||
#endif
|
||||
if (mListener) {
|
||||
mListener->NoteEdge((PRUint64)mCurrPi->mPointer, (PRUint64)child,
|
||||
edgeName.get());
|
||||
}
|
||||
++childPi->mInternalRefs;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
GCGraphBuilder::NoteScriptChild(PRUint32 langID, void *child)
|
||||
{
|
||||
#ifdef DEBUG_CC
|
||||
nsCString edgeName(mNextEdgeName);
|
||||
mNextEdgeName.Truncate();
|
||||
#endif
|
||||
nsCString edgeName;
|
||||
if (WantDebugInfo()) {
|
||||
edgeName.Assign(mNextEdgeName);
|
||||
mNextEdgeName.Truncate();
|
||||
}
|
||||
if (!child)
|
||||
return;
|
||||
|
||||
|
@ -1559,15 +1651,19 @@ GCGraphBuilder::NoteScriptChild(PRUint32 langID, void *child)
|
|||
#ifdef DEBUG_CC
|
||||
mCurrPi->mEdgeNames.AppendElement(edgeName);
|
||||
#endif
|
||||
if (mListener) {
|
||||
mListener->NoteEdge((PRUint64)mCurrPi->mPointer, (PRUint64)child,
|
||||
edgeName.get());
|
||||
}
|
||||
++childPi->mInternalRefs;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
GCGraphBuilder::NoteNextEdgeName(const char* name)
|
||||
{
|
||||
#ifdef DEBUG_CC
|
||||
mNextEdgeName = name;
|
||||
#endif
|
||||
if (WantDebugInfo()) {
|
||||
mNextEdgeName = name;
|
||||
}
|
||||
}
|
||||
|
||||
static PRBool
|
||||
|
@ -2079,91 +2175,7 @@ nsCycleCollector::ForgetRuntime(PRUint32 langID)
|
|||
mRuntimes[langID] = nsnull;
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG_CC
|
||||
static void
|
||||
WriteGraph(FILE *stream, GCGraph &graph, const void *redPtr)
|
||||
{
|
||||
fprintf(stream,
|
||||
"digraph collection {\n"
|
||||
"rankdir=LR\n"
|
||||
"node [fontname=fixed, fontsize=10, style=filled, shape=box]\n"
|
||||
);
|
||||
|
||||
NodePool::Enumerator etor(graph.mNodes);
|
||||
while (!etor.IsDone()) {
|
||||
PtrInfo *pi = etor.GetNext();
|
||||
const void *p = pi->mPointer;
|
||||
fprintf(stream,
|
||||
"n%p [label=\"%s\\n%p\\n",
|
||||
p,
|
||||
pi->mName,
|
||||
p);
|
||||
if (pi->mRefCount != 0 && pi->mRefCount != PR_UINT32_MAX) {
|
||||
fprintf(stream,
|
||||
"%u/%u refs found",
|
||||
pi->mInternalRefs, pi->mRefCount);
|
||||
}
|
||||
fprintf(stream,
|
||||
"\", fillcolor=%s, fontcolor=%s]\n",
|
||||
(redPtr && redPtr == p ? "red" : (pi->mColor == black ? "black" : "white")),
|
||||
(pi->mColor == black ? "white" : "black"));
|
||||
for (EdgePool::Iterator child = pi->mFirstChild,
|
||||
child_end = pi->mLastChild;
|
||||
child != child_end; ++child) {
|
||||
fprintf(stream, "n%p -> n%p\n", p, (*child)->mPointer);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stream, "\n}\n");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsCycleCollector::MaybeDrawGraphs()
|
||||
{
|
||||
if (mParams.mDrawGraphs) {
|
||||
// We draw graphs only if there were any white nodes.
|
||||
PRBool anyWhites = PR_FALSE;
|
||||
NodePool::Enumerator fwetor(mGraph.mNodes);
|
||||
while (!fwetor.IsDone())
|
||||
{
|
||||
PtrInfo *pinfo = fwetor.GetNext();
|
||||
if (pinfo->mColor == white) {
|
||||
anyWhites = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (anyWhites) {
|
||||
// We can't just use _popen here because graphviz-for-windows
|
||||
// doesn't set up its stdin stream properly, sigh.
|
||||
FILE *stream;
|
||||
#ifdef WIN32
|
||||
stream = fopen("c:\\cycle-graph.dot", "w+");
|
||||
#else
|
||||
stream = popen("dotty -", "w");
|
||||
#endif
|
||||
WriteGraph(stream, mGraph, nsnull);
|
||||
#ifdef WIN32
|
||||
fclose(stream);
|
||||
// Even dotty doesn't work terribly well on windows, since
|
||||
// they execute lefty asynchronously. So we'll just run
|
||||
// lefty ourselves.
|
||||
_spawnlp(_P_WAIT,
|
||||
"lefty",
|
||||
"lefty",
|
||||
"-e",
|
||||
"\"load('dotty.lefty');"
|
||||
"dotty.simple('c:\\cycle-graph.dot');\"",
|
||||
NULL);
|
||||
unlink("c:\\cycle-graph.dot");
|
||||
#else
|
||||
pclose(stream);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Suppressor :
|
||||
public nsCycleCollectionTraversalCallback
|
||||
|
@ -2416,7 +2428,8 @@ nsCycleCollector::Freed(void *n)
|
|||
#endif
|
||||
|
||||
PRUint32
|
||||
nsCycleCollector::Collect(PRUint32 aTryCollections)
|
||||
nsCycleCollector::Collect(PRUint32 aTryCollections,
|
||||
nsICycleCollectorListener *aListener)
|
||||
{
|
||||
#if defined(DEBUG_CC) && !defined(__MINGW32__)
|
||||
if (!mParams.mDoNothing && mParams.mHookMalloc)
|
||||
|
@ -2434,6 +2447,12 @@ nsCycleCollector::Collect(PRUint32 aTryCollections)
|
|||
PRTime start = PR_Now();
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_CC
|
||||
if (!aListener && mParams.mDrawGraphs) {
|
||||
aListener = new nsCycleCollectorLogger();
|
||||
}
|
||||
#endif
|
||||
|
||||
mCollectionInProgress = PR_TRUE;
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs =
|
||||
|
@ -2468,7 +2487,7 @@ nsCycleCollector::Collect(PRUint32 aTryCollections)
|
|||
#endif
|
||||
}
|
||||
|
||||
PRBool collected = BeginCollection() && FinishCollection();
|
||||
PRBool collected = BeginCollection(aListener) && FinishCollection();
|
||||
|
||||
#ifdef DEBUG_CC
|
||||
// We wait until after FinishCollection to check the white nodes because
|
||||
|
@ -2521,12 +2540,16 @@ nsCycleCollector::Collect(PRUint32 aTryCollections)
|
|||
}
|
||||
|
||||
PRBool
|
||||
nsCycleCollector::BeginCollection()
|
||||
nsCycleCollector::BeginCollection(nsICycleCollectorListener *aListener)
|
||||
{
|
||||
if (mParams.mDoNothing)
|
||||
return PR_FALSE;
|
||||
|
||||
GCGraphBuilder builder(mGraph, mRuntimes);
|
||||
if (aListener && NS_FAILED(aListener->Begin())) {
|
||||
aListener = nsnull;
|
||||
}
|
||||
|
||||
GCGraphBuilder builder(mGraph, mRuntimes, aListener);
|
||||
if (!builder.Initialized())
|
||||
return PR_FALSE;
|
||||
|
||||
|
@ -2604,12 +2627,29 @@ nsCycleCollector::BeginCollection()
|
|||
(PR_Now() - now) / PR_USEC_PER_MSEC);
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_CC
|
||||
MaybeDrawGraphs();
|
||||
#endif
|
||||
|
||||
mScanInProgress = PR_FALSE;
|
||||
|
||||
if (aListener) {
|
||||
aListener->BeginDescriptions();
|
||||
|
||||
NodePool::Enumerator etor(mGraph.mNodes);
|
||||
while (!etor.IsDone()) {
|
||||
PtrInfo *pi = etor.GetNext();
|
||||
if (pi->mColor == black) {
|
||||
PRUint64 p = (PRUint64)pi->mPointer;
|
||||
if (pi->mRefCount > 0 && pi->mRefCount < PR_UINT32_MAX) {
|
||||
aListener->DescribeRefcountedObject(p, pi->mInternalRefs,
|
||||
pi->mRefCount);
|
||||
}
|
||||
else {
|
||||
aListener->DescribeGCedObject(p, pi->mRefCount != 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aListener->End();
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CC
|
||||
if (mFollowupCollection && purpleStart != purpleEnd) {
|
||||
PRUint32 i = 0;
|
||||
|
@ -2692,10 +2732,10 @@ nsCycleCollector::Shutdown()
|
|||
mRuntimes[i]->CommenceShutdown();
|
||||
}
|
||||
|
||||
Collect(SHUTDOWN_COLLECTIONS(mParams));
|
||||
Collect(SHUTDOWN_COLLECTIONS(mParams), nsnull);
|
||||
|
||||
#ifdef DEBUG_CC
|
||||
GCGraphBuilder builder(mGraph, mRuntimes);
|
||||
GCGraphBuilder builder(mGraph, mRuntimes, nsnull);
|
||||
mScanInProgress = PR_TRUE;
|
||||
SelectPurple(builder);
|
||||
mScanInProgress = PR_FALSE;
|
||||
|
@ -2770,7 +2810,7 @@ nsCycleCollector::ExplainLiveExpectedGarbage()
|
|||
mScanInProgress = PR_TRUE;
|
||||
|
||||
{
|
||||
GCGraphBuilder builder(mGraph, mRuntimes);
|
||||
GCGraphBuilder builder(mGraph, mRuntimes, nsnull);
|
||||
|
||||
// Instead of adding roots from the purple buffer, we add them
|
||||
// from the list of nodes we were expected to collect.
|
||||
|
@ -3163,9 +3203,9 @@ NS_CycleCollectorForget2(nsPurpleBufferEntry *e)
|
|||
|
||||
|
||||
PRUint32
|
||||
nsCycleCollector_collect()
|
||||
nsCycleCollector_collect(nsICycleCollectorListener *aListener)
|
||||
{
|
||||
return sCollector ? sCollector->Collect() : 0;
|
||||
return sCollector ? sCollector->Collect(1, aListener) : 0;
|
||||
}
|
||||
|
||||
PRUint32
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
//#define DEBUG_CC
|
||||
|
||||
class nsISupports;
|
||||
class nsICycleCollectorListener;
|
||||
class nsCycleCollectionParticipant;
|
||||
class nsCycleCollectionTraversalCallback;
|
||||
|
||||
|
@ -63,7 +64,7 @@ struct nsCycleCollectionLanguageRuntime
|
|||
|
||||
nsresult nsCycleCollector_startup();
|
||||
// Returns the number of collected nodes.
|
||||
NS_COM PRUint32 nsCycleCollector_collect();
|
||||
NS_COM PRUint32 nsCycleCollector_collect(nsICycleCollectorListener *aListener);
|
||||
NS_COM PRUint32 nsCycleCollector_suspectedCount();
|
||||
void nsCycleCollector_shutdown();
|
||||
|
||||
|
@ -91,4 +92,13 @@ NS_COM void nsCycleCollector_registerRuntime(PRUint32 langID, nsCycleCollectionL
|
|||
NS_COM nsCycleCollectionLanguageRuntime * nsCycleCollector_getRuntime(PRUint32 langID);
|
||||
NS_COM void nsCycleCollector_forgetRuntime(PRUint32 langID);
|
||||
|
||||
#define NS_CYCLE_COLLECTOR_LOGGER_CID \
|
||||
{ 0x58be81b4, 0x39d2, 0x437c, \
|
||||
{ 0x94, 0xea, 0xae, 0xde, 0x2c, 0x62, 0x08, 0xd3 } }
|
||||
|
||||
extern nsresult
|
||||
nsCycleCollectorLoggerConstructor(nsISupports* outer,
|
||||
const nsIID& aIID,
|
||||
void* *aInstancePtr);
|
||||
|
||||
#endif // nsCycleCollector_h__
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is XPCOM cycle collector.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
/**
|
||||
* Interface to pass to the cycle collector to get information about the CC
|
||||
* graph while it's being built. The order of calls will be call to begin();
|
||||
* then for every node in the graph a call to noteObject() and calls to
|
||||
* noteEdge() for every edge starting at that node; then a call to
|
||||
* beginDescriptions(); then for every black node in the CC graph a call to
|
||||
* either describeRefcountedObject() or to describeGCedObject(); and then a
|
||||
* call to end(). If begin() returns an error none of the other functions will
|
||||
* be called.
|
||||
*/
|
||||
[scriptable, uuid(194b749a-4ceb-4dd1-928d-d30b5f14c23e)]
|
||||
interface nsICycleCollectorListener : nsISupports
|
||||
{
|
||||
void begin();
|
||||
void noteObject(in unsigned long long aAddress,
|
||||
in string aObjectDescription);
|
||||
void noteEdge(in unsigned long long aFromAddress,
|
||||
in unsigned long long aToAddress,
|
||||
in string aEdgeName);
|
||||
void beginDescriptions();
|
||||
void describeRefcountedObject(in unsigned long long aAddress,
|
||||
in unsigned long aKnownEdges,
|
||||
in unsigned long aTotalEdges);
|
||||
void describeGCedObject(in unsigned long long aAddress, in boolean aMarked);
|
||||
void end();
|
||||
};
|
|
@ -87,3 +87,4 @@
|
|||
COMPONENT(SYSTEMINFO, nsSystemInfoConstructor)
|
||||
COMPONENT(MEMORY_REPORTER_MANAGER, nsMemoryReporterManagerConstructor)
|
||||
COMPONENT(IOUTIL, nsIOUtilConstructor)
|
||||
COMPONENT(CYCLE_COLLECTOR_LOGGER, nsCycleCollectorLoggerConstructor)
|
||||
|
|
|
@ -276,7 +276,7 @@ void XXXNeverCalled()
|
|||
}
|
||||
|
||||
nsXPCOMCycleCollectionParticipant();
|
||||
nsCycleCollector_collect();
|
||||
nsCycleCollector_collect(nsnull);
|
||||
#ifdef XP_WIN
|
||||
sXPCOMHasLoadedNewDLLs = !sXPCOMHasLoadedNewDLLs;
|
||||
NS_SetHasLoadedNewDLLs();
|
||||
|
|
|
@ -102,6 +102,11 @@
|
|||
*/
|
||||
#define NS_MEMORY_REPORTER_MANAGER_CONTRACTID "@mozilla.org/memory-reporter-manager;1"
|
||||
|
||||
/**
|
||||
* Cycle collector logger contract id
|
||||
*/
|
||||
#define NS_CYCLE_COLLECTOR_LOGGER_CONTRACTID "@mozilla.org/cycle-collector-logger;1"
|
||||
|
||||
/**
|
||||
* The following are the CIDs and Contract IDs of the nsISupports wrappers for
|
||||
* primative types.
|
||||
|
|
Загрузка…
Ссылка в новой задаче