1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Communicator client code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * L. David Baron <dbaron@dbaron.org>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include "nsTraceRefcntImpl.h"
40 : #include "nsXPCOMPrivate.h"
41 : #include "nscore.h"
42 : #include "nsISupports.h"
43 : #include "nsTArray.h"
44 : #include "prenv.h"
45 : #include "prprf.h"
46 : #include "prlog.h"
47 : #include "plstr.h"
48 : #include "prlink.h"
49 : #include <stdlib.h>
50 : #include "nsCOMPtr.h"
51 : #include "nsCRT.h"
52 : #include <math.h>
53 : #include "nsStackWalkPrivate.h"
54 : #include "nsStackWalk.h"
55 : #include "nsString.h"
56 :
57 : #include "nsXULAppAPI.h"
58 : #ifdef XP_WIN
59 : #include <process.h>
60 : #define getpid _getpid
61 : #else
62 : #include <unistd.h>
63 : #endif
64 :
65 : #ifdef NS_TRACE_MALLOC
66 : #include "nsTraceMalloc.h"
67 : #endif
68 :
69 : #include "mozilla/BlockingResourceBase.h"
70 :
71 : #ifdef HAVE_DLOPEN
72 : #include <dlfcn.h>
73 : #endif
74 :
75 : ////////////////////////////////////////////////////////////////////////////////
76 :
77 : void
78 1540 : NS_MeanAndStdDev(double n, double sumOfValues, double sumOfSquaredValues,
79 : double *meanResult, double *stdDevResult)
80 : {
81 1540 : double mean = 0.0, var = 0.0, stdDev = 0.0;
82 1540 : if (n > 0.0 && sumOfValues >= 0) {
83 1324 : mean = sumOfValues / n;
84 1324 : double temp = (n * sumOfSquaredValues) - (sumOfValues * sumOfValues);
85 1324 : if (temp < 0.0 || n <= 1)
86 180 : var = 0.0;
87 : else
88 1144 : var = temp / (n * (n - 1));
89 : // for some reason, Windows says sqrt(0.0) is "-1.#J" (?!) so do this:
90 1324 : stdDev = var != 0.0 ? sqrt(var) : 0.0;
91 : }
92 1540 : *meanResult = mean;
93 1540 : *stdDevResult = stdDev;
94 1540 : }
95 :
96 : ////////////////////////////////////////////////////////////////////////////////
97 :
98 : #define NS_IMPL_REFCNT_LOGGING
99 :
100 : #ifdef NS_IMPL_REFCNT_LOGGING
101 : #include "plhash.h"
102 : #include "prmem.h"
103 :
104 : #include "prlock.h"
105 :
106 : // TraceRefcnt has to use bare PRLock instead of mozilla::Mutex
107 : // because TraceRefcnt can be used very early in startup.
108 : static PRLock* gTraceLock;
109 :
110 : #define LOCK_TRACELOG() PR_Lock(gTraceLock)
111 : #define UNLOCK_TRACELOG() PR_Unlock(gTraceLock)
112 :
113 : static PLHashTable* gBloatView;
114 : static PLHashTable* gTypesToLog;
115 : static PLHashTable* gObjectsToLog;
116 : static PLHashTable* gSerialNumbers;
117 : static PRInt32 gNextSerialNumber;
118 :
119 : static bool gLogging;
120 : static bool gLogToLeaky;
121 : static bool gLogLeaksOnly;
122 :
123 : static void (*leakyLogAddRef)(void* p, int oldrc, int newrc);
124 : static void (*leakyLogRelease)(void* p, int oldrc, int newrc);
125 :
126 : #define BAD_TLS_INDEX ((PRUintn) -1)
127 :
128 : // if gActivityTLS == BAD_TLS_INDEX, then we're
129 : // unitialized... otherwise this points to a NSPR TLS thread index
130 : // indicating whether addref activity is legal. If the PTR_TO_INT32 is 0 then
131 : // activity is ok, otherwise not!
132 : static PRUintn gActivityTLS = BAD_TLS_INDEX;
133 :
134 : static bool gInitialized;
135 : static nsrefcnt gInitCount;
136 :
137 : static FILE *gBloatLog = nsnull;
138 : static FILE *gRefcntsLog = nsnull;
139 : static FILE *gAllocLog = nsnull;
140 : static FILE *gLeakyLog = nsnull;
141 : static FILE *gCOMPtrLog = nsnull;
142 :
143 : struct serialNumberRecord {
144 : PRInt32 serialNumber;
145 : PRInt32 refCount;
146 : PRInt32 COMPtrCount;
147 : };
148 :
149 : struct nsTraceRefcntStats {
150 : PRUint64 mAddRefs;
151 : PRUint64 mReleases;
152 : PRUint64 mCreates;
153 : PRUint64 mDestroys;
154 : double mRefsOutstandingTotal;
155 : double mRefsOutstandingSquared;
156 : double mObjsOutstandingTotal;
157 : double mObjsOutstandingSquared;
158 : };
159 :
160 : // I hope to turn this on for everybody once we hit it a little less.
161 : #ifdef DEBUG
162 : static const char kStaticCtorDtorWarning[] =
163 : "XPCOM objects created/destroyed from static ctor/dtor";
164 :
165 : static void
166 212092067 : AssertActivityIsLegal()
167 : {
168 424180879 : if (gActivityTLS == BAD_TLS_INDEX ||
169 212098910 : NS_PTR_TO_INT32(PR_GetThreadPrivate(gActivityTLS)) != 0) {
170 438 : if (PR_GetEnv("MOZ_FATAL_STATIC_XPCOM_CTORS_DTORS")) {
171 0 : NS_RUNTIMEABORT(kStaticCtorDtorWarning);
172 : } else {
173 438 : NS_WARNING(kStaticCtorDtorWarning);
174 : }
175 : }
176 212081969 : }
177 : # define ASSERT_ACTIVITY_IS_LEGAL \
178 : PR_BEGIN_MACRO \
179 : AssertActivityIsLegal(); \
180 : PR_END_MACRO
181 : #else
182 : # define ASSERT_ACTIVITY_IS_LEGAL PR_BEGIN_MACRO PR_END_MACRO
183 : #endif // DEBUG
184 :
185 : // These functions are copied from nsprpub/lib/ds/plhash.c, with changes
186 : // to the functions not called Default* to free the serialNumberRecord or
187 : // the BloatEntry.
188 :
189 : static void *
190 3323 : DefaultAllocTable(void *pool, PRSize size)
191 : {
192 3323 : return PR_MALLOC(size);
193 : }
194 :
195 : static void
196 3321 : DefaultFreeTable(void *pool, void *item)
197 : {
198 3321 : PR_Free(item);
199 3321 : }
200 :
201 : static PLHashEntry *
202 298597 : DefaultAllocEntry(void *pool, const void *key)
203 : {
204 298597 : return PR_NEW(PLHashEntry);
205 : }
206 :
207 : static void
208 0 : SerialNumberFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
209 : {
210 0 : if (flag == HT_FREE_ENTRY) {
211 0 : PR_Free(reinterpret_cast<serialNumberRecord*>(he->value));
212 0 : PR_Free(he);
213 : }
214 0 : }
215 :
216 : static void
217 0 : TypesToLogFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
218 : {
219 0 : if (flag == HT_FREE_ENTRY) {
220 0 : nsCRT::free(const_cast<char*>
221 0 : (reinterpret_cast<const char*>(he->key)));
222 0 : PR_Free(he);
223 : }
224 0 : }
225 :
226 : static const PLHashAllocOps serialNumberHashAllocOps = {
227 : DefaultAllocTable, DefaultFreeTable,
228 : DefaultAllocEntry, SerialNumberFreeEntry
229 : };
230 :
231 : static const PLHashAllocOps typesToLogHashAllocOps = {
232 : DefaultAllocTable, DefaultFreeTable,
233 : DefaultAllocEntry, TypesToLogFreeEntry
234 : };
235 :
236 : ////////////////////////////////////////////////////////////////////////////////
237 :
238 : class BloatEntry {
239 : public:
240 300005 : BloatEntry(const char* className, PRUint32 classSize)
241 300005 : : mClassSize(classSize) {
242 300005 : mClassName = PL_strdup(className);
243 300005 : Clear(&mNewStats);
244 300005 : Clear(&mAllStats);
245 300005 : mTotalLeaked = 0;
246 300005 : }
247 :
248 299997 : ~BloatEntry() {
249 299997 : PL_strfree(mClassName);
250 299997 : }
251 :
252 120255490 : PRUint32 GetClassSize() { return (PRUint32)mClassSize; }
253 143496 : const char* GetClassName() { return mClassName; }
254 :
255 898599 : static void Clear(nsTraceRefcntStats* stats) {
256 898599 : stats->mAddRefs = 0;
257 898599 : stats->mReleases = 0;
258 898599 : stats->mCreates = 0;
259 898599 : stats->mDestroys = 0;
260 898599 : stats->mRefsOutstandingTotal = 0;
261 898599 : stats->mRefsOutstandingSquared = 0;
262 898599 : stats->mObjsOutstandingTotal = 0;
263 898599 : stats->mObjsOutstandingSquared = 0;
264 898599 : }
265 :
266 298589 : void Accumulate() {
267 298589 : mAllStats.mAddRefs += mNewStats.mAddRefs;
268 298589 : mAllStats.mReleases += mNewStats.mReleases;
269 298589 : mAllStats.mCreates += mNewStats.mCreates;
270 298589 : mAllStats.mDestroys += mNewStats.mDestroys;
271 298589 : mAllStats.mRefsOutstandingTotal += mNewStats.mRefsOutstandingTotal;
272 298589 : mAllStats.mRefsOutstandingSquared += mNewStats.mRefsOutstandingSquared;
273 298589 : mAllStats.mObjsOutstandingTotal += mNewStats.mObjsOutstandingTotal;
274 298589 : mAllStats.mObjsOutstandingSquared += mNewStats.mObjsOutstandingSquared;
275 298589 : Clear(&mNewStats);
276 298589 : }
277 :
278 87212140 : void AddRef(nsrefcnt refcnt) {
279 87212140 : mNewStats.mAddRefs++;
280 87212140 : if (refcnt == 1) {
281 15721754 : Ctor();
282 : }
283 87212140 : AccountRefs();
284 87212140 : }
285 :
286 87198327 : void Release(nsrefcnt refcnt) {
287 87198327 : mNewStats.mReleases++;
288 87198327 : if (refcnt == 0) {
289 15712698 : Dtor();
290 : }
291 87198327 : AccountRefs();
292 87198327 : }
293 :
294 32394108 : void Ctor() {
295 32394108 : mNewStats.mCreates++;
296 32394108 : AccountObjs();
297 32394108 : }
298 :
299 32382291 : void Dtor() {
300 32382291 : mNewStats.mDestroys++;
301 32382291 : AccountObjs();
302 32382291 : }
303 :
304 174410467 : void AccountRefs() {
305 174410467 : PRUint64 cnt = (mNewStats.mAddRefs - mNewStats.mReleases);
306 174410467 : mNewStats.mRefsOutstandingTotal += cnt;
307 174410467 : mNewStats.mRefsOutstandingSquared += cnt * cnt;
308 174410467 : }
309 :
310 64776399 : void AccountObjs() {
311 64776399 : PRUint64 cnt = (mNewStats.mCreates - mNewStats.mDestroys);
312 64776399 : mNewStats.mObjsOutstandingTotal += cnt;
313 64776399 : mNewStats.mObjsOutstandingSquared += cnt * cnt;
314 64776399 : }
315 :
316 298589 : static PRIntn DumpEntry(PLHashEntry *he, PRIntn i, void *arg) {
317 298589 : BloatEntry* entry = (BloatEntry*)he->value;
318 298589 : if (entry) {
319 298589 : entry->Accumulate();
320 298589 : static_cast<nsTArray<BloatEntry*>*>(arg)->AppendElement(entry);
321 : }
322 298589 : return HT_ENUMERATE_NEXT;
323 : }
324 :
325 298589 : static PRIntn TotalEntries(PLHashEntry *he, PRIntn i, void *arg) {
326 298589 : BloatEntry* entry = (BloatEntry*)he->value;
327 298589 : if (entry && nsCRT::strcmp(entry->mClassName, "TOTAL") != 0) {
328 298589 : entry->Total((BloatEntry*)arg);
329 : }
330 298589 : return HT_ENUMERATE_NEXT;
331 : }
332 :
333 298589 : void Total(BloatEntry* total) {
334 298589 : total->mAllStats.mAddRefs += mNewStats.mAddRefs + mAllStats.mAddRefs;
335 298589 : total->mAllStats.mReleases += mNewStats.mReleases + mAllStats.mReleases;
336 298589 : total->mAllStats.mCreates += mNewStats.mCreates + mAllStats.mCreates;
337 298589 : total->mAllStats.mDestroys += mNewStats.mDestroys + mAllStats.mDestroys;
338 298589 : total->mAllStats.mRefsOutstandingTotal += mNewStats.mRefsOutstandingTotal + mAllStats.mRefsOutstandingTotal;
339 298589 : total->mAllStats.mRefsOutstandingSquared += mNewStats.mRefsOutstandingSquared + mAllStats.mRefsOutstandingSquared;
340 298589 : total->mAllStats.mObjsOutstandingTotal += mNewStats.mObjsOutstandingTotal + mAllStats.mObjsOutstandingTotal;
341 298589 : total->mAllStats.mObjsOutstandingSquared += mNewStats.mObjsOutstandingSquared + mAllStats.mObjsOutstandingSquared;
342 298589 : PRUint64 count = (mNewStats.mCreates + mAllStats.mCreates);
343 298589 : total->mClassSize += mClassSize * count; // adjust for average in DumpTotal
344 : total->mTotalLeaked += (PRUint64)(mClassSize *
345 : ((mNewStats.mCreates + mAllStats.mCreates)
346 298589 : -(mNewStats.mDestroys + mAllStats.mDestroys)));
347 298589 : }
348 :
349 41 : void DumpTotal(FILE* out) {
350 41 : mClassSize /= mAllStats.mCreates;
351 41 : Dump(-1, out, nsTraceRefcntImpl::ALL_STATS);
352 41 : }
353 :
354 7038 : static bool HaveLeaks(nsTraceRefcntStats* stats) {
355 : return ((stats->mAddRefs != stats->mReleases) ||
356 7038 : (stats->mCreates != stats->mDestroys));
357 : }
358 :
359 1408 : bool PrintDumpHeader(FILE* out, const char* msg, nsTraceRefcntImpl::StatisticsType type) {
360 : fprintf(out, "\n== BloatView: %s, %s process %d\n", msg,
361 1408 : XRE_ChildProcessTypeToString(XRE_GetProcessType()), getpid());
362 : nsTraceRefcntStats& stats =
363 1408 : (type == nsTraceRefcntImpl::NEW_STATS) ? mNewStats : mAllStats;
364 1408 : if (gLogLeaksOnly && !HaveLeaks(&stats))
365 1367 : return false;
366 :
367 : fprintf(out,
368 : "\n" \
369 : " |<----------------Class--------------->|<-----Bytes------>|<----------------Objects---------------->|<--------------References-------------->|\n" \
370 41 : " Per-Inst Leaked Total Rem Mean StdDev Total Rem Mean StdDev\n");
371 :
372 41 : this->DumpTotal(out);
373 :
374 41 : return true;
375 : }
376 :
377 5806 : void Dump(PRIntn i, FILE* out, nsTraceRefcntImpl::StatisticsType type) {
378 5806 : nsTraceRefcntStats* stats = (type == nsTraceRefcntImpl::NEW_STATS) ? &mNewStats : &mAllStats;
379 5806 : if (gLogLeaksOnly && !HaveLeaks(stats)) {
380 5036 : return;
381 : }
382 :
383 : double meanRefs, stddevRefs;
384 : NS_MeanAndStdDev(stats->mAddRefs + stats->mReleases,
385 : stats->mRefsOutstandingTotal,
386 : stats->mRefsOutstandingSquared,
387 770 : &meanRefs, &stddevRefs);
388 :
389 : double meanObjs, stddevObjs;
390 : NS_MeanAndStdDev(stats->mCreates + stats->mDestroys,
391 : stats->mObjsOutstandingTotal,
392 : stats->mObjsOutstandingSquared,
393 770 : &meanObjs, &stddevObjs);
394 :
395 770 : if ((stats->mAddRefs - stats->mReleases) != 0 ||
396 : stats->mAddRefs != 0 ||
397 : meanRefs != 0 ||
398 : stddevRefs != 0 ||
399 : (stats->mCreates - stats->mDestroys) != 0 ||
400 : stats->mCreates != 0 ||
401 : meanObjs != 0 ||
402 : stddevObjs != 0) {
403 : fprintf(out, "%4d %-40.40s %8d %8llu %8llu %8llu (%8.2f +/- %8.2f) %8llu %8llu (%8.2f +/- %8.2f)\n",
404 : i+1, mClassName,
405 : (PRInt32)mClassSize,
406 770 : (nsCRT::strcmp(mClassName, "TOTAL"))
407 : ?(PRUint64)((stats->mCreates - stats->mDestroys) * mClassSize)
408 : :mTotalLeaked,
409 : stats->mCreates,
410 : (stats->mCreates - stats->mDestroys),
411 : meanObjs,
412 : stddevObjs,
413 : stats->mAddRefs,
414 : (stats->mAddRefs - stats->mReleases),
415 : meanRefs,
416 1540 : stddevRefs);
417 : }
418 : }
419 :
420 : protected:
421 : char* mClassName;
422 : double mClassSize; // this is stored as a double because of the way we compute the avg class size for total bloat
423 : PRUint64 mTotalLeaked; // used only for TOTAL entry
424 : nsTraceRefcntStats mNewStats;
425 : nsTraceRefcntStats mAllStats;
426 : };
427 :
428 : static void
429 298589 : BloatViewFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
430 : {
431 298589 : if (flag == HT_FREE_ENTRY) {
432 298589 : BloatEntry* entry = reinterpret_cast<BloatEntry*>(he->value);
433 298589 : delete entry;
434 298589 : PR_Free(he);
435 : }
436 298589 : }
437 :
438 : const static PLHashAllocOps bloatViewHashAllocOps = {
439 : DefaultAllocTable, DefaultFreeTable,
440 : DefaultAllocEntry, BloatViewFreeEntry
441 : };
442 :
443 : static void
444 1409 : RecreateBloatView()
445 : {
446 : gBloatView = PL_NewHashTable(256,
447 : PL_HashString,
448 : PL_CompareStrings,
449 : PL_CompareValues,
450 1409 : &bloatViewHashAllocOps, NULL);
451 1409 : }
452 :
453 : static BloatEntry*
454 207752414 : GetBloatEntry(const char* aTypeName, PRUint32 aInstanceSize)
455 : {
456 207752414 : if (!gBloatView) {
457 0 : RecreateBloatView();
458 : }
459 207752414 : BloatEntry* entry = NULL;
460 207752414 : if (gBloatView) {
461 207752414 : entry = (BloatEntry*)PL_HashTableLookup(gBloatView, aTypeName);
462 207752414 : if (entry == NULL && aInstanceSize > 0) {
463 :
464 298597 : entry = new BloatEntry(aTypeName, aInstanceSize);
465 298597 : PLHashEntry* e = PL_HashTableAdd(gBloatView, aTypeName, entry);
466 298597 : if (e == NULL) {
467 0 : delete entry;
468 0 : entry = NULL;
469 298597 : }
470 : } else {
471 207453817 : NS_ASSERTION(aInstanceSize == 0 ||
472 : entry->GetClassSize() == aInstanceSize,
473 : "bad size recorded");
474 : }
475 : }
476 207752414 : return entry;
477 : }
478 :
479 0 : static PRIntn DumpSerialNumbers(PLHashEntry* aHashEntry, PRIntn aIndex, void* aClosure)
480 : {
481 0 : serialNumberRecord* record = reinterpret_cast<serialNumberRecord *>(aHashEntry->value);
482 : #ifdef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR
483 : fprintf((FILE*) aClosure, "%d @%p (%d references; %d from COMPtrs)\n",
484 : record->serialNumber,
485 : NS_INT32_TO_PTR(aHashEntry->key),
486 : record->refCount,
487 0 : record->COMPtrCount);
488 : #else
489 : fprintf((FILE*) aClosure, "%d @%p (%d references)\n",
490 : record->serialNumber,
491 : NS_INT32_TO_PTR(aHashEntry->key),
492 : record->refCount);
493 : #endif
494 0 : return HT_ENUMERATE_NEXT;
495 : }
496 :
497 :
498 : template <>
499 : class nsDefaultComparator <BloatEntry*, BloatEntry*> {
500 : public:
501 25332 : bool Equals(BloatEntry* const& aA, BloatEntry* const& aB) const {
502 25332 : return PL_strcmp(aA->GetClassName(), aB->GetClassName()) == 0;
503 : }
504 46416 : bool LessThan(BloatEntry* const& aA, BloatEntry* const& aB) const {
505 46416 : return PL_strcmp(aA->GetClassName(), aB->GetClassName()) < 0;
506 : }
507 : };
508 :
509 : #endif /* NS_IMPL_REFCNT_LOGGING */
510 :
511 : nsresult
512 1442 : nsTraceRefcntImpl::DumpStatistics(StatisticsType type, FILE* out)
513 : {
514 : #ifdef NS_IMPL_REFCNT_LOGGING
515 1442 : if (gBloatLog == nsnull || gBloatView == nsnull) {
516 34 : return NS_ERROR_FAILURE;
517 : }
518 1408 : if (out == nsnull) {
519 1408 : out = gBloatLog;
520 : }
521 :
522 1408 : LOCK_TRACELOG();
523 :
524 1408 : bool wasLogging = gLogging;
525 1408 : gLogging = false; // turn off logging for this method
526 :
527 2816 : BloatEntry total("TOTAL", 0);
528 1408 : PL_HashTableEnumerateEntries(gBloatView, BloatEntry::TotalEntries, &total);
529 : const char* msg;
530 1408 : if (type == NEW_STATS) {
531 0 : if (gLogLeaksOnly)
532 0 : msg = "NEW (incremental) LEAK STATISTICS";
533 : else
534 0 : msg = "NEW (incremental) LEAK AND BLOAT STATISTICS";
535 : }
536 : else {
537 1408 : if (gLogLeaksOnly)
538 1386 : msg = "ALL (cumulative) LEAK STATISTICS";
539 : else
540 22 : msg = "ALL (cumulative) LEAK AND BLOAT STATISTICS";
541 : }
542 1408 : const bool leaked = total.PrintDumpHeader(out, msg, type);
543 :
544 2816 : nsTArray<BloatEntry*> entries;
545 1408 : PL_HashTableEnumerateEntries(gBloatView, BloatEntry::DumpEntry, &entries);
546 1408 : const PRUint32 count = entries.Length();
547 :
548 1408 : if (!gLogLeaksOnly || leaked) {
549 : // Sort the entries alphabetically by classname.
550 41 : entries.Sort();
551 :
552 5806 : for (PRUint32 i = 0; i < count; ++i) {
553 5765 : BloatEntry* entry = entries[i];
554 5765 : entry->Dump(i, out, type);
555 : }
556 :
557 41 : fprintf(out, "\n");
558 : }
559 :
560 1408 : fprintf(out, "nsTraceRefcntImpl::DumpStatistics: %d entries\n", count);
561 :
562 1408 : if (gSerialNumbers) {
563 0 : fprintf(out, "\nSerial Numbers of Leaked Objects:\n");
564 0 : PL_HashTableEnumerateEntries(gSerialNumbers, DumpSerialNumbers, out);
565 : }
566 :
567 1408 : gLogging = wasLogging;
568 1408 : UNLOCK_TRACELOG();
569 : #endif
570 :
571 1408 : return NS_OK;
572 : }
573 :
574 : void
575 1442 : nsTraceRefcntImpl::ResetStatistics()
576 : {
577 : #ifdef NS_IMPL_REFCNT_LOGGING
578 1442 : LOCK_TRACELOG();
579 1442 : if (gBloatView) {
580 1408 : PL_HashTableDestroy(gBloatView);
581 1408 : gBloatView = nsnull;
582 : }
583 1442 : UNLOCK_TRACELOG();
584 : #endif
585 1442 : }
586 :
587 : #ifdef NS_IMPL_REFCNT_LOGGING
588 0 : static bool LogThisType(const char* aTypeName)
589 : {
590 0 : void* he = PL_HashTableLookup(gTypesToLog, aTypeName);
591 0 : return nsnull != he;
592 : }
593 :
594 0 : static PRInt32 GetSerialNumber(void* aPtr, bool aCreate)
595 : {
596 0 : PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr);
597 0 : if (hep && *hep) {
598 0 : return PRInt32((reinterpret_cast<serialNumberRecord*>((*hep)->value))->serialNumber);
599 : }
600 0 : else if (aCreate) {
601 0 : serialNumberRecord *record = PR_NEW(serialNumberRecord);
602 0 : record->serialNumber = ++gNextSerialNumber;
603 0 : record->refCount = 0;
604 0 : record->COMPtrCount = 0;
605 0 : PL_HashTableRawAdd(gSerialNumbers, hep, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr, reinterpret_cast<void*>(record));
606 0 : return gNextSerialNumber;
607 : }
608 : else {
609 0 : return 0;
610 : }
611 : }
612 :
613 0 : static PRInt32* GetRefCount(void* aPtr)
614 : {
615 0 : PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr);
616 0 : if (hep && *hep) {
617 0 : return &((reinterpret_cast<serialNumberRecord*>((*hep)->value))->refCount);
618 : } else {
619 0 : return nsnull;
620 : }
621 : }
622 :
623 0 : static PRInt32* GetCOMPtrCount(void* aPtr)
624 : {
625 0 : PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr);
626 0 : if (hep && *hep) {
627 0 : return &((reinterpret_cast<serialNumberRecord*>((*hep)->value))->COMPtrCount);
628 : } else {
629 0 : return nsnull;
630 : }
631 : }
632 :
633 0 : static void RecycleSerialNumberPtr(void* aPtr)
634 : {
635 0 : PL_HashTableRemove(gSerialNumbers, aPtr);
636 0 : }
637 :
638 0 : static bool LogThisObj(PRInt32 aSerialNumber)
639 : {
640 0 : return nsnull != PL_HashTableLookup(gObjectsToLog, (const void*)(aSerialNumber));
641 : }
642 :
643 : #ifdef XP_WIN
644 : #define FOPEN_NO_INHERIT "N"
645 : #else
646 : #define FOPEN_NO_INHERIT
647 : #endif
648 :
649 7213 : static bool InitLog(const char* envVar, const char* msg, FILE* *result)
650 : {
651 7213 : const char* value = getenv(envVar);
652 7213 : if (value) {
653 1410 : if (nsCRT::strcmp(value, "1") == 0) {
654 0 : *result = stdout;
655 : fprintf(stdout, "### %s defined -- logging %s to stdout\n",
656 0 : envVar, msg);
657 0 : return true;
658 : }
659 1410 : else if (nsCRT::strcmp(value, "2") == 0) {
660 0 : *result = stderr;
661 : fprintf(stdout, "### %s defined -- logging %s to stderr\n",
662 0 : envVar, msg);
663 0 : return true;
664 : }
665 : else {
666 : FILE *stream;
667 2820 : nsCAutoString fname(value);
668 1410 : if (XRE_GetProcessType() != GeckoProcessType_Default) {
669 : bool hasLogExtension =
670 1 : fname.RFind(".log", true, -1, 4) == kNotFound ? false : true;
671 1 : if (hasLogExtension)
672 1 : fname.Cut(fname.Length() - 4, 4);
673 1 : fname.AppendLiteral("_");
674 1 : fname.Append((char*)XRE_ChildProcessTypeToString(XRE_GetProcessType()));
675 1 : fname.AppendLiteral("_pid");
676 1 : fname.AppendInt((PRUint32)getpid());
677 1 : if (hasLogExtension)
678 1 : fname.AppendLiteral(".log");
679 : }
680 1410 : stream = ::fopen(fname.get(), "w" FOPEN_NO_INHERIT);
681 1410 : if (stream != NULL) {
682 1409 : *result = stream;
683 : fprintf(stdout, "### %s defined -- logging %s to %s\n",
684 1409 : envVar, msg, fname.get());
685 : }
686 : else {
687 : fprintf(stdout, "### %s defined -- unable to log %s to %s\n",
688 1 : envVar, msg, fname.get());
689 : }
690 1410 : return stream != NULL;
691 : }
692 : }
693 5803 : return false;
694 : }
695 :
696 :
697 0 : static PLHashNumber HashNumber(const void* aKey)
698 : {
699 0 : return PLHashNumber(NS_PTR_TO_INT32(aKey));
700 : }
701 :
702 1447 : static void InitTraceLog(void)
703 : {
704 1447 : if (gInitialized) return;
705 1447 : gInitialized = true;
706 :
707 : bool defined;
708 1447 : defined = InitLog("XPCOM_MEM_BLOAT_LOG", "bloat/leaks", &gBloatLog);
709 1447 : if (!defined)
710 1425 : gLogLeaksOnly = InitLog("XPCOM_MEM_LEAK_LOG", "leaks", &gBloatLog);
711 1447 : if (defined || gLogLeaksOnly) {
712 1409 : RecreateBloatView();
713 1409 : if (!gBloatView) {
714 0 : NS_WARNING("out of memory");
715 0 : gBloatLog = nsnull;
716 0 : gLogLeaksOnly = false;
717 : }
718 : }
719 :
720 1447 : (void)InitLog("XPCOM_MEM_REFCNT_LOG", "refcounts", &gRefcntsLog);
721 :
722 1447 : (void)InitLog("XPCOM_MEM_ALLOC_LOG", "new/delete", &gAllocLog);
723 :
724 1447 : defined = InitLog("XPCOM_MEM_LEAKY_LOG", "for leaky", &gLeakyLog);
725 1447 : if (defined) {
726 0 : gLogToLeaky = true;
727 0 : PRFuncPtr p = nsnull, q = nsnull;
728 : #ifdef HAVE_DLOPEN
729 : {
730 0 : PRLibrary *lib = nsnull;
731 0 : p = PR_FindFunctionSymbolAndLibrary("__log_addref", &lib);
732 0 : if (lib) {
733 0 : PR_UnloadLibrary(lib);
734 0 : lib = nsnull;
735 : }
736 0 : q = PR_FindFunctionSymbolAndLibrary("__log_release", &lib);
737 0 : if (lib) {
738 0 : PR_UnloadLibrary(lib);
739 : }
740 : }
741 : #endif
742 0 : if (p && q) {
743 0 : leakyLogAddRef = (void (*)(void*,int,int)) p;
744 0 : leakyLogRelease = (void (*)(void*,int,int)) q;
745 : }
746 : else {
747 0 : gLogToLeaky = false;
748 0 : fprintf(stdout, "### ERROR: XPCOM_MEM_LEAKY_LOG defined, but can't locate __log_addref and __log_release symbols\n");
749 0 : fflush(stdout);
750 : }
751 : }
752 :
753 1447 : const char* classes = getenv("XPCOM_MEM_LOG_CLASSES");
754 :
755 : #ifdef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR
756 1447 : if (classes) {
757 0 : (void)InitLog("XPCOM_MEM_COMPTR_LOG", "nsCOMPtr", &gCOMPtrLog);
758 : } else {
759 1447 : if (getenv("XPCOM_MEM_COMPTR_LOG")) {
760 0 : fprintf(stdout, "### XPCOM_MEM_COMPTR_LOG defined -- but XPCOM_MEM_LOG_CLASSES is not defined\n");
761 : }
762 : }
763 : #else
764 : const char* comptr_log = getenv("XPCOM_MEM_COMPTR_LOG");
765 : if (comptr_log) {
766 : fprintf(stdout, "### XPCOM_MEM_COMPTR_LOG defined -- but it will not work without dynamic_cast\n");
767 : }
768 : #endif
769 :
770 1447 : if (classes) {
771 : // if XPCOM_MEM_LOG_CLASSES was set to some value, the value is interpreted
772 : // as a list of class names to track
773 : gTypesToLog = PL_NewHashTable(256,
774 : PL_HashString,
775 : PL_CompareStrings,
776 : PL_CompareValues,
777 0 : &typesToLogHashAllocOps, NULL);
778 0 : if (!gTypesToLog) {
779 0 : NS_WARNING("out of memory");
780 0 : fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- unable to log specific classes\n");
781 : }
782 : else {
783 0 : fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- only logging these classes: ");
784 0 : const char* cp = classes;
785 0 : for (;;) {
786 0 : char* cm = (char*) strchr(cp, ',');
787 0 : if (cm) {
788 0 : *cm = '\0';
789 : }
790 0 : PL_HashTableAdd(gTypesToLog, nsCRT::strdup(cp), (void*)1);
791 0 : fprintf(stdout, "%s ", cp);
792 0 : if (!cm) break;
793 0 : *cm = ',';
794 0 : cp = cm + 1;
795 : }
796 0 : fprintf(stdout, "\n");
797 : }
798 :
799 : gSerialNumbers = PL_NewHashTable(256,
800 : HashNumber,
801 : PL_CompareValues,
802 : PL_CompareValues,
803 0 : &serialNumberHashAllocOps, NULL);
804 :
805 :
806 : }
807 :
808 1447 : const char* objects = getenv("XPCOM_MEM_LOG_OBJECTS");
809 1447 : if (objects) {
810 : gObjectsToLog = PL_NewHashTable(256,
811 : HashNumber,
812 : PL_CompareValues,
813 : PL_CompareValues,
814 0 : NULL, NULL);
815 :
816 0 : if (!gObjectsToLog) {
817 0 : NS_WARNING("out of memory");
818 0 : fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- unable to log specific objects\n");
819 : }
820 0 : else if (! (gRefcntsLog || gAllocLog || gCOMPtrLog)) {
821 0 : fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- but none of XPCOM_MEM_(REFCNT|ALLOC|COMPTR)_LOG is defined\n");
822 : }
823 : else {
824 0 : fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- only logging these objects: ");
825 0 : const char* cp = objects;
826 0 : for (;;) {
827 0 : char* cm = (char*) strchr(cp, ',');
828 0 : if (cm) {
829 0 : *cm = '\0';
830 : }
831 0 : PRInt32 top = 0;
832 0 : PRInt32 bottom = 0;
833 0 : while (*cp) {
834 0 : if (*cp == '-') {
835 0 : bottom = top;
836 0 : top = 0;
837 0 : ++cp;
838 : }
839 0 : top *= 10;
840 0 : top += *cp - '0';
841 0 : ++cp;
842 : }
843 0 : if (!bottom) {
844 0 : bottom = top;
845 : }
846 0 : for(PRInt32 serialno = bottom; serialno <= top; serialno++) {
847 0 : PL_HashTableAdd(gObjectsToLog, (const void*)serialno, (void*)1);
848 0 : fprintf(stdout, "%d ", serialno);
849 : }
850 0 : if (!cm) break;
851 0 : *cm = ',';
852 0 : cp = cm + 1;
853 : }
854 0 : fprintf(stdout, "\n");
855 : }
856 : }
857 :
858 :
859 1447 : if (gBloatLog || gRefcntsLog || gAllocLog || gLeakyLog || gCOMPtrLog) {
860 1409 : gLogging = true;
861 : }
862 :
863 1447 : gTraceLock = PR_NewLock();
864 : }
865 :
866 : #endif
867 :
868 : extern "C" {
869 :
870 0 : static void PrintStackFrame(void *aPC, void *aClosure)
871 : {
872 0 : FILE *stream = (FILE*)aClosure;
873 : nsCodeAddressDetails details;
874 : char buf[1024];
875 :
876 0 : NS_DescribeCodeAddress(aPC, &details);
877 0 : NS_FormatCodeAddressDetails(aPC, &details, buf, sizeof(buf));
878 0 : fputs(buf, stream);
879 0 : }
880 :
881 : }
882 :
883 : void
884 0 : nsTraceRefcntImpl::WalkTheStack(FILE* aStream)
885 : {
886 0 : NS_StackWalk(PrintStackFrame, 2, aStream, 0);
887 0 : }
888 :
889 : //----------------------------------------------------------------------
890 :
891 : // This thing is exported by libstdc++
892 : // Yes, this is a gcc only hack
893 : #if defined(MOZ_DEMANGLE_SYMBOLS)
894 : #include <cxxabi.h>
895 : #include <stdlib.h> // for free()
896 : #endif // MOZ_DEMANGLE_SYMBOLS
897 :
898 : void
899 0 : nsTraceRefcntImpl::DemangleSymbol(const char * aSymbol,
900 : char * aBuffer,
901 : int aBufLen)
902 : {
903 0 : NS_ASSERTION(nsnull != aSymbol,"null symbol");
904 0 : NS_ASSERTION(nsnull != aBuffer,"null buffer");
905 0 : NS_ASSERTION(aBufLen >= 32 ,"pulled 32 out of you know where");
906 :
907 0 : aBuffer[0] = '\0';
908 :
909 : #if defined(MOZ_DEMANGLE_SYMBOLS)
910 : /* See demangle.h in the gcc source for the voodoo */
911 0 : char * demangled = abi::__cxa_demangle(aSymbol,0,0,0);
912 :
913 0 : if (demangled)
914 : {
915 0 : strncpy(aBuffer,demangled,aBufLen);
916 0 : free(demangled);
917 : }
918 : #endif // MOZ_DEMANGLE_SYMBOLS
919 0 : }
920 :
921 :
922 : //----------------------------------------------------------------------
923 :
924 : EXPORT_XPCOM_API(void)
925 2855 : NS_LogInit()
926 : {
927 : // FIXME: This is called multiple times, we should probably not allow that.
928 2855 : StackWalkInitCriticalAddress();
929 : #ifdef NS_IMPL_REFCNT_LOGGING
930 2855 : if (++gInitCount)
931 2855 : nsTraceRefcntImpl::SetActivityIsLegal(true);
932 : #endif
933 :
934 : #ifdef NS_TRACE_MALLOC
935 : // XXX we don't have to worry about shutting down trace-malloc; it
936 : // handles this itself, through an atexit() callback.
937 : if (!NS_TraceMallocHasStarted())
938 : NS_TraceMallocStartup(-1); // -1 == no logging
939 : #endif
940 2855 : }
941 :
942 : EXPORT_XPCOM_API(void)
943 2853 : NS_LogTerm()
944 : {
945 2853 : mozilla::LogTerm();
946 2853 : }
947 :
948 : namespace mozilla {
949 : void
950 2853 : LogTerm()
951 : {
952 2853 : NS_ASSERTION(gInitCount > 0,
953 : "NS_LogTerm without matching NS_LogInit");
954 :
955 2853 : if (--gInitCount == 0) {
956 : #ifdef DEBUG
957 : /* FIXME bug 491977: This is only going to operate on the
958 : * BlockingResourceBase which is compiled into
959 : * libxul/libxpcom_core.so. Anyone using external linkage will
960 : * have their own copy of BlockingResourceBase statics which will
961 : * not be freed by this method.
962 : *
963 : * It sounds like what we really want is to be able to register a
964 : * callback function to call at XPCOM shutdown. Note that with
965 : * this solution, however, we need to guarantee that
966 : * BlockingResourceBase::Shutdown() runs after all other shutdown
967 : * functions.
968 : */
969 1442 : BlockingResourceBase::Shutdown();
970 : #endif
971 :
972 1442 : if (gInitialized) {
973 1442 : nsTraceRefcntImpl::DumpStatistics();
974 1442 : nsTraceRefcntImpl::ResetStatistics();
975 : }
976 1442 : nsTraceRefcntImpl::Shutdown();
977 : #ifdef NS_IMPL_REFCNT_LOGGING
978 1442 : nsTraceRefcntImpl::SetActivityIsLegal(false);
979 1442 : gActivityTLS = BAD_TLS_INDEX;
980 : #endif
981 : }
982 2853 : }
983 :
984 : } // namespace mozilla
985 :
986 : EXPORT_XPCOM_API(void)
987 89198256 : NS_LogAddRef(void* aPtr, nsrefcnt aRefcnt,
988 : const char* aClazz, PRUint32 classSize)
989 : {
990 : #ifdef NS_IMPL_REFCNT_LOGGING
991 89198256 : ASSERT_ACTIVITY_IS_LEGAL;
992 89194203 : if (!gInitialized)
993 1447 : InitTraceLog();
994 89194230 : if (gLogging) {
995 87206913 : LOCK_TRACELOG();
996 :
997 87212140 : if (gBloatLog) {
998 87212140 : BloatEntry* entry = GetBloatEntry(aClazz, classSize);
999 87212140 : if (entry) {
1000 87212140 : entry->AddRef(aRefcnt);
1001 : }
1002 : }
1003 :
1004 : // Here's the case where MOZ_COUNT_CTOR was not used,
1005 : // yet we still want to see creation information:
1006 :
1007 87212140 : bool loggingThisType = (!gTypesToLog || LogThisType(aClazz));
1008 87212140 : PRInt32 serialno = 0;
1009 87212140 : if (gSerialNumbers && loggingThisType) {
1010 0 : serialno = GetSerialNumber(aPtr, aRefcnt == 1);
1011 0 : NS_ASSERTION(serialno != 0,
1012 : "Serial number requested for unrecognized pointer! "
1013 : "Are you memmoving a refcounted object?");
1014 0 : PRInt32* count = GetRefCount(aPtr);
1015 0 : if(count)
1016 0 : (*count)++;
1017 :
1018 : }
1019 :
1020 87212140 : bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
1021 87212140 : if (aRefcnt == 1 && gAllocLog && loggingThisType && loggingThisObject) {
1022 : fprintf(gAllocLog, "\n<%s> 0x%08X %d Create\n",
1023 0 : aClazz, NS_PTR_TO_INT32(aPtr), serialno);
1024 0 : nsTraceRefcntImpl::WalkTheStack(gAllocLog);
1025 : }
1026 :
1027 87212140 : if (gRefcntsLog && loggingThisType && loggingThisObject) {
1028 0 : if (gLogToLeaky) {
1029 0 : (*leakyLogAddRef)(aPtr, aRefcnt - 1, aRefcnt);
1030 : }
1031 : else {
1032 : // Can't use PR_LOG(), b/c it truncates the line
1033 : fprintf(gRefcntsLog,
1034 0 : "\n<%s> 0x%08X %d AddRef %d\n", aClazz, NS_PTR_TO_INT32(aPtr), serialno, aRefcnt);
1035 0 : nsTraceRefcntImpl::WalkTheStack(gRefcntsLog);
1036 0 : fflush(gRefcntsLog);
1037 : }
1038 : }
1039 87212140 : UNLOCK_TRACELOG();
1040 : }
1041 : #endif
1042 89199417 : }
1043 :
1044 : EXPORT_XPCOM_API(void)
1045 89184812 : NS_LogRelease(void* aPtr, nsrefcnt aRefcnt, const char* aClazz)
1046 : {
1047 : #ifdef NS_IMPL_REFCNT_LOGGING
1048 89184812 : ASSERT_ACTIVITY_IS_LEGAL;
1049 89182084 : if (!gInitialized)
1050 0 : InitTraceLog();
1051 89181852 : if (gLogging) {
1052 87194536 : LOCK_TRACELOG();
1053 :
1054 87198327 : if (gBloatLog) {
1055 87198327 : BloatEntry* entry = GetBloatEntry(aClazz, 0);
1056 87198327 : if (entry) {
1057 87198327 : entry->Release(aRefcnt);
1058 : }
1059 : }
1060 :
1061 87198327 : bool loggingThisType = (!gTypesToLog || LogThisType(aClazz));
1062 87198327 : PRInt32 serialno = 0;
1063 87198327 : if (gSerialNumbers && loggingThisType) {
1064 0 : serialno = GetSerialNumber(aPtr, false);
1065 0 : NS_ASSERTION(serialno != 0,
1066 : "Serial number requested for unrecognized pointer! "
1067 : "Are you memmoving a refcounted object?");
1068 0 : PRInt32* count = GetRefCount(aPtr);
1069 0 : if(count)
1070 0 : (*count)--;
1071 :
1072 : }
1073 :
1074 87198327 : bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
1075 87198327 : if (gRefcntsLog && loggingThisType && loggingThisObject) {
1076 0 : if (gLogToLeaky) {
1077 0 : (*leakyLogRelease)(aPtr, aRefcnt + 1, aRefcnt);
1078 : }
1079 : else {
1080 : // Can't use PR_LOG(), b/c it truncates the line
1081 : fprintf(gRefcntsLog,
1082 0 : "\n<%s> 0x%08X %d Release %d\n", aClazz, NS_PTR_TO_INT32(aPtr), serialno, aRefcnt);
1083 0 : nsTraceRefcntImpl::WalkTheStack(gRefcntsLog);
1084 0 : fflush(gRefcntsLog);
1085 : }
1086 : }
1087 :
1088 : // Here's the case where MOZ_COUNT_DTOR was not used,
1089 : // yet we still want to see deletion information:
1090 :
1091 87198327 : if (aRefcnt == 0 && gAllocLog && loggingThisType && loggingThisObject) {
1092 : fprintf(gAllocLog,
1093 : "\n<%s> 0x%08X %d Destroy\n",
1094 0 : aClazz, NS_PTR_TO_INT32(aPtr), serialno);
1095 0 : nsTraceRefcntImpl::WalkTheStack(gAllocLog);
1096 : }
1097 :
1098 87198327 : if (aRefcnt == 0 && gSerialNumbers && loggingThisType) {
1099 0 : RecycleSerialNumberPtr(aPtr);
1100 : }
1101 :
1102 87198327 : UNLOCK_TRACELOG();
1103 : }
1104 : #endif
1105 89185622 : }
1106 :
1107 : EXPORT_XPCOM_API(void)
1108 16862423 : NS_LogCtor(void* aPtr, const char* aType, PRUint32 aInstanceSize)
1109 : {
1110 : #ifdef NS_IMPL_REFCNT_LOGGING
1111 16862423 : ASSERT_ACTIVITY_IS_LEGAL;
1112 16862391 : if (!gInitialized)
1113 0 : InitTraceLog();
1114 :
1115 16862391 : if (gLogging) {
1116 16672315 : LOCK_TRACELOG();
1117 :
1118 16672354 : if (gBloatLog) {
1119 16672354 : BloatEntry* entry = GetBloatEntry(aType, aInstanceSize);
1120 16672354 : if (entry) {
1121 16672354 : entry->Ctor();
1122 : }
1123 : }
1124 :
1125 16672354 : bool loggingThisType = (!gTypesToLog || LogThisType(aType));
1126 16672354 : PRInt32 serialno = 0;
1127 16672354 : if (gSerialNumbers && loggingThisType) {
1128 0 : serialno = GetSerialNumber(aPtr, true);
1129 : }
1130 :
1131 16672354 : bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
1132 16672354 : if (gAllocLog && loggingThisType && loggingThisObject) {
1133 : fprintf(gAllocLog, "\n<%s> 0x%08X %d Ctor (%d)\n",
1134 0 : aType, NS_PTR_TO_INT32(aPtr), serialno, aInstanceSize);
1135 0 : nsTraceRefcntImpl::WalkTheStack(gAllocLog);
1136 : }
1137 :
1138 16672354 : UNLOCK_TRACELOG();
1139 : }
1140 : #endif
1141 16862430 : }
1142 :
1143 :
1144 : EXPORT_XPCOM_API(void)
1145 16858240 : NS_LogDtor(void* aPtr, const char* aType, PRUint32 aInstanceSize)
1146 : {
1147 : #ifdef NS_IMPL_REFCNT_LOGGING
1148 16858240 : ASSERT_ACTIVITY_IS_LEGAL;
1149 16858231 : if (!gInitialized)
1150 0 : InitTraceLog();
1151 :
1152 16858230 : if (gLogging) {
1153 16669578 : LOCK_TRACELOG();
1154 :
1155 16669593 : if (gBloatLog) {
1156 16669593 : BloatEntry* entry = GetBloatEntry(aType, aInstanceSize);
1157 16669593 : if (entry) {
1158 16669593 : entry->Dtor();
1159 : }
1160 : }
1161 :
1162 16669593 : bool loggingThisType = (!gTypesToLog || LogThisType(aType));
1163 16669593 : PRInt32 serialno = 0;
1164 16669593 : if (gSerialNumbers && loggingThisType) {
1165 0 : serialno = GetSerialNumber(aPtr, false);
1166 0 : RecycleSerialNumberPtr(aPtr);
1167 : }
1168 :
1169 16669593 : bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
1170 :
1171 : // (If we're on a losing architecture, don't do this because we'll be
1172 : // using LogDeleteXPCOM instead to get file and line numbers.)
1173 16669593 : if (gAllocLog && loggingThisType && loggingThisObject) {
1174 : fprintf(gAllocLog, "\n<%s> 0x%08X %d Dtor (%d)\n",
1175 0 : aType, NS_PTR_TO_INT32(aPtr), serialno, aInstanceSize);
1176 0 : nsTraceRefcntImpl::WalkTheStack(gAllocLog);
1177 : }
1178 :
1179 16669593 : UNLOCK_TRACELOG();
1180 : }
1181 : #endif
1182 16858245 : }
1183 :
1184 :
1185 : EXPORT_XPCOM_API(void)
1186 51565447 : NS_LogCOMPtrAddRef(void* aCOMPtr, nsISupports* aObject)
1187 : {
1188 : #if defined(NS_IMPL_REFCNT_LOGGING) && defined(HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR)
1189 : // Get the most-derived object.
1190 51565447 : void *object = dynamic_cast<void *>(aObject);
1191 :
1192 : // This is a very indirect way of finding out what the class is
1193 : // of the object being logged. If we're logging a specific type,
1194 : // then
1195 51565447 : if (!gTypesToLog || !gSerialNumbers) {
1196 51565447 : return;
1197 : }
1198 0 : PRInt32 serialno = GetSerialNumber(object, false);
1199 0 : if (serialno == 0) {
1200 0 : return;
1201 : }
1202 :
1203 0 : if (!gInitialized)
1204 0 : InitTraceLog();
1205 0 : if (gLogging) {
1206 0 : LOCK_TRACELOG();
1207 :
1208 0 : PRInt32* count = GetCOMPtrCount(object);
1209 0 : if(count)
1210 0 : (*count)++;
1211 :
1212 0 : bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
1213 :
1214 0 : if (gCOMPtrLog && loggingThisObject) {
1215 : fprintf(gCOMPtrLog, "\n<?> 0x%08X %d nsCOMPtrAddRef %d 0x%08X\n",
1216 0 : NS_PTR_TO_INT32(object), serialno, count?(*count):-1, NS_PTR_TO_INT32(aCOMPtr));
1217 0 : nsTraceRefcntImpl::WalkTheStack(gCOMPtrLog);
1218 : }
1219 :
1220 0 : UNLOCK_TRACELOG();
1221 : }
1222 : #endif
1223 : }
1224 :
1225 :
1226 : EXPORT_XPCOM_API(void)
1227 51348440 : NS_LogCOMPtrRelease(void* aCOMPtr, nsISupports* aObject)
1228 : {
1229 : #if defined(NS_IMPL_REFCNT_LOGGING) && defined(HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR)
1230 : // Get the most-derived object.
1231 51348440 : void *object = dynamic_cast<void *>(aObject);
1232 :
1233 : // This is a very indirect way of finding out what the class is
1234 : // of the object being logged. If we're logging a specific type,
1235 : // then
1236 51348440 : if (!gTypesToLog || !gSerialNumbers) {
1237 51348440 : return;
1238 : }
1239 0 : PRInt32 serialno = GetSerialNumber(object, false);
1240 0 : if (serialno == 0) {
1241 0 : return;
1242 : }
1243 :
1244 0 : if (!gInitialized)
1245 0 : InitTraceLog();
1246 0 : if (gLogging) {
1247 0 : LOCK_TRACELOG();
1248 :
1249 0 : PRInt32* count = GetCOMPtrCount(object);
1250 0 : if(count)
1251 0 : (*count)--;
1252 :
1253 0 : bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
1254 :
1255 0 : if (gCOMPtrLog && loggingThisObject) {
1256 : fprintf(gCOMPtrLog, "\n<?> 0x%08X %d nsCOMPtrRelease %d 0x%08X\n",
1257 0 : NS_PTR_TO_INT32(object), serialno, count?(*count):-1, NS_PTR_TO_INT32(aCOMPtr));
1258 0 : nsTraceRefcntImpl::WalkTheStack(gCOMPtrLog);
1259 : }
1260 :
1261 0 : UNLOCK_TRACELOG();
1262 : }
1263 : #endif
1264 : }
1265 :
1266 : void
1267 0 : nsTraceRefcntImpl::Startup()
1268 : {
1269 0 : }
1270 :
1271 : void
1272 1442 : nsTraceRefcntImpl::Shutdown()
1273 : {
1274 : #ifdef NS_IMPL_REFCNT_LOGGING
1275 :
1276 1442 : if (gBloatView) {
1277 0 : PL_HashTableDestroy(gBloatView);
1278 0 : gBloatView = nsnull;
1279 : }
1280 1442 : if (gTypesToLog) {
1281 0 : PL_HashTableDestroy(gTypesToLog);
1282 0 : gTypesToLog = nsnull;
1283 : }
1284 1442 : if (gObjectsToLog) {
1285 0 : PL_HashTableDestroy(gObjectsToLog);
1286 0 : gObjectsToLog = nsnull;
1287 : }
1288 1442 : if (gSerialNumbers) {
1289 0 : PL_HashTableDestroy(gSerialNumbers);
1290 0 : gSerialNumbers = nsnull;
1291 : }
1292 1442 : if (gBloatLog) {
1293 1408 : fclose(gBloatLog);
1294 1408 : gBloatLog = nsnull;
1295 : }
1296 1442 : if (gRefcntsLog) {
1297 0 : fclose(gRefcntsLog);
1298 0 : gRefcntsLog = nsnull;
1299 : }
1300 1442 : if (gAllocLog) {
1301 0 : fclose(gAllocLog);
1302 0 : gAllocLog = nsnull;
1303 : }
1304 1442 : if (gLeakyLog) {
1305 0 : fclose(gLeakyLog);
1306 0 : gLeakyLog = nsnull;
1307 : }
1308 1442 : if (gCOMPtrLog) {
1309 0 : fclose(gCOMPtrLog);
1310 0 : gCOMPtrLog = nsnull;
1311 : }
1312 : #endif
1313 1442 : }
1314 :
1315 : void
1316 27015 : nsTraceRefcntImpl::SetActivityIsLegal(bool aLegal)
1317 : {
1318 : #ifdef NS_IMPL_REFCNT_LOGGING
1319 27015 : if (gActivityTLS == BAD_TLS_INDEX)
1320 1443 : PR_NewThreadPrivateIndex(&gActivityTLS, nsnull);
1321 :
1322 27015 : PR_SetThreadPrivate(gActivityTLS, NS_INT32_TO_PTR(!aLegal));
1323 : #endif
1324 27015 : }
1325 :
1326 0 : NS_IMPL_QUERY_INTERFACE1(nsTraceRefcntImpl, nsITraceRefcnt)
1327 :
1328 0 : NS_IMETHODIMP_(nsrefcnt) nsTraceRefcntImpl::AddRef(void)
1329 : {
1330 0 : return 2;
1331 : }
1332 :
1333 0 : NS_IMETHODIMP_(nsrefcnt) nsTraceRefcntImpl::Release(void)
1334 : {
1335 0 : return 1;
1336 : }
1337 :
1338 : NS_IMETHODIMP
1339 0 : nsTraceRefcntImpl::LogAddRef(void *aPtr, nsrefcnt aNewRefcnt,
1340 : const char *aTypeName, PRUint32 aSize)
1341 : {
1342 0 : NS_LogAddRef(aPtr, aNewRefcnt, aTypeName, aSize);
1343 0 : return NS_OK;
1344 : }
1345 :
1346 : NS_IMETHODIMP
1347 0 : nsTraceRefcntImpl::LogRelease(void *aPtr, nsrefcnt aNewRefcnt,
1348 : const char *aTypeName)
1349 : {
1350 0 : NS_LogRelease(aPtr, aNewRefcnt, aTypeName);
1351 0 : return NS_OK;
1352 : }
1353 :
1354 : NS_IMETHODIMP
1355 0 : nsTraceRefcntImpl::LogCtor(void *aPtr, const char *aTypeName, PRUint32 aSize)
1356 : {
1357 0 : NS_LogCtor(aPtr, aTypeName, aSize);
1358 0 : return NS_OK;
1359 : }
1360 :
1361 : NS_IMETHODIMP
1362 0 : nsTraceRefcntImpl::LogDtor(void *aPtr, const char *aTypeName, PRUint32 aSize)
1363 : {
1364 0 : NS_LogDtor(aPtr, aTypeName, aSize);
1365 0 : return NS_OK;
1366 : }
1367 :
1368 : NS_IMETHODIMP
1369 0 : nsTraceRefcntImpl::LogAddCOMPtr(void *aCOMPtr, nsISupports* aObject)
1370 : {
1371 0 : NS_LogCOMPtrAddRef(aCOMPtr, aObject);
1372 0 : return NS_OK;
1373 : }
1374 :
1375 : NS_IMETHODIMP
1376 0 : nsTraceRefcntImpl::LogReleaseCOMPtr(void *aCOMPtr, nsISupports* aObject)
1377 : {
1378 0 : NS_LogCOMPtrRelease(aCOMPtr, aObject);
1379 0 : return NS_OK;
1380 : }
1381 :
1382 1464 : static const nsTraceRefcntImpl kTraceRefcntImpl;
1383 :
1384 : NS_METHOD
1385 0 : nsTraceRefcntImpl::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr)
1386 : {
1387 : return const_cast<nsTraceRefcntImpl*>(&kTraceRefcntImpl)->
1388 0 : QueryInterface(aIID, aInstancePtr);
1389 4392 : }
|