VirtualBox

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

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

libs/xpcom/xpcom: Convert some code from using PRLock to IPRT's RTSEMFASTMUTEX locks, bugref:10545

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

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