]>
Commit | Line | Data |
---|---|---|
14957cd0 A |
1 | /* |
2 | * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) | |
3 | * Copyright (C) 2001 Peter Kelly (pmk@post.com) | |
4 | * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011 Apple Inc. All rights reserved. | |
5 | * | |
6 | * This library is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU Lesser General Public | |
8 | * License as published by the Free Software Foundation; either | |
9 | * version 2 of the License, or (at your option) any later version. | |
10 | * | |
11 | * This library is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * Lesser General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU Lesser General Public | |
17 | * License along with this library; if not, write to the Free Software | |
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
19 | * | |
20 | */ | |
21 | ||
22 | #ifndef MarkedSpace_h | |
23 | #define MarkedSpace_h | |
24 | ||
25 | #include "MachineStackMarker.h" | |
6fe7ccc8 | 26 | #include "MarkedAllocator.h" |
14957cd0 | 27 | #include "MarkedBlock.h" |
6fe7ccc8 | 28 | #include "MarkedBlockSet.h" |
81345200 | 29 | #include <array> |
6fe7ccc8 | 30 | #include <wtf/PageAllocationAligned.h> |
14957cd0 A |
31 | #include <wtf/Bitmap.h> |
32 | #include <wtf/DoublyLinkedList.h> | |
14957cd0 A |
33 | #include <wtf/HashSet.h> |
34 | #include <wtf/Noncopyable.h> | |
35 | #include <wtf/Vector.h> | |
36 | ||
14957cd0 A |
37 | namespace JSC { |
38 | ||
81345200 | 39 | class DelayedReleaseScope; |
6fe7ccc8 | 40 | class Heap; |
81345200 | 41 | class HeapIterationScope; |
6fe7ccc8 A |
42 | class JSCell; |
43 | class LiveObjectIterator; | |
44 | class LLIntOffsetsExtractor; | |
45 | class WeakGCHandle; | |
46 | class SlotVisitor; | |
47 | ||
93a37866 | 48 | struct ClearMarks : MarkedBlock::VoidFunctor { |
81345200 A |
49 | void operator()(MarkedBlock* block) |
50 | { | |
51 | block->clearMarks(); | |
52 | } | |
53 | }; | |
54 | ||
55 | struct ClearRememberedSet : MarkedBlock::VoidFunctor { | |
56 | void operator()(MarkedBlock* block) | |
57 | { | |
58 | block->clearRememberedSet(); | |
59 | } | |
93a37866 A |
60 | }; |
61 | ||
62 | struct Sweep : MarkedBlock::VoidFunctor { | |
63 | void operator()(MarkedBlock* block) { block->sweep(); } | |
64 | }; | |
65 | ||
81345200 A |
66 | struct ZombifySweep : MarkedBlock::VoidFunctor { |
67 | void operator()(MarkedBlock* block) | |
68 | { | |
69 | if (block->needsSweeping()) | |
70 | block->sweep(); | |
71 | } | |
72 | }; | |
73 | ||
93a37866 A |
74 | struct MarkCount : MarkedBlock::CountFunctor { |
75 | void operator()(MarkedBlock* block) { count(block->markCount()); } | |
76 | }; | |
77 | ||
78 | struct Size : MarkedBlock::CountFunctor { | |
79 | void operator()(MarkedBlock* block) { count(block->markCount() * block->cellSize()); } | |
80 | }; | |
81 | ||
6fe7ccc8 A |
82 | class MarkedSpace { |
83 | WTF_MAKE_NONCOPYABLE(MarkedSpace); | |
84 | public: | |
6fe7ccc8 | 85 | MarkedSpace(Heap*); |
93a37866 A |
86 | ~MarkedSpace(); |
87 | void lastChanceToFinalize(); | |
6fe7ccc8 A |
88 | |
89 | MarkedAllocator& firstAllocator(); | |
90 | MarkedAllocator& allocatorFor(size_t); | |
93a37866 A |
91 | MarkedAllocator& immortalStructureDestructorAllocatorFor(size_t); |
92 | MarkedAllocator& normalDestructorAllocatorFor(size_t); | |
93 | void* allocateWithNormalDestructor(size_t); | |
94 | void* allocateWithImmortalStructureDestructor(size_t); | |
6fe7ccc8 | 95 | void* allocateWithoutDestructor(size_t); |
93a37866 | 96 | |
6fe7ccc8 A |
97 | void resetAllocators(); |
98 | ||
93a37866 A |
99 | void visitWeakSets(HeapRootVisitor&); |
100 | void reapWeakSets(); | |
101 | ||
6fe7ccc8 | 102 | MarkedBlockSet& blocks() { return m_blocks; } |
81345200 A |
103 | |
104 | void willStartIterating(); | |
105 | bool isIterating() { return m_isIterating; } | |
106 | void didFinishIterating(); | |
107 | ||
108 | void stopAllocating(); | |
109 | void resumeAllocating(); // If we just stopped allocation but we didn't do a collection, we need to resume allocation. | |
6fe7ccc8 A |
110 | |
111 | typedef HashSet<MarkedBlock*>::iterator BlockIterator; | |
112 | ||
81345200 A |
113 | template<typename Functor> typename Functor::ReturnType forEachLiveCell(HeapIterationScope&, Functor&); |
114 | template<typename Functor> typename Functor::ReturnType forEachLiveCell(HeapIterationScope&); | |
115 | template<typename Functor> typename Functor::ReturnType forEachDeadCell(HeapIterationScope&, Functor&); | |
116 | template<typename Functor> typename Functor::ReturnType forEachDeadCell(HeapIterationScope&); | |
6fe7ccc8 A |
117 | template<typename Functor> typename Functor::ReturnType forEachBlock(Functor&); |
118 | template<typename Functor> typename Functor::ReturnType forEachBlock(); | |
119 | ||
120 | void shrink(); | |
93a37866 A |
121 | void freeBlock(MarkedBlock*); |
122 | void freeOrShrinkBlock(MarkedBlock*); | |
6fe7ccc8 A |
123 | |
124 | void didAddBlock(MarkedBlock*); | |
125 | void didConsumeFreeList(MarkedBlock*); | |
81345200 | 126 | void didAllocateInBlock(MarkedBlock*); |
6fe7ccc8 | 127 | |
93a37866 | 128 | void clearMarks(); |
81345200 A |
129 | void clearRememberedSet(); |
130 | void clearNewlyAllocated(); | |
93a37866 | 131 | void sweep(); |
81345200 | 132 | void zombifySweep(); |
93a37866 A |
133 | size_t objectCount(); |
134 | size_t size(); | |
135 | size_t capacity(); | |
136 | ||
6fe7ccc8 A |
137 | bool isPagedOut(double deadline); |
138 | ||
81345200 A |
139 | #if USE(CF) |
140 | template<typename T> void releaseSoon(RetainPtr<T>&&); | |
141 | #endif | |
142 | ||
6fe7ccc8 | 143 | private: |
81345200 | 144 | friend class DelayedReleaseScope; |
6fe7ccc8 | 145 | friend class LLIntOffsetsExtractor; |
93a37866 | 146 | |
81345200 A |
147 | template<typename Functor> void forEachAllocator(Functor&); |
148 | template<typename Functor> void forEachAllocator(); | |
149 | ||
93a37866 | 150 | // [ 32... 128 ] |
6fe7ccc8 | 151 | static const size_t preciseStep = MarkedBlock::atomSize; |
93a37866 | 152 | static const size_t preciseCutoff = 128; |
6fe7ccc8 A |
153 | static const size_t preciseCount = preciseCutoff / preciseStep; |
154 | ||
93a37866 A |
155 | // [ 1024... blockSize ] |
156 | static const size_t impreciseStep = 2 * preciseCutoff; | |
157 | static const size_t impreciseCutoff = MarkedBlock::blockSize / 2; | |
6fe7ccc8 A |
158 | static const size_t impreciseCount = impreciseCutoff / impreciseStep; |
159 | ||
160 | struct Subspace { | |
81345200 A |
161 | std::array<MarkedAllocator, preciseCount> preciseAllocators; |
162 | std::array<MarkedAllocator, impreciseCount> impreciseAllocators; | |
93a37866 | 163 | MarkedAllocator largeAllocator; |
14957cd0 A |
164 | }; |
165 | ||
93a37866 A |
166 | Subspace m_normalDestructorSpace; |
167 | Subspace m_immortalStructureDestructorSpace; | |
6fe7ccc8 A |
168 | Subspace m_normalSpace; |
169 | ||
170 | Heap* m_heap; | |
81345200 A |
171 | size_t m_capacity; |
172 | bool m_isIterating; | |
6fe7ccc8 | 173 | MarkedBlockSet m_blocks; |
81345200 A |
174 | Vector<MarkedBlock*> m_blocksWithNewObjects; |
175 | ||
176 | DelayedReleaseScope* m_currentDelayedReleaseScope; | |
6fe7ccc8 A |
177 | }; |
178 | ||
81345200 | 179 | template<typename Functor> inline typename Functor::ReturnType MarkedSpace::forEachLiveCell(HeapIterationScope&, Functor& functor) |
6fe7ccc8 | 180 | { |
81345200 | 181 | ASSERT(isIterating()); |
6fe7ccc8 A |
182 | BlockIterator end = m_blocks.set().end(); |
183 | for (BlockIterator it = m_blocks.set().begin(); it != end; ++it) | |
93a37866 | 184 | (*it)->forEachLiveCell(functor); |
6fe7ccc8 A |
185 | return functor.returnValue(); |
186 | } | |
187 | ||
81345200 | 188 | template<typename Functor> inline typename Functor::ReturnType MarkedSpace::forEachLiveCell(HeapIterationScope& scope) |
6fe7ccc8 A |
189 | { |
190 | Functor functor; | |
81345200 | 191 | return forEachLiveCell(scope, functor); |
6fe7ccc8 A |
192 | } |
193 | ||
81345200 | 194 | template<typename Functor> inline typename Functor::ReturnType MarkedSpace::forEachDeadCell(HeapIterationScope&, Functor& functor) |
6fe7ccc8 | 195 | { |
81345200 | 196 | ASSERT(isIterating()); |
93a37866 A |
197 | BlockIterator end = m_blocks.set().end(); |
198 | for (BlockIterator it = m_blocks.set().begin(); it != end; ++it) | |
199 | (*it)->forEachDeadCell(functor); | |
200 | return functor.returnValue(); | |
201 | } | |
202 | ||
81345200 | 203 | template<typename Functor> inline typename Functor::ReturnType MarkedSpace::forEachDeadCell(HeapIterationScope& scope) |
93a37866 A |
204 | { |
205 | Functor functor; | |
81345200 | 206 | return forEachDeadCell(scope, functor); |
6fe7ccc8 A |
207 | } |
208 | ||
209 | inline MarkedAllocator& MarkedSpace::allocatorFor(size_t bytes) | |
210 | { | |
93a37866 | 211 | ASSERT(bytes); |
6fe7ccc8 A |
212 | if (bytes <= preciseCutoff) |
213 | return m_normalSpace.preciseAllocators[(bytes - 1) / preciseStep]; | |
93a37866 A |
214 | if (bytes <= impreciseCutoff) |
215 | return m_normalSpace.impreciseAllocators[(bytes - 1) / impreciseStep]; | |
216 | return m_normalSpace.largeAllocator; | |
6fe7ccc8 A |
217 | } |
218 | ||
93a37866 | 219 | inline MarkedAllocator& MarkedSpace::immortalStructureDestructorAllocatorFor(size_t bytes) |
6fe7ccc8 | 220 | { |
93a37866 A |
221 | ASSERT(bytes); |
222 | if (bytes <= preciseCutoff) | |
223 | return m_immortalStructureDestructorSpace.preciseAllocators[(bytes - 1) / preciseStep]; | |
224 | if (bytes <= impreciseCutoff) | |
225 | return m_immortalStructureDestructorSpace.impreciseAllocators[(bytes - 1) / impreciseStep]; | |
226 | return m_immortalStructureDestructorSpace.largeAllocator; | |
6fe7ccc8 A |
227 | } |
228 | ||
93a37866 | 229 | inline MarkedAllocator& MarkedSpace::normalDestructorAllocatorFor(size_t bytes) |
6fe7ccc8 | 230 | { |
93a37866 | 231 | ASSERT(bytes); |
6fe7ccc8 | 232 | if (bytes <= preciseCutoff) |
93a37866 A |
233 | return m_normalDestructorSpace.preciseAllocators[(bytes - 1) / preciseStep]; |
234 | if (bytes <= impreciseCutoff) | |
235 | return m_normalDestructorSpace.impreciseAllocators[(bytes - 1) / impreciseStep]; | |
236 | return m_normalDestructorSpace.largeAllocator; | |
6fe7ccc8 A |
237 | } |
238 | ||
239 | inline void* MarkedSpace::allocateWithoutDestructor(size_t bytes) | |
240 | { | |
93a37866 | 241 | return allocatorFor(bytes).allocate(bytes); |
6fe7ccc8 A |
242 | } |
243 | ||
93a37866 | 244 | inline void* MarkedSpace::allocateWithImmortalStructureDestructor(size_t bytes) |
6fe7ccc8 | 245 | { |
93a37866 A |
246 | return immortalStructureDestructorAllocatorFor(bytes).allocate(bytes); |
247 | } | |
248 | ||
249 | inline void* MarkedSpace::allocateWithNormalDestructor(size_t bytes) | |
250 | { | |
251 | return normalDestructorAllocatorFor(bytes).allocate(bytes); | |
6fe7ccc8 A |
252 | } |
253 | ||
254 | template <typename Functor> inline typename Functor::ReturnType MarkedSpace::forEachBlock(Functor& functor) | |
255 | { | |
81345200 | 256 | for (size_t i = 0; i < preciseCount; ++i) |
6fe7ccc8 | 257 | m_normalSpace.preciseAllocators[i].forEachBlock(functor); |
81345200 | 258 | for (size_t i = 0; i < impreciseCount; ++i) |
6fe7ccc8 | 259 | m_normalSpace.impreciseAllocators[i].forEachBlock(functor); |
93a37866 | 260 | m_normalSpace.largeAllocator.forEachBlock(functor); |
81345200 A |
261 | |
262 | for (size_t i = 0; i < preciseCount; ++i) | |
263 | m_normalDestructorSpace.preciseAllocators[i].forEachBlock(functor); | |
264 | for (size_t i = 0; i < impreciseCount; ++i) | |
265 | m_normalDestructorSpace.impreciseAllocators[i].forEachBlock(functor); | |
93a37866 | 266 | m_normalDestructorSpace.largeAllocator.forEachBlock(functor); |
81345200 A |
267 | |
268 | for (size_t i = 0; i < preciseCount; ++i) | |
269 | m_immortalStructureDestructorSpace.preciseAllocators[i].forEachBlock(functor); | |
270 | for (size_t i = 0; i < impreciseCount; ++i) | |
271 | m_immortalStructureDestructorSpace.impreciseAllocators[i].forEachBlock(functor); | |
93a37866 A |
272 | m_immortalStructureDestructorSpace.largeAllocator.forEachBlock(functor); |
273 | ||
6fe7ccc8 A |
274 | return functor.returnValue(); |
275 | } | |
14957cd0 | 276 | |
6fe7ccc8 A |
277 | template <typename Functor> inline typename Functor::ReturnType MarkedSpace::forEachBlock() |
278 | { | |
279 | Functor functor; | |
280 | return forEachBlock(functor); | |
281 | } | |
14957cd0 | 282 | |
6fe7ccc8 A |
283 | inline void MarkedSpace::didAddBlock(MarkedBlock* block) |
284 | { | |
81345200 | 285 | m_capacity += block->capacity(); |
6fe7ccc8 A |
286 | m_blocks.add(block); |
287 | } | |
14957cd0 | 288 | |
81345200 A |
289 | inline void MarkedSpace::didAllocateInBlock(MarkedBlock* block) |
290 | { | |
291 | #if ENABLE(GGC) | |
292 | m_blocksWithNewObjects.append(block); | |
293 | #else | |
294 | UNUSED_PARAM(block); | |
295 | #endif | |
296 | } | |
297 | ||
298 | inline void MarkedSpace::clearRememberedSet() | |
93a37866 | 299 | { |
81345200 | 300 | forEachBlock<ClearRememberedSet>(); |
93a37866 A |
301 | } |
302 | ||
303 | inline size_t MarkedSpace::objectCount() | |
304 | { | |
305 | return forEachBlock<MarkCount>(); | |
306 | } | |
307 | ||
308 | inline size_t MarkedSpace::size() | |
309 | { | |
310 | return forEachBlock<Size>(); | |
311 | } | |
312 | ||
313 | inline size_t MarkedSpace::capacity() | |
314 | { | |
81345200 | 315 | return m_capacity; |
93a37866 A |
316 | } |
317 | ||
14957cd0 A |
318 | } // namespace JSC |
319 | ||
320 | #endif // MarkedSpace_h |