LCOV - code coverage report
Current view: directory - xpcom/base - nsTraceRefcntImpl.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 614 356 58.0 %
Date: 2012-06-02 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            1540 : NS_MeanAndStdDev(double n, double sumOfValues, double sumOfSquaredValues,
      79                 :                  double *meanResult, double *stdDevResult)
      80                 : {
      81            1540 :   double mean = 0.0, var = 0.0, stdDev = 0.0;
      82            1540 :   if (n > 0.0 && sumOfValues >= 0) {
      83            1324 :     mean = sumOfValues / n;
      84            1324 :     double temp = (n * sumOfSquaredValues) - (sumOfValues * sumOfValues);
      85            1324 :     if (temp < 0.0 || n <= 1)
      86             180 :       var = 0.0;
      87                 :     else
      88            1144 :       var = temp / (n * (n - 1));
      89                 :     // for some reason, Windows says sqrt(0.0) is "-1.#J" (?!) so do this:
      90            1324 :     stdDev = var != 0.0 ? sqrt(var) : 0.0;
      91                 :   }
      92            1540 :   *meanResult = mean;
      93            1540 :   *stdDevResult = stdDev;
      94            1540 : }
      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       212092067 : AssertActivityIsLegal()
     167                 : {
     168       424180879 :   if (gActivityTLS == BAD_TLS_INDEX ||
     169       212098910 :       NS_PTR_TO_INT32(PR_GetThreadPrivate(gActivityTLS)) != 0) {
     170             438 :     if (PR_GetEnv("MOZ_FATAL_STATIC_XPCOM_CTORS_DTORS")) {
     171               0 :       NS_RUNTIMEABORT(kStaticCtorDtorWarning);
     172                 :     } else {
     173             438 :       NS_WARNING(kStaticCtorDtorWarning);
     174                 :     }
     175                 :   }
     176       212081969 : }
     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            3323 : DefaultAllocTable(void *pool, PRSize size)
     191                 : {
     192            3323 :     return PR_MALLOC(size);
     193                 : }
     194                 : 
     195                 : static void
     196            3321 : DefaultFreeTable(void *pool, void *item)
     197                 : {
     198            3321 :     PR_Free(item);
     199            3321 : }
     200                 : 
     201                 : static PLHashEntry *
     202          298597 : DefaultAllocEntry(void *pool, const void *key)
     203                 : {
     204          298597 :     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          300005 :   BloatEntry(const char* className, PRUint32 classSize)
     241          300005 :     : mClassSize(classSize) {
     242          300005 :     mClassName = PL_strdup(className);
     243          300005 :     Clear(&mNewStats);
     244          300005 :     Clear(&mAllStats);
     245          300005 :     mTotalLeaked = 0;
     246          300005 :   }
     247                 : 
     248          299997 :   ~BloatEntry() {
     249          299997 :     PL_strfree(mClassName);
     250          299997 :   }
     251                 : 
     252       120255490 :   PRUint32 GetClassSize() { return (PRUint32)mClassSize; }
     253          143496 :   const char* GetClassName() { return mClassName; }
     254                 : 
     255          898599 :   static void Clear(nsTraceRefcntStats* stats) {
     256          898599 :     stats->mAddRefs = 0;
     257          898599 :     stats->mReleases = 0;
     258          898599 :     stats->mCreates = 0;
     259          898599 :     stats->mDestroys = 0;
     260          898599 :     stats->mRefsOutstandingTotal = 0;
     261          898599 :     stats->mRefsOutstandingSquared = 0;
     262          898599 :     stats->mObjsOutstandingTotal = 0;
     263          898599 :     stats->mObjsOutstandingSquared = 0;
     264          898599 :   }
     265                 : 
     266          298589 :   void Accumulate() {
     267          298589 :       mAllStats.mAddRefs += mNewStats.mAddRefs;
     268          298589 :       mAllStats.mReleases += mNewStats.mReleases;
     269          298589 :       mAllStats.mCreates += mNewStats.mCreates;
     270          298589 :       mAllStats.mDestroys += mNewStats.mDestroys;
     271          298589 :       mAllStats.mRefsOutstandingTotal += mNewStats.mRefsOutstandingTotal;
     272          298589 :       mAllStats.mRefsOutstandingSquared += mNewStats.mRefsOutstandingSquared;
     273          298589 :       mAllStats.mObjsOutstandingTotal += mNewStats.mObjsOutstandingTotal;
     274          298589 :       mAllStats.mObjsOutstandingSquared += mNewStats.mObjsOutstandingSquared;
     275          298589 :       Clear(&mNewStats);
     276          298589 :   }
     277                 : 
     278        87212140 :   void AddRef(nsrefcnt refcnt) {
     279        87212140 :     mNewStats.mAddRefs++;
     280        87212140 :     if (refcnt == 1) {
     281        15721754 :       Ctor();
     282                 :     }
     283        87212140 :     AccountRefs();
     284        87212140 :   }
     285                 : 
     286        87198327 :   void Release(nsrefcnt refcnt) {
     287        87198327 :     mNewStats.mReleases++;
     288        87198327 :     if (refcnt == 0) {
     289        15712698 :       Dtor();
     290                 :     }
     291        87198327 :     AccountRefs();
     292        87198327 :   }
     293                 : 
     294        32394108 :   void Ctor() {
     295        32394108 :     mNewStats.mCreates++;
     296        32394108 :     AccountObjs();
     297        32394108 :   }
     298                 : 
     299        32382291 :   void Dtor() {
     300        32382291 :     mNewStats.mDestroys++;
     301        32382291 :     AccountObjs();
     302        32382291 :   }
     303                 : 
     304       174410467 :   void AccountRefs() {
     305       174410467 :     PRUint64 cnt = (mNewStats.mAddRefs - mNewStats.mReleases);
     306       174410467 :     mNewStats.mRefsOutstandingTotal += cnt;
     307       174410467 :     mNewStats.mRefsOutstandingSquared += cnt * cnt;
     308       174410467 :   }
     309                 : 
     310        64776399 :   void AccountObjs() {
     311        64776399 :     PRUint64 cnt = (mNewStats.mCreates - mNewStats.mDestroys);
     312        64776399 :     mNewStats.mObjsOutstandingTotal += cnt;
     313        64776399 :     mNewStats.mObjsOutstandingSquared += cnt * cnt;
     314        64776399 :   }
     315                 : 
     316          298589 :   static PRIntn DumpEntry(PLHashEntry *he, PRIntn i, void *arg) {
     317          298589 :     BloatEntry* entry = (BloatEntry*)he->value;
     318          298589 :     if (entry) {
     319          298589 :       entry->Accumulate();
     320          298589 :       static_cast<nsTArray<BloatEntry*>*>(arg)->AppendElement(entry);
     321                 :     }
     322          298589 :     return HT_ENUMERATE_NEXT;
     323                 :   }
     324                 : 
     325          298589 :   static PRIntn TotalEntries(PLHashEntry *he, PRIntn i, void *arg) {
     326          298589 :     BloatEntry* entry = (BloatEntry*)he->value;
     327          298589 :     if (entry && nsCRT::strcmp(entry->mClassName, "TOTAL") != 0) {
     328          298589 :       entry->Total((BloatEntry*)arg);
     329                 :     }
     330          298589 :     return HT_ENUMERATE_NEXT;
     331                 :   }
     332                 : 
     333          298589 :   void Total(BloatEntry* total) {
     334          298589 :     total->mAllStats.mAddRefs += mNewStats.mAddRefs + mAllStats.mAddRefs;
     335          298589 :     total->mAllStats.mReleases += mNewStats.mReleases + mAllStats.mReleases;
     336          298589 :     total->mAllStats.mCreates += mNewStats.mCreates + mAllStats.mCreates;
     337          298589 :     total->mAllStats.mDestroys += mNewStats.mDestroys + mAllStats.mDestroys;
     338          298589 :     total->mAllStats.mRefsOutstandingTotal += mNewStats.mRefsOutstandingTotal + mAllStats.mRefsOutstandingTotal;
     339          298589 :     total->mAllStats.mRefsOutstandingSquared += mNewStats.mRefsOutstandingSquared + mAllStats.mRefsOutstandingSquared;
     340          298589 :     total->mAllStats.mObjsOutstandingTotal += mNewStats.mObjsOutstandingTotal + mAllStats.mObjsOutstandingTotal;
     341          298589 :     total->mAllStats.mObjsOutstandingSquared += mNewStats.mObjsOutstandingSquared + mAllStats.mObjsOutstandingSquared;
     342          298589 :     PRUint64 count = (mNewStats.mCreates + mAllStats.mCreates);
     343          298589 :     total->mClassSize += mClassSize * count;    // adjust for average in DumpTotal
     344                 :     total->mTotalLeaked += (PRUint64)(mClassSize *
     345                 :                                      ((mNewStats.mCreates + mAllStats.mCreates)
     346          298589 :                                       -(mNewStats.mDestroys + mAllStats.mDestroys)));
     347          298589 :   }
     348                 : 
     349              41 :   void DumpTotal(FILE* out) {
     350              41 :     mClassSize /= mAllStats.mCreates;
     351              41 :     Dump(-1, out, nsTraceRefcntImpl::ALL_STATS);
     352              41 :   }
     353                 : 
     354            7038 :   static bool HaveLeaks(nsTraceRefcntStats* stats) {
     355                 :     return ((stats->mAddRefs != stats->mReleases) ||
     356            7038 :             (stats->mCreates != stats->mDestroys));
     357                 :   }
     358                 : 
     359            1408 :   bool PrintDumpHeader(FILE* out, const char* msg, nsTraceRefcntImpl::StatisticsType type) {
     360                 :     fprintf(out, "\n== BloatView: %s, %s process %d\n", msg,
     361            1408 :             XRE_ChildProcessTypeToString(XRE_GetProcessType()), getpid());
     362                 :     nsTraceRefcntStats& stats =
     363            1408 :       (type == nsTraceRefcntImpl::NEW_STATS) ? mNewStats : mAllStats;
     364            1408 :     if (gLogLeaksOnly && !HaveLeaks(&stats))
     365            1367 :       return false;
     366                 : 
     367                 :     fprintf(out,
     368                 :         "\n" \
     369                 :         "     |<----------------Class--------------->|<-----Bytes------>|<----------------Objects---------------->|<--------------References-------------->|\n" \
     370              41 :         "                                              Per-Inst   Leaked    Total      Rem      Mean       StdDev     Total      Rem      Mean       StdDev\n");
     371                 : 
     372              41 :     this->DumpTotal(out);
     373                 : 
     374              41 :     return true;
     375                 :   }
     376                 : 
     377            5806 :   void Dump(PRIntn i, FILE* out, nsTraceRefcntImpl::StatisticsType type) {
     378            5806 :     nsTraceRefcntStats* stats = (type == nsTraceRefcntImpl::NEW_STATS) ? &mNewStats : &mAllStats;
     379            5806 :     if (gLogLeaksOnly && !HaveLeaks(stats)) {
     380            5036 :       return;
     381                 :     }
     382                 : 
     383                 :     double meanRefs, stddevRefs;
     384                 :     NS_MeanAndStdDev(stats->mAddRefs + stats->mReleases,
     385                 :                      stats->mRefsOutstandingTotal,
     386                 :                      stats->mRefsOutstandingSquared,
     387             770 :                      &meanRefs, &stddevRefs);
     388                 : 
     389                 :     double meanObjs, stddevObjs;
     390                 :     NS_MeanAndStdDev(stats->mCreates + stats->mDestroys,
     391                 :                      stats->mObjsOutstandingTotal,
     392                 :                      stats->mObjsOutstandingSquared,
     393             770 :                      &meanObjs, &stddevObjs);
     394                 : 
     395             770 :     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             770 :               (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            1540 :               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          298589 : BloatViewFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
     430                 : {
     431          298589 :     if (flag == HT_FREE_ENTRY) {
     432          298589 :         BloatEntry* entry = reinterpret_cast<BloatEntry*>(he->value);
     433          298589 :         delete entry;
     434          298589 :         PR_Free(he);
     435                 :     }
     436          298589 : }
     437                 : 
     438                 : const static PLHashAllocOps bloatViewHashAllocOps = {
     439                 :     DefaultAllocTable, DefaultFreeTable,
     440                 :     DefaultAllocEntry, BloatViewFreeEntry
     441                 : };
     442                 : 
     443                 : static void
     444            1409 : RecreateBloatView()
     445                 : {
     446                 :   gBloatView = PL_NewHashTable(256,
     447                 :                                PL_HashString,
     448                 :                                PL_CompareStrings,
     449                 :                                PL_CompareValues,
     450            1409 :                                &bloatViewHashAllocOps, NULL);
     451            1409 : }
     452                 : 
     453                 : static BloatEntry*
     454       207752414 : GetBloatEntry(const char* aTypeName, PRUint32 aInstanceSize)
     455                 : {
     456       207752414 :   if (!gBloatView) {
     457               0 :     RecreateBloatView();
     458                 :   }
     459       207752414 :   BloatEntry* entry = NULL;
     460       207752414 :   if (gBloatView) {
     461       207752414 :     entry = (BloatEntry*)PL_HashTableLookup(gBloatView, aTypeName);
     462       207752414 :     if (entry == NULL && aInstanceSize > 0) {
     463                 : 
     464          298597 :       entry = new BloatEntry(aTypeName, aInstanceSize);
     465          298597 :       PLHashEntry* e = PL_HashTableAdd(gBloatView, aTypeName, entry);
     466          298597 :       if (e == NULL) {
     467               0 :         delete entry;
     468               0 :         entry = NULL;
     469          298597 :       }
     470                 :     } else {
     471       207453817 :       NS_ASSERTION(aInstanceSize == 0 ||
     472                 :                    entry->GetClassSize() == aInstanceSize,
     473                 :                    "bad size recorded");
     474                 :     }
     475                 :   }
     476       207752414 :   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           25332 :     bool Equals(BloatEntry* const& aA, BloatEntry* const& aB) const {
     502           25332 :       return PL_strcmp(aA->GetClassName(), aB->GetClassName()) == 0;
     503                 :     }
     504           46416 :     bool LessThan(BloatEntry* const& aA, BloatEntry* const& aB) const {
     505           46416 :       return PL_strcmp(aA->GetClassName(), aB->GetClassName()) < 0;
     506                 :     }
     507                 : };
     508                 : 
     509                 : #endif /* NS_IMPL_REFCNT_LOGGING */
     510                 : 
     511                 : nsresult
     512            1442 : nsTraceRefcntImpl::DumpStatistics(StatisticsType type, FILE* out)
     513                 : {
     514                 : #ifdef NS_IMPL_REFCNT_LOGGING
     515            1442 :   if (gBloatLog == nsnull || gBloatView == nsnull) {
     516              34 :     return NS_ERROR_FAILURE;
     517                 :   }
     518            1408 :   if (out == nsnull) {
     519            1408 :     out = gBloatLog;
     520                 :   }
     521                 : 
     522            1408 :   LOCK_TRACELOG();
     523                 : 
     524            1408 :   bool wasLogging = gLogging;
     525            1408 :   gLogging = false;  // turn off logging for this method
     526                 : 
     527            2816 :   BloatEntry total("TOTAL", 0);
     528            1408 :   PL_HashTableEnumerateEntries(gBloatView, BloatEntry::TotalEntries, &total);
     529                 :   const char* msg;
     530            1408 :   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            1408 :     if (gLogLeaksOnly)
     538            1386 :       msg = "ALL (cumulative) LEAK STATISTICS";
     539                 :     else
     540              22 :       msg = "ALL (cumulative) LEAK AND BLOAT STATISTICS";
     541                 :   }
     542            1408 :   const bool leaked = total.PrintDumpHeader(out, msg, type);
     543                 : 
     544            2816 :   nsTArray<BloatEntry*> entries;
     545            1408 :   PL_HashTableEnumerateEntries(gBloatView, BloatEntry::DumpEntry, &entries);
     546            1408 :   const PRUint32 count = entries.Length();
     547                 : 
     548            1408 :   if (!gLogLeaksOnly || leaked) {
     549                 :     // Sort the entries alphabetically by classname.
     550              41 :     entries.Sort();
     551                 : 
     552            5806 :     for (PRUint32 i = 0; i < count; ++i) {
     553            5765 :       BloatEntry* entry = entries[i];
     554            5765 :       entry->Dump(i, out, type);
     555                 :     }
     556                 : 
     557              41 :     fprintf(out, "\n");
     558                 :   }
     559                 : 
     560            1408 :   fprintf(out, "nsTraceRefcntImpl::DumpStatistics: %d entries\n", count);
     561                 : 
     562            1408 :   if (gSerialNumbers) {
     563               0 :     fprintf(out, "\nSerial Numbers of Leaked Objects:\n");
     564               0 :     PL_HashTableEnumerateEntries(gSerialNumbers, DumpSerialNumbers, out);
     565                 :   }
     566                 : 
     567            1408 :   gLogging = wasLogging;
     568            1408 :   UNLOCK_TRACELOG();
     569                 : #endif
     570                 : 
     571            1408 :   return NS_OK;
     572                 : }
     573                 : 
     574                 : void
     575            1442 : nsTraceRefcntImpl::ResetStatistics()
     576                 : {
     577                 : #ifdef NS_IMPL_REFCNT_LOGGING
     578            1442 :   LOCK_TRACELOG();
     579            1442 :   if (gBloatView) {
     580            1408 :     PL_HashTableDestroy(gBloatView);
     581            1408 :     gBloatView = nsnull;
     582                 :   }
     583            1442 :   UNLOCK_TRACELOG();
     584                 : #endif
     585            1442 : }
     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            7213 : static bool InitLog(const char* envVar, const char* msg, FILE* *result)
     650                 : {
     651            7213 :   const char* value = getenv(envVar);
     652            7213 :   if (value) {
     653            1410 :     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            1410 :     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            2820 :       nsCAutoString fname(value);
     668            1410 :       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            1410 :       stream = ::fopen(fname.get(), "w" FOPEN_NO_INHERIT);
     681            1410 :       if (stream != NULL) {
     682            1409 :         *result = stream;
     683                 :         fprintf(stdout, "### %s defined -- logging %s to %s\n",
     684            1409 :                 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            1410 :       return stream != NULL;
     691                 :     }
     692                 :   }
     693            5803 :   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            1447 : static void InitTraceLog(void)
     703                 : {
     704            1447 :   if (gInitialized) return;
     705            1447 :   gInitialized = true;
     706                 : 
     707                 :   bool defined;
     708            1447 :   defined = InitLog("XPCOM_MEM_BLOAT_LOG", "bloat/leaks", &gBloatLog);
     709            1447 :   if (!defined)
     710            1425 :     gLogLeaksOnly = InitLog("XPCOM_MEM_LEAK_LOG", "leaks", &gBloatLog);
     711            1447 :   if (defined || gLogLeaksOnly) {
     712            1409 :     RecreateBloatView();
     713            1409 :     if (!gBloatView) {
     714               0 :       NS_WARNING("out of memory");
     715               0 :       gBloatLog = nsnull;
     716               0 :       gLogLeaksOnly = false;
     717                 :     }
     718                 :   }
     719                 : 
     720            1447 :   (void)InitLog("XPCOM_MEM_REFCNT_LOG", "refcounts", &gRefcntsLog);
     721                 : 
     722            1447 :   (void)InitLog("XPCOM_MEM_ALLOC_LOG", "new/delete", &gAllocLog);
     723                 : 
     724            1447 :   defined = InitLog("XPCOM_MEM_LEAKY_LOG", "for leaky", &gLeakyLog);
     725            1447 :   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            1447 :   const char* classes = getenv("XPCOM_MEM_LOG_CLASSES");
     754                 : 
     755                 : #ifdef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR
     756            1447 :   if (classes) {
     757               0 :     (void)InitLog("XPCOM_MEM_COMPTR_LOG", "nsCOMPtr", &gCOMPtrLog);
     758                 :   } else {
     759            1447 :     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            1447 :   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            1447 :   const char* objects = getenv("XPCOM_MEM_LOG_OBJECTS");
     809            1447 :   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            1447 :   if (gBloatLog || gRefcntsLog || gAllocLog || gLeakyLog || gCOMPtrLog) {
     860            1409 :     gLogging = true;
     861                 :   }
     862                 : 
     863            1447 :   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            2855 : NS_LogInit()
     926                 : {
     927                 :   // FIXME: This is called multiple times, we should probably not allow that.
     928            2855 :   StackWalkInitCriticalAddress();
     929                 : #ifdef NS_IMPL_REFCNT_LOGGING
     930            2855 :   if (++gInitCount)
     931            2855 :     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            2855 : }
     941                 : 
     942                 : EXPORT_XPCOM_API(void)
     943            2853 : NS_LogTerm()
     944                 : {
     945            2853 :   mozilla::LogTerm();
     946            2853 : }
     947                 : 
     948                 : namespace mozilla {
     949                 : void
     950            2853 : LogTerm()
     951                 : {
     952            2853 :   NS_ASSERTION(gInitCount > 0,
     953                 :                "NS_LogTerm without matching NS_LogInit");
     954                 : 
     955            2853 :   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            1442 :     BlockingResourceBase::Shutdown();
     970                 : #endif
     971                 :     
     972            1442 :     if (gInitialized) {
     973            1442 :       nsTraceRefcntImpl::DumpStatistics();
     974            1442 :       nsTraceRefcntImpl::ResetStatistics();
     975                 :     }
     976            1442 :     nsTraceRefcntImpl::Shutdown();
     977                 : #ifdef NS_IMPL_REFCNT_LOGGING
     978            1442 :     nsTraceRefcntImpl::SetActivityIsLegal(false);
     979            1442 :     gActivityTLS = BAD_TLS_INDEX;
     980                 : #endif
     981                 :   }
     982            2853 : }
     983                 : 
     984                 : } // namespace mozilla
     985                 : 
     986                 : EXPORT_XPCOM_API(void)
     987        89198256 : NS_LogAddRef(void* aPtr, nsrefcnt aRefcnt,
     988                 :              const char* aClazz, PRUint32 classSize)
     989                 : {
     990                 : #ifdef NS_IMPL_REFCNT_LOGGING
     991        89198256 :   ASSERT_ACTIVITY_IS_LEGAL;
     992        89194203 :   if (!gInitialized)
     993            1447 :     InitTraceLog();
     994        89194230 :   if (gLogging) {
     995        87206913 :     LOCK_TRACELOG();
     996                 : 
     997        87212140 :     if (gBloatLog) {
     998        87212140 :       BloatEntry* entry = GetBloatEntry(aClazz, classSize);
     999        87212140 :       if (entry) {
    1000        87212140 :         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        87212140 :     bool loggingThisType = (!gTypesToLog || LogThisType(aClazz));
    1008        87212140 :     PRInt32 serialno = 0;
    1009        87212140 :     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        87212140 :     bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
    1021        87212140 :     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        87212140 :     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        87212140 :     UNLOCK_TRACELOG();
    1040                 :   }
    1041                 : #endif
    1042        89199417 : }
    1043                 : 
    1044                 : EXPORT_XPCOM_API(void)
    1045        89184812 : NS_LogRelease(void* aPtr, nsrefcnt aRefcnt, const char* aClazz)
    1046                 : {
    1047                 : #ifdef NS_IMPL_REFCNT_LOGGING
    1048        89184812 :   ASSERT_ACTIVITY_IS_LEGAL;
    1049        89182084 :   if (!gInitialized)
    1050               0 :     InitTraceLog();
    1051        89181852 :   if (gLogging) {
    1052        87194536 :     LOCK_TRACELOG();
    1053                 : 
    1054        87198327 :     if (gBloatLog) {
    1055        87198327 :       BloatEntry* entry = GetBloatEntry(aClazz, 0);
    1056        87198327 :       if (entry) {
    1057        87198327 :         entry->Release(aRefcnt);
    1058                 :       }
    1059                 :     }
    1060                 : 
    1061        87198327 :     bool loggingThisType = (!gTypesToLog || LogThisType(aClazz));
    1062        87198327 :     PRInt32 serialno = 0;
    1063        87198327 :     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        87198327 :     bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
    1075        87198327 :     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        87198327 :     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        87198327 :     if (aRefcnt == 0 && gSerialNumbers && loggingThisType) {
    1099               0 :       RecycleSerialNumberPtr(aPtr);
    1100                 :     }
    1101                 : 
    1102        87198327 :     UNLOCK_TRACELOG();
    1103                 :   }
    1104                 : #endif
    1105        89185622 : }
    1106                 : 
    1107                 : EXPORT_XPCOM_API(void)
    1108        16862423 : NS_LogCtor(void* aPtr, const char* aType, PRUint32 aInstanceSize)
    1109                 : {
    1110                 : #ifdef NS_IMPL_REFCNT_LOGGING
    1111        16862423 :   ASSERT_ACTIVITY_IS_LEGAL;
    1112        16862391 :   if (!gInitialized)
    1113               0 :     InitTraceLog();
    1114                 : 
    1115        16862391 :   if (gLogging) {
    1116        16672315 :     LOCK_TRACELOG();
    1117                 : 
    1118        16672354 :     if (gBloatLog) {
    1119        16672354 :       BloatEntry* entry = GetBloatEntry(aType, aInstanceSize);
    1120        16672354 :       if (entry) {
    1121        16672354 :         entry->Ctor();
    1122                 :       }
    1123                 :     }
    1124                 : 
    1125        16672354 :     bool loggingThisType = (!gTypesToLog || LogThisType(aType));
    1126        16672354 :     PRInt32 serialno = 0;
    1127        16672354 :     if (gSerialNumbers && loggingThisType) {
    1128               0 :       serialno = GetSerialNumber(aPtr, true);
    1129                 :     }
    1130                 : 
    1131        16672354 :     bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
    1132        16672354 :     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        16672354 :     UNLOCK_TRACELOG();
    1139                 :   }
    1140                 : #endif
    1141        16862430 : }
    1142                 : 
    1143                 : 
    1144                 : EXPORT_XPCOM_API(void)
    1145        16858240 : NS_LogDtor(void* aPtr, const char* aType, PRUint32 aInstanceSize)
    1146                 : {
    1147                 : #ifdef NS_IMPL_REFCNT_LOGGING
    1148        16858240 :   ASSERT_ACTIVITY_IS_LEGAL;
    1149        16858231 :   if (!gInitialized)
    1150               0 :     InitTraceLog();
    1151                 : 
    1152        16858230 :   if (gLogging) {
    1153        16669578 :     LOCK_TRACELOG();
    1154                 : 
    1155        16669593 :     if (gBloatLog) {
    1156        16669593 :       BloatEntry* entry = GetBloatEntry(aType, aInstanceSize);
    1157        16669593 :       if (entry) {
    1158        16669593 :         entry->Dtor();
    1159                 :       }
    1160                 :     }
    1161                 : 
    1162        16669593 :     bool loggingThisType = (!gTypesToLog || LogThisType(aType));
    1163        16669593 :     PRInt32 serialno = 0;
    1164        16669593 :     if (gSerialNumbers && loggingThisType) {
    1165               0 :       serialno = GetSerialNumber(aPtr, false);
    1166               0 :       RecycleSerialNumberPtr(aPtr);
    1167                 :     }
    1168                 : 
    1169        16669593 :     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        16669593 :     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        16669593 :     UNLOCK_TRACELOG();
    1180                 :   }
    1181                 : #endif
    1182        16858245 : }
    1183                 : 
    1184                 : 
    1185                 : EXPORT_XPCOM_API(void)
    1186        51565447 : 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        51565447 :   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        51565447 :   if (!gTypesToLog || !gSerialNumbers) {
    1196        51565447 :     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        51348440 : 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        51348440 :   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        51348440 :   if (!gTypesToLog || !gSerialNumbers) {
    1237        51348440 :     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            1442 : nsTraceRefcntImpl::Shutdown()
    1273                 : {
    1274                 : #ifdef NS_IMPL_REFCNT_LOGGING
    1275                 : 
    1276            1442 :   if (gBloatView) {
    1277               0 :     PL_HashTableDestroy(gBloatView);
    1278               0 :     gBloatView = nsnull;
    1279                 :   }
    1280            1442 :   if (gTypesToLog) {
    1281               0 :     PL_HashTableDestroy(gTypesToLog);
    1282               0 :     gTypesToLog = nsnull;
    1283                 :   }
    1284            1442 :   if (gObjectsToLog) {
    1285               0 :     PL_HashTableDestroy(gObjectsToLog);
    1286               0 :     gObjectsToLog = nsnull;
    1287                 :   }
    1288            1442 :   if (gSerialNumbers) {
    1289               0 :     PL_HashTableDestroy(gSerialNumbers);
    1290               0 :     gSerialNumbers = nsnull;
    1291                 :   }
    1292            1442 :   if (gBloatLog) {
    1293            1408 :     fclose(gBloatLog);
    1294            1408 :     gBloatLog = nsnull;
    1295                 :   }
    1296            1442 :   if (gRefcntsLog) {
    1297               0 :     fclose(gRefcntsLog);
    1298               0 :     gRefcntsLog = nsnull;
    1299                 :   }
    1300            1442 :   if (gAllocLog) {
    1301               0 :     fclose(gAllocLog);
    1302               0 :     gAllocLog = nsnull;
    1303                 :   }
    1304            1442 :   if (gLeakyLog) {
    1305               0 :     fclose(gLeakyLog);
    1306               0 :     gLeakyLog = nsnull;
    1307                 :   }
    1308            1442 :   if (gCOMPtrLog) {
    1309               0 :     fclose(gCOMPtrLog);
    1310               0 :     gCOMPtrLog = nsnull;
    1311                 :   }
    1312                 : #endif
    1313            1442 : }
    1314                 : 
    1315                 : void
    1316           27015 : nsTraceRefcntImpl::SetActivityIsLegal(bool aLegal)
    1317                 : {
    1318                 : #ifdef NS_IMPL_REFCNT_LOGGING
    1319           27015 :   if (gActivityTLS == BAD_TLS_INDEX)
    1320            1443 :     PR_NewThreadPrivateIndex(&gActivityTLS, nsnull);
    1321                 : 
    1322           27015 :   PR_SetThreadPrivate(gActivityTLS, NS_INT32_TO_PTR(!aLegal));
    1323                 : #endif
    1324           27015 : }
    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            1464 : 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            4392 : }

Generated by: LCOV version 1.7