static int TotalEntries(PLHashEntry *he, int i, void *arg) { BloatEntry* entry = (BloatEntry*)he->value; if (entry && nsCRT::strcmp(entry->mClassName, "TOTAL") != 0) { entry->Total((BloatEntry*)arg); } return HT_ENUMERATE_NEXT; }
static BloatEntry* GetBloatEntry(const char* aTypeName, uint32_t aInstanceSize) { if (!gBloatView) { RecreateBloatView(); } BloatEntry* entry = NULL; if (gBloatView) { entry = (BloatEntry*)PL_HashTableLookup(gBloatView, aTypeName); if (entry == NULL && aInstanceSize > 0) { entry = new BloatEntry(aTypeName, aInstanceSize); PLHashEntry* e = PL_HashTableAdd(gBloatView, aTypeName, entry); if (e == NULL) { delete entry; entry = NULL; } } else { NS_ASSERTION(aInstanceSize == 0 || entry->GetClassSize() == aInstanceSize, "bad size recorded"); } } return entry; }
NS_LogCtor(void* aPtr, const char* aType, uint32_t aInstanceSize) { #ifdef NS_IMPL_REFCNT_LOGGING ASSERT_ACTIVITY_IS_LEGAL; if (!gInitialized) InitTraceLog(); if (gLogging) { LOCK_TRACELOG(); if (gBloatLog) { BloatEntry* entry = GetBloatEntry(aType, aInstanceSize); if (entry) { entry->Ctor(); } } bool loggingThisType = (!gTypesToLog || LogThisType(aType)); intptr_t serialno = 0; if (gSerialNumbers && loggingThisType) { serialno = GetSerialNumber(aPtr, true); } bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno)); if (gAllocLog && loggingThisType && loggingThisObject) { fprintf(gAllocLog, "\n<%s> 0x%08X %ld Ctor (%d)\n", aType, NS_PTR_TO_INT32(aPtr), serialno, aInstanceSize); nsTraceRefcntImpl::WalkTheStack(gAllocLog); } UNLOCK_TRACELOG(); } #endif }
NS_LogRelease(void* aPtr, nsrefcnt aRefcnt, const char* aClass) { #ifdef NS_IMPL_REFCNT_LOGGING ASSERT_ACTIVITY_IS_LEGAL; if (!gInitialized) { InitTraceLog(); } if (gLogging == NoLogging) { return; } if (aRefcnt == 0 || gLogging == FullLogging) { LOCK_TRACELOG(); if (aRefcnt == 0 && gBloatLog) { BloatEntry* entry = GetBloatEntry(aClass, 0); if (entry) { entry->Dtor(); } } bool loggingThisType = (!gTypesToLog || LogThisType(aClass)); intptr_t serialno = 0; if (gSerialNumbers && loggingThisType) { serialno = GetSerialNumber(aPtr, false); NS_ASSERTION(serialno != 0, "Serial number requested for unrecognized pointer! " "Are you memmoving a refcounted object?"); int32_t* count = GetRefCount(aPtr); if (count) { (*count)--; } } bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno)); if (gRefcntsLog && loggingThisType && loggingThisObject) { // Can't use PR_LOG(), b/c it truncates the line fprintf(gRefcntsLog, "\n<%s> %p %" PRIuPTR " Release %" PRIuPTR "\n", aClass, aPtr, serialno, aRefcnt); nsTraceRefcnt::WalkTheStackCached(gRefcntsLog); fflush(gRefcntsLog); } // Here's the case where MOZ_COUNT_DTOR was not used, // yet we still want to see deletion information: if (aRefcnt == 0 && gAllocLog && loggingThisType && loggingThisObject) { fprintf(gAllocLog, "\n<%s> %p %" PRIdPTR " Destroy\n", aClass, aPtr, serialno); nsTraceRefcnt::WalkTheStackCached(gAllocLog); } if (aRefcnt == 0 && gSerialNumbers && loggingThisType) { RecycleSerialNumberPtr(aPtr); } UNLOCK_TRACELOG(); } #endif }
static BloatEntry* GetBloatEntry(const char* aTypeName, uint32_t aInstanceSize) { if (!gBloatView) { RecreateBloatView(); } BloatEntry* entry = nullptr; if (gBloatView) { entry = (BloatEntry*)PL_HashTableLookup(gBloatView, aTypeName); if (!entry && aInstanceSize > 0) { entry = new BloatEntry(aTypeName, aInstanceSize); PLHashEntry* e = PL_HashTableAdd(gBloatView, aTypeName, entry); if (!e) { delete entry; entry = nullptr; } } else { #ifdef DEBUG static const char kMismatchedSizesMessage[] = "Mismatched sizes were recorded in the memory leak logging table. " "The usual cause of this is having a templated class that uses " "MOZ_COUNT_{C,D}TOR in the constructor or destructor, respectively. " "As a workaround, the MOZ_COUNT_{C,D}TOR calls can be moved to a " "non-templated base class."; NS_ASSERTION(aInstanceSize == 0 || entry->GetClassSize() == aInstanceSize, kMismatchedSizesMessage); #endif } } return entry; }
NS_LogCtor(void* aPtr, const char* aType, uint32_t aInstanceSize) { #ifdef NS_IMPL_REFCNT_LOGGING ASSERT_ACTIVITY_IS_LEGAL; if (!gInitialized) { InitTraceLog(); } if (gLogging != NoLogging) { AutoTraceLogLock lock; if (gBloatLog) { BloatEntry* entry = GetBloatEntry(aType, aInstanceSize); if (entry) { entry->Ctor(); } } bool loggingThisType = (!gTypesToLog || LogThisType(aType)); intptr_t serialno = 0; if (gSerialNumbers && loggingThisType) { serialno = GetSerialNumber(aPtr, true); } bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno)); if (gAllocLog && loggingThisType && loggingThisObject) { fprintf(gAllocLog, "\n<%s> %p %" PRIdPTR " Ctor (%d)\n", aType, aPtr, serialno, aInstanceSize); WalkTheStackCached(gAllocLog); } } #endif }
NS_LogCtor(void* aPtr, const char* aType, uint32_t aInstanceSize) { ASSERT_ACTIVITY_IS_LEGAL; if (!gInitialized) { InitTraceLog(); } if (gLogging == NoLogging) { return; } AutoTraceLogLock lock; if (gBloatLog) { BloatEntry* entry = GetBloatEntry(aType, aInstanceSize); if (entry) { entry->Ctor(); } } bool loggingThisType = (!gTypesToLog || LogThisType(aType)); intptr_t serialno = 0; if (gSerialNumbers && loggingThisType) { serialno = GetSerialNumber(aPtr, true); MOZ_ASSERT(serialno != 0, "GetSerialNumber should never return 0 when passed true"); } bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno)); if (gAllocLog && loggingThisType && loggingThisObject) { fprintf(gAllocLog, "\n<%s> %p %" PRIdPTR " Ctor (%d)\n", aType, aPtr, serialno, aInstanceSize); WalkTheStackCached(gAllocLog); } }
static int DumpEntry(PLHashEntry *he, int i, void *arg) { BloatEntry* entry = (BloatEntry*)he->value; if (entry) { entry->Accumulate(); static_cast<nsTArray<BloatEntry*>*>(arg)->AppendElement(entry); } return HT_ENUMERATE_NEXT; }
NS_LogAddRef(void* aPtr, nsrefcnt aRefcnt, const char* aClazz, uint32_t classSize) { #ifdef NS_IMPL_REFCNT_LOGGING ASSERT_ACTIVITY_IS_LEGAL; if (!gInitialized) InitTraceLog(); if (gLogging) { LOCK_TRACELOG(); if (gBloatLog) { BloatEntry* entry = GetBloatEntry(aClazz, classSize); if (entry) { entry->AddRef(aRefcnt); } } // Here's the case where MOZ_COUNT_CTOR was not used, // yet we still want to see creation information: bool loggingThisType = (!gTypesToLog || LogThisType(aClazz)); intptr_t serialno = 0; if (gSerialNumbers && loggingThisType) { serialno = GetSerialNumber(aPtr, aRefcnt == 1); NS_ASSERTION(serialno != 0, "Serial number requested for unrecognized pointer! " "Are you memmoving a refcounted object?"); int32_t* count = GetRefCount(aPtr); if(count) (*count)++; } bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno)); if (aRefcnt == 1 && gAllocLog && loggingThisType && loggingThisObject) { fprintf(gAllocLog, "\n<%s> 0x%08X %ld Create\n", aClazz, NS_PTR_TO_INT32(aPtr), serialno); nsTraceRefcntImpl::WalkTheStack(gAllocLog); } if (gRefcntsLog && loggingThisType && loggingThisObject) { if (gLogToLeaky) { (*leakyLogAddRef)(aPtr, aRefcnt - 1, aRefcnt); } else { // Can't use PR_LOG(), b/c it truncates the line fprintf(gRefcntsLog, "\n<%s> 0x%08X %ld AddRef %d\n", aClazz, NS_PTR_TO_INT32(aPtr), serialno, aRefcnt); nsTraceRefcntImpl::WalkTheStack(gRefcntsLog); fflush(gRefcntsLog); } } UNLOCK_TRACELOG(); } #endif }
NS_LogAddRef(void* aPtr, nsrefcnt aRefcnt, const char* aClass, uint32_t aClassSize) { #ifdef NS_IMPL_REFCNT_LOGGING ASSERT_ACTIVITY_IS_LEGAL; if (!gInitialized) { InitTraceLog(); } if (gLogging == NoLogging) { return; } if (aRefcnt == 1 || gLogging == FullLogging) { AutoTraceLogLock lock; if (aRefcnt == 1 && gBloatLog) { BloatEntry* entry = GetBloatEntry(aClass, aClassSize); if (entry) { entry->Ctor(); } } // Here's the case where MOZ_COUNT_CTOR was not used, // yet we still want to see creation information: bool loggingThisType = (!gTypesToLog || LogThisType(aClass)); intptr_t serialno = 0; if (gSerialNumbers && loggingThisType) { serialno = GetSerialNumber(aPtr, aRefcnt == 1); NS_ASSERTION(serialno != 0, "Serial number requested for unrecognized pointer! " "Are you memmoving a refcounted object?"); int32_t* count = GetRefCount(aPtr); if (count) { (*count)++; } } bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno)); if (aRefcnt == 1 && gAllocLog && loggingThisType && loggingThisObject) { fprintf(gAllocLog, "\n<%s> %p %" PRIdPTR " Create [thread %p]\n", aClass, aPtr, serialno, PR_GetCurrentThread()); WalkTheStackCached(gAllocLog); } if (gRefcntsLog && loggingThisType && loggingThisObject) { // Can't use MOZ_LOG(), b/c it truncates the line fprintf(gRefcntsLog, "\n<%s> %p %" PRIuPTR " AddRef %" PRIuPTR " [thread %p]\n", aClass, aPtr, serialno, aRefcnt, PR_GetCurrentThread()); WalkTheStackCached(gRefcntsLog); fflush(gRefcntsLog); } } #endif }
nsresult nsTraceRefcnt::DumpStatistics() { if (!gBloatLog || !gBloatView) { return NS_ERROR_FAILURE; } AutoTraceLogLock lock; MOZ_ASSERT(!gDumpedStatistics, "Calling DumpStatistics more than once may result in " "bogus positive or negative leaks being reported"); gDumpedStatistics = true; // Don't try to log while we hold the lock, we'd deadlock. AutoRestore<LoggingType> saveLogging(gLogging); gLogging = NoLogging; BloatEntry total("TOTAL", 0); PL_HashTableEnumerateEntries(gBloatView, BloatEntry::TotalEntries, &total); const char* msg; if (gLogLeaksOnly) { msg = "ALL (cumulative) LEAK STATISTICS"; } else { msg = "ALL (cumulative) LEAK AND BLOAT STATISTICS"; } const bool leaked = total.PrintDumpHeader(gBloatLog, msg); nsTArray<BloatEntry*> entries; PL_HashTableEnumerateEntries(gBloatView, BloatEntry::DumpEntry, &entries); const uint32_t count = entries.Length(); if (!gLogLeaksOnly || leaked) { // Sort the entries alphabetically by classname. entries.Sort(); for (uint32_t i = 0; i < count; ++i) { BloatEntry* entry = entries[i]; entry->Dump(i, gBloatLog); } fprintf(gBloatLog, "\n"); } fprintf(gBloatLog, "nsTraceRefcnt::DumpStatistics: %d entries\n", count); if (gSerialNumbers) { fprintf(gBloatLog, "\nSerial Numbers of Leaked Objects:\n"); PL_HashTableEnumerateEntries(gSerialNumbers, DumpSerialNumbers, gBloatLog); } return NS_OK; }
NS_LogDtor(void* aPtr, const char* aType, uint32_t aInstanceSize) { ASSERT_ACTIVITY_IS_LEGAL; if (!gInitialized) { InitTraceLog(); } if (gLogging == NoLogging) { return; } AutoTraceLogLock lock; if (gBloatLog) { BloatEntry* entry = GetBloatEntry(aType, aInstanceSize); if (entry) { entry->Dtor(); } } bool loggingThisType = (!gTypesToLog || LogThisType(aType)); intptr_t serialno = 0; if (gSerialNumbers && loggingThisType) { serialno = GetSerialNumber(aPtr, false); MOZ_ASSERT(serialno != 0, "Serial number requested for unrecognized pointer! " "Are you memmoving a MOZ_COUNT_CTOR-tracked object?"); RecycleSerialNumberPtr(aPtr); } bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno)); // (If we're on a losing architecture, don't do this because we'll be // using LogDeleteXPCOM instead to get file and line numbers.) if (gAllocLog && loggingThisType && loggingThisObject) { fprintf(gAllocLog, "\n<%s> %p %" PRIdPTR " Dtor (%d)\n", aType, aPtr, serialno, aInstanceSize); WalkTheStackCached(gAllocLog); } }
NS_LogDtor(void* aPtr, const char* aType, uint32_t aInstanceSize) { #ifdef NS_IMPL_REFCNT_LOGGING ASSERT_ACTIVITY_IS_LEGAL; if (!gInitialized) { InitTraceLog(); } if (gLogging != NoLogging) { LOCK_TRACELOG(); if (gBloatLog) { BloatEntry* entry = GetBloatEntry(aType, aInstanceSize); if (entry) { entry->Dtor(); } } bool loggingThisType = (!gTypesToLog || LogThisType(aType)); intptr_t serialno = 0; if (gSerialNumbers && loggingThisType) { serialno = GetSerialNumber(aPtr, false); RecycleSerialNumberPtr(aPtr); } bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno)); // (If we're on a losing architecture, don't do this because we'll be // using LogDeleteXPCOM instead to get file and line numbers.) if (gAllocLog && loggingThisType && loggingThisObject) { fprintf(gAllocLog, "\n<%s> %p %" PRIdPTR " Dtor (%d)\n", aType, aPtr, serialno, aInstanceSize); nsTraceRefcnt::WalkTheStackCached(gAllocLog); } UNLOCK_TRACELOG(); } #endif }
nsresult nsTraceRefcntImpl::DumpStatistics(StatisticsType type, FILE* out) { #ifdef NS_IMPL_REFCNT_LOGGING if (gBloatLog == nullptr || gBloatView == nullptr) { return NS_ERROR_FAILURE; } if (out == nullptr) { out = gBloatLog; } LOCK_TRACELOG(); bool wasLogging = gLogging; gLogging = false; // turn off logging for this method BloatEntry total("TOTAL", 0); PL_HashTableEnumerateEntries(gBloatView, BloatEntry::TotalEntries, &total); const char* msg; if (type == NEW_STATS) { if (gLogLeaksOnly) msg = "NEW (incremental) LEAK STATISTICS"; else msg = "NEW (incremental) LEAK AND BLOAT STATISTICS"; } else { if (gLogLeaksOnly) msg = "ALL (cumulative) LEAK STATISTICS"; else msg = "ALL (cumulative) LEAK AND BLOAT STATISTICS"; } const bool leaked = total.PrintDumpHeader(out, msg, type); nsTArray<BloatEntry*> entries; PL_HashTableEnumerateEntries(gBloatView, BloatEntry::DumpEntry, &entries); const uint32_t count = entries.Length(); if (!gLogLeaksOnly || leaked) { // Sort the entries alphabetically by classname. entries.Sort(); for (uint32_t i = 0; i < count; ++i) { BloatEntry* entry = entries[i]; entry->Dump(i, out, type); } fprintf(out, "\n"); } fprintf(out, "nsTraceRefcntImpl::DumpStatistics: %d entries\n", count); if (gSerialNumbers) { fprintf(out, "\nSerial Numbers of Leaked Objects:\n"); PL_HashTableEnumerateEntries(gSerialNumbers, DumpSerialNumbers, out); } gLogging = wasLogging; UNLOCK_TRACELOG(); #endif return NS_OK; }
nsresult nsTraceRefcnt::DumpStatistics(StatisticsType aType, FILE* aOut) { #ifdef NS_IMPL_REFCNT_LOGGING if (!gBloatLog || !gBloatView) { return NS_ERROR_FAILURE; } if (!aOut) { aOut = gBloatLog; } AutoTraceLogLock lock; // Don't try to log while we hold the lock, we'd deadlock. AutoRestore<LoggingType> saveLogging(gLogging); gLogging = NoLogging; BloatEntry total("TOTAL", 0); PL_HashTableEnumerateEntries(gBloatView, BloatEntry::TotalEntries, &total); const char* msg; if (aType == NEW_STATS) { if (gLogLeaksOnly) { msg = "NEW (incremental) LEAK STATISTICS"; } else { msg = "NEW (incremental) LEAK AND BLOAT STATISTICS"; } } else { if (gLogLeaksOnly) { msg = "ALL (cumulative) LEAK STATISTICS"; } else { msg = "ALL (cumulative) LEAK AND BLOAT STATISTICS"; } } const bool leaked = total.PrintDumpHeader(aOut, msg, aType); nsTArray<BloatEntry*> entries; PL_HashTableEnumerateEntries(gBloatView, BloatEntry::DumpEntry, &entries); const uint32_t count = entries.Length(); if (!gLogLeaksOnly || leaked) { // Sort the entries alphabetically by classname. entries.Sort(); for (uint32_t i = 0; i < count; ++i) { BloatEntry* entry = entries[i]; entry->Dump(i, aOut, aType); } fprintf(aOut, "\n"); } fprintf(aOut, "nsTraceRefcnt::DumpStatistics: %d entries\n", count); if (gSerialNumbers) { fprintf(aOut, "\nSerial Numbers of Leaked Objects:\n"); PL_HashTableEnumerateEntries(gSerialNumbers, DumpSerialNumbers, aOut); } #endif return NS_OK; }