Bug 1700051: part 33) Move `AdjustSoftBeginAndBuildSoftText` to `SoftText`. r=smaug
[gecko.git] / layout / base / nsPresArena.cpp
blob20e813d62669ff12ca9c16d03120a7759423a5e1
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 */
8 /* arena allocation for the frame tree and closely-related objects */
10 #include "nsPresArena.h"
12 #include "mozilla/Poison.h"
13 #include "nsDebug.h"
14 #include "nsDisplayList.h"
15 #include "nsPrintfCString.h"
16 #include "FrameLayerBuilder.h"
17 #include "mozilla/ArrayUtils.h"
18 #include "mozilla/ComputedStyle.h"
19 #include "mozilla/ComputedStyleInlines.h"
20 #include "nsWindowSizes.h"
22 #include <inttypes.h>
24 using namespace mozilla;
26 template <size_t ArenaSize, typename ObjectId, size_t ObjectIdCount>
27 nsPresArena<ArenaSize, ObjectId, ObjectIdCount>::~nsPresArena() {
28 #if defined(MOZ_HAVE_MEM_CHECKS)
29 for (FreeList* entry = mFreeLists; entry != ArrayEnd(mFreeLists); ++entry) {
30 for (void* result : entry->mEntries) {
31 MOZ_MAKE_MEM_UNDEFINED(result, entry->mEntrySize);
33 entry->mEntries.Clear();
35 #endif
38 template <size_t ArenaSize, typename ObjectId, size_t ObjectIdCount>
39 void* nsPresArena<ArenaSize, ObjectId, ObjectIdCount>::Allocate(ObjectId aCode,
40 size_t aSize) {
41 MOZ_ASSERT(NS_IsMainThread());
42 MOZ_ASSERT(aSize > 0, "PresArena cannot allocate zero bytes");
43 MOZ_ASSERT(size_t(aCode) < ArrayLength(mFreeLists));
45 // We only hand out aligned sizes
46 aSize = mPool.AlignedSize(aSize);
48 FreeList* list = &mFreeLists[size_t(aCode)];
50 nsTArray<void*>::index_type len = list->mEntries.Length();
51 if (list->mEntrySize == 0) {
52 MOZ_ASSERT(len == 0, "list with entries but no recorded size");
53 list->mEntrySize = aSize;
54 } else {
55 MOZ_ASSERT(list->mEntrySize == aSize,
56 "different sizes for same object type code");
59 void* result;
60 if (len > 0) {
61 // Remove from the end of the mEntries array to avoid memmoving entries,
62 // and use SetLengthAndRetainStorage to avoid a lot of malloc/free
63 // from ShrinkCapacity on smaller sizes. 500 pointers means the malloc size
64 // for the array is 4096 bytes or more on a 64-bit system. The next smaller
65 // size is 2048 (with jemalloc), which we consider not worth compacting.
66 result = list->mEntries.ElementAt(len - 1);
67 if (list->mEntries.Capacity() > 500) {
68 list->mEntries.RemoveElementAt(len - 1);
69 } else {
70 list->mEntries.SetLengthAndRetainStorage(len - 1);
72 #if defined(DEBUG)
74 MOZ_MAKE_MEM_DEFINED(result, list->mEntrySize);
75 char* p = reinterpret_cast<char*>(result);
76 char* limit = p + list->mEntrySize;
77 for (; p < limit; p += sizeof(uintptr_t)) {
78 uintptr_t val = *reinterpret_cast<uintptr_t*>(p);
79 if (val != mozPoisonValue()) {
80 MOZ_ReportAssertionFailure(
81 nsPrintfCString("PresArena: poison overwritten; "
82 "wanted %.16" PRIx64 " "
83 "found %.16" PRIx64 " "
84 "errors in bits %.16" PRIx64 " ",
85 uint64_t(mozPoisonValue()), uint64_t(val),
86 uint64_t(mozPoisonValue() ^ val))
87 .get(),
88 __FILE__, __LINE__);
89 MOZ_CRASH();
93 #endif
94 MOZ_MAKE_MEM_UNDEFINED(result, list->mEntrySize);
95 return result;
98 // Allocate a new chunk from the arena
99 list->mEntriesEverAllocated++;
100 return mPool.Allocate(aSize);
103 template <size_t ArenaSize, typename ObjectId, size_t ObjectIdCount>
104 void nsPresArena<ArenaSize, ObjectId, ObjectIdCount>::Free(ObjectId aCode,
105 void* aPtr) {
106 MOZ_ASSERT(NS_IsMainThread());
107 MOZ_ASSERT(size_t(aCode) < ArrayLength(mFreeLists));
109 // Try to recycle this entry.
110 FreeList* list = &mFreeLists[size_t(aCode)];
111 MOZ_ASSERT(list->mEntrySize > 0, "object of this type was never allocated");
113 mozWritePoison(aPtr, list->mEntrySize);
115 MOZ_MAKE_MEM_NOACCESS(aPtr, list->mEntrySize);
116 list->mEntries.AppendElement(aPtr);
119 template <size_t ArenaSize, typename ObjectId, size_t ObjectIdCount>
120 void nsPresArena<ArenaSize, ObjectId, ObjectIdCount>::AddSizeOfExcludingThis(
121 nsWindowSizes& aSizes, ArenaKind aKind) const {
122 // We do a complicated dance here because we want to measure the
123 // space taken up by the different kinds of objects in the arena,
124 // but we don't have pointers to those objects. And even if we did,
125 // we wouldn't be able to use mMallocSizeOf on them, since they were
126 // allocated out of malloc'd chunks of memory. So we compute the
127 // size of the arena as known by malloc and we add up the sizes of
128 // all the objects that we care about. Subtracting these two
129 // quantities gives us a catch-all "other" number, which includes
130 // slop in the arena itself as well as the size of objects that
131 // we've not measured explicitly.
133 size_t mallocSize = mPool.SizeOfExcludingThis(aSizes.mState.mMallocSizeOf);
135 size_t totalSizeInFreeLists = 0;
136 for (const FreeList* entry = mFreeLists; entry != ArrayEnd(mFreeLists);
137 ++entry) {
138 mallocSize += entry->SizeOfExcludingThis(aSizes.mState.mMallocSizeOf);
140 // Note that we're not measuring the size of the entries on the free
141 // list here. The free list knows how many objects we've allocated
142 // ever (which includes any objects that may be on the FreeList's
143 // |mEntries| at this point) and we're using that to determine the
144 // total size of objects allocated with a given ID.
145 size_t totalSize = entry->mEntrySize * entry->mEntriesEverAllocated;
147 if (aKind == ArenaKind::PresShell) {
148 switch (entry - mFreeLists) {
149 #define PRES_ARENA_OBJECT(name_) \
150 case eArenaObjectID_##name_: \
151 aSizes.mArenaSizes.NS_ARENA_SIZES_FIELD(name_) += totalSize; \
152 break;
153 #include "nsPresArenaObjectList.h"
154 #undef PRES_ARENA_OBJECT
155 default:
156 MOZ_ASSERT_UNREACHABLE("Unknown arena object type");
158 } else {
159 MOZ_ASSERT(aKind == ArenaKind::DisplayList);
160 switch (DisplayListArenaObjectId(entry - mFreeLists)) {
161 #define DISPLAY_LIST_ARENA_OBJECT(name_) \
162 case DisplayListArenaObjectId::name_: \
163 aSizes.mArenaSizes.NS_ARENA_SIZES_FIELD(name_) += totalSize; \
164 break;
165 #include "nsDisplayListArenaTypes.h"
166 #undef DISPLAY_LIST_ARENA_OBJECT
167 default:
168 MOZ_ASSERT_UNREACHABLE("Unknown display item arena type");
172 totalSizeInFreeLists += totalSize;
175 auto& field = aKind == ArenaKind::PresShell
176 ? aSizes.mLayoutPresShellSize
177 : aSizes.mLayoutRetainedDisplayListSize;
179 field += mallocSize - totalSizeInFreeLists;
182 // Explicitly instantiate templates for the used nsPresArena allocator sizes.
183 // This is needed because nsPresArena definition is split across multiple files.
184 template class nsPresArena<8192, ArenaObjectID, eArenaObjectID_COUNT>;
185 template class nsPresArena<32768, DisplayListArenaObjectId,
186 size_t(DisplayListArenaObjectId::COUNT)>;