]> git.saurik.com Git - apple/javascriptcore.git/blob - heap/CopiedBlock.h
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / heap / CopiedBlock.h
1 /*
2 * Copyright (C) 2011 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #ifndef CopiedBlock_h
27 #define CopiedBlock_h
28
29 #include "CopyWorkList.h"
30 #include "JSCJSValue.h"
31 #include "Options.h"
32 #include <wtf/Atomics.h>
33 #include <wtf/DoublyLinkedList.h>
34 #include <wtf/SpinLock.h>
35
36 namespace JSC {
37
38 class CopiedSpace;
39
40 class CopiedBlock : public DoublyLinkedListNode<CopiedBlock> {
41 friend class WTF::DoublyLinkedListNode<CopiedBlock>;
42 friend class CopiedSpace;
43 friend class CopiedAllocator;
44 public:
45 static CopiedBlock* create(size_t = blockSize);
46 static CopiedBlock* createNoZeroFill(size_t = blockSize);
47 static void destroy(CopiedBlock*);
48
49 void pin();
50 bool isPinned();
51
52 bool isOld();
53 bool isOversize();
54 void didPromote();
55
56 unsigned liveBytes();
57 bool shouldReportLiveBytes(SpinLockHolder&, JSCell* owner);
58 void reportLiveBytes(SpinLockHolder&, JSCell*, CopyToken, unsigned);
59 void reportLiveBytesDuringCopying(unsigned);
60 void didSurviveGC();
61 void didEvacuateBytes(unsigned);
62 bool shouldEvacuate();
63 bool canBeRecycled();
64
65 // The payload is the region of the block that is usable for allocations.
66 char* payload();
67 char* payloadEnd();
68 size_t payloadCapacity();
69
70 // The data is the region of the block that has been used for allocations.
71 char* data();
72 char* dataEnd();
73 size_t dataSize();
74
75 // The wilderness is the region of the block that is usable for allocations
76 // but has not been so used.
77 char* wilderness();
78 char* wildernessEnd();
79 size_t wildernessSize();
80
81 size_t size();
82 size_t capacity();
83
84 static const size_t blockSize = 32 * KB;
85
86 bool hasWorkList();
87 CopyWorkList& workList();
88 SpinLock& workListLock() { return m_workListLock; }
89
90 private:
91 CopiedBlock(size_t);
92 void zeroFillWilderness(); // Can be called at any time to zero-fill to the end of the block.
93
94 void checkConsistency();
95
96 CopiedBlock* m_prev;
97 CopiedBlock* m_next;
98
99 size_t m_capacity;
100
101 SpinLock m_workListLock;
102 std::unique_ptr<CopyWorkList> m_workList;
103
104 size_t m_remaining;
105 bool m_isPinned : 1;
106 bool m_isOld : 1;
107 unsigned m_liveBytes;
108 #ifndef NDEBUG
109 unsigned m_liveObjects;
110 #endif
111 };
112
113 inline CopiedBlock* CopiedBlock::createNoZeroFill(size_t capacity)
114 {
115 return new(NotNull, fastAlignedMalloc(CopiedBlock::blockSize, capacity)) CopiedBlock(capacity);
116 }
117
118 inline void CopiedBlock::destroy(CopiedBlock* copiedBlock)
119 {
120 copiedBlock->~CopiedBlock();
121 fastAlignedFree(copiedBlock);
122 }
123
124 inline CopiedBlock* CopiedBlock::create(size_t capacity)
125 {
126 CopiedBlock* newBlock = createNoZeroFill(capacity);
127 newBlock->zeroFillWilderness();
128 return newBlock;
129 }
130
131 inline void CopiedBlock::zeroFillWilderness()
132 {
133 #if USE(JSVALUE64)
134 memset(wilderness(), 0, wildernessSize());
135 #else
136 JSValue emptyValue;
137 JSValue* limit = reinterpret_cast_ptr<JSValue*>(wildernessEnd());
138 for (JSValue* currentValue = reinterpret_cast_ptr<JSValue*>(wilderness()); currentValue < limit; currentValue++)
139 *currentValue = emptyValue;
140 #endif
141 }
142
143 inline CopiedBlock::CopiedBlock(size_t capacity)
144 : DoublyLinkedListNode<CopiedBlock>()
145 , m_capacity(capacity)
146 , m_remaining(payloadCapacity())
147 , m_isPinned(false)
148 , m_isOld(false)
149 , m_liveBytes(0)
150 #ifndef NDEBUG
151 , m_liveObjects(0)
152 #endif
153 {
154 ASSERT(is8ByteAligned(reinterpret_cast<void*>(m_remaining)));
155 }
156
157 inline void CopiedBlock::didSurviveGC()
158 {
159 checkConsistency();
160 ASSERT(isOld());
161 m_liveBytes = 0;
162 #ifndef NDEBUG
163 m_liveObjects = 0;
164 #endif
165 m_isPinned = false;
166 if (m_workList)
167 m_workList = nullptr;
168 }
169
170 inline void CopiedBlock::didEvacuateBytes(unsigned bytes)
171 {
172 ASSERT(m_liveBytes >= bytes);
173 ASSERT(m_liveObjects);
174 checkConsistency();
175 m_liveBytes -= bytes;
176 #ifndef NDEBUG
177 m_liveObjects--;
178 #endif
179 checkConsistency();
180 }
181
182 inline bool CopiedBlock::canBeRecycled()
183 {
184 checkConsistency();
185 return !m_liveBytes;
186 }
187
188 inline bool CopiedBlock::shouldEvacuate()
189 {
190 checkConsistency();
191 return static_cast<double>(m_liveBytes) / static_cast<double>(payloadCapacity()) <= Options::minCopiedBlockUtilization();
192 }
193
194 inline void CopiedBlock::pin()
195 {
196 m_isPinned = true;
197 if (m_workList)
198 m_workList = nullptr;
199 }
200
201 inline bool CopiedBlock::isPinned()
202 {
203 return m_isPinned;
204 }
205
206 inline bool CopiedBlock::isOld()
207 {
208 return m_isOld;
209 }
210
211 inline void CopiedBlock::didPromote()
212 {
213 m_isOld = true;
214 }
215
216 inline bool CopiedBlock::isOversize()
217 {
218 return m_capacity != blockSize;
219 }
220
221 inline unsigned CopiedBlock::liveBytes()
222 {
223 checkConsistency();
224 return m_liveBytes;
225 }
226
227 inline char* CopiedBlock::payload()
228 {
229 return reinterpret_cast<char*>(this) + WTF::roundUpToMultipleOf<sizeof(double)>(sizeof(CopiedBlock));
230 }
231
232 inline char* CopiedBlock::payloadEnd()
233 {
234 return reinterpret_cast<char*>(this) + m_capacity;
235 }
236
237 inline size_t CopiedBlock::payloadCapacity()
238 {
239 return payloadEnd() - payload();
240 }
241
242 inline char* CopiedBlock::data()
243 {
244 return payload();
245 }
246
247 inline char* CopiedBlock::dataEnd()
248 {
249 return payloadEnd() - m_remaining;
250 }
251
252 inline size_t CopiedBlock::dataSize()
253 {
254 return dataEnd() - data();
255 }
256
257 inline char* CopiedBlock::wilderness()
258 {
259 return dataEnd();
260 }
261
262 inline char* CopiedBlock::wildernessEnd()
263 {
264 return payloadEnd();
265 }
266
267 inline size_t CopiedBlock::wildernessSize()
268 {
269 return wildernessEnd() - wilderness();
270 }
271
272 inline size_t CopiedBlock::size()
273 {
274 return dataSize();
275 }
276
277 inline size_t CopiedBlock::capacity()
278 {
279 return m_capacity;
280 }
281
282 inline bool CopiedBlock::hasWorkList()
283 {
284 return !!m_workList;
285 }
286
287 inline CopyWorkList& CopiedBlock::workList()
288 {
289 return *m_workList;
290 }
291
292 inline void CopiedBlock::checkConsistency()
293 {
294 ASSERT(!!m_liveBytes == !!m_liveObjects);
295 }
296
297 } // namespace JSC
298
299 #endif