VirtualBox

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

最後變更 在這個檔案從101777是 101777,由 vboxsync 提交於 17 月 前

libs/xpcom: Remove all code associated with GC_LEAK_DETECTOR as it is never set in our case, bugref:10545

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 39.9 KB
 
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 <[email protected]>
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(VBOX) && 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 PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr);
587 if (hep && *hep) {
588 return PRInt32((NS_REINTERPRET_CAST(serialNumberRecord*,(*hep)->value))->serialNumber);
589 }
590 else if (aCreate) {
591 serialNumberRecord *record = PR_NEW(serialNumberRecord);
592 record->serialNumber = ++gNextSerialNumber;
593 record->refCount = 0;
594 record->COMPtrCount = 0;
595 PL_HashTableRawAdd(gSerialNumbers, hep, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr, NS_REINTERPRET_CAST(void*,record));
596 return gNextSerialNumber;
597 }
598 else {
599 return 0;
600 }
601}
602
603static PRInt32* GetRefCount(void* aPtr)
604{
605 PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr);
606 if (hep && *hep) {
607 return &((NS_REINTERPRET_CAST(serialNumberRecord*,(*hep)->value))->refCount);
608 } else {
609 return nsnull;
610 }
611}
612
613static PRInt32* GetCOMPtrCount(void* aPtr)
614{
615 PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr);
616 if (hep && *hep) {
617 return &((NS_REINTERPRET_CAST(serialNumberRecord*,(*hep)->value))->COMPtrCount);
618 } else {
619 return nsnull;
620 }
621}
622
623static void RecycleSerialNumberPtr(void* aPtr)
624{
625 PL_HashTableRemove(gSerialNumbers, aPtr);
626}
627
628static PRBool LogThisObj(PRInt32 aSerialNumber)
629{
630 return nsnull != PL_HashTableLookup(gObjectsToLog, (const void*)(uintptr_t)(aSerialNumber));
631}
632
633static PRBool InitLog(const char* envVar, const char* msg, FILE* *result)
634{
635 const char* value = getenv(envVar);
636 if (value) {
637 if (nsCRT::strcmp(value, "1") == 0) {
638 *result = stdout;
639 fprintf(stdout, "### %s defined -- logging %s to stdout\n",
640 envVar, msg);
641 return PR_TRUE;
642 }
643 else if (nsCRT::strcmp(value, "2") == 0) {
644 *result = stderr;
645 fprintf(stdout, "### %s defined -- logging %s to stderr\n",
646 envVar, msg);
647 return PR_TRUE;
648 }
649 else {
650 FILE *stream = ::fopen(value, "w");
651 if (stream != NULL) {
652 *result = stream;
653 fprintf(stdout, "### %s defined -- logging %s to %s\n",
654 envVar, msg, value);
655 return PR_TRUE;
656 }
657 else {
658 fprintf(stdout, "### %s defined -- unable to log %s to %s\n",
659 envVar, msg, value);
660 return PR_FALSE;
661 }
662 }
663 }
664 return PR_FALSE;
665}
666
667
668static PLHashNumber PR_CALLBACK HashNumber(const void* aKey)
669{
670 return PLHashNumber(NS_PTR_TO_INT32(aKey));
671}
672
673static void InitTraceLog(void)
674{
675 if (gInitialized) return;
676 gInitialized = PR_TRUE;
677
678#if defined(XP_MAC) && !TARGET_CARBON
679 // this can get called before Toolbox has been initialized.
680 InitializeMacToolbox();
681#endif
682
683 PRBool defined;
684 defined = InitLog("XPCOM_MEM_BLOAT_LOG", "bloat/leaks", &gBloatLog);
685 if (!defined)
686 gLogLeaksOnly = InitLog("XPCOM_MEM_LEAK_LOG", "leaks", &gBloatLog);
687 if (defined || gLogLeaksOnly) {
688 RecreateBloatView();
689 if (!gBloatView) {
690 NS_WARNING("out of memory");
691 gBloatLog = nsnull;
692 gLogLeaksOnly = PR_FALSE;
693 }
694 }
695
696 (void)InitLog("XPCOM_MEM_REFCNT_LOG", "refcounts", &gRefcntsLog);
697
698 (void)InitLog("XPCOM_MEM_ALLOC_LOG", "new/delete", &gAllocLog);
699
700 defined = InitLog("XPCOM_MEM_LEAKY_LOG", "for leaky", &gLeakyLog);
701 if (defined) {
702 gLogToLeaky = PR_TRUE;
703 void* p = nsnull;
704 void* q = nsnull;
705#ifdef HAVE_LIBDL
706 p = dlsym(0, "__log_addref");
707 q = dlsym(0, "__log_release");
708#endif
709 if (p && q) {
710 leakyLogAddRef = (void (*)(void*,int,int)) p;
711 leakyLogRelease = (void (*)(void*,int,int)) q;
712 }
713 else {
714 gLogToLeaky = PR_FALSE;
715 fprintf(stdout, "### ERROR: XPCOM_MEM_LEAKY_LOG defined, but can't locate __log_addref and __log_release symbols\n");
716 fflush(stdout);
717 }
718 }
719
720 const char* classes = getenv("XPCOM_MEM_LOG_CLASSES");
721
722#ifdef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR
723 if (classes) {
724 (void)InitLog("XPCOM_MEM_COMPTR_LOG", "nsCOMPtr", &gCOMPtrLog);
725 } else {
726 if (getenv("XPCOM_MEM_COMPTR_LOG")) {
727 fprintf(stdout, "### XPCOM_MEM_COMPTR_LOG defined -- but XPCOM_MEM_LOG_CLASSES is not defined\n");
728 }
729 }
730#else
731 const char* comptr_log = getenv("XPCOM_MEM_COMPTR_LOG");
732 if (comptr_log) {
733 fprintf(stdout, "### XPCOM_MEM_COMPTR_LOG defined -- but it will not work without dynamic_cast\n");
734 }
735#endif
736
737 if (classes) {
738 // if XPCOM_MEM_LOG_CLASSES was set to some value, the value is interpreted
739 // as a list of class names to track
740 gTypesToLog = PL_NewHashTable(256,
741 PL_HashString,
742 PL_CompareStrings,
743 PL_CompareValues,
744 &typesToLogHashAllocOps, NULL);
745 if (!gTypesToLog) {
746 NS_WARNING("out of memory");
747 fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- unable to log specific classes\n");
748 }
749 else {
750 fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- only logging these classes: ");
751 const char* cp = classes;
752 for (;;) {
753 char* cm = (char*) strchr(cp, ',');
754 if (cm) {
755 *cm = '\0';
756 }
757 PL_HashTableAdd(gTypesToLog, nsCRT::strdup(cp), (void*)1);
758 fprintf(stdout, "%s ", cp);
759 if (!cm) break;
760 *cm = ',';
761 cp = cm + 1;
762 }
763 fprintf(stdout, "\n");
764 }
765
766 gSerialNumbers = PL_NewHashTable(256,
767 HashNumber,
768 PL_CompareValues,
769 PL_CompareValues,
770 &serialNumberHashAllocOps, NULL);
771
772
773 }
774
775 const char* objects = getenv("XPCOM_MEM_LOG_OBJECTS");
776 if (objects) {
777 gObjectsToLog = PL_NewHashTable(256,
778 HashNumber,
779 PL_CompareValues,
780 PL_CompareValues,
781 NULL, NULL);
782
783 if (!gObjectsToLog) {
784 NS_WARNING("out of memory");
785 fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- unable to log specific objects\n");
786 }
787 else if (! (gRefcntsLog || gAllocLog || gCOMPtrLog)) {
788 fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- but none of XPCOM_MEM_(REFCNT|ALLOC|COMPTR)_LOG is defined\n");
789 }
790 else {
791 fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- only logging these objects: ");
792 const char* cp = objects;
793 for (;;) {
794 char* cm = (char*) strchr(cp, ',');
795 if (cm) {
796 *cm = '\0';
797 }
798 PRInt32 top = 0;
799 PRInt32 bottom = 0;
800 while (*cp) {
801 if (*cp == '-') {
802 bottom = top;
803 top = 0;
804 ++cp;
805 }
806 top *= 10;
807 top += *cp - '0';
808 ++cp;
809 }
810 if (!bottom) {
811 bottom = top;
812 }
813 for(PRInt32 serialno = bottom; serialno <= top; serialno++) {
814 PL_HashTableAdd(gObjectsToLog, (const void*)serialno, (void*)1);
815 fprintf(stdout, "%d ", serialno);
816 }
817 if (!cm) break;
818 *cm = ',';
819 cp = cm + 1;
820 }
821 fprintf(stdout, "\n");
822 }
823 }
824
825
826 if (gBloatLog || gRefcntsLog || gAllocLog || gLeakyLog || gCOMPtrLog) {
827 gLogging = PR_TRUE;
828 }
829
830 gTraceLock = PR_NewLock();
831}
832
833#endif
834
835#if defined(_WIN32) && defined(_M_IX86) // WIN32 x86 stack walking code
836#include "nsStackFrameWin.h"
837void
838nsTraceRefcntImpl::WalkTheStack(FILE* aStream)
839{
840 DumpStackToFile(aStream);
841}
842
843// WIN32 x86 stack walking code
844// i386 or PPC Linux stackwalking code or Solaris
845#elif (defined(linux) && !defined(VBOX) && defined(__GLIBC__) && (defined(__i386) || defined(PPC))) || (defined(__sun) && (defined(__sparc) || defined(sparc) || defined(__i386) || defined(i386)))
846#include "nsStackFrameUnix.h"
847void
848nsTraceRefcntImpl::WalkTheStack(FILE* aStream)
849{
850 DumpStackToFile(aStream);
851}
852
853#elif defined(XP_MAC)
854
855/**
856 * Stack walking code for the Mac OS.
857 */
858
859#include "gc_fragments.h"
860
861#include <typeinfo>
862
863extern "C" {
864void MWUnmangle(const char *mangled_name, char *unmangled_name, size_t buffersize);
865}
866
867struct traceback_table {
868 long zero;
869 long magic;
870 long reserved;
871 long codeSize;
872 short nameLength;
873 char name[2];
874};
875
876static char* pc2name(long* pc, char name[], long size)
877{
878 name[0] = '\0';
879
880 // make sure pc is instruction aligned (at least).
881 if (UInt32(pc) == (UInt32(pc) & 0xFFFFFFFC)) {
882 long instructionsToLook = 4096;
883 long* instruction = (long*)pc;
884
885 // look for the traceback table.
886 while (instructionsToLook--) {
887 if (instruction[0] == 0x4E800020 && instruction[1] == 0x00000000) {
888 traceback_table* tb = (traceback_table*)&instruction[1];
889 memcpy(name, tb->name + 1, --nameLength);
890 name[nameLength] = '\0';
891 break;
892 }
893 ++instruction;
894 }
895 }
896
897 return name;
898}
899
900struct stack_frame {
901 stack_frame* next; // savedSP
902 void* savedCR;
903 void* savedLR;
904 void* reserved0;
905 void* reserved1;
906 void* savedTOC;
907};
908
909static asm stack_frame* getStackFrame()
910{
911 mr r3, sp
912 blr
913}
914
915NS_COM void
916nsTraceRefcntImpl::WalkTheStack(FILE* aStream)
917{
918 stack_frame* currentFrame = getStackFrame(); // WalkTheStack's frame.
919 currentFrame = currentFrame->next; // WalkTheStack's caller's frame.
920 currentFrame = currentFrame->next; // WalkTheStack's caller's caller's frame.
921
922 while (true) {
923 // LR saved at 8(SP) in each frame. subtract 4 to get address of calling instruction.
924 void* pc = currentFrame->savedLR;
925
926 // convert PC to name, unmangle it, and generate source location, if possible.
927 static char symbol_name[1024], unmangled_name[1024], file_name[256]; UInt32 file_offset;
928
929 if (GC_address_to_source((char*)pc, symbol_name, file_name, &file_offset)) {
930 MWUnmangle(symbol_name, unmangled_name, sizeof(unmangled_name));
931 fprintf(aStream, "%s[%s,%ld]\n", unmangled_name, file_name, file_offset);
932 } else {
933 pc2name((long*)pc, symbol_name, sizeof(symbol_name));
934 MWUnmangle(symbol_name, unmangled_name, sizeof(unmangled_name));
935 fprintf(aStream, "%s(0x%08X)\n", unmangled_name, pc);
936 }
937
938 currentFrame = currentFrame->next;
939 // the bottom-most frame is marked as pointing to NULL, or is ODD if a 68K transition frame.
940 if (currentFrame == NULL || UInt32(currentFrame) & 0x1)
941 break;
942 }
943}
944
945#else // unsupported platform.
946
947void
948nsTraceRefcntImpl::WalkTheStack(FILE* aStream)
949{
950 fprintf(aStream, "write me, dammit!\n");
951}
952
953#endif
954
955//----------------------------------------------------------------------
956
957// This thing is exported by libstdc++
958// Yes, this is a gcc only hack
959#if defined(MOZ_DEMANGLE_SYMBOLS)
960#include <cxxabi.h>
961#include <stdlib.h> // for free()
962#endif // MOZ_DEMANGLE_SYMBOLS
963
964NS_COM void
965nsTraceRefcntImpl::DemangleSymbol(const char * aSymbol,
966 char * aBuffer,
967 int aBufLen)
968{
969 NS_ASSERTION(nsnull != aSymbol,"null symbol");
970 NS_ASSERTION(nsnull != aBuffer,"null buffer");
971 NS_ASSERTION(aBufLen >= 32 ,"pulled 32 out of you know where");
972
973 aBuffer[0] = '\0';
974
975#if defined(MOZ_DEMANGLE_SYMBOLS)
976 /* See demangle.h in the gcc source for the voodoo */
977 char * demangled = abi::__cxa_demangle(aSymbol,0,0,0);
978
979 if (demangled)
980 {
981 strncpy(aBuffer,demangled,aBufLen);
982 free(demangled);
983 }
984#endif // MOZ_DEMANGLE_SYMBOLS
985}
986
987
988//----------------------------------------------------------------------
989
990NS_COM void
991nsTraceRefcntImpl::LoadLibrarySymbols(const char* aLibraryName,
992 void* aLibrayHandle)
993{
994#ifdef NS_BUILD_REFCNT_LOGGING
995#if defined(_WIN32) && defined(_M_IX86) /* Win32 x86 only */
996 if (!gInitialized)
997 InitTraceLog();
998
999 if (gAllocLog || gRefcntsLog) {
1000 fprintf(stdout, "### Loading symbols for %s\n", aLibraryName);
1001 fflush(stdout);
1002
1003 HANDLE myProcess = ::GetCurrentProcess();
1004 BOOL ok = EnsureSymInitialized();
1005 if (ok) {
1006 const char* baseName = aLibraryName;
1007 // just get the base name of the library if a full path was given:
1008 PRInt32 len = strlen(aLibraryName);
1009 for (PRInt32 i = len - 1; i >= 0; i--) {
1010 if (aLibraryName[i] == '\\') {
1011 baseName = &aLibraryName[i + 1];
1012 break;
1013 }
1014 }
1015 DWORD baseAddr = _SymLoadModule(myProcess,
1016 NULL,
1017 (char*)baseName,
1018 (char*)baseName,
1019 0,
1020 0);
1021 ok = (baseAddr != nsnull);
1022 }
1023 if (!ok) {
1024 LPVOID lpMsgBuf;
1025 FormatMessage(
1026 FORMAT_MESSAGE_ALLOCATE_BUFFER |
1027 FORMAT_MESSAGE_FROM_SYSTEM |
1028 FORMAT_MESSAGE_IGNORE_INSERTS,
1029 NULL,
1030 GetLastError(),
1031 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
1032 (LPTSTR) &lpMsgBuf,
1033 0,
1034 NULL
1035 );
1036 fprintf(stdout, "### ERROR: LoadLibrarySymbols for %s: %s\n",
1037 aLibraryName, lpMsgBuf);
1038 fflush(stdout);
1039 LocalFree( lpMsgBuf );
1040 }
1041 }
1042#endif
1043#endif
1044}
1045
1046//----------------------------------------------------------------------
1047
1048
1049
1050
1051
1052
1053// don't use the logging ones. :-)
1054NS_IMETHODIMP_(nsrefcnt) nsTraceRefcntImpl::AddRef(void)
1055{
1056 NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt");
1057 ++mRefCnt;
1058 return mRefCnt;
1059}
1060
1061NS_IMETHODIMP_(nsrefcnt) nsTraceRefcntImpl::Release(void)
1062{
1063 NS_PRECONDITION(0 != mRefCnt, "dup release");
1064 --mRefCnt;
1065 if (mRefCnt == 0) {
1066 mRefCnt = 1; /* stabilize */
1067 delete this;
1068 return 0;
1069 }
1070 return mRefCnt;
1071}
1072
1073NS_IMPL_QUERY_INTERFACE1(nsTraceRefcntImpl, nsITraceRefcnt)
1074
1075nsTraceRefcntImpl::nsTraceRefcntImpl()
1076{
1077 /* member initializers and constructor code */
1078}
1079
1080NS_IMETHODIMP
1081nsTraceRefcntImpl::LogAddRef(void* aPtr,
1082 nsrefcnt aRefcnt,
1083 const char* aClazz,
1084 PRUint32 classSize)
1085{
1086#ifdef NS_BUILD_REFCNT_LOGGING
1087 ASSERT_ACTIVITY_IS_LEGAL;
1088 if (!gInitialized)
1089 InitTraceLog();
1090 if (gLogging) {
1091 LOCK_TRACELOG();
1092
1093 if (gBloatLog) {
1094 BloatEntry* entry = GetBloatEntry(aClazz, classSize);
1095 if (entry) {
1096 entry->AddRef(aRefcnt);
1097 }
1098 }
1099
1100 // Here's the case where neither NS_NEWXPCOM nor MOZ_COUNT_CTOR were used,
1101 // yet we still want to see creation information:
1102
1103 PRBool loggingThisType = (!gTypesToLog || LogThisType(aClazz));
1104 PRInt32 serialno = 0;
1105 if (gSerialNumbers && loggingThisType) {
1106 serialno = GetSerialNumber(aPtr, aRefcnt == 1);
1107 PRInt32* count = GetRefCount(aPtr);
1108 if(count)
1109 (*count)++;
1110
1111 }
1112
1113 PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
1114 if (aRefcnt == 1 && gAllocLog && loggingThisType && loggingThisObject) {
1115 fprintf(gAllocLog, "\n<%s> 0x%08X %d Create\n",
1116 aClazz, NS_PTR_TO_INT32(aPtr), serialno);
1117 WalkTheStack(gAllocLog);
1118 }
1119
1120 if (gRefcntsLog && loggingThisType && loggingThisObject) {
1121 if (gLogToLeaky) {
1122 (*leakyLogAddRef)(aPtr, aRefcnt - 1, aRefcnt);
1123 }
1124 else {
1125 // Can't use PR_LOG(), b/c it truncates the line
1126 fprintf(gRefcntsLog,
1127 "\n<%s> 0x%08X %d AddRef %d\n", aClazz, NS_PTR_TO_INT32(aPtr), serialno, aRefcnt);
1128 WalkTheStack(gRefcntsLog);
1129 fflush(gRefcntsLog);
1130 }
1131 }
1132 UNLOCK_TRACELOG();
1133 }
1134#endif
1135 return NS_OK;
1136}
1137
1138NS_IMETHODIMP
1139nsTraceRefcntImpl::LogRelease(void* aPtr,
1140 nsrefcnt aRefcnt,
1141 const char* aClazz)
1142{
1143#ifdef NS_BUILD_REFCNT_LOGGING
1144 ASSERT_ACTIVITY_IS_LEGAL;
1145 if (!gInitialized)
1146 InitTraceLog();
1147 if (gLogging) {
1148 LOCK_TRACELOG();
1149
1150 if (gBloatLog) {
1151 BloatEntry* entry = GetBloatEntry(aClazz, 0);
1152 if (entry) {
1153 entry->Release(aRefcnt);
1154 }
1155 }
1156
1157 PRBool loggingThisType = (!gTypesToLog || LogThisType(aClazz));
1158 PRInt32 serialno = 0;
1159 if (gSerialNumbers && loggingThisType) {
1160 serialno = GetSerialNumber(aPtr, PR_FALSE);
1161 PRInt32* count = GetRefCount(aPtr);
1162 if(count)
1163 (*count)--;
1164
1165 }
1166
1167 PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
1168 if (gRefcntsLog && loggingThisType && loggingThisObject) {
1169 if (gLogToLeaky) {
1170 (*leakyLogRelease)(aPtr, aRefcnt + 1, aRefcnt);
1171 }
1172 else {
1173 // Can't use PR_LOG(), b/c it truncates the line
1174 fprintf(gRefcntsLog,
1175 "\n<%s> 0x%08X %d Release %d\n", aClazz, NS_PTR_TO_INT32(aPtr), serialno, aRefcnt);
1176 WalkTheStack(gRefcntsLog);
1177 fflush(gRefcntsLog);
1178 }
1179 }
1180
1181 // Here's the case where neither NS_DELETEXPCOM nor MOZ_COUNT_DTOR were used,
1182 // yet we still want to see deletion information:
1183
1184 if (aRefcnt == 0 && gAllocLog && loggingThisType && loggingThisObject) {
1185 fprintf(gAllocLog,
1186 "\n<%s> 0x%08X %d Destroy\n",
1187 aClazz, NS_PTR_TO_INT32(aPtr), serialno);
1188 WalkTheStack(gAllocLog);
1189 }
1190
1191 if (aRefcnt == 0 && gSerialNumbers && loggingThisType) {
1192 RecycleSerialNumberPtr(aPtr);
1193 }
1194
1195 UNLOCK_TRACELOG();
1196 }
1197#endif
1198 return NS_OK;
1199}
1200
1201NS_IMETHODIMP
1202nsTraceRefcntImpl::LogCtor(void* aPtr,
1203 const char* aType,
1204 PRUint32 aInstanceSize)
1205{
1206#ifdef NS_BUILD_REFCNT_LOGGING
1207 ASSERT_ACTIVITY_IS_LEGAL;
1208 if (!gInitialized)
1209 InitTraceLog();
1210
1211 if (gLogging) {
1212 LOCK_TRACELOG();
1213
1214 if (gBloatLog) {
1215 BloatEntry* entry = GetBloatEntry(aType, aInstanceSize);
1216 if (entry) {
1217 entry->Ctor();
1218 }
1219 }
1220
1221 PRBool loggingThisType = (!gTypesToLog || LogThisType(aType));
1222 PRInt32 serialno = 0;
1223 if (gSerialNumbers && loggingThisType) {
1224 serialno = GetSerialNumber(aPtr, PR_TRUE);
1225 }
1226
1227 PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
1228 if (gAllocLog && loggingThisType && loggingThisObject) {
1229 fprintf(gAllocLog, "\n<%s> 0x%08X %d Ctor (%d)\n",
1230 aType, NS_PTR_TO_INT32(aPtr), serialno, aInstanceSize);
1231 WalkTheStack(gAllocLog);
1232 }
1233
1234 UNLOCK_TRACELOG();
1235 }
1236#endif
1237 return NS_OK;
1238}
1239
1240
1241NS_IMETHODIMP
1242nsTraceRefcntImpl::LogDtor(void* aPtr,
1243 const char* aType,
1244 PRUint32 aInstanceSize)
1245{
1246#ifdef NS_BUILD_REFCNT_LOGGING
1247 ASSERT_ACTIVITY_IS_LEGAL;
1248 if (!gInitialized)
1249 InitTraceLog();
1250
1251 if (gLogging) {
1252 LOCK_TRACELOG();
1253
1254 if (gBloatLog) {
1255 BloatEntry* entry = GetBloatEntry(aType, aInstanceSize);
1256 if (entry) {
1257 entry->Dtor();
1258 }
1259 }
1260
1261 PRBool loggingThisType = (!gTypesToLog || LogThisType(aType));
1262 PRInt32 serialno = 0;
1263 if (gSerialNumbers && loggingThisType) {
1264 serialno = GetSerialNumber(aPtr, PR_FALSE);
1265 RecycleSerialNumberPtr(aPtr);
1266 }
1267
1268 PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
1269
1270 // (If we're on a losing architecture, don't do this because we'll be
1271 // using LogDeleteXPCOM instead to get file and line numbers.)
1272 if (gAllocLog && loggingThisType && loggingThisObject) {
1273 fprintf(gAllocLog, "\n<%s> 0x%08X %d Dtor (%d)\n",
1274 aType, NS_PTR_TO_INT32(aPtr), serialno, aInstanceSize);
1275 WalkTheStack(gAllocLog);
1276 }
1277
1278 UNLOCK_TRACELOG();
1279 }
1280#endif
1281 return NS_OK;
1282}
1283
1284
1285NS_IMETHODIMP
1286nsTraceRefcntImpl::LogAddCOMPtr(void* aCOMPtr,
1287 nsISupports* aObject)
1288{
1289#if defined(NS_BUILD_REFCNT_LOGGING) && defined(HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR)
1290 // Get the most-derived object.
1291 void *object = dynamic_cast<void *>(aObject);
1292
1293 // This is a very indirect way of finding out what the class is
1294 // of the object being logged. If we're logging a specific type,
1295 // then
1296 if (!gTypesToLog || !gSerialNumbers) {
1297 return NS_OK;
1298 }
1299 PRInt32 serialno = GetSerialNumber(object, PR_FALSE);
1300 if (serialno == 0) {
1301 return NS_OK;
1302 }
1303
1304 if (!gInitialized)
1305 InitTraceLog();
1306 if (gLogging) {
1307 LOCK_TRACELOG();
1308
1309 PRInt32* count = GetCOMPtrCount(object);
1310 if(count)
1311 (*count)++;
1312
1313 PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
1314
1315 if (gCOMPtrLog && loggingThisObject) {
1316 fprintf(gCOMPtrLog, "\n<?> 0x%08X %d nsCOMPtrAddRef %d 0x%08X\n",
1317 NS_PTR_TO_INT32(object), serialno, count?(*count):-1, NS_PTR_TO_INT32(aCOMPtr));
1318 WalkTheStack(gCOMPtrLog);
1319 }
1320
1321 UNLOCK_TRACELOG();
1322 }
1323#endif
1324 return NS_OK;
1325}
1326
1327
1328NS_IMETHODIMP
1329nsTraceRefcntImpl::LogReleaseCOMPtr(void* aCOMPtr,
1330 nsISupports* aObject)
1331{
1332#if defined(NS_BUILD_REFCNT_LOGGING) && defined(HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR)
1333 // Get the most-derived object.
1334 void *object = dynamic_cast<void *>(aObject);
1335
1336 // This is a very indirect way of finding out what the class is
1337 // of the object being logged. If we're logging a specific type,
1338 // then
1339 if (!gTypesToLog || !gSerialNumbers) {
1340 return NS_OK;
1341 }
1342 PRInt32 serialno = GetSerialNumber(object, PR_FALSE);
1343 if (serialno == 0) {
1344 return NS_OK;
1345 }
1346
1347 if (!gInitialized)
1348 InitTraceLog();
1349 if (gLogging) {
1350 LOCK_TRACELOG();
1351
1352 PRInt32* count = GetCOMPtrCount(object);
1353 if(count)
1354 (*count)--;
1355
1356 PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
1357
1358 if (gCOMPtrLog && loggingThisObject) {
1359 fprintf(gCOMPtrLog, "\n<?> 0x%08X %d nsCOMPtrRelease %d 0x%08X\n",
1360 NS_PTR_TO_INT32(object), serialno, count?(*count):-1, NS_PTR_TO_INT32(aCOMPtr));
1361 WalkTheStack(gCOMPtrLog);
1362 }
1363
1364 UNLOCK_TRACELOG();
1365 }
1366#endif
1367 return NS_OK;
1368}
1369
1370NS_COM void
1371nsTraceRefcntImpl::Startup()
1372{
1373#ifdef NS_BUILD_REFCNT_LOGGING
1374 SetActivityIsLegal(PR_TRUE);
1375#endif
1376}
1377
1378NS_COM void
1379nsTraceRefcntImpl::Shutdown()
1380{
1381#ifdef NS_BUILD_REFCNT_LOGGING
1382
1383 if (gBloatView) {
1384 PL_HashTableDestroy(gBloatView);
1385 gBloatView = nsnull;
1386 }
1387 if (gTypesToLog) {
1388 PL_HashTableDestroy(gTypesToLog);
1389 gTypesToLog = nsnull;
1390 }
1391 if (gObjectsToLog) {
1392 PL_HashTableDestroy(gObjectsToLog);
1393 gObjectsToLog = nsnull;
1394 }
1395 if (gSerialNumbers) {
1396 PL_HashTableDestroy(gSerialNumbers);
1397 gSerialNumbers = nsnull;
1398 }
1399
1400 SetActivityIsLegal(PR_FALSE);
1401
1402#endif
1403}
1404
1405NS_COM void
1406nsTraceRefcntImpl::SetActivityIsLegal(PRBool aLegal)
1407{
1408#ifdef NS_BUILD_REFCNT_LOGGING
1409 gActivityIsLegal = aLegal;
1410#endif
1411}
1412
1413
1414NS_METHOD
1415nsTraceRefcntImpl::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr)
1416{
1417 *aInstancePtr = nsnull;
1418 nsITraceRefcnt* tracer = new nsTraceRefcntImpl();
1419 if (!tracer)
1420 return NS_ERROR_OUT_OF_MEMORY;
1421
1422 nsresult rv = tracer->QueryInterface(aIID, aInstancePtr);
1423 if (NS_FAILED(rv)) {
1424 delete tracer;
1425 }
1426
1427 return rv;
1428}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette