LCOV - app.info - xpcom/base/nsTraceRefcntImpl.cpp

LCOV - code coverage report
| Current view: | directory - xpcom/base - nsTraceRefcntImpl.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 614 | 354 | 57.7 %
| Date: | 2012-04-21 | Functions: | 71 | 46 | 64.8 %

           1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
           2                 : /* ***** BEGIN LICENSE BLOCK *****
           3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           4                 :  *
           5                 :  * The contents of this file are subject to the Mozilla Public License Version
           6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           7                 :  * the License. You may obtain a copy of the License at
           8                 :  * http://www.mozilla.org/MPL/
           9                 :  *
          10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          12                 :  * for the specific language governing rights and limitations under the
          13                 :  * License.
          14                 :  *
          15                 :  * The Original Code is Mozilla Communicator client code.
          16                 :  *
          17                 :  * The Initial Developer of the Original Code is
          18                 :  * Netscape Communications Corporation.
          19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
          20                 :  * the Initial Developer. All Rights Reserved.
          21                 :  *
          22                 :  * Contributor(s):
          23                 :  *   L. David Baron <dbaron@dbaron.org>
          24                 :  *
          25                 :  * Alternatively, the contents of this file may be used under the terms of
          26                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
          27                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          29                 :  * of those above. If you wish to allow use of your version of this file only
          30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          31                 :  * use your version of this file under the terms of the MPL, indicate your
          32                 :  * decision by deleting the provisions above and replace them with the notice
          33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          34                 :  * the provisions above, a recipient may use your version of this file under
          35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          36                 :  *
          37                 :  * ***** END LICENSE BLOCK ***** */
          38                 :
          39                 : #include "nsTraceRefcntImpl.h"
          40                 : #include "nsXPCOMPrivate.h"
          41                 : #include "nscore.h"
          42                 : #include "nsISupports.h"
          43                 : #include "nsTArray.h"
          44                 : #include "prenv.h"
          45                 : #include "prprf.h"
          46                 : #include "prlog.h"
          47                 : #include "plstr.h"
          48                 : #include "prlink.h"
          49                 : #include <stdlib.h>
          50                 : #include "nsCOMPtr.h"
          51                 : #include "nsCRT.h"
          52                 : #include <math.h>
          53                 : #include "nsStackWalkPrivate.h"
          54                 : #include "nsStackWalk.h"
          55                 : #include "nsString.h"
          56                 :
          57                 : #include "nsXULAppAPI.h"
          58                 : #ifdef XP_WIN
          59                 : #include <process.h>
          60                 : #define getpid _getpid
          61                 : #else
          62                 : #include <unistd.h>
          63                 : #endif
          64                 :
          65                 : #ifdef NS_TRACE_MALLOC
          66                 : #include "nsTraceMalloc.h"
          67                 : #endif
          68                 :
          69                 : #include "mozilla/BlockingResourceBase.h"
          70                 :
          71                 : #ifdef HAVE_DLOPEN
          72                 : #include <dlfcn.h>
          73                 : #endif
          74                 :
          75                 : ////////////////////////////////////////////////////////////////////////////////
          76                 :
          77                 : void
          78            1546 : NS_MeanAndStdDev(double n, double sumOfValues, double sumOfSquaredValues,
          79                 :                  double *meanResult, double *stdDevResult)
          80                 : {
          81            1546 :   double mean = 0.0, var = 0.0, stdDev = 0.0;
          82            1546 :   if (n > 0.0 && sumOfValues >= 0) {
          83            1329 :     mean = sumOfValues / n;
          84            1329 :     double temp = (n * sumOfSquaredValues) - (sumOfValues * sumOfValues);
          85            1329 :     if (temp < 0.0 || n <= 1)
          86             180 :       var = 0.0;
          87                 :     else
          88            1149 :       var = temp / (n * (n - 1));
          89                 :     // for some reason, Windows says sqrt(0.0) is "-1.#J" (?!) so do this:
          90            1329 :     stdDev = var != 0.0 ? sqrt(var) : 0.0;
          91                 :   }
          92            1546 :   *meanResult = mean;
          93            1546 :   *stdDevResult = stdDev;
          94            1546 : }
          95                 :
          96                 : ////////////////////////////////////////////////////////////////////////////////
          97                 :
          98                 : #define NS_IMPL_REFCNT_LOGGING
          99                 :
         100                 : #ifdef NS_IMPL_REFCNT_LOGGING
         101                 : #include "plhash.h"
         102                 : #include "prmem.h"
         103                 :
         104                 : #include "prlock.h"
         105                 :
         106                 : // TraceRefcnt has to use bare PRLock instead of mozilla::Mutex
         107                 : // because TraceRefcnt can be used very early in startup.
         108                 : static PRLock* gTraceLock;
         109                 :
         110                 : #define LOCK_TRACELOG()   PR_Lock(gTraceLock)
         111                 : #define UNLOCK_TRACELOG() PR_Unlock(gTraceLock)
         112                 :
         113                 : static PLHashTable* gBloatView;
         114                 : static PLHashTable* gTypesToLog;
         115                 : static PLHashTable* gObjectsToLog;
         116                 : static PLHashTable* gSerialNumbers;
         117                 : static PRInt32 gNextSerialNumber;
         118                 :
         119                 : static bool gLogging;
         120                 : static bool gLogToLeaky;
         121                 : static bool gLogLeaksOnly;
         122                 :
         123                 : static void (*leakyLogAddRef)(void* p, int oldrc, int newrc);
         124                 : static void (*leakyLogRelease)(void* p, int oldrc, int newrc);
         125                 :
         126                 : #define BAD_TLS_INDEX ((PRUintn) -1)
         127                 :
         128                 : // if gActivityTLS == BAD_TLS_INDEX, then we're
         129                 : // unitialized... otherwise this points to a NSPR TLS thread index
         130                 : // indicating whether addref activity is legal. If the PTR_TO_INT32 is 0 then
         131                 : // activity is ok, otherwise not!
         132                 : static PRUintn gActivityTLS = BAD_TLS_INDEX;
         133                 :
         134                 : static bool gInitialized;
         135                 : static nsrefcnt gInitCount;
         136                 :
         137                 : static FILE *gBloatLog = nsnull;
         138                 : static FILE *gRefcntsLog = nsnull;
         139                 : static FILE *gAllocLog = nsnull;
         140                 : static FILE *gLeakyLog = nsnull;
         141                 : static FILE *gCOMPtrLog = nsnull;
         142                 :
         143                 : struct serialNumberRecord {
         144                 :   PRInt32 serialNumber;
         145                 :   PRInt32 refCount;
         146                 :   PRInt32 COMPtrCount;
         147                 : };
         148                 :
         149                 : struct nsTraceRefcntStats {
         150                 :   PRUint64 mAddRefs;
         151                 :   PRUint64 mReleases;
         152                 :   PRUint64 mCreates;
         153                 :   PRUint64 mDestroys;
         154                 :   double mRefsOutstandingTotal;
         155                 :   double mRefsOutstandingSquared;
         156                 :   double mObjsOutstandingTotal;
         157                 :   double mObjsOutstandingSquared;
         158                 : };
         159                 :
         160                 :   // I hope to turn this on for everybody once we hit it a little less.
         161                 : #ifdef DEBUG
         162                 : static const char kStaticCtorDtorWarning[] =
         163                 :   "XPCOM objects created/destroyed from static ctor/dtor";
         164                 :
         165                 : static void
         166       212526772 : AssertActivityIsLegal()
         167                 : {
         168       425053582 :   if (gActivityTLS == BAD_TLS_INDEX ||
         169       212526772 :       NS_PTR_TO_INT32(PR_GetThreadPrivate(gActivityTLS)) != 0) {
         170               0 :     if (PR_GetEnv("MOZ_FATAL_STATIC_XPCOM_CTORS_DTORS")) {
         171               0 :       NS_RUNTIMEABORT(kStaticCtorDtorWarning);
         172                 :     } else {
         173               0 :       NS_WARNING(kStaticCtorDtorWarning);
         174                 :     }
         175                 :   }
         176       212526810 : }
         177                 : #  define ASSERT_ACTIVITY_IS_LEGAL              \
         178                 :   PR_BEGIN_MACRO                                \
         179                 :     AssertActivityIsLegal();                    \
         180                 :   PR_END_MACRO
         181                 : #else
         182                 : #  define ASSERT_ACTIVITY_IS_LEGAL PR_BEGIN_MACRO PR_END_MACRO
         183                 : #endif  // DEBUG
         184                 :
         185                 : // These functions are copied from nsprpub/lib/ds/plhash.c, with changes
         186                 : // to the functions not called Default* to free the serialNumberRecord or
         187                 : // the BloatEntry.
         188                 :
         189                 : static void *
         190            3283 : DefaultAllocTable(void *pool, PRSize size)
         191                 : {
         192            3283 :     return PR_MALLOC(size);
         193                 : }
         194                 :
         195                 : static void
         196            3281 : DefaultFreeTable(void *pool, void *item)
         197                 : {
         198            3281 :     PR_Free(item);
         199            3281 : }
         200                 :
         201                 : static PLHashEntry *
         202          295534 : DefaultAllocEntry(void *pool, const void *key)
         203                 : {
         204          295534 :     return PR_NEW(PLHashEntry);
         205                 : }
         206                 :
         207                 : static void
         208               0 : SerialNumberFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
         209                 : {
         210               0 :     if (flag == HT_FREE_ENTRY) {
         211               0 :         PR_Free(reinterpret_cast<serialNumberRecord*>(he->value));
         212               0 :         PR_Free(he);
         213                 :     }
         214               0 : }
         215                 :
         216                 : static void
         217               0 : TypesToLogFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
         218                 : {
         219               0 :     if (flag == HT_FREE_ENTRY) {
         220               0 :         nsCRT::free(const_cast<char*>
         221               0 :                               (reinterpret_cast<const char*>(he->key)));
         222               0 :         PR_Free(he);
         223                 :     }
         224               0 : }
         225                 :
         226                 : static const PLHashAllocOps serialNumberHashAllocOps = {
         227                 :     DefaultAllocTable, DefaultFreeTable,
         228                 :     DefaultAllocEntry, SerialNumberFreeEntry
         229                 : };
         230                 :
         231                 : static const PLHashAllocOps typesToLogHashAllocOps = {
         232                 :     DefaultAllocTable, DefaultFreeTable,
         233                 :     DefaultAllocEntry, TypesToLogFreeEntry
         234                 : };
         235                 :
         236                 : ////////////////////////////////////////////////////////////////////////////////
         237                 :
         238                 : class BloatEntry {
         239                 : public:
         240          296921 :   BloatEntry(const char* className, PRUint32 classSize)
         241          296921 :     : mClassSize(classSize) {
         242          296921 :     mClassName = PL_strdup(className);
         243          296921 :     Clear(&mNewStats);
         244          296921 :     Clear(&mAllStats);
         245          296921 :     mTotalLeaked = 0;
         246          296921 :   }
         247                 :
         248          296913 :   ~BloatEntry() {
         249          296913 :     PL_strfree(mClassName);
         250          296913 :   }
         251                 :
         252       123332160 :   PRUint32 GetClassSize() { return (PRUint32)mClassSize; }
         253          149846 :   const char* GetClassName() { return mClassName; }
         254                 :
         255          889368 :   static void Clear(nsTraceRefcntStats* stats) {
         256          889368 :     stats->mAddRefs = 0;
         257          889368 :     stats->mReleases = 0;
         258          889368 :     stats->mCreates = 0;
         259          889368 :     stats->mDestroys = 0;
         260          889368 :     stats->mRefsOutstandingTotal = 0;
         261          889368 :     stats->mRefsOutstandingSquared = 0;
         262          889368 :     stats->mObjsOutstandingTotal = 0;
         263          889368 :     stats->mObjsOutstandingSquared = 0;
         264          889368 :   }
         265                 :
         266          295526 :   void Accumulate() {
         267          295526 :       mAllStats.mAddRefs += mNewStats.mAddRefs;
         268          295526 :       mAllStats.mReleases += mNewStats.mReleases;
         269          295526 :       mAllStats.mCreates += mNewStats.mCreates;
         270          295526 :       mAllStats.mDestroys += mNewStats.mDestroys;
         271          295526 :       mAllStats.mRefsOutstandingTotal += mNewStats.mRefsOutstandingTotal;
         272          295526 :       mAllStats.mRefsOutstandingSquared += mNewStats.mRefsOutstandingSquared;
         273          295526 :       mAllStats.mObjsOutstandingTotal += mNewStats.mObjsOutstandingTotal;
         274          295526 :       mAllStats.mObjsOutstandingSquared += mNewStats.mObjsOutstandingSquared;
         275          295526 :       Clear(&mNewStats);
         276          295526 :   }
         277                 :
         278        88911470 :   void AddRef(nsrefcnt refcnt) {
         279        88911470 :     mNewStats.mAddRefs++;
         280        88911470 :     if (refcnt == 1) {
         281        15654657 :       Ctor();
         282                 :     }
         283        88911470 :     AccountRefs();
         284        88911470 :   }
         285                 :
         286        88897657 :   void Release(nsrefcnt refcnt) {
         287        88897657 :     mNewStats.mReleases++;
         288        88897657 :     if (refcnt == 0) {
         289        15645601 :       Dtor();
         290                 :     }
         291        88897657 :     AccountRefs();
         292        88897657 :   }
         293                 :
         294        33014164 :   void Ctor() {
         295        33014164 :     mNewStats.mCreates++;
         296        33014164 :     AccountObjs();
         297        33014164 :   }
         298                 :
         299        33002318 :   void Dtor() {
         300        33002318 :     mNewStats.mDestroys++;
         301        33002318 :     AccountObjs();
         302        33002318 :   }
         303                 :
         304       177809127 :   void AccountRefs() {
         305       177809127 :     PRUint64 cnt = (mNewStats.mAddRefs - mNewStats.mReleases);
         306       177809127 :     mNewStats.mRefsOutstandingTotal += cnt;
         307       177809127 :     mNewStats.mRefsOutstandingSquared += cnt * cnt;
         308       177809127 :   }
         309                 :
         310        66016482 :   void AccountObjs() {
         311        66016482 :     PRUint64 cnt = (mNewStats.mCreates - mNewStats.mDestroys);
         312        66016482 :     mNewStats.mObjsOutstandingTotal += cnt;
         313        66016482 :     mNewStats.mObjsOutstandingSquared += cnt * cnt;
         314        66016482 :   }
         315                 :
         316          295526 :   static PRIntn DumpEntry(PLHashEntry *he, PRIntn i, void *arg) {
         317          295526 :     BloatEntry* entry = (BloatEntry*)he->value;
         318          295526 :     if (entry) {
         319          295526 :       entry->Accumulate();
         320          295526 :       static_cast<nsTArray<BloatEntry*>*>(arg)->AppendElement(entry);
         321                 :     }
         322          295526 :     return HT_ENUMERATE_NEXT;
         323                 :   }
         324                 :
         325          295526 :   static PRIntn TotalEntries(PLHashEntry *he, PRIntn i, void *arg) {
         326          295526 :     BloatEntry* entry = (BloatEntry*)he->value;
         327          295526 :     if (entry && nsCRT::strcmp(entry->mClassName, "TOTAL") != 0) {
         328          295526 :       entry->Total((BloatEntry*)arg);
         329                 :     }
         330          295526 :     return HT_ENUMERATE_NEXT;
         331                 :   }
         332                 :
         333          295526 :   void Total(BloatEntry* total) {
         334          295526 :     total->mAllStats.mAddRefs += mNewStats.mAddRefs + mAllStats.mAddRefs;
         335          295526 :     total->mAllStats.mReleases += mNewStats.mReleases + mAllStats.mReleases;
         336          295526 :     total->mAllStats.mCreates += mNewStats.mCreates + mAllStats.mCreates;
         337          295526 :     total->mAllStats.mDestroys += mNewStats.mDestroys + mAllStats.mDestroys;
         338          295526 :     total->mAllStats.mRefsOutstandingTotal += mNewStats.mRefsOutstandingTotal + mAllStats.mRefsOutstandingTotal;
         339          295526 :     total->mAllStats.mRefsOutstandingSquared += mNewStats.mRefsOutstandingSquared + mAllStats.mRefsOutstandingSquared;
         340          295526 :     total->mAllStats.mObjsOutstandingTotal += mNewStats.mObjsOutstandingTotal + mAllStats.mObjsOutstandingTotal;
         341          295526 :     total->mAllStats.mObjsOutstandingSquared += mNewStats.mObjsOutstandingSquared + mAllStats.mObjsOutstandingSquared;
         342          295526 :     PRUint64 count = (mNewStats.mCreates + mAllStats.mCreates);
         343          295526 :     total->mClassSize += mClassSize * count;    // adjust for average in DumpTotal
         344                 :     total->mTotalLeaked += (PRUint64)(mClassSize *
         345                 :                                      ((mNewStats.mCreates + mAllStats.mCreates)
         346          295526 :                                       -(mNewStats.mDestroys + mAllStats.mDestroys)));
         347          295526 :   }
         348                 :
         349              42 :   void DumpTotal(FILE* out) {
         350              42 :     mClassSize /= mAllStats.mCreates;
         351              42 :     Dump(-1, out, nsTraceRefcntImpl::ALL_STATS);
         352              42 :   }
         353                 :
         354            7281 :   static bool HaveLeaks(nsTraceRefcntStats* stats) {
         355                 :     return ((stats->mAddRefs != stats->mReleases) ||
         356            7281 :             (stats->mCreates != stats->mDestroys));
         357                 :   }
         358                 :
         359            1387 :   bool PrintDumpHeader(FILE* out, const char* msg, nsTraceRefcntImpl::StatisticsType type) {
         360                 :     fprintf(out, "\n== BloatView: %s, %s process %d\n", msg,
         361            1387 :             XRE_ChildProcessTypeToString(XRE_GetProcessType()), getpid());
         362                 :     nsTraceRefcntStats& stats =
         363            1387 :       (type == nsTraceRefcntImpl::NEW_STATS) ? mNewStats : mAllStats;
         364            1387 :     if (gLogLeaksOnly && !HaveLeaks(&stats))
         365            1345 :       return false;
         366                 :
         367                 :     fprintf(out,
         368                 :         "\n" \
         369                 :         "     |<----------------Class--------------->|<-----Bytes------>|<----------------Objects---------------->|<--------------References-------------->|\n" \
         370              42 :         "                                              Per-Inst   Leaked    Total      Rem      Mean       StdDev     Total      Rem      Mean       StdDev\n");
         371                 :
         372              42 :     this->DumpTotal(out);
         373                 :
         374              42 :     return true;
         375                 :   }
         376                 :
         377            6070 :   void Dump(PRIntn i, FILE* out, nsTraceRefcntImpl::StatisticsType type) {
         378            6070 :     nsTraceRefcntStats* stats = (type == nsTraceRefcntImpl::NEW_STATS) ? &mNewStats : &mAllStats;
         379            6070 :     if (gLogLeaksOnly && !HaveLeaks(stats)) {
         380            5297 :       return;
         381                 :     }
         382                 :
         383                 :     double meanRefs, stddevRefs;
         384                 :     NS_MeanAndStdDev(stats->mAddRefs + stats->mReleases,
         385                 :                      stats->mRefsOutstandingTotal,
         386                 :                      stats->mRefsOutstandingSquared,
         387             773 :                      &meanRefs, &stddevRefs);
         388                 :
         389                 :     double meanObjs, stddevObjs;
         390                 :     NS_MeanAndStdDev(stats->mCreates + stats->mDestroys,
         391                 :                      stats->mObjsOutstandingTotal,
         392                 :                      stats->mObjsOutstandingSquared,
         393             773 :                      &meanObjs, &stddevObjs);
         394                 :
         395             773 :     if ((stats->mAddRefs - stats->mReleases) != 0 ||
         396                 :         stats->mAddRefs != 0 ||
         397                 :         meanRefs != 0 ||
         398                 :         stddevRefs != 0 ||
         399                 :         (stats->mCreates - stats->mDestroys) != 0 ||
         400                 :         stats->mCreates != 0 ||
         401                 :         meanObjs != 0 ||
         402                 :         stddevObjs != 0) {
         403                 :       fprintf(out, "%4d %-40.40s %8d %8llu %8llu %8llu (%8.2f +/- %8.2f) %8llu %8llu (%8.2f +/- %8.2f)\n",
         404                 :               i+1, mClassName,
         405                 :               (PRInt32)mClassSize,
         406             773 :               (nsCRT::strcmp(mClassName, "TOTAL"))
         407                 :                   ?(PRUint64)((stats->mCreates - stats->mDestroys) * mClassSize)
         408                 :                   :mTotalLeaked,
         409                 :               stats->mCreates,
         410                 :               (stats->mCreates - stats->mDestroys),
         411                 :               meanObjs,
         412                 :               stddevObjs,
         413                 :               stats->mAddRefs,
         414                 :               (stats->mAddRefs - stats->mReleases),
         415                 :               meanRefs,
         416            1546 :               stddevRefs);
         417                 :     }
         418                 :   }
         419                 :
         420                 : protected:
         421                 :   char*         mClassName;
         422                 :   double        mClassSize;     // this is stored as a double because of the way we compute the avg class size for total bloat
         423                 :   PRUint64      mTotalLeaked; // used only for TOTAL entry
         424                 :   nsTraceRefcntStats mNewStats;
         425                 :   nsTraceRefcntStats mAllStats;
         426                 : };
         427                 :
         428                 : static void
         429          295526 : BloatViewFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
         430                 : {
         431          295526 :     if (flag == HT_FREE_ENTRY) {
         432          295526 :         BloatEntry* entry = reinterpret_cast<BloatEntry*>(he->value);
         433          295526 :         delete entry;
         434          295526 :         PR_Free(he);
         435                 :     }
         436          295526 : }
         437                 :
         438                 : const static PLHashAllocOps bloatViewHashAllocOps = {
         439                 :     DefaultAllocTable, DefaultFreeTable,
         440                 :     DefaultAllocEntry, BloatViewFreeEntry
         441                 : };
         442                 :
         443                 : static void
         444            1388 : RecreateBloatView()
         445                 : {
         446                 :   gBloatView = PL_NewHashTable(256,
         447                 :                                PL_HashString,
         448                 :                                PL_CompareStrings,
         449                 :                                PL_CompareValues,
         450            1388 :                                &bloatViewHashAllocOps, NULL);
         451            1388 : }
         452                 :
         453                 : static BloatEntry*
         454       212525351 : GetBloatEntry(const char* aTypeName, PRUint32 aInstanceSize)
         455                 : {
         456       212525351 :   if (!gBloatView) {
         457               0 :     RecreateBloatView();
         458                 :   }
         459       212525351 :   BloatEntry* entry = NULL;
         460       212525351 :   if (gBloatView) {
         461       212525351 :     entry = (BloatEntry*)PL_HashTableLookup(gBloatView, aTypeName);
         462       212525351 :     if (entry == NULL && aInstanceSize > 0) {
         463                 :
         464          295534 :       entry = new BloatEntry(aTypeName, aInstanceSize);
         465          295534 :       PLHashEntry* e = PL_HashTableAdd(gBloatView, aTypeName, entry);
         466          295534 :       if (e == NULL) {
         467               0 :         delete entry;
         468               0 :         entry = NULL;
         469          295534 :       }
         470                 :     } else {
         471       212229817 :       NS_ASSERTION(aInstanceSize == 0 ||
         472                 :                    entry->GetClassSize() == aInstanceSize,
         473                 :                    "bad size recorded");
         474                 :     }
         475                 :   }
         476       212525351 :   return entry;
         477                 : }
         478                 :
         479               0 : static PRIntn DumpSerialNumbers(PLHashEntry* aHashEntry, PRIntn aIndex, void* aClosure)
         480                 : {
         481               0 :   serialNumberRecord* record = reinterpret_cast<serialNumberRecord *>(aHashEntry->value);
         482                 : #ifdef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR
         483                 :   fprintf((FILE*) aClosure, "%d @%p (%d references; %d from COMPtrs)\n",
         484                 :                             record->serialNumber,
         485                 :                             NS_INT32_TO_PTR(aHashEntry->key),
         486                 :                             record->refCount,
         487               0 :                             record->COMPtrCount);
         488                 : #else
         489                 :   fprintf((FILE*) aClosure, "%d @%p (%d references)\n",
         490                 :                             record->serialNumber,
         491                 :                             NS_INT32_TO_PTR(aHashEntry->key),
         492                 :                             record->refCount);
         493                 : #endif
         494               0 :   return HT_ENUMERATE_NEXT;
         495                 : }
         496                 :
         497                 :
         498                 : template <>
         499                 : class nsDefaultComparator <BloatEntry*, BloatEntry*> {
         500                 :   public:
         501           26427 :     bool Equals(BloatEntry* const& aA, BloatEntry* const& aB) const {
         502           26427 :       return PL_strcmp(aA->GetClassName(), aB->GetClassName()) == 0;
         503                 :     }
         504           48496 :     bool LessThan(BloatEntry* const& aA, BloatEntry* const& aB) const {
         505           48496 :       return PL_strcmp(aA->GetClassName(), aB->GetClassName()) < 0;
         506                 :     }
         507                 : };
         508                 :
         509                 : #endif /* NS_IMPL_REFCNT_LOGGING */
         510                 :
         511                 : nsresult
         512            1388 : nsTraceRefcntImpl::DumpStatistics(StatisticsType type, FILE* out)
         513                 : {
         514                 : #ifdef NS_IMPL_REFCNT_LOGGING
         515            1388 :   if (gBloatLog == nsnull || gBloatView == nsnull) {
         516               1 :     return NS_ERROR_FAILURE;
         517                 :   }
         518            1387 :   if (out == nsnull) {
         519            1387 :     out = gBloatLog;
         520                 :   }
         521                 :
         522            1387 :   LOCK_TRACELOG();
         523                 :
         524            1387 :   bool wasLogging = gLogging;
         525            1387 :   gLogging = false;  // turn off logging for this method
         526                 :
         527            2774 :   BloatEntry total("TOTAL", 0);
         528            1387 :   PL_HashTableEnumerateEntries(gBloatView, BloatEntry::TotalEntries, &total);
         529                 :   const char* msg;
         530            1387 :   if (type == NEW_STATS) {
         531               0 :     if (gLogLeaksOnly)
         532               0 :       msg = "NEW (incremental) LEAK STATISTICS";
         533                 :     else
         534               0 :       msg = "NEW (incremental) LEAK AND BLOAT STATISTICS";
         535                 :   }
         536                 :   else {
         537            1387 :     if (gLogLeaksOnly)
         538            1365 :       msg = "ALL (cumulative) LEAK STATISTICS";
         539                 :     else
         540              22 :       msg = "ALL (cumulative) LEAK AND BLOAT STATISTICS";
         541                 :   }
         542            1387 :   const bool leaked = total.PrintDumpHeader(out, msg, type);
         543                 :
         544            2774 :   nsTArray<BloatEntry*> entries;
         545            1387 :   PL_HashTableEnumerateEntries(gBloatView, BloatEntry::DumpEntry, &entries);
         546            1387 :   const PRUint32 count = entries.Length();
         547                 :
         548            1387 :   if (!gLogLeaksOnly || leaked) {
         549                 :     // Sort the entries alphabetically by classname.
         550              42 :     entries.Sort();
         551                 :
         552            6070 :     for (PRUint32 i = 0; i < count; ++i) {
         553            6028 :       BloatEntry* entry = entries[i];
         554            6028 :       entry->Dump(i, out, type);
         555                 :     }
         556                 :
         557              42 :     fprintf(out, "\n");
         558                 :   }
         559                 :
         560            1387 :   fprintf(out, "nsTraceRefcntImpl::DumpStatistics: %d entries\n", count);
         561                 :
         562            1387 :   if (gSerialNumbers) {
         563               0 :     fprintf(out, "\nSerial Numbers of Leaked Objects:\n");
         564               0 :     PL_HashTableEnumerateEntries(gSerialNumbers, DumpSerialNumbers, out);
         565                 :   }
         566                 :
         567            1387 :   gLogging = wasLogging;
         568            1387 :   UNLOCK_TRACELOG();
         569                 : #endif
         570                 :
         571            1387 :   return NS_OK;
         572                 : }
         573                 :
         574                 : void
         575            1388 : nsTraceRefcntImpl::ResetStatistics()
         576                 : {
         577                 : #ifdef NS_IMPL_REFCNT_LOGGING
         578            1388 :   LOCK_TRACELOG();
         579            1388 :   if (gBloatView) {
         580            1387 :     PL_HashTableDestroy(gBloatView);
         581            1387 :     gBloatView = nsnull;
         582                 :   }
         583            1388 :   UNLOCK_TRACELOG();
         584                 : #endif
         585            1388 : }
         586                 :
         587                 : #ifdef NS_IMPL_REFCNT_LOGGING
         588               0 : static bool LogThisType(const char* aTypeName)
         589                 : {
         590               0 :   void* he = PL_HashTableLookup(gTypesToLog, aTypeName);
         591               0 :   return nsnull != he;
         592                 : }
         593                 :
         594               0 : static PRInt32 GetSerialNumber(void* aPtr, bool aCreate)
         595                 : {
         596               0 :   PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr);
         597               0 :   if (hep && *hep) {
         598               0 :     return PRInt32((reinterpret_cast<serialNumberRecord*>((*hep)->value))->serialNumber);
         599                 :   }
         600               0 :   else if (aCreate) {
         601               0 :     serialNumberRecord *record = PR_NEW(serialNumberRecord);
         602               0 :     record->serialNumber = ++gNextSerialNumber;
         603               0 :     record->refCount = 0;
         604               0 :     record->COMPtrCount = 0;
         605               0 :     PL_HashTableRawAdd(gSerialNumbers, hep, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr, reinterpret_cast<void*>(record));
         606               0 :     return gNextSerialNumber;
         607                 :   }
         608                 :   else {
         609               0 :     return 0;
         610                 :   }
         611                 : }
         612                 :
         613               0 : static PRInt32* GetRefCount(void* aPtr)
         614                 : {
         615               0 :   PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr);
         616               0 :   if (hep && *hep) {
         617               0 :     return &((reinterpret_cast<serialNumberRecord*>((*hep)->value))->refCount);
         618                 :   } else {
         619               0 :     return nsnull;
         620                 :   }
         621                 : }
         622                 :
         623               0 : static PRInt32* GetCOMPtrCount(void* aPtr)
         624                 : {
         625               0 :   PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr);
         626               0 :   if (hep && *hep) {
         627               0 :     return &((reinterpret_cast<serialNumberRecord*>((*hep)->value))->COMPtrCount);
         628                 :   } else {
         629               0 :     return nsnull;
         630                 :   }
         631                 : }
         632                 :
         633               0 : static void RecycleSerialNumberPtr(void* aPtr)
         634                 : {
         635               0 :   PL_HashTableRemove(gSerialNumbers, aPtr);
         636               0 : }
         637                 :
         638               0 : static bool LogThisObj(PRInt32 aSerialNumber)
         639                 : {
         640               0 :   return nsnull != PL_HashTableLookup(gObjectsToLog, (const void*)(aSerialNumber));
         641                 : }
         642                 :
         643                 : #ifdef XP_WIN
         644                 : #define FOPEN_NO_INHERIT "N"
         645                 : #else
         646                 : #define FOPEN_NO_INHERIT
         647                 : #endif
         648                 :
         649            6923 : static bool InitLog(const char* envVar, const char* msg, FILE* *result)
         650                 : {
         651            6923 :   const char* value = getenv(envVar);
         652            6923 :   if (value) {
         653            1389 :     if (nsCRT::strcmp(value, "1") == 0) {
         654               0 :       *result = stdout;
         655                 :       fprintf(stdout, "### %s defined -- logging %s to stdout\n",
         656               0 :               envVar, msg);
         657               0 :       return true;
         658                 :     }
         659            1389 :     else if (nsCRT::strcmp(value, "2") == 0) {
         660               0 :       *result = stderr;
         661                 :       fprintf(stdout, "### %s defined -- logging %s to stderr\n",
         662               0 :               envVar, msg);
         663               0 :       return true;
         664                 :     }
         665                 :     else {
         666                 :       FILE *stream;
         667            2778 :       nsCAutoString fname(value);
         668            1389 :       if (XRE_GetProcessType() != GeckoProcessType_Default) {
         669                 :         bool hasLogExtension =
         670               1 :             fname.RFind(".log", true, -1, 4) == kNotFound ? false : true;
         671               1 :         if (hasLogExtension)
         672               1 :           fname.Cut(fname.Length() - 4, 4);
         673               1 :         fname.AppendLiteral("_");
         674               1 :         fname.Append((char*)XRE_ChildProcessTypeToString(XRE_GetProcessType()));
         675               1 :         fname.AppendLiteral("_pid");
         676               1 :         fname.AppendInt((PRUint32)getpid());
         677               1 :         if (hasLogExtension)
         678               1 :           fname.AppendLiteral(".log");
         679                 :       }
         680            1389 :       stream = ::fopen(fname.get(), "w" FOPEN_NO_INHERIT);
         681            1389 :       if (stream != NULL) {
         682            1388 :         *result = stream;
         683                 :         fprintf(stdout, "### %s defined -- logging %s to %s\n",
         684            1388 :                 envVar, msg, fname.get());
         685                 :       }
         686                 :       else {
         687                 :         fprintf(stdout, "### %s defined -- unable to log %s to %s\n",
         688               1 :                 envVar, msg, fname.get());
         689                 :       }
         690            1389 :       return stream != NULL;
         691                 :     }
         692                 :   }
         693            5534 :   return false;
         694                 : }
         695                 :
         696                 :
         697               0 : static PLHashNumber HashNumber(const void* aKey)
         698                 : {
         699               0 :   return PLHashNumber(NS_PTR_TO_INT32(aKey));
         700                 : }
         701                 :
         702            1389 : static void InitTraceLog(void)
         703                 : {
         704            1389 :   if (gInitialized) return;
         705            1389 :   gInitialized = true;
         706                 :
         707                 :   bool defined;
         708            1389 :   defined = InitLog("XPCOM_MEM_BLOAT_LOG", "bloat/leaks", &gBloatLog);
         709            1389 :   if (!defined)
         710            1367 :     gLogLeaksOnly = InitLog("XPCOM_MEM_LEAK_LOG", "leaks", &gBloatLog);
         711            1389 :   if (defined || gLogLeaksOnly) {
         712            1388 :     RecreateBloatView();
         713            1388 :     if (!gBloatView) {
         714               0 :       NS_WARNING("out of memory");
         715               0 :       gBloatLog = nsnull;
         716               0 :       gLogLeaksOnly = false;
         717                 :     }
         718                 :   }
         719                 :
         720            1389 :   (void)InitLog("XPCOM_MEM_REFCNT_LOG", "refcounts", &gRefcntsLog);
         721                 :
         722            1389 :   (void)InitLog("XPCOM_MEM_ALLOC_LOG", "new/delete", &gAllocLog);
         723                 :
         724            1389 :   defined = InitLog("XPCOM_MEM_LEAKY_LOG", "for leaky", &gLeakyLog);
         725            1389 :   if (defined) {
         726               0 :     gLogToLeaky = true;
         727               0 :     PRFuncPtr p = nsnull, q = nsnull;
         728                 : #ifdef HAVE_DLOPEN
         729                 :     {
         730               0 :       PRLibrary *lib = nsnull;
         731               0 :       p = PR_FindFunctionSymbolAndLibrary("__log_addref", &lib);
         732               0 :       if (lib) {
         733               0 :         PR_UnloadLibrary(lib);
         734               0 :         lib = nsnull;
         735                 :       }
         736               0 :       q = PR_FindFunctionSymbolAndLibrary("__log_release", &lib);
         737               0 :       if (lib) {
         738               0 :         PR_UnloadLibrary(lib);
         739                 :       }
         740                 :     }
         741                 : #endif
         742               0 :     if (p && q) {
         743               0 :       leakyLogAddRef = (void (*)(void*,int,int)) p;
         744               0 :       leakyLogRelease = (void (*)(void*,int,int)) q;
         745                 :     }
         746                 :     else {
         747               0 :       gLogToLeaky = false;
         748               0 :       fprintf(stdout, "### ERROR: XPCOM_MEM_LEAKY_LOG defined, but can't locate __log_addref and __log_release symbols\n");
         749               0 :       fflush(stdout);
         750                 :     }
         751                 :   }
         752                 :
         753            1389 :   const char* classes = getenv("XPCOM_MEM_LOG_CLASSES");
         754                 :
         755                 : #ifdef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR
         756            1389 :   if (classes) {
         757               0 :     (void)InitLog("XPCOM_MEM_COMPTR_LOG", "nsCOMPtr", &gCOMPtrLog);
         758                 :   } else {
         759            1389 :     if (getenv("XPCOM_MEM_COMPTR_LOG")) {
         760               0 :       fprintf(stdout, "### XPCOM_MEM_COMPTR_LOG defined -- but XPCOM_MEM_LOG_CLASSES is not defined\n");
         761                 :     }
         762                 :   }
         763                 : #else
         764                 :   const char* comptr_log = getenv("XPCOM_MEM_COMPTR_LOG");
         765                 :   if (comptr_log) {
         766                 :     fprintf(stdout, "### XPCOM_MEM_COMPTR_LOG defined -- but it will not work without dynamic_cast\n");
         767                 :   }
         768                 : #endif
         769                 :
         770            1389 :   if (classes) {
         771                 :     // if XPCOM_MEM_LOG_CLASSES was set to some value, the value is interpreted
         772                 :     // as a list of class names to track
         773                 :     gTypesToLog = PL_NewHashTable(256,
         774                 :                                   PL_HashString,
         775                 :                                   PL_CompareStrings,
         776                 :                                   PL_CompareValues,
         777               0 :                                   &typesToLogHashAllocOps, NULL);
         778               0 :     if (!gTypesToLog) {
         779               0 :       NS_WARNING("out of memory");
         780               0 :       fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- unable to log specific classes\n");
         781                 :     }
         782                 :     else {
         783               0 :       fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- only logging these classes: ");
         784               0 :       const char* cp = classes;
         785               0 :       for (;;) {
         786               0 :         char* cm = (char*) strchr(cp, ',');
         787               0 :         if (cm) {
         788               0 :           *cm = '\0';
         789                 :         }
         790               0 :         PL_HashTableAdd(gTypesToLog, nsCRT::strdup(cp), (void*)1);
         791               0 :         fprintf(stdout, "%s ", cp);
         792               0 :         if (!cm) break;
         793               0 :         *cm = ',';
         794               0 :         cp = cm + 1;
         795                 :       }
         796               0 :       fprintf(stdout, "\n");
         797                 :     }
         798                 :
         799                 :     gSerialNumbers = PL_NewHashTable(256,
         800                 :                                      HashNumber,
         801                 :                                      PL_CompareValues,
         802                 :                                      PL_CompareValues,
         803               0 :                                      &serialNumberHashAllocOps, NULL);
         804                 :
         805                 :
         806                 :   }
         807                 :
         808            1389 :   const char* objects = getenv("XPCOM_MEM_LOG_OBJECTS");
         809            1389 :   if (objects) {
         810                 :     gObjectsToLog = PL_NewHashTable(256,
         811                 :                                     HashNumber,
         812                 :                                     PL_CompareValues,
         813                 :                                     PL_CompareValues,
         814               0 :                                     NULL, NULL);
         815                 :
         816               0 :     if (!gObjectsToLog) {
         817               0 :       NS_WARNING("out of memory");
         818               0 :       fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- unable to log specific objects\n");
         819                 :     }
         820               0 :     else if (! (gRefcntsLog || gAllocLog || gCOMPtrLog)) {
         821               0 :       fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- but none of XPCOM_MEM_(REFCNT|ALLOC|COMPTR)_LOG is defined\n");
         822                 :     }
         823                 :     else {
         824               0 :       fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- only logging these objects: ");
         825               0 :       const char* cp = objects;
         826               0 :       for (;;) {
         827               0 :         char* cm = (char*) strchr(cp, ',');
         828               0 :         if (cm) {
         829               0 :           *cm = '\0';
         830                 :         }
         831               0 :         PRInt32 top = 0;
         832               0 :         PRInt32 bottom = 0;
         833               0 :         while (*cp) {
         834               0 :           if (*cp == '-') {
         835               0 :             bottom = top;
         836               0 :             top = 0;
         837               0 :             ++cp;
         838                 :           }
         839               0 :           top *= 10;
         840               0 :           top += *cp - '0';
         841               0 :           ++cp;
         842                 :         }
         843               0 :         if (!bottom) {
         844               0 :           bottom = top;
         845                 :         }
         846               0 :         for(PRInt32 serialno = bottom; serialno <= top; serialno++) {
         847               0 :           PL_HashTableAdd(gObjectsToLog, (const void*)serialno, (void*)1);
         848               0 :           fprintf(stdout, "%d ", serialno);
         849                 :         }
         850               0 :         if (!cm) break;
         851               0 :         *cm = ',';
         852               0 :         cp = cm + 1;
         853                 :       }
         854               0 :       fprintf(stdout, "\n");
         855                 :     }
         856                 :   }
         857                 :
         858                 :
         859            1389 :   if (gBloatLog || gRefcntsLog || gAllocLog || gLeakyLog || gCOMPtrLog) {
         860            1388 :     gLogging = true;
         861                 :   }
         862                 :
         863            1389 :   gTraceLock = PR_NewLock();
         864                 : }
         865                 :
         866                 : #endif
         867                 :
         868                 : extern "C" {
         869                 :
         870               0 : static void PrintStackFrame(void *aPC, void *aClosure)
         871                 : {
         872               0 :   FILE *stream = (FILE*)aClosure;
         873                 :   nsCodeAddressDetails details;
         874                 :   char buf[1024];
         875                 :
         876               0 :   NS_DescribeCodeAddress(aPC, &details);
         877               0 :   NS_FormatCodeAddressDetails(aPC, &details, buf, sizeof(buf));
         878               0 :   fputs(buf, stream);
         879               0 : }
         880                 :
         881                 : }
         882                 :
         883                 : void
         884               0 : nsTraceRefcntImpl::WalkTheStack(FILE* aStream)
         885                 : {
         886               0 :   NS_StackWalk(PrintStackFrame, 2, aStream, 0);
         887               0 : }
         888                 :
         889                 : //----------------------------------------------------------------------
         890                 :
         891                 : // This thing is exported by libstdc++
         892                 : // Yes, this is a gcc only hack
         893                 : #if defined(MOZ_DEMANGLE_SYMBOLS)
         894                 : #include <cxxabi.h>
         895                 : #include <stdlib.h> // for free()
         896                 : #endif // MOZ_DEMANGLE_SYMBOLS
         897                 :
         898                 : void
         899               0 : nsTraceRefcntImpl::DemangleSymbol(const char * aSymbol,
         900                 :                               char * aBuffer,
         901                 :                               int aBufLen)
         902                 : {
         903               0 :   NS_ASSERTION(nsnull != aSymbol,"null symbol");
         904               0 :   NS_ASSERTION(nsnull != aBuffer,"null buffer");
         905               0 :   NS_ASSERTION(aBufLen >= 32 ,"pulled 32 out of you know where");
         906                 :
         907               0 :   aBuffer[0] = '\0';
         908                 :
         909                 : #if defined(MOZ_DEMANGLE_SYMBOLS)
         910                 :  /* See demangle.h in the gcc source for the voodoo */
         911               0 :   char * demangled = abi::__cxa_demangle(aSymbol,0,0,0);
         912                 :
         913               0 :   if (demangled)
         914                 :   {
         915               0 :     strncpy(aBuffer,demangled,aBufLen);
         916               0 :     free(demangled);
         917                 :   }
         918                 : #endif // MOZ_DEMANGLE_SYMBOLS
         919               0 : }
         920                 :
         921                 :
         922                 : //----------------------------------------------------------------------
         923                 :
         924                 : EXPORT_XPCOM_API(void)
         925            2778 : NS_LogInit()
         926                 : {
         927                 :   // FIXME: This is called multiple times, we should probably not allow that.
         928            2778 :   StackWalkInitCriticalAddress();
         929                 : #ifdef NS_IMPL_REFCNT_LOGGING
         930            2778 :   if (++gInitCount)
         931            2778 :     nsTraceRefcntImpl::SetActivityIsLegal(true);
         932                 : #endif
         933                 :
         934                 : #ifdef NS_TRACE_MALLOC
         935                 :   // XXX we don't have to worry about shutting down trace-malloc; it
         936                 :   // handles this itself, through an atexit() callback.
         937                 :   if (!NS_TraceMallocHasStarted())
         938                 :     NS_TraceMallocStartup(-1);  // -1 == no logging
         939                 : #endif
         940            2778 : }
         941                 :
         942                 : EXPORT_XPCOM_API(void)
         943            2776 : NS_LogTerm()
         944                 : {
         945            2776 :   mozilla::LogTerm();
         946            2776 : }
         947                 :
         948                 : namespace mozilla {
         949                 : void
         950            2776 : LogTerm()
         951                 : {
         952            2776 :   NS_ASSERTION(gInitCount > 0,
         953                 :                "NS_LogTerm without matching NS_LogInit");
         954                 :
         955            2776 :   if (--gInitCount == 0) {
         956                 : #ifdef DEBUG
         957                 :     /* FIXME bug 491977: This is only going to operate on the
         958                 :      * BlockingResourceBase which is compiled into
         959                 :      * libxul/libxpcom_core.so. Anyone using external linkage will
         960                 :      * have their own copy of BlockingResourceBase statics which will
         961                 :      * not be freed by this method.
         962                 :      *
         963                 :      * It sounds like what we really want is to be able to register a
         964                 :      * callback function to call at XPCOM shutdown.  Note that with
         965                 :      * this solution, however, we need to guarantee that
         966                 :      * BlockingResourceBase::Shutdown() runs after all other shutdown
         967                 :      * functions.
         968                 :      */
         969            1388 :     BlockingResourceBase::Shutdown();
         970                 : #endif
         971                 :
         972            1388 :     if (gInitialized) {
         973            1388 :       nsTraceRefcntImpl::DumpStatistics();
         974            1388 :       nsTraceRefcntImpl::ResetStatistics();
         975                 :     }
         976            1388 :     nsTraceRefcntImpl::Shutdown();
         977                 : #ifdef NS_IMPL_REFCNT_LOGGING
         978            1388 :     nsTraceRefcntImpl::SetActivityIsLegal(false);
         979            1388 :     gActivityTLS = BAD_TLS_INDEX;
         980                 : #endif
         981                 :   }
         982            2776 : }
         983                 :
         984                 : } // namespace mozilla
         985                 :
         986                 : EXPORT_XPCOM_API(void)
         987        88911500 : NS_LogAddRef(void* aPtr, nsrefcnt aRefcnt,
         988                 :              const char* aClazz, PRUint32 classSize)
         989                 : {
         990                 : #ifdef NS_IMPL_REFCNT_LOGGING
         991        88911500 :   ASSERT_ACTIVITY_IS_LEGAL;
         992        88911499 :   if (!gInitialized)
         993            1389 :     InitTraceLog();
         994        88911500 :   if (gLogging) {
         995        88911470 :     LOCK_TRACELOG();
         996                 :
         997        88911470 :     if (gBloatLog) {
         998        88911470 :       BloatEntry* entry = GetBloatEntry(aClazz, classSize);
         999        88911470 :       if (entry) {
        1000        88911470 :         entry->AddRef(aRefcnt);
        1001                 :       }
        1002                 :     }
        1003                 :
        1004                 :     // Here's the case where MOZ_COUNT_CTOR was not used,
        1005                 :     // yet we still want to see creation information:
        1006                 :
        1007        88911470 :     bool loggingThisType = (!gTypesToLog || LogThisType(aClazz));
        1008        88911470 :     PRInt32 serialno = 0;
        1009        88911470 :     if (gSerialNumbers && loggingThisType) {
        1010               0 :       serialno = GetSerialNumber(aPtr, aRefcnt == 1);
        1011               0 :       NS_ASSERTION(serialno != 0,
        1012                 :                    "Serial number requested for unrecognized pointer!  "
        1013                 :                    "Are you memmoving a refcounted object?");
        1014               0 :       PRInt32* count = GetRefCount(aPtr);
        1015               0 :       if(count)
        1016               0 :         (*count)++;
        1017                 :
        1018                 :     }
        1019                 :
        1020        88911470 :     bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
        1021        88911470 :     if (aRefcnt == 1 && gAllocLog && loggingThisType && loggingThisObject) {
        1022                 :       fprintf(gAllocLog, "\n<%s> 0x%08X %d Create\n",
        1023               0 :               aClazz, NS_PTR_TO_INT32(aPtr), serialno);
        1024               0 :       nsTraceRefcntImpl::WalkTheStack(gAllocLog);
        1025                 :     }
        1026                 :
        1027        88911470 :     if (gRefcntsLog && loggingThisType && loggingThisObject) {
        1028               0 :       if (gLogToLeaky) {
        1029               0 :         (*leakyLogAddRef)(aPtr, aRefcnt - 1, aRefcnt);
        1030                 :       }
        1031                 :       else {
        1032                 :           // Can't use PR_LOG(), b/c it truncates the line
        1033                 :           fprintf(gRefcntsLog,
        1034               0 :                   "\n<%s> 0x%08X %d AddRef %d\n", aClazz, NS_PTR_TO_INT32(aPtr), serialno, aRefcnt);
        1035               0 :           nsTraceRefcntImpl::WalkTheStack(gRefcntsLog);
        1036               0 :           fflush(gRefcntsLog);
        1037                 :       }
        1038                 :     }
        1039        88911470 :     UNLOCK_TRACELOG();
        1040                 :   }
        1041                 : #endif
        1042        88911495 : }
        1043                 :
        1044                 : EXPORT_XPCOM_API(void)
        1045        88897687 : NS_LogRelease(void* aPtr, nsrefcnt aRefcnt, const char* aClazz)
        1046                 : {
        1047                 : #ifdef NS_IMPL_REFCNT_LOGGING
        1048        88897687 :   ASSERT_ACTIVITY_IS_LEGAL;
        1049        88895420 :   if (!gInitialized)
        1050               0 :     InitTraceLog();
        1051        88897655 :   if (gLogging) {
        1052        88897625 :     LOCK_TRACELOG();
        1053                 :
        1054        88897657 :     if (gBloatLog) {
        1055        88897657 :       BloatEntry* entry = GetBloatEntry(aClazz, 0);
        1056        88897657 :       if (entry) {
        1057        88897657 :         entry->Release(aRefcnt);
        1058                 :       }
        1059                 :     }
        1060                 :
        1061        88897657 :     bool loggingThisType = (!gTypesToLog || LogThisType(aClazz));
        1062        88897657 :     PRInt32 serialno = 0;
        1063        88897657 :     if (gSerialNumbers && loggingThisType) {
        1064               0 :       serialno = GetSerialNumber(aPtr, false);
        1065               0 :       NS_ASSERTION(serialno != 0,
        1066                 :                    "Serial number requested for unrecognized pointer!  "
        1067                 :                    "Are you memmoving a refcounted object?");
        1068               0 :       PRInt32* count = GetRefCount(aPtr);
        1069               0 :       if(count)
        1070               0 :         (*count)--;
        1071                 :
        1072                 :     }
        1073                 :
        1074        88897657 :     bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
        1075        88897657 :     if (gRefcntsLog && loggingThisType && loggingThisObject) {
        1076               0 :       if (gLogToLeaky) {
        1077               0 :         (*leakyLogRelease)(aPtr, aRefcnt + 1, aRefcnt);
        1078                 :       }
        1079                 :       else {
        1080                 :           // Can't use PR_LOG(), b/c it truncates the line
        1081                 :           fprintf(gRefcntsLog,
        1082               0 :                   "\n<%s> 0x%08X %d Release %d\n", aClazz, NS_PTR_TO_INT32(aPtr), serialno, aRefcnt);
        1083               0 :           nsTraceRefcntImpl::WalkTheStack(gRefcntsLog);
        1084               0 :           fflush(gRefcntsLog);
        1085                 :       }
        1086                 :     }
        1087                 :
        1088                 :     // Here's the case where MOZ_COUNT_DTOR was not used,
        1089                 :     // yet we still want to see deletion information:
        1090                 :
        1091        88897657 :     if (aRefcnt == 0 && gAllocLog && loggingThisType && loggingThisObject) {
        1092                 :       fprintf(gAllocLog,
        1093                 :               "\n<%s> 0x%08X %d Destroy\n",
        1094               0 :               aClazz, NS_PTR_TO_INT32(aPtr), serialno);
        1095               0 :       nsTraceRefcntImpl::WalkTheStack(gAllocLog);
        1096                 :     }
        1097                 :
        1098        88897657 :     if (aRefcnt == 0 && gSerialNumbers && loggingThisType) {
        1099               0 :       RecycleSerialNumberPtr(aPtr);
        1100                 :     }
        1101                 :
        1102        88897657 :     UNLOCK_TRACELOG();
        1103                 :   }
        1104                 : #endif
        1105        88897687 : }
        1106                 :
        1107                 : EXPORT_XPCOM_API(void)
        1108        17360899 : NS_LogCtor(void* aPtr, const char* aType, PRUint32 aInstanceSize)
        1109                 : {
        1110                 : #ifdef NS_IMPL_REFCNT_LOGGING
        1111        17360899 :   ASSERT_ACTIVITY_IS_LEGAL;
        1112        17360899 :   if (!gInitialized)
        1113               0 :     InitTraceLog();
        1114                 :
        1115        17360900 :   if (gLogging) {
        1116        17359507 :     LOCK_TRACELOG();
        1117                 :
        1118        17359507 :     if (gBloatLog) {
        1119        17359507 :       BloatEntry* entry = GetBloatEntry(aType, aInstanceSize);
        1120        17359507 :       if (entry) {
        1121        17359507 :         entry->Ctor();
        1122                 :       }
        1123                 :     }
        1124                 :
        1125        17359507 :     bool loggingThisType = (!gTypesToLog || LogThisType(aType));
        1126        17359507 :     PRInt32 serialno = 0;
        1127        17359507 :     if (gSerialNumbers && loggingThisType) {
        1128               0 :       serialno = GetSerialNumber(aPtr, true);
        1129                 :     }
        1130                 :
        1131        17359507 :     bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
        1132        17359507 :     if (gAllocLog && loggingThisType && loggingThisObject) {
        1133                 :       fprintf(gAllocLog, "\n<%s> 0x%08X %d Ctor (%d)\n",
        1134               0 :              aType, NS_PTR_TO_INT32(aPtr), serialno, aInstanceSize);
        1135               0 :       nsTraceRefcntImpl::WalkTheStack(gAllocLog);
        1136                 :     }
        1137                 :
        1138        17359507 :     UNLOCK_TRACELOG();
        1139                 :   }
        1140                 : #endif
        1141        17360900 : }
        1142                 :
        1143                 :
        1144                 : EXPORT_XPCOM_API(void)
        1145        17356723 : NS_LogDtor(void* aPtr, const char* aType, PRUint32 aInstanceSize)
        1146                 : {
        1147                 : #ifdef NS_IMPL_REFCNT_LOGGING
        1148        17356723 :   ASSERT_ACTIVITY_IS_LEGAL;
        1149        17356723 :   if (!gInitialized)
        1150               0 :     InitTraceLog();
        1151                 :
        1152        17356723 :   if (gLogging) {
        1153        17356717 :     LOCK_TRACELOG();
        1154                 :
        1155        17356717 :     if (gBloatLog) {
        1156        17356717 :       BloatEntry* entry = GetBloatEntry(aType, aInstanceSize);
        1157        17356717 :       if (entry) {
        1158        17356717 :         entry->Dtor();
        1159                 :       }
        1160                 :     }
        1161                 :
        1162        17356717 :     bool loggingThisType = (!gTypesToLog || LogThisType(aType));
        1163        17356717 :     PRInt32 serialno = 0;
        1164        17356717 :     if (gSerialNumbers && loggingThisType) {
        1165               0 :       serialno = GetSerialNumber(aPtr, false);
        1166               0 :       RecycleSerialNumberPtr(aPtr);
        1167                 :     }
        1168                 :
        1169        17356717 :     bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
        1170                 :
        1171                 :     // (If we're on a losing architecture, don't do this because we'll be
        1172                 :     // using LogDeleteXPCOM instead to get file and line numbers.)
        1173        17356717 :     if (gAllocLog && loggingThisType && loggingThisObject) {
        1174                 :       fprintf(gAllocLog, "\n<%s> 0x%08X %d Dtor (%d)\n",
        1175               0 :              aType, NS_PTR_TO_INT32(aPtr), serialno, aInstanceSize);
        1176               0 :       nsTraceRefcntImpl::WalkTheStack(gAllocLog);
        1177                 :     }
        1178                 :
        1179        17356717 :     UNLOCK_TRACELOG();
        1180                 :   }
        1181                 : #endif
        1182        17356723 : }
        1183                 :
        1184                 :
        1185                 : EXPORT_XPCOM_API(void)
        1186        51630506 : NS_LogCOMPtrAddRef(void* aCOMPtr, nsISupports* aObject)
        1187                 : {
        1188                 : #if defined(NS_IMPL_REFCNT_LOGGING) && defined(HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR)
        1189                 :   // Get the most-derived object.
        1190        51630506 :   void *object = dynamic_cast<void *>(aObject);
        1191                 :
        1192                 :   // This is a very indirect way of finding out what the class is
        1193                 :   // of the object being logged.  If we're logging a specific type,
        1194                 :   // then
        1195        51630506 :   if (!gTypesToLog || !gSerialNumbers) {
        1196        51630506 :     return;
        1197                 :   }
        1198               0 :   PRInt32 serialno = GetSerialNumber(object, false);
        1199               0 :   if (serialno == 0) {
        1200               0 :     return;
        1201                 :   }
        1202                 :
        1203               0 :   if (!gInitialized)
        1204               0 :     InitTraceLog();
        1205               0 :   if (gLogging) {
        1206               0 :     LOCK_TRACELOG();
        1207                 :
        1208               0 :     PRInt32* count = GetCOMPtrCount(object);
        1209               0 :     if(count)
        1210               0 :       (*count)++;
        1211                 :
        1212               0 :     bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
        1213                 :
        1214               0 :     if (gCOMPtrLog && loggingThisObject) {
        1215                 :       fprintf(gCOMPtrLog, "\n<?> 0x%08X %d nsCOMPtrAddRef %d 0x%08X\n",
        1216               0 :               NS_PTR_TO_INT32(object), serialno, count?(*count):-1, NS_PTR_TO_INT32(aCOMPtr));
        1217               0 :       nsTraceRefcntImpl::WalkTheStack(gCOMPtrLog);
        1218                 :     }
        1219                 :
        1220               0 :     UNLOCK_TRACELOG();
        1221                 :   }
        1222                 : #endif
        1223                 : }
        1224                 :
        1225                 :
        1226                 : EXPORT_XPCOM_API(void)
        1227        51416493 : NS_LogCOMPtrRelease(void* aCOMPtr, nsISupports* aObject)
        1228                 : {
        1229                 : #if defined(NS_IMPL_REFCNT_LOGGING) && defined(HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR)
        1230                 :   // Get the most-derived object.
        1231        51416493 :   void *object = dynamic_cast<void *>(aObject);
        1232                 :
        1233                 :   // This is a very indirect way of finding out what the class is
        1234                 :   // of the object being logged.  If we're logging a specific type,
        1235                 :   // then
        1236        51416493 :   if (!gTypesToLog || !gSerialNumbers) {
        1237        51416493 :     return;
        1238                 :   }
        1239               0 :   PRInt32 serialno = GetSerialNumber(object, false);
        1240               0 :   if (serialno == 0) {
        1241               0 :     return;
        1242                 :   }
        1243                 :
        1244               0 :   if (!gInitialized)
        1245               0 :     InitTraceLog();
        1246               0 :   if (gLogging) {
        1247               0 :     LOCK_TRACELOG();
        1248                 :
        1249               0 :     PRInt32* count = GetCOMPtrCount(object);
        1250               0 :     if(count)
        1251               0 :       (*count)--;
        1252                 :
        1253               0 :     bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
        1254                 :
        1255               0 :     if (gCOMPtrLog && loggingThisObject) {
        1256                 :       fprintf(gCOMPtrLog, "\n<?> 0x%08X %d nsCOMPtrRelease %d 0x%08X\n",
        1257               0 :               NS_PTR_TO_INT32(object), serialno, count?(*count):-1, NS_PTR_TO_INT32(aCOMPtr));
        1258               0 :       nsTraceRefcntImpl::WalkTheStack(gCOMPtrLog);
        1259                 :     }
        1260                 :
        1261               0 :     UNLOCK_TRACELOG();
        1262                 :   }
        1263                 : #endif
        1264                 : }
        1265                 :
        1266                 : void
        1267               0 : nsTraceRefcntImpl::Startup()
        1268                 : {
        1269               0 : }
        1270                 :
        1271                 : void
        1272            1388 : nsTraceRefcntImpl::Shutdown()
        1273                 : {
        1274                 : #ifdef NS_IMPL_REFCNT_LOGGING
        1275                 :
        1276            1388 :   if (gBloatView) {
        1277               0 :     PL_HashTableDestroy(gBloatView);
        1278               0 :     gBloatView = nsnull;
        1279                 :   }
        1280            1388 :   if (gTypesToLog) {
        1281               0 :     PL_HashTableDestroy(gTypesToLog);
        1282               0 :     gTypesToLog = nsnull;
        1283                 :   }
        1284            1388 :   if (gObjectsToLog) {
        1285               0 :     PL_HashTableDestroy(gObjectsToLog);
        1286               0 :     gObjectsToLog = nsnull;
        1287                 :   }
        1288            1388 :   if (gSerialNumbers) {
        1289               0 :     PL_HashTableDestroy(gSerialNumbers);
        1290               0 :     gSerialNumbers = nsnull;
        1291                 :   }
        1292            1388 :   if (gBloatLog) {
        1293            1387 :     fclose(gBloatLog);
        1294            1387 :     gBloatLog = nsnull;
        1295                 :   }
        1296            1388 :   if (gRefcntsLog) {
        1297               0 :     fclose(gRefcntsLog);
        1298               0 :     gRefcntsLog = nsnull;
        1299                 :   }
        1300            1388 :   if (gAllocLog) {
        1301               0 :     fclose(gAllocLog);
        1302               0 :     gAllocLog = nsnull;
        1303                 :   }
        1304            1388 :   if (gLeakyLog) {
        1305               0 :     fclose(gLeakyLog);
        1306               0 :     gLeakyLog = nsnull;
        1307                 :   }
        1308            1388 :   if (gCOMPtrLog) {
        1309               0 :     fclose(gCOMPtrLog);
        1310               0 :     gCOMPtrLog = nsnull;
        1311                 :   }
        1312                 : #endif
        1313            1388 : }
        1314                 :
        1315                 : void
        1316           26024 : nsTraceRefcntImpl::SetActivityIsLegal(bool aLegal)
        1317                 : {
        1318                 : #ifdef NS_IMPL_REFCNT_LOGGING
        1319           26024 :   if (gActivityTLS == BAD_TLS_INDEX)
        1320            1389 :     PR_NewThreadPrivateIndex(&gActivityTLS, nsnull);
        1321                 :
        1322           26024 :   PR_SetThreadPrivate(gActivityTLS, NS_INT32_TO_PTR(!aLegal));
        1323                 : #endif
        1324           26024 : }
        1325                 :
        1326               0 : NS_IMPL_QUERY_INTERFACE1(nsTraceRefcntImpl, nsITraceRefcnt)
        1327                 :
        1328               0 : NS_IMETHODIMP_(nsrefcnt) nsTraceRefcntImpl::AddRef(void)
        1329                 : {
        1330               0 :   return 2;
        1331                 : }
        1332                 :
        1333               0 : NS_IMETHODIMP_(nsrefcnt) nsTraceRefcntImpl::Release(void)
        1334                 : {
        1335               0 :   return 1;
        1336                 : }
        1337                 :
        1338                 : NS_IMETHODIMP
        1339               0 : nsTraceRefcntImpl::LogAddRef(void *aPtr, nsrefcnt aNewRefcnt,
        1340                 :                              const char *aTypeName, PRUint32 aSize)
        1341                 : {
        1342               0 :   NS_LogAddRef(aPtr, aNewRefcnt, aTypeName, aSize);
        1343               0 :   return NS_OK;
        1344                 : }
        1345                 :
        1346                 : NS_IMETHODIMP
        1347               0 : nsTraceRefcntImpl::LogRelease(void *aPtr, nsrefcnt aNewRefcnt,
        1348                 :                               const char *aTypeName)
        1349                 : {
        1350               0 :   NS_LogRelease(aPtr, aNewRefcnt, aTypeName);
        1351               0 :   return NS_OK;
        1352                 : }
        1353                 :
        1354                 : NS_IMETHODIMP
        1355               0 : nsTraceRefcntImpl::LogCtor(void *aPtr, const char *aTypeName, PRUint32 aSize)
        1356                 : {
        1357               0 :   NS_LogCtor(aPtr, aTypeName, aSize);
        1358               0 :   return NS_OK;
        1359                 : }
        1360                 :
        1361                 : NS_IMETHODIMP
        1362               0 : nsTraceRefcntImpl::LogDtor(void *aPtr, const char *aTypeName, PRUint32 aSize)
        1363                 : {
        1364               0 :   NS_LogDtor(aPtr, aTypeName, aSize);
        1365               0 :   return NS_OK;
        1366                 : }
        1367                 :
        1368                 : NS_IMETHODIMP
        1369               0 : nsTraceRefcntImpl::LogAddCOMPtr(void *aCOMPtr, nsISupports* aObject)
        1370                 : {
        1371               0 :   NS_LogCOMPtrAddRef(aCOMPtr, aObject);
        1372               0 :   return NS_OK;
        1373                 : }
        1374                 :
        1375                 : NS_IMETHODIMP
        1376               0 : nsTraceRefcntImpl::LogReleaseCOMPtr(void *aCOMPtr, nsISupports* aObject)
        1377                 : {
        1378               0 :   NS_LogCOMPtrRelease(aCOMPtr, aObject);
        1379               0 :   return NS_OK;
        1380                 : }
        1381                 :
        1382            1396 : static const nsTraceRefcntImpl kTraceRefcntImpl;
        1383                 :
        1384                 : NS_METHOD
        1385               0 : nsTraceRefcntImpl::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr)
        1386                 : {
        1387                 :   return const_cast<nsTraceRefcntImpl*>(&kTraceRefcntImpl)->
        1388               0 :     QueryInterface(aIID, aInstancePtr);
        1389            4188 : }

Generated by: LCOV version 1.7