Make some of the DEBUG_CC code accessible to code in non-debug builds so it can be used by memory tools for Web developers. (Bug 500233) r+sr=peterv

This commit is contained in:
L. David Baron 2009-07-08 18:10:29 -07:00
parent caf9fffbee
commit dfd2b373c7
15 changed files with 217 additions and 209 deletions

View File

@ -36,6 +36,7 @@
* ***** END LICENSE BLOCK ***** */
#include "nsIObserver.h"
#include "nsCycleCollectionParticipant.h"
class nsCCUncollectableMarker : public nsIObserver
{
@ -50,8 +51,11 @@ class nsCCUncollectableMarker : public nsIObserver
/**
* Checks if we're collecting during a given generation
*/
static PRBool InGeneration(PRUint32 aGeneration) {
return aGeneration && aGeneration == sGeneration;
static PRBool InGeneration(nsCycleCollectionTraversalCallback &cb,
PRUint32 aGeneration) {
return !cb.WantAllTraces() &&
aGeneration &&
aGeneration == sGeneration;
}
static PRUint32 sGeneration;

View File

@ -1723,7 +1723,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDocument)
// if we're uncollectable.
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
if (nsCCUncollectableMarker::InGeneration(tmp->GetMarkedCCGeneration())) {
if (nsCCUncollectableMarker::InGeneration(cb, tmp->GetMarkedCCGeneration())) {
return NS_SUCCESS_INTERRUPTED_TRAVERSE;
}

View File

@ -91,7 +91,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsGenericDOMDataNode)
nsIDocument* currentDoc = tmp->GetCurrentDoc();
if (currentDoc && nsCCUncollectableMarker::InGeneration(
currentDoc->GetMarkedCCGeneration())) {
cb, currentDoc->GetMarkedCCGeneration())) {
return NS_SUCCESS_INTERRUPTED_TRAVERSE;
}

View File

@ -4009,7 +4009,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsGenericElement)
nsIDocument* currentDoc = tmp->GetCurrentDoc();
if (currentDoc && nsCCUncollectableMarker::InGeneration(
currentDoc->GetMarkedCCGeneration())) {
cb, currentDoc->GetMarkedCCGeneration())) {
return NS_SUCCESS_INTERRUPTED_TRAVERSE;
}

View File

@ -238,7 +238,7 @@ nsHTMLDocument::nsHTMLDocument()
NS_IMPL_CYCLE_COLLECTION_CLASS(nsHTMLDocument)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsHTMLDocument, nsDocument)
NS_ASSERTION(!nsCCUncollectableMarker::InGeneration(tmp->GetMarkedCCGeneration()),
NS_ASSERTION(!nsCCUncollectableMarker::InGeneration(cb, tmp->GetMarkedCCGeneration()),
"Shouldn't traverse nsHTMLDocument!");
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mImageMaps)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mImages)

View File

@ -335,7 +335,7 @@ TraverseObservers(nsIURI* aKey, nsIObserver* aData, void* aContext)
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXULDocument, nsXMLDocument)
NS_ASSERTION(!nsCCUncollectableMarker::InGeneration(tmp->GetMarkedCCGeneration()),
NS_ASSERTION(!nsCCUncollectableMarker::InGeneration(cb, tmp->GetMarkedCCGeneration()),
"Shouldn't traverse nsXULDocument!");
// XXX tmp->mForwardReferences?
// XXX tmp->mContextStack?

View File

@ -1017,7 +1017,7 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsGlobalWindow,
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsGlobalWindow)
if (tmp->mDoc && nsCCUncollectableMarker::InGeneration(
tmp->mDoc->GetMarkedCCGeneration())) {
cb, tmp->mDoc->GetMarkedCCGeneration())) {
return NS_SUCCESS_INTERRUPTED_TRAVERSE;
}

View File

