VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/xpcom/base/nsTraceRefcntImpl.cpp@ 4837

Last change on this file since 4837 was 1, checked in by vboxsync, 54 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 40.4 KB
Line 
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 "nscore.h"
41#include "nsISupports.h"
42#include "nsVoidArray.h"
43#include "prprf.h"
44#include "prlog.h"
45#include "plstr.h"
46#include <stdlib.h>
47#include "nsCOMPtr.h"
48#include "nsCRT.h"
49#include <math.h>
50
51#if defined(_WIN32)
52#include <windows.h>
53#elif defined(linux) && defined(__GLIBC__) && (defined(__i386) || defined(PPC))
54#include <setjmp.h>
55
56//
57// On glibc 2.1, the Dl_info api defined in <dlfcn.h> is only exposed
58// if __USE_GNU is defined. I suppose its some kind of standards
59// adherence thing.
60//
61#if (__GLIBC_MINOR__ >= 1) && !defined(__USE_GNU)
62#define __USE_GNU
63#endif
64
65#include <dlfcn.h>
66#endif
67
68#ifdef HAVE_LIBDL
69#include <dlfcn.h>
70#endif
71
72#if defined(XP_MAC) && !TARGET_CARBON
73#include "macstdlibextras.h"
74#endif
75
76////////////////////////////////////////////////////////////////////////////////
77
78NS_COM void
79NS_MeanAndStdDev(double n, double sumOfValues, double sumOfSquaredValues,
80 double *meanResult, double *stdDevResult)
81{
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;
92 }
93 *meanResult = mean;
94 *stdDevResult = stdDev;
95}
96
97////////////////////////////////////////////////////////////////////////////////
98
99#ifdef NS_BUILD_REFCNT_LOGGING
100#include "plhash.h"
101#include "prmem.h"
102
103#include "prlock.h"
104
105static PRLock* gTraceLock;
106
107#define LOCK_TRACELOG() PR_Lock(gTraceLock)
108#define UNLOCK_TRACELOG() PR_Unlock(gTraceLock)
109
110static PLHashTable* gBloatView;
111static PLHashTable* gTypesToLog;
112static PLHashTable* gObjectsToLog;
113static PLHashTable* gSerialNumbers;
114static PRInt32 gNextSerialNumber;
115
116static PRBool gLogging;
117static PRBool gLogToLeaky;
118static PRBool gLogLeaksOnly;
119
120static void (*leakyLogAddRef)(void* p, int oldrc, int newrc);
121static void (*leakyLogRelease)(void* p, int oldrc, int newrc);
122
123static PRBool gInitialized = PR_FALSE;
124static FILE *gBloatLog = nsnull;
125static FILE *gRefcntsLog = nsnull;
126static FILE *gAllocLog = nsnull;
127static FILE *gLeakyLog = nsnull;
128static FILE *gCOMPtrLog = nsnull;
129static PRBool gActivityIsLegal = PR_FALSE;
130
131struct serialNumberRecord {
132 PRInt32 serialNumber;
133 PRInt32 refCount;
134 PRInt32 COMPtrCount;
135};
136
137struct nsTraceRefcntStats {
138 nsrefcnt mAddRefs;
139 nsrefcnt mReleases;
140 nsrefcnt mCreates;
141 nsrefcnt mDestroys;
142 double mRefsOutstandingTotal;
143 double mRefsOutstandingSquared;
144 double mObjsOutstandingTotal;
145 double mObjsOutstandingSquared;
146};
147
148#ifdef DEBUG_dbaron_off
149 // I hope to turn this on for everybody once we hit it a little less.
150#define ASSERT_ACTIVITY_IS_LEGAL \
151 NS_WARN_IF_FALSE(gActivityIsLegal, \
152 "XPCOM objects created/destroyed from static ctor/dtor")
153#else
154#define ASSERT_ACTIVITY_IS_LEGAL
155#endif
156
157
158// These functions are copied from nsprpub/lib/ds/plhash.c, with changes
159// to the functions not called Default* to free the serialNumberRecord or
160// the BloatEntry.
161
162static void * PR_CALLBACK
163DefaultAllocTable(void *pool, PRSize size)
164{
165#if defined(XP_MAC)
166#pragma unused (pool)
167#endif
168
169 return PR_MALLOC(size);
170}
171
172static void PR_CALLBACK
173DefaultFreeTable(void *pool, void *item)
174{
175#if defined(XP_MAC)
176#pragma unused (pool)
177#endif
178
179 PR_Free(item);
180}
181
182static PLHashEntry * PR_CALLBACK
183DefaultAllocEntry(void *pool, const void *key)
184{
185#if defined(XP_MAC)
186#pragma unused (pool,key)
187#endif
188
189 return PR_NEW(PLHashEntry);
190}
191
192static void PR_CALLBACK
193SerialNumberFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
194{
195#if defined(XP_MAC)
196#pragma unused (pool)
197#endif
198
199 if (flag == HT_FREE_ENTRY) {
200 PR_Free(NS_REINTERPRET_CAST(serialNumberRecord*,he->value));
201 PR_Free(he);
202 }
203}
204
205static void PR_CALLBACK
206TypesToLogFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
207{
208#if defined(XP_MAC)
209#pragma unused (pool)
210#endif
211
212 if (flag == HT_FREE_ENTRY) {
213 nsCRT::free(NS_CONST_CAST(char*,
214 NS_REINTERPRET_CAST(const char*, he->key)));
215 PR_Free(he);
216 }
217}
218
219static const PLHashAllocOps serialNumberHashAllocOps = {
220 DefaultAllocTable, DefaultFreeTable,
221 DefaultAllocEntry, SerialNumberFreeEntry
222};
223
224static const PLHashAllocOps typesToLogHashAllocOps = {
225 DefaultAllocTable, DefaultFreeTable,
226 DefaultAllocEntry, TypesToLogFreeEntry
227};
228
229////////////////////////////////////////////////////////////////////////////////
230
231class BloatEntry {
232public:
233 BloatEntry(const char* className, PRUint32 classSize)
234 : mClassSize(classSize) {
235 mClassName = PL_strdup(className);
236 Clear(&mNewStats);
237 Clear(&mAllStats);
238 mTotalLeaked = 0;
239 }
240
241 ~BloatEntry() {
242 PL_strfree(mClassName);
243 }
244
245 PRUint32 GetClassSize() { return (PRUint32)mClassSize; }
246 const char* GetClassName() { return mClassName; }
247
248 static void Clear(nsTraceRefcntStats* stats) {
249 stats->mAddRefs = 0;
250 stats->mReleases = 0;
251 stats->mCreates = 0;
252 stats->mDestroys = 0;
253 stats->mRefsOutstandingTotal = 0;
254 stats->mRefsOutstandingSquared = 0;
255 stats->mObjsOutstandingTotal = 0;
256 stats->mObjsOutstandingSquared = 0;
257 }
258
259 void Accumulate() {
260 mAllStats.mAddRefs += mNewStats.mAddRefs;
261 mAllStats.mReleases += mNewStats.mReleases;
262 mAllStats.mCreates += mNewStats.mCreates;
263 mAllStats.mDestroys += mNewStats.mDestroys;
264 mAllStats.mRefsOutstandingTotal += mNewStats.mRefsOutstandingTotal;
265 mAllStats.mRefsOutstandingSquared += mNewStats.mRefsOutstandingSquared;
266 mAllStats.mObjsOutstandingTotal += mNewStats.mObjsOutstandingTotal;
267 mAllStats.mObjsOutstandingSquared += mNewStats.mObjsOutstandingSquared;
268 Clear(&mNewStats);
269 }
270
271 void AddRef(nsrefcnt refcnt) {
272 mNewStats.mAddRefs++;
273 if (refcnt == 1) {
274 Ctor();
275 }
276 AccountRefs();
277 }
278
279 void Release(nsrefcnt refcnt) {
280 mNewStats.mReleases++;
281 if (refcnt == 0) {
282 Dtor();
283 }
284 AccountRefs();
285 }
286
287 void Ctor() {
288 mNewStats.mCreates++;
289 AccountObjs();
290 }
291
292 void Dtor() {
293 mNewStats.mDestroys++;
294 AccountObjs();
295 }
296
297 void AccountRefs() {
298 PRInt32 cnt = (mNewStats.mAddRefs - mNewStats.mReleases);
299 mNewStats.mRefsOutstandingTotal += cnt;
300 mNewStats.mRefsOutstandingSquared += cnt * cnt;
301 }
302
303 void AccountObjs() {
304 PRInt32 cnt = (mNewStats.mCreates - mNewStats.mDestroys);
305 mNewStats.mObjsOutstandingTotal += cnt;
306 mNewStats.mObjsOutstandingSquared += cnt * cnt;
307 }
308
309 static PRIntn PR_CALLBACK DumpEntry(PLHashEntry *he, PRIntn i, void *arg) {
310 BloatEntry* entry = (BloatEntry*)he->value;
311 if (entry) {
312 entry->Accumulate();
313 NS_STATIC_CAST(nsVoidArray*, arg)->AppendElement(entry);
314 }
315 return HT_ENUMERATE_NEXT;
316 }
317
318 static PRIntn PR_CALLBACK TotalEntries(PLHashEntry *he, PRIntn i, void *arg) {
319 BloatEntry* entry = (BloatEntry*)he->value;
320 if (entry && nsCRT::strcmp(entry->mClassName, "TOTAL") != 0) {
321 entry->Total((BloatEntry*)arg);
322 }
323 return HT_ENUMERATE_NEXT;
324 }
325
326 void Total(BloatEntry* total) {
327 total->mAllStats.mAddRefs += mNewStats.mAddRefs + mAllStats.mAddRefs;
328 total->mAllStats.mReleases += mNewStats.mReleases + mAllStats.mReleases;
329 total->mAllStats.mCreates += mNewStats.mCreates + mAllStats.mCreates;
330 total->mAllStats.mDestroys += mNewStats.mDestroys + mAllStats.mDestroys;
331 total->mAllStats.mRefsOutstandingTotal += mNewStats.mRefsOutstandingTotal + mAllStats.mRefsOutstandingTotal;
332 total->mAllStats.mRefsOutstandingSquared += mNewStats.mRefsOutstandingSquared + mAllStats.mRefsOutstandingSquared;
333 total->mAllStats.mObjsOutstandingTotal += mNewStats.mObjsOutstandingTotal + mAllStats.mObjsOutstandingTotal;
334 total->mAllStats.mObjsOutstandingSquared += mNewStats.mObjsOutstandingSquared + mAllStats.mObjsOutstandingSquared;
335 PRInt32 count = (mNewStats.mCreates + mAllStats.mCreates);
336 total->mClassSize += mClassSize * count; // adjust for average in DumpTotal
337 total->mTotalLeaked += (PRInt32)(mClassSize *
338 ((mNewStats.mCreates + mAllStats.mCreates)
339 -(mNewStats.mDestroys + mAllStats.mDestroys)));
340 }
341
342 nsresult DumpTotal(PRUint32 nClasses, FILE* out) {
343 mClassSize /= mAllStats.mCreates;
344 return Dump(-1, out, nsTraceRefcntImpl::ALL_STATS);
345 }
346
347 static PRBool HaveLeaks(nsTraceRefcntStats* stats) {
348 return ((stats->mAddRefs != stats->mReleases) ||
349 (stats->mCreates != stats->mDestroys));
350 }
351
352 static nsresult PrintDumpHeader(FILE* out, const char* msg) {
353 fprintf(out, "\n== BloatView: %s\n\n", msg);
354 fprintf(out,
355 " |<----------------Class--------------->|<-----Bytes------>|<----------------Objects---------------->|<--------------References-------------->|\n");
356 fprintf(out,
357 " Per-Inst Leaked Total Rem Mean StdDev Total Rem Mean StdDev\n");
358 return NS_OK;
359 }
360
361 nsresult Dump(PRIntn i, FILE* out, nsTraceRefcntImpl::StatisticsType type) {
362 nsTraceRefcntStats* stats = (type == nsTraceRefcntImpl::NEW_STATS) ? &mNewStats : &mAllStats;
363 if (gLogLeaksOnly && !HaveLeaks(stats)) {
364 return NS_OK;
365 }
366
367 double meanRefs, stddevRefs;
368 NS_MeanAndStdDev(stats->mAddRefs + stats->mReleases,
369 stats->mRefsOutstandingTotal,
370 stats->mRefsOutstandingSquared,
371 &meanRefs, &stddevRefs);
372
373 double meanObjs, stddevObjs;
374 NS_MeanAndStdDev(stats->mCreates + stats->mDestroys,
375 stats->mObjsOutstandingTotal,
376 stats->mObjsOutstandingSquared,
377 &meanObjs, &stddevObjs);
378
379 if ((stats->mAddRefs - stats->mReleases) != 0 ||
380 stats->mAddRefs != 0 ||
381 meanRefs != 0 ||
382 stddevRefs != 0 ||
383 (stats->mCreates - stats->mDestroys) != 0 ||
384 stats->mCreates != 0 ||
385 meanObjs != 0 ||
386 stddevObjs != 0) {
387 fprintf(out, "%4d %-40.40s %8d %8d %8d %8d (%8.2f +/- %8.2f) %8d %8d (%8.2f +/- %8.2f)\n",
388 i+1, mClassName,
389 (PRInt32)mClassSize,
390 (nsCRT::strcmp(mClassName, "TOTAL"))
391 ?(PRInt32)((stats->mCreates - stats->mDestroys) * mClassSize)
392 :mTotalLeaked,
393 stats->mCreates,
394 (stats->mCreates - stats->mDestroys),
395 meanObjs,
396 stddevObjs,
397 stats->mAddRefs,
398 (stats->mAddRefs - stats->mReleases),
399 meanRefs,
400 stddevRefs);
401 }
402 return NS_OK;
403 }
404
405protected:
406 char* mClassName;
407 double mClassSize; // this is stored as a double because of the way we compute the avg class size for total bloat
408 PRInt32 mTotalLeaked; // used only for TOTAL entry
409 nsTraceRefcntStats mNewStats;
410 nsTraceRefcntStats mAllStats;
411};
412
413static void PR_CALLBACK
414BloatViewFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
415{
416#if defined(XP_MAC)
417#pragma unused (pool)
418#endif
419
420 if (flag == HT_FREE_ENTRY) {
421 BloatEntry* entry = NS_REINTERPRET_CAST(BloatEntry*,he->value);
422 delete entry;
423 PR_Free(he);
424 }
425}
426
427const static PLHashAllocOps bloatViewHashAllocOps = {
428 DefaultAllocTable, DefaultFreeTable,
429 DefaultAllocEntry, BloatViewFreeEntry
430};
431
432static void
433RecreateBloatView()
434{
435 gBloatView = PL_NewHashTable(256,
436 PL_HashString,
437 PL_CompareStrings,
438 PL_CompareValues,
439 &bloatViewHashAllocOps, NULL);
440}
441
442static BloatEntry*
443GetBloatEntry(const char* aTypeName, PRUint32 aInstanceSize)
444{
445 if (!gBloatView) {
446 RecreateBloatView();
447 }
448 BloatEntry* entry = NULL;
449 if (gBloatView) {
450 entry = (BloatEntry*)PL_HashTableLookup(gBloatView, aTypeName);
451 if (entry == NULL && aInstanceSize > 0) {
452
453 entry = new BloatEntry(aTypeName, aInstanceSize);
454 PLHashEntry* e = PL_HashTableAdd(gBloatView, aTypeName, entry);
455 if (e == NULL) {
456 delete entry;
457 entry = NULL;
458 }
459 } else {
460 NS_ASSERTION(aInstanceSize == 0 ||
461 entry->GetClassSize() == aInstanceSize,
462 "bad size recorded");
463 }
464 }
465 return entry;
466}
467
468static PRIntn PR_CALLBACK DumpSerialNumbers(PLHashEntry* aHashEntry, PRIntn aIndex, void* aClosure)
469{
470 serialNumberRecord* record = NS_REINTERPRET_CAST(serialNumberRecord *,aHashEntry->value);
471#ifdef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR
472 fprintf((FILE*) aClosure, "%d (%d references; %d from COMPtrs)\n",
473 record->serialNumber,
474 record->refCount,
475 record->COMPtrCount);
476#else
477 fprintf((FILE*) aClosure, "%d (%d references)\n",
478 record->serialNumber,
479 record->refCount);
480#endif
481 return HT_ENUMERATE_NEXT;
482}
483
484
485#endif /* NS_BUILD_REFCNT_LOGGING */
486
487nsresult
488nsTraceRefcntImpl::DumpStatistics(StatisticsType type, FILE* out)
489{
490 nsresult rv = NS_OK;
491#ifdef NS_BUILD_REFCNT_LOGGING
492 if (gBloatLog == nsnull || gBloatView == nsnull) {
493 return NS_ERROR_FAILURE;
494 }
495 if (out == nsnull) {
496 out = gBloatLog;
497 }
498
499 LOCK_TRACELOG();
500
501 PRBool wasLogging = gLogging;
502 gLogging = PR_FALSE; // turn off logging for this method
503
504 const char* msg;
505 if (type == NEW_STATS) {
506 if (gLogLeaksOnly)
507 msg = "NEW (incremental) LEAK STATISTICS";
508 else
509 msg = "NEW (incremental) LEAK AND BLOAT STATISTICS";
510 }
511 else {
512 if (gLogLeaksOnly)
513 msg = "ALL (cumulative) LEAK STATISTICS";
514 else
515 msg = "ALL (cumulative) LEAK AND BLOAT STATISTICS";
516 }
517 rv = BloatEntry::PrintDumpHeader(out, msg);
518 if (NS_FAILED(rv)) goto done;
519
520 {
521 BloatEntry total("TOTAL", 0);
522 PL_HashTableEnumerateEntries(gBloatView, BloatEntry::TotalEntries, &total);
523 total.DumpTotal(gBloatView->nentries, out);
524
525 nsVoidArray entries;
526 PL_HashTableEnumerateEntries(gBloatView, BloatEntry::DumpEntry, &entries);
527
528 fprintf(stdout, "nsTraceRefcntImpl::DumpStatistics: %d entries\n",
529 entries.Count());
530
531 // Sort the entries alphabetically by classname.
532 PRInt32 i, j;
533 for (i = entries.Count() - 1; i >= 1; --i) {
534 for (j = i - 1; j >= 0; --j) {
535 BloatEntry* left = NS_STATIC_CAST(BloatEntry*, entries[i]);
536 BloatEntry* right = NS_STATIC_CAST(BloatEntry*, entries[j]);
537
538 if (PL_strcmp(left->GetClassName(), right->GetClassName()) < 0) {
539 entries.ReplaceElementAt(right, i);
540 entries.ReplaceElementAt(left, j);
541 }
542 }
543 }
544
545 // Enumerate from back-to-front, so things come out in alpha order
546 for (i = 0; i < entries.Count(); ++i) {
547 BloatEntry* entry = NS_STATIC_CAST(BloatEntry*, entries[i]);
548 entry->Dump(i, out, type);
549 }
550 }
551
552 if (gSerialNumbers) {
553 fprintf(out, "\n\nSerial Numbers of Leaked Objects:\n");
554 PL_HashTableEnumerateEntries(gSerialNumbers, DumpSerialNumbers, out);
555 }
556
557done:
558 gLogging = wasLogging;
559 UNLOCK_TRACELOG();
560#endif
561 return rv;
562}
563
564void
565nsTraceRefcntImpl::ResetStatistics()
566{
567#ifdef NS_BUILD_REFCNT_LOGGING
568 LOCK_TRACELOG();
569 if (gBloatView) {
570 PL_HashTableDestroy(gBloatView);
571 gBloatView = nsnull;
572 }
573 UNLOCK_TRACELOG();
574#endif
575}
576
577#ifdef NS_BUILD_REFCNT_LOGGING
578static PRBool LogThisType(const char* aTypeName)
579{
580 void* he = PL_HashTableLookup(gTypesToLog, aTypeName);
581 return nsnull != he;
582}
583
584static PRInt32 GetSerialNumber(void* aPtr, PRBool aCreate)
585{
586#ifdef GC_LEAK_DETECTOR
587 // need to disguise this pointer, so the table won't keep the object alive.
588 aPtr = (void*) ~PLHashNumber(aPtr);
589#endif
590 PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr);
591 if (hep && *hep) {
592 return PRInt32((NS_REINTERPRET_CAST(serialNumberRecord*,(*hep)->value))->serialNumber);
593 }
594 else if (aCreate) {
595 serialNumberRecord *record = PR_NEW(serialNumberRecord);
596 record->serialNumber = ++gNextSerialNumber;
597 record->refCount = 0;
598 record->COMPtrCount = 0;
599 PL_HashTableRawAdd(gSerialNumbers, hep, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr, NS_REINTERPRET_CAST(void*,record));
600 return gNextSerialNumber;
601 }
602 else {
603 return 0;
604 }
605}
606
607static PRInt32* GetRefCount(void* aPtr)
608{
609#ifdef GC_LEAK_DETECTOR
610 // need to disguise this pointer, so the table won't keep the object alive.
611 aPtr = (void*) ~PLHashNumber(aPtr);
612#endif
613 PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr);
614 if (hep && *hep) {
615 return &((NS_REINTERPRET_CAST(serialNumberRecord*,(*hep)->value))->refCount);
616 } else {
617 return nsnull;
618 }
619}
620
621static PRInt32* GetCOMPtrCount(void* aPtr)
622{
623#ifdef GC_LEAK_DETECTOR
624 // need to disguise this pointer, so the table won't keep the object alive.
625 aPtr = (void*) ~PLHashNumber(aPtr);
626#endif
627 PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr);
628 if (hep && *hep) {
629 return &((NS_REINTERPRET_CAST(serialNumberRecord*,(*hep)->value))->COMPtrCount);
630 } else {
631 return nsnull;
632 }
633}
634
635static void RecycleSerialNumberPtr(void* aPtr)
636{
637#ifdef GC_LEAK_DETECTOR
638 // need to disguise this pointer, so the table won't keep the object alive.
639 aPtr = (void*) ~PLHashNumber(aPtr);
640#endif
641 PL_HashTableRemove(gSerialNumbers, aPtr);
642}
643
644static PRBool LogThisObj(PRInt32 aSerialNumber)
645{
646 return nsnull != PL_HashTableLookup(gObjectsToLog, (const void*)(aSerialNumber));
647}
648
649static PRBool InitLog(const char* envVar, const char* msg, FILE* *result)
650{
651 const char* value = getenv(envVar);
652 if (value) {
653 if (nsCRT::strcmp(value, "1") == 0) {
654 *result = stdout;
655 fprintf(stdout, "### %s defined -- logging %s to stdout\n",
656 envVar, msg);
657 return PR_TRUE;
658 }
659 else if (nsCRT::strcmp(value, "2") == 0) {
660 *result = stderr;
661 fprintf(stdout, "### %s defined -- logging %s to stderr\n",
662 envVar, msg);
663 return PR_TRUE;
664 }
665 else {
666 FILE *stream = ::fopen(value, "w");
667 if (stream != NULL) {
668 *result = stream;
669 fprintf(stdout, "### %s defined -- logging %s to %s\n",
670 envVar, msg, value);
671 return PR_TRUE;
672 }
673 else {
674 fprintf(stdout, "### %s defined -- unable to log %s to %s\n",
675 envVar, msg, value);
676 return PR_FALSE;
677 }
678 }
679 }
680 return PR_FALSE;
681}
682
683
684static PLHashNumber PR_CALLBACK HashNumber(const void* aKey)
685{
686 return PLHashNumber(NS_PTR_TO_INT32(aKey));
687}
688
689static void InitTraceLog(void)
690{
691 if (gInitialized) return;
692 gInitialized = PR_TRUE;
693
694#if defined(XP_MAC) && !TARGET_CARBON
695 // this can get called before Toolbox has been initialized.
696 InitializeMacToolbox();
697#endif
698
699 PRBool defined;
700 defined = InitLog("XPCOM_MEM_BLOAT_LOG", "bloat/leaks", &gBloatLog);
701 if (!defined)
702 gLogLeaksOnly = InitLog("XPCOM_MEM_LEAK_LOG", "leaks", &gBloatLog);
703 if (defined || gLogLeaksOnly) {
704 RecreateBloatView();
705 if (!gBloatView) {
706 NS_WARNING("out of memory");
707 gBloatLog = nsnull;
708 gLogLeaksOnly = PR_FALSE;
709 }
710 }
711
712 (void)InitLog("XPCOM_MEM_REFCNT_LOG", "refcounts", &gRefcntsLog);
713
714 (void)InitLog("XPCOM_MEM_ALLOC_LOG", "new/delete", &gAllocLog);
715
716 defined = InitLog("XPCOM_MEM_LEAKY_LOG", "for leaky", &gLeakyLog);
717 if (defined) {
718 gLogToLeaky = PR_TRUE;
719 void* p = nsnull;
720 void* q = nsnull;
721#ifdef HAVE_LIBDL
722 p = dlsym(0, "__log_addref");
723 q = dlsym(0, "__log_release");
724#endif
725 if (p && q) {
726 leakyLogAddRef = (void (*)(void*,int,int)) p;
727 leakyLogRelease = (void (*)(void*,int,int)) q;
728 }
729 else {
730 gLogToLeaky = PR_FALSE;
731 fprintf(stdout, "### ERROR: XPCOM_MEM_LEAKY_LOG defined, but can't locate __log_addref and __log_release symbols\n");
732 fflush(stdout);
733 }
734 }
735
736 const char* classes = getenv("XPCOM_MEM_LOG_CLASSES");
737
738#ifdef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR
739 if (classes) {
740 (void)InitLog("XPCOM_MEM_COMPTR_LOG", "nsCOMPtr", &gCOMPtrLog);
741 } else {
742 if (getenv("XPCOM_MEM_COMPTR_LOG")) {
743 fprintf(stdout, "### XPCOM_MEM_COMPTR_LOG defined -- but XPCOM_MEM_LOG_CLASSES is not defined\n");
744 }
745 }
746#else
747 const char* comptr_log = getenv("XPCOM_MEM_COMPTR_LOG");
748 if (comptr_log) {
749 fprintf(stdout, "### XPCOM_MEM_COMPTR_LOG defined -- but it will not work without dynamic_cast\n");
750 }
751#endif
752
753 if (classes) {
754 // if XPCOM_MEM_LOG_CLASSES was set to some value, the value is interpreted
755 // as a list of class names to track
756 gTypesToLog = PL_NewHashTable(256,
757 PL_HashString,
758 PL_CompareStrings,
759 PL_CompareValues,
760 &typesToLogHashAllocOps, NULL);
761 if (!gTypesToLog) {
762 NS_WARNING("out of memory");
763 fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- unable to log specific classes\n");
764 }
765 else {
766 fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- only logging these classes: ");
767 const char* cp = classes;
768 for (;;) {
769 char* cm = (char*) strchr(cp, ',');
770 if (cm) {
771 *cm = '\0';
772 }
773 PL_HashTableAdd(gTypesToLog, nsCRT::strdup(cp), (void*)1);
774 fprintf(stdout, "%s ", cp);
775 if (!cm) break;
776 *cm = ',';
777 cp = cm + 1;
778 }
779 fprintf(stdout, "\n");
780 }
781
782 gSerialNumbers = PL_NewHashTable(256,
783 HashNumber,
784 PL_CompareValues,
785 PL_CompareValues,
786 &serialNumberHashAllocOps, NULL);
787
788
789 }
790
791 const char* objects = getenv("XPCOM_MEM_LOG_OBJECTS");
792 if (objects) {
793 gObjectsToLog = PL_NewHashTable(256,
794 HashNumber,
795 PL_CompareValues,
796 PL_CompareValues,
797 NULL, NULL);
798
799 if (!gObjectsToLog) {
800 NS_WARNING("out of memory");
801 fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- unable to log specific objects\n");
802 }
803 else if (! (gRefcntsLog || gAllocLog || gCOMPtrLog)) {
804 fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- but none of XPCOM_MEM_(REFCNT|ALLOC|COMPTR)_LOG is defined\n");
805 }
806 else {
807 fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- only logging these objects: ");
808 const char* cp = objects;
809 for (;;) {
810 char* cm = (char*) strchr(cp, ',');
811 if (cm) {
812 *cm = '\0';
813 }
814 PRInt32 top = 0;
815 PRInt32 bottom = 0;
816 while (*cp) {
817 if (*cp == '-') {
818 bottom = top;
819 top = 0;
820 ++cp;
821 }
822 top *= 10;
823 top += *cp - '0';
824 ++cp;
825 }
826 if (!bottom) {
827 bottom = top;
828 }
829 for(PRInt32 serialno = bottom; serialno <= top; serialno++) {
830 PL_HashTableAdd(gObjectsToLog, (const void*)serialno, (void*)1);
831 fprintf(stdout, "%d ", serialno);
832 }
833 if (!cm) break;
834 *cm = ',';
835 cp = cm + 1;
836 }
837 fprintf(stdout, "\n");
838 }
839 }
840
841
842 if (gBloatLog || gRefcntsLog || gAllocLog || gLeakyLog || gCOMPtrLog) {
843 gLogging = PR_TRUE;
844 }
845
846 gTraceLock = PR_NewLock();
847}
848
849#endif
850
851#if defined(_WIN32) && defined(_M_IX86) // WIN32 x86 stack walking code
852#include "nsStackFrameWin.h"
853void
854nsTraceRefcntImpl::WalkTheStack(FILE* aStream)
855{
856 DumpStackToFile(aStream);
857}
858
859// WIN32 x86 stack walking code
860// i386 or PPC Linux stackwalking code or Solaris
861#elif (defined(linux) && defined(__GLIBC__) && (defined(__i386) || defined(PPC))) || (defined(__sun) && (defined(__sparc) || defined(sparc) || defined(__i386) || defined(i386)))
862#include "nsStackFrameUnix.h"
863void
864nsTraceRefcntImpl::WalkTheStack(FILE* aStream)
865{
866 DumpStackToFile(aStream);
867}
868
869#elif defined(XP_MAC)
870
871/**
872 * Stack walking code for the Mac OS.
873 */
874
875#include "gc_fragments.h"
876
877#include <typeinfo>
878
879extern "C" {
880void MWUnmangle(const char *mangled_name, char *unmangled_name, size_t buffersize);
881}
882
883struct traceback_table {
884 long zero;
885 long magic;
886 long reserved;
887 long codeSize;
888 short nameLength;
889 char name[2];
890};
891
892static char* pc2name(long* pc, char name[], long size)
893{
894 name[0] = '\0';
895
896 // make sure pc is instruction aligned (at least).
897 if (UInt32(pc) == (UInt32(pc) & 0xFFFFFFFC)) {
898 long instructionsToLook = 4096;
899 long* instruction = (long*)pc;
900
901 // look for the traceback table.
902 while (instructionsToLook--) {
903 if (instruction[0] == 0x4E800020 && instruction[1] == 0x00000000) {
904 traceback_table* tb = (traceback_table*)&instruction[1];
905 memcpy(name, tb->name + 1, --nameLength);
906 name[nameLength] = '\0';
907 break;
908 }
909 ++instruction;
910 }
911 }
912
913 return name;
914}
915
916struct stack_frame {
917 stack_frame* next; // savedSP
918 void* savedCR;
919 void* savedLR;
920 void* reserved0;
921 void* reserved1;
922 void* savedTOC;
923};
924
925static asm stack_frame* getStackFrame()
926{
927 mr r3, sp
928 blr
929}
930
931NS_COM void
932nsTraceRefcntImpl::WalkTheStack(FILE* aStream)
933{
934 stack_frame* currentFrame = getStackFrame(); // WalkTheStack's frame.
935 currentFrame = currentFrame->next; // WalkTheStack's caller's frame.
936 currentFrame = currentFrame->next; // WalkTheStack's caller's caller's frame.
937
938 while (true) {
939 // LR saved at 8(SP) in each frame. subtract 4 to get address of calling instruction.
940 void* pc = currentFrame->savedLR;
941
942 // convert PC to name, unmangle it, and generate source location, if possible.
943 static char symbol_name[1024], unmangled_name[1024], file_name[256]; UInt32 file_offset;
944
945 if (GC_address_to_source((char*)pc, symbol_name, file_name, &file_offset)) {
946 MWUnmangle(symbol_name, unmangled_name, sizeof(unmangled_name));
947 fprintf(aStream, "%s[%s,%ld]\n", unmangled_name, file_name, file_offset);
948 } else {
949 pc2name((long*)pc, symbol_name, sizeof(symbol_name));
950 MWUnmangle(symbol_name, unmangled_name, sizeof(unmangled_name));
951 fprintf(aStream, "%s(0x%08X)\n", unmangled_name, pc);
952 }
953
954 currentFrame = currentFrame->next;
955 // the bottom-most frame is marked as pointing to NULL, or is ODD if a 68K transition frame.
956 if (currentFrame == NULL || UInt32(currentFrame) & 0x1)
957 break;
958 }
959}
960
961#else // unsupported platform.
962
963void
964nsTraceRefcntImpl::WalkTheStack(FILE* aStream)
965{
966 fprintf(aStream, "write me, dammit!\n");
967}
968
969#endif
970
971//----------------------------------------------------------------------
972
973// This thing is exported by libstdc++
974// Yes, this is a gcc only hack
975#if defined(MOZ_DEMANGLE_SYMBOLS)
976#include <cxxabi.h>
977#include <stdlib.h> // for free()
978#endif // MOZ_DEMANGLE_SYMBOLS
979
980NS_COM void
981nsTraceRefcntImpl::DemangleSymbol(const char * aSymbol,
982 char * aBuffer,
983 int aBufLen)
984{
985 NS_ASSERTION(nsnull != aSymbol,"null symbol");
986 NS_ASSERTION(nsnull != aBuffer,"null buffer");
987 NS_ASSERTION(aBufLen >= 32 ,"pulled 32 out of you know where");
988
989 aBuffer[0] = '\0';
990
991#if defined(MOZ_DEMANGLE_SYMBOLS)
992 /* See demangle.h in the gcc source for the voodoo */
993 char * demangled = abi::__cxa_demangle(aSymbol,0,0,0);
994
995 if (demangled)
996 {
997 strncpy(aBuffer,demangled,aBufLen);
998 free(demangled);
999 }
1000#endif // MOZ_DEMANGLE_SYMBOLS
1001}
1002
1003
1004//----------------------------------------------------------------------
1005
1006NS_COM void
1007nsTraceRefcntImpl::LoadLibrarySymbols(const char* aLibraryName,
1008 void* aLibrayHandle)
1009{
1010#ifdef NS_BUILD_REFCNT_LOGGING
1011#if defined(_WIN32) && defined(_M_IX86) /* Win32 x86 only */
1012 if (!gInitialized)
1013 InitTraceLog();
1014
1015 if (gAllocLog || gRefcntsLog) {
1016 fprintf(stdout, "### Loading symbols for %s\n", aLibraryName);
1017 fflush(stdout);
1018
1019 HANDLE myProcess = ::GetCurrentProcess();
1020 BOOL ok = EnsureSymInitialized();
1021 if (ok) {
1022 const char* baseName = aLibraryName;
1023 // just get the base name of the library if a full path was given:
1024 PRInt32 len = strlen(aLibraryName);
1025 for (PRInt32 i = len - 1; i >= 0; i--) {
1026 if (aLibraryName[i] == '\\') {
1027 baseName = &aLibraryName[i + 1];
1028 break;
1029 }
1030 }
1031 DWORD baseAddr = _SymLoadModule(myProcess,
1032 NULL,
1033 (char*)baseName,
1034 (char*)baseName,
1035 0,
1036 0);
1037 ok = (baseAddr != nsnull);
1038 }
1039 if (!ok) {
1040 LPVOID lpMsgBuf;
1041 FormatMessage(
1042 FORMAT_MESSAGE_ALLOCATE_BUFFER |
1043 FORMAT_MESSAGE_FROM_SYSTEM |
1044 FORMAT_MESSAGE_IGNORE_INSERTS,
1045 NULL,
1046 GetLastError(),
1047 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
1048 (LPTSTR) &lpMsgBuf,
1049 0,
1050 NULL
1051 );
1052 fprintf(stdout, "### ERROR: LoadLibrarySymbols for %s: %s\n",
1053 aLibraryName, lpMsgBuf);
1054 fflush(stdout);
1055 LocalFree( lpMsgBuf );
1056 }
1057 }
1058#endif
1059#endif
1060}
1061
1062//----------------------------------------------------------------------
1063
1064
1065
1066
1067
1068
1069// don't use the logging ones. :-)
1070NS_IMETHODIMP_(nsrefcnt) nsTraceRefcntImpl::AddRef(void)
1071{
1072 NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt");
1073 ++mRefCnt;
1074 return mRefCnt;
1075}
1076
1077NS_IMETHODIMP_(nsrefcnt) nsTraceRefcntImpl::Release(void)
1078{
1079 NS_PRECONDITION(0 != mRefCnt, "dup release");
1080 --mRefCnt;
1081 if (mRefCnt == 0) {
1082 mRefCnt = 1; /* stabilize */
1083 delete this;
1084 return 0;
1085 }
1086 return mRefCnt;
1087}
1088
1089NS_IMPL_QUERY_INTERFACE1(nsTraceRefcntImpl, nsITraceRefcnt)
1090
1091nsTraceRefcntImpl::nsTraceRefcntImpl()
1092{
1093 /* member initializers and constructor code */
1094}
1095
1096NS_IMETHODIMP
1097nsTraceRefcntImpl::LogAddRef(void* aPtr,
1098 nsrefcnt aRefcnt,
1099 const char* aClazz,
1100 PRUint32 classSize)
1101{
1102#ifdef NS_BUILD_REFCNT_LOGGING
1103 ASSERT_ACTIVITY_IS_LEGAL;
1104 if (!gInitialized)
1105 InitTraceLog();
1106 if (gLogging) {
1107 LOCK_TRACELOG();
1108
1109 if (gBloatLog) {
1110 BloatEntry* entry = GetBloatEntry(aClazz, classSize);
1111 if (entry) {
1112 entry->AddRef(aRefcnt);
1113 }
1114 }
1115
1116 // Here's the case where neither NS_NEWXPCOM nor MOZ_COUNT_CTOR were used,
1117 // yet we still want to see creation information:
1118
1119 PRBool loggingThisType = (!gTypesToLog || LogThisType(aClazz));
1120 PRInt32 serialno = 0;
1121 if (gSerialNumbers && loggingThisType) {
1122 serialno = GetSerialNumber(aPtr, aRefcnt == 1);
1123 PRInt32* count = GetRefCount(aPtr);
1124 if(count)
1125 (*count)++;
1126
1127 }
1128
1129 PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
1130 if (aRefcnt == 1 && gAllocLog && loggingThisType && loggingThisObject) {
1131 fprintf(gAllocLog, "\n<%s> 0x%08X %d Create\n",
1132 aClazz, NS_PTR_TO_INT32(aPtr), serialno);
1133 WalkTheStack(gAllocLog);
1134 }
1135
1136 if (gRefcntsLog && loggingThisType && loggingThisObject) {
1137 if (gLogToLeaky) {
1138 (*leakyLogAddRef)(aPtr, aRefcnt - 1, aRefcnt);
1139 }
1140 else {
1141 // Can't use PR_LOG(), b/c it truncates the line
1142 fprintf(gRefcntsLog,
1143 "\n<%s> 0x%08X %d AddRef %d\n", aClazz, NS_PTR_TO_INT32(aPtr), serialno, aRefcnt);
1144 WalkTheStack(gRefcntsLog);
1145 fflush(gRefcntsLog);
1146 }
1147 }
1148 UNLOCK_TRACELOG();
1149 }
1150#endif
1151 return NS_OK;
1152}
1153
1154NS_IMETHODIMP
1155nsTraceRefcntImpl::LogRelease(void* aPtr,
1156 nsrefcnt aRefcnt,
1157 const char* aClazz)
1158{
1159#ifdef NS_BUILD_REFCNT_LOGGING
1160 ASSERT_ACTIVITY_IS_LEGAL;
1161 if (!gInitialized)
1162 InitTraceLog();
1163 if (gLogging) {
1164 LOCK_TRACELOG();
1165
1166 if (gBloatLog) {
1167 BloatEntry* entry = GetBloatEntry(aClazz, 0);
1168 if (entry) {
1169 entry->Release(aRefcnt);
1170 }
1171 }
1172
1173 PRBool loggingThisType = (!gTypesToLog || LogThisType(aClazz));
1174 PRInt32 serialno = 0;
1175 if (gSerialNumbers && loggingThisType) {
1176 serialno = GetSerialNumber(aPtr, PR_FALSE);
1177 PRInt32* count = GetRefCount(aPtr);
1178 if(count)
1179 (*count)--;
1180
1181 }
1182
1183 PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
1184 if (gRefcntsLog && loggingThisType && loggingThisObject) {
1185 if (gLogToLeaky) {
1186 (*leakyLogRelease)(aPtr, aRefcnt + 1, aRefcnt);
1187 }
1188 else {
1189 // Can't use PR_LOG(), b/c it truncates the line
1190 fprintf(gRefcntsLog,
1191 "\n<%s> 0x%08X %d Release %d\n", aClazz, NS_PTR_TO_INT32(aPtr), serialno, aRefcnt);
1192 WalkTheStack(gRefcntsLog);
1193 fflush(gRefcntsLog);
1194 }
1195 }
1196
1197 // Here's the case where neither NS_DELETEXPCOM nor MOZ_COUNT_DTOR were used,
1198 // yet we still want to see deletion information:
1199
1200 if (aRefcnt == 0 && gAllocLog && loggingThisType && loggingThisObject) {
1201 fprintf(gAllocLog,
1202 "\n<%s> 0x%08X %d Destroy\n",
1203 aClazz, NS_PTR_TO_INT32(aPtr), serialno);
1204 WalkTheStack(gAllocLog);
1205 }
1206
1207 if (aRefcnt == 0 && gSerialNumbers && loggingThisType) {
1208 RecycleSerialNumberPtr(aPtr);
1209 }
1210
1211 UNLOCK_TRACELOG();
1212 }
1213#endif
1214 return NS_OK;
1215}
1216
1217NS_IMETHODIMP
1218nsTraceRefcntImpl::LogCtor(void* aPtr,
1219 const char* aType,
1220 PRUint32 aInstanceSize)
1221{
1222#ifdef NS_BUILD_REFCNT_LOGGING
1223 ASSERT_ACTIVITY_IS_LEGAL;
1224 if (!gInitialized)
1225 InitTraceLog();
1226
1227 if (gLogging) {
1228 LOCK_TRACELOG();
1229
1230 if (gBloatLog) {
1231 BloatEntry* entry = GetBloatEntry(aType, aInstanceSize);
1232 if (entry) {
1233 entry->Ctor();
1234 }
1235 }
1236
1237 PRBool loggingThisType = (!gTypesToLog || LogThisType(aType));
1238 PRInt32 serialno = 0;
1239 if (gSerialNumbers && loggingThisType) {
1240 serialno = GetSerialNumber(aPtr, PR_TRUE);
1241 }
1242
1243 PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
1244 if (gAllocLog && loggingThisType && loggingThisObject) {
1245 fprintf(gAllocLog, "\n<%s> 0x%08X %d Ctor (%d)\n",
1246 aType, NS_PTR_TO_INT32(aPtr), serialno, aInstanceSize);
1247 WalkTheStack(gAllocLog);
1248 }
1249
1250 UNLOCK_TRACELOG();
1251 }
1252#endif
1253 return NS_OK;
1254}
1255
1256
1257NS_IMETHODIMP
1258nsTraceRefcntImpl::LogDtor(void* aPtr,
1259 const char* aType,
1260 PRUint32 aInstanceSize)
1261{
1262#ifdef NS_BUILD_REFCNT_LOGGING
1263 ASSERT_ACTIVITY_IS_LEGAL;
1264 if (!gInitialized)
1265 InitTraceLog();
1266
1267 if (gLogging) {
1268 LOCK_TRACELOG();
1269
1270 if (gBloatLog) {
1271 BloatEntry* entry = GetBloatEntry(aType, aInstanceSize);
1272 if (entry) {
1273 entry->Dtor();
1274 }
1275 }
1276
1277 PRBool loggingThisType = (!gTypesToLog || LogThisType(aType));
1278 PRInt32 serialno = 0;
1279 if (gSerialNumbers && loggingThisType) {
1280 serialno = GetSerialNumber(aPtr, PR_FALSE);
1281 RecycleSerialNumberPtr(aPtr);
1282 }
1283
1284 PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
1285
1286 // (If we're on a losing architecture, don't do this because we'll be
1287 // using LogDeleteXPCOM instead to get file and line numbers.)
1288 if (gAllocLog && loggingThisType && loggingThisObject) {
1289 fprintf(gAllocLog, "\n<%s> 0x%08X %d Dtor (%d)\n",
1290 aType, NS_PTR_TO_INT32(aPtr), serialno, aInstanceSize);
1291 WalkTheStack(gAllocLog);
1292 }
1293
1294 UNLOCK_TRACELOG();
1295 }
1296#endif
1297 return NS_OK;
1298}
1299
1300
1301NS_IMETHODIMP
1302nsTraceRefcntImpl::LogAddCOMPtr(void* aCOMPtr,
1303 nsISupports* aObject)
1304{
1305#if defined(NS_BUILD_REFCNT_LOGGING) && defined(HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR)
1306 // Get the most-derived object.
1307 void *object = dynamic_cast<void *>(aObject);
1308
1309 // This is a very indirect way of finding out what the class is
1310 // of the object being logged. If we're logging a specific type,
1311 // then
1312 if (!gTypesToLog || !gSerialNumbers) {
1313 return NS_OK;
1314 }
1315 PRInt32 serialno = GetSerialNumber(object, PR_FALSE);
1316 if (serialno == 0) {
1317 return NS_OK;
1318 }
1319
1320 if (!gInitialized)
1321 InitTraceLog();
1322 if (gLogging) {
1323 LOCK_TRACELOG();
1324
1325 PRInt32* count = GetCOMPtrCount(object);
1326 if(count)
1327 (*count)++;
1328
1329 PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
1330
1331 if (gCOMPtrLog && loggingThisObject) {
1332 fprintf(gCOMPtrLog, "\n<?> 0x%08X %d nsCOMPtrAddRef %d 0x%08X\n",
1333 NS_PTR_TO_INT32(object), serialno, count?(*count):-1, NS_PTR_TO_INT32(aCOMPtr));
1334 WalkTheStack(gCOMPtrLog);
1335 }
1336
1337 UNLOCK_TRACELOG();
1338 }
1339#endif
1340 return NS_OK;
1341}
1342
1343
1344NS_IMETHODIMP
1345nsTraceRefcntImpl::LogReleaseCOMPtr(void* aCOMPtr,
1346 nsISupports* aObject)
1347{
1348#if defined(NS_BUILD_REFCNT_LOGGING) && defined(HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR)
1349 // Get the most-derived object.
1350 void *object = dynamic_cast<void *>(aObject);
1351
1352 // This is a very indirect way of finding out what the class is
1353 // of the object being logged. If we're logging a specific type,
1354 // then
1355 if (!gTypesToLog || !gSerialNumbers) {
1356 return NS_OK;
1357 }
1358 PRInt32 serialno = GetSerialNumber(object, PR_FALSE);
1359 if (serialno == 0) {
1360 return NS_OK;
1361 }
1362
1363 if (!gInitialized)
1364 InitTraceLog();
1365 if (gLogging) {
1366 LOCK_TRACELOG();
1367
1368 PRInt32* count = GetCOMPtrCount(object);
1369 if(count)
1370 (*count)--;
1371
1372 PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
1373
1374 if (gCOMPtrLog && loggingThisObject) {
1375 fprintf(gCOMPtrLog, "\n<?> 0x%08X %d nsCOMPtrRelease %d 0x%08X\n",
1376 NS_PTR_TO_INT32(object), serialno, count?(*count):-1, NS_PTR_TO_INT32(aCOMPtr));
1377 WalkTheStack(gCOMPtrLog);
1378 }
1379
1380 UNLOCK_TRACELOG();
1381 }
1382#endif
1383 return NS_OK;
1384}
1385
1386NS_COM void
1387nsTraceRefcntImpl::Startup()
1388{
1389#ifdef NS_BUILD_REFCNT_LOGGING
1390 SetActivityIsLegal(PR_TRUE);
1391#endif
1392}
1393
1394NS_COM void
1395nsTraceRefcntImpl::Shutdown()
1396{
1397#ifdef NS_BUILD_REFCNT_LOGGING
1398
1399 if (gBloatView) {
1400 PL_HashTableDestroy(gBloatView);
1401 gBloatView = nsnull;
1402 }
1403 if (gTypesToLog) {
1404 PL_HashTableDestroy(gTypesToLog);
1405 gTypesToLog = nsnull;
1406 }
1407 if (gObjectsToLog) {
1408 PL_HashTableDestroy(gObjectsToLog);
1409 gObjectsToLog = nsnull;
1410 }
1411 if (gSerialNumbers) {
1412 PL_HashTableDestroy(gSerialNumbers);
1413 gSerialNumbers = nsnull;
1414 }
1415
1416 SetActivityIsLegal(PR_FALSE);
1417
1418#endif
1419}
1420
1421NS_COM void
1422nsTraceRefcntImpl::SetActivityIsLegal(PRBool aLegal)
1423{
1424#ifdef NS_BUILD_REFCNT_LOGGING
1425 gActivityIsLegal = aLegal;
1426#endif
1427}
1428
1429
1430NS_METHOD
1431nsTraceRefcntImpl::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr)
1432{
1433 *aInstancePtr = nsnull;
1434 nsITraceRefcnt* tracer = new nsTraceRefcntImpl();
1435 if (!tracer)
1436 return NS_ERROR_OUT_OF_MEMORY;
1437
1438 nsresult rv = tracer->QueryInterface(aIID, aInstancePtr);
1439 if (NS_FAILED(rv)) {
1440 delete tracer;
1441 }
1442
1443 return rv;
1444}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use