1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/base/nsPresArena.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,201 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * vim: set ts=2 sw=2 et tw=78: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. 1.9 + */ 1.10 + 1.11 +/* arena allocation for the frame tree and closely-related objects */ 1.12 + 1.13 +// Even on 32-bit systems, we allocate objects from the frame arena 1.14 +// that require 8-byte alignment. The cast to uintptr_t is needed 1.15 +// because plarena isn't as careful about mask construction as it 1.16 +// ought to be. 1.17 +#define ALIGN_SHIFT 3 1.18 +#define PL_ARENA_CONST_ALIGN_MASK ((uintptr_t(1) << ALIGN_SHIFT) - 1) 1.19 +#include "plarena.h" 1.20 +// plarena.h needs to be included first to make it use the above 1.21 +// PL_ARENA_CONST_ALIGN_MASK in this file. 1.22 + 1.23 +#include "nsPresArena.h" 1.24 + 1.25 +#include "mozilla/Poison.h" 1.26 +#include "nsDebug.h" 1.27 +#include "nsArenaMemoryStats.h" 1.28 +#include "nsPrintfCString.h" 1.29 + 1.30 +// Size to use for PLArena block allocations. 1.31 +static const size_t ARENA_PAGE_SIZE = 8192; 1.32 + 1.33 +nsPresArena::nsPresArena() 1.34 +{ 1.35 + PL_INIT_ARENA_POOL(&mPool, "PresArena", ARENA_PAGE_SIZE); 1.36 +} 1.37 + 1.38 +nsPresArena::~nsPresArena() 1.39 +{ 1.40 +#if defined(MOZ_HAVE_MEM_CHECKS) 1.41 + mFreeLists.EnumerateEntries(UnpoisonFreeList, nullptr); 1.42 +#endif 1.43 + PL_FinishArenaPool(&mPool); 1.44 +} 1.45 + 1.46 +NS_HIDDEN_(void*) 1.47 +nsPresArena::Allocate(uint32_t aCode, size_t aSize) 1.48 +{ 1.49 + NS_ABORT_IF_FALSE(aSize > 0, "PresArena cannot allocate zero bytes"); 1.50 + 1.51 + // We only hand out aligned sizes 1.52 + aSize = PL_ARENA_ALIGN(&mPool, aSize); 1.53 + 1.54 + // If there is no free-list entry for this type already, we have 1.55 + // to create one now, to record its size. 1.56 + FreeList* list = mFreeLists.PutEntry(aCode); 1.57 + 1.58 + nsTArray<void*>::index_type len = list->mEntries.Length(); 1.59 + if (list->mEntrySize == 0) { 1.60 + NS_ABORT_IF_FALSE(len == 0, "list with entries but no recorded size"); 1.61 + list->mEntrySize = aSize; 1.62 + } else { 1.63 + NS_ABORT_IF_FALSE(list->mEntrySize == aSize, 1.64 + "different sizes for same object type code"); 1.65 + } 1.66 + 1.67 + void* result; 1.68 + if (len > 0) { 1.69 + // LIFO behavior for best cache utilization 1.70 + result = list->mEntries.ElementAt(len - 1); 1.71 + list->mEntries.RemoveElementAt(len - 1); 1.72 +#if defined(DEBUG) 1.73 + { 1.74 + MOZ_MAKE_MEM_DEFINED(result, list->mEntrySize); 1.75 + char* p = reinterpret_cast<char*>(result); 1.76 + char* limit = p + list->mEntrySize; 1.77 + for (; p < limit; p += sizeof(uintptr_t)) { 1.78 + uintptr_t val = *reinterpret_cast<uintptr_t*>(p); 1.79 + NS_ABORT_IF_FALSE(val == mozPoisonValue(), 1.80 + nsPrintfCString("PresArena: poison overwritten; " 1.81 + "wanted %.16llx " 1.82 + "found %.16llx " 1.83 + "errors in bits %.16llx", 1.84 + uint64_t(mozPoisonValue()), 1.85 + uint64_t(val), 1.86 + uint64_t(mozPoisonValue() ^ val) 1.87 + ).get()); 1.88 + } 1.89 + } 1.90 +#endif 1.91 + MOZ_MAKE_MEM_UNDEFINED(result, list->mEntrySize); 1.92 + return result; 1.93 + } 1.94 + 1.95 + // Allocate a new chunk from the arena 1.96 + list->mEntriesEverAllocated++; 1.97 + PL_ARENA_ALLOCATE(result, &mPool, aSize); 1.98 + if (!result) { 1.99 + NS_RUNTIMEABORT("out of memory"); 1.100 + } 1.101 + return result; 1.102 +} 1.103 + 1.104 +NS_HIDDEN_(void) 1.105 +nsPresArena::Free(uint32_t aCode, void* aPtr) 1.106 +{ 1.107 + // Try to recycle this entry. 1.108 + FreeList* list = mFreeLists.GetEntry(aCode); 1.109 + NS_ABORT_IF_FALSE(list, "no free list for pres arena object"); 1.110 + NS_ABORT_IF_FALSE(list->mEntrySize > 0, "PresArena cannot free zero bytes"); 1.111 + 1.112 + mozWritePoison(aPtr, list->mEntrySize); 1.113 + 1.114 + MOZ_MAKE_MEM_NOACCESS(aPtr, list->mEntrySize); 1.115 + list->mEntries.AppendElement(aPtr); 1.116 +} 1.117 + 1.118 +/* static */ size_t 1.119 +nsPresArena::SizeOfFreeListEntryExcludingThis( 1.120 + FreeList* aEntry, mozilla::MallocSizeOf aMallocSizeOf, void*) 1.121 +{ 1.122 + return aEntry->mEntries.SizeOfExcludingThis(aMallocSizeOf); 1.123 +} 1.124 + 1.125 +struct EnumerateData { 1.126 + nsArenaMemoryStats* stats; 1.127 + size_t total; 1.128 +}; 1.129 + 1.130 +#if defined(MOZ_HAVE_MEM_CHECKS) 1.131 +/* static */ PLDHashOperator 1.132 +nsPresArena::UnpoisonFreeList(FreeList* aEntry, void*) 1.133 +{ 1.134 + nsTArray<void*>::index_type len; 1.135 + while ((len = aEntry->mEntries.Length())) { 1.136 + void* result = aEntry->mEntries.ElementAt(len - 1); 1.137 + aEntry->mEntries.RemoveElementAt(len - 1); 1.138 + MOZ_MAKE_MEM_UNDEFINED(result, aEntry->mEntrySize); 1.139 + } 1.140 + return PL_DHASH_NEXT; 1.141 +} 1.142 +#endif 1.143 + 1.144 +/* static */ PLDHashOperator 1.145 +nsPresArena::FreeListEnumerator(FreeList* aEntry, void* aData) 1.146 +{ 1.147 + EnumerateData* data = static_cast<EnumerateData*>(aData); 1.148 + // Note that we're not measuring the size of the entries on the free 1.149 + // list here. The free list knows how many objects we've allocated 1.150 + // ever (which includes any objects that may be on the FreeList's 1.151 + // |mEntries| at this point) and we're using that to determine the 1.152 + // total size of objects allocated with a given ID. 1.153 + size_t totalSize = aEntry->mEntrySize * aEntry->mEntriesEverAllocated; 1.154 + size_t* p; 1.155 + 1.156 + switch (NS_PTR_TO_INT32(aEntry->mKey)) { 1.157 +#define FRAME_ID(classname) \ 1.158 + case nsQueryFrame::classname##_id: \ 1.159 + p = &data->stats->FRAME_ID_STAT_FIELD(classname); \ 1.160 + break; 1.161 +#include "nsFrameIdList.h" 1.162 +#undef FRAME_ID 1.163 + case nsLineBox_id: 1.164 + p = &data->stats->mLineBoxes; 1.165 + break; 1.166 + case nsRuleNode_id: 1.167 + p = &data->stats->mRuleNodes; 1.168 + break; 1.169 + case nsStyleContext_id: 1.170 + p = &data->stats->mStyleContexts; 1.171 + break; 1.172 + default: 1.173 + return PL_DHASH_NEXT; 1.174 + } 1.175 + 1.176 + *p += totalSize; 1.177 + data->total += totalSize; 1.178 + 1.179 + return PL_DHASH_NEXT; 1.180 +} 1.181 + 1.182 +void 1.183 +nsPresArena::AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf, 1.184 + nsArenaMemoryStats* aArenaStats) 1.185 +{ 1.186 + // We do a complicated dance here because we want to measure the 1.187 + // space taken up by the different kinds of objects in the arena, 1.188 + // but we don't have pointers to those objects. And even if we did, 1.189 + // we wouldn't be able to use aMallocSizeOf on them, since they were 1.190 + // allocated out of malloc'd chunks of memory. So we compute the 1.191 + // size of the arena as known by malloc and we add up the sizes of 1.192 + // all the objects that we care about. Subtracting these two 1.193 + // quantities gives us a catch-all "other" number, which includes 1.194 + // slop in the arena itself as well as the size of objects that 1.195 + // we've not measured explicitly. 1.196 + 1.197 + size_t mallocSize = PL_SizeOfArenaPoolExcludingPool(&mPool, aMallocSizeOf); 1.198 + mallocSize += mFreeLists.SizeOfExcludingThis(SizeOfFreeListEntryExcludingThis, 1.199 + aMallocSizeOf); 1.200 + 1.201 + EnumerateData data = { aArenaStats, 0 }; 1.202 + mFreeLists.EnumerateEntries(FreeListEnumerator, &data); 1.203 + aArenaStats->mOther += mallocSize - data.total; 1.204 +}