author | Jonathan Kew <jfkthame@gmail.com> |
Fri, 14 Oct 2011 08:06:35 +0100 | |
changeset 78729 | 56c7568767f18154d266287d6ba03264602a3133 |
parent 78728 | aa2e380c86fb21743b7e627687357fc06761a84b |
child 78730 | 6715771c1d9a32da64293eebccd6fcf9a07eaae0 |
push id | 21329 |
push user | eakhgari@mozilla.com |
push date | Fri, 14 Oct 2011 14:37:50 +0000 |
treeherder | mozilla-central@349f3d4b2d87 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | roc, jlebar |
bugs | 671297 |
milestone | 10.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -3110,45 +3110,54 @@ AccountStorageForTextRun(gfxTextRun *aTe bytes &= ~(sizeof(gfxTextRun::CompressedGlyph) - 1); } bytes += sizeof(gfxTextRun); gTextRunStorage += bytes*aSign; gTextRunStorageHighWaterMark = NS_MAX(gTextRunStorageHighWaterMark, gTextRunStorage); } #endif +static PRUint64 +GlyphStorageAllocCount(PRUint32 aLength, PRUint32 aFlags) +{ + // always need to allocate storage for the glyph data + PRUint64 allocCount = aLength; + + // if the text is not persistent, we also need space for a copy + if (!(aFlags & gfxTextRunFactory::TEXT_IS_PERSISTENT)) { + // figure out number of extra CompressedGlyph elements we need to + // get sufficient space for the text + typedef gfxTextRun::CompressedGlyph CompressedGlyph; + if (aFlags & gfxTextRunFactory::TEXT_IS_8BIT) { + allocCount += (aLength + sizeof(CompressedGlyph) - 1) / + sizeof(CompressedGlyph); + } else { + allocCount += (aLength * sizeof(PRUnichar) + + sizeof(CompressedGlyph) - 1) / + sizeof(CompressedGlyph); + } + } + return allocCount; +} + // Helper for textRun creation to preallocate storage for glyphs and text; // this function returns a pointer to the newly-allocated glyph storage, // AND modifies the aText parameter if TEXT_IS_PERSISTENT was not set. // In that case, the text is appended to the glyph storage, so a single // delete[] operation in the textRun destructor will free both. // Returns nsnull if allocation fails. gfxTextRun::CompressedGlyph * gfxTextRun::AllocateStorage(const void*& aText, PRUint32 aLength, PRUint32 aFlags) { // Here, we rely on CompressedGlyph being the largest unit we care about for // allocation/alignment of either glyph data or text, so we allocate an array // of CompressedGlyphs, then take the last chunk of that and cast a pointer to // PRUint8* or PRUnichar* for text storage. - // always need to allocate storage for the glyph data - PRUint64 allocCount = aLength; - - // if the text is not persistent, we also need space for a copy - if (!(aFlags & gfxTextRunFactory::TEXT_IS_PERSISTENT)) { - // figure out number of extra CompressedGlyph elements we need to - // get sufficient space for the text - if (aFlags & gfxTextRunFactory::TEXT_IS_8BIT) { - allocCount += (aLength + sizeof(CompressedGlyph)-1) - / sizeof(CompressedGlyph); - } else { - allocCount += (aLength*sizeof(PRUnichar) + sizeof(CompressedGlyph)-1) - / sizeof(CompressedGlyph); - } - } + PRUint64 allocCount = GlyphStorageAllocCount(aLength, aFlags); // allocate the storage we need, returning nsnull on failure rather than // throwing an exception (because web content can create huge runs) CompressedGlyph *storage = new (std::nothrow) CompressedGlyph[allocCount]; if (!storage) { NS_WARNING("failed to allocate glyph/text storage for text run!"); return nsnull; } @@ -4466,16 +4475,41 @@ gfxTextRun::ClusterIterator::ClusterAdva { if (mCurrentChar == PRUint32(-1)) { return 0; } return mTextRun->GetAdvanceWidth(mCurrentChar, ClusterLength(), aProvider); } +PRUint64 +gfxTextRun::ComputeSize() +{ + PRUint64 total = moz_malloc_usable_size(this); + if (total == 0) { + total = sizeof(gfxTextRun); + } + + PRUint64 glyphDataSize = moz_malloc_usable_size(mCharacterGlyphs); + if (glyphDataSize == 0) { + // calculate how much gfxTextRun::AllocateStorage would have allocated + glyphDataSize = sizeof(CompressedGlyph) * + GlyphStorageAllocCount(mCharacterCount, mFlags); + } + total += glyphDataSize; + + if (mDetailedGlyphs) { + total += mDetailedGlyphs->SizeOf(); + } + + total += mGlyphRuns.SizeOf(); + + return total; +} + #ifdef DEBUG void gfxTextRun::Dump(FILE* aOutput) { if (!aOutput) { aOutput = stdout; }
--- a/gfx/thebes/gfxFont.h +++ b/gfx/thebes/gfxFont.h @@ -1348,17 +1348,25 @@ public: * required for legible text should still be enabled. */ TEXT_DISABLE_OPTIONAL_LIGATURES = 0x0080, /** * When set, the textrun should favour speed of construction over * quality. This may involve disabling ligatures and/or kerning or * other effects. */ - TEXT_OPTIMIZE_SPEED = 0x0100 + TEXT_OPTIMIZE_SPEED = 0x0100, + /** + * For internal use by the memory reporter when accounting for + * storage used by textruns. + * Because the reporter may visit each textrun multiple times while + * walking the frame trees and textrun cache, it needs to mark + * textruns that have been seen so as to avoid multiple-accounting. + */ + TEXT_RUN_SIZE_ACCOUNTED = 0x0200 }; /** * This record contains all the parameters needed to initialize a textrun. */ struct Parameters { // A reference context suggesting where the textrun will be rendered gfxContext *mContext; @@ -2033,16 +2041,31 @@ public: bool mClipBeforePart; bool mClipAfterPart; }; // user font set generation when text run was created PRUint64 GetUserFontSetGeneration() { return mUserFontSetGeneration; } + // return storage used by this run, for memory reporter; + // nsTransformedTextRun needs to override this as it holds additional data + virtual PRUint64 ComputeSize(); + + void AccountForSize(PRUint64* aTotal) { + if (mFlags & gfxTextRunFactory::TEXT_RUN_SIZE_ACCOUNTED) { + return; + } + mFlags |= gfxTextRunFactory::TEXT_RUN_SIZE_ACCOUNTED; + *aTotal += ComputeSize(); + } + void ClearSizeAccounted() { + mFlags &= ~gfxTextRunFactory::TEXT_RUN_SIZE_ACCOUNTED; + } + #ifdef DEBUG // number of entries referencing this textrun in the gfxTextRunWordCache PRUint32 mCachedWords; // generation of gfxTextRunWordCache that refers to this textrun; // if the cache gets cleared, then mCachedWords is no longer meaningful PRUint32 mCacheGeneration; void Dump(FILE* aOutput); @@ -2203,16 +2226,21 @@ private: if (!mOffsetToIndex.InsertElementSorted(DGRec(aOffset, detailIndex), CompareRecordOffsets())) { return nsnull; } } return details; } + PRUint32 SizeOf() { + return sizeof(DetailedGlyphStore) + + mDetails.SizeOf() + mOffsetToIndex.SizeOf(); + } + private: struct DGRec { DGRec(const PRUint32& aOffset, const PRUint32& aIndex) : mOffset(aOffset), mIndex(aIndex) { } PRUint32 mOffset; // source character offset in the textrun PRUint32 mIndex; // index where this char's DetailedGlyphs begin };
--- a/gfx/thebes/gfxTextRunWordCache.cpp +++ b/gfx/thebes/gfxTextRunWordCache.cpp @@ -130,16 +130,18 @@ public: */ void Flush() { mCache.Clear(); #ifdef DEBUG mGeneration++; #endif } + void ComputeStorage(PRUint64 *aTotal); + #ifdef DEBUG PRUint32 mGeneration; void Dump(); #endif protected: struct CacheHashKey { void *mFontOrGroup; @@ -212,16 +214,21 @@ protected: void FinishTextRun(gfxTextRun *aTextRun, gfxTextRun *aNewRun, const gfxFontGroup::Parameters *aParams, const nsTArray<DeferredWord>& aDeferredWords, bool aSuccessful); void RemoveWord(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd, PRUint32 aHash); void Uninit(); + static PLDHashOperator AccountForStorage(CacheHashEntry *aEntry, + void *aUserData); + static PLDHashOperator ClearSizeAccounted(CacheHashEntry *aEntry, + void *aUserData); + nsTHashtable<CacheHashEntry> mCache; PRInt32 mBidiNumeral; #ifdef DEBUG static PLDHashOperator CacheDumpEntry(CacheHashEntry* aEntry, void* userArg); #endif }; @@ -902,16 +909,48 @@ TextRunWordCache::RemoveTextRun(gfxTextR } RemoveWord(aTextRun, wordStart, i, hash); #ifdef DEBUG NS_ASSERTION(aTextRun->mCachedWords == 0, "Textrun was not completely removed from the cache!"); #endif } +/*static*/ PLDHashOperator +TextRunWordCache::AccountForStorage(CacheHashEntry *aEntry, void *aUserData) +{ + gfxTextRun *run = aEntry->mTextRun; + if (run) { + PRUint64 *total = static_cast<PRUint64*>(aUserData); + run->AccountForSize(total); + } + return PL_DHASH_NEXT; +} + +/*static*/ PLDHashOperator +TextRunWordCache::ClearSizeAccounted(CacheHashEntry *aEntry, void *) +{ + gfxTextRun *run = aEntry->mTextRun; + if (run) { + run->ClearSizeAccounted(); + } + return PL_DHASH_NEXT; +} + +void +TextRunWordCache::ComputeStorage(PRUint64 *aTotal) +{ + if (aTotal) { + *aTotal += mCache.SizeOf(); + mCache.EnumerateEntries(AccountForStorage, aTotal); + } else { + mCache.EnumerateEntries(ClearSizeAccounted, nsnull); + } +} + static bool CompareDifferentWidthStrings(const PRUint8 *aStr1, const PRUnichar *aStr2, PRUint32 aLength) { PRUint32 i; for (i = 0; i < aLength; ++i) { if (aStr1[i] != aStr2[i]) return PR_FALSE; @@ -1056,8 +1095,18 @@ gfxTextRunWordCache::RemoveTextRun(gfxTe void gfxTextRunWordCache::Flush() { if (!gTextRunWordCache) return; gTextRunWordCache->Flush(); } + +void +gfxTextRunWordCache::ComputeStorage(PRUint64 *aTotal) +{ + if (!gTextRunWordCache) { + return; + } + gTextRunWordCache->ComputeStorage(aTotal); +} +
--- a/gfx/thebes/gfxTextRunWordCache.h +++ b/gfx/thebes/gfxTextRunWordCache.h @@ -100,16 +100,25 @@ public: static void RemoveTextRun(gfxTextRun *aTextRun); /** * Flush the textrun cache. This must be called if a configuration * change that would affect textruns is applied. */ static void Flush(); + /** + * If aTotal is NULL, just clears the TEXT_RUN_MEMORY_ACCOUNTED flag + * on each textRun found. + * If aTotal is non-NULL, adds the storage used for each textRun to the + * total, and sets the TEXT_RUN_MEMORY_ACCOUNTED flag to avoid double- + * accounting. (Runs with this flag already set will be skipped.) + */ + static void ComputeStorage(PRUint64 *aTotal); + protected: friend class gfxPlatform; static nsresult Init(); static void Shutdown(); }; #endif /* GFX_TEXT_RUN_WORD_CACHE_H */
--- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -4278,16 +4278,49 @@ nsLayoutUtils::GetFontFacesForText(nsIFr curr); } while (aFollowContinuations && (curr = static_cast<nsTextFrame*>(curr->GetNextContinuation()))); return NS_OK; } /* static */ +nsresult +nsLayoutUtils::GetTextRunMemoryForFrames(nsIFrame* aFrame, PRUint64* aTotal) +{ + NS_PRECONDITION(aFrame, "NULL frame pointer"); + + if (aFrame->GetType() == nsGkAtoms::textFrame) { + nsTextFrame* textFrame = static_cast<nsTextFrame*>(aFrame); + gfxTextRun *run = textFrame->GetTextRun(); + if (run) { + if (aTotal) { + run->AccountForSize(aTotal); + } else { + run->ClearSizeAccounted(); + } + } + return NS_OK; + } + + nsAutoTArray<nsIFrame::ChildList,4> childListArray; + aFrame->GetChildLists(&childListArray); + + for (nsIFrame::ChildListArrayIterator childLists(childListArray); + !childLists.IsDone(); childLists.Next()) { + for (nsFrameList::Enumerator e(childLists.CurrentList()); + !e.AtEnd(); e.Next()) { + GetTextRunMemoryForFrames(e.get(), aTotal); + } + } + + return NS_OK; +} + +/* static */ void nsLayoutUtils::Shutdown() { if (sContentMap) { delete sContentMap; sContentMap = NULL; } }
--- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -1429,16 +1429,30 @@ public: */ static nsresult GetFontFacesForText(nsIFrame* aFrame, PRInt32 aStartOffset, PRInt32 aEndOffset, bool aFollowContinuations, nsFontFaceList* aFontFaceList); /** + * Walks the frame tree starting at aFrame looking for textRuns. + * If aTotal is NULL, just clears the TEXT_RUN_MEMORY_ACCOUNTED flag + * on each textRun found. + * If aTotal is non-NULL, adds the storage used for each textRun to the + * total, and sets the TEXT_RUN_MEMORY_ACCOUNTED flag to avoid double- + * accounting. (Runs with this flag already set will be skipped.) + * Expected usage pattern is therefore to call twice: + * rv = GetTextRunMemoryForFrames(rootFrame, NULL); + * rv = GetTextRunMemoryForFrames(rootFrame, &total); + */ + static nsresult GetTextRunMemoryForFrames(nsIFrame* aFrame, + PRUint64* aTotal); + + /** * Checks if CSS 3D transforms are currently enabled. */ static bool Are3DTransformsEnabled(); static void Shutdown(); #ifdef DEBUG /**
--- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -215,16 +215,18 @@ #define ANCHOR_SCROLL_FLAGS (SCROLL_OVERFLOW_HIDDEN | SCROLL_NO_PARENT_FRAMES) #include "nsContentCID.h" static NS_DEFINE_IID(kRangeCID, NS_RANGE_CID); /* for NS_MEMORY_REPORTER_IMPLEMENT */ #include "nsIMemoryReporter.h" +#include "gfxTextRunWordCache.h" + using namespace mozilla; using namespace mozilla::dom; using namespace mozilla::layers; CapturingContentInfo nsIPresShell::gCaptureInfo = { PR_FALSE /* mAllowed */, PR_FALSE /* mRetargetToElement */, PR_FALSE /* mPreventDrag */, nsnull /* mContent */ }; nsIContent* nsIPresShell::gKeyDownTarget; @@ -636,50 +638,79 @@ PresShell::MemoryReporter::SizeEnumerato str += spec; } } str += NS_LITERAL_CSTRING(")"); NS_NAMED_LITERAL_CSTRING(kArenaDesc, "Memory used by layout PresShell, PresContext, and other related areas."); NS_NAMED_LITERAL_CSTRING(kStyleDesc, "Memory used by the style system."); + NS_NAMED_LITERAL_CSTRING(kTextRunsDesc, "Memory used for text-runs (glyph layout) in the PresShell's frame tree."); nsCAutoString arenaPath = str + NS_LITERAL_CSTRING("/arenas"); nsCAutoString stylePath = str + NS_LITERAL_CSTRING("/styledata"); + nsCAutoString textRunsPath = str + NS_LITERAL_CSTRING("/textruns"); PRUint32 arenasSize; arenasSize = aShell->EstimateMemoryUsed(); arenasSize += aShell->mPresContext->EstimateMemoryUsed(); PRUint32 styleSize; styleSize = aShell->StyleSet()->SizeOf(); + PRUint64 textRunsSize; + textRunsSize = aShell->ComputeTextRunMemoryUsed(); + data->callback-> Callback(EmptyCString(), arenaPath, nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::UNITS_BYTES, arenasSize, kArenaDesc, data->closure); data->callback-> Callback(EmptyCString(), stylePath, nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::UNITS_BYTES, styleSize, kStyleDesc, data->closure); + if (textRunsSize) { + data->callback-> + Callback(EmptyCString(), textRunsPath, nsIMemoryReporter::KIND_HEAP, + nsIMemoryReporter::UNITS_BYTES, textRunsSize, kTextRunsDesc, + data->closure); + } + return PL_DHASH_NEXT; } NS_IMETHODIMP PresShell::MemoryReporter::CollectReports(nsIMemoryMultiReporterCallback* aCb, nsISupports* aClosure) { MemoryReporterData data; data.callback = aCb; data.closure = aClosure; + // clear TEXT_RUN_SIZE_ACCOUNTED flag on cached runs + gfxTextRunWordCache::ComputeStorage(nsnull); + sLiveShells->EnumerateEntries(SizeEnumerator, &data); + NS_NAMED_LITERAL_CSTRING(kTextRunWordCachePath, + "explicit/gfx/textrun-word-cache"); + NS_NAMED_LITERAL_CSTRING(kTextRunWordCacheDesc, + "Memory used by cached text-runs that are " + "not owned by a PresShell's frame tree."); + + // now total up cached runs that aren't otherwise accounted for + PRUint64 textRunWordCacheSize = 0; + gfxTextRunWordCache::ComputeStorage(&textRunWordCacheSize); + + aCb->Callback(EmptyCString(), kTextRunWordCachePath, + nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::UNITS_BYTES, + textRunWordCacheSize, kTextRunWordCacheDesc, aClosure); + return NS_OK; } class nsAutoCauseReflowNotifier { public: nsAutoCauseReflowNotifier(PresShell* aShell) : mShell(aShell) @@ -8705,8 +8736,27 @@ PresShell::GetRootPresShell() if (mPresContext) { nsPresContext* rootPresContext = mPresContext->GetRootPresContext(); if (rootPresContext) { return static_cast<PresShell*>(rootPresContext->PresShell()); } } return nsnull; } + +PRUint64 +PresShell::ComputeTextRunMemoryUsed() +{ + nsIFrame* rootFrame = FrameManager()->GetRootFrame(); + if (!rootFrame) { + return 0; + } + + // clear the TEXT_RUN_MEMORY_ACCOUNTED flags + nsLayoutUtils::GetTextRunMemoryForFrames(rootFrame, nsnull); + + // collect the total memory in use for textruns + PRUint64 total = 0; + nsLayoutUtils::GetTextRunMemoryForFrames(rootFrame, &total); + + return total; +} +
--- a/layout/base/nsPresShell.h +++ b/layout/base/nsPresShell.h @@ -893,16 +893,18 @@ public: result += sizeof(PresShell); result += mStackArena.Size(); result += mFrameArena.Size(); return result; } + PRUint64 ComputeTextRunMemoryUsed(); + class MemoryReporter : public nsIMemoryMultiReporter { public: NS_DECL_ISUPPORTS NS_DECL_NSIMEMORYMULTIREPORTER protected: static PLDHashOperator SizeEnumerator(PresShellPtrKey *aEntry, void *userArg); };
--- a/layout/generic/nsTextRunTransformations.cpp +++ b/layout/generic/nsTextRunTransformations.cpp @@ -94,16 +94,38 @@ nsTransformedTextRun::SetPotentialLineBr bool changed = gfxTextRun::SetPotentialLineBreaks(aStart, aLength, aBreakBefore, aRefContext); if (changed) { mNeedsRebuild = PR_TRUE; } return changed; } +PRUint64 +nsTransformedTextRun::ComputeSize() +{ + PRUint32 total = gfxTextRun::ComputeSize(); + if (moz_malloc_usable_size(this) == 0) { + total += sizeof(nsTransformedTextRun) - sizeof(gfxTextRun); + } + total += mStyles.SizeOf(); + total += mCapitalize.SizeOf(); + if (mOwnsFactory) { + PRUint32 factorySize = moz_malloc_usable_size(mFactory); + if (factorySize == 0) { + // this may not quite account for everything + // (e.g. nsCaseTransformTextRunFactory adds a couple of members) + // but I'm not sure it's worth the effort to track more precisely + factorySize = sizeof(nsTransformingTextRunFactory); + } + total += factorySize; + } + return total; +} + nsTransformedTextRun* nsTransformingTextRunFactory::MakeTextRun(const PRUnichar* aString, PRUint32 aLength, const gfxTextRunFactory::Parameters* aParams, gfxFontGroup* aFontGroup, PRUint32 aFlags, nsStyleContext** aStyles, bool aOwnsFactory) { return nsTransformedTextRun::Create(aParams, this, aFontGroup, aString, aLength, aFlags, aStyles, aOwnsFactory);
--- a/layout/generic/nsTextRunTransformations.h +++ b/layout/generic/nsTextRunTransformations.h @@ -127,16 +127,19 @@ public: void FinishSettingProperties(gfxContext* aRefContext) { if (mNeedsRebuild) { mNeedsRebuild = PR_FALSE; mFactory->RebuildTextRun(this, aRefContext); } } + // override the gfxTextRun impl to account for additional members here + virtual PRUint64 ComputeSize(); + nsTransformingTextRunFactory *mFactory; nsTArray<nsRefPtr<nsStyleContext> > mStyles; nsTArray<bool> mCapitalize; bool mOwnsFactory; bool mNeedsRebuild; private: nsTransformedTextRun(const gfxTextRunFactory::Parameters* aParams,
--- a/xpcom/glue/nsTArray-inl.h +++ b/xpcom/glue/nsTArray-inl.h @@ -50,43 +50,43 @@ template<class Alloc> nsTArray_base<Alloc>::~nsTArray_base() { if (mHdr != EmptyHdr() && !UsesAutoArrayBuffer()) { Alloc::Free(mHdr); } MOZ_COUNT_DTOR(nsTArray_base); } template<class Alloc> -nsTArrayHeader* nsTArray_base<Alloc>::GetAutoArrayBufferUnsafe(size_t elemAlign) { +const nsTArrayHeader* nsTArray_base<Alloc>::GetAutoArrayBufferUnsafe(size_t elemAlign) const { // Assuming |this| points to an nsAutoArray, we want to get a pointer to // mAutoBuf. So just cast |this| to nsAutoArray* and read &mAutoBuf! - void* autoBuf = &reinterpret_cast<nsAutoArrayBase<nsTArray<PRUint32>, 1>*>(this)->mAutoBuf; + const void* autoBuf = &reinterpret_cast<const nsAutoArrayBase<nsTArray<PRUint32>, 1>*>(this)->mAutoBuf; // If we're on a 32-bit system and elemAlign is 8, we need to adjust our // pointer to take into account the extra alignment in the auto array. // Check that the auto array is padded as we expect. PR_STATIC_ASSERT(sizeof(void*) != 4 || (MOZ_ALIGNOF(mozilla::AlignedElem<8>) == 8 && sizeof(nsAutoTArray<mozilla::AlignedElem<8>, 1>) == sizeof(void*) + sizeof(nsTArrayHeader) + 4 + sizeof(mozilla::AlignedElem<8>))); // We don't support alignments greater than 8 bytes. NS_ABORT_IF_FALSE(elemAlign <= 4 || elemAlign == 8, "unsupported alignment."); if (sizeof(void*) == 4 && elemAlign == 8) { - autoBuf = reinterpret_cast<char*>(autoBuf) + 4; + autoBuf = reinterpret_cast<const char*>(autoBuf) + 4; } - return reinterpret_cast<Header*>(autoBuf); + return reinterpret_cast<const Header*>(autoBuf); } template<class Alloc> -bool nsTArray_base<Alloc>::UsesAutoArrayBuffer() { +bool nsTArray_base<Alloc>::UsesAutoArrayBuffer() const { if (!mHdr->mIsAutoArray) { return PR_FALSE; } // This is nuts. If we were sane, we'd pass elemAlign as a parameter to // this function. Unfortunately this function is called in nsTArray_base's // destructor, at which point we don't know elem_type's alignment. // @@ -113,18 +113,18 @@ bool nsTArray_base<Alloc>::UsesAutoArray // Note that this means that we can't store elements with alignment 16 in an // nsTArray, because GetAutoArrayBuffer(16) could lie outside the memory // owned by this nsAutoTArray. We statically assert that elem_type's // alignment is 8 bytes or less in nsAutoArrayBase. PR_STATIC_ASSERT(sizeof(nsTArrayHeader) > 4); #ifdef DEBUG - PRPtrdiff diff = reinterpret_cast<char*>(GetAutoArrayBuffer(8)) - - reinterpret_cast<char*>(GetAutoArrayBuffer(4)); + PRPtrdiff diff = reinterpret_cast<const char*>(GetAutoArrayBuffer(8)) - + reinterpret_cast<const char*>(GetAutoArrayBuffer(4)); NS_ABORT_IF_FALSE(diff >= 0 && diff <= 4, "GetAutoArrayBuffer doesn't do what we expect."); #endif return mHdr == GetAutoArrayBuffer(4) || mHdr == GetAutoArrayBuffer(8); } template<class Alloc>
--- a/xpcom/glue/nsTArray.h +++ b/xpcom/glue/nsTArray.h @@ -251,33 +251,41 @@ protected: bool mIsAuto; }; // Helper function for SwapArrayElements. Ensures that if the array // is an nsAutoTArray that it doesn't use the built-in buffer. bool EnsureNotUsingAutoArrayBuffer(size_type elemSize); // Returns true if this nsTArray is an nsAutoTArray with a built-in buffer. - bool IsAutoArray() { + bool IsAutoArray() const { return mHdr->mIsAutoArray; } // Returns a Header for the built-in buffer of this nsAutoTArray. Header* GetAutoArrayBuffer(size_t elemAlign) { NS_ASSERTION(IsAutoArray(), "Should be an auto array to call this"); return GetAutoArrayBufferUnsafe(elemAlign); } + const Header* GetAutoArrayBuffer(size_t elemAlign) const { + NS_ASSERTION(IsAutoArray(), "Should be an auto array to call this"); + return GetAutoArrayBufferUnsafe(elemAlign); + } // Returns a Header for the built-in buffer of this nsAutoTArray, but doesn't // assert that we are an nsAutoTArray. - Header* GetAutoArrayBufferUnsafe(size_t elemAlign); + Header* GetAutoArrayBufferUnsafe(size_t elemAlign) { + return const_cast<Header*>(static_cast<const nsTArray_base<Alloc>*>(this)-> + GetAutoArrayBufferUnsafe(elemAlign)); + } + const Header* GetAutoArrayBufferUnsafe(size_t elemAlign) const; // Returns true if this is an nsAutoTArray and it currently uses the // built-in buffer to store its elements. - bool UsesAutoArrayBuffer(); + bool UsesAutoArrayBuffer() const; // The array's elements (prefixed with a Header). This pointer is never // null. If the array is empty, then this will point to sEmptyHdr. Header *mHdr; Header* Hdr() const { return mHdr; } @@ -470,17 +478,18 @@ public: nsTArray& operator=(const nsTArray<E, Allocator>& other) { ReplaceElementsAt(0, Length(), other.Elements(), other.Length()); return *this; } // @return The amount of memory taken used by this nsTArray, not including // sizeof(this) size_t SizeOf() const { - return this->Capacity() * sizeof(elem_type) + sizeof(*this->Hdr()); + return this->UsesAutoArrayBuffer() ? + 0 : this->Capacity() * sizeof(elem_type) + sizeof(*this->Hdr()); } // // Accessor methods // // This method provides direct access to the array elements. // @return A pointer to the first element of the array. If the array is