]>
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> |
14957cd0 A |
30 | #include <wtf/Bitmap.h> |
31 | #include <wtf/DoublyLinkedList.h> | |
14957cd0 A |
32 | #include <wtf/HashSet.h> |
33 | #include <wtf/Noncopyable.h> | |
ed1e77d3 | 34 | #include <wtf/RetainPtr.h> |
14957cd0 A |
35 | #include <wtf/Vector.h> |
36 | ||
14957cd0 A |
37 | namespace JSC { |
38 | ||
6fe7ccc8 | 39 | class Heap; |
81345200 | 40 | class HeapIterationScope; |
6fe7ccc8 A |
41 | class JSCell; |
42 | class LiveObjectIterator; | |
43 | class LLIntOffsetsExtractor; | |
44 | class WeakGCHandle; | |
45 | class SlotVisitor; | |
46 | ||
93a37866 | 47 | struct ClearMarks : MarkedBlock::VoidFunctor { |
81345200 A |
48 | void operator()(MarkedBlock* block) |
49 | { | |
50 | block->clearMarks(); | |
51 | } | |
52 | }; | |
53 | ||
93a37866 A |
54 | struct Sweep : MarkedBlock::VoidFunctor { |
55 | void operator()(MarkedBlock* block) { block->sweep(); } | |
56 | }; | |
57 | ||
81345200 A |
58 | struct ZombifySweep : MarkedBlock::VoidFunctor { |
59 | void operator()(MarkedBlock* block) | |
60 | { | |
61 | if (block->needsSweeping()) | |
62 | block->sweep(); | |
63 | } | |
64 | }; | |
65 | ||
93a37866 A |
66 | struct MarkCount : MarkedBlock::CountFunctor { |
67 | void operator()(MarkedBlock* block) { count(block->markCount()); } | |
68 | }; | |
69 | ||
70 | struct Size : MarkedBlock::CountFunctor { | |
71 | void operator()(MarkedBlock* block) { count(block->markCount() * block->cellSize()); } | |
72 | }; | |
73 | ||
6fe7ccc8 A |
74 | class MarkedSpace { |
75 | WTF_MAKE_NONCOPYABLE(MarkedSpace); | |
76 | public: | |
ed1e77d3 A |
77 | // [ 32... 128 ] |
78 | static const size_t preciseStep = MarkedBlock::atomSize; | |
79 | static const size_t preciseCutoff = 128; | |
80 | static const size_t preciseCount = preciseCutoff / preciseStep; | |
81 | ||
82 | // [ 1024... blockSize ] | |
83 | static const size_t impreciseStep = 2 * preciseCutoff; | |
84 | static const size_t impreciseCutoff = MarkedBlock::blockSize / 2; | |
85 | static const size_t impreciseCount = impreciseCutoff / impreciseStep; | |
86 | ||
87 | struct Subspace { | |
88 | std::array<MarkedAllocator, preciseCount> preciseAllocators; | |
89 | std::array<MarkedAllocator, impreciseCount> impreciseAllocators; | |
90 | MarkedAllocator largeAllocator; | |
91 | }; | |
92 | ||
6fe7ccc8 | 93 | MarkedSpace(Heap*); |
93a37866 A |
94 | ~MarkedSpace(); |
95 | void lastChanceToFinalize(); | |
6fe7ccc8 A |
96 | |
97 | MarkedAllocator& firstAllocator(); | |
98 | MarkedAllocator& allocatorFor(size_t); | |
ed1e77d3 A |
99 | MarkedAllocator& destructorAllocatorFor(size_t); |
100 | void* allocateWithDestructor(size_t); | |
6fe7ccc8 | 101 | void* allocateWithoutDestructor(size_t); |
ed1e77d3 A |
102 | |
103 | Subspace& subspaceForObjectsWithDestructor() { return m_destructorSpace; } | |
104 | Subspace& subspaceForObjectsWithoutDestructor() { return m_normalSpace; } | |
105 | ||
6fe7ccc8 A |
106 | void resetAllocators(); |
107 | ||
93a37866 A |
108 | void visitWeakSets(HeapRootVisitor&); |
109 | void reapWeakSets(); | |
110 | ||
6fe7ccc8 | 111 | MarkedBlockSet& blocks() { return m_blocks; } |
81345200 A |
112 | |
113 | void willStartIterating(); | |
114 | bool isIterating() { return m_isIterating; } | |
115 | void didFinishIterating(); | |
116 | ||
117 | void stopAllocating(); | |
118 | void resumeAllocating(); // If we just stopped allocation but we didn't do a collection, we need to resume allocation. | |
6fe7ccc8 A |
119 | |
120 | typedef HashSet<MarkedBlock*>::iterator BlockIterator; | |
121 | ||
81345200 A |
122 | template<typename Functor> typename Functor::ReturnType forEachLiveCell(HeapIterationScope&, Functor&); |
123 | template<typename Functor> typename Functor::ReturnType forEachLiveCell(HeapIterationScope&); | |
124 | template<typename Functor> typename Functor::ReturnType forEachDeadCell(HeapIterationScope&, Functor&); | |
125 | template<typename Functor> typename Functor::ReturnType forEachDeadCell(HeapIterationScope&); | |
6fe7ccc8 A |
126 | template<typename Functor> typename Functor::ReturnType forEachBlock(Functor&); |
127 | template<typename Functor> typename Functor::ReturnType forEachBlock(); | |
128 | ||
129 | void shrink(); | |
93a37866 A |
130 | void freeBlock(MarkedBlock*); |
131 | void freeOrShrinkBlock(MarkedBlock*); | |
6fe7ccc8 A |
132 | |
133 | void didAddBlock(MarkedBlock*); | |
134 | void didConsumeFreeList(MarkedBlock*); | |
81345200 | 135 | void didAllocateInBlock(MarkedBlock*); |
6fe7ccc8 | 136 | |
93a37866 | 137 | void clearMarks(); |
81345200 | 138 | void clearNewlyAllocated(); |
93a37866 | 139 | void sweep(); |
81345200 | 140 | void zombifySweep(); |
93a37866 A |
141 | size_t objectCount(); |
142 | size_t size(); | |
143 | size_t capacity(); | |
144 | ||
6fe7ccc8 A |
145 | bool isPagedOut(double deadline); |
146 | ||
81345200 A |
147 | #if USE(CF) |
148 | template<typename T> void releaseSoon(RetainPtr<T>&&); | |
149 | #endif | |
150 | ||
ed1e77d3 A |
151 | const Vector<MarkedBlock*>& blocksWithNewObjects() const { return m_blocksWithNewObjects; } |
152 | ||
6fe7ccc8 A |
153 | private: |
154 | friend class LLIntOffsetsExtractor; | |
ed1e77d3 | 155 | friend class JIT; |
93a37866 | 156 | |
81345200 A |
157 | template<typename Functor> void forEachAllocator(Functor&); |
158 | template<typename Functor> void forEachAllocator(); | |
159 | ||
ed1e77d3 | 160 | Subspace m_destructorSpace; |
6fe7ccc8 A |
161 | Subspace m_normalSpace; |
162 | ||
163 | Heap* m_heap; | |
81345200 A |
164 | size_t m_capacity; |
165 | bool m_isIterating; | |
6fe7ccc8 | 166 | MarkedBlockSet m_blocks; |
81345200 | 167 | Vector<MarkedBlock*> m_blocksWithNewObjects; |
6fe7ccc8 A |
168 | }; |
169 | ||
81345200 | 170 | template<typename Functor> inline typename Functor::ReturnType MarkedSpace::forEachLiveCell(HeapIterationScope&, Functor& functor) |
6fe7ccc8 | 171 | { |
81345200 | 172 | ASSERT(isIterating()); |
6fe7ccc8 | 173 | BlockIterator end = m_blocks.set().end(); |
ed1e77d3 A |
174 | for (BlockIterator it = m_blocks.set().begin(); it != end; ++it) { |
175 | if ((*it)->forEachLiveCell(functor) == IterationStatus::Done) | |
176 | break; | |
177 | } | |
6fe7ccc8 A |
178 | return functor.returnValue(); |
179 | } | |
180 | ||
81345200 | 181 | template<typename Functor> inline typename Functor::ReturnType MarkedSpace::forEachLiveCell(HeapIterationScope& scope) |
6fe7ccc8 A |
182 | { |
183 | Functor functor; | |
81345200 | 184 | return forEachLiveCell(scope, functor); |
6fe7ccc8 A |
185 | } |
186 | ||
81345200 | 187 | template<typename Functor> inline typename Functor::ReturnType MarkedSpace::forEachDeadCell(HeapIterationScope&, Functor& functor) |
6fe7ccc8 | 188 | { |
81345200 | 189 | ASSERT(isIterating()); |
93a37866 | 190 | BlockIterator end = m_blocks.set().end(); |
ed1e77d3 A |
191 | for (BlockIterator it = m_blocks.set().begin(); it != end; ++it) { |
192 | if ((*it)->forEachDeadCell(functor) == IterationStatus::Done) | |
193 | break; | |
194 | } | |
93a37866 A |
195 | return functor.returnValue(); |
196 | } | |
197 | ||
81345200 | 198 | template<typename Functor> inline typename Functor::ReturnType MarkedSpace::forEachDeadCell(HeapIterationScope& scope) |
93a37866 A |
199 | { |
200 | Functor functor; | |
81345200 | 201 | return forEachDeadCell(scope, functor); |
6fe7ccc8 A |
202 | } |
203 | ||
204 | inline MarkedAllocator& MarkedSpace::allocatorFor(size_t bytes) | |
205 | { | |
93a37866 | 206 | ASSERT(bytes); |
6fe7ccc8 A |
207 | if (bytes <= preciseCutoff) |
208 | return m_normalSpace.preciseAllocators[(bytes - 1) / preciseStep]; | |
93a37866 A |
209 | if (bytes <= impreciseCutoff) |
210 | return m_normalSpace.impreciseAllocators[(bytes - 1) / impreciseStep]; | |
211 | return m_normalSpace.largeAllocator; | |
6fe7ccc8 A |
212 | } |
213 | ||
ed1e77d3 | 214 | inline MarkedAllocator& MarkedSpace::destructorAllocatorFor(size_t bytes) |
6fe7ccc8 | 215 | { |
93a37866 A |
216 | ASSERT(bytes); |
217 | if (bytes <= preciseCutoff) | |
ed1e77d3 | 218 | return m_destructorSpace.preciseAllocators[(bytes - 1) / preciseStep]; |
93a37866 | 219 | if (bytes <= impreciseCutoff) |
ed1e77d3 A |
220 | return m_destructorSpace.impreciseAllocators[(bytes - 1) / impreciseStep]; |
221 | return m_destructorSpace.largeAllocator; | |
6fe7ccc8 A |
222 | } |
223 | ||
224 | inline void* MarkedSpace::allocateWithoutDestructor(size_t bytes) | |
225 | { | |
93a37866 | 226 | return allocatorFor(bytes).allocate(bytes); |
6fe7ccc8 A |
227 | } |
228 | ||
ed1e77d3 | 229 | inline void* MarkedSpace::allocateWithDestructor(size_t bytes) |
93a37866 | 230 | { |
ed1e77d3 | 231 | return destructorAllocatorFor(bytes).allocate(bytes); |
6fe7ccc8 A |
232 | } |
233 | ||
234 | template <typename Functor> inline typename Functor::ReturnType MarkedSpace::forEachBlock(Functor& functor) | |
235 | { | |
81345200 | 236 | for (size_t i = 0; i < preciseCount; ++i) |
6fe7ccc8 | 237 | m_normalSpace.preciseAllocators[i].forEachBlock(functor); |
81345200 | 238 | for (size_t i = 0; i < impreciseCount; ++i) |
6fe7ccc8 | 239 | m_normalSpace.impreciseAllocators[i].forEachBlock(functor); |
93a37866 | 240 | m_normalSpace.largeAllocator.forEachBlock(functor); |
81345200 A |
241 | |
242 | for (size_t i = 0; i < preciseCount; ++i) | |
ed1e77d3 | 243 | m_destructorSpace.preciseAllocators[i].forEachBlock(functor); |
81345200 | 244 | for (size_t i = 0; i < impreciseCount; ++i) |
ed1e77d3 A |
245 | m_destructorSpace.impreciseAllocators[i].forEachBlock(functor); |
246 | m_destructorSpace.largeAllocator.forEachBlock(functor); | |
93a37866 | 247 | |
6fe7ccc8 A |
248 | return functor.returnValue(); |
249 | } | |
14957cd0 | 250 | |
6fe7ccc8 A |
251 | template <typename Functor> inline typename Functor::ReturnType MarkedSpace::forEachBlock() |
252 | { | |
253 | Functor functor; | |
254 | return forEachBlock(functor); | |
255 | } | |
14957cd0 | 256 | |
6fe7ccc8 A |
257 | inline void MarkedSpace::didAddBlock(MarkedBlock* block) |
258 | { | |
81345200 | 259 | m_capacity += block->capacity(); |
6fe7ccc8 A |
260 | m_blocks.add(block); |
261 | } | |
14957cd0 | 262 | |
81345200 A |
263 | inline void MarkedSpace::didAllocateInBlock(MarkedBlock* block) |
264 | { | |
265 | #if ENABLE(GGC) | |
266 | m_blocksWithNewObjects.append(block); | |
267 | #else | |
268 | UNUSED_PARAM(block); | |
269 | #endif | |
270 | } | |
271 | ||
93a37866 A |
272 | inline size_t MarkedSpace::objectCount() |
273 | { | |
274 | return forEachBlock<MarkCount>(); | |
275 | } | |
276 | ||
277 | inline size_t MarkedSpace::size() | |
278 | { | |
279 | return forEachBlock<Size>(); | |
280 | } | |
281 | ||
282 | inline size_t MarkedSpace::capacity() | |
283 | { | |
81345200 | 284 | return m_capacity; |
93a37866 A |
285 | } |
286 | ||
14957cd0 A |
287 | } // namespace JSC |
288 | ||
289 | #endif // MarkedSpace_h |