@ -651,21 +651,23 @@ NoteJSChild(JSTracer *trc, void *thing, uint32 kind)
if(ADD_TO_CC(kind))
{
TraversalTracer *tracer = static_cast<TraversalTracer*>(trc);
#if defined(DEBUG) && defined(DEBUG_CC)
// based on DumpNotify in jsapi.c
if (tracer->debugPrinter) {
char buffer[200];
tracer->debugPrinter(trc, buffer, sizeof(buffer));
tracer->cb.NoteNextEdgeName(buffer);
} else if (tracer->debugPrintIndex != (size_t)-1) {
char buffer[200];
JS_snprintf(buffer, sizeof(buffer), "%s[%lu]",
static_cast<const char *>(tracer->debugPrintArg),
tracer->debugPrintIndex);
tracer->cb.NoteNextEdgeName(buffer);
} else {
tracer->cb.NoteNextEdgeName(
static_cast<const char*>(tracer->debugPrintArg));
#if defined(DEBUG)
if (NS_UNLIKELY(tracer->cb.WantDebugInfo())) {
// based on DumpNotify in jsapi.c
if (tracer->debugPrinter) {
char buffer[200];
tracer->debugPrinter(trc, buffer, sizeof(buffer));
tracer->cb.NoteNextEdgeName(buffer);
} else if (tracer->debugPrintIndex != (size_t)-1) {
char buffer[200];
JS_snprintf(buffer, sizeof(buffer), "%s[%lu]",
static_cast<const char *>(tracer->debugPrintArg),
tracer->debugPrintIndex);
tracer->cb.NoteNextEdgeName(buffer);
} else {
tracer->cb.NoteNextEdgeName(
static_cast<const char*>(tracer->debugPrintArg));
}
}
#endif
tracer->cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, thing);
@ -732,7 +734,6 @@ nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb)
CCNodeType type;
#ifdef DEBUG_CC
{
// Note that the conditions under which we specify GCMarked vs.
// GCUnmarked are different between ExplainLiveExpectedGarbage and
// the normal case. In the normal case, we're saying that anything
@ -752,149 +753,150 @@ nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb)
GCUnmarked;
}
else
#endif
{
// Normal codepath (matches non-DEBUG_CC codepath).
type = !markJSObject && JS_IsAboutToBeFinalized(cx, p) ? GCUnmarked :
GCMarked;
}
char name[72];
if(traceKind == JSTRACE_OBJECT)
{
JSObject *obj = static_cast<JSObject*>(p);
JSClass *clazz = OBJ_GET_CLASS(cx, obj);
if(XPCNativeWrapper::IsNativeWrapperClass(clazz))
if (cb.WantDebugInfo()) {
char name[72];
if(traceKind == JSTRACE_OBJECT)
{
XPCWrappedNative* wn;
if(XPCNativeWrapper::GetWrappedNative(cx, obj, &wn) && wn)
JSObject *obj = static_cast<JSObject*>(p);
JSClass *clazz = OBJ_GET_CLASS(cx, obj);
if(XPCNativeWrapper::IsNativeWrapperClass(clazz))
{
XPCNativeScriptableInfo* si = wn->GetScriptableInfo();
if(si)
XPCWrappedNative* wn;
if(XPCNativeWrapper::GetWrappedNative(cx, obj, &wn) && wn)
{
JS_snprintf(name, sizeof(name), "XPCNativeWrapper (%s)",
si->GetJSClass()->name);
}
else
{
nsIClassInfo* ci = wn->GetClassInfo();
char* className = nsnull;
if(ci)
ci->GetClassDescription(&className);
if(className)
XPCNativeScriptableInfo* si = wn->GetScriptableInfo();
if(si)
{
JS_snprintf(name, sizeof(name), "XPCNativeWrapper (%s)",
className);
PR_Free(className);
si->GetJSClass()->name);
}
else
{
XPCNativeSet* set = wn->GetSet();
XPCNativeInterface** array = set->GetInterfaceArray();
PRUint16 count = set->GetInterfaceCount();
if(count > 0)
nsIClassInfo* ci = wn->GetClassInfo();
char* className = nsnull;
if(ci)
ci->GetClassDescription(&className);
if(className)
{
JS_snprintf(name, sizeof(name),
"XPCNativeWrapper (%s)",
array[0]->GetNameString());
"XPCNativeWrapper (%s)", className);
PR_Free(className);
}
else
JS_snprintf(name, sizeof(name), "XPCNativeWrapper");
{
XPCNativeSet* set = wn->GetSet();
XPCNativeInterface** array =
set->GetInterfaceArray();
PRUint16 count = set->GetInterfaceCount();
if(count > 0)
JS_snprintf(name, sizeof(name),
"XPCNativeWrapper (%s)",
array[0]->GetNameString());
else
JS_snprintf(name, sizeof(name),
"XPCNativeWrapper");
}
}
}
else
{
JS_snprintf(name, sizeof(name), "XPCNativeWrapper");
}
}
else
{
JS_snprintf(name, sizeof(name), "XPCNativeWrapper");
XPCNativeScriptableInfo* si = nsnull;
if(IS_PROTO_CLASS(clazz))
{
XPCWrappedNativeProto* p =
(XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
si = p->GetScriptableInfo();
}
if(si)
{
JS_snprintf(name, sizeof(name), "JS Object (%s - %s)",
clazz->name, si->GetJSClass()->name);
}
else if(clazz == &js_ScriptClass)
{
JSScript* script = (JSScript*) xpc_GetJSPrivate(obj);
if(script->filename)
{
JS_snprintf(name, sizeof(name),
"JS Object (Script - %s)",
script->filename);
}
else
{
JS_snprintf(name, sizeof(name), "JS Object (Script)");
}
}
else if(clazz == &js_FunctionClass)
{
JSFunction* fun = (JSFunction*) xpc_GetJSPrivate(obj);
JSString* str = JS_GetFunctionId(fun);
if(str)
{
NS_ConvertUTF16toUTF8
fname(JS_GetStringChars(str));
JS_snprintf(name, sizeof(name),
"JS Object (Function - %s)", fname.get());
}
else
{
JS_snprintf(name, sizeof(name), "JS Object (Function)");
}
}
else
{
JS_snprintf(name, sizeof(name), "JS Object (%s)",
clazz->name);
}
}
}
else
{
XPCNativeScriptableInfo* si = nsnull;
if(IS_PROTO_CLASS(clazz))
{
XPCWrappedNativeProto* p =
(XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
si = p->GetScriptableInfo();
}
if(si)
{
JS_snprintf(name, sizeof(name), "JS Object (%s - %s)",
clazz->name, si->GetJSClass()->name);
}
else if(clazz == &js_ScriptClass)
{
JSScript* script = (JSScript*) xpc_GetJSPrivate(obj);
if(script->filename)
{
JS_snprintf(name, sizeof(name), "JS Object (Script - %s)",
script->filename);
}
else
{
JS_snprintf(name, sizeof(name), "JS Object (Script)");
}
}
else if(clazz == &js_FunctionClass)
{
JSFunction* fun = (JSFunction*) xpc_GetJSPrivate(obj);
JSString* str = JS_GetFunctionId(fun);
if(str)
{
NS_ConvertUTF16toUTF8
fname(JS_GetStringChars(str));
JS_snprintf(name, sizeof(name), "JS Object (Function - %s)",
fname.get());
}
else
{
JS_snprintf(name, sizeof(name), "JS Object (Function)");
}
}
else
{
JS_snprintf(name, sizeof(name), "JS Object (%s)", clazz->name);
}
static const char trace_types[JSTRACE_LIMIT][7] = {
"Object",
"Double",
"String",
"Xml"
};
JS_snprintf(name, sizeof(name), "JS %s", trace_types[traceKind]);
}
}
else
{
static const char trace_types[JSTRACE_LIMIT][7] = {
"Object",
"Double",
"String",
"Xml"
};
JS_snprintf(name, sizeof(name), "JS %s", trace_types[traceKind]);
}
if(traceKind == JSTRACE_OBJECT) {
JSObject *global = static_cast<JSObject*>(p), *parent;
while((parent = JS_GetParent(cx, global)))
global = parent;
char fullname[100];
JS_snprintf(fullname, sizeof(fullname), "%s (global=%p)", name, global);
cb.DescribeNode(type, 0, sizeof(JSObject), fullname);
if(traceKind == JSTRACE_OBJECT) {
JSObject *global = static_cast<JSObject*>(p), *parent;
while((parent = JS_GetParent(cx, global)))
global = parent;
char fullname[100];
JS_snprintf(fullname, sizeof(fullname),
"%s (global=%p)", name, global);
cb.DescribeNode(type, 0, sizeof(JSObject), fullname);
} else {
cb.DescribeNode(type, 0, sizeof(JSObject), name);
}
} else {
cb.DescribeNode(type, 0, sizeof(JSObject), name);
cb.DescribeNode(type, 0, sizeof(JSObject), "JS Object");
}
}
#else
type = !markJSObject && JS_IsAboutToBeFinalized(cx, p) ? GCUnmarked :
GCMarked;
cb.DescribeNode(type, 0);
#endif
if(!ADD_TO_CC(traceKind))
return NS_OK;
#ifndef DEBUG_CC
// There's no need to trace objects that have already been marked by the JS
// GC. Any JS objects hanging from them will already be marked. Only do this
// if DEBUG_CC is not defined, else we do want to know about all JS objects
// to get better graphs and explanations.
if(type == GCMarked)
if(!cb.WantAllTraces() && type == GCMarked)
return NS_OK;
#endif
TraversalTracer trc(cb);
@ -968,13 +970,9 @@ public:
// collected.
PRInt32 refCount = nsXPConnect::GetXPConnect()->GetRequestDepth(cx) + 1;
#ifdef DEBUG_CC
cb.DescribeNode(RefCounted, refCount, sizeof(JSContext),
"JSContext");
cb.NoteNextEdgeName("[global object]");
#else
cb.DescribeNode(RefCounted, refCount);
#endif
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "[global object]");
cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT,
cx->globalObject);

