зеркало из https://github.com/mozilla/gecko-dev.git
Bug 820652 (part 6) - DMD: Don't use LiveBlockKey in LiveBlock. r=jlebar.
--HG-- extra : rebase_source : b65e0d34f6787a0f5031b685ececc61e19d4b0a3
This commit is contained in:
Родитель
308ad9d075
Коммит
942c88c933
|
@ -649,145 +649,8 @@ StackTrace::Get(Thread* aT)
|
||||||
|
|
||||||
static const char* gUnreportedName = "unreported";
|
static const char* gUnreportedName = "unreported";
|
||||||
|
|
||||||
// This is used by both LiveBlocks and LiveBlockGroups.
|
|
||||||
class LiveBlockKey
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
const StackTrace* const mAllocStackTrace; // never null
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// Live blocks can be reported in two ways.
|
|
||||||
// - The most common is via a memory reporter traversal -- the block is
|
|
||||||
// reported when the reporter runs, causing DMD to mark it as reported,
|
|
||||||
// and DMD must clear the marking once it has finished its analysis.
|
|
||||||
// - Less common are ones that are reported immediately on allocation. DMD
|
|
||||||
// must *not* clear the markings of these blocks once it has finished its
|
|
||||||
// analysis. The |mReportedOnAlloc| field is set for such blocks.
|
|
||||||
//
|
|
||||||
// These fields are used as the value in LiveBlock, so it's ok for them to be
|
|
||||||
// |mutable|.
|
|
||||||
mutable const StackTrace* mReportStackTrace; // nullptr if unreported
|
|
||||||
mutable const char* mReporterName; // gUnreportedName if unreported
|
|
||||||
mutable bool mReportedOnAlloc; // true if block was reported
|
|
||||||
|
|
||||||
public:
|
|
||||||
LiveBlockKey(const StackTrace* aAllocStackTrace)
|
|
||||||
: mAllocStackTrace(aAllocStackTrace),
|
|
||||||
mReportStackTrace(nullptr),
|
|
||||||
mReporterName(gUnreportedName),
|
|
||||||
mReportedOnAlloc(false)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(IsSane());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsSane() const
|
|
||||||
{
|
|
||||||
bool hasReporterName = mReporterName != gUnreportedName;
|
|
||||||
return mAllocStackTrace &&
|
|
||||||
(( mReportStackTrace && hasReporterName) ||
|
|
||||||
(!mReportStackTrace && !hasReporterName && !mReportedOnAlloc));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsReported() const
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(IsSane());
|
|
||||||
bool isRep = mReporterName != gUnreportedName;
|
|
||||||
return isRep;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash policy.
|
|
||||||
//
|
|
||||||
// hash() and match() both assume that identical reporter names have
|
|
||||||
// identical pointers. In practice this always happens because they are
|
|
||||||
// static strings (as specified in the NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN
|
|
||||||
// macro). This is true even for multi-reporters. (If it ever became
|
|
||||||
// untrue, the worst that would happen is that some blocks that should be in
|
|
||||||
// the same block group would end up in separate block groups.)
|
|
||||||
|
|
||||||
typedef LiveBlockKey Lookup;
|
|
||||||
|
|
||||||
static uint32_t hash(const LiveBlockKey& aKey)
|
|
||||||
{
|
|
||||||
return mozilla::HashGeneric(aKey.mAllocStackTrace,
|
|
||||||
aKey.mReportStackTrace,
|
|
||||||
aKey.mReporterName);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool match(const LiveBlockKey& aA, const LiveBlockKey& aB)
|
|
||||||
{
|
|
||||||
return aA.mAllocStackTrace == aB.mAllocStackTrace &&
|
|
||||||
aA.mReportStackTrace == aB.mReportStackTrace &&
|
|
||||||
aA.mReporterName == aB.mReporterName;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is used by DoubleReportBlockGroups.
|
|
||||||
class DoubleReportBlockKey
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
const StackTrace* const mAllocStackTrace; // never null
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// When double-reports occur we record (and later print) the stack trace
|
|
||||||
// and reporter name of *both* the reporting locations.
|
|
||||||
const StackTrace* const mReportStackTrace1; // never null
|
|
||||||
const StackTrace* const mReportStackTrace2; // never null
|
|
||||||
const char* const mReporterName1; // never gUnreportedName
|
|
||||||
const char* const mReporterName2; // never gUnreportedName
|
|
||||||
|
|
||||||
public:
|
|
||||||
DoubleReportBlockKey(const StackTrace* aAllocStackTrace,
|
|
||||||
const StackTrace* aReportStackTrace1,
|
|
||||||
const StackTrace* aReportStackTrace2,
|
|
||||||
const char* aReporterName1,
|
|
||||||
const char* aReporterName2)
|
|
||||||
: mAllocStackTrace(aAllocStackTrace),
|
|
||||||
mReportStackTrace1(aReportStackTrace1),
|
|
||||||
mReportStackTrace2(aReportStackTrace2),
|
|
||||||
mReporterName1(aReporterName1),
|
|
||||||
mReporterName2(aReporterName2)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(IsSane());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsSane() const
|
|
||||||
{
|
|
||||||
return mAllocStackTrace &&
|
|
||||||
mReportStackTrace1 &&
|
|
||||||
mReportStackTrace2 &&
|
|
||||||
mReporterName1 != gUnreportedName &&
|
|
||||||
mReporterName2 != gUnreportedName;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash policy.
|
|
||||||
//
|
|
||||||
// hash() and match() both assume that identical reporter names have
|
|
||||||
// identical pointers. See LiveBlockKey for more.
|
|
||||||
|
|
||||||
typedef DoubleReportBlockKey Lookup;
|
|
||||||
|
|
||||||
static uint32_t hash(const DoubleReportBlockKey& aKey)
|
|
||||||
{
|
|
||||||
return mozilla::HashGeneric(aKey.mAllocStackTrace,
|
|
||||||
aKey.mReportStackTrace1,
|
|
||||||
aKey.mReportStackTrace2,
|
|
||||||
aKey.mReporterName1,
|
|
||||||
aKey.mReporterName2);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool match(const DoubleReportBlockKey& aA,
|
|
||||||
const DoubleReportBlockKey& aB)
|
|
||||||
{
|
|
||||||
return aA.mAllocStackTrace == aB.mAllocStackTrace &&
|
|
||||||
aA.mReportStackTrace1 == aB.mReportStackTrace1 &&
|
|
||||||
aA.mReportStackTrace2 == aB.mReportStackTrace2 &&
|
|
||||||
aA.mReporterName1 == aB.mReporterName1 &&
|
|
||||||
aA.mReporterName2 == aB.mReporterName2;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// A live heap block.
|
// A live heap block.
|
||||||
class LiveBlock : public LiveBlockKey
|
class LiveBlock
|
||||||
{
|
{
|
||||||
const void* mPtr;
|
const void* mPtr;
|
||||||
|
|
||||||
|
@ -797,17 +660,49 @@ class LiveBlock : public LiveBlockKey
|
||||||
const size_t mReqSize:kReqBits; // size requested
|
const size_t mReqSize:kReqBits; // size requested
|
||||||
const size_t mSampled:1; // was this block sampled? (if so, slop == 0)
|
const size_t mSampled:1; // was this block sampled? (if so, slop == 0)
|
||||||
|
|
||||||
|
public:
|
||||||
|
const StackTrace* const mAllocStackTrace; // never null
|
||||||
|
|
||||||
|
// Live blocks can be reported in two ways.
|
||||||
|
// - The most common is via a memory reporter traversal -- the block is
|
||||||
|
// reported when the reporter runs, causing DMD to mark it as reported,
|
||||||
|
// and DMD must clear the marking once it has finished its analysis.
|
||||||
|
// - Less common are ones that are reported immediately on allocation. DMD
|
||||||
|
// must *not* clear the markings of these blocks once it has finished its
|
||||||
|
// analysis. The |mReportedOnAlloc| field is set for such blocks.
|
||||||
|
//
|
||||||
|
// |mPtr| is used as the key in LiveBlockTable, so it's ok for these fields
|
||||||
|
// to be |mutable|.
|
||||||
|
private:
|
||||||
|
mutable const StackTrace* mReportStackTrace; // nullptr if unreported
|
||||||
|
mutable const char* mReporterName; // gUnreportedName if unreported
|
||||||
|
mutable bool mReportedOnAlloc; // true if block was reported
|
||||||
|
// immediately after alloc
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LiveBlock(const void* aPtr, size_t aReqSize,
|
LiveBlock(const void* aPtr, size_t aReqSize,
|
||||||
const StackTrace* aAllocStackTrace, bool aSampled)
|
const StackTrace* aAllocStackTrace, bool aSampled)
|
||||||
: LiveBlockKey(aAllocStackTrace),
|
: mPtr(aPtr),
|
||||||
mPtr(aPtr),
|
|
||||||
mReqSize(aReqSize),
|
mReqSize(aReqSize),
|
||||||
mSampled(aSampled)
|
mSampled(aSampled),
|
||||||
|
mAllocStackTrace(aAllocStackTrace),
|
||||||
|
mReportStackTrace(nullptr),
|
||||||
|
mReporterName(gUnreportedName),
|
||||||
|
mReportedOnAlloc(false)
|
||||||
|
{
|
||||||
|
if (mReqSize != aReqSize)
|
||||||
{
|
{
|
||||||
if (mReqSize != aReqSize) {
|
|
||||||
MOZ_CRASH(); // overflowed mReqSize
|
MOZ_CRASH(); // overflowed mReqSize
|
||||||
}
|
}
|
||||||
|
MOZ_ASSERT(IsSane());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsSane() const
|
||||||
|
{
|
||||||
|
bool hasReporterName = mReporterName != gUnreportedName;
|
||||||
|
return mAllocStackTrace &&
|
||||||
|
(( mReportStackTrace && hasReporterName) ||
|
||||||
|
(!mReportStackTrace && !hasReporterName && !mReportedOnAlloc));
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ReqSize() const { return mReqSize; }
|
size_t ReqSize() const { return mReqSize; }
|
||||||
|
@ -825,6 +720,16 @@ public:
|
||||||
|
|
||||||
bool IsSampled() const { return mSampled; }
|
bool IsSampled() const { return mSampled; }
|
||||||
|
|
||||||
|
bool IsReported() const
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(IsSane());
|
||||||
|
bool isRep = mReporterName != gUnreportedName;
|
||||||
|
return isRep;
|
||||||
|
}
|
||||||
|
|
||||||
|
const StackTrace* ReportStackTrace() const { return mReportStackTrace; }
|
||||||
|
const char* ReporterName() const { return mReporterName; }
|
||||||
|
|
||||||
// This is |const| thanks to the |mutable| fields above.
|
// This is |const| thanks to the |mutable| fields above.
|
||||||
void Report(Thread* aT, const char* aReporterName, bool aReportedOnAlloc)
|
void Report(Thread* aT, const char* aReporterName, bool aReportedOnAlloc)
|
||||||
const;
|
const;
|
||||||
|
@ -1051,6 +956,128 @@ namespace dmd {
|
||||||
// Live and double-report block groups
|
// Live and double-report block groups
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class LiveBlockKey
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
const StackTrace* const mAllocStackTrace; // never null
|
||||||
|
protected:
|
||||||
|
const StackTrace* const mReportStackTrace; // nullptr if unreported
|
||||||
|
const char* const mReporterName; // gUnreportedName if unreported
|
||||||
|
|
||||||
|
public:
|
||||||
|
LiveBlockKey(const LiveBlock& aB)
|
||||||
|
: mAllocStackTrace(aB.mAllocStackTrace),
|
||||||
|
mReportStackTrace(aB.ReportStackTrace()),
|
||||||
|
mReporterName(aB.ReporterName())
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(IsSane());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsSane() const
|
||||||
|
{
|
||||||
|
bool hasReporterName = mReporterName != gUnreportedName;
|
||||||
|
return mAllocStackTrace &&
|
||||||
|
(( mReportStackTrace && hasReporterName) ||
|
||||||
|
(!mReportStackTrace && !hasReporterName));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsReported() const
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(IsSane());
|
||||||
|
bool isRep = mReporterName != gUnreportedName;
|
||||||
|
return isRep;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash policy.
|
||||||
|
//
|
||||||
|
// hash() and match() both assume that identical reporter names have
|
||||||
|
// identical pointers. In practice this always happens because they are
|
||||||
|
// static strings (as specified in the NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN
|
||||||
|
// macro). This is true even for multi-reporters. (If it ever became
|
||||||
|
// untrue, the worst that would happen is that some blocks that should be in
|
||||||
|
// the same block group would end up in separate block groups.)
|
||||||
|
|
||||||
|
typedef LiveBlockKey Lookup;
|
||||||
|
|
||||||
|
static uint32_t hash(const LiveBlockKey& aKey)
|
||||||
|
{
|
||||||
|
return mozilla::HashGeneric(aKey.mAllocStackTrace,
|
||||||
|
aKey.mReportStackTrace,
|
||||||
|
aKey.mReporterName);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool match(const LiveBlockKey& aA, const LiveBlockKey& aB)
|
||||||
|
{
|
||||||
|
return aA.mAllocStackTrace == aB.mAllocStackTrace &&
|
||||||
|
aA.mReportStackTrace == aB.mReportStackTrace &&
|
||||||
|
aA.mReporterName == aB.mReporterName;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class DoubleReportBlockKey
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
const StackTrace* const mAllocStackTrace; // never null
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// When double-reports occur we record (and later print) the stack trace
|
||||||
|
// and reporter name of *both* the reporting locations.
|
||||||
|
const StackTrace* const mReportStackTrace1; // never null
|
||||||
|
const StackTrace* const mReportStackTrace2; // never null
|
||||||
|
const char* const mReporterName1; // never gUnreportedName
|
||||||
|
const char* const mReporterName2; // never gUnreportedName
|
||||||
|
|
||||||
|
public:
|
||||||
|
DoubleReportBlockKey(const StackTrace* aAllocStackTrace,
|
||||||
|
const StackTrace* aReportStackTrace1,
|
||||||
|
const StackTrace* aReportStackTrace2,
|
||||||
|
const char* aReporterName1,
|
||||||
|
const char* aReporterName2)
|
||||||
|
: mAllocStackTrace(aAllocStackTrace),
|
||||||
|
mReportStackTrace1(aReportStackTrace1),
|
||||||
|
mReportStackTrace2(aReportStackTrace2),
|
||||||
|
mReporterName1(aReporterName1),
|
||||||
|
mReporterName2(aReporterName2)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(IsSane());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsSane() const
|
||||||
|
{
|
||||||
|
return mAllocStackTrace &&
|
||||||
|
mReportStackTrace1 &&
|
||||||
|
mReportStackTrace2 &&
|
||||||
|
mReporterName1 != gUnreportedName &&
|
||||||
|
mReporterName2 != gUnreportedName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash policy.
|
||||||
|
//
|
||||||
|
// hash() and match() both assume that identical reporter names have
|
||||||
|
// identical pointers. See LiveBlockKey for more.
|
||||||
|
|
||||||
|
typedef DoubleReportBlockKey Lookup;
|
||||||
|
|
||||||
|
static uint32_t hash(const DoubleReportBlockKey& aKey)
|
||||||
|
{
|
||||||
|
return mozilla::HashGeneric(aKey.mAllocStackTrace,
|
||||||
|
aKey.mReportStackTrace1,
|
||||||
|
aKey.mReportStackTrace2,
|
||||||
|
aKey.mReporterName1,
|
||||||
|
aKey.mReporterName2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool match(const DoubleReportBlockKey& aA,
|
||||||
|
const DoubleReportBlockKey& aB)
|
||||||
|
{
|
||||||
|
return aA.mAllocStackTrace == aB.mAllocStackTrace &&
|
||||||
|
aA.mReportStackTrace1 == aB.mReportStackTrace1 &&
|
||||||
|
aA.mReportStackTrace2 == aB.mReportStackTrace2 &&
|
||||||
|
aA.mReporterName1 == aB.mReporterName1 &&
|
||||||
|
aA.mReporterName2 == aB.mReporterName2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class GroupSize
|
class GroupSize
|
||||||
{
|
{
|
||||||
static const size_t kReqBits = sizeof(size_t) * 8 - 1; // 31 or 63
|
static const size_t kReqBits = sizeof(size_t) * 8 - 1; // 31 or 63
|
||||||
|
@ -1831,7 +1858,8 @@ Dump(Writer aWriter)
|
||||||
LiveBlockGroupTable& table = !b.IsReported()
|
LiveBlockGroupTable& table = !b.IsReported()
|
||||||
? unreportedLiveBlockGroupTable
|
? unreportedLiveBlockGroupTable
|
||||||
: reportedLiveBlockGroupTable;
|
: reportedLiveBlockGroupTable;
|
||||||
LiveBlockGroupTable::AddPtr p = table.lookupForAdd(b);
|
LiveBlockKey liveKey(b);
|
||||||
|
LiveBlockGroupTable::AddPtr p = table.lookupForAdd(liveKey);
|
||||||
if (!p) {
|
if (!p) {
|
||||||
LiveBlockGroup bg(b);
|
LiveBlockGroup bg(b);
|
||||||
(void)table.add(p, bg);
|
(void)table.add(p, bg);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче