bug 313956: expand installer .exe contents to make complete mar. r=ted.
[gecko.git] / xpcom / base / nsTraceRefcntImpl.cpp
blob9f8bb2794865e6f91e1ccd07dc2f6bd0dd82181f
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
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/
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.
15 * The Original Code is Mozilla Communicator client code.
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.
22 * Contributor(s):
23 * L. David Baron <dbaron@dbaron.org>
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.
37 * ***** END LICENSE BLOCK ***** */
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 "nsStackWalk.h"
54 #include "nsString.h"
56 #ifdef MOZ_IPC
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 #endif
66 #ifdef NS_TRACE_MALLOC
67 #include "nsTraceMalloc.h"
68 #endif
70 #include "mozilla/BlockingResourceBase.h"
72 #ifdef HAVE_DLOPEN
73 #include <dlfcn.h>
74 #endif
76 ////////////////////////////////////////////////////////////////////////////////
78 NS_COM void
79 NS_MeanAndStdDev(double n, double sumOfValues, double sumOfSquaredValues,
80 double *meanResult, double *stdDevResult)
82 double mean = 0.0, var = 0.0, stdDev = 0.0;
83 if (n > 0.0 && sumOfValues >= 0) {
84 mean = sumOfValues / n;
85 double temp = (n * sumOfSquaredValues) - (sumOfValues * sumOfValues);
86 if (temp < 0.0 || n <= 1)
87 var = 0.0;
88 else
89 var = temp / (n * (n - 1));
90 // for some reason, Windows says sqrt(0.0) is "-1.#J" (?!) so do this:
91 stdDev = var != 0.0 ? sqrt(var) : 0.0;
93 *meanResult = mean;
94 *stdDevResult = stdDev;
97 ////////////////////////////////////////////////////////////////////////////////
99 #define NS_IMPL_REFCNT_LOGGING
101 #ifdef NS_IMPL_REFCNT_LOGGING
102 #include "plhash.h"
103 #include "prmem.h"
105 #include "prlock.h"
107 static PRLock* gTraceLock;
109 #define LOCK_TRACELOG() PR_Lock(gTraceLock)
110 #define UNLOCK_TRACELOG() PR_Unlock(gTraceLock)
112 static PLHashTable* gBloatView;
113 static PLHashTable* gTypesToLog;
114 static PLHashTable* gObjectsToLog;
115 static PLHashTable* gSerialNumbers;
116 static PRInt32 gNextSerialNumber;
118 static PRBool gLogging;
119 static PRBool gLogToLeaky;
120 static PRBool gLogLeaksOnly;
122 static void (*leakyLogAddRef)(void* p, int oldrc, int newrc);
123 static void (*leakyLogRelease)(void* p, int oldrc, int newrc);
125 #define BAD_TLS_INDEX ((PRUintn) -1)
127 // if gActivityTLS == BAD_TLS_INDEX, then we're
128 // unitialized... otherwise this points to a NSPR TLS thread index
129 // indicating whether addref activity is legal. If the PTR_TO_INT32 is 0 then
130 // activity is ok, otherwise not!
131 static PRUintn gActivityTLS = BAD_TLS_INDEX;
133 static PRBool gInitialized;
134 static nsrefcnt gInitCount;
136 static FILE *gBloatLog = nsnull;
137 static FILE *gRefcntsLog = nsnull;
138 static FILE *gAllocLog = nsnull;
139 static FILE *gLeakyLog = nsnull;
140 static FILE *gCOMPtrLog = nsnull;
142 struct serialNumberRecord {
143 PRInt32 serialNumber;
144 PRInt32 refCount;
145 PRInt32 COMPtrCount;
148 struct nsTraceRefcntStats {
149 PRUint64 mAddRefs;
150 PRUint64 mReleases;
151 PRUint64 mCreates;
152 PRUint64 mDestroys;
153 double mRefsOutstandingTotal;
154 double mRefsOutstandingSquared;
155 double mObjsOutstandingTotal;
156 double mObjsOutstandingSquared;
159 // I hope to turn this on for everybody once we hit it a little less.
160 #ifdef DEBUG
161 static const char kStaticCtorDtorWarning[] =
162 "XPCOM objects created/destroyed from static ctor/dtor";
164 static void
165 AssertActivityIsLegal()
167 if (gActivityTLS == BAD_TLS_INDEX ||
168 NS_PTR_TO_INT32(PR_GetThreadPrivate(gActivityTLS)) != 0) {
169 if (PR_GetEnv("MOZ_FATAL_STATIC_XPCOM_CTORS_DTORS")) {
170 NS_RUNTIMEABORT(kStaticCtorDtorWarning);
171 } else {
172 NS_WARNING(kStaticCtorDtorWarning);
176 # define ASSERT_ACTIVITY_IS_LEGAL \
177 PR_BEGIN_MACRO \
178 AssertActivityIsLegal(); \
179 PR_END_MACRO
180 #else
181 # define ASSERT_ACTIVITY_IS_LEGAL PR_BEGIN_MACRO PR_END_MACRO
182 #endif // DEBUG
184 // These functions are copied from nsprpub/lib/ds/plhash.c, with changes
185 // to the functions not called Default* to free the serialNumberRecord or
186 // the BloatEntry.
188 static void *
189 DefaultAllocTable(void *pool, PRSize size)
191 return PR_MALLOC(size);
194 static void
195 DefaultFreeTable(void *pool, void *item)
197 PR_Free(item);
200 static PLHashEntry *
201 DefaultAllocEntry(void *pool, const void *key)
203 return PR_NEW(PLHashEntry);
206 static void
207 SerialNumberFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
209 if (flag == HT_FREE_ENTRY) {
210 PR_Free(reinterpret_cast<serialNumberRecord*>(he->value));
211 PR_Free(he);
215 static void
216 TypesToLogFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
218 if (flag == HT_FREE_ENTRY) {
219 nsCRT::free(const_cast<char*>
220 (reinterpret_cast<const char*>(he->key)));
221 PR_Free(he);
225 static const PLHashAllocOps serialNumberHashAllocOps = {
226 DefaultAllocTable, DefaultFreeTable,
227 DefaultAllocEntry, SerialNumberFreeEntry
230 static const PLHashAllocOps typesToLogHashAllocOps = {
231 DefaultAllocTable, DefaultFreeTable,
232 DefaultAllocEntry, TypesToLogFreeEntry
235 ////////////////////////////////////////////////////////////////////////////////
237 class BloatEntry {
238 public:
239 BloatEntry(const char* className, PRUint32 classSize)
240 : mClassSize(classSize) {
241 mClassName = PL_strdup(className);
242 Clear(&mNewStats);
243 Clear(&mAllStats);
244 mTotalLeaked = 0;
247 ~BloatEntry() {
248 PL_strfree(mClassName);
251 PRUint32 GetClassSize() { return (PRUint32)mClassSize; }
252 const char* GetClassName() { return mClassName; }
254 static void Clear(nsTraceRefcntStats* stats) {
255 stats->mAddRefs = 0;
256 stats->mReleases = 0;
257 stats->mCreates = 0;
258 stats->mDestroys = 0;
259 stats->mRefsOutstandingTotal = 0;
260 stats->mRefsOutstandingSquared = 0;
261 stats->mObjsOutstandingTotal = 0;
262 stats->mObjsOutstandingSquared = 0;
265 void Accumulate() {
266 mAllStats.mAddRefs += mNewStats.mAddRefs;
267 mAllStats.mReleases += mNewStats.mReleases;
268 mAllStats.mCreates += mNewStats.mCreates;
269 mAllStats.mDestroys += mNewStats.mDestroys;
270 mAllStats.mRefsOutstandingTotal += mNewStats.mRefsOutstandingTotal;
271 mAllStats.mRefsOutstandingSquared += mNewStats.mRefsOutstandingSquared;
272 mAllStats.mObjsOutstandingTotal += mNewStats.mObjsOutstandingTotal;
273 mAllStats.mObjsOutstandingSquared += mNewStats.mObjsOutstandingSquared;
274 Clear(&mNewStats);
277 void AddRef(nsrefcnt refcnt) {
278 mNewStats.mAddRefs++;
279 if (refcnt == 1) {
280 Ctor();
282 AccountRefs();
285 void Release(nsrefcnt refcnt) {
286 mNewStats.mReleases++;
287 if (refcnt == 0) {
288 Dtor();
290 AccountRefs();
293 void Ctor() {
294 mNewStats.mCreates++;
295 AccountObjs();
298 void Dtor() {
299 mNewStats.mDestroys++;
300 AccountObjs();
303 void AccountRefs() {
304 PRUint64 cnt = (mNewStats.mAddRefs - mNewStats.mReleases);
305 mNewStats.mRefsOutstandingTotal += cnt;
306 mNewStats.mRefsOutstandingSquared += cnt * cnt;
309 void AccountObjs() {
310 PRUint64 cnt = (mNewStats.mCreates - mNewStats.mDestroys);
311 mNewStats.mObjsOutstandingTotal += cnt;
312 mNewStats.mObjsOutstandingSquared += cnt * cnt;
315 static PRIntn DumpEntry(PLHashEntry *he, PRIntn i, void *arg) {
316 BloatEntry* entry = (BloatEntry*)he->value;
317 if (entry) {
318 entry->Accumulate();
319 static_cast<nsTArray<BloatEntry*>*>(arg)->AppendElement(entry);
321 return HT_ENUMERATE_NEXT;
324 static PRIntn TotalEntries(PLHashEntry *he, PRIntn i, void *arg) {
325 BloatEntry* entry = (BloatEntry*)he->value;
326 if (entry && nsCRT::strcmp(entry->mClassName, "TOTAL") != 0) {
327 entry->Total((BloatEntry*)arg);
329 return HT_ENUMERATE_NEXT;
332 void Total(BloatEntry* total) {
333 total->mAllStats.mAddRefs += mNewStats.mAddRefs + mAllStats.mAddRefs;
334 total->mAllStats.mReleases += mNewStats.mReleases + mAllStats.mReleases;
335 total->mAllStats.mCreates += mNewStats.mCreates + mAllStats.mCreates;
336 total->mAllStats.mDestroys += mNewStats.mDestroys + mAllStats.mDestroys;
337 total->mAllStats.mRefsOutstandingTotal += mNewStats.mRefsOutstandingTotal + mAllStats.mRefsOutstandingTotal;
338 total->mAllStats.mRefsOutstandingSquared += mNewStats.mRefsOutstandingSquared + mAllStats.mRefsOutstandingSquared;
339 total->mAllStats.mObjsOutstandingTotal += mNewStats.mObjsOutstandingTotal + mAllStats.mObjsOutstandingTotal;
340 total->mAllStats.mObjsOutstandingSquared += mNewStats.mObjsOutstandingSquared + mAllStats.mObjsOutstandingSquared;
341 PRUint64 count = (mNewStats.mCreates + mAllStats.mCreates);
342 total->mClassSize += mClassSize * count; // adjust for average in DumpTotal
343 total->mTotalLeaked += (PRUint64)(mClassSize *
344 ((mNewStats.mCreates + mAllStats.mCreates)
345 -(mNewStats.mDestroys + mAllStats.mDestroys)));
348 void DumpTotal(FILE* out) {
349 mClassSize /= mAllStats.mCreates;
350 Dump(-1, out, nsTraceRefcntImpl::ALL_STATS);
353 static PRBool HaveLeaks(nsTraceRefcntStats* stats) {
354 return ((stats->mAddRefs != stats->mReleases) ||
355 (stats->mCreates != stats->mDestroys));
358 PRBool PrintDumpHeader(FILE* out, const char* msg, nsTraceRefcntImpl::StatisticsType type) {
359 #ifdef MOZ_IPC
360 fprintf(out, "\n== BloatView: %s, %s process %d\n", msg,
361 XRE_ChildProcessTypeToString(XRE_GetProcessType()), getpid());
362 #else
363 fprintf(out, "\n== BloatView: %s\n", msg);
364 #endif
365 nsTraceRefcntStats& stats =
366 (type == nsTraceRefcntImpl::NEW_STATS) ? mNewStats : mAllStats;
367 if (gLogLeaksOnly && !HaveLeaks(&stats))
368 return PR_FALSE;
370 fprintf(out,
371 "\n" \
372 " |<----------------Class--------------->|<-----Bytes------>|<----------------Objects---------------->|<--------------References-------------->|\n" \
373 " Per-Inst Leaked Total Rem Mean StdDev Total Rem Mean StdDev\n");
375 this->DumpTotal(out);
377 return PR_TRUE;
380 void Dump(PRIntn i, FILE* out, nsTraceRefcntImpl::StatisticsType type) {
381 nsTraceRefcntStats* stats = (type == nsTraceRefcntImpl::NEW_STATS) ? &mNewStats : &mAllStats;
382 if (gLogLeaksOnly && !HaveLeaks(stats)) {
383 return;
386 double meanRefs, stddevRefs;
387 NS_MeanAndStdDev(stats->mAddRefs + stats->mReleases,
388 stats->mRefsOutstandingTotal,
389 stats->mRefsOutstandingSquared,
390 &meanRefs, &stddevRefs);
392 double meanObjs, stddevObjs;
393 NS_MeanAndStdDev(stats->mCreates + stats->mDestroys,
394 stats->mObjsOutstandingTotal,
395 stats->mObjsOutstandingSquared,
396 &meanObjs, &stddevObjs);
398 if ((stats->mAddRefs - stats->mReleases) != 0 ||
399 stats->mAddRefs != 0 ||
400 meanRefs != 0 ||
401 stddevRefs != 0 ||
402 (stats->mCreates - stats->mDestroys) != 0 ||
403 stats->mCreates != 0 ||
404 meanObjs != 0 ||
405 stddevObjs != 0) {
406 fprintf(out, "%4d %-40.40s %8d %8llu %8llu %8llu (%8.2f +/- %8.2f) %8llu %8llu (%8.2f +/- %8.2f)\n",
407 i+1, mClassName,
408 (PRInt32)mClassSize,
409 (nsCRT::strcmp(mClassName, "TOTAL"))
410 ?(PRUint64)((stats->mCreates - stats->mDestroys) * mClassSize)
411 :mTotalLeaked,
412 stats->mCreates,
413 (stats->mCreates - stats->mDestroys),
414 meanObjs,
415 stddevObjs,
416 stats->mAddRefs,
417 (stats->mAddRefs - stats->mReleases),
418 meanRefs,
419 stddevRefs);
423 protected:
424 char* mClassName;
425 double mClassSize; // this is stored as a double because of the way we compute the avg class size for total bloat
426 PRUint64 mTotalLeaked; // used only for TOTAL entry
427 nsTraceRefcntStats mNewStats;
428 nsTraceRefcntStats mAllStats;
431 static void
432 BloatViewFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
434 if (flag == HT_FREE_ENTRY) {
435 BloatEntry* entry = reinterpret_cast<BloatEntry*>(he->value);
436 delete entry;
437 PR_Free(he);
441 const static PLHashAllocOps bloatViewHashAllocOps = {
442 DefaultAllocTable, DefaultFreeTable,
443 DefaultAllocEntry, BloatViewFreeEntry
446 static void
447 RecreateBloatView()
449 gBloatView = PL_NewHashTable(256,
450 PL_HashString,
451 PL_CompareStrings,
452 PL_CompareValues,
453 &bloatViewHashAllocOps, NULL);
456 static BloatEntry*
457 GetBloatEntry(const char* aTypeName, PRUint32 aInstanceSize)
459 if (!gBloatView) {
460 RecreateBloatView();
462 BloatEntry* entry = NULL;
463 if (gBloatView) {
464 entry = (BloatEntry*)PL_HashTableLookup(gBloatView, aTypeName);
465 if (entry == NULL && aInstanceSize > 0) {
467 entry = new BloatEntry(aTypeName, aInstanceSize);
468 PLHashEntry* e = PL_HashTableAdd(gBloatView, aTypeName, entry);
469 if (e == NULL) {
470 delete entry;
471 entry = NULL;
473 } else {
474 NS_ASSERTION(aInstanceSize == 0 ||
475 entry->GetClassSize() == aInstanceSize,
476 "bad size recorded");
479 return entry;
482 static PRIntn DumpSerialNumbers(PLHashEntry* aHashEntry, PRIntn aIndex, void* aClosure)
484 serialNumberRecord* record = reinterpret_cast<serialNumberRecord *>(aHashEntry->value);
485 #ifdef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR
486 fprintf((FILE*) aClosure, "%d @%p (%d references; %d from COMPtrs)\n",
487 record->serialNumber,
488 NS_INT32_TO_PTR(aHashEntry->key),
489 record->refCount,
490 record->COMPtrCount);
491 #else
492 fprintf((FILE*) aClosure, "%d @%p (%d references)\n",
493 record->serialNumber,
494 NS_INT32_TO_PTR(aHashEntry->key),
495 record->refCount);
496 #endif
497 return HT_ENUMERATE_NEXT;
501 NS_SPECIALIZE_TEMPLATE
502 class nsDefaultComparator <BloatEntry*, BloatEntry*> {
503 public:
504 PRBool Equals(BloatEntry* const& aA, BloatEntry* const& aB) const {
505 return PL_strcmp(aA->GetClassName(), aB->GetClassName()) == 0;
507 PRBool LessThan(BloatEntry* const& aA, BloatEntry* const& aB) const {
508 return PL_strcmp(aA->GetClassName(), aB->GetClassName()) < 0;
512 #endif /* NS_IMPL_REFCNT_LOGGING */
514 NS_COM nsresult
515 nsTraceRefcntImpl::DumpStatistics(StatisticsType type, FILE* out)
517 #ifdef NS_IMPL_REFCNT_LOGGING
518 if (gBloatLog == nsnull || gBloatView == nsnull) {
519 return NS_ERROR_FAILURE;
521 if (out == nsnull) {
522 out = gBloatLog;
525 LOCK_TRACELOG();
527 PRBool wasLogging = gLogging;
528 gLogging = PR_FALSE; // turn off logging for this method
530 BloatEntry total("TOTAL", 0);
531 PL_HashTableEnumerateEntries(gBloatView, BloatEntry::TotalEntries, &total);
532 const char* msg;
533 if (type == NEW_STATS) {
534 if (gLogLeaksOnly)
535 msg = "NEW (incremental) LEAK STATISTICS";
536 else
537 msg = "NEW (incremental) LEAK AND BLOAT STATISTICS";
539 else {
540 if (gLogLeaksOnly)
541 msg = "ALL (cumulative) LEAK STATISTICS";
542 else
543 msg = "ALL (cumulative) LEAK AND BLOAT STATISTICS";
545 const PRBool leaked = total.PrintDumpHeader(out, msg, type);
547 nsTArray<BloatEntry*> entries;
548 PL_HashTableEnumerateEntries(gBloatView, BloatEntry::DumpEntry, &entries);
549 const PRUint32 count = entries.Length();
551 if (!gLogLeaksOnly || leaked) {
552 // Sort the entries alphabetically by classname.
553 entries.Sort();
555 for (PRUint32 i = 0; i < count; ++i) {
556 BloatEntry* entry = entries[i];
557 entry->Dump(i, out, type);
560 fprintf(out, "\n");
563 fprintf(out, "nsTraceRefcntImpl::DumpStatistics: %d entries\n", count);
565 if (gSerialNumbers) {
566 fprintf(out, "\nSerial Numbers of Leaked Objects:\n");
567 PL_HashTableEnumerateEntries(gSerialNumbers, DumpSerialNumbers, out);
570 gLogging = wasLogging;
571 UNLOCK_TRACELOG();
572 #endif
574 return NS_OK;
577 NS_COM void
578 nsTraceRefcntImpl::ResetStatistics()
580 #ifdef NS_IMPL_REFCNT_LOGGING
581 LOCK_TRACELOG();
582 if (gBloatView) {
583 PL_HashTableDestroy(gBloatView);
584 gBloatView = nsnull;
586 UNLOCK_TRACELOG();
587 #endif
590 #ifdef NS_IMPL_REFCNT_LOGGING
591 static PRBool LogThisType(const char* aTypeName)
593 void* he = PL_HashTableLookup(gTypesToLog, aTypeName);
594 return nsnull != he;
597 static PRInt32 GetSerialNumber(void* aPtr, PRBool aCreate)
599 PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr);
600 if (hep && *hep) {
601 return PRInt32((reinterpret_cast<serialNumberRecord*>((*hep)->value))->serialNumber);
603 else if (aCreate) {
604 serialNumberRecord *record = PR_NEW(serialNumberRecord);
605 record->serialNumber = ++gNextSerialNumber;
606 record->refCount = 0;
607 record->COMPtrCount = 0;
608 PL_HashTableRawAdd(gSerialNumbers, hep, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr, reinterpret_cast<void*>(record));
609 return gNextSerialNumber;
611 else {
612 return 0;
616 static PRInt32* GetRefCount(void* aPtr)
618 PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr);
619 if (hep && *hep) {
620 return &((reinterpret_cast<serialNumberRecord*>((*hep)->value))->refCount);
621 } else {
622 return nsnull;
626 static PRInt32* GetCOMPtrCount(void* aPtr)
628 PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr);
629 if (hep && *hep) {
630 return &((reinterpret_cast<serialNumberRecord*>((*hep)->value))->COMPtrCount);
631 } else {
632 return nsnull;
636 static void RecycleSerialNumberPtr(void* aPtr)
638 PL_HashTableRemove(gSerialNumbers, aPtr);
641 static PRBool LogThisObj(PRInt32 aSerialNumber)
643 return nsnull != PL_HashTableLookup(gObjectsToLog, (const void*)(aSerialNumber));
646 #ifdef XP_WIN
647 #define FOPEN_NO_INHERIT "N"
648 #else
649 #define FOPEN_NO_INHERIT
650 #endif
652 static PRBool InitLog(const char* envVar, const char* msg, FILE* *result)
654 const char* value = getenv(envVar);
655 if (value) {
656 if (nsCRT::strcmp(value, "1") == 0) {
657 *result = stdout;
658 fprintf(stdout, "### %s defined -- logging %s to stdout\n",
659 envVar, msg);
660 return PR_TRUE;
662 else if (nsCRT::strcmp(value, "2") == 0) {
663 *result = stderr;
664 fprintf(stdout, "### %s defined -- logging %s to stderr\n",
665 envVar, msg);
666 return PR_TRUE;
668 else {
669 FILE *stream;
670 nsCAutoString fname(value);
671 #ifdef MOZ_IPC
672 if (XRE_GetProcessType() != GeckoProcessType_Default) {
673 bool hasLogExtension =
674 fname.RFind(".log", PR_TRUE, -1, 4) == kNotFound ? false : true;
675 if (hasLogExtension)
676 fname.Cut(fname.Length() - 4, 4);
677 fname.AppendLiteral("_");
678 fname.Append((char*)XRE_ChildProcessTypeToString(XRE_GetProcessType()));
679 fname.AppendLiteral("_pid");
680 fname.AppendInt((PRUint32)getpid());
681 if (hasLogExtension)
682 fname.AppendLiteral(".log");
684 #endif
685 stream = ::fopen(fname.get(), "w" FOPEN_NO_INHERIT);
686 if (stream != NULL) {
687 *result = stream;
688 fprintf(stdout, "### %s defined -- logging %s to %s\n",
689 envVar, msg, fname.get());
691 else {
692 fprintf(stdout, "### %s defined -- unable to log %s to %s\n",
693 envVar, msg, fname.get());
695 return stream != NULL;
698 return PR_FALSE;
702 static PLHashNumber HashNumber(const void* aKey)
704 return PLHashNumber(NS_PTR_TO_INT32(aKey));
707 static void InitTraceLog(void)
709 if (gInitialized) return;
710 gInitialized = PR_TRUE;
712 PRBool defined;
713 defined = InitLog("XPCOM_MEM_BLOAT_LOG", "bloat/leaks", &gBloatLog);
714 if (!defined)
715 gLogLeaksOnly = InitLog("XPCOM_MEM_LEAK_LOG", "leaks", &gBloatLog);
716 if (defined || gLogLeaksOnly) {
717 RecreateBloatView();
718 if (!gBloatView) {
719 NS_WARNING("out of memory");
720 gBloatLog = nsnull;
721 gLogLeaksOnly = PR_FALSE;
725 (void)InitLog("XPCOM_MEM_REFCNT_LOG", "refcounts", &gRefcntsLog);
727 (void)InitLog("XPCOM_MEM_ALLOC_LOG", "new/delete", &gAllocLog);
729 defined = InitLog("XPCOM_MEM_LEAKY_LOG", "for leaky", &gLeakyLog);
730 if (defined) {
731 gLogToLeaky = PR_TRUE;
732 PRFuncPtr p = nsnull, q = nsnull;
733 #ifdef HAVE_DLOPEN
735 PRLibrary *lib = nsnull;
736 p = PR_FindFunctionSymbolAndLibrary("__log_addref", &lib);
737 if (lib) {
738 PR_UnloadLibrary(lib);
739 lib = nsnull;
741 q = PR_FindFunctionSymbolAndLibrary("__log_release", &lib);
742 if (lib) {
743 PR_UnloadLibrary(lib);
746 #endif
747 if (p && q) {
748 leakyLogAddRef = (void (*)(void*,int,int)) p;
749 leakyLogRelease = (void (*)(void*,int,int)) q;
751 else {
752 gLogToLeaky = PR_FALSE;
753 fprintf(stdout, "### ERROR: XPCOM_MEM_LEAKY_LOG defined, but can't locate __log_addref and __log_release symbols\n");
754 fflush(stdout);
758 const char* classes = getenv("XPCOM_MEM_LOG_CLASSES");
760 #ifdef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR
761 if (classes) {
762 (void)InitLog("XPCOM_MEM_COMPTR_LOG", "nsCOMPtr", &gCOMPtrLog);
763 } else {
764 if (getenv("XPCOM_MEM_COMPTR_LOG")) {
765 fprintf(stdout, "### XPCOM_MEM_COMPTR_LOG defined -- but XPCOM_MEM_LOG_CLASSES is not defined\n");
768 #else
769 const char* comptr_log = getenv("XPCOM_MEM_COMPTR_LOG");
770 if (comptr_log) {
771 fprintf(stdout, "### XPCOM_MEM_COMPTR_LOG defined -- but it will not work without dynamic_cast\n");
773 #endif
775 if (classes) {
776 // if XPCOM_MEM_LOG_CLASSES was set to some value, the value is interpreted
777 // as a list of class names to track
778 gTypesToLog = PL_NewHashTable(256,
779 PL_HashString,
780 PL_CompareStrings,
781 PL_CompareValues,
782 &typesToLogHashAllocOps, NULL);
783 if (!gTypesToLog) {
784 NS_WARNING("out of memory");
785 fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- unable to log specific classes\n");
787 else {
788 fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- only logging these classes: ");
789 const char* cp = classes;
790 for (;;) {
791 char* cm = (char*) strchr(cp, ',');
792 if (cm) {
793 *cm = '\0';
795 PL_HashTableAdd(gTypesToLog, nsCRT::strdup(cp), (void*)1);
796 fprintf(stdout, "%s ", cp);
797 if (!cm) break;
798 *cm = ',';
799 cp = cm + 1;
801 fprintf(stdout, "\n");
804 gSerialNumbers = PL_NewHashTable(256,
805 HashNumber,
806 PL_CompareValues,
807 PL_CompareValues,
808 &serialNumberHashAllocOps, NULL);
813 const char* objects = getenv("XPCOM_MEM_LOG_OBJECTS");
814 if (objects) {
815 gObjectsToLog = PL_NewHashTable(256,
816 HashNumber,
817 PL_CompareValues,
818 PL_CompareValues,
819 NULL, NULL);
821 if (!gObjectsToLog) {
822 NS_WARNING("out of memory");
823 fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- unable to log specific objects\n");
825 else if (! (gRefcntsLog || gAllocLog || gCOMPtrLog)) {
826 fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- but none of XPCOM_MEM_(REFCNT|ALLOC|COMPTR)_LOG is defined\n");
828 else {
829 fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- only logging these objects: ");
830 const char* cp = objects;
831 for (;;) {
832 char* cm = (char*) strchr(cp, ',');
833 if (cm) {
834 *cm = '\0';
836 PRInt32 top = 0;
837 PRInt32 bottom = 0;
838 while (*cp) {
839 if (*cp == '-') {
840 bottom = top;
841 top = 0;
842 ++cp;
844 top *= 10;
845 top += *cp - '0';
846 ++cp;
848 if (!bottom) {
849 bottom = top;
851 for(PRInt32 serialno = bottom; serialno <= top; serialno++) {
852 PL_HashTableAdd(gObjectsToLog, (const void*)serialno, (void*)1);
853 fprintf(stdout, "%d ", serialno);
855 if (!cm) break;
856 *cm = ',';
857 cp = cm + 1;
859 fprintf(stdout, "\n");
864 if (gBloatLog || gRefcntsLog || gAllocLog || gLeakyLog || gCOMPtrLog) {
865 gLogging = PR_TRUE;
868 gTraceLock = PR_NewLock();
871 #endif
873 extern "C" {
875 static void PrintStackFrame(void *aPC, void *aClosure)
877 FILE *stream = (FILE*)aClosure;
878 nsCodeAddressDetails details;
879 char buf[1024];
881 NS_DescribeCodeAddress(aPC, &details);
882 NS_FormatCodeAddressDetails(aPC, &details, buf, sizeof(buf));
883 fputs(buf, stream);
888 NS_COM void
889 nsTraceRefcntImpl::WalkTheStack(FILE* aStream)
891 NS_StackWalk(PrintStackFrame, 2, aStream);
894 //----------------------------------------------------------------------
896 // This thing is exported by libstdc++
897 // Yes, this is a gcc only hack
898 #if defined(MOZ_DEMANGLE_SYMBOLS)
899 #include <cxxabi.h>
900 #include <stdlib.h> // for free()
901 #endif // MOZ_DEMANGLE_SYMBOLS
903 NS_COM void
904 nsTraceRefcntImpl::DemangleSymbol(const char * aSymbol,
905 char * aBuffer,
906 int aBufLen)
908 NS_ASSERTION(nsnull != aSymbol,"null symbol");
909 NS_ASSERTION(nsnull != aBuffer,"null buffer");
910 NS_ASSERTION(aBufLen >= 32 ,"pulled 32 out of you know where");
912 aBuffer[0] = '\0';
914 #if defined(MOZ_DEMANGLE_SYMBOLS)
915 /* See demangle.h in the gcc source for the voodoo */
916 char * demangled = abi::__cxa_demangle(aSymbol,0,0,0);
918 if (demangled)
920 strncpy(aBuffer,demangled,aBufLen);
921 free(demangled);
923 #endif // MOZ_DEMANGLE_SYMBOLS
927 //----------------------------------------------------------------------
929 EXPORT_XPCOM_API(void)
930 NS_LogInit()
932 #ifdef NS_IMPL_REFCNT_LOGGING
933 if (++gInitCount)
934 nsTraceRefcntImpl::SetActivityIsLegal(PR_TRUE);
935 #endif
937 #ifdef NS_TRACE_MALLOC
938 // XXX we don't have to worry about shutting down trace-malloc; it
939 // handles this itself, through an atexit() callback.
940 if (!NS_TraceMallocHasStarted())
941 NS_TraceMallocStartup(-1); // -1 == no logging
942 #endif
945 EXPORT_XPCOM_API(void)
946 NS_LogTerm()
948 mozilla::LogTerm();
951 namespace mozilla {
952 void
953 LogTerm()
955 NS_ASSERTION(gInitCount > 0,
956 "NS_LogTerm without matching NS_LogInit");
958 if (--gInitCount == 0) {
959 #ifdef DEBUG
960 /* FIXME bug 491977: This is only going to operate on the
961 * BlockingResourceBase which is compiled into
962 * libxul/libxpcom_core.so. Anyone using external linkage will
963 * have their own copy of BlockingResourceBase statics which will
964 * not be freed by this method.
966 * It sounds like what we really want is to be able to register a
967 * callback function to call at XPCOM shutdown. Note that with
968 * this solution, however, we need to guarantee that
969 * BlockingResourceBase::Shutdown() runs after all other shutdown
970 * functions.
972 BlockingResourceBase::Shutdown();
973 #endif
975 if (gInitialized) {
976 nsTraceRefcntImpl::DumpStatistics();
977 nsTraceRefcntImpl::ResetStatistics();
979 nsTraceRefcntImpl::Shutdown();
980 #ifdef NS_IMPL_REFCNT_LOGGING
981 nsTraceRefcntImpl::SetActivityIsLegal(PR_FALSE);
982 gActivityTLS = BAD_TLS_INDEX;
983 #endif
987 } // namespace mozilla
989 EXPORT_XPCOM_API(void)
990 NS_LogAddRef(void* aPtr, nsrefcnt aRefcnt,
991 const char* aClazz, PRUint32 classSize)
993 #ifdef NS_IMPL_REFCNT_LOGGING
994 ASSERT_ACTIVITY_IS_LEGAL;
995 if (!gInitialized)
996 InitTraceLog();
997 if (gLogging) {
998 LOCK_TRACELOG();
1000 if (gBloatLog) {
1001 BloatEntry* entry = GetBloatEntry(aClazz, classSize);
1002 if (entry) {
1003 entry->AddRef(aRefcnt);
1007 // Here's the case where MOZ_COUNT_CTOR was not used,
1008 // yet we still want to see creation information:
1010 PRBool loggingThisType = (!gTypesToLog || LogThisType(aClazz));
1011 PRInt32 serialno = 0;
1012 if (gSerialNumbers && loggingThisType) {
1013 serialno = GetSerialNumber(aPtr, aRefcnt == 1);
1014 NS_ASSERTION(serialno != 0,
1015 "Serial number requested for unrecognized pointer! "
1016 "Are you memmoving a refcounted object?");
1017 PRInt32* count = GetRefCount(aPtr);
1018 if(count)
1019 (*count)++;
1023 PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
1024 if (aRefcnt == 1 && gAllocLog && loggingThisType && loggingThisObject) {
1025 fprintf(gAllocLog, "\n<%s> 0x%08X %d Create\n",
1026 aClazz, NS_PTR_TO_INT32(aPtr), serialno);
1027 nsTraceRefcntImpl::WalkTheStack(gAllocLog);
1030 if (gRefcntsLog && loggingThisType && loggingThisObject) {
1031 if (gLogToLeaky) {
1032 (*leakyLogAddRef)(aPtr, aRefcnt - 1, aRefcnt);
1034 else {
1035 // Can't use PR_LOG(), b/c it truncates the line
1036 fprintf(gRefcntsLog,
1037 "\n<%s> 0x%08X %d AddRef %d\n", aClazz, NS_PTR_TO_INT32(aPtr), serialno, aRefcnt);
1038 nsTraceRefcntImpl::WalkTheStack(gRefcntsLog);
1039 fflush(gRefcntsLog);
1042 UNLOCK_TRACELOG();
1044 #endif
1047 EXPORT_XPCOM_API(void)
1048 NS_LogRelease(void* aPtr, nsrefcnt aRefcnt, const char* aClazz)
1050 #ifdef NS_IMPL_REFCNT_LOGGING
1051 ASSERT_ACTIVITY_IS_LEGAL;
1052 if (!gInitialized)
1053 InitTraceLog();
1054 if (gLogging) {
1055 LOCK_TRACELOG();
1057 if (gBloatLog) {
1058 BloatEntry* entry = GetBloatEntry(aClazz, 0);
1059 if (entry) {
1060 entry->Release(aRefcnt);
1064 PRBool loggingThisType = (!gTypesToLog || LogThisType(aClazz));
1065 PRInt32 serialno = 0;
1066 if (gSerialNumbers && loggingThisType) {
1067 serialno = GetSerialNumber(aPtr, PR_FALSE);
1068 NS_ASSERTION(serialno != 0,
1069 "Serial number requested for unrecognized pointer! "
1070 "Are you memmoving a refcounted object?");
1071 PRInt32* count = GetRefCount(aPtr);
1072 if(count)
1073 (*count)--;
1077 PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
1078 if (gRefcntsLog && loggingThisType && loggingThisObject) {
1079 if (gLogToLeaky) {
1080 (*leakyLogRelease)(aPtr, aRefcnt + 1, aRefcnt);
1082 else {
1083 // Can't use PR_LOG(), b/c it truncates the line
1084 fprintf(gRefcntsLog,
1085 "\n<%s> 0x%08X %d Release %d\n", aClazz, NS_PTR_TO_INT32(aPtr), serialno, aRefcnt);
1086 nsTraceRefcntImpl::WalkTheStack(gRefcntsLog);
1087 fflush(gRefcntsLog);
1091 // Here's the case where MOZ_COUNT_DTOR was not used,
1092 // yet we still want to see deletion information:
1094 if (aRefcnt == 0 && gAllocLog && loggingThisType && loggingThisObject) {
1095 fprintf(gAllocLog,
1096 "\n<%s> 0x%08X %d Destroy\n",
1097 aClazz, NS_PTR_TO_INT32(aPtr), serialno);
1098 nsTraceRefcntImpl::WalkTheStack(gAllocLog);
1101 if (aRefcnt == 0 && gSerialNumbers && loggingThisType) {
1102 RecycleSerialNumberPtr(aPtr);
1105 UNLOCK_TRACELOG();
1107 #endif
1110 EXPORT_XPCOM_API(void)
1111 NS_LogCtor(void* aPtr, const char* aType, PRUint32 aInstanceSize)
1113 #ifdef NS_IMPL_REFCNT_LOGGING
1114 ASSERT_ACTIVITY_IS_LEGAL;
1115 if (!gInitialized)
1116 InitTraceLog();
1118 if (gLogging) {
1119 LOCK_TRACELOG();
1121 if (gBloatLog) {
1122 BloatEntry* entry = GetBloatEntry(aType, aInstanceSize);
1123 if (entry) {
1124 entry->Ctor();
1128 PRBool loggingThisType = (!gTypesToLog || LogThisType(aType));
1129 PRInt32 serialno = 0;
1130 if (gSerialNumbers && loggingThisType) {
1131 serialno = GetSerialNumber(aPtr, PR_TRUE);
1134 PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
1135 if (gAllocLog && loggingThisType && loggingThisObject) {
1136 fprintf(gAllocLog, "\n<%s> 0x%08X %d Ctor (%d)\n",
1137 aType, NS_PTR_TO_INT32(aPtr), serialno, aInstanceSize);
1138 nsTraceRefcntImpl::WalkTheStack(gAllocLog);
1141 UNLOCK_TRACELOG();
1143 #endif
1147 EXPORT_XPCOM_API(void)
1148 NS_LogDtor(void* aPtr, const char* aType, PRUint32 aInstanceSize)
1150 #ifdef NS_IMPL_REFCNT_LOGGING
1151 ASSERT_ACTIVITY_IS_LEGAL;
1152 if (!gInitialized)
1153 InitTraceLog();
1155 if (gLogging) {
1156 LOCK_TRACELOG();
1158 if (gBloatLog) {
1159 BloatEntry* entry = GetBloatEntry(aType, aInstanceSize);
1160 if (entry) {
1161 entry->Dtor();
1165 PRBool loggingThisType = (!gTypesToLog || LogThisType(aType));
1166 PRInt32 serialno = 0;
1167 if (gSerialNumbers && loggingThisType) {
1168 serialno = GetSerialNumber(aPtr, PR_FALSE);
1169 RecycleSerialNumberPtr(aPtr);
1172 PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
1174 // (If we're on a losing architecture, don't do this because we'll be
1175 // using LogDeleteXPCOM instead to get file and line numbers.)
1176 if (gAllocLog && loggingThisType && loggingThisObject) {
1177 fprintf(gAllocLog, "\n<%s> 0x%08X %d Dtor (%d)\n",
1178 aType, NS_PTR_TO_INT32(aPtr), serialno, aInstanceSize);
1179 nsTraceRefcntImpl::WalkTheStack(gAllocLog);
1182 UNLOCK_TRACELOG();
1184 #endif
1188 EXPORT_XPCOM_API(void)
1189 NS_LogCOMPtrAddRef(void* aCOMPtr, nsISupports* aObject)
1191 #if defined(NS_IMPL_REFCNT_LOGGING) && defined(HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR)
1192 // Get the most-derived object.
1193 void *object = dynamic_cast<void *>(aObject);
1195 // This is a very indirect way of finding out what the class is
1196 // of the object being logged. If we're logging a specific type,
1197 // then
1198 if (!gTypesToLog || !gSerialNumbers) {
1199 return;
1201 PRInt32 serialno = GetSerialNumber(object, PR_FALSE);
1202 if (serialno == 0) {
1203 return;
1206 if (!gInitialized)
1207 InitTraceLog();
1208 if (gLogging) {
1209 LOCK_TRACELOG();
1211 PRInt32* count = GetCOMPtrCount(object);
1212 if(count)
1213 (*count)++;
1215 PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
1217 if (gCOMPtrLog && loggingThisObject) {
1218 fprintf(gCOMPtrLog, "\n<?> 0x%08X %d nsCOMPtrAddRef %d 0x%08X\n",
1219 NS_PTR_TO_INT32(object), serialno, count?(*count):-1, NS_PTR_TO_INT32(aCOMPtr));
1220 nsTraceRefcntImpl::WalkTheStack(gCOMPtrLog);
1223 UNLOCK_TRACELOG();
1225 #endif
1229 EXPORT_XPCOM_API(void)
1230 NS_LogCOMPtrRelease(void* aCOMPtr, nsISupports* aObject)
1232 #if defined(NS_IMPL_REFCNT_LOGGING) && defined(HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR)
1233 // Get the most-derived object.
1234 void *object = dynamic_cast<void *>(aObject);
1236 // This is a very indirect way of finding out what the class is
1237 // of the object being logged. If we're logging a specific type,
1238 // then
1239 if (!gTypesToLog || !gSerialNumbers) {
1240 return;
1242 PRInt32 serialno = GetSerialNumber(object, PR_FALSE);
1243 if (serialno == 0) {
1244 return;
1247 if (!gInitialized)
1248 InitTraceLog();
1249 if (gLogging) {
1250 LOCK_TRACELOG();
1252 PRInt32* count = GetCOMPtrCount(object);
1253 if(count)
1254 (*count)--;
1256 PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
1258 if (gCOMPtrLog && loggingThisObject) {
1259 fprintf(gCOMPtrLog, "\n<?> 0x%08X %d nsCOMPtrRelease %d 0x%08X\n",
1260 NS_PTR_TO_INT32(object), serialno, count?(*count):-1, NS_PTR_TO_INT32(aCOMPtr));
1261 nsTraceRefcntImpl::WalkTheStack(gCOMPtrLog);
1264 UNLOCK_TRACELOG();
1266 #endif
1269 NS_COM void
1270 nsTraceRefcntImpl::Startup()
1274 NS_COM void
1275 nsTraceRefcntImpl::Shutdown()
1277 #ifdef NS_IMPL_REFCNT_LOGGING
1279 if (gBloatView) {
1280 PL_HashTableDestroy(gBloatView);
1281 gBloatView = nsnull;
1283 if (gTypesToLog) {
1284 PL_HashTableDestroy(gTypesToLog);
1285 gTypesToLog = nsnull;
1287 if (gObjectsToLog) {
1288 PL_HashTableDestroy(gObjectsToLog);
1289 gObjectsToLog = nsnull;
1291 if (gSerialNumbers) {
1292 PL_HashTableDestroy(gSerialNumbers);
1293 gSerialNumbers = nsnull;
1295 #endif
1298 NS_COM void
1299 nsTraceRefcntImpl::SetActivityIsLegal(PRBool aLegal)
1301 #ifdef NS_IMPL_REFCNT_LOGGING
1302 if (gActivityTLS == BAD_TLS_INDEX)
1303 PR_NewThreadPrivateIndex(&gActivityTLS, nsnull);
1305 PR_SetThreadPrivate(gActivityTLS, NS_INT32_TO_PTR(!aLegal));
1306 #endif
1309 NS_IMPL_QUERY_INTERFACE1(nsTraceRefcntImpl, nsITraceRefcnt)
1311 NS_IMETHODIMP_(nsrefcnt) nsTraceRefcntImpl::AddRef(void)
1313 return 2;
1316 NS_IMETHODIMP_(nsrefcnt) nsTraceRefcntImpl::Release(void)
1318 return 1;
1321 NS_IMETHODIMP
1322 nsTraceRefcntImpl::LogAddRef(void *aPtr, nsrefcnt aNewRefcnt,
1323 const char *aTypeName, PRUint32 aSize)
1325 NS_LogAddRef(aPtr, aNewRefcnt, aTypeName, aSize);
1326 return NS_OK;
1329 NS_IMETHODIMP
1330 nsTraceRefcntImpl::LogRelease(void *aPtr, nsrefcnt aNewRefcnt,
1331 const char *aTypeName)
1333 NS_LogRelease(aPtr, aNewRefcnt, aTypeName);
1334 return NS_OK;
1337 NS_IMETHODIMP
1338 nsTraceRefcntImpl::LogCtor(void *aPtr, const char *aTypeName, PRUint32 aSize)
1340 NS_LogCtor(aPtr, aTypeName, aSize);
1341 return NS_OK;
1344 NS_IMETHODIMP
1345 nsTraceRefcntImpl::LogDtor(void *aPtr, const char *aTypeName, PRUint32 aSize)
1347 NS_LogDtor(aPtr, aTypeName, aSize);
1348 return NS_OK;
1351 NS_IMETHODIMP
1352 nsTraceRefcntImpl::LogAddCOMPtr(void *aCOMPtr, nsISupports* aObject)
1354 NS_LogCOMPtrAddRef(aCOMPtr, aObject);
1355 return NS_OK;
1358 NS_IMETHODIMP
1359 nsTraceRefcntImpl::LogReleaseCOMPtr(void *aCOMPtr, nsISupports* aObject)
1361 NS_LogCOMPtrRelease(aCOMPtr, aObject);
1362 return NS_OK;
1365 static const nsTraceRefcntImpl kTraceRefcntImpl;
1367 NS_METHOD
1368 nsTraceRefcntImpl::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr)
1370 return const_cast<nsTraceRefcntImpl*>(&kTraceRefcntImpl)->
1371 QueryInterface(aIID, aInstancePtr);