xpcom/base/nsTraceRefcnt.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "nsTraceRefcnt.h"
     7 #include "mozilla/IntegerPrintfMacros.h"
     8 #include "nsXPCOMPrivate.h"
     9 #include "nscore.h"
    10 #include "nsISupports.h"
    11 #include "nsTArray.h"
    12 #include "prenv.h"
    13 #include "plstr.h"
    14 #include "prlink.h"
    15 #include "nsCRT.h"
    16 #include <math.h>
    17 #include "nsStackWalkPrivate.h"
    18 #include "nsStackWalk.h"
    19 #include "nsString.h"
    21 #include "nsXULAppAPI.h"
    22 #ifdef XP_WIN
    23 #include <process.h>
    24 #define getpid _getpid
    25 #else
    26 #include <unistd.h>
    27 #endif
    29 #ifdef NS_TRACE_MALLOC
    30 #include "nsTraceMalloc.h"
    31 #endif
    33 #include "mozilla/BlockingResourceBase.h"
    34 #include "mozilla/PoisonIOInterposer.h"
    36 #ifdef HAVE_DLOPEN
    37 #include <dlfcn.h>
    38 #endif
    40 ////////////////////////////////////////////////////////////////////////////////
    42 void
    43 NS_MeanAndStdDev(double n, double sumOfValues, double sumOfSquaredValues,
    44                  double *meanResult, double *stdDevResult)
    45 {
    46   double mean = 0.0, var = 0.0, stdDev = 0.0;
    47   if (n > 0.0 && sumOfValues >= 0) {
    48     mean = sumOfValues / n;
    49     double temp = (n * sumOfSquaredValues) - (sumOfValues * sumOfValues);
    50     if (temp < 0.0 || n <= 1)
    51       var = 0.0;
    52     else
    53       var = temp / (n * (n - 1));
    54     // for some reason, Windows says sqrt(0.0) is "-1.#J" (?!) so do this:
    55     stdDev = var != 0.0 ? sqrt(var) : 0.0;
    56   }
    57   *meanResult = mean;
    58   *stdDevResult = stdDev;
    59 }
    61 ////////////////////////////////////////////////////////////////////////////////
    63 #if !defined(XP_WIN) || (!defined(MOZ_OPTIMIZE) || defined(MOZ_PROFILING) || defined(DEBUG))
    64 #define STACKWALKING_AVAILABLE
    65 #endif
    67 #define NS_IMPL_REFCNT_LOGGING
    69 #ifdef NS_IMPL_REFCNT_LOGGING
    70 #include "plhash.h"
    71 #include "prmem.h"
    73 #include "prlock.h"
    75 // TraceRefcnt has to use bare PRLock instead of mozilla::Mutex
    76 // because TraceRefcnt can be used very early in startup.
    77 static PRLock* gTraceLock;
    79 #define LOCK_TRACELOG()   PR_Lock(gTraceLock)
    80 #define UNLOCK_TRACELOG() PR_Unlock(gTraceLock)
    82 static PLHashTable* gBloatView;
    83 static PLHashTable* gTypesToLog;
    84 static PLHashTable* gObjectsToLog;
    85 static PLHashTable* gSerialNumbers;
    86 static intptr_t gNextSerialNumber;
    88 static bool gLogging;
    89 static bool gLogToLeaky;
    90 static bool gLogLeaksOnly;
    92 static void (*leakyLogAddRef)(void* p, int oldrc, int newrc);
    93 static void (*leakyLogRelease)(void* p, int oldrc, int newrc);
    95 #define BAD_TLS_INDEX ((unsigned) -1)
    97 // if gActivityTLS == BAD_TLS_INDEX, then we're
    98 // unitialized... otherwise this points to a NSPR TLS thread index
    99 // indicating whether addref activity is legal. If the PTR_TO_INT32 is 0 then
   100 // activity is ok, otherwise not!
   101 static unsigned gActivityTLS = BAD_TLS_INDEX;
   103 static bool gInitialized;
   104 static nsrefcnt gInitCount;
   106 static FILE *gBloatLog = nullptr;
   107 static FILE *gRefcntsLog = nullptr;
   108 static FILE *gAllocLog = nullptr;
   109 static FILE *gLeakyLog = nullptr;
   110 static FILE *gCOMPtrLog = nullptr;
   112 struct serialNumberRecord {
   113   intptr_t serialNumber;
   114   int32_t refCount;
   115   int32_t COMPtrCount;
   116 };
   118 struct nsTraceRefcntStats {
   119   uint64_t mAddRefs;
   120   uint64_t mReleases;
   121   uint64_t mCreates;
   122   uint64_t mDestroys;
   123   double mRefsOutstandingTotal;
   124   double mRefsOutstandingSquared;
   125   double mObjsOutstandingTotal;
   126   double mObjsOutstandingSquared;
   127 };
   129   // I hope to turn this on for everybody once we hit it a little less.
   130 #ifdef DEBUG
   131 static const char kStaticCtorDtorWarning[] =
   132   "XPCOM objects created/destroyed from static ctor/dtor";
   134 static void
   135 AssertActivityIsLegal()
   136 {
   137   if (gActivityTLS == BAD_TLS_INDEX ||
   138       NS_PTR_TO_INT32(PR_GetThreadPrivate(gActivityTLS)) != 0) {
   139     if (PR_GetEnv("MOZ_FATAL_STATIC_XPCOM_CTORS_DTORS")) {
   140       NS_RUNTIMEABORT(kStaticCtorDtorWarning);
   141     } else {
   142       NS_WARNING(kStaticCtorDtorWarning);
   143     }
   144   }
   145 }
   146 #  define ASSERT_ACTIVITY_IS_LEGAL              \
   147   PR_BEGIN_MACRO                                \
   148     AssertActivityIsLegal();                    \
   149   PR_END_MACRO
   150 #else
   151 #  define ASSERT_ACTIVITY_IS_LEGAL PR_BEGIN_MACRO PR_END_MACRO
   152 #endif  // DEBUG
   154 // These functions are copied from nsprpub/lib/ds/plhash.c, with changes
   155 // to the functions not called Default* to free the serialNumberRecord or
   156 // the BloatEntry.
   158 static void *
   159 DefaultAllocTable(void *pool, size_t size)
   160 {
   161     return PR_MALLOC(size);
   162 }
   164 static void
   165 DefaultFreeTable(void *pool, void *item)
   166 {
   167     PR_Free(item);
   168 }
   170 static PLHashEntry *
   171 DefaultAllocEntry(void *pool, const void *key)
   172 {
   173     return PR_NEW(PLHashEntry);
   174 }
   176 static void
   177 SerialNumberFreeEntry(void *pool, PLHashEntry *he, unsigned flag)
   178 {
   179     if (flag == HT_FREE_ENTRY) {
   180         PR_Free(reinterpret_cast<serialNumberRecord*>(he->value));
   181         PR_Free(he);
   182     }
   183 }
   185 static void
   186 TypesToLogFreeEntry(void *pool, PLHashEntry *he, unsigned flag)
   187 {
   188     if (flag == HT_FREE_ENTRY) {
   189         free(const_cast<char*>(reinterpret_cast<const char*>(he->key)));
   190         PR_Free(he);
   191     }
   192 }
   194 static const PLHashAllocOps serialNumberHashAllocOps = {
   195     DefaultAllocTable, DefaultFreeTable,
   196     DefaultAllocEntry, SerialNumberFreeEntry
   197 };
   199 static const PLHashAllocOps typesToLogHashAllocOps = {
   200     DefaultAllocTable, DefaultFreeTable,
   201     DefaultAllocEntry, TypesToLogFreeEntry
   202 };
   204 ////////////////////////////////////////////////////////////////////////////////
   206 class BloatEntry {
   207 public:
   208   BloatEntry(const char* className, uint32_t classSize)
   209     : mClassSize(classSize) {
   210     mClassName = PL_strdup(className);
   211     Clear(&mNewStats);
   212     Clear(&mAllStats);
   213     mTotalLeaked = 0;
   214   }
   216   ~BloatEntry() {
   217     PL_strfree(mClassName);
   218   }
   220   uint32_t GetClassSize() { return (uint32_t)mClassSize; }
   221   const char* GetClassName() { return mClassName; }
   223   static void Clear(nsTraceRefcntStats* stats) {
   224     stats->mAddRefs = 0;
   225     stats->mReleases = 0;
   226     stats->mCreates = 0;
   227     stats->mDestroys = 0;
   228     stats->mRefsOutstandingTotal = 0;
   229     stats->mRefsOutstandingSquared = 0;
   230     stats->mObjsOutstandingTotal = 0;
   231     stats->mObjsOutstandingSquared = 0;
   232   }
   234   void Accumulate() {
   235       mAllStats.mAddRefs += mNewStats.mAddRefs;
   236       mAllStats.mReleases += mNewStats.mReleases;
   237       mAllStats.mCreates += mNewStats.mCreates;
   238       mAllStats.mDestroys += mNewStats.mDestroys;
   239       mAllStats.mRefsOutstandingTotal += mNewStats.mRefsOutstandingTotal;
   240       mAllStats.mRefsOutstandingSquared += mNewStats.mRefsOutstandingSquared;
   241       mAllStats.mObjsOutstandingTotal += mNewStats.mObjsOutstandingTotal;
   242       mAllStats.mObjsOutstandingSquared += mNewStats.mObjsOutstandingSquared;
   243       Clear(&mNewStats);
   244   }
   246   void AddRef(nsrefcnt refcnt) {
   247     mNewStats.mAddRefs++;
   248     if (refcnt == 1) {
   249       Ctor();
   250     }
   251     AccountRefs();
   252   }
   254   void Release(nsrefcnt refcnt) {
   255     mNewStats.mReleases++;
   256     if (refcnt == 0) {
   257       Dtor();
   258     }
   259     AccountRefs();
   260   }
   262   void Ctor() {
   263     mNewStats.mCreates++;
   264     AccountObjs();
   265   }
   267   void Dtor() {
   268     mNewStats.mDestroys++;
   269     AccountObjs();
   270   }
   272   void AccountRefs() {
   273     uint64_t cnt = (mNewStats.mAddRefs - mNewStats.mReleases);
   274     mNewStats.mRefsOutstandingTotal += cnt;
   275     mNewStats.mRefsOutstandingSquared += cnt * cnt;
   276   }
   278   void AccountObjs() {
   279     uint64_t cnt = (mNewStats.mCreates - mNewStats.mDestroys);
   280     mNewStats.mObjsOutstandingTotal += cnt;
   281     mNewStats.mObjsOutstandingSquared += cnt * cnt;
   282   }
   284   static int DumpEntry(PLHashEntry *he, int i, void *arg) {
   285     BloatEntry* entry = (BloatEntry*)he->value;
   286     if (entry) {
   287       entry->Accumulate();
   288       static_cast<nsTArray<BloatEntry*>*>(arg)->AppendElement(entry);
   289     }
   290     return HT_ENUMERATE_NEXT;
   291   }
   293   static int TotalEntries(PLHashEntry *he, int i, void *arg) {
   294     BloatEntry* entry = (BloatEntry*)he->value;
   295     if (entry && nsCRT::strcmp(entry->mClassName, "TOTAL") != 0) {
   296       entry->Total((BloatEntry*)arg);
   297     }
   298     return HT_ENUMERATE_NEXT;
   299   }
   301   void Total(BloatEntry* total) {
   302     total->mAllStats.mAddRefs += mNewStats.mAddRefs + mAllStats.mAddRefs;
   303     total->mAllStats.mReleases += mNewStats.mReleases + mAllStats.mReleases;
   304     total->mAllStats.mCreates += mNewStats.mCreates + mAllStats.mCreates;
   305     total->mAllStats.mDestroys += mNewStats.mDestroys + mAllStats.mDestroys;
   306     total->mAllStats.mRefsOutstandingTotal += mNewStats.mRefsOutstandingTotal + mAllStats.mRefsOutstandingTotal;
   307     total->mAllStats.mRefsOutstandingSquared += mNewStats.mRefsOutstandingSquared + mAllStats.mRefsOutstandingSquared;
   308     total->mAllStats.mObjsOutstandingTotal += mNewStats.mObjsOutstandingTotal + mAllStats.mObjsOutstandingTotal;
   309     total->mAllStats.mObjsOutstandingSquared += mNewStats.mObjsOutstandingSquared + mAllStats.mObjsOutstandingSquared;
   310     uint64_t count = (mNewStats.mCreates + mAllStats.mCreates);
   311     total->mClassSize += mClassSize * count;    // adjust for average in DumpTotal
   312     total->mTotalLeaked += (uint64_t)(mClassSize *
   313                                      ((mNewStats.mCreates + mAllStats.mCreates)
   314                                       -(mNewStats.mDestroys + mAllStats.mDestroys)));
   315   }
   317   void DumpTotal(FILE* out) {
   318     mClassSize /= mAllStats.mCreates;
   319     Dump(-1, out, nsTraceRefcnt::ALL_STATS);
   320   }
   322   static bool HaveLeaks(nsTraceRefcntStats* stats) {
   323     return ((stats->mAddRefs != stats->mReleases) ||
   324             (stats->mCreates != stats->mDestroys));
   325   }
   327   bool PrintDumpHeader(FILE* out, const char* msg, nsTraceRefcnt::StatisticsType type) {
   328     fprintf(out, "\n== BloatView: %s, %s process %d\n", msg,
   329             XRE_ChildProcessTypeToString(XRE_GetProcessType()), getpid());
   330     nsTraceRefcntStats& stats =
   331       (type == nsTraceRefcnt::NEW_STATS) ? mNewStats : mAllStats;
   332     if (gLogLeaksOnly && !HaveLeaks(&stats))
   333       return false;
   335     fprintf(out,
   336         "\n" \
   337         "     |<----------------Class--------------->|<-----Bytes------>|<----------------Objects---------------->|<--------------References-------------->|\n" \
   338         "                                              Per-Inst   Leaked    Total      Rem      Mean       StdDev     Total      Rem      Mean       StdDev\n");
   340     this->DumpTotal(out);
   342     return true;
   343   }
   345   void Dump(int i, FILE* out, nsTraceRefcnt::StatisticsType type) {
   346     nsTraceRefcntStats* stats = (type == nsTraceRefcnt::NEW_STATS) ? &mNewStats : &mAllStats;
   347     if (gLogLeaksOnly && !HaveLeaks(stats)) {
   348       return;
   349     }
   351     double meanRefs, stddevRefs;
   352     NS_MeanAndStdDev(stats->mAddRefs + stats->mReleases,
   353                      stats->mRefsOutstandingTotal,
   354                      stats->mRefsOutstandingSquared,
   355                      &meanRefs, &stddevRefs);
   357     double meanObjs, stddevObjs;
   358     NS_MeanAndStdDev(stats->mCreates + stats->mDestroys,
   359                      stats->mObjsOutstandingTotal,
   360                      stats->mObjsOutstandingSquared,
   361                      &meanObjs, &stddevObjs);
   363     if ((stats->mAddRefs - stats->mReleases) != 0 ||
   364         stats->mAddRefs != 0 ||
   365         meanRefs != 0 ||
   366         stddevRefs != 0 ||
   367         (stats->mCreates - stats->mDestroys) != 0 ||
   368         stats->mCreates != 0 ||
   369         meanObjs != 0 ||
   370         stddevObjs != 0) {
   371       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",
   372               i+1, mClassName,
   373               (int32_t)mClassSize,
   374               (nsCRT::strcmp(mClassName, "TOTAL"))
   375                   ?(uint64_t)((stats->mCreates - stats->mDestroys) * mClassSize)
   376                   :mTotalLeaked,
   377               stats->mCreates,
   378               (stats->mCreates - stats->mDestroys),
   379               meanObjs,
   380               stddevObjs,
   381               stats->mAddRefs,
   382               (stats->mAddRefs - stats->mReleases),
   383               meanRefs,
   384               stddevRefs);
   385     }
   386   }
   388 protected:
   389   char*         mClassName;
   390   double        mClassSize;     // this is stored as a double because of the way we compute the avg class size for total bloat
   391   uint64_t      mTotalLeaked; // used only for TOTAL entry
   392   nsTraceRefcntStats mNewStats;
   393   nsTraceRefcntStats mAllStats;
   394 };
   396 static void
   397 BloatViewFreeEntry(void *pool, PLHashEntry *he, unsigned flag)
   398 {
   399     if (flag == HT_FREE_ENTRY) {
   400         BloatEntry* entry = reinterpret_cast<BloatEntry*>(he->value);
   401         delete entry;
   402         PR_Free(he);
   403     }
   404 }
   406 const static PLHashAllocOps bloatViewHashAllocOps = {
   407     DefaultAllocTable, DefaultFreeTable,
   408     DefaultAllocEntry, BloatViewFreeEntry
   409 };
   411 static void
   412 RecreateBloatView()
   413 {
   414   gBloatView = PL_NewHashTable(256,
   415                                PL_HashString,
   416                                PL_CompareStrings,
   417                                PL_CompareValues,
   418                                &bloatViewHashAllocOps, nullptr);
   419 }
   421 static BloatEntry*
   422 GetBloatEntry(const char* aTypeName, uint32_t aInstanceSize)
   423 {
   424   if (!gBloatView) {
   425     RecreateBloatView();
   426   }
   427   BloatEntry* entry = nullptr;
   428   if (gBloatView) {
   429     entry = (BloatEntry*)PL_HashTableLookup(gBloatView, aTypeName);
   430     if (entry == nullptr && aInstanceSize > 0) {
   432       entry = new BloatEntry(aTypeName, aInstanceSize);
   433       PLHashEntry* e = PL_HashTableAdd(gBloatView, aTypeName, entry);
   434       if (e == nullptr) {
   435         delete entry;
   436         entry = nullptr;
   437       }
   438     } else {
   439       NS_ASSERTION(aInstanceSize == 0 ||
   440                    entry->GetClassSize() == aInstanceSize,
   441                    "bad size recorded");
   442     }
   443   }
   444   return entry;
   445 }
   447 static int DumpSerialNumbers(PLHashEntry* aHashEntry, int aIndex, void* aClosure)
   448 {
   449   serialNumberRecord* record = reinterpret_cast<serialNumberRecord *>(aHashEntry->value);
   450 #ifdef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR
   451   fprintf((FILE*) aClosure, "%" PRIdPTR
   452                             " @%p (%d references; %d from COMPtrs)\n",
   453                             record->serialNumber,
   454                             NS_INT32_TO_PTR(aHashEntry->key),
   455                             record->refCount,
   456                             record->COMPtrCount);
   457 #else
   458   fprintf((FILE*) aClosure, "%" PRIdPTR
   459                             " @%p (%d references)\n",
   460                             record->serialNumber,
   461                             NS_INT32_TO_PTR(aHashEntry->key),
   462                             record->refCount);
   463 #endif
   464   return HT_ENUMERATE_NEXT;
   465 }
   468 template <>
   469 class nsDefaultComparator <BloatEntry*, BloatEntry*> {
   470   public:
   471     bool Equals(BloatEntry* const& aA, BloatEntry* const& aB) const {
   472       return PL_strcmp(aA->GetClassName(), aB->GetClassName()) == 0;
   473     }
   474     bool LessThan(BloatEntry* const& aA, BloatEntry* const& aB) const {
   475       return PL_strcmp(aA->GetClassName(), aB->GetClassName()) < 0;
   476     }
   477 };
   479 #endif /* NS_IMPL_REFCNT_LOGGING */
   481 nsresult
   482 nsTraceRefcnt::DumpStatistics(StatisticsType type, FILE* out)
   483 {
   484 #ifdef NS_IMPL_REFCNT_LOGGING
   485   if (gBloatLog == nullptr || gBloatView == nullptr) {
   486     return NS_ERROR_FAILURE;
   487   }
   488   if (out == nullptr) {
   489     out = gBloatLog;
   490   }
   492   LOCK_TRACELOG();
   494   bool wasLogging = gLogging;
   495   gLogging = false;  // turn off logging for this method
   497   BloatEntry total("TOTAL", 0);
   498   PL_HashTableEnumerateEntries(gBloatView, BloatEntry::TotalEntries, &total);
   499   const char* msg;
   500   if (type == NEW_STATS) {
   501     if (gLogLeaksOnly)
   502       msg = "NEW (incremental) LEAK STATISTICS";
   503     else
   504       msg = "NEW (incremental) LEAK AND BLOAT STATISTICS";
   505   }
   506   else {
   507     if (gLogLeaksOnly)
   508       msg = "ALL (cumulative) LEAK STATISTICS";
   509     else
   510       msg = "ALL (cumulative) LEAK AND BLOAT STATISTICS";
   511   }
   512   const bool leaked = total.PrintDumpHeader(out, msg, type);
   514   nsTArray<BloatEntry*> entries;
   515   PL_HashTableEnumerateEntries(gBloatView, BloatEntry::DumpEntry, &entries);
   516   const uint32_t count = entries.Length();
   518   if (!gLogLeaksOnly || leaked) {
   519     // Sort the entries alphabetically by classname.
   520     entries.Sort();
   522     for (uint32_t i = 0; i < count; ++i) {
   523       BloatEntry* entry = entries[i];
   524       entry->Dump(i, out, type);
   525     }
   527     fprintf(out, "\n");
   528   }
   530   fprintf(out, "nsTraceRefcnt::DumpStatistics: %d entries\n", count);
   532   if (gSerialNumbers) {
   533     fprintf(out, "\nSerial Numbers of Leaked Objects:\n");
   534     PL_HashTableEnumerateEntries(gSerialNumbers, DumpSerialNumbers, out);
   535   }
   537   gLogging = wasLogging;
   538   UNLOCK_TRACELOG();
   539 #endif
   541   return NS_OK;
   542 }
   544 void
   545 nsTraceRefcnt::ResetStatistics()
   546 {
   547 #ifdef NS_IMPL_REFCNT_LOGGING
   548   LOCK_TRACELOG();
   549   if (gBloatView) {
   550     PL_HashTableDestroy(gBloatView);
   551     gBloatView = nullptr;
   552   }
   553   UNLOCK_TRACELOG();
   554 #endif
   555 }
   557 #ifdef NS_IMPL_REFCNT_LOGGING
   558 static bool LogThisType(const char* aTypeName)
   559 {
   560   void* he = PL_HashTableLookup(gTypesToLog, aTypeName);
   561   return nullptr != he;
   562 }
   564 static intptr_t GetSerialNumber(void* aPtr, bool aCreate)
   565 {
   566   PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr);
   567   if (hep && *hep) {
   568     return reinterpret_cast<serialNumberRecord*>((*hep)->value)->serialNumber;
   569   }
   570   else if (aCreate) {
   571     serialNumberRecord *record = PR_NEW(serialNumberRecord);
   572     record->serialNumber = ++gNextSerialNumber;
   573     record->refCount = 0;
   574     record->COMPtrCount = 0;
   575     PL_HashTableRawAdd(gSerialNumbers, hep, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr, reinterpret_cast<void*>(record));
   576     return gNextSerialNumber;
   577   }
   578   else {
   579     return 0;
   580   }
   581 }
   583 static int32_t* GetRefCount(void* aPtr)
   584 {
   585   PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr);
   586   if (hep && *hep) {
   587     return &((reinterpret_cast<serialNumberRecord*>((*hep)->value))->refCount);
   588   } else {
   589     return nullptr;
   590   }
   591 }
   593 #if defined(NS_IMPL_REFCNT_LOGGING) && defined(HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR)
   594 static int32_t* GetCOMPtrCount(void* aPtr)
   595 {
   596   PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr);
   597   if (hep && *hep) {
   598     return &((reinterpret_cast<serialNumberRecord*>((*hep)->value))->COMPtrCount);
   599   } else {
   600     return nullptr;
   601   }
   602 }
   603 #endif
   605 static void RecycleSerialNumberPtr(void* aPtr)
   606 {
   607   PL_HashTableRemove(gSerialNumbers, aPtr);
   608 }
   610 static bool LogThisObj(intptr_t aSerialNumber)
   611 {
   612   return nullptr != PL_HashTableLookup(gObjectsToLog, (const void*)aSerialNumber);
   613 }
   615 #ifdef XP_WIN
   616 #define FOPEN_NO_INHERIT "N"
   617 #else
   618 #define FOPEN_NO_INHERIT
   619 #endif
   621 static bool InitLog(const char* envVar, const char* msg, FILE* *result)
   622 {
   623   const char* value = getenv(envVar);
   624   if (value) {
   625     if (nsCRT::strcmp(value, "1") == 0) {
   626       *result = stdout;
   627       fprintf(stdout, "### %s defined -- logging %s to stdout\n",
   628               envVar, msg);
   629       return true;
   630     }
   631     else if (nsCRT::strcmp(value, "2") == 0) {
   632       *result = stderr;
   633       fprintf(stdout, "### %s defined -- logging %s to stderr\n",
   634               envVar, msg);
   635       return true;
   636     }
   637     else {
   638       FILE *stream;
   639       nsAutoCString fname(value);
   640       if (XRE_GetProcessType() != GeckoProcessType_Default) {
   641         bool hasLogExtension = 
   642             fname.RFind(".log", true, -1, 4) == kNotFound ? false : true;
   643         if (hasLogExtension)
   644           fname.Cut(fname.Length() - 4, 4);
   645         fname.AppendLiteral("_");
   646         fname.Append((char*)XRE_ChildProcessTypeToString(XRE_GetProcessType()));
   647         fname.AppendLiteral("_pid");
   648         fname.AppendInt((uint32_t)getpid());
   649         if (hasLogExtension)
   650           fname.AppendLiteral(".log");
   651       }
   652       stream = ::fopen(fname.get(), "w" FOPEN_NO_INHERIT);
   653       if (stream != nullptr) {
   654         MozillaRegisterDebugFD(fileno(stream));
   655         *result = stream;
   656         fprintf(stdout, "### %s defined -- logging %s to %s\n",
   657                 envVar, msg, fname.get());
   658       }
   659       else {
   660         fprintf(stdout, "### %s defined -- unable to log %s to %s\n",
   661                 envVar, msg, fname.get());
   662       }
   663       return stream != nullptr;
   664     }
   665   }
   666   return false;
   667 }
   670 static PLHashNumber HashNumber(const void* aKey)
   671 {
   672   return PLHashNumber(NS_PTR_TO_INT32(aKey));
   673 }
   675 static void InitTraceLog(void)
   676 {
   677   if (gInitialized) return;
   678   gInitialized = true;
   680   bool defined;
   681   defined = InitLog("XPCOM_MEM_BLOAT_LOG", "bloat/leaks", &gBloatLog);
   682   if (!defined)
   683     gLogLeaksOnly = InitLog("XPCOM_MEM_LEAK_LOG", "leaks", &gBloatLog);
   684   if (defined || gLogLeaksOnly) {
   685     RecreateBloatView();
   686     if (!gBloatView) {
   687       NS_WARNING("out of memory");
   688       gBloatLog = nullptr;
   689       gLogLeaksOnly = false;
   690     }
   691   }
   693   (void)InitLog("XPCOM_MEM_REFCNT_LOG", "refcounts", &gRefcntsLog);
   695   (void)InitLog("XPCOM_MEM_ALLOC_LOG", "new/delete", &gAllocLog);
   697   defined = InitLog("XPCOM_MEM_LEAKY_LOG", "for leaky", &gLeakyLog);
   698   if (defined) {
   699     gLogToLeaky = true;
   700     PRFuncPtr p = nullptr, q = nullptr;
   701 #ifdef HAVE_DLOPEN
   702     {
   703       PRLibrary *lib = nullptr;
   704       p = PR_FindFunctionSymbolAndLibrary("__log_addref", &lib);
   705       if (lib) {
   706         PR_UnloadLibrary(lib);
   707         lib = nullptr;
   708       }
   709       q = PR_FindFunctionSymbolAndLibrary("__log_release", &lib);
   710       if (lib) {
   711         PR_UnloadLibrary(lib);
   712       }
   713     }
   714 #endif
   715     if (p && q) {
   716       leakyLogAddRef = (void (*)(void*,int,int)) p;
   717       leakyLogRelease = (void (*)(void*,int,int)) q;
   718     }
   719     else {
   720       gLogToLeaky = false;
   721       fprintf(stdout, "### ERROR: XPCOM_MEM_LEAKY_LOG defined, but can't locate __log_addref and __log_release symbols\n");
   722       fflush(stdout);
   723     }
   724   }
   726   const char* classes = getenv("XPCOM_MEM_LOG_CLASSES");
   728 #ifdef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR
   729   if (classes) {
   730     (void)InitLog("XPCOM_MEM_COMPTR_LOG", "nsCOMPtr", &gCOMPtrLog);
   731   } else {
   732     if (getenv("XPCOM_MEM_COMPTR_LOG")) {
   733       fprintf(stdout, "### XPCOM_MEM_COMPTR_LOG defined -- but XPCOM_MEM_LOG_CLASSES is not defined\n");
   734     }
   735   }
   736 #else
   737   const char* comptr_log = getenv("XPCOM_MEM_COMPTR_LOG");
   738   if (comptr_log) {
   739     fprintf(stdout, "### XPCOM_MEM_COMPTR_LOG defined -- but it will not work without dynamic_cast\n");
   740   }
   741 #endif
   743   if (classes) {
   744     // if XPCOM_MEM_LOG_CLASSES was set to some value, the value is interpreted
   745     // as a list of class names to track
   746     gTypesToLog = PL_NewHashTable(256,
   747                                   PL_HashString,
   748                                   PL_CompareStrings,
   749                                   PL_CompareValues,
   750                                   &typesToLogHashAllocOps, nullptr);
   751     if (!gTypesToLog) {
   752       NS_WARNING("out of memory");
   753       fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- unable to log specific classes\n");
   754     }
   755     else {
   756       fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- only logging these classes: ");
   757       const char* cp = classes;
   758       for (;;) {
   759         char* cm = (char*) strchr(cp, ',');
   760         if (cm) {
   761           *cm = '\0';
   762         }
   763         PL_HashTableAdd(gTypesToLog, strdup(cp), (void*)1);
   764         fprintf(stdout, "%s ", cp);
   765         if (!cm) break;
   766         *cm = ',';
   767         cp = cm + 1;
   768       }
   769       fprintf(stdout, "\n");
   770     }
   772     gSerialNumbers = PL_NewHashTable(256,
   773                                      HashNumber,
   774                                      PL_CompareValues,
   775                                      PL_CompareValues,
   776                                      &serialNumberHashAllocOps, nullptr);
   779   }
   781   const char* objects = getenv("XPCOM_MEM_LOG_OBJECTS");
   782   if (objects) {
   783     gObjectsToLog = PL_NewHashTable(256,
   784                                     HashNumber,
   785                                     PL_CompareValues,
   786                                     PL_CompareValues,
   787                                     nullptr, nullptr);
   789     if (!gObjectsToLog) {
   790       NS_WARNING("out of memory");
   791       fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- unable to log specific objects\n");
   792     }
   793     else if (! (gRefcntsLog || gAllocLog || gCOMPtrLog)) {
   794       fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- but none of XPCOM_MEM_(REFCNT|ALLOC|COMPTR)_LOG is defined\n");
   795     }
   796     else {
   797       fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- only logging these objects: ");
   798       const char* cp = objects;
   799       for (;;) {
   800         char* cm = (char*) strchr(cp, ',');
   801         if (cm) {
   802           *cm = '\0';
   803         }
   804         intptr_t top = 0;
   805         intptr_t bottom = 0;
   806         while (*cp) {
   807           if (*cp == '-') {
   808             bottom = top;
   809             top = 0;
   810             ++cp;
   811           }
   812           top *= 10;
   813           top += *cp - '0';
   814           ++cp;
   815         }
   816         if (!bottom) {
   817           bottom = top;
   818         }
   819         for (intptr_t serialno = bottom; serialno <= top; serialno++) {
   820           PL_HashTableAdd(gObjectsToLog, (const void*)serialno, (void*)1);
   821           fprintf(stdout, "%" PRIdPTR " ", serialno);
   822         }
   823         if (!cm) break;
   824         *cm = ',';
   825         cp = cm + 1;
   826       }
   827       fprintf(stdout, "\n");
   828     }
   829   }
   832   if (gBloatLog || gRefcntsLog || gAllocLog || gLeakyLog || gCOMPtrLog) {
   833     gLogging = true;
   834   }
   836   gTraceLock = PR_NewLock();
   837 }
   839 #endif
   841 extern "C" {
   843 #ifdef STACKWALKING_AVAILABLE
   844 static void PrintStackFrame(void *aPC, void *aSP, void *aClosure)
   845 {
   846   FILE *stream = (FILE*)aClosure;
   847   nsCodeAddressDetails details;
   848   char buf[1024];
   850   NS_DescribeCodeAddress(aPC, &details);
   851   NS_FormatCodeAddressDetails(aPC, &details, buf, sizeof(buf));
   852   fputs(buf, stream);
   853 }
   854 #endif
   856 }
   858 void
   859 nsTraceRefcnt::WalkTheStack(FILE* aStream)
   860 {
   861 #ifdef STACKWALKING_AVAILABLE
   862   NS_StackWalk(PrintStackFrame, /* skipFrames */ 2, /* maxFrames */ 0, aStream,
   863                0, nullptr);
   864 #endif
   865 }
   867 //----------------------------------------------------------------------
   869 // This thing is exported by libstdc++
   870 // Yes, this is a gcc only hack
   871 #if defined(MOZ_DEMANGLE_SYMBOLS)
   872 #include <cxxabi.h>
   873 #include <stdlib.h> // for free()
   874 #endif // MOZ_DEMANGLE_SYMBOLS
   876 void
   877 nsTraceRefcnt::DemangleSymbol(const char * aSymbol,
   878                               char * aBuffer,
   879                               int aBufLen)
   880 {
   881   NS_ASSERTION(nullptr != aSymbol,"null symbol");
   882   NS_ASSERTION(nullptr != aBuffer,"null buffer");
   883   NS_ASSERTION(aBufLen >= 32 ,"pulled 32 out of you know where");
   885   aBuffer[0] = '\0';
   887 #if defined(MOZ_DEMANGLE_SYMBOLS)
   888  /* See demangle.h in the gcc source for the voodoo */
   889   char * demangled = abi::__cxa_demangle(aSymbol,0,0,0);
   891   if (demangled)
   892   {
   893     strncpy(aBuffer,demangled,aBufLen);
   894     free(demangled);
   895   }
   896 #endif // MOZ_DEMANGLE_SYMBOLS
   897 }
   900 //----------------------------------------------------------------------
   902 EXPORT_XPCOM_API(void)
   903 NS_LogInit()
   904 {
   905   // FIXME: This is called multiple times, we should probably not allow that.
   906 #ifdef STACKWALKING_AVAILABLE
   907   StackWalkInitCriticalAddress();
   908 #endif
   909 #ifdef NS_IMPL_REFCNT_LOGGING
   910   if (++gInitCount)
   911     nsTraceRefcnt::SetActivityIsLegal(true);
   912 #endif
   914 #ifdef NS_TRACE_MALLOC
   915   // XXX we don't have to worry about shutting down trace-malloc; it
   916   // handles this itself, through an atexit() callback.
   917   if (!NS_TraceMallocHasStarted())
   918     NS_TraceMallocStartup(-1);  // -1 == no logging
   919 #endif
   920 }
   922 EXPORT_XPCOM_API(void)
   923 NS_LogTerm()
   924 {
   925   mozilla::LogTerm();
   926 }
   928 namespace mozilla {
   929 void
   930 LogTerm()
   931 {
   932   NS_ASSERTION(gInitCount > 0,
   933                "NS_LogTerm without matching NS_LogInit");
   935   if (--gInitCount == 0) {
   936 #ifdef DEBUG
   937     /* FIXME bug 491977: This is only going to operate on the
   938      * BlockingResourceBase which is compiled into
   939      * libxul/libxpcom_core.so. Anyone using external linkage will
   940      * have their own copy of BlockingResourceBase statics which will
   941      * not be freed by this method.
   942      *
   943      * It sounds like what we really want is to be able to register a
   944      * callback function to call at XPCOM shutdown.  Note that with
   945      * this solution, however, we need to guarantee that
   946      * BlockingResourceBase::Shutdown() runs after all other shutdown
   947      * functions.
   948      */
   949     BlockingResourceBase::Shutdown();
   950 #endif
   952     if (gInitialized) {
   953       nsTraceRefcnt::DumpStatistics();
   954       nsTraceRefcnt::ResetStatistics();
   955     }
   956     nsTraceRefcnt::Shutdown();
   957 #ifdef NS_IMPL_REFCNT_LOGGING
   958     nsTraceRefcnt::SetActivityIsLegal(false);
   959     gActivityTLS = BAD_TLS_INDEX;
   960 #endif
   961   }
   962 }
   964 } // namespace mozilla
   966 EXPORT_XPCOM_API(void)
   967 NS_LogAddRef(void* aPtr, nsrefcnt aRefcnt,
   968              const char* aClazz, uint32_t classSize)
   969 {
   970 #ifdef NS_IMPL_REFCNT_LOGGING
   971   ASSERT_ACTIVITY_IS_LEGAL;
   972   if (!gInitialized)
   973     InitTraceLog();
   974   if (gLogging) {
   975     LOCK_TRACELOG();
   977     if (gBloatLog) {
   978       BloatEntry* entry = GetBloatEntry(aClazz, classSize);
   979       if (entry) {
   980         entry->AddRef(aRefcnt);
   981       }
   982     }
   984     // Here's the case where MOZ_COUNT_CTOR was not used,
   985     // yet we still want to see creation information:
   987     bool loggingThisType = (!gTypesToLog || LogThisType(aClazz));
   988     intptr_t serialno = 0;
   989     if (gSerialNumbers && loggingThisType) {
   990       serialno = GetSerialNumber(aPtr, aRefcnt == 1);
   991       NS_ASSERTION(serialno != 0,
   992                    "Serial number requested for unrecognized pointer!  "
   993                    "Are you memmoving a refcounted object?");
   994       int32_t* count = GetRefCount(aPtr);
   995       if(count)
   996         (*count)++;
   998     }
  1000     bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
  1001     if (aRefcnt == 1 && gAllocLog && loggingThisType && loggingThisObject) {
  1002       fprintf(gAllocLog, "\n<%s> 0x%08X %" PRIdPTR " Create\n",
  1003               aClazz, NS_PTR_TO_INT32(aPtr), serialno);
  1004       nsTraceRefcnt::WalkTheStack(gAllocLog);
  1007     if (gRefcntsLog && loggingThisType && loggingThisObject) {
  1008       if (gLogToLeaky) {
  1009         (*leakyLogAddRef)(aPtr, aRefcnt - 1, aRefcnt);
  1011       else {
  1012           // Can't use PR_LOG(), b/c it truncates the line
  1013           fprintf(gRefcntsLog,
  1014                   "\n<%s> 0x%08X %" PRIuPTR " AddRef %" PRIuPTR "\n", aClazz, NS_PTR_TO_INT32(aPtr), serialno, aRefcnt);
  1015           nsTraceRefcnt::WalkTheStack(gRefcntsLog);
  1016           fflush(gRefcntsLog);
  1019     UNLOCK_TRACELOG();
  1021 #endif
  1024 EXPORT_XPCOM_API(void)
  1025 NS_LogRelease(void* aPtr, nsrefcnt aRefcnt, const char* aClazz)
  1027 #ifdef NS_IMPL_REFCNT_LOGGING
  1028   ASSERT_ACTIVITY_IS_LEGAL;
  1029   if (!gInitialized)
  1030     InitTraceLog();
  1031   if (gLogging) {
  1032     LOCK_TRACELOG();
  1034     if (gBloatLog) {
  1035       BloatEntry* entry = GetBloatEntry(aClazz, 0);
  1036       if (entry) {
  1037         entry->Release(aRefcnt);
  1041     bool loggingThisType = (!gTypesToLog || LogThisType(aClazz));
  1042     intptr_t serialno = 0;
  1043     if (gSerialNumbers && loggingThisType) {
  1044       serialno = GetSerialNumber(aPtr, false);
  1045       NS_ASSERTION(serialno != 0,
  1046                    "Serial number requested for unrecognized pointer!  "
  1047                    "Are you memmoving a refcounted object?");
  1048       int32_t* count = GetRefCount(aPtr);
  1049       if(count)
  1050         (*count)--;
  1054     bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
  1055     if (gRefcntsLog && loggingThisType && loggingThisObject) {
  1056       if (gLogToLeaky) {
  1057         (*leakyLogRelease)(aPtr, aRefcnt + 1, aRefcnt);
  1059       else {
  1060           // Can't use PR_LOG(), b/c it truncates the line
  1061           fprintf(gRefcntsLog,
  1062                   "\n<%s> 0x%08X %" PRIuPTR " Release %" PRIuPTR "\n", aClazz, NS_PTR_TO_INT32(aPtr), serialno, aRefcnt);
  1063           nsTraceRefcnt::WalkTheStack(gRefcntsLog);
  1064           fflush(gRefcntsLog);
  1068     // Here's the case where MOZ_COUNT_DTOR was not used,
  1069     // yet we still want to see deletion information:
  1071     if (aRefcnt == 0 && gAllocLog && loggingThisType && loggingThisObject) {
  1072       fprintf(gAllocLog,
  1073               "\n<%s> 0x%08X %" PRIdPTR " Destroy\n",
  1074               aClazz, NS_PTR_TO_INT32(aPtr), serialno);
  1075       nsTraceRefcnt::WalkTheStack(gAllocLog);
  1078     if (aRefcnt == 0 && gSerialNumbers && loggingThisType) {
  1079       RecycleSerialNumberPtr(aPtr);
  1082     UNLOCK_TRACELOG();
  1084 #endif
  1087 EXPORT_XPCOM_API(void)
  1088 NS_LogCtor(void* aPtr, const char* aType, uint32_t aInstanceSize)
  1090 #ifdef NS_IMPL_REFCNT_LOGGING
  1091   ASSERT_ACTIVITY_IS_LEGAL;
  1092   if (!gInitialized)
  1093     InitTraceLog();
  1095   if (gLogging) {
  1096     LOCK_TRACELOG();
  1098     if (gBloatLog) {
  1099       BloatEntry* entry = GetBloatEntry(aType, aInstanceSize);
  1100       if (entry) {
  1101         entry->Ctor();
  1105     bool loggingThisType = (!gTypesToLog || LogThisType(aType));
  1106     intptr_t serialno = 0;
  1107     if (gSerialNumbers && loggingThisType) {
  1108       serialno = GetSerialNumber(aPtr, true);
  1111     bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
  1112     if (gAllocLog && loggingThisType && loggingThisObject) {
  1113       fprintf(gAllocLog, "\n<%s> 0x%08X %" PRIdPTR " Ctor (%d)\n",
  1114              aType, NS_PTR_TO_INT32(aPtr), serialno, aInstanceSize);
  1115       nsTraceRefcnt::WalkTheStack(gAllocLog);
  1118     UNLOCK_TRACELOG();
  1120 #endif
  1124 EXPORT_XPCOM_API(void)
  1125 NS_LogDtor(void* aPtr, const char* aType, uint32_t aInstanceSize)
  1127 #ifdef NS_IMPL_REFCNT_LOGGING
  1128   ASSERT_ACTIVITY_IS_LEGAL;
  1129   if (!gInitialized)
  1130     InitTraceLog();
  1132   if (gLogging) {
  1133     LOCK_TRACELOG();
  1135     if (gBloatLog) {
  1136       BloatEntry* entry = GetBloatEntry(aType, aInstanceSize);
  1137       if (entry) {
  1138         entry->Dtor();
  1142     bool loggingThisType = (!gTypesToLog || LogThisType(aType));
  1143     intptr_t serialno = 0;
  1144     if (gSerialNumbers && loggingThisType) {
  1145       serialno = GetSerialNumber(aPtr, false);
  1146       RecycleSerialNumberPtr(aPtr);
  1149     bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
  1151     // (If we're on a losing architecture, don't do this because we'll be
  1152     // using LogDeleteXPCOM instead to get file and line numbers.)
  1153     if (gAllocLog && loggingThisType && loggingThisObject) {
  1154       fprintf(gAllocLog, "\n<%s> 0x%08X %" PRIdPTR " Dtor (%d)\n",
  1155              aType, NS_PTR_TO_INT32(aPtr), serialno, aInstanceSize);
  1156       nsTraceRefcnt::WalkTheStack(gAllocLog);
  1159     UNLOCK_TRACELOG();
  1161 #endif
  1165 EXPORT_XPCOM_API(void)
  1166 NS_LogCOMPtrAddRef(void* aCOMPtr, nsISupports* aObject)
  1168 #if defined(NS_IMPL_REFCNT_LOGGING) && defined(HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR)
  1169   // Get the most-derived object.
  1170   void *object = dynamic_cast<void *>(aObject);
  1172   // This is a very indirect way of finding out what the class is
  1173   // of the object being logged.  If we're logging a specific type,
  1174   // then
  1175   if (!gTypesToLog || !gSerialNumbers) {
  1176     return;
  1178   intptr_t serialno = GetSerialNumber(object, false);
  1179   if (serialno == 0) {
  1180     return;
  1183   if (!gInitialized)
  1184     InitTraceLog();
  1185   if (gLogging) {
  1186     LOCK_TRACELOG();
  1188     int32_t* count = GetCOMPtrCount(object);
  1189     if(count)
  1190       (*count)++;
  1192     bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
  1194     if (gCOMPtrLog && loggingThisObject) {
  1195       fprintf(gCOMPtrLog, "\n<?> 0x%08X %" PRIdPTR " nsCOMPtrAddRef %d 0x%08X\n",
  1196               NS_PTR_TO_INT32(object), serialno, count?(*count):-1, NS_PTR_TO_INT32(aCOMPtr));
  1197       nsTraceRefcnt::WalkTheStack(gCOMPtrLog);
  1200     UNLOCK_TRACELOG();
  1202 #endif
  1206 EXPORT_XPCOM_API(void)
  1207 NS_LogCOMPtrRelease(void* aCOMPtr, nsISupports* aObject)
  1209 #if defined(NS_IMPL_REFCNT_LOGGING) && defined(HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR)
  1210   // Get the most-derived object.
  1211   void *object = dynamic_cast<void *>(aObject);
  1213   // This is a very indirect way of finding out what the class is
  1214   // of the object being logged.  If we're logging a specific type,
  1215   // then
  1216   if (!gTypesToLog || !gSerialNumbers) {
  1217     return;
  1219   intptr_t serialno = GetSerialNumber(object, false);
  1220   if (serialno == 0) {
  1221     return;
  1224   if (!gInitialized)
  1225     InitTraceLog();
  1226   if (gLogging) {
  1227     LOCK_TRACELOG();
  1229     int32_t* count = GetCOMPtrCount(object);
  1230     if(count)
  1231       (*count)--;
  1233     bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
  1235     if (gCOMPtrLog && loggingThisObject) {
  1236       fprintf(gCOMPtrLog, "\n<?> 0x%08X %" PRIdPTR " nsCOMPtrRelease %d 0x%08X\n",
  1237               NS_PTR_TO_INT32(object), serialno, count?(*count):-1, NS_PTR_TO_INT32(aCOMPtr));
  1238       nsTraceRefcnt::WalkTheStack(gCOMPtrLog);
  1241     UNLOCK_TRACELOG();
  1243 #endif
  1246 void
  1247 nsTraceRefcnt::Startup()
  1251 static void maybeUnregisterAndCloseFile(FILE *&f) {
  1252   if (!f)
  1253     return;
  1255   MozillaUnRegisterDebugFILE(f);
  1256   fclose(f);
  1257   f = nullptr;
  1260 void
  1261 nsTraceRefcnt::Shutdown()
  1263 #ifdef NS_IMPL_REFCNT_LOGGING
  1265   if (gBloatView) {
  1266     PL_HashTableDestroy(gBloatView);
  1267     gBloatView = nullptr;
  1269   if (gTypesToLog) {
  1270     PL_HashTableDestroy(gTypesToLog);
  1271     gTypesToLog = nullptr;
  1273   if (gObjectsToLog) {
  1274     PL_HashTableDestroy(gObjectsToLog);
  1275     gObjectsToLog = nullptr;
  1277   if (gSerialNumbers) {
  1278     PL_HashTableDestroy(gSerialNumbers);
  1279     gSerialNumbers = nullptr;
  1281   maybeUnregisterAndCloseFile(gBloatLog);
  1282   maybeUnregisterAndCloseFile(gRefcntsLog);
  1283   maybeUnregisterAndCloseFile(gAllocLog);
  1284   maybeUnregisterAndCloseFile(gLeakyLog);
  1285   maybeUnregisterAndCloseFile(gCOMPtrLog);
  1286 #endif
  1289 void
  1290 nsTraceRefcnt::SetActivityIsLegal(bool aLegal)
  1292 #ifdef NS_IMPL_REFCNT_LOGGING
  1293   if (gActivityTLS == BAD_TLS_INDEX)
  1294     PR_NewThreadPrivateIndex(&gActivityTLS, nullptr);
  1296   PR_SetThreadPrivate(gActivityTLS, NS_INT32_TO_PTR(!aLegal));
  1297 #endif

mercurial