зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1442765 - Part 2: Switch nsTraceRefcnt's hashtables to use xpcom hashtables. r=mccr8
--HG-- extra : rebase_source : 5fecdd86a3ef27d211cb43d4c602162db7554f2f
This commit is contained in:
Родитель
e63e92aa34
Коммит
cf21a1de96
|
@ -11,7 +11,9 @@
|
||||||
#include "mozilla/StaticPtr.h"
|
#include "mozilla/StaticPtr.h"
|
||||||
#include "nsXPCOMPrivate.h"
|
#include "nsXPCOMPrivate.h"
|
||||||
#include "nscore.h"
|
#include "nscore.h"
|
||||||
|
#include "nsClassHashtable.h"
|
||||||
#include "nsISupports.h"
|
#include "nsISupports.h"
|
||||||
|
#include "nsHashKeys.h"
|
||||||
#include "nsTArray.h"
|
#include "nsTArray.h"
|
||||||
#include "nsTHashtable.h"
|
#include "nsTHashtable.h"
|
||||||
#include "prenv.h"
|
#include "prenv.h"
|
||||||
|
@ -52,8 +54,6 @@
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include "plhash.h"
|
|
||||||
|
|
||||||
#include "prthread.h"
|
#include "prthread.h"
|
||||||
|
|
||||||
// We use a spin lock instead of a regular mutex because this lock is usually
|
// We use a spin lock instead of a regular mutex because this lock is usually
|
||||||
|
@ -80,10 +80,19 @@ struct MOZ_STACK_CLASS AutoTraceLogLock final
|
||||||
~AutoTraceLogLock() { if (doRelease) gTraceLogLocked = 0; }
|
~AutoTraceLogLock() { if (doRelease) gTraceLogLocked = 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
static PLHashTable* gBloatView;
|
class BloatEntry;
|
||||||
static PLHashTable* gTypesToLog;
|
struct SerialNumberRecord;
|
||||||
static PLHashTable* gObjectsToLog;
|
|
||||||
static PLHashTable* gSerialNumbers;
|
using BloatHash = nsClassHashtable<nsDepCharHashKey, BloatEntry>;
|
||||||
|
using CharPtrSet = nsTHashtable<nsCharPtrHashKey>;
|
||||||
|
using IntPtrSet = nsTHashtable<IntPtrHashKey>;
|
||||||
|
using SerialHash = nsClassHashtable<nsVoidPtrHashKey, SerialNumberRecord>;
|
||||||
|
|
||||||
|
static StaticAutoPtr<BloatHash> gBloatView;
|
||||||
|
static StaticAutoPtr<CharPtrSet> gTypesToLog;
|
||||||
|
static StaticAutoPtr<IntPtrSet> gObjectsToLog;
|
||||||
|
static StaticAutoPtr<SerialHash> gSerialNumbers;
|
||||||
|
|
||||||
static intptr_t gNextSerialNumber;
|
static intptr_t gNextSerialNumber;
|
||||||
static bool gDumpedStatistics = false;
|
static bool gDumpedStatistics = false;
|
||||||
static bool gLogJSStacks = false;
|
static bool gLogJSStacks = false;
|
||||||
|
@ -205,56 +214,6 @@ AssertActivityIsLegal()
|
||||||
# define ASSERT_ACTIVITY_IS_LEGAL do { } while(0)
|
# define ASSERT_ACTIVITY_IS_LEGAL do { } while(0)
|
||||||
#endif // DEBUG
|
#endif // DEBUG
|
||||||
|
|
||||||
// These functions are copied from nsprpub/lib/ds/plhash.c, with changes
|
|
||||||
// to the functions not called Default* to free the SerialNumberRecord or
|
|
||||||
// the BloatEntry.
|
|
||||||
|
|
||||||
static void*
|
|
||||||
DefaultAllocTable(void* aPool, size_t aSize)
|
|
||||||
{
|
|
||||||
return malloc(aSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
DefaultFreeTable(void* aPool, void* aItem)
|
|
||||||
{
|
|
||||||
free(aItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
static PLHashEntry*
|
|
||||||
DefaultAllocEntry(void* aPool, const void* aKey)
|
|
||||||
{
|
|
||||||
return (PLHashEntry*) malloc(sizeof(PLHashEntry));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
SerialNumberFreeEntry(void* aPool, PLHashEntry* aHashEntry, unsigned aFlag)
|
|
||||||
{
|
|
||||||
if (aFlag == HT_FREE_ENTRY) {
|
|
||||||
delete static_cast<SerialNumberRecord*>(aHashEntry->value);
|
|
||||||
free(aHashEntry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
TypesToLogFreeEntry(void* aPool, PLHashEntry* aHashEntry, unsigned aFlag)
|
|
||||||
{
|
|
||||||
if (aFlag == HT_FREE_ENTRY) {
|
|
||||||
free(const_cast<char*>(static_cast<const char*>(aHashEntry->key)));
|
|
||||||
free(aHashEntry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const PLHashAllocOps serialNumberHashAllocOps = {
|
|
||||||
DefaultAllocTable, DefaultFreeTable,
|
|
||||||
DefaultAllocEntry, SerialNumberFreeEntry
|
|
||||||
};
|
|
||||||
|
|
||||||
static const PLHashAllocOps typesToLogHashAllocOps = {
|
|
||||||
DefaultAllocTable, DefaultFreeTable,
|
|
||||||
DefaultAllocEntry, TypesToLogFreeEntry
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
class CodeAddressServiceStringTable final
|
class CodeAddressServiceStringTable final
|
||||||
|
@ -338,24 +297,6 @@ public:
|
||||||
mStats.mDestroys++;
|
mStats.mDestroys++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int DumpEntry(PLHashEntry* aHashEntry, int aIndex, void* aArg)
|
|
||||||
{
|
|
||||||
BloatEntry* entry = (BloatEntry*)aHashEntry->value;
|
|
||||||
if (entry) {
|
|
||||||
static_cast<nsTArray<BloatEntry*>*>(aArg)->AppendElement(entry);
|
|
||||||
}
|
|
||||||
return HT_ENUMERATE_NEXT;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int TotalEntries(PLHashEntry* aHashEntry, int aIndex, void* aArg)
|
|
||||||
{
|
|
||||||
BloatEntry* entry = (BloatEntry*)aHashEntry->value;
|
|
||||||
if (entry && nsCRT::strcmp(entry->mClassName, "TOTAL") != 0) {
|
|
||||||
entry->Total((BloatEntry*)aArg);
|
|
||||||
}
|
|
||||||
return HT_ENUMERATE_NEXT;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Total(BloatEntry* aTotal)
|
void Total(BloatEntry* aTotal)
|
||||||
{
|
{
|
||||||
aTotal->mStats.mCreates += mStats.mCreates;
|
aTotal->mStats.mCreates += mStats.mCreates;
|
||||||
|
@ -411,29 +352,10 @@ protected:
|
||||||
nsTraceRefcntStats mStats;
|
nsTraceRefcntStats mStats;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
|
||||||
BloatViewFreeEntry(void* aPool, PLHashEntry* aHashEntry, unsigned aFlag)
|
|
||||||
{
|
|
||||||
if (aFlag == HT_FREE_ENTRY) {
|
|
||||||
BloatEntry* entry = static_cast<BloatEntry*>(aHashEntry->value);
|
|
||||||
delete entry;
|
|
||||||
free(aHashEntry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const static PLHashAllocOps bloatViewHashAllocOps = {
|
|
||||||
DefaultAllocTable, DefaultFreeTable,
|
|
||||||
DefaultAllocEntry, BloatViewFreeEntry
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
RecreateBloatView()
|
RecreateBloatView()
|
||||||
{
|
{
|
||||||
gBloatView = PL_NewHashTable(256,
|
gBloatView = new BloatHash(256);
|
||||||
PL_HashString,
|
|
||||||
PL_CompareStrings,
|
|
||||||
PL_CompareValues,
|
|
||||||
&bloatViewHashAllocOps, nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static BloatEntry*
|
static BloatEntry*
|
||||||
|
@ -442,48 +364,39 @@ GetBloatEntry(const char* aTypeName, uint32_t aInstanceSize)
|
||||||
if (!gBloatView) {
|
if (!gBloatView) {
|
||||||
RecreateBloatView();
|
RecreateBloatView();
|
||||||
}
|
}
|
||||||
BloatEntry* entry = nullptr;
|
BloatEntry* entry = gBloatView->Get(aTypeName);
|
||||||
if (gBloatView) {
|
if (!entry && aInstanceSize > 0) {
|
||||||
entry = (BloatEntry*)PL_HashTableLookup(gBloatView, aTypeName);
|
entry = new BloatEntry(aTypeName, aInstanceSize);
|
||||||
if (!entry && aInstanceSize > 0) {
|
gBloatView->Put(aTypeName, entry);
|
||||||
|
} else {
|
||||||
entry = new BloatEntry(aTypeName, aInstanceSize);
|
MOZ_ASSERT(aInstanceSize == 0 || entry->GetClassSize() == aInstanceSize,
|
||||||
PLHashEntry* e = PL_HashTableAdd(gBloatView, aTypeName, entry);
|
"Mismatched sizes were recorded in the memory leak logging table. "
|
||||||
if (!e) {
|
"The usual cause of this is having a templated class that uses "
|
||||||
delete entry;
|
"MOZ_COUNT_{C,D}TOR in the constructor or destructor, respectively. "
|
||||||
entry = nullptr;
|
"As a workaround, the MOZ_COUNT_{C,D}TOR calls can be moved to a "
|
||||||
}
|
"non-templated base class. Another possible cause is a runnable with "
|
||||||
} else {
|
"an mName that matches another refcounted class.");
|
||||||
MOZ_ASSERT(aInstanceSize == 0 || entry->GetClassSize() == aInstanceSize,
|
|
||||||
"Mismatched sizes were recorded in the memory leak logging table. "
|
|
||||||
"The usual cause of this is having a templated class that uses "
|
|
||||||
"MOZ_COUNT_{C,D}TOR in the constructor or destructor, respectively. "
|
|
||||||
"As a workaround, the MOZ_COUNT_{C,D}TOR calls can be moved to a "
|
|
||||||
"non-templated base class. Another possible cause is a runnable with "
|
|
||||||
"an mName that matches another refcounted class.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static void
|
||||||
DumpSerialNumbers(PLHashEntry* aHashEntry, int aIndex, void* aClosure)
|
DumpSerialNumbers(const SerialHash::Iterator& aHashEntry, FILE* aFd)
|
||||||
{
|
{
|
||||||
SerialNumberRecord* record =
|
SerialNumberRecord* record = aHashEntry.Data();
|
||||||
static_cast<SerialNumberRecord*>(aHashEntry->value);
|
auto* outputFile = aFd;
|
||||||
auto* outputFile = static_cast<FILE*>(aClosure);
|
|
||||||
#ifdef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR
|
#ifdef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR
|
||||||
fprintf(outputFile, "%" PRIdPTR
|
fprintf(outputFile, "%" PRIdPTR
|
||||||
" @%p (%d references; %d from COMPtrs)\n",
|
" @%p (%d references; %d from COMPtrs)\n",
|
||||||
record->serialNumber,
|
record->serialNumber,
|
||||||
aHashEntry->key,
|
aHashEntry.Key(),
|
||||||
record->refCount,
|
record->refCount,
|
||||||
record->COMPtrCount);
|
record->COMPtrCount);
|
||||||
#else
|
#else
|
||||||
fprintf(outputFile, "%" PRIdPTR
|
fprintf(outputFile, "%" PRIdPTR
|
||||||
" @%p (%d references)\n",
|
" @%p (%d references)\n",
|
||||||
record->serialNumber,
|
record->serialNumber,
|
||||||
aHashEntry->key,
|
aHashEntry.Key(),
|
||||||
record->refCount);
|
record->refCount);
|
||||||
#endif
|
#endif
|
||||||
if (!record->allocationStack.empty()) {
|
if (!record->allocationStack.empty()) {
|
||||||
|
@ -506,8 +419,6 @@ DumpSerialNumbers(PLHashEntry* aHashEntry, int aIndex, void* aClosure)
|
||||||
fprintf(outputFile, "There is no JS context on the stack.\n");
|
fprintf(outputFile, "There is no JS context on the stack.\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return HT_ENUMERATE_NEXT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -545,7 +456,13 @@ nsTraceRefcnt::DumpStatistics()
|
||||||
gLogging = NoLogging;
|
gLogging = NoLogging;
|
||||||
|
|
||||||
BloatEntry total("TOTAL", 0);
|
BloatEntry total("TOTAL", 0);
|
||||||
PL_HashTableEnumerateEntries(gBloatView, BloatEntry::TotalEntries, &total);
|
for (auto iter = gBloatView->Iter(); !iter.Done(); iter.Next()) {
|
||||||
|
BloatEntry* entry = iter.Data();
|
||||||
|
if (nsCRT::strcmp(entry->GetClassName(), "TOTAL") != 0) {
|
||||||
|
entry->Total(&total);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const char* msg;
|
const char* msg;
|
||||||
if (gLogLeaksOnly) {
|
if (gLogLeaksOnly) {
|
||||||
msg = "ALL (cumulative) LEAK STATISTICS";
|
msg = "ALL (cumulative) LEAK STATISTICS";
|
||||||
|
@ -555,7 +472,10 @@ nsTraceRefcnt::DumpStatistics()
|
||||||
const bool leaked = total.PrintDumpHeader(gBloatLog, msg);
|
const bool leaked = total.PrintDumpHeader(gBloatLog, msg);
|
||||||
|
|
||||||
nsTArray<BloatEntry*> entries;
|
nsTArray<BloatEntry*> entries;
|
||||||
PL_HashTableEnumerateEntries(gBloatView, BloatEntry::DumpEntry, &entries);
|
for (auto iter = gBloatView->Iter(); !iter.Done(); iter.Next()) {
|
||||||
|
entries.AppendElement(iter.Data());
|
||||||
|
}
|
||||||
|
|
||||||
const uint32_t count = entries.Length();
|
const uint32_t count = entries.Length();
|
||||||
|
|
||||||
if (!gLogLeaksOnly || leaked) {
|
if (!gLogLeaksOnly || leaked) {
|
||||||
|
@ -574,7 +494,9 @@ nsTraceRefcnt::DumpStatistics()
|
||||||
|
|
||||||
if (gSerialNumbers) {
|
if (gSerialNumbers) {
|
||||||
fprintf(gBloatLog, "\nSerial Numbers of Leaked Objects:\n");
|
fprintf(gBloatLog, "\nSerial Numbers of Leaked Objects:\n");
|
||||||
PL_HashTableEnumerateEntries(gSerialNumbers, DumpSerialNumbers, gBloatLog);
|
for (auto iter = gSerialNumbers->Iter(); !iter.Done(); iter.Next()) {
|
||||||
|
DumpSerialNumbers(iter, gBloatLog);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -584,87 +506,40 @@ void
|
||||||
nsTraceRefcnt::ResetStatistics()
|
nsTraceRefcnt::ResetStatistics()
|
||||||
{
|
{
|
||||||
AutoTraceLogLock lock;
|
AutoTraceLogLock lock;
|
||||||
if (gBloatView) {
|
gBloatView = nullptr;
|
||||||
PL_HashTableDestroy(gBloatView);
|
|
||||||
gBloatView = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
LogThisType(const char* aTypeName)
|
|
||||||
{
|
|
||||||
void* he = PL_HashTableLookup(gTypesToLog, aTypeName);
|
|
||||||
return he != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PLHashNumber
|
|
||||||
HashNumber(const void* aKey)
|
|
||||||
{
|
|
||||||
return PLHashNumber(NS_PTR_TO_INT32(aKey));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static intptr_t
|
static intptr_t
|
||||||
GetSerialNumber(void* aPtr, bool aCreate)
|
GetSerialNumber(void* aPtr, bool aCreate)
|
||||||
{
|
{
|
||||||
PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers,
|
|
||||||
HashNumber(aPtr),
|
|
||||||
aPtr);
|
|
||||||
if (hep && *hep) {
|
|
||||||
MOZ_RELEASE_ASSERT(!aCreate, "If an object already has a serial number, we should be destroying it.");
|
|
||||||
return static_cast<SerialNumberRecord*>((*hep)->value)->serialNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!aCreate) {
|
if (!aCreate) {
|
||||||
return 0;
|
auto record = gSerialNumbers->Get(aPtr);
|
||||||
|
return record ? record->serialNumber : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SerialNumberRecord* record = new SerialNumberRecord();
|
auto entry = gSerialNumbers->LookupForAdd(aPtr);
|
||||||
|
if (entry) {
|
||||||
|
MOZ_CRASH("If an object already has a serial number, we should be destroying it.");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto record = entry.OrInsert([]() { return new SerialNumberRecord(); });
|
||||||
WalkTheStackSavingLocations(record->allocationStack);
|
WalkTheStackSavingLocations(record->allocationStack);
|
||||||
PL_HashTableRawAdd(gSerialNumbers, hep, HashNumber(aPtr),
|
|
||||||
aPtr, static_cast<void*>(record));
|
|
||||||
if (gLogJSStacks) {
|
if (gLogJSStacks) {
|
||||||
record->SaveJSStack();
|
record->SaveJSStack();
|
||||||
}
|
}
|
||||||
return gNextSerialNumber;
|
return gNextSerialNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t*
|
|
||||||
GetRefCount(void* aPtr)
|
|
||||||
{
|
|
||||||
PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers,
|
|
||||||
HashNumber(aPtr),
|
|
||||||
aPtr);
|
|
||||||
if (hep && *hep) {
|
|
||||||
return &(static_cast<SerialNumberRecord*>((*hep)->value)->refCount);
|
|
||||||
} else {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR
|
|
||||||
static int32_t*
|
|
||||||
GetCOMPtrCount(void* aPtr)
|
|
||||||
{
|
|
||||||
PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers,
|
|
||||||
HashNumber(aPtr),
|
|
||||||
aPtr);
|
|
||||||
if (hep && *hep) {
|
|
||||||
return &(static_cast<SerialNumberRecord*>((*hep)->value)->COMPtrCount);
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
#endif // HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
RecycleSerialNumberPtr(void* aPtr)
|
RecycleSerialNumberPtr(void* aPtr)
|
||||||
{
|
{
|
||||||
PL_HashTableRemove(gSerialNumbers, aPtr);
|
gSerialNumbers->Remove(aPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
LogThisObj(intptr_t aSerialNumber)
|
LogThisObj(intptr_t aSerialNumber)
|
||||||
{
|
{
|
||||||
return (bool)PL_HashTableLookup(gObjectsToLog, (const void*)aSerialNumber);
|
return gObjectsToLog->Contains(aSerialNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
using EnvCharType = mozilla::filesystem::Path::value_type;
|
using EnvCharType = mozilla::filesystem::Path::value_type;
|
||||||
|
@ -802,54 +677,33 @@ InitTraceLog()
|
||||||
if (classes) {
|
if (classes) {
|
||||||
// if XPCOM_MEM_LOG_CLASSES was set to some value, the value is interpreted
|
// if XPCOM_MEM_LOG_CLASSES was set to some value, the value is interpreted
|
||||||
// as a list of class names to track
|
// as a list of class names to track
|
||||||
gTypesToLog = PL_NewHashTable(256,
|
gTypesToLog = new CharPtrSet(256);
|
||||||
PL_HashString,
|
|
||||||
PL_CompareStrings,
|
fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- only logging these classes: ");
|
||||||
PL_CompareValues,
|
const char* cp = classes;
|
||||||
&typesToLogHashAllocOps, nullptr);
|
for (;;) {
|
||||||
if (!gTypesToLog) {
|
char* cm = (char*)strchr(cp, ',');
|
||||||
NS_WARNING("out of memory");
|
if (cm) {
|
||||||
fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- unable to log specific classes\n");
|
*cm = '\0';
|
||||||
} else {
|
|
||||||
fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- only logging these classes: ");
|
|
||||||
const char* cp = classes;
|
|
||||||
for (;;) {
|
|
||||||
char* cm = (char*)strchr(cp, ',');
|
|
||||||
if (cm) {
|
|
||||||
*cm = '\0';
|
|
||||||
}
|
|
||||||
PL_HashTableAdd(gTypesToLog, strdup(cp), (void*)1);
|
|
||||||
fprintf(stdout, "%s ", cp);
|
|
||||||
if (!cm) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
*cm = ',';
|
|
||||||
cp = cm + 1;
|
|
||||||
}
|
}
|
||||||
fprintf(stdout, "\n");
|
gTypesToLog->PutEntry(cp);
|
||||||
|
fprintf(stdout, "%s ", cp);
|
||||||
|
if (!cm) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*cm = ',';
|
||||||
|
cp = cm + 1;
|
||||||
}
|
}
|
||||||
|
fprintf(stdout, "\n");
|
||||||
|
|
||||||
gSerialNumbers = PL_NewHashTable(256,
|
gSerialNumbers = new SerialHash(256);
|
||||||
HashNumber,
|
|
||||||
PL_CompareValues,
|
|
||||||
PL_CompareValues,
|
|
||||||
&serialNumberHashAllocOps, nullptr);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* objects = getenv("XPCOM_MEM_LOG_OBJECTS");
|
const char* objects = getenv("XPCOM_MEM_LOG_OBJECTS");
|
||||||
if (objects) {
|
if (objects) {
|
||||||
gObjectsToLog = PL_NewHashTable(256,
|
gObjectsToLog = new IntPtrSet(256);
|
||||||
HashNumber,
|
|
||||||
PL_CompareValues,
|
|
||||||
PL_CompareValues,
|
|
||||||
nullptr, nullptr);
|
|
||||||
|
|
||||||
if (!gObjectsToLog) {
|
if (!(gRefcntsLog || gAllocLog || gCOMPtrLog)) {
|
||||||
NS_WARNING("out of memory");
|
|
||||||
fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- unable to log specific objects\n");
|
|
||||||
} else if (!(gRefcntsLog || gAllocLog || gCOMPtrLog)) {
|
|
||||||
fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- but none of XPCOM_MEM_(REFCNT|ALLOC|COMPTR)_LOG is defined\n");
|
fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- but none of XPCOM_MEM_(REFCNT|ALLOC|COMPTR)_LOG is defined\n");
|
||||||
} else {
|
} else {
|
||||||
fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- only logging these objects: ");
|
fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- only logging these objects: ");
|
||||||
|
@ -875,7 +729,7 @@ InitTraceLog()
|
||||||
bottom = top;
|
bottom = top;
|
||||||
}
|
}
|
||||||
for (intptr_t serialno = bottom; serialno <= top; serialno++) {
|
for (intptr_t serialno = bottom; serialno <= top; serialno++) {
|
||||||
PL_HashTableAdd(gObjectsToLog, (const void*)serialno, (void*)1);
|
gObjectsToLog->PutEntry(serialno);
|
||||||
fprintf(stdout, "%" PRIdPTR " ", serialno);
|
fprintf(stdout, "%" PRIdPTR " ", serialno);
|
||||||
}
|
}
|
||||||
if (!cm) {
|
if (!cm) {
|
||||||
|
@ -1093,18 +947,17 @@ NS_LogAddRef(void* aPtr, nsrefcnt aRefcnt,
|
||||||
// Here's the case where MOZ_COUNT_CTOR was not used,
|
// Here's the case where MOZ_COUNT_CTOR was not used,
|
||||||
// yet we still want to see creation information:
|
// yet we still want to see creation information:
|
||||||
|
|
||||||
bool loggingThisType = (!gTypesToLog || LogThisType(aClass));
|
bool loggingThisType = (!gTypesToLog || gTypesToLog->Contains(aClass));
|
||||||
intptr_t serialno = 0;
|
intptr_t serialno = 0;
|
||||||
if (gSerialNumbers && loggingThisType) {
|
if (gSerialNumbers && loggingThisType) {
|
||||||
serialno = GetSerialNumber(aPtr, aRefcnt == 1);
|
serialno = GetSerialNumber(aPtr, aRefcnt == 1);
|
||||||
MOZ_ASSERT(serialno != 0,
|
MOZ_ASSERT(serialno != 0,
|
||||||
"Serial number requested for unrecognized pointer! "
|
"Serial number requested for unrecognized pointer! "
|
||||||
"Are you memmoving a refcounted object?");
|
"Are you memmoving a refcounted object?");
|
||||||
int32_t* count = GetRefCount(aPtr);
|
auto record = gSerialNumbers->Get(aPtr);
|
||||||
if (count) {
|
if (record) {
|
||||||
(*count)++;
|
++record->refCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
|
bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
|
||||||
|
@ -1143,18 +996,17 @@ NS_LogRelease(void* aPtr, nsrefcnt aRefcnt, const char* aClass)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool loggingThisType = (!gTypesToLog || LogThisType(aClass));
|
bool loggingThisType = (!gTypesToLog || gTypesToLog->Contains(aClass));
|
||||||
intptr_t serialno = 0;
|
intptr_t serialno = 0;
|
||||||
if (gSerialNumbers && loggingThisType) {
|
if (gSerialNumbers && loggingThisType) {
|
||||||
serialno = GetSerialNumber(aPtr, false);
|
serialno = GetSerialNumber(aPtr, false);
|
||||||
MOZ_ASSERT(serialno != 0,
|
MOZ_ASSERT(serialno != 0,
|
||||||
"Serial number requested for unrecognized pointer! "
|
"Serial number requested for unrecognized pointer! "
|
||||||
"Are you memmoving a refcounted object?");
|
"Are you memmoving a refcounted object?");
|
||||||
int32_t* count = GetRefCount(aPtr);
|
auto record = gSerialNumbers->Get(aPtr);
|
||||||
if (count) {
|
if (record) {
|
||||||
(*count)--;
|
--record->refCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
|
bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
|
||||||
|
@ -1202,7 +1054,7 @@ NS_LogCtor(void* aPtr, const char* aType, uint32_t aInstanceSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool loggingThisType = (!gTypesToLog || LogThisType(aType));
|
bool loggingThisType = (!gTypesToLog || gTypesToLog->Contains(aType));
|
||||||
intptr_t serialno = 0;
|
intptr_t serialno = 0;
|
||||||
if (gSerialNumbers && loggingThisType) {
|
if (gSerialNumbers && loggingThisType) {
|
||||||
serialno = GetSerialNumber(aPtr, true);
|
serialno = GetSerialNumber(aPtr, true);
|
||||||
|
@ -1239,7 +1091,7 @@ NS_LogDtor(void* aPtr, const char* aType, uint32_t aInstanceSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool loggingThisType = (!gTypesToLog || LogThisType(aType));
|
bool loggingThisType = (!gTypesToLog || gTypesToLog->Contains(aType));
|
||||||
intptr_t serialno = 0;
|
intptr_t serialno = 0;
|
||||||
if (gSerialNumbers && loggingThisType) {
|
if (gSerialNumbers && loggingThisType) {
|
||||||
serialno = GetSerialNumber(aPtr, false);
|
serialno = GetSerialNumber(aPtr, false);
|
||||||
|
@ -1285,16 +1137,13 @@ NS_LogCOMPtrAddRef(void* aCOMPtr, nsISupports* aObject)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t* count = GetCOMPtrCount(object);
|
auto record = gSerialNumbers->Get(object);
|
||||||
if (count) {
|
int32_t count = record ? ++record->COMPtrCount : -1;
|
||||||
(*count)++;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
|
bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
|
||||||
|
|
||||||
if (gCOMPtrLog && loggingThisObject) {
|
if (gCOMPtrLog && loggingThisObject) {
|
||||||
fprintf(gCOMPtrLog, "\n<?> %p %" PRIdPTR " nsCOMPtrAddRef %d %p\n",
|
fprintf(gCOMPtrLog, "\n<?> %p %" PRIdPTR " nsCOMPtrAddRef %d %p\n",
|
||||||
object, serialno, count ? (*count) : -1, aCOMPtr);
|
object, serialno, count, aCOMPtr);
|
||||||
WalkTheStackCached(gCOMPtrLog);
|
WalkTheStackCached(gCOMPtrLog);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1326,16 +1175,13 @@ NS_LogCOMPtrRelease(void* aCOMPtr, nsISupports* aObject)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t* count = GetCOMPtrCount(object);
|
auto record = gSerialNumbers->Get(object);
|
||||||
if (count) {
|
int32_t count = record ? --record->COMPtrCount : -1;
|
||||||
(*count)--;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
|
bool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno));
|
||||||
|
|
||||||
if (gCOMPtrLog && loggingThisObject) {
|
if (gCOMPtrLog && loggingThisObject) {
|
||||||
fprintf(gCOMPtrLog, "\n<?> %p %" PRIdPTR " nsCOMPtrRelease %d %p\n",
|
fprintf(gCOMPtrLog, "\n<?> %p %" PRIdPTR " nsCOMPtrRelease %d %p\n",
|
||||||
object, serialno, count ? (*count) : -1, aCOMPtr);
|
object, serialno, count, aCOMPtr);
|
||||||
WalkTheStackCached(gCOMPtrLog);
|
WalkTheStackCached(gCOMPtrLog);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1346,22 +1192,10 @@ void
|
||||||
nsTraceRefcnt::Shutdown()
|
nsTraceRefcnt::Shutdown()
|
||||||
{
|
{
|
||||||
gCodeAddressService = nullptr;
|
gCodeAddressService = nullptr;
|
||||||
if (gBloatView) {
|
gBloatView = nullptr;
|
||||||
PL_HashTableDestroy(gBloatView);
|
gTypesToLog = nullptr;
|
||||||
gBloatView = nullptr;
|
gObjectsToLog = nullptr;
|
||||||
}
|
gSerialNumbers = nullptr;
|
||||||
if (gTypesToLog) {
|
|
||||||
PL_HashTableDestroy(gTypesToLog);
|
|
||||||
gTypesToLog = nullptr;
|
|
||||||
}
|
|
||||||
if (gObjectsToLog) {
|
|
||||||
PL_HashTableDestroy(gObjectsToLog);
|
|
||||||
gObjectsToLog = nullptr;
|
|
||||||
}
|
|
||||||
if (gSerialNumbers) {
|
|
||||||
PL_HashTableDestroy(gSerialNumbers);
|
|
||||||
gSerialNumbers = nullptr;
|
|
||||||
}
|
|
||||||
maybeUnregisterAndCloseFile(gBloatLog);
|
maybeUnregisterAndCloseFile(gBloatLog);
|
||||||
maybeUnregisterAndCloseFile(gRefcntsLog);
|
maybeUnregisterAndCloseFile(gRefcntsLog);
|
||||||
maybeUnregisterAndCloseFile(gAllocLog);
|
maybeUnregisterAndCloseFile(gAllocLog);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче