1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/base/nsTraceRefcnt.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1298 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsTraceRefcnt.h" 1.10 +#include "mozilla/IntegerPrintfMacros.h" 1.11 +#include "nsXPCOMPrivate.h" 1.12 +#include "nscore.h" 1.13 +#include "nsISupports.h" 1.14 +#include "nsTArray.h" 1.15 +#include "prenv.h" 1.16 +#include "plstr.h" 1.17 +#include "prlink.h" 1.18 +#include "nsCRT.h" 1.19 +#include <math.h> 1.20 +#include "nsStackWalkPrivate.h" 1.21 +#include "nsStackWalk.h" 1.22 +#include "nsString.h" 1.23 + 1.24 +#include "nsXULAppAPI.h" 1.25 +#ifdef XP_WIN 1.26 +#include <process.h> 1.27 +#define getpid _getpid 1.28 +#else 1.29 +#include <unistd.h> 1.30 +#endif 1.31 + 1.32 +#ifdef NS_TRACE_MALLOC 1.33 +#include "nsTraceMalloc.h" 1.34 +#endif 1.35 + 1.36 +#include "mozilla/BlockingResourceBase.h" 1.37 +#include "mozilla/PoisonIOInterposer.h" 1.38 + 1.39 +#ifdef HAVE_DLOPEN 1.40 +#include <dlfcn.h> 1.41 +#endif 1.42 + 1.43 +//////////////////////////////////////////////////////////////////////////////// 1.44 + 1.45 +void 1.46 +NS_MeanAndStdDev(double n, double sumOfValues, double sumOfSquaredValues, 1.47 + double *meanResult, double *stdDevResult) 1.48 +{ 1.49 + double mean = 0.0, var = 0.0, stdDev = 0.0; 1.50 + if (n > 0.0 && sumOfValues >= 0) { 1.51 + mean = sumOfValues / n; 1.52 + double temp = (n * sumOfSquaredValues) - (sumOfValues * sumOfValues); 1.53 + if (temp < 0.0 || n <= 1) 1.54 + var = 0.0; 1.55 + else 1.56 + var = temp / (n * (n - 1)); 1.57 + // for some reason, Windows says sqrt(0.0) is "-1.#J" (?!) so do this: 1.58 + stdDev = var != 0.0 ? sqrt(var) : 0.0; 1.59 + } 1.60 + *meanResult = mean; 1.61 + *stdDevResult = stdDev; 1.62 +} 1.63 + 1.64 +//////////////////////////////////////////////////////////////////////////////// 1.65 + 1.66 +#if !defined(XP_WIN) || (!defined(MOZ_OPTIMIZE) || defined(MOZ_PROFILING) || defined(DEBUG)) 1.67 +#define STACKWALKING_AVAILABLE 1.68 +#endif 1.69 + 1.70 +#define NS_IMPL_REFCNT_LOGGING 1.71 + 1.72 +#ifdef NS_IMPL_REFCNT_LOGGING 1.73 +#include "plhash.h" 1.74 +#include "prmem.h" 1.75 + 1.76 +#include "prlock.h" 1.77 + 1.78 +// TraceRefcnt has to use bare PRLock instead of mozilla::Mutex 1.79 +// because TraceRefcnt can be used very early in startup. 1.80 +static PRLock* gTraceLock; 1.81 + 1.82 +#define LOCK_TRACELOG() PR_Lock(gTraceLock) 1.83 +#define UNLOCK_TRACELOG() PR_Unlock(gTraceLock) 1.84 + 1.85 +static PLHashTable* gBloatView; 1.86 +static PLHashTable* gTypesToLog; 1.87 +static PLHashTable* gObjectsToLog; 1.88 +static PLHashTable* gSerialNumbers; 1.89 +static intptr_t gNextSerialNumber; 1.90 + 1.91 +static bool gLogging; 1.92 +static bool gLogToLeaky; 1.93 +static bool gLogLeaksOnly; 1.94 + 1.95 +static void (*leakyLogAddRef)(void* p, int oldrc, int newrc); 1.96 +static void (*leakyLogRelease)(void* p, int oldrc, int newrc); 1.97 + 1.98 +#define BAD_TLS_INDEX ((unsigned) -1) 1.99 + 1.100 +// if gActivityTLS == BAD_TLS_INDEX, then we're 1.101 +// unitialized... otherwise this points to a NSPR TLS thread index 1.102 +// indicating whether addref activity is legal. If the PTR_TO_INT32 is 0 then 1.103 +// activity is ok, otherwise not! 1.104 +static unsigned gActivityTLS = BAD_TLS_INDEX; 1.105 + 1.106 +static bool gInitialized; 1.107 +static nsrefcnt gInitCount; 1.108 + 1.109 +static FILE *gBloatLog = nullptr; 1.110 +static FILE *gRefcntsLog = nullptr; 1.111 +static FILE *gAllocLog = nullptr; 1.112 +static FILE *gLeakyLog = nullptr; 1.113 +static FILE *gCOMPtrLog = nullptr; 1.114 + 1.115 +struct serialNumberRecord { 1.116 + intptr_t serialNumber; 1.117 + int32_t refCount; 1.118 + int32_t COMPtrCount; 1.119 +}; 1.120 + 1.121 +struct nsTraceRefcntStats { 1.122 + uint64_t mAddRefs; 1.123 + uint64_t mReleases; 1.124 + uint64_t mCreates; 1.125 + uint64_t mDestroys; 1.126 + double mRefsOutstandingTotal; 1.127 + double mRefsOutstandingSquared; 1.128 + double mObjsOutstandingTotal; 1.129 + double mObjsOutstandingSquared; 1.130 +}; 1.131 + 1.132 + // I hope to turn this on for everybody once we hit it a little less. 1.133 +#ifdef DEBUG 1.134 +static const char kStaticCtorDtorWarning[] = 1.135 + "XPCOM objects created/destroyed from static ctor/dtor"; 1.136 + 1.137 +static void 1.138 +AssertActivityIsLegal() 1.139 +{ 1.140 + if (gActivityTLS == BAD_TLS_INDEX || 1.141 + NS_PTR_TO_INT32(PR_GetThreadPrivate(gActivityTLS)) != 0) { 1.142 + if (PR_GetEnv("MOZ_FATAL_STATIC_XPCOM_CTORS_DTORS")) { 1.143 + NS_RUNTIMEABORT(kStaticCtorDtorWarning); 1.144 + } else { 1.145 + NS_WARNING(kStaticCtorDtorWarning); 1.146 + } 1.147 + } 1.148 +} 1.149 +# define ASSERT_ACTIVITY_IS_LEGAL \ 1.150 + PR_BEGIN_MACRO \ 1.151 + AssertActivityIsLegal(); \ 1.152 + PR_END_MACRO 1.153 +#else 1.154 +# define ASSERT_ACTIVITY_IS_LEGAL PR_BEGIN_MACRO PR_END_MACRO 1.155 +#endif // DEBUG 1.156 + 1.157 +// These functions are copied from nsprpub/lib/ds/plhash.c, with changes 1.158 +// to the functions not called Default* to free the serialNumberRecord or 1.159 +// the BloatEntry. 1.160 + 1.161 +static void * 1.162 +DefaultAllocTable(void *pool, size_t size) 1.163 +{ 1.164 + return PR_MALLOC(size); 1.165 +} 1.166 + 1.167 +static void 1.168 +DefaultFreeTable(void *pool, void *item) 1.169 +{ 1.170 + PR_Free(item); 1.171 +} 1.172 + 1.173 +static PLHashEntry * 1.174 +DefaultAllocEntry(void *pool, const void *key) 1.175 +{ 1.176 + return PR_NEW(PLHashEntry); 1.177 +} 1.178 + 1.179 +static void 1.180 +SerialNumberFreeEntry(void *pool, PLHashEntry *he, unsigned flag) 1.181 +{ 1.182 + if (flag == HT_FREE_ENTRY) { 1.183 + PR_Free(reinterpret_cast<serialNumberRecord*>(he->value)); 1.184 + PR_Free(he); 1.185 + } 1.186 +} 1.187 + 1.188 +static void 1.189 +TypesToLogFreeEntry(void *pool, PLHashEntry *he, unsigned flag) 1.190 +{ 1.191 + if (flag == HT_FREE_ENTRY) { 1.192 + free(const_cast<char*>(reinterpret_cast<const char*>(he->key))); 1.193 + PR_Free(he); 1.194 + } 1.195 +} 1.196 + 1.197 +static const PLHashAllocOps serialNumberHashAllocOps = { 1.198 + DefaultAllocTable, DefaultFreeTable, 1.199 + DefaultAllocEntry, SerialNumberFreeEntry 1.200 +}; 1.201 + 1.202 +static const PLHashAllocOps typesToLogHashAllocOps = { 1.203 + DefaultAllocTable, DefaultFreeTable, 1.204 + DefaultAllocEntry, TypesToLogFreeEntry 1.205 +}; 1.206 + 1.207 +//////////////////////////////////////////////////////////////////////////////// 1.208 + 1.209 +class BloatEntry { 1.210 +public: 1.211 + BloatEntry(const char* className, uint32_t classSize) 1.212 + : mClassSize(classSize) { 1.213 + mClassName = PL_strdup(className); 1.214 + Clear(&mNewStats); 1.215 + Clear(&mAllStats); 1.216 + mTotalLeaked = 0; 1.217 + } 1.218 + 1.219 + ~BloatEntry() { 1.220 + PL_strfree(mClassName); 1.221 + } 1.222 + 1.223 + uint32_t GetClassSize() { return (uint32_t)mClassSize; } 1.224 + const char* GetClassName() { return mClassName; } 1.225 + 1.226 + static void Clear(nsTraceRefcntStats* stats) { 1.227 + stats->mAddRefs = 0; 1.228 + stats->mReleases = 0; 1.229 + stats->mCreates = 0; 1.230 + stats->mDestroys = 0; 1.231 + stats->mRefsOutstandingTotal = 0; 1.232 + stats->mRefsOutstandingSquared = 0; 1.233 + stats->mObjsOutstandingTotal = 0; 1.234 + stats->mObjsOutstandingSquared = 0; 1.235 + } 1.236 + 1.237 + void Accumulate() { 1.238 + mAllStats.mAddRefs += mNewStats.mAddRefs; 1.239 + mAllStats.mReleases += mNewStats.mReleases; 1.240 + mAllStats.mCreates += mNewStats.mCreates; 1.241 + mAllStats.mDestroys += mNewStats.mDestroys; 1.242 + mAllStats.mRefsOutstandingTotal += mNewStats.mRefsOutstandingTotal; 1.243 + mAllStats.mRefsOutstandingSquared += mNewStats.mRefsOutstandingSquared; 1.244 + mAllStats.mObjsOutstandingTotal += mNewStats.mObjsOutstandingTotal; 1.245 + mAllStats.mObjsOutstandingSquared += mNewStats.mObjsOutstandingSquared; 1.246 + Clear(&mNewStats); 1.247 + } 1.248 + 1.249 + void AddRef(nsrefcnt refcnt) { 1.250 + mNewStats.mAddRefs++; 1.251 + if (refcnt == 1) { 1.252 + Ctor(); 1.253 + } 1.254 + AccountRefs(); 1.255 + } 1.256 + 1.257 + void Release(nsrefcnt refcnt) { 1.258 + mNewStats.mReleases++; 1.259 + if (refcnt == 0) { 1.260 + Dtor(); 1.261 + } 1.262 + AccountRefs(); 1.263 + } 1.264 + 1.265 + void Ctor() { 1.266 + mNewStats.mCreates++; 1.267 + AccountObjs(); 1.268 + } 1.269 + 1.270 + void Dtor() { 1.271 + mNewStats.mDestroys++; 1.272 + AccountObjs(); 1.273 + } 1.274 + 1.275 + void AccountRefs() { 1.276 + uint64_t cnt = (mNewStats.mAddRefs - mNewStats.mReleases); 1.277 + mNewStats.mRefsOutstandingTotal += cnt; 1.278 + mNewStats.mRefsOutstandingSquared += cnt * cnt; 1.279 + } 1.280 + 1.281 + void AccountObjs() { 1.282 + uint64_t cnt = (mNewStats.mCreates - mNewStats.mDestroys); 1.283 + mNewStats.mObjsOutstandingTotal += cnt; 1.284 + mNewStats.mObjsOutstandingSquared += cnt * cnt; 1.285 + } 1.286 + 1.287 + static int DumpEntry(PLHashEntry *he, int i, void *arg) { 1.288 + BloatEntry* entry = (BloatEntry*)he->value; 1.289 + if (entry) { 1.290 + entry->Accumulate(); 1.291 + static_cast<nsTArray<BloatEntry*>*>(arg)->AppendElement(entry); 1.292 + } 1.293 + return HT_ENUMERATE_NEXT; 1.294 + } 1.295 + 1.296 + static int TotalEntries(PLHashEntry *he, int i, void *arg) { 1.297 + BloatEntry* entry = (BloatEntry*)he->value; 1.298 + if (entry && nsCRT::strcmp(entry->mClassName, "TOTAL") != 0) { 1.299 + entry->Total((BloatEntry*)arg); 1.300 + } 1.301 + return HT_ENUMERATE_NEXT; 1.302 + } 1.303 + 1.304 + void Total(BloatEntry* total) { 1.305 + total->mAllStats.mAddRefs += mNewStats.mAddRefs + mAllStats.mAddRefs; 1.306 + total->mAllStats.mReleases += mNewStats.mReleases + mAllStats.mReleases; 1.307 + total->mAllStats.mCreates += mNewStats.mCreates + mAllStats.mCreates; 1.308 + total->mAllStats.mDestroys += mNewStats.mDestroys + mAllStats.mDestroys; 1.309 + total->mAllStats.mRefsOutstandingTotal += mNewStats.mRefsOutstandingTotal + mAllStats.mRefsOutstandingTotal; 1.310 + total->mAllStats.mRefsOutstandingSquared += mNewStats.mRefsOutstandingSquared + mAllStats.mRefsOutstandingSquared; 1.311 + total->mAllStats.mObjsOutstandingTotal += mNewStats.mObjsOutstandingTotal + mAllStats.mObjsOutstandingTotal; 1.312 + total->mAllStats.mObjsOutstandingSquared += mNewStats.mObjsOutstandingSquared + mAllStats.mObjsOutstandingSquared; 1.313 + uint64_t count = (mNewStats.mCreates + mAllStats.mCreates); 1.314 + total->mClassSize += mClassSize * count; // adjust for average in DumpTotal 1.315 + total->mTotalLeaked += (uint64_t)(mClassSize * 1.316 + ((mNewStats.mCreates + mAllStats.mCreates) 1.317 + -(mNewStats.mDestroys + mAllStats.mDestroys))); 1.318 + } 1.319 + 1.320 + void DumpTotal(FILE* out) { 1.321 + mClassSize /= mAllStats.mCreates; 1.322 + Dump(-1, out, nsTraceRefcnt::ALL_STATS); 1.323 + } 1.324 + 1.325 + static bool HaveLeaks(nsTraceRefcntStats* stats) { 1.326 + return ((stats->mAddRefs != stats->mReleases) || 1.327 + (stats->mCreates != stats->mDestroys)); 1.328 + } 1.329 + 1.330 + bool PrintDumpHeader(FILE* out, const char* msg, nsTraceRefcnt::StatisticsType type) { 1.331 + fprintf(out, "\n== BloatView: %s, %s process %d\n", msg, 1.332 + XRE_ChildProcessTypeToString(XRE_GetProcessType()), getpid()); 1.333 + nsTraceRefcntStats& stats = 1.334 + (type == nsTraceRefcnt::NEW_STATS) ? mNewStats : mAllStats; 1.335 + if (gLogLeaksOnly && !HaveLeaks(&stats)) 1.336 + return false; 1.337 + 1.338 + fprintf(out, 1.339 + "\n" \ 1.340 + " |<----------------Class--------------->|<-----Bytes------>|<----------------Objects---------------->|<--------------References-------------->|\n" \ 1.341 + " Per-Inst Leaked Total Rem Mean StdDev Total Rem Mean StdDev\n"); 1.342 + 1.343 + this->DumpTotal(out); 1.344 + 1.345 + return true; 1.346 + } 1.347 + 1.348 + void Dump(int i, FILE* out, nsTraceRefcnt::StatisticsType type) { 1.349 + nsTraceRefcntStats* stats = (type == nsTraceRefcnt::NEW_STATS) ? &mNewStats : &mAllStats; 1.350 + if (gLogLeaksOnly && !HaveLeaks(stats)) { 1.351 + return; 1.352 + } 1.353 + 1.354 + double meanRefs, stddevRefs; 1.355 + NS_MeanAndStdDev(stats->mAddRefs + stats->mReleases, 1.356 + stats->mRefsOutstandingTotal, 1.357 + stats->mRefsOutstandingSquared, 1.358 + &meanRefs, &stddevRefs); 1.359 + 1.360 + double meanObjs, stddevObjs; 1.361 + NS_MeanAndStdDev(stats->mCreates + stats->mDestroys, 1.362 + stats->mObjsOutstandingTotal, 1.363 + stats->mObjsOutstandingSquared, 1.364 + &meanObjs, &stddevObjs); 1.365 + 1.366 + if ((stats->mAddRefs - stats->mReleases) != 0 || 1.367 + stats->mAddRefs != 0 || 1.368 + meanRefs != 0 || 1.369 + stddevRefs != 0 || 1.370 + (stats->mCreates - stats->mDestroys) != 0 || 1.371 + stats->mCreates != 0 || 1.372 + meanObjs != 0 || 1.373 + stddevObjs != 0) { 1.374 + fprintf(out, "%4d %-40.40s %8d %8" PRIu64 " %8" PRIu64 " %8" PRIu64 " (%8.2f +/- %8.2f) %8" PRIu64 " %8" PRIu64 " (%8.2f +/- %8.2f)\n", 1.375 + i+1, mClassName, 1.376 + (int32_t)mClassSize, 1.377 + (nsCRT::strcmp(mClassName, "TOTAL")) 1.378 + ?(uint64_t)((stats->mCreates - stats->mDestroys) * mClassSize) 1.379 + :mTotalLeaked, 1.380 + stats->mCreates, 1.381 + (stats->mCreates - stats->mDestroys), 1.382 + meanObjs, 1.383 + stddevObjs, 1.384 + stats->mAddRefs, 1.385 + (stats->mAddRefs - stats->mReleases), 1.386 + meanRefs, 1.387 + stddevRefs); 1.388 + } 1.389 + } 1.390 + 1.391 +protected: 1.392 + char* mClassName; 1.393 + double mClassSize; // this is stored as a double because of the way we compute the avg class size for total bloat 1.394 + uint64_t mTotalLeaked; // used only for TOTAL entry 1.395 + nsTraceRefcntStats mNewStats; 1.396 + nsTraceRefcntStats mAllStats; 1.397 +}; 1.398 + 1.399 +static void 1.400 +BloatViewFreeEntry(void *pool, PLHashEntry *he, unsigned flag) 1.401 +{ 1.402 + if (flag == HT_FREE_ENTRY) { 1.403 + BloatEntry* entry = reinterpret_cast<BloatEntry*>(he->value); 1.404 + delete entry; 1.405 + PR_Free(he); 1.406 + } 1.407 +} 1.408 + 1.409 +const static PLHashAllocOps bloatViewHashAllocOps = { 1.410 + DefaultAllocTable, DefaultFreeTable, 1.411 + DefaultAllocEntry, BloatViewFreeEntry 1.412 +}; 1.413 + 1.414 +static void 1.415 +RecreateBloatView() 1.416 +{ 1.417 + gBloatView = PL_NewHashTable(256, 1.418 + PL_HashString, 1.419 + PL_CompareStrings, 1.420 + PL_CompareValues, 1.421 + &bloatViewHashAllocOps, nullptr); 1.422 +} 1.423 + 1.424 +static BloatEntry* 1.425 +GetBloatEntry(const char* aTypeName, uint32_t aInstanceSize) 1.426 +{ 1.427 + if (!gBloatView) { 1.428 + RecreateBloatView(); 1.429 + } 1.430 + BloatEntry* entry = nullptr; 1.431 + if (gBloatView) { 1.432 + entry = (BloatEntry*)PL_HashTableLookup(gBloatView, aTypeName); 1.433 + if (entry == nullptr && aInstanceSize > 0) { 1.434 + 1.435 + entry = new BloatEntry(aTypeName, aInstanceSize); 1.436 + PLHashEntry* e = PL_HashTableAdd(gBloatView, aTypeName, entry); 1.437 + if (e == nullptr) { 1.438 + delete entry; 1.439 + entry = nullptr; 1.440 + } 1.441 + } else { 1.442 + NS_ASSERTION(aInstanceSize == 0 || 1.443 + entry->GetClassSize() == aInstanceSize, 1.444 + "bad size recorded"); 1.445 + } 1.446 + } 1.447 + return entry; 1.448 +} 1.449 + 1.450 +static int DumpSerialNumbers(PLHashEntry* aHashEntry, int aIndex, void* aClosure) 1.451 +{ 1.452 + serialNumberRecord* record = reinterpret_cast<serialNumberRecord *>(aHashEntry->value); 1.453 +#ifdef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR 1.454 + fprintf((FILE*) aClosure, "%" PRIdPTR 1.455 + " @%p (%d references; %d from COMPtrs)\n", 1.456 + record->serialNumber, 1.457 + NS_INT32_TO_PTR(aHashEntry->key), 1.458 + record->refCount, 1.459 + record->COMPtrCount); 1.460 +#else 1.461 + fprintf((FILE*) aClosure, "%" PRIdPTR 1.462 + " @%p (%d references)\n", 1.463 + record->serialNumber, 1.464 + NS_INT32_TO_PTR(aHashEntry->key), 1.465 + record->refCount); 1.466 +#endif 1.467 + return HT_ENUMERATE_NEXT; 1.468 +} 1.469 + 1.470 + 1.471 +template <> 1.472 +class nsDefaultComparator <BloatEntry*, BloatEntry*> { 1.473 + public: 1.474 + bool Equals(BloatEntry* const& aA, BloatEntry* const& aB) const { 1.475 + return PL_strcmp(aA->GetClassName(), aB->GetClassName()) == 0; 1.476 + } 1.477 + bool LessThan(BloatEntry* const& aA, BloatEntry* const& aB) const { 1.478 + return PL_strcmp(aA->GetClassName(), aB->GetClassName()) < 0; 1.479 + } 1.480 +}; 1.481 + 1.482 +#endif /* NS_IMPL_REFCNT_LOGGING */ 1.483 + 1.484 +nsresult 1.485 +nsTraceRefcnt::DumpStatistics(StatisticsType type, FILE* out) 1.486 +{ 1.487 +#ifdef NS_IMPL_REFCNT_LOGGING 1.488 + if (gBloatLog == nullptr || gBloatView == nullptr) { 1.489 + return NS_ERROR_FAILURE; 1.490 + } 1.491 + if (out == nullptr) { 1.492 + out = gBloatLog; 1.493 + } 1.494 + 1.495 + LOCK_TRACELOG(); 1.496 + 1.497 + bool wasLogging = gLogging; 1.498 + gLogging = false; // turn off logging for this method 1.499 + 1.500 + BloatEntry total("TOTAL", 0); 1.501 + PL_HashTableEnumerateEntries(gBloatView, BloatEntry::TotalEntries, &total); 1.502 + const char* msg; 1.503 + if (type == NEW_STATS) { 1.504 + if (gLogLeaksOnly) 1.505 + msg = "NEW (incremental) LEAK STATISTICS"; 1.506 + else 1.507 + msg = "NEW (incremental) LEAK AND BLOAT STATISTICS"; 1.508 + } 1.509 + else { 1.510 + if (gLogLeaksOnly) 1.511 + msg = "ALL (cumulative) LEAK STATISTICS"; 1.512 + else 1.513 + msg = "ALL (cumulative) LEAK AND BLOAT STATISTICS"; 1.514 + } 1.515 + const bool leaked = total.PrintDumpHeader(out, msg, type); 1.516 + 1.517 + nsTArray<BloatEntry*> entries; 1.518 + PL_HashTableEnumerateEntries(gBloatView, BloatEntry::DumpEntry, &entries); 1.519 + const uint32_t count = entries.Length(); 1.520 + 1.521 + if (!gLogLeaksOnly || leaked) { 1.522 + // Sort the entries alphabetically by classname. 1.523 + entries.Sort(); 1.524 + 1.525 + for (uint32_t i = 0; i < count; ++i) { 1.526 + BloatEntry* entry = entries[i]; 1.527 + entry->Dump(i, out, type); 1.528 + } 1.529 + 1.530 + fprintf(out, "\n"); 1.531 + } 1.532 + 1.533 + fprintf(out, "nsTraceRefcnt::DumpStatistics: %d entries\n", count); 1.534 + 1.535 + if (gSerialNumbers) { 1.536 + fprintf(out, "\nSerial Numbers of Leaked Objects:\n"); 1.537 + PL_HashTableEnumerateEntries(gSerialNumbers, DumpSerialNumbers, out); 1.538 + } 1.539 + 1.540 + gLogging = wasLogging; 1.541 + UNLOCK_TRACELOG(); 1.542 +#endif 1.543 + 1.544 + return NS_OK; 1.545 +} 1.546 + 1.547 +void 1.548 +nsTraceRefcnt::ResetStatistics() 1.549 +{ 1.550 +#ifdef NS_IMPL_REFCNT_LOGGING 1.551 + LOCK_TRACELOG(); 1.552 + if (gBloatView) { 1.553 + PL_HashTableDestroy(gBloatView); 1.554 + gBloatView = nullptr; 1.555 + } 1.556 + UNLOCK_TRACELOG(); 1.557 +#endif 1.558 +} 1.559 + 1.560 +#ifdef NS_IMPL_REFCNT_LOGGING 1.561 +static bool LogThisType(const char* aTypeName) 1.562 +{ 1.563 + void* he = PL_HashTableLookup(gTypesToLog, aTypeName); 1.564 + return nullptr != he; 1.565 +} 1.566 + 1.567 +static intptr_t GetSerialNumber(void* aPtr, bool aCreate) 1.568 +{ 1.569 + PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr); 1.570 + if (hep && *hep) { 1.571 + return reinterpret_cast<serialNumberRecord*>((*hep)->value)->serialNumber; 1.572 + } 1.573 + else if (aCreate) { 1.574 + serialNumberRecord *record = PR_NEW(serialNumberRecord); 1.575 + record->serialNumber = ++gNextSerialNumber; 1.576 + record->refCount = 0; 1.577 + record->COMPtrCount = 0; 1.578 + PL_HashTableRawAdd(gSerialNumbers, hep, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr, reinterpret_cast<void*>(record)); 1.579 + return gNextSerialNumber; 1.580 + } 1.581 + else { 1.582 + return 0; 1.583 + } 1.584 +} 1.585 + 1.586 +static int32_t* GetRefCount(void* aPtr) 1.587 +{ 1.588 + PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr); 1.589 + if (hep && *hep) { 1.590 + return &((reinterpret_cast<serialNumberRecord*>((*hep)->value))->refCount); 1.591 + } else { 1.592 + return nullptr; 1.593 + } 1.594 +} 1.595 + 1.596 +#if defined(NS_IMPL_REFCNT_LOGGING) && defined(HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR) 1.597 +static int32_t* GetCOMPtrCount(void* aPtr) 1.598 +{ 1.599 + PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr); 1.600 + if (hep && *hep) { 1.601 + return &((reinterpret_cast<serialNumberRecord*>((*hep)->value))->COMPtrCount); 1.602 + } else { 1.603 + return nullptr; 1.604 + } 1.605 +} 1.606 +#endif 1.607 + 1.608 +static void RecycleSerialNumberPtr(void* aPtr) 1.609 +{ 1.610 + PL_HashTableRemove(gSerialNumbers, aPtr); 1.611 +} 1.612 + 1.613 +static bool LogThisObj(intptr_t aSerialNumber) 1.614 +{ 1.615 + return nullptr != PL_HashTableLookup(gObjectsToLog, (const void*)aSerialNumber); 1.616 +} 1.617 + 1.618 +#ifdef XP_WIN 1.619 +#define FOPEN_NO_INHERIT "N" 1.620 +#else 1.621 +#define FOPEN_NO_INHERIT 1.622 +#endif 1.623 + 1.624 +static bool InitLog(const char* envVar, const char* msg, FILE* *result) 1.625 +{ 1.626 + const char* value = getenv(envVar); 1.627 + if (value) { 1.628 + if (nsCRT::strcmp(value, "1") == 0) { 1.629 + *result = stdout; 1.630 + fprintf(stdout, "### %s defined -- logging %s to stdout\n", 1.631 + envVar, msg); 1.632 + return true; 1.633 + } 1.634 + else if (nsCRT::strcmp(value, "2") == 0) { 1.635 + *result = stderr; 1.636 + fprintf(stdout, "### %s defined -- logging %s to stderr\n", 1.637 + envVar, msg); 1.638 + return true; 1.639 + } 1.640 + else { 1.641 + FILE *stream; 1.642 + nsAutoCString fname(value); 1.643 + if (XRE_GetProcessType() != GeckoProcessType_Default) { 1.644 + bool hasLogExtension = 1.645 + fname.RFind(".log", true, -1, 4) == kNotFound ? false : true; 1.646 + if (hasLogExtension) 1.647 + fname.Cut(fname.Length() - 4, 4); 1.648 + fname.AppendLiteral("_"); 1.649 + fname.Append((char*)XRE_ChildProcessTypeToString(XRE_GetProcessType())); 1.650 + fname.AppendLiteral("_pid"); 1.651 + fname.AppendInt((uint32_t)getpid()); 1.652 + if (hasLogExtension) 1.653 + fname.AppendLiteral(".log"); 1.654 + } 1.655 + stream = ::fopen(fname.get(), "w" FOPEN_NO_INHERIT); 1.656 + if (stream != nullptr) { 1.657 + MozillaRegisterDebugFD(fileno(stream)); 1.658 + *result = stream; 1.659 + fprintf(stdout, "### %s defined -- logging %s to %s\n", 1.660 + envVar, msg, fname.get()); 1.661 + } 1.662 + else { 1.663 + fprintf(stdout, "### %s defined -- unable to log %s to %s\n", 1.664 + envVar, msg, fname.get()); 1.665 + } 1.666 + return stream != nullptr; 1.667 + } 1.668 + } 1.669 + return false; 1.670 +} 1.671 + 1.672 + 1.673 +static PLHashNumber HashNumber(const void* aKey) 1.674 +{ 1.675 + return PLHashNumber(NS_PTR_TO_INT32(aKey)); 1.676 +} 1.677 + 1.678 +static void InitTraceLog(void) 1.679 +{ 1.680 + if (gInitialized) return; 1.681 + gInitialized = true; 1.682 + 1.683 + bool defined; 1.684 + defined = InitLog("XPCOM_MEM_BLOAT_LOG", "bloat/leaks", &gBloatLog); 1.685 + if (!defined) 1.686 + gLogLeaksOnly = InitLog("XPCOM_MEM_LEAK_LOG", "leaks", &gBloatLog); 1.687 + if (defined || gLogLeaksOnly) { 1.688 + RecreateBloatView(); 1.689 + if (!gBloatView) { 1.690 + NS_WARNING("out of memory"); 1.691 + gBloatLog = nullptr; 1.692 + gLogLeaksOnly = false; 1.693 + } 1.694 + } 1.695 + 1.696 + (void)InitLog("XPCOM_MEM_REFCNT_LOG", "refcounts", &gRefcntsLog); 1.697 + 1.698 + (void)InitLog("XPCOM_MEM_ALLOC_LOG", "new/delete", &gAllocLog); 1.699 + 1.700 + defined = InitLog("XPCOM_MEM_LEAKY_LOG", "for leaky", &gLeakyLog); 1.701 + if (defined) { 1.702 + gLogToLeaky = true; 1.703 + PRFuncPtr p = nullptr, q = nullptr; 1.704 +#ifdef HAVE_DLOPEN 1.705 + { 1.706 + PRLibrary *lib = nullptr; 1.707 + p = PR_FindFunctionSymbolAndLibrary("__log_addref", &lib); 1.708 + if (lib) { 1.709 + PR_UnloadLibrary(lib); 1.710 + lib = nullptr; 1.711 + } 1.712 + q = PR_FindFunctionSymbolAndLibrary("__log_release", &lib); 1.713 + if (lib) { 1.714 + PR_UnloadLibrary(lib); 1.715 + } 1.716 + } 1.717 +#endif 1.718 + if (p && q) { 1.719 + leakyLogAddRef = (void (*)(void*,int,int)) p; 1.720 + leakyLogRelease = (void (*)(void*,int,int)) q; 1.721 + } 1.722 + else { 1.723 + gLogToLeaky = false; 1.724 + fprintf(stdout, "### ERROR: XPCOM_MEM_LEAKY_LOG defined, but can't locate __log_addref and __log_release symbols\n"); 1.725 + fflush(stdout); 1.726 + } 1.727 + } 1.728 + 1.729 + const char* classes = getenv("XPCOM_MEM_LOG_CLASSES"); 1.730 + 1.731 +#ifdef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR 1.732 + if (classes) { 1.733 + (void)InitLog("XPCOM_MEM_COMPTR_LOG", "nsCOMPtr", &gCOMPtrLog); 1.734 + } else { 1.735 + if (getenv("XPCOM_MEM_COMPTR_LOG")) { 1.736 + fprintf(stdout, "### XPCOM_MEM_COMPTR_LOG defined -- but XPCOM_MEM_LOG_CLASSES is not defined\n"); 1.737 + } 1.738 + } 1.739 +#else 1.740 + const char* comptr_log = getenv("XPCOM_MEM_COMPTR_LOG"); 1.741 + if (comptr_log) { 1.742 + fprintf(stdout, "### XPCOM_MEM_COMPTR_LOG defined -- but it will not work without dynamic_cast\n"); 1.743 + } 1.744 +#endif 1.745 + 1.746 + if (classes) { 1.747 + // if XPCOM_MEM_LOG_CLASSES was set to some value, the value is interpreted 1.748 + // as a list of class names to track 1.749 + gTypesToLog = PL_NewHashTable(256, 1.750 + PL_HashString, 1.751 + PL_CompareStrings, 1.752 + PL_CompareValues, 1.753 + &typesToLogHashAllocOps, nullptr); 1.754 + if (!gTypesToLog) { 1.755 + NS_WARNING("out of memory"); 1.756 + fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- unable to log specific classes\n"); 1.757 + } 1.758 + else { 1.759 + fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- only logging these classes: "); 1.760 + const char* cp = classes; 1.761 + for (;;) { 1.762 + char* cm = (char*) strchr(cp, ','); 1.763 + if (cm) { 1.764 + *cm = '\0'; 1.765 + } 1.766 + PL_HashTableAdd(gTypesToLog, strdup(cp), (void*)1); 1.767 + fprintf(stdout, "%s ", cp); 1.768 + if (!cm) break; 1.769 + *cm = ','; 1.770 + cp = cm + 1; 1.771 + } 1.772 + fprintf(stdout, "\n"); 1.773 + } 1.774 + 1.775 + gSerialNumbers = PL_NewHashTable(256, 1.776 + HashNumber, 1.777 + PL_CompareValues, 1.778 + PL_CompareValues, 1.779 + &serialNumberHashAllocOps, nullptr); 1.780 + 1.781 + 1.782 + } 1.783 + 1.784 + const char* objects = getenv("XPCOM_MEM_LOG_OBJECTS"); 1.785 + if (objects) { 1.786 + gObjectsToLog = PL_NewHashTable(256, 1.787 + HashNumber, 1.788 + PL_CompareValues, 1.789 + PL_CompareValues, 1.790 + nullptr, nullptr); 1.791 + 1.792 + if (!gObjectsToLog) { 1.793 + NS_WARNING("out of memory"); 1.794 + fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- unable to log specific objects\n"); 1.795 + } 1.796 + else if (! (gRefcntsLog || gAllocLog || gCOMPtrLog)) { 1.797 + fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- but none of XPCOM_MEM_(REFCNT|ALLOC|COMPTR)_LOG is defined\n"); 1.798 + } 1.799 + else { 1.800 + fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- only logging these objects: "); 1.801 + const char* cp = objects; 1.802 + for (;;) { 1.803 + char* cm = (char*) strchr(cp, ','); 1.804 + if (cm) { 1.805 + *cm = '\0'; 1.806 + } 1.807 + intptr_t top = 0; 1.808 + intptr_t bottom = 0; 1.809 + while (*cp) { 1.810 + if (*cp == '-') { 1.811 + bottom = top; 1.812 + top = 0; 1.813 + ++cp; 1.814 + } 1.815 + top *= 10; 1.816 + top += *cp - '0'; 1.817 + ++cp; 1.818 + } 1.819 + if (!bottom) { 1.820 + bottom = top; 1.821 + } 1.822 + for (intptr_t serialno = bottom; serialno <= top; serialno++) { 1.823 + PL_HashTableAdd(gObjectsToLog, (const void*)serialno, (void*)1); 1.824 + fprintf(stdout, "%" PRIdPTR " ", serialno); 1.825 + } 1.826 + if (!cm) break; 1.827 + *cm = ','; 1.828 + cp = cm + 1; 1.829 + } 1.830 + fprintf(stdout, "\n"); 1.831 + } 1.832 + } 1.833 + 1.834 + 1.835 + if (gBloatLog || gRefcntsLog || gAllocLog || gLeakyLog || gCOMPtrLog) { 1.836 + gLogging = true; 1.837 + } 1.838 + 1.839 + gTraceLock = PR_NewLock(); 1.840 +} 1.841 + 1.842 +#endif 1.843 + 1.844 +extern "C" { 1.845 + 1.846 +#ifdef STACKWALKING_AVAILABLE 1.847 +static void PrintStackFrame(void *aPC, void *aSP, void *aClosure) 1.848 +{ 1.849 + FILE *stream = (FILE*)aClosure; 1.850 + nsCodeAddressDetails details; 1.851 + char buf[1024]; 1.852 + 1.853 + NS_DescribeCodeAddress(aPC, &details); 1.854 + NS_FormatCodeAddressDetails(aPC, &details, buf, sizeof(buf)); 1.855 + fputs(buf, stream); 1.856 +} 1.857 +#endif 1.858 + 1.859 +} 1.860 + 1.861 +void 1.862 +nsTraceRefcnt::WalkTheStack(FILE* aStream) 1.863 +{ 1.864 +#ifdef STACKWALKING_AVAILABLE 1.865 + NS_StackWalk(PrintStackFrame, /* skipFrames */ 2, /* maxFrames */ 0, aStream, 1.866 + 0, nullptr); 1.867 +#endif 1.868 +} 1.869 + 1.870 +//---------------------------------------------------------------------- 1.871 + 1.872 +// This thing is exported by libstdc++ 1.873 +// Yes, this is a gcc only hack 1.874 +#if defined(MOZ_DEMANGLE_SYMBOLS) 1.875 +#include <cxxabi.h> 1.876 +#include <stdlib.h> // for free() 1.877 +#endif // MOZ_DEMANGLE_SYMBOLS 1.878 + 1.879 +void 1.880 +nsTraceRefcnt::DemangleSymbol(const char * aSymbol, 1.881 + char * aBuffer, 1.882 + int aBufLen) 1.883 +{ 1.884 + NS_ASSERTION(nullptr != aSymbol,"null symbol"); 1.885 + NS_ASSERTION(nullptr != aBuffer,"null buffer"); 1.886 + NS_ASSERTION(aBufLen >= 32 ,"pulled 32 out of you know where"); 1.887 + 1.888 + aBuffer[0] = '\0'; 1.889 + 1.890 +#if defined(MOZ_DEMANGLE_SYMBOLS) 1.891 + /* See demangle.h in the gcc source for the voodoo */ 1.892 + char * demangled = abi::__cxa_demangle(aSymbol,0,0,0); 1.893 + 1.894 + if (demangled) 1.895 + { 1.896 + strncpy(aBuffer,demangled,aBufLen); 1.897 + free(demangled); 1.898 + } 1.899 +#endif // MOZ_DEMANGLE_SYMBOLS 1.900 +} 1.901 + 1.902 + 1.903 +//---------------------------------------------------------------------- 1.904 + 1.905 +EXPORT_XPCOM_API(void) 1.906 +NS_LogInit() 1.907 +{ 1.908 + // FIXME: This is called multiple times, we should probably not allow that. 1.909 +#ifdef STACKWALKING_AVAILABLE 1.910 + StackWalkInitCriticalAddress(); 1.911 +#endif 1.912 +#ifdef NS_IMPL_REFCNT_LOGGING 1.913 + if (++gInitCount) 1.914 + nsTraceRefcnt::SetActivityIsLegal(true); 1.915 +#endif 1.916 + 1.917 +#ifdef NS_TRACE_MALLOC 1.918 + // XXX we don't have to worry about shutting down trace-malloc; it 1.919 + // handles this itself, through an atexit() callback. 1.920 + if (!NS_TraceMallocHasStarted()) 1.921 + NS_TraceMallocStartup(-1); // -1 == no logging 1.922 +#endif 1.923 +} 1.924 + 1.925 +EXPORT_XPCOM_API(void) 1.926 +NS_LogTerm() 1.927 +{ 1.928 + mozilla::LogTerm(); 1.929 +} 1.930 + 1.931 +namespace mozilla { 1.932 +void 1.933 +LogTerm() 1.934 +{ 1.935 + NS_ASSERTION(gInitCount > 0, 1.936 + "NS_LogTerm without matching NS_LogInit"); 1.937 + 1.938 + if (--gInitCount == 0) { 1.939 +#ifdef DEBUG 1.940 + /* FIXME bug 491977: This is only going to operate on the 1.941 + * BlockingResourceBase which is compiled into 1.942 + * libxul/libxpcom_core.so. Anyone using external linkage will 1.943 + * have their own copy of BlockingResourceBase statics which will 1.944 + * not be freed by this method. 1.945 + * 1.946 + * It sounds like what we really want is to be able to register a 1.947 + * callback function to call at XPCOM shutdown. Note that with 1.948 + * this solution, however, we need to guarantee that 1.949 + * BlockingResourceBase::Shutdown() runs after all other shutdown 1.950 + * functions. 1.951 + */ 1.952 + BlockingResourceBase::Shutdown(); 1.953 +#endif 1.954 + 1.955 + if (gInitialized) { 1.956 + nsTraceRefcnt::DumpStatistics(); 1.957 + nsTraceRefcnt::ResetStatistics(); 1.958 + } 1.959 + nsTraceRefcnt::Shutdown(); 1.960 +#ifdef NS_IMPL_REFCNT_LOGGING 1.961 + nsTraceRefcnt::SetActivityIsLegal(false); 1.962 + gActivityTLS = BAD_TLS_INDEX; 1.963 +#endif 1.964 + } 1.965 +} 1.966 + 1.967 +} // namespace mozilla 1.968 + 1.969 +EXPORT_XPCOM_API(void) 1.970 +NS_LogAddRef(void* aPtr, nsrefcnt aRefcnt, 1.971 + const char* aClazz, uint32_t classSize) 1.972 +{ 1.973 +#ifdef NS_IMPL_REFCNT_LOGGING 1.974 + ASSERT_ACTIVITY_IS_LEGAL; 1.975 + if (!gInitialized) 1.976 + InitTraceLog(); 1.977 + if (gLogging) { 1.978 + LOCK_TRACELOG(); 1.979 + 1.980 + if (gBloatLog) { 1.981 + BloatEntry* entry = GetBloatEntry(aClazz, classSize); 1.982 + if (entry) { 1.983 + entry->AddRef(aRefcnt); 1.984 + } 1.985 + } 1.986 + 1.987 + // Here's the case where MOZ_COUNT_CTOR was not used, 1.988 + // yet we still want to see creation information: 1.989 + 1.990 + bool loggingThisType = (!gTypesToLog || LogThisType(aClazz)); 1.991 + intptr_t serialno = 0; 1.992 + if (gSerialNumbers && loggingThisType) { 1.993 + serialno = GetSerialNumber(aPtr, aRefcnt == 1); 1.994 + NS_ASSERTION(serialno != 0, 1.995 + "Serial number requested for unrecognized pointer! " 1.996 + "Are you memmoving a refcounted object?"); 1.997 + int32_t* count = GetRefCount(aPtr); 1.998 + if(count) 1.999 + (*count)++; 1.1000 + 1.1001 + } 1.1002 + 1.1003 + bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno)); 1.1004 + if (aRefcnt == 1 && gAllocLog && loggingThisType && loggingThisObject) { 1.1005 + fprintf(gAllocLog, "\n<%s> 0x%08X %" PRIdPTR " Create\n", 1.1006 + aClazz, NS_PTR_TO_INT32(aPtr), serialno); 1.1007 + nsTraceRefcnt::WalkTheStack(gAllocLog); 1.1008 + } 1.1009 + 1.1010 + if (gRefcntsLog && loggingThisType && loggingThisObject) { 1.1011 + if (gLogToLeaky) { 1.1012 + (*leakyLogAddRef)(aPtr, aRefcnt - 1, aRefcnt); 1.1013 + } 1.1014 + else { 1.1015 + // Can't use PR_LOG(), b/c it truncates the line 1.1016 + fprintf(gRefcntsLog, 1.1017 + "\n<%s> 0x%08X %" PRIuPTR " AddRef %" PRIuPTR "\n", aClazz, NS_PTR_TO_INT32(aPtr), serialno, aRefcnt); 1.1018 + nsTraceRefcnt::WalkTheStack(gRefcntsLog); 1.1019 + fflush(gRefcntsLog); 1.1020 + } 1.1021 + } 1.1022 + UNLOCK_TRACELOG(); 1.1023 + } 1.1024 +#endif 1.1025 +} 1.1026 + 1.1027 +EXPORT_XPCOM_API(void) 1.1028 +NS_LogRelease(void* aPtr, nsrefcnt aRefcnt, const char* aClazz) 1.1029 +{ 1.1030 +#ifdef NS_IMPL_REFCNT_LOGGING 1.1031 + ASSERT_ACTIVITY_IS_LEGAL; 1.1032 + if (!gInitialized) 1.1033 + InitTraceLog(); 1.1034 + if (gLogging) { 1.1035 + LOCK_TRACELOG(); 1.1036 + 1.1037 + if (gBloatLog) { 1.1038 + BloatEntry* entry = GetBloatEntry(aClazz, 0); 1.1039 + if (entry) { 1.1040 + entry->Release(aRefcnt); 1.1041 + } 1.1042 + } 1.1043 + 1.1044 + bool loggingThisType = (!gTypesToLog || LogThisType(aClazz)); 1.1045 + intptr_t serialno = 0; 1.1046 + if (gSerialNumbers && loggingThisType) { 1.1047 + serialno = GetSerialNumber(aPtr, false); 1.1048 + NS_ASSERTION(serialno != 0, 1.1049 + "Serial number requested for unrecognized pointer! " 1.1050 + "Are you memmoving a refcounted object?"); 1.1051 + int32_t* count = GetRefCount(aPtr); 1.1052 + if(count) 1.1053 + (*count)--; 1.1054 + 1.1055 + } 1.1056 + 1.1057 + bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno)); 1.1058 + if (gRefcntsLog && loggingThisType && loggingThisObject) { 1.1059 + if (gLogToLeaky) { 1.1060 + (*leakyLogRelease)(aPtr, aRefcnt + 1, aRefcnt); 1.1061 + } 1.1062 + else { 1.1063 + // Can't use PR_LOG(), b/c it truncates the line 1.1064 + fprintf(gRefcntsLog, 1.1065 + "\n<%s> 0x%08X %" PRIuPTR " Release %" PRIuPTR "\n", aClazz, NS_PTR_TO_INT32(aPtr), serialno, aRefcnt); 1.1066 + nsTraceRefcnt::WalkTheStack(gRefcntsLog); 1.1067 + fflush(gRefcntsLog); 1.1068 + } 1.1069 + } 1.1070 + 1.1071 + // Here's the case where MOZ_COUNT_DTOR was not used, 1.1072 + // yet we still want to see deletion information: 1.1073 + 1.1074 + if (aRefcnt == 0 && gAllocLog && loggingThisType && loggingThisObject) { 1.1075 + fprintf(gAllocLog, 1.1076 + "\n<%s> 0x%08X %" PRIdPTR " Destroy\n", 1.1077 + aClazz, NS_PTR_TO_INT32(aPtr), serialno); 1.1078 + nsTraceRefcnt::WalkTheStack(gAllocLog); 1.1079 + } 1.1080 + 1.1081 + if (aRefcnt == 0 && gSerialNumbers && loggingThisType) { 1.1082 + RecycleSerialNumberPtr(aPtr); 1.1083 + } 1.1084 + 1.1085 + UNLOCK_TRACELOG(); 1.1086 + } 1.1087 +#endif 1.1088 +} 1.1089 + 1.1090 +EXPORT_XPCOM_API(void) 1.1091 +NS_LogCtor(void* aPtr, const char* aType, uint32_t aInstanceSize) 1.1092 +{ 1.1093 +#ifdef NS_IMPL_REFCNT_LOGGING 1.1094 + ASSERT_ACTIVITY_IS_LEGAL; 1.1095 + if (!gInitialized) 1.1096 + InitTraceLog(); 1.1097 + 1.1098 + if (gLogging) { 1.1099 + LOCK_TRACELOG(); 1.1100 + 1.1101 + if (gBloatLog) { 1.1102 + BloatEntry* entry = GetBloatEntry(aType, aInstanceSize); 1.1103 + if (entry) { 1.1104 + entry->Ctor(); 1.1105 + } 1.1106 + } 1.1107 + 1.1108 + bool loggingThisType = (!gTypesToLog || LogThisType(aType)); 1.1109 + intptr_t serialno = 0; 1.1110 + if (gSerialNumbers && loggingThisType) { 1.1111 + serialno = GetSerialNumber(aPtr, true); 1.1112 + } 1.1113 + 1.1114 + bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno)); 1.1115 + if (gAllocLog && loggingThisType && loggingThisObject) { 1.1116 + fprintf(gAllocLog, "\n<%s> 0x%08X %" PRIdPTR " Ctor (%d)\n", 1.1117 + aType, NS_PTR_TO_INT32(aPtr), serialno, aInstanceSize); 1.1118 + nsTraceRefcnt::WalkTheStack(gAllocLog); 1.1119 + } 1.1120 + 1.1121 + UNLOCK_TRACELOG(); 1.1122 + } 1.1123 +#endif 1.1124 +} 1.1125 + 1.1126 + 1.1127 +EXPORT_XPCOM_API(void) 1.1128 +NS_LogDtor(void* aPtr, const char* aType, uint32_t aInstanceSize) 1.1129 +{ 1.1130 +#ifdef NS_IMPL_REFCNT_LOGGING 1.1131 + ASSERT_ACTIVITY_IS_LEGAL; 1.1132 + if (!gInitialized) 1.1133 + InitTraceLog(); 1.1134 + 1.1135 + if (gLogging) { 1.1136 + LOCK_TRACELOG(); 1.1137 + 1.1138 + if (gBloatLog) { 1.1139 + BloatEntry* entry = GetBloatEntry(aType, aInstanceSize); 1.1140 + if (entry) { 1.1141 + entry->Dtor(); 1.1142 + } 1.1143 + } 1.1144 + 1.1145 + bool loggingThisType = (!gTypesToLog || LogThisType(aType)); 1.1146 + intptr_t serialno = 0; 1.1147 + if (gSerialNumbers && loggingThisType) { 1.1148 + serialno = GetSerialNumber(aPtr, false); 1.1149 + RecycleSerialNumberPtr(aPtr); 1.1150 + } 1.1151 + 1.1152 + bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno)); 1.1153 + 1.1154 + // (If we're on a losing architecture, don't do this because we'll be 1.1155 + // using LogDeleteXPCOM instead to get file and line numbers.) 1.1156 + if (gAllocLog && loggingThisType && loggingThisObject) { 1.1157 + fprintf(gAllocLog, "\n<%s> 0x%08X %" PRIdPTR " Dtor (%d)\n", 1.1158 + aType, NS_PTR_TO_INT32(aPtr), serialno, aInstanceSize); 1.1159 + nsTraceRefcnt::WalkTheStack(gAllocLog); 1.1160 + } 1.1161 + 1.1162 + UNLOCK_TRACELOG(); 1.1163 + } 1.1164 +#endif 1.1165 +} 1.1166 + 1.1167 + 1.1168 +EXPORT_XPCOM_API(void) 1.1169 +NS_LogCOMPtrAddRef(void* aCOMPtr, nsISupports* aObject) 1.1170 +{ 1.1171 +#if defined(NS_IMPL_REFCNT_LOGGING) && defined(HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR) 1.1172 + // Get the most-derived object. 1.1173 + void *object = dynamic_cast<void *>(aObject); 1.1174 + 1.1175 + // This is a very indirect way of finding out what the class is 1.1176 + // of the object being logged. If we're logging a specific type, 1.1177 + // then 1.1178 + if (!gTypesToLog || !gSerialNumbers) { 1.1179 + return; 1.1180 + } 1.1181 + intptr_t serialno = GetSerialNumber(object, false); 1.1182 + if (serialno == 0) { 1.1183 + return; 1.1184 + } 1.1185 + 1.1186 + if (!gInitialized) 1.1187 + InitTraceLog(); 1.1188 + if (gLogging) { 1.1189 + LOCK_TRACELOG(); 1.1190 + 1.1191 + int32_t* count = GetCOMPtrCount(object); 1.1192 + if(count) 1.1193 + (*count)++; 1.1194 + 1.1195 + bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno)); 1.1196 + 1.1197 + if (gCOMPtrLog && loggingThisObject) { 1.1198 + fprintf(gCOMPtrLog, "\n<?> 0x%08X %" PRIdPTR " nsCOMPtrAddRef %d 0x%08X\n", 1.1199 + NS_PTR_TO_INT32(object), serialno, count?(*count):-1, NS_PTR_TO_INT32(aCOMPtr)); 1.1200 + nsTraceRefcnt::WalkTheStack(gCOMPtrLog); 1.1201 + } 1.1202 + 1.1203 + UNLOCK_TRACELOG(); 1.1204 + } 1.1205 +#endif 1.1206 +} 1.1207 + 1.1208 + 1.1209 +EXPORT_XPCOM_API(void) 1.1210 +NS_LogCOMPtrRelease(void* aCOMPtr, nsISupports* aObject) 1.1211 +{ 1.1212 +#if defined(NS_IMPL_REFCNT_LOGGING) && defined(HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR) 1.1213 + // Get the most-derived object. 1.1214 + void *object = dynamic_cast<void *>(aObject); 1.1215 + 1.1216 + // This is a very indirect way of finding out what the class is 1.1217 + // of the object being logged. If we're logging a specific type, 1.1218 + // then 1.1219 + if (!gTypesToLog || !gSerialNumbers) { 1.1220 + return; 1.1221 + } 1.1222 + intptr_t serialno = GetSerialNumber(object, false); 1.1223 + if (serialno == 0) { 1.1224 + return; 1.1225 + } 1.1226 + 1.1227 + if (!gInitialized) 1.1228 + InitTraceLog(); 1.1229 + if (gLogging) { 1.1230 + LOCK_TRACELOG(); 1.1231 + 1.1232 + int32_t* count = GetCOMPtrCount(object); 1.1233 + if(count) 1.1234 + (*count)--; 1.1235 + 1.1236 + bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno)); 1.1237 + 1.1238 + if (gCOMPtrLog && loggingThisObject) { 1.1239 + fprintf(gCOMPtrLog, "\n<?> 0x%08X %" PRIdPTR " nsCOMPtrRelease %d 0x%08X\n", 1.1240 + NS_PTR_TO_INT32(object), serialno, count?(*count):-1, NS_PTR_TO_INT32(aCOMPtr)); 1.1241 + nsTraceRefcnt::WalkTheStack(gCOMPtrLog); 1.1242 + } 1.1243 + 1.1244 + UNLOCK_TRACELOG(); 1.1245 + } 1.1246 +#endif 1.1247 +} 1.1248 + 1.1249 +void 1.1250 +nsTraceRefcnt::Startup() 1.1251 +{ 1.1252 +} 1.1253 + 1.1254 +static void maybeUnregisterAndCloseFile(FILE *&f) { 1.1255 + if (!f) 1.1256 + return; 1.1257 + 1.1258 + MozillaUnRegisterDebugFILE(f); 1.1259 + fclose(f); 1.1260 + f = nullptr; 1.1261 +} 1.1262 + 1.1263 +void 1.1264 +nsTraceRefcnt::Shutdown() 1.1265 +{ 1.1266 +#ifdef NS_IMPL_REFCNT_LOGGING 1.1267 + 1.1268 + if (gBloatView) { 1.1269 + PL_HashTableDestroy(gBloatView); 1.1270 + gBloatView = nullptr; 1.1271 + } 1.1272 + if (gTypesToLog) { 1.1273 + PL_HashTableDestroy(gTypesToLog); 1.1274 + gTypesToLog = nullptr; 1.1275 + } 1.1276 + if (gObjectsToLog) { 1.1277 + PL_HashTableDestroy(gObjectsToLog); 1.1278 + gObjectsToLog = nullptr; 1.1279 + } 1.1280 + if (gSerialNumbers) { 1.1281 + PL_HashTableDestroy(gSerialNumbers); 1.1282 + gSerialNumbers = nullptr; 1.1283 + } 1.1284 + maybeUnregisterAndCloseFile(gBloatLog); 1.1285 + maybeUnregisterAndCloseFile(gRefcntsLog); 1.1286 + maybeUnregisterAndCloseFile(gAllocLog); 1.1287 + maybeUnregisterAndCloseFile(gLeakyLog); 1.1288 + maybeUnregisterAndCloseFile(gCOMPtrLog); 1.1289 +#endif 1.1290 +} 1.1291 + 1.1292 +void 1.1293 +nsTraceRefcnt::SetActivityIsLegal(bool aLegal) 1.1294 +{ 1.1295 +#ifdef NS_IMPL_REFCNT_LOGGING 1.1296 + if (gActivityTLS == BAD_TLS_INDEX) 1.1297 + PR_NewThreadPrivateIndex(&gActivityTLS, nullptr); 1.1298 + 1.1299 + PR_SetThreadPrivate(gActivityTLS, NS_INT32_TO_PTR(!aLegal)); 1.1300 +#endif 1.1301 +}