Back to index

lightning-sunbird  0.9+nobinonly
nsTraceRefcntImpl.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   L. David Baron <dbaron@dbaron.org>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsTraceRefcntImpl.h"
00040 #include "nscore.h"
00041 #include "nsISupports.h"
00042 #include "nsVoidArray.h"
00043 #include "prprf.h"
00044 #include "prlog.h"
00045 #include "plstr.h"
00046 #include <stdlib.h>
00047 #include "nsCOMPtr.h"
00048 #include "nsCRT.h"
00049 #include <math.h>
00050 
00051 #if defined(_WIN32)
00052 #include <windows.h>
00053 #endif
00054 
00055 #ifdef HAVE_LIBDL
00056 #include <dlfcn.h>
00057 #endif
00058 
00060 
00061 NS_COM void 
00062 NS_MeanAndStdDev(double n, double sumOfValues, double sumOfSquaredValues,
00063                  double *meanResult, double *stdDevResult)
00064 {
00065   double mean = 0.0, var = 0.0, stdDev = 0.0;
00066   if (n > 0.0 && sumOfValues >= 0) {
00067     mean = sumOfValues / n;
00068     double temp = (n * sumOfSquaredValues) - (sumOfValues * sumOfValues);
00069     if (temp < 0.0 || n <= 1)
00070       var = 0.0;
00071     else
00072       var = temp / (n * (n - 1));
00073     // for some reason, Windows says sqrt(0.0) is "-1.#J" (?!) so do this:
00074     stdDev = var != 0.0 ? sqrt(var) : 0.0;
00075   }
00076   *meanResult = mean;
00077   *stdDevResult = stdDev;
00078 }
00079 
00081 
00082 #ifdef WINCE
00083 #undef NS_BUILD_REFCNT_LOGGING
00084 #endif
00085 
00086 #ifdef NS_BUILD_REFCNT_LOGGING
00087 #include "plhash.h"
00088 #include "prmem.h"
00089 
00090 #include "prlock.h"
00091 
00092 static PRLock* gTraceLock;
00093 
00094 #define LOCK_TRACELOG()   PR_Lock(gTraceLock)
00095 #define UNLOCK_TRACELOG() PR_Unlock(gTraceLock)
00096 
00097 static PLHashTable* gBloatView;
00098 static PLHashTable* gTypesToLog;
00099 static PLHashTable* gObjectsToLog;
00100 static PLHashTable* gSerialNumbers;
00101 static PRInt32 gNextSerialNumber;
00102 
00103 static PRBool gLogging;
00104 static PRBool gLogToLeaky;
00105 static PRBool gLogLeaksOnly;
00106 
00107 static void (*leakyLogAddRef)(void* p, int oldrc, int newrc);
00108 static void (*leakyLogRelease)(void* p, int oldrc, int newrc);
00109 
00110 static PRBool gInitialized = PR_FALSE;
00111 static FILE *gBloatLog = nsnull;
00112 static FILE *gRefcntsLog = nsnull;
00113 static FILE *gAllocLog = nsnull;
00114 static FILE *gLeakyLog = nsnull;
00115 static FILE *gCOMPtrLog = nsnull;
00116 static PRBool gActivityIsLegal = PR_FALSE;
00117 
00118 struct serialNumberRecord {
00119   PRInt32 serialNumber;
00120   PRInt32 refCount;
00121   PRInt32 COMPtrCount;
00122 };
00123 
00124 struct nsTraceRefcntStats {
00125   nsrefcnt mAddRefs;
00126   nsrefcnt mReleases;
00127   nsrefcnt mCreates;
00128   nsrefcnt mDestroys;
00129   double mRefsOutstandingTotal;
00130   double mRefsOutstandingSquared;
00131   double mObjsOutstandingTotal;
00132   double mObjsOutstandingSquared;
00133 };
00134 
00135 #ifdef DEBUG_dbaron_off
00136   // I hope to turn this on for everybody once we hit it a little less.
00137 #define ASSERT_ACTIVITY_IS_LEGAL                                                \
00138   NS_WARN_IF_FALSE(gActivityIsLegal,                                         \
00139                    "XPCOM objects created/destroyed from static ctor/dtor")
00140 #else
00141 #define ASSERT_ACTIVITY_IS_LEGAL
00142 #endif
00143 
00144 
00145 // These functions are copied from nsprpub/lib/ds/plhash.c, with changes
00146 // to the functions not called Default* to free the serialNumberRecord or
00147 // the BloatEntry.
00148 
00149 static void * PR_CALLBACK
00150 DefaultAllocTable(void *pool, PRSize size)
00151 {
00152     return PR_MALLOC(size);
00153 }
00154 
00155 static void PR_CALLBACK
00156 DefaultFreeTable(void *pool, void *item)
00157 {
00158     PR_Free(item);
00159 }
00160 
00161 static PLHashEntry * PR_CALLBACK
00162 DefaultAllocEntry(void *pool, const void *key)
00163 {
00164     return PR_NEW(PLHashEntry);
00165 }
00166 
00167 static void PR_CALLBACK
00168 SerialNumberFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
00169 {
00170     if (flag == HT_FREE_ENTRY) {
00171         PR_Free(NS_REINTERPRET_CAST(serialNumberRecord*,he->value));
00172         PR_Free(he);
00173     }
00174 }
00175 
00176 static void PR_CALLBACK
00177 TypesToLogFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
00178 {
00179     if (flag == HT_FREE_ENTRY) {
00180         nsCRT::free(NS_CONST_CAST(char*,
00181                      NS_REINTERPRET_CAST(const char*, he->key)));
00182         PR_Free(he);
00183     }
00184 }
00185 
00186 static const PLHashAllocOps serialNumberHashAllocOps = {
00187     DefaultAllocTable, DefaultFreeTable,
00188     DefaultAllocEntry, SerialNumberFreeEntry
00189 };
00190 
00191 static const PLHashAllocOps typesToLogHashAllocOps = {
00192     DefaultAllocTable, DefaultFreeTable,
00193     DefaultAllocEntry, TypesToLogFreeEntry
00194 };
00195 
00197 
00198 class BloatEntry {
00199 public:
00200   BloatEntry(const char* className, PRUint32 classSize)
00201     : mClassSize(classSize) { 
00202     mClassName = PL_strdup(className);
00203     Clear(&mNewStats);
00204     Clear(&mAllStats);
00205     mTotalLeaked = 0;
00206   }
00207 
00208   ~BloatEntry() {
00209     PL_strfree(mClassName);
00210   }
00211 
00212   PRUint32 GetClassSize() { return (PRUint32)mClassSize; }
00213   const char* GetClassName() { return mClassName; }
00214 
00215   static void Clear(nsTraceRefcntStats* stats) {
00216     stats->mAddRefs = 0;
00217     stats->mReleases = 0;
00218     stats->mCreates = 0;
00219     stats->mDestroys = 0;
00220     stats->mRefsOutstandingTotal = 0;
00221     stats->mRefsOutstandingSquared = 0;
00222     stats->mObjsOutstandingTotal = 0;
00223     stats->mObjsOutstandingSquared = 0;
00224   }
00225 
00226   void Accumulate() {
00227       mAllStats.mAddRefs += mNewStats.mAddRefs;
00228       mAllStats.mReleases += mNewStats.mReleases;
00229       mAllStats.mCreates += mNewStats.mCreates;
00230       mAllStats.mDestroys += mNewStats.mDestroys;
00231       mAllStats.mRefsOutstandingTotal += mNewStats.mRefsOutstandingTotal;
00232       mAllStats.mRefsOutstandingSquared += mNewStats.mRefsOutstandingSquared;
00233       mAllStats.mObjsOutstandingTotal += mNewStats.mObjsOutstandingTotal;
00234       mAllStats.mObjsOutstandingSquared += mNewStats.mObjsOutstandingSquared;
00235       Clear(&mNewStats);
00236   }
00237 
00238   void AddRef(nsrefcnt refcnt) {
00239     mNewStats.mAddRefs++;
00240     if (refcnt == 1) {
00241       Ctor();
00242     }
00243     AccountRefs();
00244   }
00245 
00246   void Release(nsrefcnt refcnt) {
00247     mNewStats.mReleases++;
00248     if (refcnt == 0) {
00249       Dtor();
00250     }
00251     AccountRefs();
00252   }
00253 
00254   void Ctor() {
00255     mNewStats.mCreates++;
00256     AccountObjs();
00257   }
00258 
00259   void Dtor() {
00260     mNewStats.mDestroys++;
00261     AccountObjs();
00262   }
00263 
00264   void AccountRefs() {
00265     PRInt32 cnt = (mNewStats.mAddRefs - mNewStats.mReleases);
00266     mNewStats.mRefsOutstandingTotal += cnt;
00267     mNewStats.mRefsOutstandingSquared += cnt * cnt;
00268   }
00269 
00270   void AccountObjs() {
00271     PRInt32 cnt = (mNewStats.mCreates - mNewStats.mDestroys);
00272     mNewStats.mObjsOutstandingTotal += cnt;
00273     mNewStats.mObjsOutstandingSquared += cnt * cnt;
00274   }
00275 
00276   static PRIntn PR_CALLBACK DumpEntry(PLHashEntry *he, PRIntn i, void *arg) {
00277     BloatEntry* entry = (BloatEntry*)he->value;
00278     if (entry) {
00279       entry->Accumulate();
00280       NS_STATIC_CAST(nsVoidArray*, arg)->AppendElement(entry);
00281     }
00282     return HT_ENUMERATE_NEXT;
00283   }
00284 
00285   static PRIntn PR_CALLBACK TotalEntries(PLHashEntry *he, PRIntn i, void *arg) {
00286     BloatEntry* entry = (BloatEntry*)he->value;
00287     if (entry && nsCRT::strcmp(entry->mClassName, "TOTAL") != 0) {
00288       entry->Total((BloatEntry*)arg);
00289     }
00290     return HT_ENUMERATE_NEXT;
00291   }
00292 
00293   void Total(BloatEntry* total) {
00294     total->mAllStats.mAddRefs += mNewStats.mAddRefs + mAllStats.mAddRefs;
00295     total->mAllStats.mReleases += mNewStats.mReleases + mAllStats.mReleases;
00296     total->mAllStats.mCreates += mNewStats.mCreates + mAllStats.mCreates;
00297     total->mAllStats.mDestroys += mNewStats.mDestroys + mAllStats.mDestroys;
00298     total->mAllStats.mRefsOutstandingTotal += mNewStats.mRefsOutstandingTotal + mAllStats.mRefsOutstandingTotal;
00299     total->mAllStats.mRefsOutstandingSquared += mNewStats.mRefsOutstandingSquared + mAllStats.mRefsOutstandingSquared;
00300     total->mAllStats.mObjsOutstandingTotal += mNewStats.mObjsOutstandingTotal + mAllStats.mObjsOutstandingTotal;
00301     total->mAllStats.mObjsOutstandingSquared += mNewStats.mObjsOutstandingSquared + mAllStats.mObjsOutstandingSquared;
00302     PRInt32 count = (mNewStats.mCreates + mAllStats.mCreates);
00303     total->mClassSize += mClassSize * count;    // adjust for average in DumpTotal
00304     total->mTotalLeaked += (PRInt32)(mClassSize *
00305                                      ((mNewStats.mCreates + mAllStats.mCreates)
00306                                       -(mNewStats.mDestroys + mAllStats.mDestroys)));
00307   }
00308 
00309   nsresult DumpTotal(PRUint32 nClasses, FILE* out) {
00310     mClassSize /= mAllStats.mCreates;
00311     return Dump(-1, out, nsTraceRefcntImpl::ALL_STATS);
00312   }
00313 
00314   static PRBool HaveLeaks(nsTraceRefcntStats* stats) {
00315     return ((stats->mAddRefs != stats->mReleases) ||
00316             (stats->mCreates != stats->mDestroys));
00317   }
00318 
00319   static nsresult PrintDumpHeader(FILE* out, const char* msg) {
00320     fprintf(out, "\n== BloatView: %s\n\n", msg);
00321     fprintf(out, 
00322         "     |<----------------Class--------------->|<-----Bytes------>|<----------------Objects---------------->|<--------------References-------------->|\n");
00323     fprintf(out,
00324         "                                              Per-Inst   Leaked    Total      Rem      Mean       StdDev     Total      Rem      Mean       StdDev\n");
00325     return NS_OK;
00326   }
00327 
00328   nsresult Dump(PRIntn i, FILE* out, nsTraceRefcntImpl::StatisticsType type) {
00329     nsTraceRefcntStats* stats = (type == nsTraceRefcntImpl::NEW_STATS) ? &mNewStats : &mAllStats;
00330     if (gLogLeaksOnly && !HaveLeaks(stats)) {
00331       return NS_OK;
00332     }
00333 
00334     double meanRefs, stddevRefs;
00335     NS_MeanAndStdDev(stats->mAddRefs + stats->mReleases, 
00336                      stats->mRefsOutstandingTotal, 
00337                      stats->mRefsOutstandingSquared,
00338                      &meanRefs, &stddevRefs);
00339 
00340     double meanObjs, stddevObjs;
00341     NS_MeanAndStdDev(stats->mCreates + stats->mDestroys,
00342                      stats->mObjsOutstandingTotal, 
00343                      stats->mObjsOutstandingSquared,
00344                      &meanObjs, &stddevObjs);
00345 
00346     if ((stats->mAddRefs - stats->mReleases) != 0 ||
00347         stats->mAddRefs != 0 ||
00348         meanRefs != 0 ||
00349         stddevRefs != 0 ||
00350         (stats->mCreates - stats->mDestroys) != 0 ||
00351         stats->mCreates != 0 ||
00352         meanObjs != 0 ||
00353         stddevObjs != 0) {
00354       fprintf(out, "%4d %-40.40s %8d %8d %8d %8d (%8.2f +/- %8.2f) %8d %8d (%8.2f +/- %8.2f)\n",
00355               i+1, mClassName,
00356               (PRInt32)mClassSize,
00357               (nsCRT::strcmp(mClassName, "TOTAL"))
00358                   ?(PRInt32)((stats->mCreates - stats->mDestroys) * mClassSize)
00359                   :mTotalLeaked,
00360               stats->mCreates,
00361               (stats->mCreates - stats->mDestroys),
00362               meanObjs,
00363               stddevObjs, 
00364               stats->mAddRefs,
00365               (stats->mAddRefs - stats->mReleases),
00366               meanRefs,
00367               stddevRefs);
00368     }
00369     return NS_OK;
00370   }
00371 
00372 protected:
00373   char*         mClassName;
00374   double        mClassSize;     // this is stored as a double because of the way we compute the avg class size for total bloat
00375   PRInt32       mTotalLeaked; // used only for TOTAL entry
00376   nsTraceRefcntStats mNewStats;
00377   nsTraceRefcntStats mAllStats;
00378 };
00379 
00380 static void PR_CALLBACK
00381 BloatViewFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
00382 {
00383     if (flag == HT_FREE_ENTRY) {
00384         BloatEntry* entry = NS_REINTERPRET_CAST(BloatEntry*,he->value);
00385         delete entry;
00386         PR_Free(he);
00387     }
00388 }
00389 
00390 const static PLHashAllocOps bloatViewHashAllocOps = {
00391     DefaultAllocTable, DefaultFreeTable,
00392     DefaultAllocEntry, BloatViewFreeEntry
00393 };
00394 
00395 static void
00396 RecreateBloatView()
00397 {
00398   gBloatView = PL_NewHashTable(256, 
00399                                PL_HashString,
00400                                PL_CompareStrings,
00401                                PL_CompareValues,
00402                                &bloatViewHashAllocOps, NULL);
00403 }
00404 
00405 static BloatEntry*
00406 GetBloatEntry(const char* aTypeName, PRUint32 aInstanceSize)
00407 {
00408   if (!gBloatView) {
00409     RecreateBloatView();
00410   }
00411   BloatEntry* entry = NULL;
00412   if (gBloatView) {
00413     entry = (BloatEntry*)PL_HashTableLookup(gBloatView, aTypeName);
00414     if (entry == NULL && aInstanceSize > 0) {
00415 
00416       entry = new BloatEntry(aTypeName, aInstanceSize);
00417       PLHashEntry* e = PL_HashTableAdd(gBloatView, aTypeName, entry);
00418       if (e == NULL) {
00419         delete entry;
00420         entry = NULL;
00421       }
00422     } else {
00423       NS_ASSERTION(aInstanceSize == 0 || 
00424                    entry->GetClassSize() == aInstanceSize, 
00425                    "bad size recorded");
00426     }
00427   }
00428   return entry;
00429 }
00430 
00431 static PRIntn PR_CALLBACK DumpSerialNumbers(PLHashEntry* aHashEntry, PRIntn aIndex, void* aClosure)
00432 {
00433   serialNumberRecord* record = NS_REINTERPRET_CAST(serialNumberRecord *,aHashEntry->value);
00434 #ifdef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR
00435   fprintf((FILE*) aClosure, "%d (%d references; %d from COMPtrs)\n",
00436                             record->serialNumber,
00437                             record->refCount,
00438                             record->COMPtrCount);
00439 #else
00440   fprintf((FILE*) aClosure, "%d (%d references)\n",
00441                             record->serialNumber,
00442                             record->refCount);
00443 #endif
00444   return HT_ENUMERATE_NEXT;
00445 }
00446 
00447 
00448 #endif /* NS_BUILD_REFCNT_LOGGING */
00449 
00450 NS_COM nsresult
00451 nsTraceRefcntImpl::DumpStatistics(StatisticsType type, FILE* out)
00452 {
00453   nsresult rv = NS_OK;
00454 #ifdef NS_BUILD_REFCNT_LOGGING
00455   if (gBloatLog == nsnull || gBloatView == nsnull) {
00456     return NS_ERROR_FAILURE;
00457   }
00458   if (out == nsnull) {
00459     out = gBloatLog;
00460   }
00461 
00462   LOCK_TRACELOG();
00463 
00464   PRBool wasLogging = gLogging;
00465   gLogging = PR_FALSE;  // turn off logging for this method
00466   
00467   const char* msg;
00468   if (type == NEW_STATS) {
00469     if (gLogLeaksOnly)
00470       msg = "NEW (incremental) LEAK STATISTICS";
00471     else
00472       msg = "NEW (incremental) LEAK AND BLOAT STATISTICS";
00473   }
00474   else {
00475     if (gLogLeaksOnly)
00476       msg = "ALL (cumulative) LEAK STATISTICS";
00477     else
00478       msg = "ALL (cumulative) LEAK AND BLOAT STATISTICS";
00479   }
00480   rv = BloatEntry::PrintDumpHeader(out, msg);
00481   if (NS_FAILED(rv)) goto done;
00482 
00483   {
00484     BloatEntry total("TOTAL", 0);
00485     PL_HashTableEnumerateEntries(gBloatView, BloatEntry::TotalEntries, &total);
00486     total.DumpTotal(gBloatView->nentries, out);
00487 
00488     nsVoidArray entries;
00489     PL_HashTableEnumerateEntries(gBloatView, BloatEntry::DumpEntry, &entries);
00490 
00491     fprintf(stdout, "nsTraceRefcntImpl::DumpStatistics: %d entries\n",
00492            entries.Count());
00493 
00494     // Sort the entries alphabetically by classname.
00495     PRInt32 i, j;
00496     for (i = entries.Count() - 1; i >= 1; --i) {
00497       for (j = i - 1; j >= 0; --j) {
00498         BloatEntry* left  = NS_STATIC_CAST(BloatEntry*, entries[i]);
00499         BloatEntry* right = NS_STATIC_CAST(BloatEntry*, entries[j]);
00500 
00501         if (PL_strcmp(left->GetClassName(), right->GetClassName()) < 0) {
00502           entries.ReplaceElementAt(right, i);
00503           entries.ReplaceElementAt(left, j);
00504         }
00505       }
00506     }
00507 
00508     // Enumerate from back-to-front, so things come out in alpha order
00509     for (i = 0; i < entries.Count(); ++i) {
00510       BloatEntry* entry = NS_STATIC_CAST(BloatEntry*, entries[i]);
00511       entry->Dump(i, out, type);
00512     }
00513   }
00514 
00515   if (gSerialNumbers) {
00516     fprintf(out, "\n\nSerial Numbers of Leaked Objects:\n");
00517     PL_HashTableEnumerateEntries(gSerialNumbers, DumpSerialNumbers, out);
00518   }
00519 
00520 done:
00521   gLogging = wasLogging;
00522   UNLOCK_TRACELOG();
00523 #endif
00524   return rv;
00525 }
00526 
00527 NS_COM void
00528 nsTraceRefcntImpl::ResetStatistics()
00529 {
00530 #ifdef NS_BUILD_REFCNT_LOGGING
00531   LOCK_TRACELOG();
00532   if (gBloatView) {
00533     PL_HashTableDestroy(gBloatView);
00534     gBloatView = nsnull;
00535   }
00536   UNLOCK_TRACELOG();
00537 #endif
00538 }
00539 
00540 #ifdef NS_BUILD_REFCNT_LOGGING
00541 static PRBool LogThisType(const char* aTypeName)
00542 {
00543   void* he = PL_HashTableLookup(gTypesToLog, aTypeName);
00544   return nsnull != he;
00545 }
00546 
00547 static PRInt32 GetSerialNumber(void* aPtr, PRBool aCreate)
00548 {
00549 #ifdef GC_LEAK_DETECTOR
00550   // need to disguise this pointer, so the table won't keep the object alive.
00551   aPtr = (void*) ~PLHashNumber(aPtr);
00552 #endif
00553   PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr);
00554   if (hep && *hep) {
00555     return PRInt32((NS_REINTERPRET_CAST(serialNumberRecord*,(*hep)->value))->serialNumber);
00556   }
00557   else if (aCreate) {
00558     serialNumberRecord *record = PR_NEW(serialNumberRecord);
00559     record->serialNumber = ++gNextSerialNumber;
00560     record->refCount = 0;
00561     record->COMPtrCount = 0;
00562     PL_HashTableRawAdd(gSerialNumbers, hep, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr, NS_REINTERPRET_CAST(void*,record));
00563     return gNextSerialNumber;
00564   }
00565   else {
00566     return 0;
00567   }
00568 }
00569 
00570 static PRInt32* GetRefCount(void* aPtr)
00571 {
00572 #ifdef GC_LEAK_DETECTOR
00573   // need to disguise this pointer, so the table won't keep the object alive.
00574   aPtr = (void*) ~PLHashNumber(aPtr);
00575 #endif
00576   PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr);
00577   if (hep && *hep) {
00578     return &((NS_REINTERPRET_CAST(serialNumberRecord*,(*hep)->value))->refCount);
00579   } else {
00580     return nsnull;
00581   }
00582 }
00583 
00584 static PRInt32* GetCOMPtrCount(void* aPtr)
00585 {
00586 #ifdef GC_LEAK_DETECTOR
00587   // need to disguise this pointer, so the table won't keep the object alive.
00588   aPtr = (void*) ~PLHashNumber(aPtr);
00589 #endif
00590   PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr);
00591   if (hep && *hep) {
00592     return &((NS_REINTERPRET_CAST(serialNumberRecord*,(*hep)->value))->COMPtrCount);
00593   } else {
00594     return nsnull;
00595   }
00596 }
00597 
00598 static void RecycleSerialNumberPtr(void* aPtr)
00599 {
00600 #ifdef GC_LEAK_DETECTOR
00601   // need to disguise this pointer, so the table won't keep the object alive.
00602   aPtr = (void*) ~PLHashNumber(aPtr);
00603 #endif
00604   PL_HashTableRemove(gSerialNumbers, aPtr);
00605 }
00606 
00607 static PRBool LogThisObj(PRInt32 aSerialNumber)
00608 {
00609   return nsnull != PL_HashTableLookup(gObjectsToLog, (const void*)(aSerialNumber));
00610 }
00611 
00612 static PRBool InitLog(const char* envVar, const char* msg, FILE* *result)
00613 {
00614   const char* value = getenv(envVar);
00615   if (value) {
00616     if (nsCRT::strcmp(value, "1") == 0) {
00617       *result = stdout;
00618       fprintf(stdout, "### %s defined -- logging %s to stdout\n", 
00619               envVar, msg);
00620       return PR_TRUE;
00621     }
00622     else if (nsCRT::strcmp(value, "2") == 0) {
00623       *result = stderr;
00624       fprintf(stdout, "### %s defined -- logging %s to stderr\n", 
00625               envVar, msg);
00626       return PR_TRUE;
00627     }
00628     else {
00629       FILE *stream = ::fopen(value, "w");
00630       if (stream != NULL) {
00631         *result = stream;
00632         fprintf(stdout, "### %s defined -- logging %s to %s\n", 
00633                 envVar, msg, value);
00634         return PR_TRUE;
00635       }
00636       else {
00637         fprintf(stdout, "### %s defined -- unable to log %s to %s\n", 
00638                 envVar, msg, value);
00639         return PR_FALSE;
00640       }
00641     }
00642   }
00643   return PR_FALSE;
00644 }
00645 
00646 
00647 static PLHashNumber PR_CALLBACK HashNumber(const void* aKey)
00648 {
00649   return PLHashNumber(NS_PTR_TO_INT32(aKey));
00650 }
00651 
00652 static void InitTraceLog(void)
00653 {
00654   if (gInitialized) return;
00655   gInitialized = PR_TRUE;
00656 
00657   PRBool defined;
00658   defined = InitLog("XPCOM_MEM_BLOAT_LOG", "bloat/leaks", &gBloatLog);
00659   if (!defined)
00660     gLogLeaksOnly = InitLog("XPCOM_MEM_LEAK_LOG", "leaks", &gBloatLog);
00661   if (defined || gLogLeaksOnly) {
00662     RecreateBloatView();
00663     if (!gBloatView) {
00664       NS_WARNING("out of memory");
00665       gBloatLog = nsnull;
00666       gLogLeaksOnly = PR_FALSE;
00667     }
00668   }
00669 
00670   (void)InitLog("XPCOM_MEM_REFCNT_LOG", "refcounts", &gRefcntsLog);
00671 
00672   (void)InitLog("XPCOM_MEM_ALLOC_LOG", "new/delete", &gAllocLog);
00673 
00674   defined = InitLog("XPCOM_MEM_LEAKY_LOG", "for leaky", &gLeakyLog);
00675   if (defined) {
00676     gLogToLeaky = PR_TRUE;
00677     void* p = nsnull;
00678     void* q = nsnull;
00679 #ifdef HAVE_LIBDL
00680     p = dlsym(0, "__log_addref");
00681     q = dlsym(0, "__log_release");
00682 #endif
00683     if (p && q) {
00684       leakyLogAddRef = (void (*)(void*,int,int)) p;
00685       leakyLogRelease = (void (*)(void*,int,int)) q;
00686     }
00687     else {
00688       gLogToLeaky = PR_FALSE;
00689       fprintf(stdout, "### ERROR: XPCOM_MEM_LEAKY_LOG defined, but can't locate __log_addref and __log_release symbols\n");
00690       fflush(stdout);
00691     }
00692   }
00693 
00694   const char* classes = getenv("XPCOM_MEM_LOG_CLASSES");
00695 
00696 #ifdef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR
00697   if (classes) {
00698     (void)InitLog("XPCOM_MEM_COMPTR_LOG", "nsCOMPtr", &gCOMPtrLog);
00699   } else {
00700     if (getenv("XPCOM_MEM_COMPTR_LOG")) {
00701       fprintf(stdout, "### XPCOM_MEM_COMPTR_LOG defined -- but XPCOM_MEM_LOG_CLASSES is not defined\n");
00702     }
00703   }
00704 #else
00705   const char* comptr_log = getenv("XPCOM_MEM_COMPTR_LOG");
00706   if (comptr_log) {
00707     fprintf(stdout, "### XPCOM_MEM_COMPTR_LOG defined -- but it will not work without dynamic_cast\n");
00708   }
00709 #endif
00710 
00711   if (classes) {
00712     // if XPCOM_MEM_LOG_CLASSES was set to some value, the value is interpreted
00713     // as a list of class names to track
00714     gTypesToLog = PL_NewHashTable(256,
00715                                   PL_HashString,
00716                                   PL_CompareStrings,
00717                                   PL_CompareValues,
00718                                   &typesToLogHashAllocOps, NULL);
00719     if (!gTypesToLog) {
00720       NS_WARNING("out of memory");
00721       fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- unable to log specific classes\n");
00722     }
00723     else {
00724       fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- only logging these classes: ");
00725       const char* cp = classes;
00726       for (;;) {
00727         char* cm = (char*) strchr(cp, ',');
00728         if (cm) {
00729           *cm = '\0';
00730         }
00731         PL_HashTableAdd(gTypesToLog, nsCRT::strdup(cp), (void*)1);
00732         fprintf(stdout, "%s ", cp);
00733         if (!cm) break;
00734         *cm = ',';
00735         cp = cm + 1;
00736       }
00737       fprintf(stdout, "\n");
00738     }
00739 
00740     gSerialNumbers = PL_NewHashTable(256,
00741                                      HashNumber,
00742                                      PL_CompareValues,
00743                                      PL_CompareValues,
00744                                      &serialNumberHashAllocOps, NULL);
00745 
00746 
00747   }
00748 
00749   const char* objects = getenv("XPCOM_MEM_LOG_OBJECTS");
00750   if (objects) {
00751     gObjectsToLog = PL_NewHashTable(256,
00752                                     HashNumber,
00753                                     PL_CompareValues,
00754                                     PL_CompareValues,
00755                                     NULL, NULL);
00756 
00757     if (!gObjectsToLog) {
00758       NS_WARNING("out of memory");
00759       fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- unable to log specific objects\n");
00760     }
00761     else if (! (gRefcntsLog || gAllocLog || gCOMPtrLog)) {
00762       fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- but none of XPCOM_MEM_(REFCNT|ALLOC|COMPTR)_LOG is defined\n");
00763     }
00764     else {
00765       fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- only logging these objects: ");
00766       const char* cp = objects;
00767       for (;;) {
00768         char* cm = (char*) strchr(cp, ',');
00769         if (cm) {
00770           *cm = '\0';
00771         }
00772         PRInt32 top = 0;
00773         PRInt32 bottom = 0;
00774         while (*cp) {
00775           if (*cp == '-') {
00776             bottom = top;
00777             top = 0;
00778             ++cp;
00779           }
00780           top *= 10;
00781           top += *cp - '0';
00782           ++cp;
00783         }
00784         if (!bottom) {
00785           bottom = top;
00786         }
00787         for(PRInt32 serialno = bottom; serialno <= top; serialno++) {
00788           PL_HashTableAdd(gObjectsToLog, (const void*)serialno, (void*)1);
00789           fprintf(stdout, "%d ", serialno);
00790         }
00791         if (!cm) break;
00792         *cm = ',';
00793         cp = cm + 1;
00794       }
00795       fprintf(stdout, "\n");
00796     }
00797   }
00798 
00799 
00800   if (gBloatLog || gRefcntsLog || gAllocLog || gLeakyLog || gCOMPtrLog) {
00801     gLogging = PR_TRUE;
00802   }
00803 
00804   gTraceLock = PR_NewLock();
00805 }
00806 
00807 #endif
00808 
00809 #if defined(_WIN32) && defined(_M_IX86) && !defined(WINCE) // WIN32 x86 stack walking code
00810 #include "nsStackFrameWin.h"
00811 NS_COM void
00812 nsTraceRefcntImpl::WalkTheStack(FILE* aStream)
00813 {
00814   DumpStackToFile(aStream);
00815 }
00816 
00817 // WIN32 x86 stack walking code
00818 // i386 or PPC Linux stackwalking code or Solaris
00819 #elif (defined(linux) && defined(__GNUC__) && (defined(__i386) || defined(PPC) || defined(__x86_64__))) || (defined(__sun) && (defined(__sparc) || defined(sparc) || defined(__i386) || defined(i386)))
00820 #include "nsStackFrameUnix.h"
00821 NS_COM void
00822 nsTraceRefcntImpl::WalkTheStack(FILE* aStream)
00823 {
00824   DumpStackToFile(aStream);
00825 }
00826 
00827 #else // unsupported platform.
00828 
00829 NS_COM void
00830 nsTraceRefcntImpl::WalkTheStack(FILE* aStream)
00831 {
00832        fprintf(aStream, "write me, dammit!\n");
00833 }
00834 
00835 #endif
00836 
00837 //----------------------------------------------------------------------
00838 
00839 // This thing is exported by libstdc++
00840 // Yes, this is a gcc only hack
00841 #if defined(MOZ_DEMANGLE_SYMBOLS)
00842 #include <cxxabi.h>
00843 #include <stdlib.h> // for free()
00844 #endif // MOZ_DEMANGLE_SYMBOLS
00845 
00846 NS_COM void 
00847 nsTraceRefcntImpl::DemangleSymbol(const char * aSymbol, 
00848                               char * aBuffer,
00849                               int aBufLen)
00850 {
00851   NS_ASSERTION(nsnull != aSymbol,"null symbol");
00852   NS_ASSERTION(nsnull != aBuffer,"null buffer");
00853   NS_ASSERTION(aBufLen >= 32 ,"pulled 32 out of you know where");
00854 
00855   aBuffer[0] = '\0';
00856 
00857 #if defined(MOZ_DEMANGLE_SYMBOLS)
00858  /* See demangle.h in the gcc source for the voodoo */
00859   char * demangled = abi::__cxa_demangle(aSymbol,0,0,0);
00860 
00861   if (demangled)
00862   {
00863     strncpy(aBuffer,demangled,aBufLen);
00864     free(demangled);
00865   }
00866 #endif // MOZ_DEMANGLE_SYMBOLS
00867 }
00868 
00869 
00870 //----------------------------------------------------------------------
00871 
00872 NS_COM void
00873 nsTraceRefcntImpl::LoadLibrarySymbols(const char* aLibraryName,
00874                                   void* aLibrayHandle)
00875 {
00876 #ifdef NS_BUILD_REFCNT_LOGGING
00877 #if defined(_WIN32) && defined(_M_IX86) /* Win32 x86 only */
00878   if (!gInitialized)
00879     InitTraceLog();
00880 
00881   if (gAllocLog || gRefcntsLog) {
00882     fprintf(stdout, "### Loading symbols for %s\n", aLibraryName);
00883     fflush(stdout);
00884 
00885     HANDLE myProcess = ::GetCurrentProcess();    
00886     BOOL ok = EnsureSymInitialized();
00887     if (ok) {
00888       const char* baseName = aLibraryName;
00889       // just get the base name of the library if a full path was given:
00890       PRInt32 len = strlen(aLibraryName);
00891       for (PRInt32 i = len - 1; i >= 0; i--) {
00892         if (aLibraryName[i] == '\\') {
00893           baseName = &aLibraryName[i + 1];
00894           break;
00895         }
00896       }
00897       DWORD baseAddr = _SymLoadModule(myProcess,
00898                                      NULL,
00899                                      (char*)baseName,
00900                                      (char*)baseName,
00901                                      0,
00902                                      0);
00903       ok = (baseAddr != nsnull);
00904     }
00905     if (!ok) {
00906       LPVOID lpMsgBuf;
00907       FormatMessage( 
00908         FORMAT_MESSAGE_ALLOCATE_BUFFER | 
00909         FORMAT_MESSAGE_FROM_SYSTEM | 
00910         FORMAT_MESSAGE_IGNORE_INSERTS,
00911         NULL,
00912         GetLastError(),
00913         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
00914         (LPTSTR) &lpMsgBuf,
00915         0,
00916         NULL 
00917         );
00918       fprintf(stdout, "### ERROR: LoadLibrarySymbols for %s: %s\n",
00919               aLibraryName, lpMsgBuf);
00920       fflush(stdout);
00921       LocalFree( lpMsgBuf );
00922     }
00923   }
00924 #endif
00925 #endif
00926 }
00927 
00928 //----------------------------------------------------------------------
00929 
00930 
00931 
00932 
00933 
00934 
00935 // don't use the logging ones. :-)
00936 NS_IMETHODIMP_(nsrefcnt) nsTraceRefcntImpl::AddRef(void)
00937 {
00938   NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt");
00939   ++mRefCnt;
00940   return mRefCnt;
00941 }
00942 
00943 NS_IMETHODIMP_(nsrefcnt) nsTraceRefcntImpl::Release(void)                                
00944 {                                                                             
00945   NS_PRECONDITION(0 != mRefCnt, "dup release");                               
00946   --mRefCnt;                                                                  
00947   if (mRefCnt == 0) {                                                         
00948     mRefCnt = 1; /* stabilize */                                              
00949     delete this;                                                              
00950     return 0;                                                                 
00951   }
00952   return mRefCnt;                                                             
00953 }
00954 
00955 NS_IMPL_QUERY_INTERFACE1(nsTraceRefcntImpl, nsITraceRefcnt)
00956 
00957 nsTraceRefcntImpl::nsTraceRefcntImpl()
00958 {
00959   /* member initializers and constructor code */
00960 }
00961 
00962 NS_IMETHODIMP 
00963 nsTraceRefcntImpl::LogAddRef(void* aPtr,
00964                              nsrefcnt aRefcnt,
00965                              const char* aClazz,
00966                              PRUint32 classSize)
00967 {
00968 #ifdef NS_BUILD_REFCNT_LOGGING
00969   ASSERT_ACTIVITY_IS_LEGAL;
00970   if (!gInitialized)
00971     InitTraceLog();
00972   if (gLogging) {
00973     LOCK_TRACELOG();
00974 
00975     if (gBloatLog) {
00976       BloatEntry* entry = GetBloatEntry(aClazz, classSize);
00977       if (entry) {
00978         entry->AddRef(aRefcnt);
00979       }
00980     }
00981 
00982     // Here's the case where neither NS_NEWXPCOM nor MOZ_COUNT_CTOR were used,
00983     // yet we still want to see creation information:
00984 
00985     PRBool loggingThisType = (!gTypesToLog || LogThisType(aClazz));
00986     PRInt32 serialno = 0;
00987     if (gSerialNumbers && loggingThisType) {
00988       serialno = GetSerialNumber(aPtr, aRefcnt == 1);
00989       PRInt32* count = GetRefCount(aPtr);
00990       if(count)
00991         (*count)++;
00992 
00993     }
00994 
00995     PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
00996     if (aRefcnt == 1 && gAllocLog && loggingThisType && loggingThisObject) {
00997       fprintf(gAllocLog, "\n<%s> 0x%08X %d Create\n",
00998               aClazz, NS_PTR_TO_INT32(aPtr), serialno);
00999       WalkTheStack(gAllocLog);
01000     }
01001 
01002     if (gRefcntsLog && loggingThisType && loggingThisObject) {
01003       if (gLogToLeaky) {
01004         (*leakyLogAddRef)(aPtr, aRefcnt - 1, aRefcnt);
01005       }
01006       else {        
01007           // Can't use PR_LOG(), b/c it truncates the line
01008           fprintf(gRefcntsLog,
01009                   "\n<%s> 0x%08X %d AddRef %d\n", aClazz, NS_PTR_TO_INT32(aPtr), serialno, aRefcnt);       
01010           WalkTheStack(gRefcntsLog);
01011           fflush(gRefcntsLog);
01012       }
01013     }
01014     UNLOCK_TRACELOG();
01015   }
01016 #endif
01017   return NS_OK;
01018 }
01019 
01020 NS_IMETHODIMP 
01021 nsTraceRefcntImpl::LogRelease(void* aPtr,
01022                           nsrefcnt aRefcnt,
01023                           const char* aClazz)
01024 {
01025 #ifdef NS_BUILD_REFCNT_LOGGING
01026   ASSERT_ACTIVITY_IS_LEGAL;
01027   if (!gInitialized)
01028     InitTraceLog();
01029   if (gLogging) {
01030     LOCK_TRACELOG();
01031 
01032     if (gBloatLog) {
01033       BloatEntry* entry = GetBloatEntry(aClazz, 0);
01034       if (entry) {
01035         entry->Release(aRefcnt);
01036       }
01037     }
01038 
01039     PRBool loggingThisType = (!gTypesToLog || LogThisType(aClazz));
01040     PRInt32 serialno = 0;
01041     if (gSerialNumbers && loggingThisType) {
01042       serialno = GetSerialNumber(aPtr, PR_FALSE);
01043       PRInt32* count = GetRefCount(aPtr);
01044       if(count)
01045         (*count)--;
01046 
01047     }
01048 
01049     PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
01050     if (gRefcntsLog && loggingThisType && loggingThisObject) {
01051       if (gLogToLeaky) {
01052         (*leakyLogRelease)(aPtr, aRefcnt + 1, aRefcnt);
01053       }
01054       else {
01055           // Can't use PR_LOG(), b/c it truncates the line
01056           fprintf(gRefcntsLog,
01057                   "\n<%s> 0x%08X %d Release %d\n", aClazz, NS_PTR_TO_INT32(aPtr), serialno, aRefcnt);
01058           WalkTheStack(gRefcntsLog);
01059           fflush(gRefcntsLog);
01060       }
01061     }
01062 
01063     // Here's the case where neither NS_DELETEXPCOM nor MOZ_COUNT_DTOR were used,
01064     // yet we still want to see deletion information:
01065 
01066     if (aRefcnt == 0 && gAllocLog && loggingThisType && loggingThisObject) {
01067       fprintf(gAllocLog,
01068               "\n<%s> 0x%08X %d Destroy\n",
01069               aClazz, NS_PTR_TO_INT32(aPtr), serialno);
01070       WalkTheStack(gAllocLog);
01071     }
01072 
01073     if (aRefcnt == 0 && gSerialNumbers && loggingThisType) {
01074       RecycleSerialNumberPtr(aPtr);
01075     }
01076 
01077     UNLOCK_TRACELOG();
01078   }
01079 #endif
01080   return NS_OK;
01081 }
01082 
01083 NS_IMETHODIMP 
01084 nsTraceRefcntImpl::LogCtor(void* aPtr,
01085                            const char* aType,
01086                            PRUint32 aInstanceSize)
01087 {
01088 #ifdef NS_BUILD_REFCNT_LOGGING
01089   ASSERT_ACTIVITY_IS_LEGAL;
01090   if (!gInitialized)
01091     InitTraceLog();
01092 
01093   if (gLogging) {
01094     LOCK_TRACELOG();
01095 
01096     if (gBloatLog) {
01097       BloatEntry* entry = GetBloatEntry(aType, aInstanceSize);
01098       if (entry) {
01099         entry->Ctor();
01100       }
01101     }
01102 
01103     PRBool loggingThisType = (!gTypesToLog || LogThisType(aType));
01104     PRInt32 serialno = 0;
01105     if (gSerialNumbers && loggingThisType) {
01106       serialno = GetSerialNumber(aPtr, PR_TRUE);
01107     }
01108 
01109     PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
01110     if (gAllocLog && loggingThisType && loggingThisObject) {
01111       fprintf(gAllocLog, "\n<%s> 0x%08X %d Ctor (%d)\n",
01112              aType, NS_PTR_TO_INT32(aPtr), serialno, aInstanceSize);
01113       WalkTheStack(gAllocLog);
01114     }
01115 
01116     UNLOCK_TRACELOG();
01117   }
01118 #endif
01119   return NS_OK;
01120 }
01121 
01122 
01123 NS_IMETHODIMP 
01124 nsTraceRefcntImpl::LogDtor(void* aPtr, 
01125                            const char* aType,
01126                            PRUint32 aInstanceSize)
01127 {
01128 #ifdef NS_BUILD_REFCNT_LOGGING
01129   ASSERT_ACTIVITY_IS_LEGAL;
01130   if (!gInitialized)
01131     InitTraceLog();
01132 
01133   if (gLogging) {
01134     LOCK_TRACELOG();
01135 
01136     if (gBloatLog) {
01137       BloatEntry* entry = GetBloatEntry(aType, aInstanceSize);
01138       if (entry) {
01139         entry->Dtor();
01140       }
01141     }
01142 
01143     PRBool loggingThisType = (!gTypesToLog || LogThisType(aType));
01144     PRInt32 serialno = 0;
01145     if (gSerialNumbers && loggingThisType) {
01146       serialno = GetSerialNumber(aPtr, PR_FALSE);
01147       RecycleSerialNumberPtr(aPtr);
01148     }
01149 
01150     PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
01151 
01152     // (If we're on a losing architecture, don't do this because we'll be
01153     // using LogDeleteXPCOM instead to get file and line numbers.)
01154     if (gAllocLog && loggingThisType && loggingThisObject) {
01155       fprintf(gAllocLog, "\n<%s> 0x%08X %d Dtor (%d)\n",
01156              aType, NS_PTR_TO_INT32(aPtr), serialno, aInstanceSize);
01157       WalkTheStack(gAllocLog);
01158     }
01159 
01160     UNLOCK_TRACELOG();
01161   }
01162 #endif
01163   return NS_OK;
01164 }
01165 
01166 
01167 NS_IMETHODIMP 
01168 nsTraceRefcntImpl::LogAddCOMPtr(void* aCOMPtr,
01169                             nsISupports* aObject)
01170 {
01171 #if defined(NS_BUILD_REFCNT_LOGGING) && defined(HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR)
01172   // Get the most-derived object.
01173   void *object = dynamic_cast<void *>(aObject);
01174 
01175   // This is a very indirect way of finding out what the class is
01176   // of the object being logged.  If we're logging a specific type,
01177   // then 
01178   if (!gTypesToLog || !gSerialNumbers) {
01179     return NS_OK;
01180   }
01181   PRInt32 serialno = GetSerialNumber(object, PR_FALSE);
01182   if (serialno == 0) {
01183     return NS_OK;
01184   }
01185 
01186   if (!gInitialized)
01187     InitTraceLog();
01188   if (gLogging) {
01189     LOCK_TRACELOG();
01190 
01191     PRInt32* count = GetCOMPtrCount(object);
01192     if(count)
01193       (*count)++;
01194 
01195     PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
01196 
01197     if (gCOMPtrLog && loggingThisObject) {
01198       fprintf(gCOMPtrLog, "\n<?> 0x%08X %d nsCOMPtrAddRef %d 0x%08X\n",
01199               NS_PTR_TO_INT32(object), serialno, count?(*count):-1, NS_PTR_TO_INT32(aCOMPtr));
01200       WalkTheStack(gCOMPtrLog);
01201     }
01202 
01203     UNLOCK_TRACELOG();
01204   }
01205 #endif
01206   return NS_OK;
01207 }
01208 
01209 
01210 NS_IMETHODIMP 
01211 nsTraceRefcntImpl::LogReleaseCOMPtr(void* aCOMPtr,
01212                                     nsISupports* aObject)
01213 {
01214 #if defined(NS_BUILD_REFCNT_LOGGING) && defined(HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR)
01215   // Get the most-derived object.
01216   void *object = dynamic_cast<void *>(aObject);
01217 
01218   // This is a very indirect way of finding out what the class is
01219   // of the object being logged.  If we're logging a specific type,
01220   // then 
01221   if (!gTypesToLog || !gSerialNumbers) {
01222     return NS_OK;
01223   }
01224   PRInt32 serialno = GetSerialNumber(object, PR_FALSE);
01225   if (serialno == 0) {
01226     return NS_OK;
01227   }
01228 
01229   if (!gInitialized)
01230     InitTraceLog();
01231   if (gLogging) {
01232     LOCK_TRACELOG();
01233 
01234     PRInt32* count = GetCOMPtrCount(object);
01235     if(count)
01236       (*count)--;
01237 
01238     PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
01239 
01240     if (gCOMPtrLog && loggingThisObject) {
01241       fprintf(gCOMPtrLog, "\n<?> 0x%08X %d nsCOMPtrRelease %d 0x%08X\n",
01242               NS_PTR_TO_INT32(object), serialno, count?(*count):-1, NS_PTR_TO_INT32(aCOMPtr));
01243       WalkTheStack(gCOMPtrLog);
01244     }
01245 
01246     UNLOCK_TRACELOG();
01247   }
01248 #endif
01249   return NS_OK;
01250 }
01251 
01252 NS_COM void
01253 nsTraceRefcntImpl::Startup()
01254 {
01255 #ifdef NS_BUILD_REFCNT_LOGGING
01256   SetActivityIsLegal(PR_TRUE);
01257 #endif
01258 }
01259 
01260 NS_COM void
01261 nsTraceRefcntImpl::Shutdown()
01262 {
01263 #ifdef NS_BUILD_REFCNT_LOGGING
01264 
01265   if (gBloatView) {
01266     PL_HashTableDestroy(gBloatView);
01267     gBloatView = nsnull;
01268   }
01269   if (gTypesToLog) {
01270     PL_HashTableDestroy(gTypesToLog);
01271     gTypesToLog = nsnull;
01272   }
01273   if (gObjectsToLog) {
01274     PL_HashTableDestroy(gObjectsToLog);
01275     gObjectsToLog = nsnull;
01276   }
01277   if (gSerialNumbers) {
01278     PL_HashTableDestroy(gSerialNumbers);
01279     gSerialNumbers = nsnull;
01280   }
01281 
01282   SetActivityIsLegal(PR_FALSE);
01283 
01284 #endif
01285 }
01286 
01287 NS_COM void
01288 nsTraceRefcntImpl::SetActivityIsLegal(PRBool aLegal)
01289 {
01290 #ifdef NS_BUILD_REFCNT_LOGGING
01291   gActivityIsLegal = aLegal;
01292 #endif
01293 }
01294 
01295 
01296 NS_METHOD
01297 nsTraceRefcntImpl::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr)
01298 {
01299   *aInstancePtr = nsnull;
01300   nsITraceRefcnt* tracer = new nsTraceRefcntImpl();
01301   if (!tracer)
01302     return NS_ERROR_OUT_OF_MEMORY;
01303   
01304   nsresult rv = tracer->QueryInterface(aIID, aInstancePtr);
01305   if (NS_FAILED(rv)) {
01306     delete tracer;
01307   }
01308   
01309   return rv;
01310 }