layout/base/nsPresArena.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
michael@0 2 * vim: set ts=2 sw=2 et tw=78:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
michael@0 6 */
michael@0 7
michael@0 8 /* arena allocation for the frame tree and closely-related objects */
michael@0 9
michael@0 10 // Even on 32-bit systems, we allocate objects from the frame arena
michael@0 11 // that require 8-byte alignment. The cast to uintptr_t is needed
michael@0 12 // because plarena isn't as careful about mask construction as it
michael@0 13 // ought to be.
michael@0 14 #define ALIGN_SHIFT 3
michael@0 15 #define PL_ARENA_CONST_ALIGN_MASK ((uintptr_t(1) << ALIGN_SHIFT) - 1)
michael@0 16 #include "plarena.h"
michael@0 17 // plarena.h needs to be included first to make it use the above
michael@0 18 // PL_ARENA_CONST_ALIGN_MASK in this file.
michael@0 19
michael@0 20 #include "nsPresArena.h"
michael@0 21
michael@0 22 #include "mozilla/Poison.h"
michael@0 23 #include "nsDebug.h"
michael@0 24 #include "nsArenaMemoryStats.h"
michael@0 25 #include "nsPrintfCString.h"
michael@0 26
michael@0 27 // Size to use for PLArena block allocations.
michael@0 28 static const size_t ARENA_PAGE_SIZE = 8192;
michael@0 29
michael@0 30 nsPresArena::nsPresArena()
michael@0 31 {
michael@0 32 PL_INIT_ARENA_POOL(&mPool, "PresArena", ARENA_PAGE_SIZE);
michael@0 33 }
michael@0 34
michael@0 35 nsPresArena::~nsPresArena()
michael@0 36 {
michael@0 37 #if defined(MOZ_HAVE_MEM_CHECKS)
michael@0 38 mFreeLists.EnumerateEntries(UnpoisonFreeList, nullptr);
michael@0 39 #endif
michael@0 40 PL_FinishArenaPool(&mPool);
michael@0 41 }
michael@0 42
michael@0 43 NS_HIDDEN_(void*)
michael@0 44 nsPresArena::Allocate(uint32_t aCode, size_t aSize)
michael@0 45 {
michael@0 46 NS_ABORT_IF_FALSE(aSize > 0, "PresArena cannot allocate zero bytes");
michael@0 47
michael@0 48 // We only hand out aligned sizes
michael@0 49 aSize = PL_ARENA_ALIGN(&mPool, aSize);
michael@0 50
michael@0 51 // If there is no free-list entry for this type already, we have
michael@0 52 // to create one now, to record its size.
michael@0 53 FreeList* list = mFreeLists.PutEntry(aCode);
michael@0 54
michael@0 55 nsTArray<void*>::index_type len = list->mEntries.Length();
michael@0 56 if (list->mEntrySize == 0) {
michael@0 57 NS_ABORT_IF_FALSE(len == 0, "list with entries but no recorded size");
michael@0 58 list->mEntrySize = aSize;
michael@0 59 } else {
michael@0 60 NS_ABORT_IF_FALSE(list->mEntrySize == aSize,
michael@0 61 "different sizes for same object type code");
michael@0 62 }
michael@0 63
michael@0 64 void* result;
michael@0 65 if (len > 0) {
michael@0 66 // LIFO behavior for best cache utilization
michael@0 67 result = list->mEntries.ElementAt(len - 1);
michael@0 68 list->mEntries.RemoveElementAt(len - 1);
michael@0 69 #if defined(DEBUG)
michael@0 70 {
michael@0 71 MOZ_MAKE_MEM_DEFINED(result, list->mEntrySize);
michael@0 72 char* p = reinterpret_cast<char*>(result);
michael@0 73 char* limit = p + list->mEntrySize;
michael@0 74 for (; p < limit; p += sizeof(uintptr_t)) {
michael@0 75 uintptr_t val = *reinterpret_cast<uintptr_t*>(p);
michael@0 76 NS_ABORT_IF_FALSE(val == mozPoisonValue(),
michael@0 77 nsPrintfCString("PresArena: poison overwritten; "
michael@0 78 "wanted %.16llx "
michael@0 79 "found %.16llx "
michael@0 80 "errors in bits %.16llx",
michael@0 81 uint64_t(mozPoisonValue()),
michael@0 82 uint64_t(val),
michael@0 83 uint64_t(mozPoisonValue() ^ val)
michael@0 84 ).get());
michael@0 85 }
michael@0 86 }
michael@0 87 #endif
michael@0 88 MOZ_MAKE_MEM_UNDEFINED(result, list->mEntrySize);
michael@0 89 return result;
michael@0 90 }
michael@0 91
michael@0 92 // Allocate a new chunk from the arena
michael@0 93 list->mEntriesEverAllocated++;
michael@0 94 PL_ARENA_ALLOCATE(result, &mPool, aSize);
michael@0 95 if (!result) {
michael@0 96 NS_RUNTIMEABORT("out of memory");
michael@0 97 }
michael@0 98 return result;
michael@0 99 }
michael@0 100
michael@0 101 NS_HIDDEN_(void)
michael@0 102 nsPresArena::Free(uint32_t aCode, void* aPtr)
michael@0 103 {
michael@0 104 // Try to recycle this entry.
michael@0 105 FreeList* list = mFreeLists.GetEntry(aCode);
michael@0 106 NS_ABORT_IF_FALSE(list, "no free list for pres arena object");
michael@0 107 NS_ABORT_IF_FALSE(list->mEntrySize > 0, "PresArena cannot free zero bytes");
michael@0 108
michael@0 109 mozWritePoison(aPtr, list->mEntrySize);
michael@0 110
michael@0 111 MOZ_MAKE_MEM_NOACCESS(aPtr, list->mEntrySize);
michael@0 112 list->mEntries.AppendElement(aPtr);
michael@0 113 }
michael@0 114
michael@0 115 /* static */ size_t
michael@0 116 nsPresArena::SizeOfFreeListEntryExcludingThis(
michael@0 117 FreeList* aEntry, mozilla::MallocSizeOf aMallocSizeOf, void*)
michael@0 118 {
michael@0 119 return aEntry->mEntries.SizeOfExcludingThis(aMallocSizeOf);
michael@0 120 }
michael@0 121
michael@0 122 struct EnumerateData {
michael@0 123 nsArenaMemoryStats* stats;
michael@0 124 size_t total;
michael@0 125 };
michael@0 126
michael@0 127 #if defined(MOZ_HAVE_MEM_CHECKS)
michael@0 128 /* static */ PLDHashOperator
michael@0 129 nsPresArena::UnpoisonFreeList(FreeList* aEntry, void*)
michael@0 130 {
michael@0 131 nsTArray<void*>::index_type len;
michael@0 132 while ((len = aEntry->mEntries.Length())) {
michael@0 133 void* result = aEntry->mEntries.ElementAt(len - 1);
michael@0 134 aEntry->mEntries.RemoveElementAt(len - 1);
michael@0 135 MOZ_MAKE_MEM_UNDEFINED(result, aEntry->mEntrySize);
michael@0 136 }
michael@0 137 return PL_DHASH_NEXT;
michael@0 138 }
michael@0 139 #endif
michael@0 140
michael@0 141 /* static */ PLDHashOperator
michael@0 142 nsPresArena::FreeListEnumerator(FreeList* aEntry, void* aData)
michael@0 143 {
michael@0 144 EnumerateData* data = static_cast<EnumerateData*>(aData);
michael@0 145 // Note that we're not measuring the size of the entries on the free
michael@0 146 // list here. The free list knows how many objects we've allocated
michael@0 147 // ever (which includes any objects that may be on the FreeList's
michael@0 148 // |mEntries| at this point) and we're using that to determine the
michael@0 149 // total size of objects allocated with a given ID.
michael@0 150 size_t totalSize = aEntry->mEntrySize * aEntry->mEntriesEverAllocated;
michael@0 151 size_t* p;
michael@0 152
michael@0 153 switch (NS_PTR_TO_INT32(aEntry->mKey)) {
michael@0 154 #define FRAME_ID(classname) \
michael@0 155 case nsQueryFrame::classname##_id: \
michael@0 156 p = &data->stats->FRAME_ID_STAT_FIELD(classname); \
michael@0 157 break;
michael@0 158 #include "nsFrameIdList.h"
michael@0 159 #undef FRAME_ID
michael@0 160 case nsLineBox_id:
michael@0 161 p = &data->stats->mLineBoxes;
michael@0 162 break;
michael@0 163 case nsRuleNode_id:
michael@0 164 p = &data->stats->mRuleNodes;
michael@0 165 break;
michael@0 166 case nsStyleContext_id:
michael@0 167 p = &data->stats->mStyleContexts;
michael@0 168 break;
michael@0 169 default:
michael@0 170 return PL_DHASH_NEXT;
michael@0 171 }
michael@0 172
michael@0 173 *p += totalSize;
michael@0 174 data->total += totalSize;
michael@0 175
michael@0 176 return PL_DHASH_NEXT;
michael@0 177 }
michael@0 178
michael@0 179 void
michael@0 180 nsPresArena::AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
michael@0 181 nsArenaMemoryStats* aArenaStats)
michael@0 182 {
michael@0 183 // We do a complicated dance here because we want to measure the
michael@0 184 // space taken up by the different kinds of objects in the arena,
michael@0 185 // but we don't have pointers to those objects. And even if we did,
michael@0 186 // we wouldn't be able to use aMallocSizeOf on them, since they were
michael@0 187 // allocated out of malloc'd chunks of memory. So we compute the
michael@0 188 // size of the arena as known by malloc and we add up the sizes of
michael@0 189 // all the objects that we care about. Subtracting these two
michael@0 190 // quantities gives us a catch-all "other" number, which includes
michael@0 191 // slop in the arena itself as well as the size of objects that
michael@0 192 // we've not measured explicitly.
michael@0 193
michael@0 194 size_t mallocSize = PL_SizeOfArenaPoolExcludingPool(&mPool, aMallocSizeOf);
michael@0 195 mallocSize += mFreeLists.SizeOfExcludingThis(SizeOfFreeListEntryExcludingThis,
michael@0 196 aMallocSizeOf);
michael@0 197
michael@0 198 EnumerateData data = { aArenaStats, 0 };
michael@0 199 mFreeLists.EnumerateEntries(FreeListEnumerator, &data);
michael@0 200 aArenaStats->mOther += mallocSize - data.total;
michael@0 201 }

mercurial