Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : * vim: set ts=2 sw=2 et tw=78:
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 : */
7 :
8 : /* arena allocation for the frame tree and closely-related objects */
9 :
10 : #include "nsPresArena.h"
11 :
12 : #include "mozilla/Poison.h"
13 : #include "nsDebug.h"
14 : #include "nsArenaMemoryStats.h"
15 : #include "nsPrintfCString.h"
16 : #include "GeckoStyleContext.h"
17 : #include "FrameLayerBuilder.h"
18 : #include "mozilla/ArrayUtils.h"
19 :
20 : #include <inttypes.h>
21 :
22 : using namespace mozilla;
23 :
24 28 : nsPresArena::nsPresArena()
25 : {
26 28 : }
27 :
28 8 : nsPresArena::~nsPresArena()
29 : {
30 4 : ClearArenaRefPtrs();
31 :
32 : #if defined(MOZ_HAVE_MEM_CHECKS)
33 : for (FreeList* entry = mFreeLists; entry != ArrayEnd(mFreeLists); ++entry) {
34 : nsTArray<void*>::index_type len;
35 : while ((len = entry->mEntries.Length())) {
36 : void* result = entry->mEntries.ElementAt(len - 1);
37 : entry->mEntries.RemoveElementAt(len - 1);
38 : MOZ_MAKE_MEM_UNDEFINED(result, entry->mEntrySize);
39 : }
40 : }
41 : #endif
42 4 : }
43 :
44 : /* inline */ void
45 0 : nsPresArena::ClearArenaRefPtrWithoutDeregistering(void* aPtr,
46 : ArenaObjectID aObjectID)
47 : {
48 0 : switch (aObjectID) {
49 : #define PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT(name_) \
50 : case eArenaObjectID_##name_: \
51 : static_cast<ArenaRefPtr<name_>*>(aPtr)->ClearWithoutDeregistering(); \
52 : return;
53 : #include "nsPresArenaObjectList.h"
54 : #undef PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT
55 : default:
56 0 : break;
57 : }
58 0 : switch (aObjectID) {
59 : #define PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT(name_) \
60 : case eArenaObjectID_##name_: \
61 : MOZ_ASSERT(false, #name_ " must be declared in nsPresArenaObjectList.h "\
62 : "with PRES_ARENA_OBJECT_SUPPORTS_ARENAREFPTR"); \
63 : break;
64 : #include "nsPresArenaObjectList.h"
65 : #undef PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT
66 : default:
67 0 : MOZ_ASSERT(false, "unexpected ArenaObjectID value");
68 : break;
69 : }
70 : }
71 :
72 : void
73 8 : nsPresArena::ClearArenaRefPtrs()
74 : {
75 8 : for (auto iter = mArenaRefPtrs.Iter(); !iter.Done(); iter.Next()) {
76 0 : void* ptr = iter.Key();
77 0 : ArenaObjectID id = iter.UserData();
78 0 : ClearArenaRefPtrWithoutDeregistering(ptr, id);
79 : }
80 8 : mArenaRefPtrs.Clear();
81 8 : }
82 :
83 : void
84 2 : nsPresArena::ClearArenaRefPtrs(ArenaObjectID aObjectID)
85 : {
86 2 : for (auto iter = mArenaRefPtrs.Iter(); !iter.Done(); iter.Next()) {
87 0 : void* ptr = iter.Key();
88 0 : ArenaObjectID id = iter.UserData();
89 0 : if (id == aObjectID) {
90 0 : ClearArenaRefPtrWithoutDeregistering(ptr, id);
91 0 : iter.Remove();
92 : }
93 : }
94 2 : }
95 :
96 : void*
97 11959 : nsPresArena::Allocate(uint32_t aCode, size_t aSize)
98 : {
99 11959 : MOZ_ASSERT(aSize > 0, "PresArena cannot allocate zero bytes");
100 11959 : MOZ_ASSERT(aCode < ArrayLength(mFreeLists));
101 :
102 : // We only hand out aligned sizes
103 11959 : aSize = mPool.AlignedSize(aSize);
104 :
105 11959 : FreeList* list = &mFreeLists[aCode];
106 :
107 11959 : nsTArray<void*>::index_type len = list->mEntries.Length();
108 11959 : if (list->mEntrySize == 0) {
109 720 : MOZ_ASSERT(len == 0, "list with entries but no recorded size");
110 720 : list->mEntrySize = aSize;
111 : } else {
112 11239 : MOZ_ASSERT(list->mEntrySize == aSize,
113 : "different sizes for same object type code");
114 : }
115 :
116 : void* result;
117 11959 : if (len > 0) {
118 : // Remove from the end of the mEntries array to avoid memmoving entries,
119 : // and use SetLengthAndRetainStorage to avoid a lot of malloc/free
120 : // from ShrinkCapacity on smaller sizes. 500 pointers means the malloc size
121 : // for the array is 4096 bytes or more on a 64-bit system. The next smaller
122 : // size is 2048 (with jemalloc), which we consider not worth compacting.
123 4812 : result = list->mEntries.ElementAt(len - 1);
124 4812 : if (list->mEntries.Capacity() > 500) {
125 245 : list->mEntries.RemoveElementAt(len - 1);
126 : } else {
127 4567 : list->mEntries.SetLengthAndRetainStorage(len - 1);
128 : }
129 : #if defined(DEBUG)
130 : {
131 : MOZ_MAKE_MEM_DEFINED(result, list->mEntrySize);
132 4812 : char* p = reinterpret_cast<char*>(result);
133 4812 : char* limit = p + list->mEntrySize;
134 153782 : for (; p < limit; p += sizeof(uintptr_t)) {
135 74485 : uintptr_t val = *reinterpret_cast<uintptr_t*>(p);
136 74485 : if (val != mozPoisonValue()) {
137 0 : MOZ_ReportAssertionFailure(
138 0 : nsPrintfCString("PresArena: poison overwritten; "
139 : "wanted %.16" PRIx64 " "
140 : "found %.16" PRIx64 " "
141 : "errors in bits %.16" PRIx64 " ",
142 0 : uint64_t(mozPoisonValue()),
143 : uint64_t(val),
144 0 : uint64_t(mozPoisonValue() ^ val)).get(),
145 0 : __FILE__, __LINE__);
146 0 : MOZ_CRASH();
147 : }
148 : }
149 : }
150 : #endif
151 : MOZ_MAKE_MEM_UNDEFINED(result, list->mEntrySize);
152 4812 : return result;
153 : }
154 :
155 : // Allocate a new chunk from the arena
156 7147 : list->mEntriesEverAllocated++;
157 7147 : return mPool.Allocate(aSize);
158 : }
159 :
160 : void
161 6852 : nsPresArena::Free(uint32_t aCode, void* aPtr)
162 : {
163 6852 : MOZ_ASSERT(aCode < ArrayLength(mFreeLists));
164 :
165 : // Try to recycle this entry.
166 6852 : FreeList* list = &mFreeLists[aCode];
167 6852 : MOZ_ASSERT(list->mEntrySize > 0, "object of this type was never allocated");
168 :
169 6852 : mozWritePoison(aPtr, list->mEntrySize);
170 :
171 : MOZ_MAKE_MEM_NOACCESS(aPtr, list->mEntrySize);
172 6852 : list->mEntries.AppendElement(aPtr);
173 6852 : }
174 :
175 : void
176 21 : nsPresArena::AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
177 : nsArenaMemoryStats* aArenaStats)
178 : {
179 : // We do a complicated dance here because we want to measure the
180 : // space taken up by the different kinds of objects in the arena,
181 : // but we don't have pointers to those objects. And even if we did,
182 : // we wouldn't be able to use aMallocSizeOf on them, since they were
183 : // allocated out of malloc'd chunks of memory. So we compute the
184 : // size of the arena as known by malloc and we add up the sizes of
185 : // all the objects that we care about. Subtracting these two
186 : // quantities gives us a catch-all "other" number, which includes
187 : // slop in the arena itself as well as the size of objects that
188 : // we've not measured explicitly.
189 :
190 21 : size_t mallocSize = mPool.SizeOfExcludingThis(aMallocSizeOf);
191 :
192 21 : size_t totalSizeInFreeLists = 0;
193 4494 : for (FreeList* entry = mFreeLists; entry != ArrayEnd(mFreeLists); ++entry) {
194 4473 : mallocSize += entry->SizeOfExcludingThis(aMallocSizeOf);
195 :
196 : // Note that we're not measuring the size of the entries on the free
197 : // list here. The free list knows how many objects we've allocated
198 : // ever (which includes any objects that may be on the FreeList's
199 : // |mEntries| at this point) and we're using that to determine the
200 : // total size of objects allocated with a given ID.
201 4473 : size_t totalSize = entry->mEntrySize * entry->mEntriesEverAllocated;
202 : size_t* p;
203 :
204 4473 : switch (entry - mFreeLists) {
205 : #define FRAME_ID(classname, ...) \
206 : case nsQueryFrame::classname##_id: \
207 : p = &aArenaStats->FRAME_ID_STAT_FIELD(classname); \
208 : break;
209 : #define ABSTRACT_FRAME_ID(...)
210 : #include "nsFrameIdList.h"
211 : #undef FRAME_ID
212 : #undef ABSTRACT_FRAME_ID
213 : case eArenaObjectID_nsLineBox:
214 21 : p = &aArenaStats->mLineBoxes;
215 21 : break;
216 : case eArenaObjectID_nsRuleNode:
217 21 : p = &aArenaStats->mRuleNodes;
218 21 : break;
219 : case eArenaObjectID_GeckoStyleContext:
220 21 : p = &aArenaStats->mStyleContexts;
221 21 : break;
222 : #define STYLE_STRUCT(name_, checkdata_cb_) \
223 : case eArenaObjectID_nsStyle##name_:
224 : #include "nsStyleStructList.h"
225 : #undef STYLE_STRUCT
226 504 : p = &aArenaStats->mStyleStructs;
227 504 : break;
228 : default:
229 903 : continue;
230 : }
231 :
232 3570 : *p += totalSize;
233 3570 : totalSizeInFreeLists += totalSize;
234 : }
235 :
236 21 : aArenaStats->mOther += mallocSize - totalSizeInFreeLists;
237 21 : }
|