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/.
8 /* arena allocation for the frame tree and closely-related objects */
10 #include "nsPresArena.h"
12 #include "mozilla/Poison.h"
14 #include "nsDisplayList.h"
15 #include "nsPrintfCString.h"
16 #include "mozilla/ArrayUtils.h"
17 #include "mozilla/ComputedStyle.h"
18 #include "mozilla/ComputedStyleInlines.h"
19 #include "nsWindowSizes.h"
23 using namespace mozilla
;
25 template <size_t ArenaSize
, typename ObjectId
, size_t ObjectIdCount
>
26 nsPresArena
<ArenaSize
, ObjectId
, ObjectIdCount
>::~nsPresArena() {
27 #if defined(MOZ_HAVE_MEM_CHECKS)
28 for (FreeList
* entry
= mFreeLists
; entry
!= ArrayEnd(mFreeLists
); ++entry
) {
29 for (void* result
: entry
->mEntries
) {
30 MOZ_MAKE_MEM_UNDEFINED(result
, entry
->mEntrySize
);
32 entry
->mEntries
.Clear();
37 template <size_t ArenaSize
, typename ObjectId
, size_t ObjectIdCount
>
38 void* nsPresArena
<ArenaSize
, ObjectId
, ObjectIdCount
>::Allocate(ObjectId aCode
,
40 MOZ_ASSERT(NS_IsMainThread());
41 MOZ_ASSERT(aSize
> 0, "PresArena cannot allocate zero bytes");
42 MOZ_ASSERT(size_t(aCode
) < ArrayLength(mFreeLists
));
44 // We only hand out aligned sizes
45 aSize
= mPool
.AlignedSize(aSize
);
47 FreeList
* list
= &mFreeLists
[size_t(aCode
)];
49 nsTArray
<void*>::index_type len
= list
->mEntries
.Length();
50 if (list
->mEntrySize
== 0) {
51 MOZ_ASSERT(len
== 0, "list with entries but no recorded size");
52 list
->mEntrySize
= aSize
;
54 MOZ_ASSERT(list
->mEntrySize
== aSize
,
55 "different sizes for same object type code");
60 // Remove from the end of the mEntries array to avoid memmoving entries,
61 // and use SetLengthAndRetainStorage to avoid a lot of malloc/free
62 // from ShrinkCapacity on smaller sizes. 500 pointers means the malloc size
63 // for the array is 4096 bytes or more on a 64-bit system. The next smaller
64 // size is 2048 (with jemalloc), which we consider not worth compacting.
65 result
= list
->mEntries
.Elements()[len
- 1];
66 if (list
->mEntries
.Capacity() > 500) {
67 list
->mEntries
.RemoveElementAtUnsafe(len
- 1);
69 list
->mEntries
.SetLengthAndRetainStorage(len
- 1);
73 MOZ_MAKE_MEM_DEFINED(result
, list
->mEntrySize
);
74 char* p
= reinterpret_cast<char*>(result
);
75 char* limit
= p
+ list
->mEntrySize
;
76 for (; p
< limit
; p
+= sizeof(uintptr_t)) {
77 uintptr_t val
= *reinterpret_cast<uintptr_t*>(p
);
78 if (val
!= mozPoisonValue()) {
79 MOZ_ReportAssertionFailure(
80 nsPrintfCString("PresArena: poison overwritten; "
81 "wanted %.16" PRIx64
" "
82 "found %.16" PRIx64
" "
83 "errors in bits %.16" PRIx64
" ",
84 uint64_t(mozPoisonValue()), uint64_t(val
),
85 uint64_t(mozPoisonValue() ^ val
))
93 MOZ_MAKE_MEM_UNDEFINED(result
, list
->mEntrySize
);
97 // Allocate a new chunk from the arena
98 list
->mEntriesEverAllocated
++;
99 return mPool
.Allocate(aSize
);
102 template <size_t ArenaSize
, typename ObjectId
, size_t ObjectIdCount
>
103 void nsPresArena
<ArenaSize
, ObjectId
, ObjectIdCount
>::Free(ObjectId aCode
,
105 MOZ_ASSERT(NS_IsMainThread());
106 MOZ_ASSERT(size_t(aCode
) < ArrayLength(mFreeLists
));
108 // Try to recycle this entry.
109 FreeList
* list
= &mFreeLists
[size_t(aCode
)];
110 MOZ_ASSERT(list
->mEntrySize
> 0, "object of this type was never allocated");
112 mozWritePoison(aPtr
, list
->mEntrySize
);
114 MOZ_MAKE_MEM_NOACCESS(aPtr
, list
->mEntrySize
);
115 list
->mEntries
.AppendElement(aPtr
);
118 template <size_t ArenaSize
, typename ObjectId
, size_t ObjectIdCount
>
119 void nsPresArena
<ArenaSize
, ObjectId
, ObjectIdCount
>::AddSizeOfExcludingThis(
120 nsWindowSizes
& aSizes
, ArenaKind aKind
) const {
121 // We do a complicated dance here because we want to measure the
122 // space taken up by the different kinds of objects in the arena,
123 // but we don't have pointers to those objects. And even if we did,
124 // we wouldn't be able to use mMallocSizeOf on them, since they were
125 // allocated out of malloc'd chunks of memory. So we compute the
126 // size of the arena as known by malloc and we add up the sizes of
127 // all the objects that we care about. Subtracting these two
128 // quantities gives us a catch-all "other" number, which includes
129 // slop in the arena itself as well as the size of objects that
130 // we've not measured explicitly.
132 size_t mallocSize
= mPool
.SizeOfExcludingThis(aSizes
.mState
.mMallocSizeOf
);
134 size_t totalSizeInFreeLists
= 0;
135 for (const FreeList
* entry
= mFreeLists
; entry
!= ArrayEnd(mFreeLists
);
137 mallocSize
+= entry
->SizeOfExcludingThis(aSizes
.mState
.mMallocSizeOf
);
139 // Note that we're not measuring the size of the entries on the free
140 // list here. The free list knows how many objects we've allocated
141 // ever (which includes any objects that may be on the FreeList's
142 // |mEntries| at this point) and we're using that to determine the
143 // total size of objects allocated with a given ID.
144 size_t totalSize
= entry
->mEntrySize
* entry
->mEntriesEverAllocated
;
146 if (aKind
== ArenaKind::PresShell
) {
147 switch (entry
- mFreeLists
) {
148 #define PRES_ARENA_OBJECT(name_) \
149 case eArenaObjectID_##name_: \
150 aSizes.mArenaSizes.NS_ARENA_SIZES_FIELD(name_) += totalSize; \
152 #include "nsPresArenaObjectList.h"
153 #undef PRES_ARENA_OBJECT
155 MOZ_ASSERT_UNREACHABLE("Unknown arena object type");
158 MOZ_ASSERT(aKind
== ArenaKind::DisplayList
);
159 switch (DisplayListArenaObjectId(entry
- mFreeLists
)) {
160 #define DISPLAY_LIST_ARENA_OBJECT(name_) \
161 case DisplayListArenaObjectId::name_: \
162 aSizes.mArenaSizes.NS_ARENA_SIZES_FIELD(name_) += totalSize; \
164 #include "nsDisplayListArenaTypes.h"
165 #undef DISPLAY_LIST_ARENA_OBJECT
167 MOZ_ASSERT_UNREACHABLE("Unknown display item arena type");
171 totalSizeInFreeLists
+= totalSize
;
174 auto& field
= aKind
== ArenaKind::PresShell
175 ? aSizes
.mLayoutPresShellSize
176 : aSizes
.mLayoutRetainedDisplayListSize
;
178 field
+= mallocSize
- totalSizeInFreeLists
;
181 // Explicitly instantiate templates for the used nsPresArena allocator sizes.
182 // This is needed because nsPresArena definition is split across multiple files.
183 template class nsPresArena
<8192, ArenaObjectID
, eArenaObjectID_COUNT
>;
184 template class nsPresArena
<32768, DisplayListArenaObjectId
,
185 size_t(DisplayListArenaObjectId::COUNT
)>;