diff --git a/xpcom/base/nsTraceRefcnt.cpp b/xpcom/base/nsTraceRefcnt.cpp index e00d634ddaf5..ffa6f071f8bd 100644 --- a/xpcom/base/nsTraceRefcnt.cpp +++ b/xpcom/base/nsTraceRefcnt.cpp @@ -17,8 +17,10 @@ * Netscape Communications Corporation. All Rights Reserved. */ #include "nsISupports.h" +#include "nsVoidArray.h" #include "prprf.h" #include "prlog.h" +#include "plstr.h" #if defined(_WIN32) #include @@ -542,3 +544,99 @@ nsTraceRefcnt::DemangleSymbol(const char * aSymbol, } #endif // __linux__ +//---------------------------------------------------------------------- + +#ifdef DEBUG + +struct CtorEntry { + const char* type; + mozCtorDtorCounter* counter; +}; + +nsVoidArray* nsTraceRefcnt::mCtors; + +void +nsTraceRefcnt::RegisterCtor(const char* aType, + mozCtorDtorCounter* aCounterAddr) +{ + if (!mCtors) { + mCtors = new nsVoidArray(); + if (!mCtors) { + return; + } + } + CtorEntry* e = new CtorEntry(); + if (!e) { + return; + } + e->type = aType; + e->counter = aCounterAddr; + mCtors->AppendElement(e); +} + +void +nsTraceRefcnt::UnregisterCtor(const char* aType) +{ + if (mCtors) { + PRInt32 i, n = mCtors->Count(); + for (i = 0; i < n; i++) { + CtorEntry* e = (CtorEntry*) mCtors->ElementAt(i); + if (0 == PL_strcmp(e->type, aType)) { + delete e; + mCtors->RemoveElementAt(i); + break; + } + } + } +} + +void +nsTraceRefcnt::DumpLeaks(FILE* out) +{ + if (mCtors) { + PRBool haveLeaks = PR_FALSE; + PRInt32 i, n = mCtors->Count(); + for (i = 0; i < n; i++) { + CtorEntry* e = (CtorEntry*) mCtors->ElementAt(i); + if (e) { + mozCtorDtorCounter* cdc = e->counter; + if (cdc) { + if (cdc->ctors != cdc->dtors) { + haveLeaks = PR_TRUE; + break; + } + } + } + } + if (haveLeaks) { + fprintf(out, "*** There are memory leaks:\n"); + fprintf(out, "%-40s %-15s %s\n", "Type", "# created", "# leaked"); + fprintf(out, "%-40s %-15s %s\n", "----", "---------", "--------"); + + for (i = 0; i < n; i++) { + CtorEntry* e = (CtorEntry*) mCtors->ElementAt(i); + if (e && e->counter) { + mozCtorDtorCounter* cdc = e->counter; + if (cdc->ctors != cdc->dtors) { + fprintf(out, "%-40s %-15d %d\n", e->type, cdc->ctors, + cdc->ctors - cdc->dtors); + } + } + } + } + } +} + +void +nsTraceRefcnt::FlushCtorRegistry(void) +{ + if (mCtors) { + PRInt32 i, n = mCtors->Count(); + for (i = 0; i < n; i++) { + CtorEntry* e = (CtorEntry*) mCtors->ElementAt(i); + delete e; + } + delete mCtors; + } +} +#endif /* DEBUG */ diff --git a/xpcom/base/nsTraceRefcnt.h b/xpcom/base/nsTraceRefcnt.h index 2424a0f2e6bb..d4967e821921 100644 --- a/xpcom/base/nsTraceRefcnt.h +++ b/xpcom/base/nsTraceRefcnt.h @@ -20,6 +20,16 @@ #define nsTraceRefcnt_h___ #include "nsCom.h" +#include + +class nsVoidArray; + +#ifdef DEBUG +struct mozCtorDtorCounter { + PRInt32 ctors; + PRInt32 dtors; +}; +#endif /** * This class is used to support tracing (and logging using nspr) of @@ -71,6 +81,63 @@ public: const char* aFile, int aLine); +#ifdef DEBUG + /** + * Register a constructor with the xpcom library. This records the + * type name and the address of the counter so that later on when + * DumpLeaks is called, we can print out those objects ctors whose + * counter is not zero (the ones that have live object references + * still out there) + */ + static NS_COM void RegisterCtor(const char* aType, + mozCtorDtorCounter* aCounterAddr); + + static NS_COM void UnregisterCtor(const char* aType); + + /** + * Dump the leaking constructors out. + */ + static NS_COM void DumpLeaks(FILE* out); + + /** + * Erase the ctor registration data. + */ + static NS_COM void FlushCtorRegistry(void); +#endif + +protected: +#ifdef DEBUG + static nsVoidArray* mCtors; +#endif }; +//---------------------------------------------------------------------- + +#ifdef DEBUG + +#define MOZ_DECL_CTOR(_type) \ + static mozCtorDtorCounter gCounter_##_type + +#define MOZ_CTOR(_type) \ +PR_BEGIN_MACRO \ + if (0 == gCounter_##_type . ctors) { \ + nsTraceRefcnt::RegisterCtor(#_type, &gCounter_##_type); \ + } \ + gCounter_##_type . ctors++; \ +PR_END_MACRO + +#define MOZ_DTOR(_type) \ +PR_BEGIN_MACRO \ + gCounter_##_type . dtors ++; \ +PR_END_MACRO + +#else + +#define MOZ_REG_CTOR(_type,_counter) +#define MOZ_DECL_CTOR_(type) +#define MOZ_CTOR(_type) +#define MOZ_DTOR(_type) + +#endif /* DEBUG */ + #endif /* nsTraceRefcnt_h___ */ diff --git a/xpcom/base/nsTraceRefcntImpl.cpp b/xpcom/base/nsTraceRefcntImpl.cpp index e00d634ddaf5..ffa6f071f8bd 100644 --- a/xpcom/base/nsTraceRefcntImpl.cpp +++ b/xpcom/base/nsTraceRefcntImpl.cpp @@ -17,8 +17,10 @@ * Netscape Communications Corporation. All Rights Reserved. */ #include "nsISupports.h" +#include "nsVoidArray.h" #include "prprf.h" #include "prlog.h" +#include "plstr.h" #if defined(_WIN32) #include @@ -542,3 +544,99 @@ nsTraceRefcnt::DemangleSymbol(const char * aSymbol, } #endif // __linux__ +//---------------------------------------------------------------------- + +#ifdef DEBUG + +struct CtorEntry { + const char* type; + mozCtorDtorCounter* counter; +}; + +nsVoidArray* nsTraceRefcnt::mCtors; + +void +nsTraceRefcnt::RegisterCtor(const char* aType, + mozCtorDtorCounter* aCounterAddr) +{ + if (!mCtors) { + mCtors = new nsVoidArray(); + if (!mCtors) { + return; + } + } + CtorEntry* e = new CtorEntry(); + if (!e) { + return; + } + e->type = aType; + e->counter = aCounterAddr; + mCtors->AppendElement(e); +} + +void +nsTraceRefcnt::UnregisterCtor(const char* aType) +{ + if (mCtors) { + PRInt32 i, n = mCtors->Count(); + for (i = 0; i < n; i++) { + CtorEntry* e = (CtorEntry*) mCtors->ElementAt(i); + if (0 == PL_strcmp(e->type, aType)) { + delete e; + mCtors->RemoveElementAt(i); + break; + } + } + } +} + +void +nsTraceRefcnt::DumpLeaks(FILE* out) +{ + if (mCtors) { + PRBool haveLeaks = PR_FALSE; + PRInt32 i, n = mCtors->Count(); + for (i = 0; i < n; i++) { + CtorEntry* e = (CtorEntry*) mCtors->ElementAt(i); + if (e) { + mozCtorDtorCounter* cdc = e->counter; + if (cdc) { + if (cdc->ctors != cdc->dtors) { + haveLeaks = PR_TRUE; + break; + } + } + } + } + if (haveLeaks) { + fprintf(out, "*** There are memory leaks:\n"); + fprintf(out, "%-40s %-15s %s\n", "Type", "# created", "# leaked"); + fprintf(out, "%-40s %-15s %s\n", "----", "---------", "--------"); + + for (i = 0; i < n; i++) { + CtorEntry* e = (CtorEntry*) mCtors->ElementAt(i); + if (e && e->counter) { + mozCtorDtorCounter* cdc = e->counter; + if (cdc->ctors != cdc->dtors) { + fprintf(out, "%-40s %-15d %d\n", e->type, cdc->ctors, + cdc->ctors - cdc->dtors); + } + } + } + } + } +} + +void +nsTraceRefcnt::FlushCtorRegistry(void) +{ + if (mCtors) { + PRInt32 i, n = mCtors->Count(); + for (i = 0; i < n; i++) { + CtorEntry* e = (CtorEntry*) mCtors->ElementAt(i); + delete e; + } + delete mCtors; + } +} +#endif /* DEBUG */ diff --git a/xpcom/base/nsTraceRefcntImpl.h b/xpcom/base/nsTraceRefcntImpl.h index 2424a0f2e6bb..d4967e821921 100644 --- a/xpcom/base/nsTraceRefcntImpl.h +++ b/xpcom/base/nsTraceRefcntImpl.h @@ -20,6 +20,16 @@ #define nsTraceRefcnt_h___ #include "nsCom.h" +#include + +class nsVoidArray; + +#ifdef DEBUG +struct mozCtorDtorCounter { + PRInt32 ctors; + PRInt32 dtors; +}; +#endif /** * This class is used to support tracing (and logging using nspr) of @@ -71,6 +81,63 @@ public: const char* aFile, int aLine); +#ifdef DEBUG + /** + * Register a constructor with the xpcom library. This records the + * type name and the address of the counter so that later on when + * DumpLeaks is called, we can print out those objects ctors whose + * counter is not zero (the ones that have live object references + * still out there) + */ + static NS_COM void RegisterCtor(const char* aType, + mozCtorDtorCounter* aCounterAddr); + + static NS_COM void UnregisterCtor(const char* aType); + + /** + * Dump the leaking constructors out. + */ + static NS_COM void DumpLeaks(FILE* out); + + /** + * Erase the ctor registration data. + */ + static NS_COM void FlushCtorRegistry(void); +#endif + +protected: +#ifdef DEBUG + static nsVoidArray* mCtors; +#endif }; +//---------------------------------------------------------------------- + +#ifdef DEBUG + +#define MOZ_DECL_CTOR(_type) \ + static mozCtorDtorCounter gCounter_##_type + +#define MOZ_CTOR(_type) \ +PR_BEGIN_MACRO \ + if (0 == gCounter_##_type . ctors) { \ + nsTraceRefcnt::RegisterCtor(#_type, &gCounter_##_type); \ + } \ + gCounter_##_type . ctors++; \ +PR_END_MACRO + +#define MOZ_DTOR(_type) \ +PR_BEGIN_MACRO \ + gCounter_##_type . dtors ++; \ +PR_END_MACRO + +#else + +#define MOZ_REG_CTOR(_type,_counter) +#define MOZ_DECL_CTOR_(type) +#define MOZ_CTOR(_type) +#define MOZ_DTOR(_type) + +#endif /* DEBUG */ + #endif /* nsTraceRefcnt_h___ */