View File

@ -414,13 +414,13 @@ void XPCJSRuntime::AddXPConnectRoots(JSContext* cx,
JSContext *iter = nsnull, *acx;
while((acx = JS_ContextIterator(GetJSRuntime(), &iter)))
{
#ifndef DEBUG_CC
// Only skip JSContexts with outstanding requests if DEBUG_CC is not
// defined, else we do want to know about all JSContexts to get better
// graphs and explanations.
if(nsXPConnect::GetXPConnect()->GetRequestDepth(acx) != 0)
// Only skip JSContexts with outstanding requests if the
// callback does not want all traces (a debug feature).
// Otherwise, we do want to know about all JSContexts to get
// better graphs and explanations.
if(!cb.WantAllTraces() &&
nsXPConnect::GetXPConnect()->GetRequestDepth(acx) != 0)
continue;
#endif
cb.NoteRoot(nsIProgrammingLanguage::CPLUSPLUS, acx,
nsXPConnect::JSContextParticipant());
}

View File

@ -57,17 +57,18 @@ NS_CYCLE_COLLECTION_CLASSNAME(nsXPCWrappedJS)::Traverse
nsXPCWrappedJS *tmp = Downcast(s);
nsrefcnt refcnt = tmp->mRefCnt.get();
#ifdef DEBUG_CC
char name[72];
if (tmp->GetClass())
JS_snprintf(name, sizeof(name), "nsXPCWrappedJS (%s)",
tmp->GetClass()->GetInterfaceName());
else
JS_snprintf(name, sizeof(name), "nsXPCWrappedJS");
cb.DescribeNode(RefCounted, refcnt, sizeof(nsXPCWrappedJS), name);
#else
cb.DescribeNode(RefCounted, refcnt);
#endif
if (cb.WantDebugInfo()) {
char name[72];
if (tmp->GetClass())
JS_snprintf(name, sizeof(name), "nsXPCWrappedJS (%s)",
tmp->GetClass()->GetInterfaceName());
else
JS_snprintf(name, sizeof(name), "nsXPCWrappedJS");
cb.DescribeNode(RefCounted, refcnt, sizeof(nsXPCWrappedJS), name);
} else {
cb.DescribeNode(RefCounted, refcnt, sizeof(nsXPCWrappedJS),
"nsXPCWrappedJS");
}
// nsXPCWrappedJS keeps its own refcount artificially at or above 1, see the
// comment above nsXPCWrappedJS::AddRef.

View File

@ -69,20 +69,21 @@ NS_CYCLE_COLLECTION_CLASSNAME(XPCWrappedNative)::Traverse(void *p,
if(!tmp->IsValid())
return NS_OK;
#ifdef DEBUG_CC
char name[72];
XPCNativeScriptableInfo* si = tmp->GetScriptableInfo();
if(si)
JS_snprintf(name, sizeof(name), "XPCWrappedNative (%s)",
si->GetJSClass()->name);
else
JS_snprintf(name, sizeof(name), "XPCWrappedNative");
if (NS_UNLIKELY(cb.WantDebugInfo())) {
char name[72];
XPCNativeScriptableInfo* si = tmp->GetScriptableInfo();
if(si)
JS_snprintf(name, sizeof(name), "XPCWrappedNative (%s)",
si->GetJSClass()->name);
else
JS_snprintf(name, sizeof(name), "XPCWrappedNative");
cb.DescribeNode(RefCounted, tmp->mRefCnt.get(), sizeof(XPCWrappedNative),
name);
#else
cb.DescribeNode(RefCounted, tmp->mRefCnt.get());
#endif
cb.DescribeNode(RefCounted, tmp->mRefCnt.get(),
sizeof(XPCWrappedNative), name);
} else {
cb.DescribeNode(RefCounted, tmp->mRefCnt.get(),
sizeof(XPCWrappedNative), "XPCWrappedNative");
}
if(tmp->mRefCnt.get() > 1) {

View File

@ -412,11 +412,11 @@ WrappedNativeSuspecter(JSDHashTable *table, JSDHashEntryHdr *hdr,
NS_ASSERTION(NS_IsMainThread(),
"Suspecting wrapped natives from non-main thread");
#ifndef DEBUG_CC
// Only record objects that might be part of a cycle as roots.
if(!JS_IsAboutToBeFinalized(closure->cx, wrapper->GetFlatJSObject()))
// Only record objects that might be part of a cycle as roots, unless
// the callback wants all traces (a debug feature).
if(!(closure->cb.WantAllTraces()) &&
!JS_IsAboutToBeFinalized(closure->cx, wrapper->GetFlatJSObject()))
return JS_DHASH_NEXT;
#endif
closure->cb.NoteRoot(nsIProgrammingLanguage::JAVASCRIPT,
wrapper->GetFlatJSObject(),

View File

@ -239,13 +239,11 @@ nsLayoutStatics::Initialize()
return rv;
}
#ifndef DEBUG_CC
rv = nsCCUncollectableMarker::Init();
if (NS_FAILED(rv)) {
NS_ERROR("Could not initialize nsCCUncollectableMarker");
return rv;
}
#endif
nsCSSRuleProcessor::Startup();

View File

@ -152,6 +152,14 @@
#include <process.h>
#endif
#ifdef DEBUG_CC
#define IF_DEBUG_CC_PARAM(_p) , _p
#define IF_DEBUG_CC_ONLY_PARAM(_p) _p
#else
#define IF_DEBUG_CC_PARAM(_p)
#define IF_DEBUG_CC_ONLY_PARAM(_p)
#endif
#define DEFAULT_SHUTDOWN_COLLECTIONS 5
#ifdef DEBUG_CC
#define SHUTDOWN_COLLECTIONS(params) params.mShutdownCollections
@ -1289,21 +1297,15 @@ public:
NS_IMETHOD_(void) NoteXPCOMRoot(nsISupports *root);
private:
#ifdef DEBUG_CC
NS_IMETHOD_(void) DescribeNode(CCNodeType type, nsrefcnt refCount,
size_t objSz, const char *objName);
#else
NS_IMETHOD_(void) DescribeNode(CCNodeType type, nsrefcnt refCount);
#endif
NS_IMETHOD_(void) NoteRoot(PRUint32 langID, void *child,
nsCycleCollectionParticipant* participant);
NS_IMETHOD_(void) NoteXPCOMChild(nsISupports *child);
NS_IMETHOD_(void) NoteNativeChild(void *child,
nsCycleCollectionParticipant *participant);
NS_IMETHOD_(void) NoteScriptChild(PRUint32 langID, void *child);
#ifdef DEBUG_CC
NS_IMETHOD_(void) NoteNextEdgeName(const char* name);
#endif
};
GCGraphBuilder::GCGraphBuilder(GCGraph &aGraph,
@ -1315,6 +1317,11 @@ GCGraphBuilder::GCGraphBuilder(GCGraph &aGraph,
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;
#endif
}
GCGraphBuilder::~GCGraphBuilder()
@ -1404,12 +1411,8 @@ GCGraphBuilder::NoteRoot(PRUint32 langID, void *root,
}
NS_IMETHODIMP_(void)
#ifdef DEBUG_CC
GCGraphBuilder::DescribeNode(CCNodeType type, nsrefcnt refCount,
size_t objSz, const char *objName)
#else
GCGraphBuilder::DescribeNode(CCNodeType type, nsrefcnt refCount)
#endif
{
#ifdef DEBUG_CC
mCurrPi->mBytes = objSz;
@ -1517,13 +1520,13 @@ GCGraphBuilder::NoteScriptChild(PRUint32 langID, void *child)
++childPi->mInternalRefs;
}
#ifdef DEBUG_CC
NS_IMETHODIMP_(void)
GCGraphBuilder::NoteNextEdgeName(const char* name)
{
#ifdef DEBUG_CC
mNextEdgeName = name;
}
#endif
}
static PRBool
AddPurpleRoot(GCGraphBuilder &builder, nsISupports *root)

View File

@ -44,14 +44,6 @@
// *and* in nsCycleCollector.h
//#define DEBUG_CC
#ifdef DEBUG_CC
#define IF_DEBUG_CC_PARAM(_p) , _p
#define IF_DEBUG_CC_ONLY_PARAM(_p) _p
#else
#define IF_DEBUG_CC_PARAM(_p)
#define IF_DEBUG_CC_ONLY_PARAM(_p)
#endif
#define NS_CYCLECOLLECTIONPARTICIPANT_IID \
{ \
0x9674489b, \
@ -97,15 +89,12 @@ public:
// If type is RefCounted you must call DescribeNode() with an accurate
// refcount, otherwise cycle collection will fail, and probably crash.
// If type is not refcounted then the refcount will be ignored.
#ifdef DEBUG_CC
// If the callback cares about objsz or objname, it should
// put WANT_DEBUG_INFO in mFlags.
NS_IMETHOD_(void) DescribeNode(CCNodeType type,
nsrefcnt refcount,
size_t objsz,
const char *objname) = 0;
#else
NS_IMETHOD_(void) DescribeNode(CCNodeType type,
nsrefcnt refcount) = 0;
#endif
NS_IMETHOD_(void) NoteXPCOMRoot(nsISupports *root) = 0;
NS_IMETHOD_(void) NoteRoot(PRUint32 langID, void *root,
nsCycleCollectionParticipant* helper) = 0;
@ -113,11 +102,31 @@ public:
NS_IMETHOD_(void) NoteXPCOMChild(nsISupports *child) = 0;
NS_IMETHOD_(void) NoteNativeChild(void *child,
nsCycleCollectionParticipant *helper) = 0;
#ifdef DEBUG_CC
// Give a name to the edge associated with the next call to
// NoteScriptChild, NoteXPCOMChild, or NoteNativeChild.
// Callbacks who care about this should set WANT_DEBUG_INFO in the
// flags.
NS_IMETHOD_(void) NoteNextEdgeName(const char* name) = 0;
#endif
enum {
// Values for flags:
// Caller should pass useful objsz and objname to DescribeNode
// and should call NoteNextEdgeName.
WANT_DEBUG_INFO = (1<<0),
// Caller should not skip objects that we know will be
// uncollectable.
WANT_ALL_TRACES = (1<<1)
};
PRUint32 Flags() const { return mFlags; }
PRBool WantDebugInfo() const { return (mFlags & WANT_DEBUG_INFO) != 0; }
PRBool WantAllTraces() const { return (mFlags & WANT_ALL_TRACES) != 0; }
protected:
nsCycleCollectionTraversalCallback() : mFlags(0) {}
PRUint32 mFlags;
};
class NS_NO_VTABLE nsCycleCollectionParticipant
@ -321,13 +330,8 @@ public:
// Helpers for implementing nsCycleCollectionParticipant::Traverse
///////////////////////////////////////////////////////////////////////////////
#ifdef DEBUG_CC
#define NS_IMPL_CYCLE_COLLECTION_DESCRIBE(_class, _refcnt) \
cb.DescribeNode(RefCounted, _refcnt, sizeof(_class), #_class);
#else
#define NS_IMPL_CYCLE_COLLECTION_DESCRIBE(_class, _refcnt) \
cb.DescribeNode(RefCounted, _refcnt);
#endif
#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_REFCNT(_class, _refcnt) \
NS_IMETHODIMP \
@ -374,13 +378,12 @@ public:
_class *tmp = static_cast<_class*>(p); \
NS_IMPL_CYCLE_COLLECTION_DESCRIBE(_class, tmp->mRefCnt.get())
#ifdef DEBUG_CC
#define NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(_cb, _name) \
PR_BEGIN_MACRO (_cb).NoteNextEdgeName(_name); PR_END_MACRO
#else
#define NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(_cb, _name) \
PR_BEGIN_MACRO PR_END_MACRO
#endif
#define NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(_cb, _name) \
PR_BEGIN_MACRO \
if (NS_UNLIKELY((_cb).WantDebugInfo())) { \
(_cb).NoteNextEdgeName(_name); \
} \
PR_END_MACRO
#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(_field) \
PR_BEGIN_MACRO \