VirtualBox

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

Last change on this file since 102214 was 102175, checked in by vboxsync, 17 months ago

libs/xpcom: Replace PL_strdup/PL_strndup/PL_strfree with IPRT equivalents, bugref:10545

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

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